[Pkg-mozext-commits] [SCM] Mozilla addon for sharing interesting websites branch, upstream, updated. debian/3.3.8-3-20-gace74ad

Fabrizio Regalli fabreg at fabreg.it
Tue Aug 9 09:58:49 UTC 2011


The following commit has been merged in the upstream branch:
commit ace74ad952745d99bcee8b626b24247d17fcdabc
Author: Fabrizio Regalli <fabreg at fabreg.it>
Date:   Tue Aug 9 11:58:23 2011 +0200

    Imported Upstream version 3.91

diff --git a/META-INF/manifest.mf b/META-INF/manifest.mf
new file mode 100644
index 0000000..6029047
--- /dev/null
+++ b/META-INF/manifest.mf
@@ -0,0 +1,759 @@
+Manifest-Version: 1.0
+Created-by: XPISigner
+XPI-Signer-Version: 1.4 (free) http://o-regan.org
+Comments: PLEASE DO NOT EDIT THIS FILE. YOU WILL BREAK IT.
+
+Name: components/stumbleuponService.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: nZjzyRx3ONkdRuXBfD1cTw==
+SHA1-Digest: XIFQKAbEtdmIKVl4OwDhIlxMM/E=
+
+Name: install.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: P8HECCAFMzyJ+CviLkPnDQ==
+SHA1-Digest: hbQ7Dgt9BbUW6zRDKL9uKiZlNuU=
+
+Name: install.rdf
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 6w82sTvrxz5/ZbmmpUf3fQ==
+SHA1-Digest: PezdnwEZEz3t/kRHI0w1kDELKrA=
+
+Name: chrome.manifest
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 7B+3ELZWlVKBICfcdjTnWA==
+SHA1-Digest: 8AXSGrWjgbXJ6JMgwH9UCY7J9Bg=
+
+Name: content/DatabaseConnection.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: yHDEdiEDmM9MEXz4RWWXiw==
+SHA1-Digest: OiY1JPoeU5wx2LdFFjkturRFTT8=
+
+Name: content/contents.rdf
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: YvOMN3oh8ryda3Y+9NSyRg==
+SHA1-Digest: FntUow9JrIs1mUpjcPDpBqJQnf4=
+
+Name: content/datastore.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: M8PyAyW9ihWm3r478NZjUA==
+SHA1-Digest: DFECSIaxJOH9UhzuZjCRkxVCe1o=
+
+Name: content/discoveryDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: uk5lijS4CwDzTpyBItCRJw==
+SHA1-Digest: ZD2VGzs3BvcIOmoXtkmMj3dWclo=
+
+Name: content/downloadFavsDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: iARnkaf0M/aRP0DEPep7EA==
+SHA1-Digest: tWXpKBEEXKCuEz4NWlAYNSBzgRk=
+
+Name: content/migrate.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: lrej8HvTI8zo6IEQRpYGfA==
+SHA1-Digest: bw/Q08xuHDpHuBXcalAgzW+1PhA=
+
+Name: content/moreChannelsDialog.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: Pw5EO/8xUZMhwjAMlfl2vQ==
+SHA1-Digest: dNljBLNe/wWXjLJu7i5YefRmbtQ=
+
+Name: content/moreChannelsDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: wIpnK+4542Zq8IMO5z6epg==
+SHA1-Digest: TMIZyrZuiM7jT5ttIAWMnZ7thJk=
+
+Name: content/passwordDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: d1G33VQ+wN+qYJjXwdRwIg==
+SHA1-Digest: njUPRZcYe2/VgYW9Ptuff8yiJqU=
+
+Name: content/positionDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: mD3s2NrWMZMF9OEeZaX5pA==
+SHA1-Digest: HPPbbffdwB98RebpCfHQkl8HMuU=
+
+Name: content/preferenceDialog.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: lEJ8oQ+K/T9XXMQXBBrfgw==
+SHA1-Digest: M5TduzoH6a+2lDI/yHnb+cDpu+w=
+
+Name: content/preferenceDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: eW/hrlJhYRE67LaQJDNS4g==
+SHA1-Digest: RfFOkZpEQB56Q5xEDVz8ptvt6ds=
+
+Name: content/prefetcher.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: vMqgkvjP6QVU5dSYyI36cg==
+SHA1-Digest: tLdO004opIgRJsFe0Q7MY5W4/2g=
+
+Name: content/ratingDialog.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: Jt/7k2Jo8x37S0ZAPrJE4w==
+SHA1-Digest: 8oOF0Jz13OQJqD2zJ9ZM18yDs68=
+
+Name: content/ratingDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: xMzGba9xrmUYO0Iow/u08g==
+SHA1-Digest: d9AZRMbC9Q4H6IfTYGdZzBhmLo0=
+
+Name: content/reportTopicDialog.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: Eni50WRhhap5//Qs67+vpg==
+SHA1-Digest: 5YQEXlHc5TEIb6rfAWBbu4zOJTg=
+
+Name: content/reportTopicDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: Z8X4lqAZdA16VVjpXMGubg==
+SHA1-Digest: 1sXCsM9hvZeZXG33Ua7hn2o0dno=
+
+Name: content/searchDialog.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: gLLfZWFrzpMZeIlt0loDiA==
+SHA1-Digest: MR3ibbxrB48BakdLE69+DV5AIZg=
+
+Name: content/searchDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 09eY1IaDQyj8gxAkFuI8HQ==
+SHA1-Digest: GLwf4ZJENl5z9e2B6mLOR0/Fk2o=
+
+Name: content/searchlinksDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: AAVUDTuWyfvljsTBCyPCwQ==
+SHA1-Digest: gamdnn7/m/OrWfKEZCOdlx0V/Mg=
+
+Name: content/sendDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: JhAzzC2Pv7bTkw69v0jUfw==
+SHA1-Digest: QCYJEFRzrr7A1tRtyFywXqPSw08=
+
+Name: content/sidebar.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 3tJz0Z+gCMOfwqpVSiL8sA==
+SHA1-Digest: NWRoMU6lMlYaFK3izDOsTAu7maU=
+
+Name: content/sidebar.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: C0hatfUReS8wMCoUXSsNjg==
+SHA1-Digest: a2cK/9gpOYB03n+csbJiH6mu7LE=
+
+Name: content/sidebarOverlay.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: QWPjyT2sS1+dVCwjpjxfeA==
+SHA1-Digest: oCwBEu+oKVu/vMPf/gYiJRtZhw4=
+
+Name: content/signinDialog.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: egUNOUwZdxTmQ+65ycRkcw==
+SHA1-Digest: gCBSF3Mz5+4b/lpnN5GqaLZPS3k=
+
+Name: content/signinDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: dlmAKigNXB19KHLICAJLgw==
+SHA1-Digest: 8KhzA6XzZzZfm4qAHgu+fwY4c1E=
+
+Name: content/signoutDialog.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 8tD+3PNe7FdxLP8dZMQeJw==
+SHA1-Digest: Cr0PuZcL0lbCrz5oIeh1PDE477Y=
+
+Name: content/signoutDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: dNQZK79JAfJLIeEL6UEg8g==
+SHA1-Digest: uRj4YdDktm42KGpxMeQkzXs2rO4=
+
+Name: content/skin/ChangePassword.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: T7V1euzUK4RnHQLuWaC0VQ==
+SHA1-Digest: OqMvz4+YjbEDTh9rT1XslRx0i2A=
+
+Name: content/skin/Throbber-small.gif
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: QEGDg5R/5jNQVvzgWr5Eog==
+SHA1-Digest: pJ12a8ioOZtv5R62Xsl8wzu2hyE=
+
+Name: content/skin/Throbber-small.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: zIG8vHLhO7lbAn+r8pGgJw==
+SHA1-Digest: SxhqBZbTmKUJ5H8J+qx+a1kJNLM=
+
+Name: content/skin/aaaa.gif
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: A+zpJuftEHb1c62EKMX1ZA==
+SHA1-Digest: Cswq/sAZOso/uKhDQ9uVgOb5WLk=
+
+Name: content/skin/all.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: zbq5JS3S1uTpHtu5t0F6gA==
+SHA1-Digest: rz5fHzaxTNpaf8+4aLucTdD9Md0=
+
+Name: content/skin/arrow.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: dILBZ6U8DKz8jUXInl0nkw==
+SHA1-Digest: Bo1DN9Gg+IoELvCL3n0TRJZxMWo=
+
+Name: content/skin/arrow_ani4-a.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: RtRuP526OXAYNugl0PGytw==
+SHA1-Digest: L8AZnx0scPenu6jZRqxbLZsRcDU=
+
+Name: content/skin/arrow_ani4.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: LPX9T6N1vvz8Rr2OU23/Dw==
+SHA1-Digest: BVTDZNAIgxhrsoEjhBpOWSxSw54=
+
+Name: content/skin/arrow_green-b.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: p/1KjhNzCVTlAht+dcKIuA==
+SHA1-Digest: 2CqU+Ath0XRQF1NaYicvj4pop2E=
+
+Name: content/skin/arrow_green-c.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: UEWG/SNlVuGuM0rMbhP/lw==
+SHA1-Digest: NSFAGwPyTx/Lx1aT5W5NlowmNH4=
+
+Name: content/skin/btn_turniton.gif
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: jVrN9BYfsXuQNSvmUYKBPg==
+SHA1-Digest: 3akBX8VpuKlpd/8mzFOkQVM1t/w=
+
+Name: content/skin/bubble.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: vdI8bbFQ5J/k19kdffRjqQ==
+SHA1-Digest: rcKdc8HEHoo0AKQ/z+qwRWACiJw=
+
+Name: content/skin/bubble1.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: AnbYSktNEkSKS0s7pxT+yQ==
+SHA1-Digest: yHglZzz/+JUe6KgTTNbOlKfa2K0=
+
+Name: content/skin/bubble2.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: Ov7ZKXAuhM8ZHq9WFtyxFQ==
+SHA1-Digest: pOrhkNO8MoPXlsABQA03XGw+VH4=
+
+Name: content/skin/bubble3.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: c0tGTt9M2rnQtPPGersjow==
+SHA1-Digest: j7Un6MFtGxIi9Yxqc1UVJQ0zQnA=
+
+Name: content/skin/bubblex.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: ugtq/L76q55517VDkebVeA==
+SHA1-Digest: OdAJzGkKPLJ93Qz581GTiz0gv5s=
+
+Name: content/skin/bug.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: cd+smG+1TKTA4dQ2F+mLeg==
+SHA1-Digest: JaD7uZ1CVCDC1UBf1iqwyO2eImI=
+
+Name: content/skin/chevron.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 9yrQNCeFO9tiZS2WWcm/Gg==
+SHA1-Digest: YWG5fr1Wg5jTXCp7Xfsigb97R64=
+
+Name: content/skin/close-c.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: DTY+keD5Qi7BDNF263lYvQ==
+SHA1-Digest: mJi33R6ZoPvmUo3+oSblNyNVNF8=
+
+Name: content/skin/close-d.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: gxczf2QcbIglFvqtN3YS+g==
+SHA1-Digest: DCF0VIpNo5Nzwocf4s0aEaKg6Dg=
+
+Name: content/skin/close.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 7h607/eRKeau7XntOi2fCw==
+SHA1-Digest: iTy8yNjtkoRcODVHdACukPyUdmk=
+
+Name: content/skin/closetab-active.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 15eiaxNRyLJlX2L8PJDjPw==
+SHA1-Digest: 2dzOw8Ky3fg991GCfAGipZJ08mg=
+
+Name: content/skin/closetab-hover.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: /0A6O+4B0tEE/0FqwoCWQA==
+SHA1-Digest: sxXI9zmIw8zTOgaUWOYB86F0BF8=
+
+Name: content/skin/closetab.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 45hbaM0gfjMvPWTwGQhvjg==
+SHA1-Digest: XL1LA8Sca5USaA8xh8V00slxUZc=
+
+Name: content/skin/comment.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 36num7iMyiPq4+C9trzUAg==
+SHA1-Digest: eXNeioeiUeSgEcZbp0z8pEtcTtI=
+
+Name: content/skin/contents.rdf
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 8zmJwV5tqKQ4ujjhAPFYtg==
+SHA1-Digest: hsLyf7oN/odCdHWfoUOUXBigRv0=
+
+Name: content/skin/domain.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: qYtFskUQddE8TtOlJIJROw==
+SHA1-Digest: 5H/vFgiuMRh29Sx8qZ3D59SVeb0=
+
+Name: content/skin/editinfo.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: PAZ2zMygO8sT6HjE4XDPkg==
+SHA1-Digest: N4+EPNg6tThCOCqrk3JU/+QrWCI=
+
+Name: content/skin/facebook_share_icon.gif
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: EBYXWVoJ0AWqzK3tyc8Bvg==
+SHA1-Digest: jJhScjYU62auV6SWoqura5ilh6o=
+
+Name: content/skin/favicon_aol.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: SSgajS6sWEKwnZnRfHGOoQ==
+SHA1-Digest: CAw8gPNimWYbrcoE4KQMzbAcjMw=
+
+Name: content/skin/favicon_ask.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: plAyTJ8IR4DhwniaojxMHQ==
+SHA1-Digest: /aw/Bzs2mjpjYqLhiPsCs6x/RkU=
+
+Name: content/skin/favicon_facebook.gif
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 3sU4vDoL3FyoQngMkW6SVQ==
+SHA1-Digest: xGPJfl5cFwxKsKpVaQNh4APinGg=
+
+Name: content/skin/favicon_flickr.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 1Ou9xWStXS+AaVb7rCe+Hg==
+SHA1-Digest: aZqLKzQaEVQ4k/cHwC0eLvZPjlM=
+
+Name: content/skin/favicon_google.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 595sZ7iXXKqSI6rbWElFsQ==
+SHA1-Digest: OVAhH1/vbuZ9MpdCUQLFB9YtZ1I=
+
+Name: content/skin/favicon_mslive.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: JRTY0VtaOzq7mNeVrg8AzQ==
+SHA1-Digest: vXvKG8dcYcOsdSdKbFTa7JPI+UQ=
+
+Name: content/skin/favicon_twitter.gif
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: LEz+FHRuGFgo2UZNccZ6Zg==
+SHA1-Digest: F8g46StdzcTpXUtSsTV/OcwlwDQ=
+
+Name: content/skin/favicon_yahoo.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: OpOkcdvWU079Oh68a9rajA==
+SHA1-Digest: b3mcmJDq5ZgmTYVumC+NsHXkdHU=
+
+Name: content/skin/favicon_youtube.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: iXi31QXSWMn8XPdwKcVI8Q==
+SHA1-Digest: NPVVx4jrqOiqItpRJKRYucKcK/o=
+
+Name: content/skin/firstrater.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 7iK/ghJYLUgDVjU6h/APtA==
+SHA1-Digest: NCwxr500o4IVHILeh/N//SAy+sA=
+
+Name: content/skin/forum.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: HCWohtljwB+KkRQY8F+zSw==
+SHA1-Digest: RD8n6Y8a4h64yfqqrjGwsrAM4Ow=
+
+Name: content/skin/friend.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: +3VISZX85fCSI5LyRyLlXA==
+SHA1-Digest: H8imgpGvwJrz2zsYpXDIZtxdDhs=
+
+Name: content/skin/g.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: iYrnhKIo1E4FVEBZKFoopQ==
+SHA1-Digest: jZtF1U/zYH5MyIRdxhIBwE2Yr7k=
+
+Name: content/skin/greenthumbdown.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: TnpZVVtyq7MB8lepXPdATw==
+SHA1-Digest: r3jQl8hrE7qTGndIWRb+/buMZ00=
+
+Name: content/skin/greenthumbup.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: OtrjcZ5q8jBPiPIt30bf+Q==
+SHA1-Digest: Nt5s6z9+25SuWdz77kxqsN8b/tc=
+
+Name: content/skin/greyman.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 41CwbLDifxghBHs8B7V3Aw==
+SHA1-Digest: mHXID0aHZ/VQ80Zasv7ZeyMDCtY=
+
+Name: content/skin/groups.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: CZgOTKnb4/XQ8U2VyEOBPA==
+SHA1-Digest: XA7D/AdnFlCcZ3XRPbHkDsSP4wE=
+
+Name: content/skin/icon_signin.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: YUODDQg5ivLLm540aIGD3Q==
+SHA1-Digest: JGYAdj0i4X7x3hBSIiCICAtnO+E=
+
+Name: content/skin/icon_tb_favorites_hover.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: ycAWtdIKrfISKGy9LPPVww==
+SHA1-Digest: ijyZPQTdYoYXodhg2TmSE9l6LRU=
+
+Name: content/skin/icon_tb_flag_blue.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: +9YM+TlLn5IlIG0/0V2cNQ==
+SHA1-Digest: ju1oSFlA6jtYnFASrDF+lphvlXY=
+
+Name: content/skin/icon_tb_news.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: nQqR9sHK2XfePhqce2IdwQ==
+SHA1-Digest: 23qXoc3LhxuAfT+mvFzWs0CBGbA=
+
+Name: content/skin/icon_tb_people.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 9TYUeY2LDQsnkd9G7MVtuw==
+SHA1-Digest: htngyQb/suyEt3OlQ6rV7KYaQ9o=
+
+Name: content/skin/icon_tb_photo_hover.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: xP4N1s5nKJaGaFKbW+CaPw==
+SHA1-Digest: ZCRDzBJlh7ULh9p+6Guez8xsG88=
+
+Name: content/skin/icon_tb_search_user.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: N2X9VJ637gsUQ9heAd+mJw==
+SHA1-Digest: r1Z/oWcvuacUO7BJcD2j0e8Dj04=
+
+Name: content/skin/icon_tb_share.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: NMzj7W3qp1hE/UouBUQ1rQ==
+SHA1-Digest: R7pd/UMl9AOreYXAyo2kzq3AN5U=
+
+Name: content/skin/icon_tb_share2.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: i60+1KSg/DcKtu2Kfs5SLA==
+SHA1-Digest: AzrF7nSRJesDpgEL86WXxF1VZUQ=
+
+Name: content/skin/icon_tb_tag_left.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 6QVKSLfzfJKymmoYjz9PKA==
+SHA1-Digest: SgAJe2g7qov0Sce2MIvuP99eecY=
+
+Name: content/skin/icon_tb_user_comment.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: RS8l51JKOALStN8zII41hg==
+SHA1-Digest: H1oJObbkbtx9z+rTkyeNMjLisms=
+
+Name: content/skin/logo24.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: kTek9pBo0u28Clxk1QoAOw==
+SHA1-Digest: lqDlQ658hJrBZ6ch6FBt91+S+Vc=
+
+Name: content/skin/logo32.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: GvkeI4bTHt3xOkrdmf5xNA==
+SHA1-Digest: YBjR1VPNczb+2xL/YqrwHrHjEyw=
+
+Name: content/skin/mail.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: VVbUnAaZ+Lmy2RvP5n0d0Q==
+SHA1-Digest: 5v5aLwYcpNN2SxLmYaoKT7lp8G0=
+
+Name: content/skin/mail2.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: uAuU0RkYkJPN+w+iEUYW4g==
+SHA1-Digest: Vcy2DfRVra1C0pkKOCQl57AOycU=
+
+Name: content/skin/mutual_favorites.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: dpPGYBt6lnwG9tMdMS42Wg==
+SHA1-Digest: fHqXJMQ5eGeoiQlK4s7ksdpxSVU=
+
+Name: content/skin/point3.gif
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: e+KUxwK2uUUGkbpJ5cqGFg==
+SHA1-Digest: wyTBOWhpHN2I4zUMKMMn1l+P+U4=
+
+Name: content/skin/preferenceDialog.css
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 3TlPOq6wTlOlkpk92EIRwA==
+SHA1-Digest: AQ8y5cIVdyR1f2AqXiEHIefD3ZI=
+
+Name: content/skin/profile.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 2W4SZV9zw0tHrpo834j3eg==
+SHA1-Digest: L0NaJ4Icwv99lErjwe/Byzds7oM=
+
+Name: content/skin/r.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: AESOUzBHeX++5pl8QNsFSg==
+SHA1-Digest: WzYUo75tBaXBGIoPY+FQ6I/mV08=
+
+Name: content/skin/ratingDialog.css
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: /UOlXJgqTCF+cerSK5oBTQ==
+SHA1-Digest: 6kLAchJIea37uu8pJGbftw5UoWk=
+
+Name: content/skin/redman.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 5jP0SIO9+LwDZiXzDxPqTQ==
+SHA1-Digest: DQWDDEm3k2h3fd2UR1aPiMtEhUI=
+
+Name: content/skin/search.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 0KtAogx0pZSq6BuU5RTm7A==
+SHA1-Digest: SF3DpefonLQ4F85VZa/eyvLJVV0=
+
+Name: content/skin/searchDialog.css
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: YaooNABBUURRVrL9ef8wyg==
+SHA1-Digest: VZ5mOjPr7ufpwfnPXzjIiM4QHSE=
+
+Name: content/skin/smallbubble1.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: ZSRowGiQYnNmCacXTxMnqQ==
+SHA1-Digest: Dohu5kb+OonG45GKVIjrDnvke/w=
+
+Name: content/skin/smallbubble2.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: aIwwn4FtkWpTVjwkXCIs4g==
+SHA1-Digest: LGAz8GwANEoJzY7/S1ZZKogZR7k=
+
+Name: content/skin/smallbubble3.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: CCGpeM+tmOQCKyzyMZJdyg==
+SHA1-Digest: k5kHiAyr+yI8JKl8xMYfkJ58Yl0=
+
+Name: content/skin/smallgreenthumbup.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: FG134MO/T0P0Crvk3wAJsA==
+SHA1-Digest: eFiRurLQgOHJ7VTzZjSvAXiBoLk=
+
+Name: content/skin/smallgreythumbup.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: A5AQNTZXjn6uCBFcVitCrg==
+SHA1-Digest: wmi9ChWKl+amQFrX8Xk887GmCic=
+
+Name: content/skin/smallredman.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: ytzoKaHeoZBDj0eoFfuSUw==
+SHA1-Digest: Y2wCBZW5082ysCdHoBnaappXrMg=
+
+Name: content/skin/smallstumble.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: PYtSDZ9l3OgilfS0iwvWkA==
+SHA1-Digest: FvlhFinzWByhywiUIUUql8lIfnI=
+
+Name: content/skin/splitter.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: wZuE6bjKtrG1YS2cv6EtWg==
+SHA1-Digest: q5Oh6xtBFtz0GolZDNdPu3H7tso=
+
+Name: content/skin/sponsor.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: RBJHg5TFPwpil3RGd5xk+g==
+SHA1-Digest: FICZyUhdpgbLJd6Do+x+mvSEXb8=
+
+Name: content/skin/sponsor_mac.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: xfb7skW/wZduwQcMoS7yaw==
+SHA1-Digest: QmsBM7ZNmotprkTXv1hZaPhZNcA=
+
+Name: content/skin/star.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: os8uh4oVQ+DcZdA9H3I2pg==
+SHA1-Digest: 6jY9UGruHaour8VZhiPGRleL5Wo=
+
+Name: content/skin/stopa.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: FVOKTaOeAhcmHclUv28hJQ==
+SHA1-Digest: huIc2b21Ekn/ZYQHlZPxzvtX+WY=
+
+Name: content/skin/stumble.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: agfZ/KEolO2Z9HjH8d+jew==
+SHA1-Digest: 2A3nKZpsYWZHFWjZx2qPbLGQ7QU=
+
+Name: content/skin/stumble2.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: mTMoQiEWMXBu91f1cKKFxw==
+SHA1-Digest: BJAFcvEq4pOEDp2rontCTzc67GA=
+
+Name: content/skin/stumbler_favorites.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: TAkawZl9hz5NLUvEwY7rsQ==
+SHA1-Digest: tTL/HEa9lUROJHZLK8eSLetBcR8=
+
+Name: content/skin/stumblers.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 1PtIz5/Gst9nIY+0KVHd8A==
+SHA1-Digest: 4NhCWNwibKcHLVidsnuHgUolSBU=
+
+Name: content/skin/stumbleuponOverlay.css
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: f5m4b1+4t8l75W440PHgJw==
+SHA1-Digest: H48Pz4JyyyOokzNBDcwDdkiqwfU=
+
+Name: content/skin/tag.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: VeY1pk9GDqeVXR1k4Z3aXg==
+SHA1-Digest: +3f6Sc/l0XACnRU3Hv4HgH0hFuA=
+
+Name: content/skin/tag2.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: IKDc8hLFyhBNAwdelI4Mog==
+SHA1-Digest: GWIEJ9P733S0/geV/mZ2u6AHCa8=
+
+Name: content/skin/taggingDialog.css
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: /UOlXJgqTCF+cerSK5oBTQ==
+SHA1-Digest: 6kLAchJIea37uu8pJGbftw5UoWk=
+
+Name: content/skin/tbgrip-texture-12px.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: nwrgjh2GA/veb61pY/FL5w==
+SHA1-Digest: 8WfbeTFIe2UiGHe2PYcrx0ZRphc=
+
+Name: content/skin/thumbdown.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 0skFcBuzIEyslgqYSMXC3Q==
+SHA1-Digest: Zg66Swg9uOnu0FvwkCRg0Zh9Fco=
+
+Name: content/skin/thumbup.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: R97XdomGlMPFNuAXogg1YA==
+SHA1-Digest: b8BfzB6/Jpz61WokS+2kevcwMyE=
+
+Name: content/skin/thumbupcomment.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: +3WLFP9a6u1NaU1KELtfoQ==
+SHA1-Digest: c2G2i74VtaPcB6C2SOlhh5GdjBM=
+
+Name: content/skin/toggle_preview.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: ykGpSa6Memi/akVla9cJTQ==
+SHA1-Digest: BQjeaYJ/Ltz6gdV/9l5HUuDPTtE=
+
+Name: content/skin/topic.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: Vumv3NOesTMYx0yiMrRTwg==
+SHA1-Digest: p6dVld9VtGUGf7fbMJHZlEnvOes=
+
+Name: content/skin/upgrade.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: e/KlO+6yaxnQ7flT/spvIg==
+SHA1-Digest: VZIxVcdTDt0pl4fo49M3N8SiIeU=
+
+Name: content/skin/video.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: DprIx4WUsyvGC3GQMGKj7Q==
+SHA1-Digest: 3MWhIcSKiqx3hrEPBiTHql7bJqI=
+
+Name: content/skin/widgets.css
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: jxI3XQeCH/UGgRHC1wRzjg==
+SHA1-Digest: rx55L5lOHBzMyKbVcA6xladt1rs=
+
+Name: content/skin/wiki.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 7iVR8KQV6RLIK/oiZDv1dA==
+SHA1-Digest: kZRNyUPbYxVBvZ2BCHTsDneY7+0=
+
+Name: content/skin/x.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: pNdFoOU1F8KTjTn/7so4Bg==
+SHA1-Digest: h2tkZZjm2kvzBE9OzHXSs8/j0oY=
+
+Name: content/stumbleReporter.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: FoniHjHZQHD2HfjTTkOVwA==
+SHA1-Digest: 88OVnYYOu42M1lusS+9l5LYyQp0=
+
+Name: content/stumbleuponOverlay.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: ERlrMiCnX5U/2FEuop7tEg==
+SHA1-Digest: ZLL0twPT5AU7fZgl0yTqscmC9OA=
+
+Name: content/stumbleuponOverlay.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: jeYh9X4Ul/4qeUacgxrnEg==
+SHA1-Digest: vKJ3yz0JDGDc7cQO02VJSbLF7Nk=
+
+Name: content/taggingDialog.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: aoxeVxh4RRJ10pJb98aMkg==
+SHA1-Digest: Sph3r8RxtBDTgHi9cC5udCtfQ0E=
+
+Name: content/taggingDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: eEGRPbc2SqGUeGRDFHbhOw==
+SHA1-Digest: SkxPJYVRaVpDIUA95JnzzPFtj1k=
+
+Name: content/tldEmulation.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 7sWoS5ty2/Qs1CJJqBSAVw==
+SHA1-Digest: u/C7TjIBZfofvZjktDkLqmEPsgc=
+
+Name: content/topics.csv
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 76nSRajHqSz8LZZn7WdSTQ==
+SHA1-Digest: SVoRKc9WGfOfuAFImxZ0N54/ogY=
+
+Name: content/uninstallDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: zISgrFbRq+3G1wgO3/9QGg==
+SHA1-Digest: Ghl1lw+FxCaLYfpQ2aQVdE8Ou7k=
+
+Name: content/userdb.sql
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 7mPZ5YckWnBnsKl0l7+ZfA==
+SHA1-Digest: 1SR08oA8TRB2cFnI8exrSJAC70c=
+
+Name: content/widgets.xml
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: AMhBzuXF/3cO6cD9TL0kUg==
+SHA1-Digest: KYC87XP/Xu0z8w+II3oclf5OBls=
+
+Name: content/initOverlay.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: N5euA03LSwwVDQCuw0/BMA==
+SHA1-Digest: 0il8RgWn533JwK3upGQEtdYFiHg=
+
+Name: content/extensionApi.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: k0Kyim1SZXKto0vyj8CFEQ==
+SHA1-Digest: j7jpjymY7AduvGW/UV2gWQNmA80=
+
+Name: content/requestTracker.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: twuia7S9W7MU/KCOO+1RQQ==
+SHA1-Digest: Qp8ay5ZCdTYkeoiC+t95LYfJlXE=
+
+Name: content/json_sans_eval.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 66xp4EG+dv01png5tDCO5A==
+SHA1-Digest: h6P/13+YYcyenj2UryTojAUpl5o=
+
+Name: content/namespace.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: PrG45Oc+1nzq2s0UD02xbw==
+SHA1-Digest: fZkD1OGZxRyCrhuZTn9jLLyHHt8=
+
+Name: locale/en-US/contents.rdf
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: SbpsWMzLGiGC4IGfap+Omg==
+SHA1-Digest: 9lmGu5PDCWHiR0MIc7g3BsdBOg0=
+
+Name: locale/en-US/stumbleupon.dtd
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 9FZ6U39Bda5J+ZxIsZ2tFg==
+SHA1-Digest: 1as/L73SiwzcnmiOCn/BTwCJlzY=
+
+Name: locale/en-US/stumbleupon.properties
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 9tbNI1hq/FaXKM/0slSJRg==
+SHA1-Digest: ZB3Rna7Y3A2a8DNka0kGVxx80so=
diff --git a/META-INF/zigbert.rsa b/META-INF/zigbert.rsa
new file mode 100644
index 0000000..d45dfe8
Binary files /dev/null and b/META-INF/zigbert.rsa differ
diff --git a/META-INF/zigbert.sf b/META-INF/zigbert.sf
new file mode 100644
index 0000000..6908199
--- /dev/null
+++ b/META-INF/zigbert.sf
@@ -0,0 +1,762 @@
+Signature-Version: 1.0
+Created-by: XPISigner
+XPI-Signer-Version: 1.4 (free) http://o-regan.org
+Comments: PLEASE DO NOT EDIT THIS FILE. YOU WILL BREAK IT.
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: XRyG5I+7yK7gUBcu+ruhUw==
+SHA1-Digest: jCy5+JoYHOK2bTDMyVwpC3zlf00=
+
+Name: components/stumbleuponService.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: uJuji9+NN0f4c1B0yhn5fg==
+SHA1-Digest: +IPLuehuBZC4KKWBTfpSXuAnZl0=
+
+Name: install.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: SE2v9C9miOixNIMIDNsMtw==
+SHA1-Digest: rOoLGxUSseJl+e7bCIphNm6f+NI=
+
+Name: install.rdf
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: SMvPSduR00Yi6DKKDhhExg==
+SHA1-Digest: Db90f8XA9HwbagT/V4LJIyiJQkw=
+
+Name: chrome.manifest
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: JqAllbjPfeXukEUg0l/3qA==
+SHA1-Digest: GZttnqC4Y65nK1k152eBBjgEdys=
+
+Name: content/DatabaseConnection.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: tIUvflQmHo/N1ii68MIsCA==
+SHA1-Digest: G1ofXYTn7Ek2NxRKtWRlcJCUH4g=
+
+Name: content/contents.rdf
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: UO0qZwP9JcVcjeLkgwneCg==
+SHA1-Digest: UjWsf7YP4oV3C4e29ibq1Q91fGI=
+
+Name: content/datastore.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: LN2cR4zGVivGKkdcxEqsBQ==
+SHA1-Digest: gZN9wGFrX30NC/BlqGQPOxPIV48=
+
+Name: content/discoveryDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: HjKPs5EBTMhvIcgyu9BrOA==
+SHA1-Digest: hoztDaKDYpUnvjj10lCWFNfmmOI=
+
+Name: content/downloadFavsDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: yAXwkq7YxDbroJpjTa/WLA==
+SHA1-Digest: ip0FMaH6p8zBsyWORvLSC6Zs8yQ=
+
+Name: content/migrate.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: zqECKRRCLFJoJA9cJ917jw==
+SHA1-Digest: mFPccIMgUby2ma+4o3/4kGdNSzs=
+
+Name: content/moreChannelsDialog.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: IVhdaunsxYZ8yl3GYzCp/g==
+SHA1-Digest: v+kgmHwUWvAjLXW2T9QYXNiLsxA=
+
+Name: content/moreChannelsDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: j/iB0uJwVPydU7TRIkijWg==
+SHA1-Digest: xidIT73pspceAjv7YoxSd6kKyjY=
+
+Name: content/passwordDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 2W6U5rubUGACMJV6ZF3O7A==
+SHA1-Digest: GbfGYVV0x+T+7nJ8JHi6lKTiN5w=
+
+Name: content/positionDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: mNs+EnZqeUKi6RRQRFmvJg==
+SHA1-Digest: 9Kvw3v83Rjwz1eApmyt4oOps84Y=
+
+Name: content/preferenceDialog.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: lJG9H7VBhPw7njmJB9HggA==
+SHA1-Digest: 63g937K9pEikH/NuN1zlZJzcydQ=
+
+Name: content/preferenceDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 3pQ3OH4iEXh4xoP8wN5Fhg==
+SHA1-Digest: ijv4WDgA4habpGPrnCOZ/AEBtHI=
+
+Name: content/prefetcher.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: bqA9L1bSPtW7EBf0LqIIzA==
+SHA1-Digest: t8Mirl7AvewZGL1271kxe8YYVow=
+
+Name: content/ratingDialog.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: b8Enx2D+T4pZ35ALK1w2+A==
+SHA1-Digest: LAzMXVnTBKtB5l6p89Bi4AQWZYM=
+
+Name: content/ratingDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: kYc6r2oBZHol6idk4LYPww==
+SHA1-Digest: amjjSw/CQZ4HnXYWDn6yMZBTrt4=
+
+Name: content/reportTopicDialog.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: iZcO1V7jAAsV33TbCgaCzA==
+SHA1-Digest: NgRTGmhZ3ggBmZ7Y2MXir4bPiIM=
+
+Name: content/reportTopicDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: ozvxaRzT3s23khXAdRKR+w==
+SHA1-Digest: H+sa89MxuwwMHMkgxOgA2qm+V04=
+
+Name: content/searchDialog.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: exnDwFteazNAEPJT/jkvCA==
+SHA1-Digest: clYNDTekJN1k/97sqc56bw3FOoc=
+
+Name: content/searchDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: sF8oTWJ2Q7vsdTtYPtaarw==
+SHA1-Digest: pIRm7vLv0CtNH86V7Xc0kwLswoU=
+
+Name: content/searchlinksDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 3QQ10WQNvprxfk0xO2j5bw==
+SHA1-Digest: 9tKCq2hg2qD9oPsvyZxfK7lY0Fw=
+
+Name: content/sendDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: kmMNp2febOUxTyyqNiWrlw==
+SHA1-Digest: DLBlXSFNPv3OxwGcKzspx2CU78s=
+
+Name: content/sidebar.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: ycCeP+Fn/eDmoLdLHC8Juw==
+SHA1-Digest: /w5Z/e/62q6vj4RG677ZcpXsQmI=
+
+Name: content/sidebar.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: r8uSAfnYzgkXgy/PNMh3ow==
+SHA1-Digest: 4twb+86OfOZ/4nEpW7EHqLHjfEk=
+
+Name: content/sidebarOverlay.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: ABiYb16WMh6U0FImx0ec4Q==
+SHA1-Digest: x9DZ9+Z06nQQl3hnJQO7budN3UU=
+
+Name: content/signinDialog.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: DhYzkL2EEhCQP+7F+/03Lw==
+SHA1-Digest: jYxxOhxsXNuIizMcWyV+1UJ6m8I=
+
+Name: content/signinDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 31RpmyZKw6qb/dKdwy6krg==
+SHA1-Digest: 0Fnk6lzG2ZvH+CdJSbUorl+gNUw=
+
+Name: content/signoutDialog.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 3V907BaM6zh27bis8yedUQ==
+SHA1-Digest: P/wxnwq61ovvsD7Jl4q0zDiv+LU=
+
+Name: content/signoutDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: Y9t+ysOzYH57FeqHWshk0w==
+SHA1-Digest: MOCjVfq3fE4pyQaa2y7BJij5jxw=
+
+Name: content/skin/ChangePassword.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: NCe0CkHLHQgxso54lVp6YQ==
+SHA1-Digest: LlXNmx1HBd8jZXBWd9vfr7gwBfg=
+
+Name: content/skin/Throbber-small.gif
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: dEc9Os8CysGK8iAsAOX9SQ==
+SHA1-Digest: jFCz4VnxcEWCZJ/Ry1GLHE1VvJs=
+
+Name: content/skin/Throbber-small.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: TiBGi8Gz405GLajSeEzIRA==
+SHA1-Digest: /fWMUXNAcNmrT5O9UTzdWUNFiA8=
+
+Name: content/skin/aaaa.gif
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 4gtWsxp8olYeZdQB0zDUvw==
+SHA1-Digest: nBozHHWRkECPMcvoeJfeHDlxLBs=
+
+Name: content/skin/all.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: xoLDx3nYC/AF5KLtpJr5Dg==
+SHA1-Digest: cP6SdZysa5GKwbdMj6diEYFLw14=
+
+Name: content/skin/arrow.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 2nBSmKDgwgi5nfOlt+8t/A==
+SHA1-Digest: pdZnzvH7INuekpG+gQdFnzqQlC0=
+
+Name: content/skin/arrow_ani4-a.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: +0s5n+U3rwnzgXLyCL1r0w==
+SHA1-Digest: 98eLn3Y6nI4YNLNNB/QL9OBGZo4=
+
+Name: content/skin/arrow_ani4.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: /840fHmEAr7eC3vKoQgovg==
+SHA1-Digest: s4Zle6aFLlX2syODgFbeHrQP1u0=
+
+Name: content/skin/arrow_green-b.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 36ZAZ+CUqKkLxOu1P2TsgA==
+SHA1-Digest: cwyLBPdZnHJjG7FHUWh4YYqIsJI=
+
+Name: content/skin/arrow_green-c.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: WUq8/1n8jXrG4HK2zSQ4yw==
+SHA1-Digest: U7gTmjuNMBrCu1UL/qn+nLl9UV0=
+
+Name: content/skin/btn_turniton.gif
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: skWCXtUrVhdU1ZJ3CuS3tg==
+SHA1-Digest: JSjzGz4oT7FZOG6gb/wGLWDZgJc=
+
+Name: content/skin/bubble.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: EQNCaZPamd/ekOxUFHjoxA==
+SHA1-Digest: 5myMshLmVt40tExQjQzQxpDUJ+M=
+
+Name: content/skin/bubble1.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: D3YTQ/t3Req6IJLkgx16Kw==
+SHA1-Digest: BAiWxg1iNqyQqpqRWdnLhKtGmt4=
+
+Name: content/skin/bubble2.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: dPUJqHtSSlnE9gToKjuASA==
+SHA1-Digest: 97w/G4zNpCuO3OfqZw2oSL2thys=
+
+Name: content/skin/bubble3.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: hrDNs/FlRSIn1l2vdhOJVA==
+SHA1-Digest: Kl3l1F2h3Pf0PeAYesUqciHbfrY=
+
+Name: content/skin/bubblex.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: Zq6itNl2Z8izYt99paOuxg==
+SHA1-Digest: zozLIk8MEIJ/mRNinRxhC8VlcAw=
+
+Name: content/skin/bug.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: dKt25U986yP6RjLzzzSq/Q==
+SHA1-Digest: 94G5dq/jSKzjRWZMBJRlvX1N5gk=
+
+Name: content/skin/chevron.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: EMKXYI/h8Yk+nWvl7lzgZA==
+SHA1-Digest: 6ieofgBBwvD2e6A5+Y1VQZS/kSA=
+
+Name: content/skin/close-c.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: kaZjDih+wSoeNdidFXrxxw==
+SHA1-Digest: KGrQhhdkPSA5Dfc+Nz7G5QORnwE=
+
+Name: content/skin/close-d.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: VGnuvHFfWrn6W+1s051Fxw==
+SHA1-Digest: IcPjfxSmlR71hhRgD2LJmQkG3MI=
+
+Name: content/skin/close.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: SFMyT3cfEi760JgHVW3WOw==
+SHA1-Digest: lT1kNMIp8C6jt44vFgT0FrW223E=
+
+Name: content/skin/closetab-active.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: XM/uo2q6hh5znsJFoI4SSg==
+SHA1-Digest: 0GRZ1lXPh602i1Lsbqql6+dUaYw=
+
+Name: content/skin/closetab-hover.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 1n1oOSH70HSg7C177s59UA==
+SHA1-Digest: l7ga3hde/tFa203wy4ZB2uI4j+A=
+
+Name: content/skin/closetab.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: JqDmtmreOQB9RbifI8GO5g==
+SHA1-Digest: yApbPEesgynRPLLPnQIJnrNd938=
+
+Name: content/skin/comment.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: l5rd7fwuPGxYb0u/sdgX3w==
+SHA1-Digest: koSNQb/GzjpgIjiC60spwyVa4Pc=
+
+Name: content/skin/contents.rdf
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: bnuYIIqUhleTpfeXtUTfWg==
+SHA1-Digest: Qg6w8ssoMTIvP7D9v44iDUCs6gM=
+
+Name: content/skin/domain.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: vqcJePJjgiBQbtyPX1C1JA==
+SHA1-Digest: tvSVjnh/Y1V7/ZCIeq/qutDUj1A=
+
+Name: content/skin/editinfo.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: yof08i9rjDbBF/nyuoTfQA==
+SHA1-Digest: Wu7RaN1ZiD5Aty+iowgNi/HRyr8=
+
+Name: content/skin/facebook_share_icon.gif
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 9o8qmuQqaFjCtfV7Lph9jA==
+SHA1-Digest: rnoFKRCKPbMh2ZKEfVqKocuwEr0=
+
+Name: content/skin/favicon_aol.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: HhshFY5AoOg2V6j2X4j6uw==
+SHA1-Digest: kLzZssMkkUSKSCVVSbnHn47iv+c=
+
+Name: content/skin/favicon_ask.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 0k0QsbW7sHA0Rl/iezJSfg==
+SHA1-Digest: oqeAhjpYdlksJrtJS6WIQCv6s/4=
+
+Name: content/skin/favicon_facebook.gif
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: VkjKQr5RTACkM27dvEWAhg==
+SHA1-Digest: /+8PBd6ZE9nh1VyQTWVRtPsR4UI=
+
+Name: content/skin/favicon_flickr.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: WpePdawvgk8ia/cVdvduuA==
+SHA1-Digest: z5aWYLLKDkHGkIBb+3xUKekWMZE=
+
+Name: content/skin/favicon_google.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: zh40H+RhJhxFj0E3YYBmRA==
+SHA1-Digest: LpAe2TAtSh2qRZAn2oaSbuSoBLA=
+
+Name: content/skin/favicon_mslive.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: LqB495MOhVQFxzaoHjX97Q==
+SHA1-Digest: CzDJnYVhqcyeVXjhpdws0K8aQ8c=
+
+Name: content/skin/favicon_twitter.gif
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: nJlJIzCH1pZGiaixM/Gmsw==
+SHA1-Digest: SBFPeUg2D8HthcQoULesP6yTFVg=
+
+Name: content/skin/favicon_yahoo.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: Nx7DRkUYwnPg154W9Jo3rA==
+SHA1-Digest: V0/nrzBvBWPc2fG8y9Az1zb5Fgc=
+
+Name: content/skin/favicon_youtube.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: mkw3+x3iKmxbYzyoJPsRng==
+SHA1-Digest: 7oCWsgWl4SyvAeOh1cOdFWZYVRM=
+
+Name: content/skin/firstrater.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: XXXsSVUXeGzB6uh6JtIgkg==
+SHA1-Digest: I0dV5XuJJBAvopoNixcM5f28FLo=
+
+Name: content/skin/forum.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: ClXwDHvUNu9vutmckpLGww==
+SHA1-Digest: 7SU+YifwZXr9J48IN0Dpp+T41Js=
+
+Name: content/skin/friend.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: qeLl279zkpVm1CWkefyuOw==
+SHA1-Digest: XbHrSFcvRHGEJDmRGl8sgKM9M8k=
+
+Name: content/skin/g.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: nXufKuTKh64IqimzrrTakQ==
+SHA1-Digest: ciyl/Lavl7lzD3z3m2DlVuf1gu4=
+
+Name: content/skin/greenthumbdown.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: QuqdRPI49DRgJ69h29MTYQ==
+SHA1-Digest: rGXN8Zmp2f/dxWkAZv45rHTM2ek=
+
+Name: content/skin/greenthumbup.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: D8985BePkdCURDDwjk+jow==
+SHA1-Digest: karoyqUOwr5z62If/lQ1kJLawTE=
+
+Name: content/skin/greyman.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 5juIMfUD0hyuPhQt5KA+9A==
+SHA1-Digest: DCAJy+YuTLWCMgkturyNwxjjL7Y=
+
+Name: content/skin/groups.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 9lH2c5PHrFkHEZUa2U+u2Q==
+SHA1-Digest: aEAbzlPxgWkoB/rWrTZDXmILC+8=
+
+Name: content/skin/icon_signin.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: FecQGw3HhyzlR+suUxt3FA==
+SHA1-Digest: 9dXE+drimph5TMMiSAvApf1XL8w=
+
+Name: content/skin/icon_tb_favorites_hover.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: MDZ/gXZ7bZ8D+F2227vfGQ==
+SHA1-Digest: ZZNHCJrsIS7auxbZyeX9732WA4A=
+
+Name: content/skin/icon_tb_flag_blue.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: Gkc3akIfYElimlhW0qcZMg==
+SHA1-Digest: PGEV8J75mx+CdeiYZ0Xiq2+/obw=
+
+Name: content/skin/icon_tb_news.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: nsCj/Y9+vDBaMxflJOopFA==
+SHA1-Digest: 6ReCMux3JJi6ZAazRNpgcJQOkac=
+
+Name: content/skin/icon_tb_people.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: wHiMbwcPjc1CT93/72QN6A==
+SHA1-Digest: HY/1B33OOCXGXtQcMj/EjNgAUxc=
+
+Name: content/skin/icon_tb_photo_hover.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: R1lik3PkVgAt/3B2TnanBQ==
+SHA1-Digest: 5AvVGk9SqOPiuTFLsJ3O8BuDX14=
+
+Name: content/skin/icon_tb_search_user.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: X+v4VlpC4gFzQPoHlwKXvA==
+SHA1-Digest: +5WOwGNhuCPMf8OuZaCGT71EBkA=
+
+Name: content/skin/icon_tb_share.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 726mKkizkTcIvpxdQVOzPg==
+SHA1-Digest: LkD9Ccojpj79MRHvH+6NlhunAAQ=
+
+Name: content/skin/icon_tb_share2.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: Kkxl2UP1STIlNhwlkWZ/GA==
+SHA1-Digest: ngaVZHTJTY6wYSP4d5GbEvR7xN0=
+
+Name: content/skin/icon_tb_tag_left.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: bkF6MY82UoVdR+Jl+L/tKg==
+SHA1-Digest: Q/0LF9BZ5MbDZfBaMxJOL6im20g=
+
+Name: content/skin/icon_tb_user_comment.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: PaenK9l8niu1gTRoLaAY1g==
+SHA1-Digest: lZ8mE+a5MFGS4Zs/zpZtXSEE+gs=
+
+Name: content/skin/logo24.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: iaNclmIHyjRObsRV1vI8Fg==
+SHA1-Digest: PQJec2zjvaLXFaAYdeIOMSljo5c=
+
+Name: content/skin/logo32.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: rv+tysLqRnDfeHTl7GJlxw==
+SHA1-Digest: wFoGMlLpHY4RwbFMFY/OmkQGC9U=
+
+Name: content/skin/mail.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: cqItaYdDdUTn/Y09JLcE2g==
+SHA1-Digest: TuoGt49P0ZN+exW1VjLeYnexznU=
+
+Name: content/skin/mail2.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: fSulG9UCE12G1XL4jzr+vQ==
+SHA1-Digest: b8gmr+irn/Ilx7DfIP83xmPjgCY=
+
+Name: content/skin/mutual_favorites.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: wRcwcemVighhSMemXM5CHA==
+SHA1-Digest: 3YOsXfIGliZsOB3/IUzZUSrOZjM=
+
+Name: content/skin/point3.gif
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: kZ7nrcpRxkp+Y7hlc8ZW+g==
+SHA1-Digest: D5hyI1mCCxuJJtGu9xWrstqaBW8=
+
+Name: content/skin/preferenceDialog.css
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 0G/GC2q+PalILsl+Y9UTRw==
+SHA1-Digest: VmBHDoh+U+IfpRq2DFjkoxO24kE=
+
+Name: content/skin/profile.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: YlIzBDgW5H8Jrnsd5QVl0Q==
+SHA1-Digest: TrwVir1Kp8OXmItgChtK9JHmd6c=
+
+Name: content/skin/r.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: DSue0RsdxHhRWp1ZP4YiNA==
+SHA1-Digest: A/F+pC2kvfIcO8wbxelRYeiFqfk=
+
+Name: content/skin/ratingDialog.css
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 03eNu7z4wAV4tqmxK4JL+A==
+SHA1-Digest: i97frYoH57cN7HlGHl79PKRK5rE=
+
+Name: content/skin/redman.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 3JOhK2PdWLfR7bKloYcuzA==
+SHA1-Digest: 7vCemQOM9hjOCh/8Ui7v1mTNxAk=
+
+Name: content/skin/search.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: bcugJuA6t0APJhpUtVaRxQ==
+SHA1-Digest: csYHIIc4MAJsQ5yFqw9VVOV3dUc=
+
+Name: content/skin/searchDialog.css
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 5GXINuHfPcdZNTltajRS/Q==
+SHA1-Digest: /wbwBas0ZZEH9j4Dh1Uf9zTUaT4=
+
+Name: content/skin/smallbubble1.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 403KgUu1Wo47ogqZI4OD2Q==
+SHA1-Digest: QGOkz0nwBjlOTtMjzrMLLmW1gJw=
+
+Name: content/skin/smallbubble2.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: c/cae1dAtSLvDfoR0ipMkg==
+SHA1-Digest: o6muNneW2rZYurd81oJw41hEn78=
+
+Name: content/skin/smallbubble3.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: EGbAmHUEuIR74E/bl639OQ==
+SHA1-Digest: OO6gzXm1r4Rk/ImpjMdWThBO65c=
+
+Name: content/skin/smallgreenthumbup.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: tJHx6QjK025/N3hEDElZvA==
+SHA1-Digest: 57dY2aAomnasZrnbU36iPZmraRQ=
+
+Name: content/skin/smallgreythumbup.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: J/2OeunkLdrkHzp3UelQBg==
+SHA1-Digest: o2D9tC5COtfbSSyrDOC47hbZRUc=
+
+Name: content/skin/smallredman.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: wB7vvgdSHXAmcpncOlwmIQ==
+SHA1-Digest: 7e2qI1fALlpoEmZAhlBaMgt9oig=
+
+Name: content/skin/smallstumble.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: ADiqOENFPM9x595IfR8Jgw==
+SHA1-Digest: g1tNZTe0SfNLt7Mb+Y0mfvgiNsc=
+
+Name: content/skin/splitter.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: rSir3ChbdfHsBlvV760Szg==
+SHA1-Digest: qwKkSVSc/QmzBl8ZXDyJT7zkLCc=
+
+Name: content/skin/sponsor.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: rlwt9s4148BSoL0NhZirmQ==
+SHA1-Digest: EqL2O6fDAZC6/7zVdUPS2aaS7n0=
+
+Name: content/skin/sponsor_mac.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 6CrOf1/xQhMl590GDGRcKg==
+SHA1-Digest: tW4+rkoMZcZVOKjlf7ziLgXvo5Y=
+
+Name: content/skin/star.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: g6hxaFmMiyEIb6HMaeKNRA==
+SHA1-Digest: w2+i/kndVCQDIOLQHgorL/VOgrE=
+
+Name: content/skin/stopa.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: /MIIl3/xCUtpvli8RHbcRQ==
+SHA1-Digest: QxZtfisvMLsaeeYAJXdkW6HCtcA=
+
+Name: content/skin/stumble.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 7DqKShl49soML3j2Spnx1w==
+SHA1-Digest: P3c1z10/OvFQa/zAjWVGob8UQ5o=
+
+Name: content/skin/stumble2.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: rwwtuQ6l9rMqv2it3VoN1g==
+SHA1-Digest: gcuPb9LfVRRZ9Aa/qIR9l8hYbz8=
+
+Name: content/skin/stumbler_favorites.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 8J1MKlrXtc+ajcF28y3MuQ==
+SHA1-Digest: SZRFjOE93Cukjxzmmx8G3iOiro0=
+
+Name: content/skin/stumblers.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: E2ZllDOn9GpXXO0pZOt1pg==
+SHA1-Digest: enU6DSTRNc/nITFDzOTfki9NAoA=
+
+Name: content/skin/stumbleuponOverlay.css
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: JVugDj3bFhGp8TC8vtTehA==
+SHA1-Digest: 8gqijfEP5WDa4kKKmjD37gBnFWs=
+
+Name: content/skin/tag.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: yYsxHP0DBS6C5Sj1lNG+fQ==
+SHA1-Digest: r2B59SR+FffrvHZooU7EaYuMj9g=
+
+Name: content/skin/tag2.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: W3JOUp+saF2ipr7tMpOweQ==
+SHA1-Digest: 6bdcpQujYRSJsFxMJzm1KcrLlM8=
+
+Name: content/skin/taggingDialog.css
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: eIvs1/dGwioQy4+5o333gg==
+SHA1-Digest: suPRxhvyILjOFt+Be3z94ktF1nY=
+
+Name: content/skin/tbgrip-texture-12px.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: wdtXOFjPAwMZ1FvJuqF5qg==
+SHA1-Digest: HzzMpAf3E41ptNdqnCgroyZB5kU=
+
+Name: content/skin/thumbdown.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 8KZeTSdQSiBoTyTL3x45/g==
+SHA1-Digest: VEE8r90qhPvFUVzVW9ZBOg5f04o=
+
+Name: content/skin/thumbup.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: VLZgRf7CrDHtHo90DEgp4Q==
+SHA1-Digest: bbaN4cNZA1PFFOORzEprkXSxgfY=
+
+Name: content/skin/thumbupcomment.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: kx5R+og1OZkLuCSfgF19Rg==
+SHA1-Digest: JZGjcWGCG/WnMpF+D9eSButUbpk=
+
+Name: content/skin/toggle_preview.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 2KsaXAQOPIga45C80koMyA==
+SHA1-Digest: mDKu/aD6r9+ch/DufvBB1RsfrPw=
+
+Name: content/skin/topic.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: +Ulz1xCaolmUCeMXAeKYcw==
+SHA1-Digest: OItwezdOE8SWWik2Foxm3NoCfO8=
+
+Name: content/skin/upgrade.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: RzyP5Lbe7hMfEwhqOxCi6A==
+SHA1-Digest: jmQqg3BD/xYPE+nU92g1qsNWfvo=
+
+Name: content/skin/video.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: t7JCkrSVgnm+P01NaHjPJg==
+SHA1-Digest: CQ6APOQ3Kg/Ef8binpVPmRIeBOY=
+
+Name: content/skin/widgets.css
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: E1Hlt+p/erkwxBSvD8z49A==
+SHA1-Digest: DxGQCcWJT3BhlyOcnilGxwOIvwA=
+
+Name: content/skin/wiki.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: DtENJSQLot4e12yPLAdw1Q==
+SHA1-Digest: ypzKSN1/MxB9xy5F0V3A8vyVLgc=
+
+Name: content/skin/x.png
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: NM6MQGK7PMu8QPXpjpmuAQ==
+SHA1-Digest: 7VtoacLnEqpuWQn6amMzKqr/XIE=
+
+Name: content/stumbleReporter.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: TqW6VlOLtBg9BoVIv+IodA==
+SHA1-Digest: 34BHK8G0Pz/U8dhRlpAhfCTSWcM=
+
+Name: content/stumbleuponOverlay.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: Dj44Nl6jxTP/UgOhJ6hBKA==
+SHA1-Digest: tTBhsnYxg+AvuMH6QJyT+0Hp4qA=
+
+Name: content/stumbleuponOverlay.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: +DiOkSnSWxdP43nFHP6pJQ==
+SHA1-Digest: Vfa5q2jqm8fFqvbcbSoE5JHBf48=
+
+Name: content/taggingDialog.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 5v+2zKe4iz0fss3WwYGSqA==
+SHA1-Digest: tfb3zuaXtWu9QyLyKqZp7X43GEU=
+
+Name: content/taggingDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: dVVkPuAxFzDMV29j5CGHgw==
+SHA1-Digest: lzZKQl51DlpDTUvUCx23yd78vFg=
+
+Name: content/tldEmulation.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: CM4Qj5DB9OOGcGDMZXIK8Q==
+SHA1-Digest: PlHVFo2luXKAQVF/Ak4Xl+JLcMo=
+
+Name: content/topics.csv
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: cMZnJVYU6Y0LgHMCrVSieg==
+SHA1-Digest: DvvPfYytcIZeYD2a10TMHj/wXT8=
+
+Name: content/uninstallDialog.xul
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: HC3zkAyVKi8EN/FOWmu/2w==
+SHA1-Digest: 5ugWtJtEJJCOCzTE2kYbd7qtqEI=
+
+Name: content/userdb.sql
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: yFRvn+f1a2MQD7GDbuyy9w==
+SHA1-Digest: DFQyeryrzbNl8kt00TJVqcwNfMY=
+
+Name: content/widgets.xml
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: i+0NvDRX2O4jo+8f74maxQ==
+SHA1-Digest: zfwcH+7SUUwzrsa1ocJoNu1TwK4=
+
+Name: content/initOverlay.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: KS51iQ+eruEguRs0edmQQw==
+SHA1-Digest: WQYJTsKVcZXtza483qyUSbqWa+g=
+
+Name: content/extensionApi.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: 9OO9SFiaRcOWLzbIAg2L5A==
+SHA1-Digest: aEunVz2t2FJv7LVFBJs8Cfr7sv4=
+
+Name: content/requestTracker.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: KEH6Iqjkj9MQtUWH3d4UTg==
+SHA1-Digest: nMoGIGrzAucfpQhvS/qaVYNqFto=
+
+Name: content/json_sans_eval.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: Mf2RmiDtcnOV3VPC31LbAw==
+SHA1-Digest: QhN8D97M3LjOLHkUnsIhhry4pKg=
+
+Name: content/namespace.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: TGKviVxLtY5fSLV53lHr0Q==
+SHA1-Digest: bA8Rt1E1iYLb3jLXMmqT4dx2n5w=
+
+Name: locale/en-US/contents.rdf
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: VhwQhNReFuCNfb8waDyxsQ==
+SHA1-Digest: qSYdWfRMDFyO8tizhy09yHVJWnc=
+
+Name: locale/en-US/stumbleupon.dtd
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: dlo0aavy6o/KWmVXqtwi4Q==
+SHA1-Digest: WgvpBzFcr/DdiF3DqoRLOxpMvDQ=
+
+Name: locale/en-US/stumbleupon.properties
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: ytx2WCqr0nhJf+wBe6aZiQ==
+SHA1-Digest: bxbk4it7WsnOCdUattZ1u20ZfF4=
diff --git a/chrome.manifest b/chrome.manifest
index 33c92f8..3dcf61c 100644
--- a/chrome.manifest
+++ b/chrome.manifest
@@ -1,13 +1,12 @@
-
-overlay	chrome://navigator/content/navigator.xul	chrome://stumbleupon/content/stumbleuponOverlay.xul
-overlay	chrome://browser/content/browser.xul	chrome://stumbleupon/content/stumbleuponOverlay.xul
-content	stumbleupon	jar:chrome/stumbleupon.jar!/content/
-content	stumbleupon	jar:chrome/stumbleupon.jar!/content/ contentaccessible=yes
-
-skin	stumbleupon	classic/1.0	jar:chrome/stumbleupon.jar!/content/skin/
-style	chrome://browser/content/browser.xul	chrome://stumbleupon/skin/stumbleuponOverlay.css
-style	chrome://global/content/customizeToolbar.xul	chrome://stumbleupon/skin/stumbleuponOverlay.css
-
-locale	stumbleupon	en-US	jar:chrome/stumbleupon.jar!/locale/en-US/
-
-locale	stumbleupon	fr-FR	jar:chrome/stumbleupon.jar!/locale/fr-FR/
+overlay chrome://navigator/content/navigator.xul chrome://stumbleupon/content/stumbleuponOverlay.xul
+overlay chrome://browser/content/browser.xul chrome://stumbleupon/content/stumbleuponOverlay.xul
+content stumbleupon content/
+content stumbleupon content/ contentaccessible=yes
+skin stumbleupon classic/1.0 content/skin/
+locale stumbleupon en-US locale/en-US/
+style	chrome://browser/content/browser.xul chrome://stumbleupon/skin/stumbleuponOverlay.css
+style	chrome://global/content/customizeToolbar.xul chrome://stumbleupon/skin/stumbleuponOverlay.css
+component {b97c288d-917d-4d26-bd24-3adf14f5aea3} components/stumbleuponService.js
+contract @stumbleupon.com/stumbleupon-service;1 {b97c288d-917d-4d26-bd24-3adf14f5aea3}
+category profile-after-change StumbleUponService @stumbleupon.com/stumbleupon-service;1
+
diff --git a/chrome/stumbleupon.jar!/content/migrate.js b/chrome/stumbleupon.jar!/content/migrate.js
deleted file mode 100644
index 2299d60..0000000
--- a/chrome/stumbleupon.jar!/content/migrate.js
+++ /dev/null
@@ -1,875 +0,0 @@
-
-function su_migrate_version()
-{
-	var had_version = su_ds.isPrefDefined("@client_version");
-	var prev_version = su_ds.getPrefValue("@client_version", su_useragent);
-	if (had_version && (prev_version == su_useragent))
-		return;
-	su_ds.setValue("@client_version", su_useragent);
-	
-	// After upgrading, this routine gets run once.  For a new migration
-	// routine:
-	// 1: Create a M_[identifier] constant using the next sequential bit
-	// 2: OR that bit with the others in the 'if (su_new_install)' block
-	// 3: Add the migration routine near the bottom, as indicated by the
-	//    comment there.
-	// 4: Gate the migration routine using the bit.
-	// 5: Be sure to OR the bit at the end of the migration routine.
-
-	const M_PASSWORDS = 0x1;
-	const M_IDS = 0x2;
-	const M_POSITION = 0x4;
-	const M_PREFS_DB = 0x8;
-	const M_V3_27 = 0x10;
-	
-	if (su_new_install)
-	{
-		su_ds.setValue("@client_migration_state", M_PASSWORDS | 
-					M_IDS | M_POSITION | M_PREFS_DB | M_V3_27);
-		su_ds.flushPrefs();
-		return;
-	}
-
-	su_new_upgrade = true;
-	su_prev_version = prev_version;
-	su_ds.setValue("@report_error_count", 0);
-	su_ds.setValue("@report_error_count_max", 3);
-	if (! su_ds.isPrefDefined("@dd_display_message"))
-		su_ds.setValue("@dd_display_message", false);
-	
-	var migration_bitfield = su_ds.getValue("@client_migration_state");
-
-	try {  // migration can be tricky, so we do a try
-
-	
-	if (! (migration_bitfield & M_PASSWORDS))
-	{
-		// Clear passwords left by old versions.
-		su_migrate_clear_old_passwords();
-		migration_bitfield |= M_PASSWORDS;
-	}
-
-	if (! (migration_bitfield & M_IDS))
-	{
-		// Fix a bug in version 2.81.
-		if ((su_ds.getPrefType("stumble.ids") == "Bool") && (stumbleid != 0))
-			su_ds.setValue("@id_list", stumbleid + ":");
-		else if (su_ds.getPrefType("stumble.ids") == "Char")
-			su_ds.setValue("@id_list", su_ds.getValue("stumble.ids"));
-
-		su_ds.clearPref("stumble.ids");
-		migration_bitfield |= M_IDS;
-	}
-
-	if (! (migration_bitfield & M_POSITION))
-	{
-		// Clear passwords left by old versions.
-		su_migrate_toolbar_position_scheduled = true;
-		migration_bitfield |= M_POSITION;
-	}
-
-	if (! (migration_bitfield & M_PREFS_DB))
-	{
-		// version 3.05
-		try {
-			su_migrate_contacts_to_prefs();
-		}
-		catch (e) {
-			setTimeout(su_migrate_contacts_to_prefs_delayed, 8000);
-		}
-		migration_bitfield |= M_PREFS_DB;
-	}
-	
-	if (! (migration_bitfield & M_V3_27))
-	{
-		su_ds.setValue("@enable_db_backup", false);
-		
-		migration_bitfield |= M_V3_27;
-	}
-	
-	// Add each new version migration routine immediately above.
-
-	} catch (e) { try { su_log_error("MIGRATE VERSION", e); } catch (ee) {} }
-
-	su_ds.setValue("@client_migration_state", migration_bitfield)
-	su_ds.flushPrefs();
-}
-
-// used during init to handle version-specific migration
-function su_migrate_profile(new_profile)
-{
-	setTimeout(su_migrate_places, 0);
-	
-	var had_version = su_ds.isPrefDefined("$version");
-	var prev_version = su_ds.getPrefValue("$version", su_useragent);
-	if (had_version && (prev_version == su_useragent))
-		return;
-	su_ds.setValue("$version", su_useragent);
-
-	// After upgrading, this routine gets run once for each profile,
-	// upon the first use of that profile.  For a new migration routine:
-	// 1: Create a M_[identifier] constant using the next sequential bit
-	// 2: OR that bit with the others in the 'if (su_new_install)' block
-	// 3: Add the migration routine near the bottom, as indicated by the
-	//    comment there.
-	// 4: Gate the migration routine using the bit.
-	// 5: Be sure to OR the bit at the end of the migration routine.
-
-	// note: maximum positive bit for pref storage is 0x40000000
-	const M_USERAGENT = 0x1;
-	const M_SHORTCUTS = 0x2;
-	const M_MENU_DEPTH_25 = 0x4;
-	const M_INTRO_COUNT = 0x8;
-	const M_JSON_CONTACTS_AND_MENU_DEPTH_16 = 0x10;
-	const M_HIDE_TAG = 0x20;
-	const M_FIX_JSON_CONTACTS = 0x40;
-	const M_REFRESH_AVATARS = 0x80;
-	const M_INIT_AND_MERGE_BUTTONS = 0x100;
-	const M_V3_11 = 0x200;
-	const M_V3_15 = 0x400; // 0x400:1024 0x7FF:2047
-	const M_V3_16 = 0x800;
-	const M_V3_17 = 0x1000;
-	const M_V3_22 = 0x2000;
-	const M_V3_27 = 0x4000;
-	const M_V3_27A = 0x8000;
-	const M_V3_27B = 0x10000;
-	const M_V3_41  = 0x20000;
-	const M_V3_41B = 0x40000;
-	const M_V3_51  = 0x80000;
-	const M_V3_51B = 0x100000;
-	
-	if (su_new_install || new_profile)
-	{
-		su_ds.setValue("$migration_state", M_USERAGENT | M_SHORTCUTS | 
-					M_MENU_DEPTH_25 | M_INTRO_COUNT | 
-					M_JSON_CONTACTS_AND_MENU_DEPTH_16 | M_HIDE_TAG |
-					M_FIX_JSON_CONTACTS | M_REFRESH_AVATARS | 
-					M_INIT_AND_MERGE_BUTTONS | M_V3_11 | M_V3_15 | M_V3_16 |
-					M_V3_17 | M_V3_22 | M_V3_27 | M_V3_27A | M_V3_27B |
-					M_V3_41 | M_V3_41B | M_V3_51 | M_V3_51B);
-		su_ds.flushPrefs();
-		return;
-	}
-
-	var migration_bitfield = su_ds.getValue("$migration_state");
-	
-	try {  // migration can be tricky, so we do a try
-
-	
-	if (! (migration_bitfield & M_USERAGENT))
-	{
-		// Reset the useragent of pre-1.9996 clients.
-		if (su_ds.isPrefDefined("general.useragent.vendorSub") &&
-					(su_ds.getValue("general.useragent.vendorSub").indexOf("StumbleUpon") != -1))
-			su_ds.clearPref("general.useragent.vendorSub");
-		migration_bitfield |= M_USERAGENT;
-	}
-	
-	if (! (migration_bitfield & M_SHORTCUTS))
-	{
-		// version <=2.7
-		if (su_host.win)
-			su_migrate_shortcuts();
-		migration_bitfield |= M_SHORTCUTS;
-	}
-
-	if (! (migration_bitfield & M_MENU_DEPTH_25))
-	{
-		// version 2.84
-		su_ds.setValue("$sendtos_menu_depth", 25);
-		migration_bitfield |= M_MENU_DEPTH_25;
-	}
-
-	if (! (migration_bitfield & M_INTRO_COUNT))
-	{
-		// version 2.87
-		su_ds.setValue("$intro_count", 15);
-		migration_bitfield |= M_INTRO_COUNT;
-	}
-	
-	if (! (migration_bitfield & M_JSON_CONTACTS_AND_MENU_DEPTH_16))
-	{
-		// version 2.90
-		su_ds.migrateToContacts();
-		su_ds.setValue("$sendtos_menu_depth", 16);
-		su_ds.flushPrefs();
-		migration_bitfield |= M_JSON_CONTACTS_AND_MENU_DEPTH_16;
-	}
-
-	if (! (migration_bitfield & M_HIDE_TAG))
-	{
-		su_ds.setValue("$show_tag", false);
-		migration_bitfield |= M_HIDE_TAG;
-	}
-	
-	if (! (migration_bitfield & M_FIX_JSON_CONTACTS))
-	{
-//		su_ds.fixJSONContacts(false);
-		migration_bitfield |= M_FIX_JSON_CONTACTS;
-	}
-
-	if (! (migration_bitfield & M_REFRESH_AVATARS))
-	{
-		su_ds.setValue("$has_avatars", false);
-		migration_bitfield |= M_REFRESH_AVATARS;
-	}
-	
-	if (! (migration_bitfield & M_INIT_AND_MERGE_BUTTONS))
-	{
-		// version 3.07 / 3.08
-		su_ds.setValue("$show_groups", su_ds.getValue("$show_groups") || 
-					su_ds.getValue("$show_forums"));
-		su_ds.setValue("$show_aboutme", su_ds.getValue("$show_aboutme") ||
-					su_ds.getValue("$show_mystumblers"));
-
-		su_ds.setValue("$shown_find_friends", true);
-		
-		migration_bitfield |= M_INIT_AND_MERGE_BUTTONS;
-	}
-	
-	if (! (migration_bitfield & M_V3_11))
-	{
-		// version 3.11
-		if (su_host.dist)
-			su_ds.setValue("$show_mode_wiki", true);
-		
-		var show_searchlinks = su_ds.getValue("$show_searchlinks"); 
-		su_ds.setValue("$show_searchlinks_score", show_searchlinks);
-		su_ds.setValue("$show_searchlinks_friends", show_searchlinks);
-		su_ds.setValue("$show_searchlinks_topic", show_searchlinks);
-		su_ds.setValue("$shown_searchlinks", show_searchlinks);
-		su_ds.setValue("$show_searchlinks_logo", su_ds.getValue("$searchlink_logos"));
-		// pitch social searchlinks to people who have searchlinks disabled
-		
-		su_ds.setValue("$autocomplete_type", "tag,query");
-		
-		su_ds.setValue("$show_flag", su_ds.getValue("$show_tag"));
-		
-		su_get_state(true);
-		
-		if (su_ds.isPrefDefined("$stumblestats") &&
-					(su_ds.getValue("$stumblestats") != ""))
-		{
-			var stumblestats = su_ds.getValue("$stumblestats");
-	
-			var stumbletypes = "";
-			var stumblereferrals = "";
-			var first = 0;
-			var splitseen = stumblestats.split(".");
-			var i;
-			for (i = 0; i < splitseen.length; i++)
-			{
-				if (first == 0)
-				{
-					first = 1;
-				}
-				else
-				{
-					stumbletypes += ".";
-					stumblereferrals += ".";
-				}
-				stumbletypes += "0";
-			}
-			
-			// most profiles were migrated when this was in load_data1()
-			if (! su_ds.isPrefDefined("$stumbletypes"))
-				su_ds.setValue("$stumbletypes", stumbletypes);
-			
-			su_ds.setValue("$stumblereferrals", stumblereferrals);
-		}
-		
-		su_check_dyn_channels();
-		
-		migration_bitfield |= M_V3_11;
-	}
-
-	if (! (migration_bitfield & M_V3_15))
-	{
-		// version 3.15
-		
-		su_ds.enableFeature("$sociallinks");
-		
-		// remove ancient legacy contacts
-		var contacts = su_ds.getValue("$contacts");
-		var i;
-		for (i = 0; i < contacts.length; i++)
-		{
-			var contact = contacts[i];
-			if (contact.nickname && (! contact.contactid) &&
-						(typeof(contact.fbid) == "undefined"))
-				su_ds.deleteRow(contact);
-		}
-		
-		migration_bitfield |= M_V3_15;
-	}
-		
-	if (! (migration_bitfield & M_V3_16))
-	{
-		var tmpstr = su_ds.getValue("$process_rarely_timestamp");
-		if (tmpstr == "")
-			su_ds.setValue("$process_rarely_timestamp", "0");
-		
-		su_check_dyn_channels();
-		
-		migration_bitfield |= M_V3_16;
-	}
-
-	if (! (migration_bitfield & M_V3_17))
-	{
-//		if (su_ds.getValue("$shown_find_friends_time_s") == 0)
-//			su_ds.setValue("$shown_find_friends_time_s", 2);
-		su_ds.setValue("$show_tag", false);
-		su_ds.setValue("$show_flag", false);
-		su_get_state(true);
-		clear_stumbles();
-		migration_bitfield |= M_V3_17;
-	}
-
-	if (! (migration_bitfield & M_V3_22))
-	{
-		su_migrate_check_shared();
-		if (su_ds.isPrefDefined("$referral_count"))
-		{
-			su_ds.setValue("$undelivered_count", parseInt(su_ds.getValue("$referral_count")));
-			su_ds.clearPref("$referral_count");
-		}
-		
-		su_get_state(true);
-
-		migration_bitfield |= M_V3_22;
-	}
-	
-	if ((! (migration_bitfield & M_V3_27A))
-			|| (! (migration_bitfield & M_V3_27B)))
-	{
-		su_ds.setValue("$show_legacy_network", false);	
-		
-		su_ds.setValue("$migrate_places_state", "a");
-		
-		migration_bitfield |= M_V3_27A;
-		migration_bitfield |= M_V3_27B;
-	}
-	
-	if (! (migration_bitfield & M_V3_41))
-	{
-		// Turn the comment icon off by default.
-		su_ds.setValue("$show_searchlinks_comment_icon", false);
-		migration_bitfield |= M_V3_41;
-	}
-	
-	if (! (migration_bitfield & M_V3_41B))
-	{
-		// No longer add ourselves to the noscript whitelist and XSS 
-		// exception list by default.
-		su_ds.setValue("@whitelist_upon_load", false);
-		migration_bitfield |= M_V3_41B;
-		
-		// For existing users we treat the "user_changed" values as true
-		// so we don't change preferences that they may have set explicitly.
-		su_ds.setValue("$show_info_user_changed", true);
-		su_ds.setValue("$show_referral_user_changed", true);
-		su_ds.setValue("$show_home_user_changed", true);
-		su_ds.setValue("$show_friends_user_changed", true);
-	}
-
-	if (! (migration_bitfield & M_V3_51))
-	{
-		// Turn the search links topic off by default, even for existing users.
-		su_ds.setValue("$show_searchlinks_topic", false);
-		migration_bitfield |= M_V3_51;
-	}
-	
-	if (! (migration_bitfield & M_V3_51B))
-	{
-		// If they haven't changed the old default channel button configuration
-		// then remove the channel buttons
-		var modesChanged = false;
-
-		var oldDefaultModes = [ 
-			[ "$show_mode_friends", true ],
-			[ "$show_mode_more", true ],
-			[ "$show_mode_news", true ],
-			[ "$show_mode_photo", true ],
-			[ "$show_mode_search", false ],
-			[ "$show_mode_stumblers", false ],
-			[ "$show_mode_video", true ],
-			[ "$show_mode_wiki", false ]
-		];
-		
-		for(var i=0; i<oldDefaultModes.length; i++)
-		{
-			var entry = oldDefaultModes[i]
-			if(su_ds.getValue(entry[0]) != entry[1])
-			{
-				modesChanged = true;
-				break;
-			}
-		}
-
-		if(!modesChanged)
-		{
-			// Check whether they have added any "thru" domain buttons
-			var thruChannels = su_ds.getThruDomainChannels();
-			for(var i=0; i<thruChannels.length; i++)
-			{
-				if(thruChannels[i].show)
-				{
-					modesChanged = true;
-					break;
-				}
-			}
-		}
-		
-		// If they haven't changed the old default settings, then remove the
-		// channels button section
-		if(!modesChanged)
-		{
-			su_ds.setValue("$show_mode", false);
-			// But make sure the channels selector menu is visible
-			su_ds.setValue("$show_topics", true);
-			
-		}
-		migration_bitfield |= M_V3_51B;
-	}
-
-	// Add each new profile migration routine immediately above.
-
-	} catch (e) { try { su_log_error("MIGRATE PROFILE", e); } catch (ee) {}}
-	
-	su_ds.setValue("$migration_state", migration_bitfield)
-	su_ds.flushPrefs();
-}
-
-function su_migrate_places()
-{
-	if (! su_host.places)
-		return;
-	
-	var state = su_ds.getValue("$migrate_places_state");
-	
-	if (state == "d")
-		return;
-	
-	if (su_ds.getValue("#migrating_places"))
-		return;
-	
-	su_ds.setValue("#migrating_places", true);
-	
-	var context = new Object();
-	context.ratings_str = null;
-	context.processed_key = null;
-	context.processed_idx = null;
-	context.state = state;
-	context.unrated_rows = null;
-	setTimeout(function (win, context) { win.su_migrate_places2(context) }, 0, window, context);
-}
-
-function su_migrate_places2(context)
-{
-	var new_state = context.state;
-	var migrate_file;
-	var db;
-	var result;	
-	var row;
-	var url;
-	var urlid;
-	var rating;
-	var legacy_rating;
-	var has_bookmark;
-	var has_thumbup_tag;
-	var bookmarked;
-	var sql;
-	var ts;
-	var parts;
-	var lines;
-	var urls;
-	var i;
-	var j;
-	switch (context.state)
-	{
-		case "a":
-			// 1. load ratings and backup places
-			context.ratings_str = su_read_file_user("stumblerating");
-			su_backup_places("MIGRATEPLACES BACKUP");
-			new_state = "b";
-			break;
-		case "b":
-			// 2. backup ratings
-			if (! context.ratings_str)
-				context.ratings_str = su_read_file_user("stumblerating");
-			migrate_file = su_ds.getResourceNSIFile("temp", "migraterating" + su_ds.userid);
-			su_ds.writeFile(migrate_file, context.ratings_str);
-			su_ratings = null;
-			new_state = "c";
-			break;
-		case "c":
-			// 3. initialize ratings and processed_idx if necessary
-			if (! su_ratings)
-				su_load_ratings();
-			
-			db = su_ds.getDatabase();
-			if (! context.processed_key)
-				context.processed_key = su_ds.getValue("$migrate_places_key");
-			
-			if (! context.url_rows)
-			{
-				sql = "SELECT urlid,rating FROM url WHERE urlid>" + db.q(context.processed_key) + " ORDER BY urlid LIMIT 1000";
-				context.url_rows = db.query(sql);
-				context.processed_idx = 0;
-			}
-			
-			// 4. check whether we're done
-			if (context.url_rows.length == 0)
-			{
-				context.processed_key = "";
-				context.processed_idx = 0;
-				su_ds.setValue("$migrate_places_key", "");				
-				su_ds.setValue("$migrate_places_idx", 0);
-				su_ds.setValue("#migrating_places", false)
-				new_state = "d";
-				setTimeout(su_download_favs, 0, false);
-				setTimeout(su_process_command_queue, 0);
-				break;
-			}
-			
-			rating = context.url_rows[context.processed_idx].rating;
-			urlid = context.url_rows[context.processed_idx].urlid;
-			
-			context.processed_key = urlid;
-			
-			// 5. save progress periodically
-			if ((context.processed_idx % 100) == 0)
-			{
-				su_ds.setValue("$migrate_places_key", urlid);
-				su_ds.flushPrefs();
-			}
-			
-			context.processed_idx++;
-
-			if (context.url_rows.length == context.processed_idx)
-			{
-				context.url_rows = null;
-				context.processed_idx = 0;
-			}
-			
-			// 6. get urls and legacy rating for this urlid
-			sql = "SELECT url FROM url_map WHERE urlid=" + db.q(urlid);
-			rows = db.query(sql);
-			if (rows.length == 0)
-				break; // shouldn't happen
-			
-			legacy_rating = null;
-			urls = new Array();
-			while (row = rows.shift())
-			{
-				urls.push(row.url);
-				if (((typeof su_ratings[row.url]) != "undefined")
-						&& (legacy_rating != 1)) // prefer thumbup over thumbdown
-					legacy_rating = su_ratings[row.url];
-			}
-			
-			ts = su_ds.getTaggingService();
-			
-			// 7. check existing bookmarks and tags
-			has_bookmark = false; 
-			has_thumbup_tag = false;
-			for (i = 0; i < urls.length; i++)
-			{
-				url = urls[i];
-				nsiuri = su_get_nsiuri(url);
-				tags = ts.getTagsForURI(nsiuri, []);
-				bookmarked = su_is_bookmarked(nsiuri);
-				
-				has_bookmark = has_bookmark || bookmarked;
-				for (j = 0; j < tags.length; j++)
-				{
-					if (tags[j] == "SU")
-					{
-						has_thumbup_tag = true;
-						break;
-					}
-				}
-				
-				// 7a. if the url isn't bookmarked, nuke spurious tags
-				if (tags.length && (! bookmarked))
-					ts.untagURI(nsiuri, tags);
-			}
-			
-			// 8. update ratings
-			if (has_bookmark && has_thumbup_tag && (rating != 1))
-			{
-				// bookmarked with SU tag gets thumbup
-				sql = "UPDATE url SET rating=1 WHERE urlid=" + db.q(urlid); 
-				db.query(sql);
-			}
-			else if ((legacy_rating != null) && (legacy_rating != rating))
-			{
-				// legacy rating overrides db rating
-				sql = "UPDATE url SET rating=" + db.v(legacy_rating) + " WHERE urlid=" + db.q(urlid);
-				db.query(sql);
-			}
-			else if ((legacy_rating == null) && (rating == 0))
-			{
-				// unrate thumbdowns that don't have a legacy_rating
-				sql = "UPDATE url SET rating=-1 WHERE urlid=" + db.q(urlid);
-				db.query(sql);
-			}
-			
-			break;
-	}
-	
-	if (context.state != new_state)
-	{
-		context.state = new_state;
-		su_ds.setValue("$migrate_places_state", new_state);
-		su_ds.flushPrefs();
-	}
-	
-	if (new_state != "d")
-		setTimeout(function (win, context) { win.su_migrate_places2(context) }, 0, window, context);
-}
-
-function su_migrate_check_shared()
-{
-	var contacts = su_ds.getValue("$contacts");
-	var share_count = 0;
-	var i;
-	for (i = 0; i < contacts.length; i++)
-	{
-		if (contacts[i].referral_count)
-			share_count += contacts[i].referral_count;
-		
-		if (share_count >= 2)
-			break;
-	}
-	
-	if (share_count >= 1)
-		su_ds.setValue("$poll_state", "f");
-	
-	if (share_count >= 2)	
-		su_ds.setValue("$shown_referral_info", true);
-}
-
-function su_migrate_contacts_to_prefs_delayed()
-{
-	try {
-		su_migrate_contacts_to_prefs();
-	}
-	catch (e) {
-		su_log_error("MIGRATE CONTACT_DELAYED", e);
-		return;
-	}
-	
-	if (stumbleid == 0);
-		return;
-	
-	su_invoke_global_event("refresh-referral-menu", null);
-}
-
-function su_migrate_contacts_to_prefs()
-{
-	var file = su_ds.getResourceNSIFile(null, "json_db")
-	if (! file.exists())
-		return;
-	
-	var db = su_ds.deserialize(su_ds.readFile(file));
-	if (! db)
-		return;
-	
-	var ids = su_ds.getValue("@id_list").split(":");
-	var i;
-	for (i = 0; i < ids.length; i++)
-	{
-		if (ids[i] == "")
-			continue;
-		
-		if (! db[ids[i]])
-			continue;
-		
-		if (! db[ids[i]]["contact"])
-			continue;
-
-
-		var names = su_ds.getPrefNames("stumble." + ids[i] + ".c.");
-		if (! names)
-			return;
-		
-		var pref_contacts = new Array();
-		var k;
-		for (k = 0; k < names.length; k++)
-			pref_contacts.push(su_ds.deserialize(su_ds.getValue(names[k])));
-
-		
-		var contacts = db[ids[i]]["contact"];
-		if (! contacts.constructor != Array)
-		{
-			// convert to array
-			var a = new Array();
-			var p;
-			for (p in contacts)
-			{
-				if ((typeof (contacts[p])) == "function")
-					continue;
-				
-				if ((typeof (contacts[p])) == "undefined")				
-					continue;
-				
-				if (contacts[p].constructor == Object)
-					a.push(contacts[p]);
-			}
-			contacts = a;
-		}
-		
-		var j;
-		var contact;
-		for (j = 0; j < contacts.length; j++)
-		{
-			var pref_contact = null;
-			if (contacts[j].nickname)
-			{
-				pref_contact = su_get_row(
-							pref_contacts,
-							"nickname",
-							contacts[j].nickname);
-			}
-			else if (contacts[j].email)
-			{
-				pref_contact = su_get_row(
-							pref_contacts,
-							"email",
-							contacts[j].email);
-			}
-			else
-			{
-				continue;
-			}
-			
-			if (pref_contact)
-			{
-				contacts[j]._r = pref_contact._r;
-			}
-			else
-			{
-				var autoinc_name = "stumble." + ids[i] + ".c_ai";
-				contacts[j]._r = su_ds.getPrefValue(autoinc_name, 0);
-				su_ds.setValue(autoinc_name, (contacts[j]._r + 1));
-			}
-			contacts[j]._t = "c";
-			var name = "stumble." + ids[i] + ".c." + contacts[j]._r;
-			su_ds.setValue(name, su_ds.serialize(contacts[j]));
-		}
-	}
-}
-
-function su_get_row(rows, col_name, value)
-{
-	var i;
-	for (i = 0; i < rows.length; i++)
-	{
-		if (rows[i][col_name] && (rows[i][col_name] == value))
-			return rows[i];
-	}
-	return null;
-}
-
-function su_migrate_clear_old_passwords()
-{
-	var names = 	su_ds.getPrefNames("stumble.");
-	var current_id_pref = "stumble." + 
-				su_ds.getValue("@current_user") +
-				".password";
-	var i;
-	for (i = 0; i < names.length; i++)
-	{
-		if (names[i].indexOf("$password") == -1) continue;
-		if (names[i] == current_id_pref) continue;
-		su_ds.clearPref(names[i]);
-	}
-}
-
-function su_migrate_shortcuts()
-{
-	// If we're on Windows, and if all of the key bindings match the 
-	// old defaults, change the bindings to the new defaults. -- JW
-	var details = new Array();
-	var o;
-	
-	o = new Object();
-	o.oldpref = "$shortcut-stumble";
-	o.newpref = "$shortcut_stumble";
-	o.oldval = "Alt+VK_F1";
-	o.newval = "Alt+VK_BACK_QUOTE";
-	details.push(o);
-	
-	o = new Object();
-	o.oldpref = "$shortcut-thumbup";
-	o.newpref = "$shortcut_thumbup";
-	o.oldval = "Alt+VK_F2";
-	o.newval = "Alt+VK_1";
-	details.push(o);		
-	
-	o = new Object();
-	o.oldpref = "$shortcut-thumbdown";
-	o.newpref = "$shortcut_thumbdown";
-	o.oldval = "Alt+VK_F3";
-	o.newval = "Alt+VK_2";
-	details.push(o);		
-	
-	o = new Object();
-	o.oldpref = "$shortcut-reviews";
-	o.newpref = "$shortcut_reviews";
-	o.oldval = "Alt+VK_F5";
-	o.newval = "Alt+VK_3";
-	details.push(o);		
-	
-	o = new Object();
-	o.oldpref = "$shortcut-toolbar";
-	o.newpref = "$shortcut_toolbar";
-	o.oldval = "Alt+VK_11";
-	o.newval = "Alt+VK_11";
-	details.push(o);		
-	
-	var keybindings_edited = false;
-	var i;
-	for (i = 0; i < details.length; i++)
-	{
-		if (su_ds.isPrefDefined(details[i].oldpref))
-		{
-			keybindings_edited = (su_ds.getValue(details[i].oldpref) != details[i].oldval);
-			if (keybindings_edited)
-			{
-				break;
-			}
-		}
-	}
-	
-	if (keybindings_edited)
-	{
-		su_init_key_const_dictionaries();
-
-		for (i = 0; i < details.length; i++)
-		{
-			// This tranlates keyids like " " and "A" to "VK_SPACE" and 
-			// "VK_A". -- JW
-			var keyspec = su_ds.getValue(details[i].oldpref);
-			var parts = keyspec.split("+");
-			var old_keyid;
-			if (parts[parts.length - 1] == "")
-				old_keyid = "+";
-			else
-				old_keyid = parts[parts.length - 1];
-
-			if (old_keyid.length == 1)
-			{
-				var new_keyid = su_keyids_by_char[old_keyid];
-				if (new_keyid)
-				{
-					var regexp = new RegExp(su_escape_regexp_chars(old_keyid) + "$");
-					keyspec = keyspec.replace(regexp, new_keyid);
-				}
-			}
-			su_ds.setValue(details[i].newpref, keyspec);
-		}
-	}
-}
-
diff --git a/chrome/stumbleupon.jar!/content/preferenceDialog.js b/chrome/stumbleupon.jar!/content/preferenceDialog.js
deleted file mode 100644
index 72a9b99..0000000
--- a/chrome/stumbleupon.jar!/content/preferenceDialog.js
+++ /dev/null
@@ -1,1308 +0,0 @@
-
-function su_include(uri)
-{
-	try {
-		su_get_service(
-					"@mozilla.org/moz/jssubscript-loader;1",
-					"mozIJSSubScriptLoader")
-					.loadSubScript(uri);
-	}
-	catch (e) {
-		if ((uri != "chrome://stumbleupon/content/extra.js") || 
-					su_test_extra_init)
-			su_log_error("INCLUDE", e, uri);
-	}
-}
-
-function su_create_instance(nsclass, nsinterface)
-{
-	try {
-		return Components.classes[nsclass]
-					.createInstance(Components.interfaces[nsinterface]);
-	} catch (e) {
-		return null;
-	}
-}
-
-function su_get_service(nsclass, nsinterface)
-{
-	try {
-		return Components.classes[nsclass]
-					.getService(Components.interfaces[nsinterface]);
-	} catch (e) {
-		return null;
-	}
-}
-
-function su_get_element(id)
-{
-	return document.getElementById(id);
-}
-
-var su_service;
-try {
-	su_service = Components.classes["@stumbleupon.com/stumbleupon-service;1"].getService().wrappedJSObject;
-}
-catch (e) {
-	// seamonkey kludge
-	su_include("chrome://stumbleupon/content/stumbleuponService.js");
-	su_service = new su_Service();
-}
-
-var su_ds = su_service.getDatastore();
-var icons_only;
-var bad_stumble;
-var great_stumble;
-var parent_window = null;
-var search_plugin;
-//var autocomplete_source;
-var keyspec;
-var shortcut_item;
-var recent_keypress_modifiers;
-var preferred_position_group;
-var preferred_show_firstrater_label_always;
-var stumbleupon_toolbar_menuitem = null;
-var download_favs_context = null;
-var bookmarks_backup_dir = null;
-var TOGGLE_TOOLBAR_LISTITEM_INDEX = 4;
-var enable_ids = [
-			"shortcut_stumble",
-			"shortcut_thumbup",
-			"shortcut_thumbdown",
-			"shortcut_tag",
-			"shortcut_reviews"];
-//			"shortcut_details"
-var mode_ids = [
-//			"show_mode_all",
-			"show_mode_friends",
-			"show_mode_news",
-			"show_mode_photo",
-			"show_mode_search",
-			"show_mode_stumblers",
-			"show_mode_video",
-			"show_mode_wiki",
-			"show_mode_more"];
-	
-//
-// setUserChangedValue
-//
-// We want to track whether the user changes certain values.  This function
-// takes care of this by adding a new boolean key when the value is changed by
-// the user.
-//
-function setUserChangedValue(key, newValue)
-{
-	var oldValue = su_ds.getValue(key);
-	if(oldValue != newValue)
-	{
-		su_ds.setValue(key + "_user_changed", true);
-		su_ds.setValue(key, newValue);
-	}
-}
-
-function doOK()
-{
-	//!!! Update all open windows for this application. -- JW
-
-	// now save new prefs...
-
-	if (is_parent_window_destroyed())
-	{
-		su_get_element("stumble_pref_dialog").cancelDialog();
-		return true;
-	}
-	
-	su_ds.setValue("$show_mode", su_get_element("show_mode").checked);
-	for (i = 0; i < mode_ids.length; i++)
-	{
-		su_ds.setValue("$" + mode_ids[i], su_get_element(mode_ids[i]).checked);
-	}
-	
-	su_ds.setValue("$show_field", su_get_element("show_field").checked);
-
-	// see if they have changed...
-	var thebutton = su_get_element("bad-stumble");
-	bad_stumble = thebutton.checked;
-	su_ds.setValue("$bad_stumble", bad_stumble);
-
-	thebutton = su_get_element("great-stumble");
-	great_stumble = thebutton.checked;
-	su_ds.setValue("$great_stumble", great_stumble);
-
-	su_ds.setValue("$prefetch", su_get_element("prefetch").checked);
-
-//	su_ds.setValue("$comment_firstrating", su_get_element("comment_firstrating").checked);
-
-	su_ds.setValue("$review_new_window", su_get_element("review_new_window").checked);
-	su_ds.setValue("$rate_new_window", su_get_element("rate_new_window").checked);
-//	su_ds.setValue("$search_new_window", su_get_element("search_new_window").checked);
-
-	var new_show_topics = su_get_element("show_topics").checked;
-	su_ds.setValue("$show_topics", new_show_topics);
-
-    var new_stumble_topics = su_get_element("stumble_topics").checked;
-	su_ds.setValue("$stumble_topics", new_stumble_topics);
-
-	var new_show_topics_style = su_get_element("stumble_topics2_style_menu").selectedItem;
-	if (new_show_topics_style)
-		su_ds.setValue("$stumble_topics_style", new_show_topics_style.value);
-	else
-		su_ds.setValue("$stumble_topics_style", 0);
-
-	var new_show_info = su_get_element("show_info").checked;
-	setUserChangedValue("$show_info", new_show_info);
-	
-	var new_show_tag = su_get_element("show_tag").checked;
-	su_ds.setValue("$show_tag", new_show_tag);
-	if (new_show_tag)
-		su_ds.setValue("$shown_tag", true);
-
-//	var new_show_flag = su_get_element("show_flag").checked;
-//	su_ds.setValue("$show_flag", new_show_flag);
-
-//	var new_show_search = su_get_element("show_search").checked;
-//	su_ds.setValue("$show_search", new_show_search);
-
-//	su_ds.setValue("$show_legacy_network",  
-//				su_get_element("show_legacy_network").checked);
-
-	var new_show_home = su_get_element("show_home").checked;
-	setUserChangedValue("$show_home", new_show_home);
-
-//	var new_show_editinfo = su_get_element("show_editinfo").checked;
-//	su_ds.setValue("$show_editinfo", new_show_editinfo);
-
-	su_ds.setValue("$show_legacy_forums", 
-				su_get_element("show_legacy_forums").checked);
-
-	var new_show_friends = su_get_element("show_friends").checked;
-	setUserChangedValue("$show_friends", new_show_friends);
-
-	var new_sync_bm_meta = su_get_element("sync_bm_meta").checked;
-	su_ds.setValue("$sync_bm_meta", new_sync_bm_meta);
-
-	var new_sync_bm_adult = ! su_get_element("sync_bm_exclude_adult").checked;
-	su_ds.setValue("$sync_bm_adult", new_sync_bm_adult);
-
-	var new_show_matches = su_get_element("show_matches").checked;
-	su_ds.setValue("$show_matches", new_show_matches);
-
-	var new_show_aboutme = su_get_element("show_aboutme").checked;
-	su_ds.setValue("$show_aboutme", new_show_aboutme);
-
-	var new_show_groups = su_get_element("show_groups").checked;
-	su_ds.setValue("$show_groups", new_show_groups);
-
-	var new_show_messages = su_get_element("show_messages").checked;
-	su_ds.setValue("$show_messages", new_show_messages);
-
-	var new_show_referral = su_get_element("show_referral").checked;
-	setUserChangedValue("$show_referral", new_show_referral);
-
-	var new_search_clear_queries = su_get_element("search_clear_queries").checked;
-	su_ds.setValue("$search_clear_queries", new_search_clear_queries);
-
-	var new_show_searchlinks_score = su_get_element("show_searchlinks_score").checked;
-	su_ds.setValue("$show_searchlinks_score", new_show_searchlinks_score);
-
-	var new_show_searchlinks_friends = su_get_element("show_searchlinks_friends").checked;
-	su_ds.setValue("$show_searchlinks_friends", new_show_searchlinks_friends);
-
-	var new_show_searchlinks_topic = su_get_element("show_searchlinks_topic").checked;
-	su_ds.setValue("$show_searchlinks_topic", new_show_searchlinks_topic);
-
-	var new_show_searchlinks_logo = su_get_element("show_searchlinks_logo").checked;
-	su_ds.setValue("$show_searchlinks_logo", new_show_searchlinks_logo);
-
-	var new_stumble_upon_change = su_get_element("stumble_upon_change").checked;
-	su_ds.setValue("$stumble_upon_change", new_stumble_upon_change);
-
-//	var new_autocomplete_type = su_get_element("search_group").selectedItem.value;
-//	su_ds.setValue("$autocomplete_type", new_autocomplete_type);
-
-	// now see if icons thingies have changed...
-	var new_icons_only;
-	if (su_get_element("icons-only").selected)
-	{
-		new_icons_only = "icons-only";
-		su_ds.setValue("$show_firstrater_label_always", su_get_element("show_firstrater_label_always").checked);
-	}
-	else if (su_get_element("text-icons").selected)
-	{
-		new_icons_only = "text-icons";
-		su_ds.setValue("$show_firstrater_label_always", preferred_show_firstrater_label_always);
-	}
-	su_ds.setValue("$icons", new_icons_only);
-
-//	else if (su_get_element("extra-text").selected)
-//		new_icons_only = "extra-text";
-
-/*
-	if ((navigator.userAgent.indexOf("Win") != -1) &&
-				(navigator.userAgent.indexOf("Firefox") != -1))
-	{
-		// The plugin only works on Firefox under XP for now....
-		// See also the relevant section in stumbleuponOverlay.js.
-
-		var new_search_plugin = su_get_element("search_plugin").checked;
-
-		if (new_search_plugin != search_plugin)
-		{
-			su_ds.setValue("$search_plugin", new_search_plugin);
-			if (parent_window)
-			{
-				if (new_search_plugin)
-				{
-					parent_window.su_add_search_plugin(1);
-					alert("The search engine plugin will be added when you restart your browser.");
-				}
-				else
-				{
-					parent_window.su_remove_search_plugin();
-					alert("The search engine plugin will be removed when you restart your browser.");
-				}
-			}
-		}
-	}
-*/
-	var toolbar_toggle_visible = su_get_element("toggle").checked;
-	su_ds.setValue("@toolbar_toggle_visible", toolbar_toggle_visible)
-	var old_toolbar_position = su_ds.getValue("@toolbar-position");
-	var toolbar_position = su_get_element("toolbar-position").selectedItem.id;
-	su_ds.setValue("@toolbar-position", toolbar_position);
-	if (su_get_element("position-group").selectedItem)
-	{
-		var toolbar = parent_window.su_get_element(toolbar_position);
-		var customizable = (toolbar.hasAttribute("customizable") && 
-					(toolbar.getAttribute("customizable") == "true"))
-
-		var position_group = su_get_element("position-group").selectedItem.id;
-		
-		if ((position_group == "drop") && ((! customizable) ||
-					(toolbar_position != old_toolbar_position)))
-			position_group = "first";
-			
-		su_ds.setValue("@position-group", position_group);
-	}
-
-	var shortcuts_enabled = su_get_element("shortcuts-enable").checked;
-	su_ds.setValue("$shortcuts_enabled", shortcuts_enabled);
-	
-	var shortcut_stumble = su_get_element("shortcut_stumble").getAttribute("keyspec");
-	su_ds.setValue("$shortcut_stumble", shortcut_stumble);
-
-	var shortcut_reviews = su_get_element("shortcut_reviews").getAttribute("keyspec");
-	su_ds.setValue("$shortcut_reviews", shortcut_reviews);
-
-	var shortcut_thumbup = su_get_element("shortcut_thumbup").getAttribute("keyspec");
-	su_ds.setValue("$shortcut_thumbup", shortcut_thumbup);
-
-	var shortcut_thumbdown = su_get_element("shortcut_thumbdown").getAttribute("keyspec");
-	su_ds.setValue("$shortcut_thumbdown", shortcut_thumbdown);
-
-	var shortcut_tag = su_get_element("shortcut_tag").getAttribute("keyspec");
-	su_ds.setValue("$shortcut_tag", shortcut_tag);
-
-//	var shortcut_details = su_get_element("shortcut_details").getAttribute("keyspec");
-//	su_ds.setValue("$shortcut_details", shortcut_details);
-
-	var shortcut_toolbar = su_get_element("shortcut_toolbar").getAttribute("keyspec");
-	su_ds.setValue("$shortcut_toolbar", shortcut_toolbar);
-	
-	su_ds.flushPrefs();
-
-	parent_window.setTimeout(function (parent) { parent.su_handle_preference_dialog_accept(); }, 0, parent_window);
-	
-	return true;
-}
-
-function doCancel(event)
-{
-	if (! is_parent_window_destroyed())
-	{
-		parent_window.su_preference_dialog = null;
-	}
-	
-	return true;
-}
-
-function is_parent_window_destroyed()
-{
-	// Verify that the window is undestroyed. -- JW
-	try { var str = parent_window.location + " "; }
-	catch (e)
-	{
-		return true;
-	}
-	return false;
-}
-
-function init()
-{
-	var i;
-	if (opener && opener.location.href.indexOf("extensions.xul") != -1)
-	{
-		if (opener.opener && (opener.opener.location.href.indexOf("browser.xul") != -1))
-		{
-			// opened from the extensions window
-			parent_window = opener.opener;
-		}
-		else 
-		{
-			// possibly opened from the all-in-one sidebar
-			var window_service = Components.classes["@mozilla.org/appshell/window-mediator;1"]
-						.getService(Components.interfaces.nsIWindowMediator);
-			parent_window = window_service.getMostRecentWindow("navigator:browser");
-		}
-	}
-	else
-	{
-		// opened via the toolbar Menu
-		parent_window = opener;
-	}
-	
-	if (is_parent_window_destroyed())
-	{
-		su_get_element("stumble_pref_dialog").cancelDialog();
-		return;
-	}
-	
-	parent_window.su_preference_dialog = su_get_element("stumble_pref_dialog");
-	
-	if (su_ds.getValue("@current_user") == 0)
-	{
-		var id_list = su_ds.getValue("@id_list");
-		
-		var ids = id_list.split(":");
-		
-		var found_an_id = false;
-		
-		for (i = 0; i < ids.length; i++)
-		{
-			if (ids[i] == "")
-				continue;
-			
-			found_an_id = true;
-			break;
-		}
-		
-		if (found_an_id)
-		{
-			alert("You can edit preferences after you sign-in.\n\n" +
-						'Click the "Start Stumbling..." button on the toolbar to sign-in.');
-		}
-		else
-		{
-			alert("You can edit toolbar preferences after you create a StumbleUpon profile.\n\n" +
-						'Click the "Start Stumbling..." button on the toolbar to create a profile.');
-		}
-		window.close();
-		return;
-	}
-	
-	var detail;
-	if (window.arguments && window.arguments.length)
-		detail = window.arguments[0];
-	else
-		detail = null;
-	
-	su_get_element("sync_bm_meta").checked = su_ds.getValue("$sync_bm_meta");
-	su_get_element("sync_bm_exclude_adult").checked = (! su_ds.getValue("$sync_bm_adult"));
-	update_download_favs_enabled_state();
-	
-	if (su_ds.hasFeature("$sociallinks"))
-		su_get_element("show_searchlinks_friends_box").hidden = false;
-	
-//	if (su_ds.hasFeature("$reportoption"))
-//		su_get_element("show_flag_box").hidden = false;
-	
-	if (parent_window.su_host.places && (! su_ds.getValue("#migrating_places")))
-		su_get_element("favs_box").hidden = false;
-	
-	var show_searchlinks_score = su_ds.getValue("$show_searchlinks_score");
-	su_get_element("show_searchlinks_score").checked = show_searchlinks_score;
-	
-	var show_searchlinks_friends = su_ds.getValue("$show_searchlinks_friends");
-	su_get_element("show_searchlinks_friends").checked = show_searchlinks_friends;
-	
-	var show_searchlinks_topic = su_ds.getValue("$show_searchlinks_topic");
-	su_get_element("show_searchlinks_topic").checked = show_searchlinks_topic;
-	
-	var show_searchlinks_logo = su_ds.getValue("$show_searchlinks_logo");
-	su_get_element("show_searchlinks_logo").checked = show_searchlinks_logo;
-	
-	var stumble_upon_change = su_ds.getValue("$stumble_upon_change");
-	su_get_element("stumble_upon_change").checked = stumble_upon_change;
-	
-	su_update_searchlinks_logo_enabled_state();
-//	}
-	
-	bad_stumble = su_ds.getValue("$bad_stumble");
-	great_stumble = su_ds.getValue("$great_stumble");
-	
-	su_get_element("show_field").checked = su_ds.getValue("$show_field");
-//	update_field_enabled_state();	
-/*
-	if ((navigator.userAgent.indexOf("Win") != -1) &&
-				(navigator.userAgent.indexOf("Firefox") != -1))
-	{
-		search_plugin = su_ds.getValue("$search_plugin");
-	}
-	else
-	{
-		// The plugin only works on Firefox under XP for now....
-		// Hide the search plug-in configuration control until we figure out
-		// how to install/uninstall on other platforms.
-		// See also the relevant section in stumbleuponOverlay.js.
-		
-		su_get_element("search_plugin").hidden = true;
-	}
-*/
-
-	su_get_element("show_mode").checked = su_ds.getValue("$show_mode");
-	for (i = 0; i < mode_ids.length; i++)
-	{
-		su_get_element(mode_ids[i]).checked = su_ds.getValue("$" + mode_ids[i]);
-	}
-	update_mode_enabled_state();
-	
-	// set inputs...
-	su_get_element("bad-stumble").checked = bad_stumble;
-	su_get_element("great-stumble").checked = great_stumble;
-//	su_get_element("search_plugin").checked = search_plugin;
-	
-	su_get_element("prefetch").checked = su_ds.getValue("$prefetch");
-//	su_get_element("comment_firstrating").checked = su_ds.getValue("$comment_firstrating");
-	su_get_element("review_new_window").checked = su_ds.getValue("$review_new_window");
-	su_get_element("rate_new_window").checked = su_ds.getValue("$rate_new_window");
-//	su_get_element("search_new_window").checked = su_ds.getValue("$search_new_window");
-	su_get_element("stumble_topics").checked = su_ds.getValue("$stumble_topics");
-	su_get_element("stumble_topics2").checked = su_ds.getValue("$stumble_topics");
-	su_get_element("stumble_topics2_style_menu").disabled = !su_ds.getValue("$stumble_topics");
-	var current_select = su_ds.getValue("$stumble_topics_style");
-	if (current_select == 1 || current_select == 2)
-		su_get_element("stumble_topics2_style_menu").selectedIndex = current_select;
-	else
-		su_get_element("stumble_topics2_style_menu").selectedIndex = 0;
-	su_get_element("search_clear_queries").checked = su_ds.getValue("$search_clear_queries");
-	
-	su_get_element("show_topics").checked = su_ds.getValue("$show_topics");
-	su_get_element("show_info").checked = su_ds.getValue("$show_info");
-//	su_get_element("show_search").checked = su_ds.getValue("$show_search");
-	su_get_element("show_tag").checked = su_ds.getValue("$show_tag");
-	su_get_element("show_tag2").checked = su_ds.getValue("$show_tag");
-//	su_get_element("show_flag").checked = su_ds.getValue("$show_flag");
-	su_get_element("show_referral").checked = su_ds.getValue("$show_referral");
-	su_get_element("show_aboutme").checked = su_ds.getValue("$show_aboutme");
-	su_get_element("show_home").checked = su_ds.getValue("$show_home");
-	su_get_element("show_friends").checked = su_ds.getValue("$show_friends");
-	su_get_element("show_messages").checked = su_ds.getValue("$show_messages");
-//	su_get_element("show_legacy_network").checked = su_ds.getValue("$show_legacy_network");
-	su_get_element("show_matches").checked = su_ds.getValue("$show_matches");
-	su_get_element("show_legacy_forums").checked = su_ds.getValue("$show_legacy_forums");
-	su_get_element("show_groups").checked = su_ds.getValue("$show_groups");
-//	su_get_element("show_editinfo").checked = su_ds.getValue("$show_editinfo");
-	
-	su_get_element("toggle").checked = su_ds.getValue("@toolbar_toggle_visible");
-	
-	icons_only = su_ds.getValue("$icons");
-	
-	if (icons_only == "extra-text")
-		icons_only = "text-icons";
-	
-	su_get_element("text-group").selectedItem = su_get_element(icons_only);
-	
-	preferred_show_firstrater_label_always = su_ds.getValue("$show_firstrater_label_always");
-	update_firstrater_label_enabled_state();
-	
-//	var autocomplete_type = su_ds.getValue("$autocomplete_type");
-//	su_get_element("search_group").selectedItem = su_get_element("search_group_" + autocomplete_type);
-	
-	var shortcut_stumble_default;
-	var shortcut_reviews_default;
-	var shortcut_thumbup_default;
-	var shortcut_thumbdown_default;
-	var shortcut_tag_default;
-//	var shortcut_details_default;
-	var shortcut_toolbar_default;
-	
-	if (parent_window.su_host.mac)
-	{
-		shortcut_stumble_default = "Alt+VK_ESCAPE";
-		shortcut_thumbup_default = "Alt+VK_F1";
-		shortcut_thumbdown_default = "Alt+VK_F2";
-		shortcut_tag_default     = "Alt+VK_SLASH";
-		shortcut_reviews_default = "Alt+VK_F3";
-//		shortcut_details_default = "Alt+VK_F4";
-		shortcut_toolbar_default = "Command+VK_F11";
-	}
-	else if (parent_window.su_host.win)
-	{
- 		shortcut_stumble_default = "Alt+VK_BACK_QUOTE";
- 		shortcut_thumbup_default = "Alt+VK_1";
- 		shortcut_thumbdown_default = "Alt+VK_2";
-		shortcut_tag_default     = "Alt+VK_SLASH";
- 		shortcut_reviews_default = "Alt+VK_3";
-//		shortcut_details_default = "Alt+VK_4";
-		shortcut_toolbar_default = "Ctrl+VK_F11";
-	}
-	else
-	{
-		shortcut_stumble_default = "Alt+VK_ESCAPE";
-		shortcut_thumbup_default = "Alt+VK_F1";
-		shortcut_thumbdown_default = "Alt+VK_F2";
-		shortcut_tag_default     = "Alt+VK_SLASH";
- 		shortcut_reviews_default = "Alt+VK_F3";
-//		shortcut_details_default = "Alt+VK_F4";
-		shortcut_toolbar_default = "Ctrl+VK_F11";
-	}
-	var shortcut_stumble = su_ds.getPrefValue("$shortcut_stumble", shortcut_stumble_default);
-	var shortcut_thumbup = su_ds.getPrefValue("$shortcut_thumbup", shortcut_thumbup_default);
-	var shortcut_thumbdown = su_ds.getPrefValue("$shortcut_thumbdown", shortcut_thumbdown_default);
-	var shortcut_tag = su_ds.getPrefValue("$shortcut_tag", shortcut_tag_default);
-	var shortcut_reviews = su_ds.getPrefValue("$shortcut_reviews", shortcut_reviews_default);
-//	var shortcut_details = su_ds.getPrefValue("$shortcut_details", shortcut_details_default);
-	var shortcut_toolbar = su_ds.getPrefValue("$shortcut_toolbar", shortcut_toolbar_default);
-	
-	su_get_element("shortcut_stumble").setAttribute("keyspec", shortcut_stumble);
-	su_get_element("shortcut_stumble").setAttribute("keyspec-default", shortcut_stumble_default);
-	su_get_element("shortcut_thumbup").setAttribute("keyspec", shortcut_thumbup);
-	su_get_element("shortcut_thumbup").setAttribute("keyspec-default", shortcut_thumbup_default);
-	su_get_element("shortcut_thumbdown").setAttribute("keyspec", shortcut_thumbdown);
-	su_get_element("shortcut_thumbdown").setAttribute("keyspec-default", shortcut_thumbdown_default);
-	su_get_element("shortcut_tag").setAttribute("keyspec", shortcut_tag);
-	su_get_element("shortcut_tag").setAttribute("keyspec-default", shortcut_tag_default);
-	su_get_element("shortcut_reviews").setAttribute("keyspec", shortcut_reviews);
-	su_get_element("shortcut_reviews").setAttribute("keyspec-default", shortcut_reviews_default);
-//	su_get_element("shortcut_details").setAttribute("keyspec", shortcut_details);
-//	su_get_element("shortcut_details").setAttribute("keyspec-default", shortcut_details_default);
-	
-	var shortcuts_enabled = su_ds.getValue("$shortcuts_enabled");
-	su_get_element("shortcuts-enable").checked = shortcuts_enabled;
-	handle_shortcuts_enable_command(shortcuts_enabled);
-	
-	su_get_element("shortcut_toolbar").setAttribute("label", "  " + parent_window.su_get_display_keyspec(shortcut_toolbar));
-	su_get_element("shortcut_toolbar").setAttribute("keyspec", shortcut_toolbar);
-	su_get_element("shortcut_toolbar").setAttribute("keyspec-default", shortcut_toolbar_default);
-	
-	
-	if (! parent_window.BrowserCustomizeToolbar)
-	{
-		su_get_element("placement-toolkit-caption").hidden = true;
-		su_get_element("placement-caption").hidden = false;
-		su_get_element("customize-position-box").hidden = true;
-	}
-	init_toolbar_placement();
-	
-	if (detail && detail.initial_tab)
-		setTimeout(select_tab, 0, detail.initial_tab);
-}
-
-function select_tab(tabid)
-{
-	su_get_element("prefs_tabbox").selectedTab = su_get_element(tabid);
-}
-
-function init_toolbar_placement()
-{
-	// Create list of toolbars for toolbar-position
-	
-	var toolbars = parent_window.document.getElementsByTagName("toolbar");
-	var statusbars = parent_window.document.getElementsByTagName("statusbar");
-	var menubars = parent_window.document.getElementsByTagName("menubar");
-	var popup = su_get_element("placement-popup");
-	var x, bar, item, val, list;
-	
-	// first remove the toolbars already there...
-	while (popup.hasChildNodes())
-		popup.removeChild(popup.firstChild);
-	
-	toolbars = concat(toolbars, statusbars);
-	toolbars = concat(toolbars, menubars);
-	
-	for (x = 0; x < toolbars.length; x++)
-	{
-		if (! toolbars[x].hasAttribute("id"))
-			continue;
-		
-		var bar_id = toolbars[x].getAttribute("id");
-
-		if (su_ds.lookup("toolbarid:bad_target_flag", bar_id))
-			continue;
-		
-		// Skip non-customizable toolbars with the exception of the status-bar
-		if (! toolbars[x].hasAttribute("customizable") ||
-			! (toolbars[x].getAttribute("customizable").toLowerCase() == "true"))
-		{
-			if(bar_id != "status-bar")
-				continue;
-		}
-		
-		// weird firefox toolbar
-		if ((bar_id == "toolbar-menubar") &&
-					(navigator.userAgent.indexOf("Mac") != -1))
-			continue;
-
-		// Exclude the All-in-One Sidebar extension toolbars. -- JW
-		if (bar_id.indexOf("aios") == 0)
-			continue;
-		
-		// Exclude the ScrapBook toolbars. -- JW
-		if (bar_id.indexOf("ScrapBook") == 0)
-			continue;
-		
-		// Exclude webdeveloper supplemental toolbars. -- JW
-		if ((bar_id.indexOf("webdeveloper") != -1) && 
-					(bar_id != "webdeveloper-toolbar"))
-			continue;
-		
-		item = document.createElement("menuitem");
-		item.setAttribute("id", bar_id);
-		item.value = bar_id;
-		if (item.value == "status-bar")
-			item.setAttribute("label", "Status Bar");
-		else if (item.value == "toolbar-menubar")
-			item.setAttribute("label", "Menu Bar");
-		else if (item.value == "nav-bar")
-			item.setAttribute("label", "Navigation Toolbar");
-		else if (item.value == "PersonalToolbar")
-			item.setAttribute("label", "Personal Toolbar");
-		else if (item.value == "linktoolbar")
-			item.setAttribute("label", "Link Toolbar");
-		else if (toolbars[x].hasAttribute("toolbarname"))
-			item.setAttribute("label", toolbars[x].getAttribute("toolbarname"));
-		else
-			item.setAttribute("label", bar_id);
-		
-		if (bar_id == "stumbleupon")
-		{
-			stumbleupon_toolbar_menuitem = item;
-		}
-		
-		popup.appendChild(item);
-	}
-
-	var toolbar_position = su_ds.getValue("@toolbar-position");
-	if ((toolbar_position == "webpedia") || 
-			(toolbar_position == "fbToolbar"))
-	{
-		toolbar_position = "stumbleupon";
-	}
-	su_get_element("toolbar-position").selectedItem = su_get_element(toolbar_position);
-
-	var position_group = su_ds.getValue("@position-group");
-	if ((toolbar_position == "stumbleupon") || 
-			(toolbar_position == "gtbToolbar") || 
-			(toolbar_position == "yahoo-toolbar") ||
-			(toolbar_position == "prefbar") ||
-			(toolbar_position == "MBSTB-Toolbar"))
-	{
-		position_group = "first";
-		su_ds.setValue("@position-group", "first");
-	}
-	preferred_position_group = position_group;
-	su_get_element("position-group").selectedItem = su_get_element(position_group);
-	
-	handle_toolbar_position_command(toolbar_position);
-	handle_position_group_command(position_group);
-}
-	
-function concat(c1, c2)
-{
-	// Concats too collections into an array.
-	var c3 = new Array(c1.length + c2.length);
-	var x,y = 0;
-	
-	for (x = 0; x < c1.length; x++)
-		c3[y++] = c1[x];
-	
-	for (x = 0; x < c2.length; x++)
-		c3[y++] = c2[x];
-	
-	return c3;
-}
-
-/*
-function topWindow()
-{
-	//XXX need app specific
-	var windowManager = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService();
-	var windowManagerInterface = windowManager.QueryInterface(Components.interfaces.nsIWindowMediator);
-	var win = windowManagerInterface.getMostRecentWindow("navigator:browser");
-	if (!win)
-		win = window.openDialog("chrome://browser/content/browser.xul", "_blank", "chrome,all,dialog=no", "about:blank", null, null);
-	return win;
-}
-*/
-
-function handle_show_tag_command()
-{
-	su_get_element("show_tag2").checked = su_get_element("show_tag").checked;
-}
-
-function handle_show_tag2_command()
-{
-	su_get_element("show_tag").checked = su_get_element("show_tag2").checked;
-}
-
-function handle_stumble_topics_command()
-{
-	su_get_element("stumble_topics2").checked = su_get_element("stumble_topics").checked;
-	su_get_element("stumble_topics2_style_menu").disabled = !su_get_element("stumble_topics2").checked;
-}
-
-function handle_stumble_topics2_command()
-{
-	su_get_element("stumble_topics").checked = su_get_element("stumble_topics2").checked;
-	su_get_element("stumble_topics2_style_menu").disabled = !su_get_element("stumble_topics2").checked;
-}
-
-function update_download_favs_enabled_state()
-{
-	var sync = su_get_element("sync_bm_meta").checked;
-	
-	if (! sync)
-		handle_stop_download_favs_command();
-	
-	var detail = su_ds.getValue("#download_favs_detail");
-	
-	var enabled = (! detail);
-	
-	su_get_element("download_start").disabled = (! sync) || (! enabled);
-	su_get_element("download_stop").disabled = (! sync) || enabled;
-	su_get_element("sync_bm_exclude_adult").disabled = (! sync);
-}
-
-function update_firstrater_label_enabled_state()
-{
-	if (su_get_element("icons-only").selected)
-	{
-		su_get_element("show_firstrater_label_always").checked = preferred_show_firstrater_label_always;
-		su_get_element("show_firstrater_label_always").disabled = false;
-	}
-	else if (su_get_element("text-icons").selected)
-	{
-		preferred_show_firstrater_label_always = su_get_element("show_firstrater_label_always").checked;
-		su_get_element("show_firstrater_label_always").checked = true;
-		su_get_element("show_firstrater_label_always").disabled = true;
-	}
-}
-
-function su_update_searchlinks_logo_enabled_state()
-{
-	var show_searchlinks_score = su_get_element("show_searchlinks_score").checked;
-	var show_searchlinks_friends = su_get_element("show_searchlinks_friends").checked;
-	var show_searchlinks_topic = su_get_element("show_searchlinks_topic").checked;
-	su_get_element("show_searchlinks_logo").disabled = 
-			(!(show_searchlinks_score || show_searchlinks_friends || show_searchlinks_topic));
-}
-
-function update_mode_enabled_state()
-{
-	var enabled = su_get_element("show_mode").checked;
-	var i;
-	for (i = 0; i < mode_ids.length; i++)
-		su_get_element(mode_ids[i]).disabled = (! enabled);
-	
-	su_get_element("show_mode_more").disabled = (! enabled);
-	su_get_element("show_mode_more_button").disabled = (! enabled);
-}
-
-//function update_field_enabled_state()
-//{
-//	var enabled = su_get_element("show_field").checked;
-//	
-//	su_get_element("search_group_prompt").disabled = (! enabled);
-//	su_get_element("search_group_query").disabled = (! enabled);
-//	su_get_element("search_group_tag").disabled = (! enabled);
-//	
-//}
-
-function handle_download_favs_command()
-{
-	su_ds.setValue("#download_favs_detail", null);
-	su_ds.setValue("$download_favs_detail", {});
-	su_ds.flushPrefs();
-	
-	parent_window.setTimeout(function (win) {
-				win.su_handle_download_favs_command(); },
-			100,
-			parent_window);
-}
-
-function handle_stop_download_favs_command()
-{
-	setTimeout(handle_stop_download_favs_command2, 100);
-}
-
-function handle_stop_download_favs_command2()
-{
-	var db = su_ds.getDatabase();
-	var sql;
-	var context;
-	su_ds.setValue("$download_favs_state", "a");
-	su_ds.setValue("#download_favs_detail", null);
-	su_ds.setValue("$download_favs_detail", {});
-	su_ds.flushPrefs();
-	sql = "DELETE FROM command_queue WHERE priority=16000";
-	db.query(sql);
-	context = su_ds.getValue("#command_queue_context");
-	if (context)
-		context.command_rows = new Array();
-	su_get_element("download_progress").value = 0;
-	update_download_favs_enabled_state();
-}
-
-function handle_toggle_label_click()
-{
-	su_get_element("toggle").checked = (! su_get_element("toggle").checked); 
-}
-
-function handle_toolbar_position_command(toolbar_position)
-{
-	if ((toolbar_position == "stumbleupon") || 
-			(toolbar_position == "gtbToolbar") || 
-			(toolbar_position == "yahoo-toolbar") ||
-			(toolbar_position == "prefbar") ||
-			(toolbar_position == "MBSTB-Toolbar"))
-	{
-		su_get_element("last").disabled = true;
-		su_get_element("position-group").selectedItem = su_get_element("first");
-	}
-	else
-	{
-		su_get_element("last").disabled = false;
-		su_get_element("position-group").selectedItem = su_get_element(preferred_position_group);
-	}
-}
-
-function handle_position_group_command(position_group)
-{
-	preferred_position_group = position_group;
-}
-
-function handle_customize_position_command()
-{
-	su_ds.setValue("@toolbar-position", "stumbleupon");
-	su_ds.setValue("@position-group", "drop");
-	su_ds.flushPrefs();
-	parent_window.setTimeout(function (parent) { parent.su_customize_toolbox(); }, 100, parent_window);
-	window.close();
-}
-
-function handle_more_mode_command()
-{
-	window.openDialog(
-			"chrome://stumbleupon/content/moreChannelsDialog.xul", 
-			"More Channels",
-			"chrome,modal,dialog,centerscreen,dependent");
-}
-
-function handle_shortcuts_enable_command(enabled)
-{
-	var ids = enable_ids;
-	
-	var i;
-	var found = false;
-	for (i = 0; i < ids.length; i++)
-	{
-		var el = su_get_element(ids[i]);
-		if (el == shortcut_item)
-			found = true;
-		var label = su_get_element(ids[i] + "_label");
-		if (enabled)
-		{
-			label.disabled = false;
-			el.setAttribute("label", "  " + 
-					parent_window.su_get_display_keyspec(
-					el.getAttribute("keyspec")));
-		}
-		else
-		{
-			label.disabled = true;
-			el.setAttribute("label", "");
-		}
-	}
-	
-	if (found && (! enabled))
-	{
-		shortcut_item = null;
-		refresh_shortcut_preview();
-	}
-}
-		
-// handles the select event for the shortcuts element
-function handle_shortcuts_select(event)
-{
-	su_get_element("shortcut_preview").disabled = false;
-	su_get_element("shortcut_change").disabled = false;
-	
-	shortcut_item = get_shortcut_item_from_index(event.target.selectedIndex);
-	keyspec = shortcut_item.getAttribute("keyspec");
-	
-	if (! su_get_element("shortcuts-enable").checked)
-	{
-		var ids = enable_ids;
-		var found = false;
-		for (i = 0; i < ids.length; i++)
-		{
-			if (ids[i] == shortcut_item.id)
-			{
-				found = true;
-				break;
-			}
-		}
-		if (found)
-		{
-			su_get_element("shortcuts-enable").checked = true;
-			handle_shortcuts_enable_command(true);
-		}
-	}
-	
-	refresh_shortcut_preview();
-}
-
-// dereferences a shortcut selected item index to the cell element
-// used to display the shortcut
-function get_shortcut_item_from_index(index)
-{
-	switch (index)
-	{
-		case 0: item_id = "shortcut_stumble";   break;
-		case 1: item_id = "shortcut_thumbup";   break;
-		case 2: item_id = "shortcut_thumbdown"; break;
-		case 3: item_id = "shortcut_tag";       break;
-		case 4: item_id = "shortcut_reviews";   break;
-		case 5: item_id = "shortcut_toolbar";   break;
-//		case 5: item_id = "shortcut_details";   break;
-//		case 6: item_id = "shortcut_toolbar";   break;
-	}
-	return su_get_element(item_id);
-}
-
-// handles the shortcut disable button command
-function handle_shortcut_disable_command()
-{
-	keyspec = "";
-	shortcut_item.setAttribute("keyspec", keyspec);
-	shortcut_item.setAttribute("label", "");
-	
-	refresh_shortcut_preview();
-
-	if (shortcut_item.id == "shortcut_toolbar")
-	{
-		set_toolbar_position_label("StumbleUpon Toolbar");
-	}
-}
-
-// handles the shortcut revert button command
-function handle_shortcut_revert_command()
-{
-	keyspec = shortcut_item.getAttribute("keyspec-default");
-	shortcut_item.setAttribute("keyspec", keyspec);
-	shortcut_item.setAttribute("label", "  " + parent_window.su_get_display_keyspec(keyspec));
-	
-	refresh_shortcut_preview();
-	
-	var item_cur;
-	for (var i = 0; i <= 5; i++)
-	{
-		item_cur = get_shortcut_item_from_index(i);
- 		if ((item_cur != shortcut_item) && (item_cur.getAttribute("keyspec") == keyspec))
-		{
-			item_cur.setAttribute("keyspec", "");
-			item_cur.setAttribute("label", "");
-			if ((i == TOGGLE_TOOLBAR_LISTITEM_INDEX) && (stumbleupon_toolbar_menuitem != null))
-			{
-				set_toolbar_position_label("StumbleUpon Toolbar");
-			}
-		}
-	}
-}
-
-// handles the shortcut change button command
-function handle_shortcut_change_command()
-{
-	shortcut_item.setAttribute("keyspec", keyspec);
-	shortcut_item.setAttribute("label", "  " + parent_window.su_get_display_keyspec(keyspec));
-
-	refresh_shortcut_preview();	
-	
-	var item_cur;
-	for (var i = 0; i <= 4; i++)
-	{
-		item_cur = get_shortcut_item_from_index(i);
-		if ((item_cur != shortcut_item) && (item_cur.getAttribute("keyspec") == keyspec))
-		{
-			item_cur.setAttribute("keyspec", "");
-			item_cur.setAttribute("label", "");
-			if (i == TOGGLE_TOOLBAR_LISTITEM_INDEX)
-			{
-				set_toolbar_position_label("StumbleUpon Toolbar");
-			}
-		}
-	}
-	
-	if (shortcut_item.id == "shortcut_toolbar")
-	{
-		set_toolbar_position_label("StumbleUpon Toolbar (" +
-				parent_window.su_get_display_keyspec(keyspec) + ")")
-	}
-}
-
-// used by the shortcut configuration routines to update the 
-// StumbleUpon Toolbar menuitem in the toolbar-position popup
-function set_toolbar_position_label(label)
-{
-	if (stumbleupon_toolbar_menuitem != null)
-	{
-		stumbleupon_toolbar_menuitem.label = label;
-		var toolbar_position = su_get_element("toolbar-position");
-		if (toolbar_position.selectedItem == stumbleupon_toolbar_menuitem)
-		{
-			if (stumbleupon_toolbar_menuitem.previousSibling)
-			{
-				toolbar_position.selectedItem = stumbleupon_toolbar_menuitem.previousSibling;
-				toolbar_position.selectedItem = stumbleupon_toolbar_menuitem;
-			}
-			else if (stumbleupon_toolbar_menuitem.nextSibling)
-			{
-				toolbar_position.selectedItem = stumbleupon_toolbar_menuitem.nextSibling;
-				toolbar_position.selectedItem = stumbleupon_toolbar_menuitem;
-			}
-		}
-	}
-}
-
-// handles the keyup event for the shortcuts list
-function handle_shortcuts_keyup(event)
-{
-	if ((event.keyCode == KeyEvent.DOM_VK_UP) ||
-			(event.keyCode == KeyEvent.DOM_VK_DOWN))
-	{
-		return true;
-	}
-	else
-	{
-		return handle_shortcut_preview_keyup(event);
-	}
-}
-
-// handles the keypress event for the shortcuts list
-function handle_shortcuts_keypress(event)
-{
-	return handle_shortcut_preview_keypress(event);
-}
-
-// handles the keypress event for the shortcut-preview textbox
-function handle_shortcut_preview_keypress(event)
-{
-  var str = "";
-
-	if (event.altKey)   str += "Alt+";
-	if (event.ctrlKey)  str += "Ctrl+";
-	if (event.metaKey)  str += "Command+";
-	if (event.shiftKey) str += "Shift+";
-
-	recent_keypress_modifiers = str;
-
-	return true;
-}
-
-// handles the keyup event for the shortcut-preview textbox
-function handle_shortcut_preview_keyup(event)
-{
-  if ((event.keyCode == KeyEvent.DOM_VK_TAB) ||
-  			(event.keyCode == KeyEvent.DOM_VK_SHIFT) ||
-  			(event.keyCode == KeyEvent.DOM_VK_CONTROL) ||
-  			(event.keyCode == KeyEvent.DOM_VK_ALT) ||
-  			(event.keyCode == KeyEvent.DOM_VK_META) ||
-  			(event.keyCode == KeyEvent.DOM_VK_NUM_LOCK) ||
-  			(event.keyCode == KeyEvent.DOM_VK_SCROLL_LOCK) ||
-  			(event.keyCode == KeyEvent.DOM_VK_CAPS_LOCK))
-  {
-  	return true;
-  }
-  event.stopPropagation();
-  event.preventDefault();
-	
-	var keyid;
-	if (event.charCode)
-		keyid = parent_window.su_keyids_by_eventkeycode[event.charCode];
-	else
-		keyid = parent_window.su_keyids_by_eventkeycode[event.keyCode];
-	
-	keyspec = recent_keypress_modifiers + keyid;
-	refresh_shortcut_preview();
-	
-	return false;
-}
-
-// sets button and label state given keyspec being previewed as a
-// binding for shortcut_item
-function refresh_shortcut_preview()
-{
-	var shortcut_revert = su_get_element("shortcut_revert");
-	var shortcut_disable = su_get_element("shortcut_disable");
-	var shortcut_change = su_get_element("shortcut_change");
-
-	if (! shortcut_item)
-	{
-		if (shortcut_revert.hasAttribute("tooltiptext"))
-			shortcut_revert.removeAttribute("tooltiptext");
-		
-		shortcut_revert.disabled = true;
-		shortcut_disable.disabled = true;
-		shortcut_change.disabled = true;
-		
-		su_get_element("shortcut_preview").value = "";
-		su_get_element("shortcut_default_behavior").value = "";
-		return;
-	}
-
-	var keyspec_current = shortcut_item.getAttribute("keyspec");
-	var keyspec_default = shortcut_item.getAttribute("keyspec-default");
-	
-	if (keyspec_current == keyspec_default)
-	{
-		shortcut_revert.removeAttribute("tooltiptext");
-		shortcut_revert.disabled = true;
-	}
-	else
-	{
-		shortcut_revert.setAttribute("tooltiptext", 
-				"Revert to " + parent_window.su_get_display_keyspec(keyspec_default));
-		shortcut_revert.disabled = false;
-	}
-	
-	shortcut_change.disabled = (keyspec_current == keyspec);
-	
-	shortcut_disable.disabled = (keyspec_current == "");
-
-	su_get_element("shortcut_preview").value = parent_window.su_get_display_keyspec(keyspec);
-	su_get_element("shortcut_default_behavior").value = get_default_binding_desc(keyspec);
-}
-
-// returns description suitable for user consuption for the target
-// of a keybinding
-function get_default_binding_desc(spec)
-{
-	var desc = "";
-
-	if (spec == "")
-	{
-		return desc;
-	}
-
-	if (is_keyspec_accellerated(spec))
-	{
-		if (typeof parent_window.su_keys_by_keyspec[spec] != "undefined")
-		{
-			var key = parent_window.su_keys_by_keyspec[spec];
-			desc = get_binding_name_from_key(key);
-			if (desc == "key_StumbleUpon:ToggleToolbar")
-				desc = "";
-		}
-		else if ((spec.indexOf("Alt") != -1) && 
-				(spec.replace(/[\+_]/g, "").search(/\d|\W/) == -1) &&
-				(spec.indexOf("VK_BACK_QUOTE") == -1) &&
-				(spec != "Alt+VK_SLASH"))
-		{
-			desc = "[menu accelerator]";
-		}
-		else if ((! parent_window.su_host.win) &&
-				(spec.search(/VK_\d/) != -1))
-		{
-			desc = "[mode/navigation]";
-		}
-	}
-	else if (is_keyspec_editing(spec))
-	{
-		desc = "[editing]";
-	}
-	else
-	{
-		desc = "[mode/navigation]"
-	}
-	return desc;
-}
-
-function is_keyspec_accellerated(spec)
-{
-	return (spec.indexOf("Ctrl") != -1) ||
-			(spec.indexOf("Alt") != -1) ||
-			(spec.indexOf("Command") != -1)
-}
-
-function is_keyspec_editing(spec)
-{
-	if ((spec.indexOf("VK_HOME") != -1) ||
-			(spec.indexOf("VK_END") != -1) ||
-			(spec.indexOf("VK_INSERT") != -1) ||
-			(spec.indexOf("VK_DELETE") != -1))
-	{
-		return true;
-	}
-	else if (is_keyspec_accellerated(spec))
-	{
-		return false;
-	}
-	else if (spec.indexOf("VK_NUMPAD") != -1)
-	{
-		return true;
-	}
-	else
-	{
-		var parts = spec.split("+");
-		return parts[parts.length - 1].length <= 4;
-	}
-}
-
-// [IP:] [kudos:] The following two functions are from the public 
-// domain keyconfig extension by Joe Dorando. -- JW
-
-// searches for a description suitable for user consumption for a
-// given key element
-function get_binding_name_from_key(aKey)
-{
-  var val;
-
-  if(aKey.hasAttribute("label")) return aKey.getAttribute("label");
-
-  if(aKey.hasAttribute("command") || aKey.hasAttribute("observes")) {
-    var command = aKey.getAttribute("command") || aKey.getAttribute("observes");
-    var node = parent_window.su_get_element(command);
-    if(node && node.hasAttribute("label")) return node.getAttribute("label");
-    val = getLabel("command", command);
-    if(!val) val = getLabel("observes", command);
-  }
-
-  if(!val) val = getLabel("key", aKey.id);
-
-  if(val) return val;
-
-  var id = aKey.id.replace(/xxx_key.+?_/,"");
-	var converter = su_create_instance(
-				"@mozilla.org/intl/scriptableunicodeconverter",
-				"nsIScriptableUnicodeConverter");
-  try {
-		id = converter.ConvertToUnicode(id);
-	} catch(err) {}
-
-  return id;
-}
-function getLabel(attr, value) {
-  var Users = parent_window.document.getElementsByAttribute(attr,value);
-  var User;
-
-  for(var i = 0, l = Users.length; i < l; i++)
-    if(Users[i].hasAttribute("label") && (!User || User.localName == "menuitem")) User = Users[i];
-
-  if(!User) return null;
-
-  if(User.localName == "menuitem" && User.parentNode.parentNode.parentNode.localName == "menupopup") {
-    return User.getAttribute("label") + " [" + User.parentNode.parentNode.getAttribute("label") + "]";
-  } else return User.getAttribute("label");
-}
-
-
diff --git a/chrome/stumbleupon.jar!/content/skin/aaaa.gif b/chrome/stumbleupon.jar!/content/skin/aaaa.gif
deleted file mode 100644
index d396ca5..0000000
Binary files a/chrome/stumbleupon.jar!/content/skin/aaaa.gif and /dev/null differ
diff --git a/chrome/stumbleupon.jar!/content/skin/arrow_ani4.png b/chrome/stumbleupon.jar!/content/skin/arrow_ani4.png
deleted file mode 100644
index efdaa74..0000000
Binary files a/chrome/stumbleupon.jar!/content/skin/arrow_ani4.png and /dev/null differ
diff --git a/chrome/stumbleupon.jar!/content/skin/favicon_facebook.gif b/chrome/stumbleupon.jar!/content/skin/favicon_facebook.gif
deleted file mode 100644
index 2788e9e..0000000
Binary files a/chrome/stumbleupon.jar!/content/skin/favicon_facebook.gif and /dev/null differ
diff --git a/chrome/stumbleupon.jar!/content/skin/icon_tb_share.png b/chrome/stumbleupon.jar!/content/skin/icon_tb_share.png
deleted file mode 100644
index d58fc4f..0000000
Binary files a/chrome/stumbleupon.jar!/content/skin/icon_tb_share.png and /dev/null differ
diff --git a/chrome/stumbleupon.jar!/content/skin/legacy_forum.png b/chrome/stumbleupon.jar!/content/skin/legacy_forum.png
deleted file mode 100644
index a4c7135..0000000
Binary files a/chrome/stumbleupon.jar!/content/skin/legacy_forum.png and /dev/null differ
diff --git a/chrome/stumbleupon.jar!/content/skin/logo24.png b/chrome/stumbleupon.jar!/content/skin/logo24.png
deleted file mode 100644
index f6b618d..0000000
Binary files a/chrome/stumbleupon.jar!/content/skin/logo24.png and /dev/null differ
diff --git a/chrome/stumbleupon.jar!/content/skin/sponsor.png b/chrome/stumbleupon.jar!/content/skin/sponsor.png
deleted file mode 100644
index e4540f1..0000000
Binary files a/chrome/stumbleupon.jar!/content/skin/sponsor.png and /dev/null differ
diff --git a/chrome/stumbleupon.jar!/content/stumbleuponOverlay.js b/chrome/stumbleupon.jar!/content/stumbleuponOverlay.js
deleted file mode 100644
index a1787ad..0000000
--- a/chrome/stumbleupon.jar!/content/stumbleuponOverlay.js
+++ /dev/null
@@ -1,21484 +0,0 @@
-/***
-
-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 StumbleUpon code.
-The Initial Developer of the Original Code is StumbleUpon.
-
-Portions created by StumbleUpon are
-Copyright (C) 2002-2007 StumbleUpon.  All
-Rights Reserved.
-
-Original Author: Geoff Smith <geoff at stumbleupon.com>
-Contributor(s): Garrett Camp <gmc at stumbleupon.com>
-		Joe Walp <joewalp at yahoo.com>
-		Manpreet Singh (loonyone.stumbleupon.com)
-
-Questions/Comments?  Please send them here:
-
-http://www.stumbleupon.com/feedback.php
-
-Copyright notes:
-1. No code contributed by Manpreet Singh remains in the codebase.
-2. Regardless of intellectual property claims, Manpreet Singh supports
-   changing the license from MPL to MPL/GPL/LGPL tri-license if other
-	 contributors so choose.  For reference:
-	 http://www.mozilla.org/MPL/boilerplate-1.1/mpl-tri-license-txt
-3. For additional intellectual property considerations, search for 
-   [IP:] and [kudos:] in the code.
-
-***/
-
-//************** GLOBALS ****************/
-var su_localdoc = "file:///usr/share/xul-ext-stumbleupon/html/";
-var su_private_label = "DEB";
-var su_source_label = "AM";
-var su_log_communication = true;
-var su_log_sync = false;
-var su_log_polling = false;
-var su_log_resource_cfd = false;
-var su_log_mimetype = false;
-var su_force_migrate_prerelease = ((su_private_label.indexOf("ALPHA") == 0) || (su_private_label.indexOf("BETA") == 0));
-var su_test_stumblethru_update = false;
-var su_test_info = false;
-var su_test_extra_init = false;
-var su_test_campus_dist = false;
-var su_test_facebookhome_prompt = false;
-var su_test_searchpage_prompt = false;
-var su_test_mimetype = false;
-var su_disable_sync = false;
-var su_enable_freereporting = true;
-var su_enable_message_log = (su_private_label.indexOf("ALPHA") == 0);
-
-var mozbar_version = "3.62";
-var su_servername = 'stumbleupon.com';
-var su_serverhttp = 'http://www.' + su_servername + '/';
-var su_serverhttps = 'https://www.' + su_servername + '/';
-var su_base_url = su_serverhttp;
-var su_ds = null;
-var su_host = null;
-var su_stumbleReporter = null;
-var su_window_time_ms = (new Date()).getTime();
-var stumbleid = 0;
-var stumblepass = "";
-var su_visited_login_page = false;
-var su_promo_mode = false;
-var su_login_initialized = false;
-var su_stumble_throttled = false;
-var su_info_spec = null;
-var su_tag_instructions = "Search or Tag here";
-var su_tagged_folder_name = "Unfiled/Tagged";
-var su_video_tagid = 1196;
-var su_enable_hashed_password;
-var su_prev_nick = null;
-var su_random_delay = 0;
-var su_cacheTimer = 0;
-var su_prefetcher;
-var su_last_typed_tag = 0;  // timestamp of the last time you typed a new tag
-var su_old_search = ""; // the search you had before we change due to tagging
-var su_url_has_tag = false;
-var su_search_service_id = null;
-var su_drawer_timers = new Object();
-
-var su_visited_searchbox = 0;
-var su_toggling_toolbar = false;
-var su_moving_toolbar = false;
-//var su_check_referral_flag = 0;
-var su_check_referral_timer = null;
-var su_process_rarely_timer = null;
-var su_dist_time_timer = null;
-var su_toolbar_disabled = false;
-
-var su_quote = "";
-var su_photoblogimage = null;
-
-var su_ratings = new Object(); // array of url->su_ratings 
-var su_tag_lists_by_url = new Object(); // object url->tag_list
-var su_tags = new Array(); // array of objects with properties 'url' and 'tag_list'
-
-var su_selected_category = "0";
-var su_stumble_async_context = null;
-var su_stumblevideo_toolbar_rate = false;
-var su_pending_stumblevideo_stumble = false;
-var su_pending_stumblevideo_rate_context = null;
-var stumbled_url = ""; // your last stumble
-var su_redirect_url = "";
-var stumbled_redirect; // the url your last stumble got redirected to
-var su_previous_query_category = "";
-var su_stumble_action_count = 0;
-var stumbles; // queue of urls to be stumbled upon in the future
-var su_user_interests = new Array(); // array of intersts the user is signed up for
-var su_catnames = new Array(); // array of catid -> catname (topics.csv)
-var su_catids = new Object(); // array of catid -> catname (topics.csv)
-var su_foldernames = new Array(); // folder names
-var su_topicfolders = new Array(); // maps topic id's to su_foldernames
-var su_queries; // list of last 100 queries
-
-var su_notifier_dialog = null;
-var su_preference_dialog = null;
-var su_customize_invoked_from_preference_dialog = false;
-var su_uninstall_scheduled = false;
-var su_remove_data_scheduled = false;
-
-// The following are used by the keybinding routines, and some are
-// accessed by the preferenceDialog and by the keybinding migration
-// routine.
-var su_keys_by_keyspec = new Object();
-var su_commands_by_keyspec;
-var su_removed_keybindings_by_keyspec = new Object();
-var su_keyids_by_eventkeycode = new Object();
-var su_chars_by_keyid = new Object();
-var su_keyids_by_char = new Object();
-var su_recent_keypress_modifiers;
-var su_load_image_count = 0;
-var su_has_searchbox = false; // for efficiency
-var su_keep_searchbox_focus = false;
-var su_searchbox_was_focused = false; // used by the searchbox click kludge
-var su_gui_initialized = false;
-
-var su_searchlinks_dialog_detail = null;
-
-// The following are used by the toolbar location and overflow routines.
-var su_sidebar_was_hidden;
-var su_old_toolbar_x;
-var su_old_toolbar_position = null;
-var su_old_toolbar_position_group = null;
-var su_reflow_delayed = false;
-var su_overflow_popup_open = false;
-var su_referred_popup_open = false;
-var su_moving_splitter = false;
-var su_toolbar_justification;
-var su_bookmarks_sibling_loc = null;
-var su_persist_queue = new Array();
-
-var su_resize_window_width = 0;
-var su_resize_window_dirty = false;
-
-var su_referral_menu_dirty = true;
-var su_referral_popup_open = false;
-var su_refreshing_referral_menu = false;
-
-var su_dyn_channels_dirty = true;
-var su_mode_more_popup_open = false;
-var su_refreshing_dyn_channels = false;
-
-var su_pagemeta_dirty = true;
-var su_refreshing_pagemeta = false;
-
-var su_refreshing_category_selector = false;
-var su_blocked_category_selector_refresh_pending = false;
-
-var su_new_install = false; // true for first run after install
-var su_new_upgrade = false; // true for first run after upgrade
-var su_new_user = false;    // true between getid.php and interests_after.php
-var su_prev_version;        // set when su_new_upgrade is true
-var su_migrate_toolbar_position_scheduled = false;
-
-var su_d_rec_rating = false;
-
-// Handle StumbleUpon sidebar (conversation bar)
-var su_sidebar_enabled = false; // Disabled by default
-
-//************** END GLOBALS ****************/
-
-//********* INCLUDES *****************//
-function su_include(uri)
-{
-	try {
-		su_get_service(
-					"@mozilla.org/moz/jssubscript-loader;1",
-					"mozIJSSubScriptLoader")
-					.loadSubScript(uri);
-	}
-	catch (e) {
-		if ((uri != "chrome://stumbleupon/content/extra.js") || 
-					su_test_extra_init)
-			su_log_error("INCLUDE", e, uri);
-	}
-}
-
-var su_toolbar_api = {
-	processCommands: function(commands) {
-		su_process_commands(commands);
-	}
-}
-
-su_include("chrome://stumbleupon/content/migrate.js");
-su_include("chrome://stumbleupon/content/prefetcher.js");
-
-//********* END INCLUDES *****************//
-
-
-//********* INITIALIZATION *****************//
-// See also the bottom of the file for additional initialization.
-
-function su_load_categories()
-{
-	su_catnames = su_ds.getDictionary("catid:topic_name");
-	su_catids = su_ds.getDictionary("topic_name:catid");
-	su_topicfolders = su_ds.getDictionary("catid:folder_name");
-	su_foldernames = su_ds.getAlphaSupertopicNames();
-	
-	// Load topics.csv
-
-	// okay, let's try topics.csv that came with the xpi
-//!!! bah, let's not bother updating topics.csv over the net
-// it changes so infrequently
-
-/*
-	alert(catdat);
-
-//!!! 	var catdat = su_read_file_global("topics.csv");
-
-	var da = new Date();
-	var timenow = da.getTime();
-	var oneweek = 24 * 60 * 60 * 7 * 1000; // javascript stores time in milliseconds
-
-	var last_categories = su_ds.getValue("$categories_dat");
-	if (catdat == "" || timenow - last_categories > oneweek)
-	{
-		// We need to hit the server and grab topics.csv
-		//!!! mozilla's caching is on crack (it doesn't even check server to see if there's a new vesrion unless we create a salt!)
-		var res = su_post_url_server("topics.csv", null);
-	
-		// If we got it, make it catdat and write it to disk
-		if (res.status == 200)
-		{
- 			catdat = res.response;
-//!!!			su_write_file_global("topics.csv", catdat);
-		}
-
-		// Write last_categories
-		last_categories = timenow;
-		su_ds.setValue("$categories_dat", timenow);
-		su_ds.flushPrefs();
-	}
-
-*/
-}
-
-
-function su_is_server_page(url, path)
-{
-	return ((url.indexOf(su_serverhttp + path) == 0) ||
-			(url.indexOf(su_serverhttps + path) == 0));
-}
-
-function su_process_slclicks(force)
-{
-	if (su_ds.getValue("#slprocessed") && (! force))
-		return;
-	su_ds.setValue("#slprocessed", true);
-	var slclicks = su_ds.selectAllRows("slclick");
-	var slstats = su_ds.getValue("$slstats").split(":");
-	var profile = new Object();
-	var url_page1 = new Object();
-	var url_page2 = new Object();
-	var tag_page = new Object();
-	var result = new Object();
-	var result_dt = new Object();
-	var result_dc = new Object();
-	var result_ds = new Object();
-	var result_dl = new Object();
-	var result_df = new Object();
-	var result_dm = new Object();
-	var result_dz = new Object();
-	var index_clicked = new Array();
-	var index_friend_clicked = new Array();
-	var i;
-	for (i = 0; i < 10; i++)
-	{
-		index_clicked[i] = 0;
-		index_friend_clicked[i] = 0;
-	}
-	
-// fields
-// ---------------
-// userid
-// timestamp
-// session query num
-// query term count
-// result count
-// decorated count
-// friend decorated count
-// first decorated num
-// url_page1        clicked count
-// comment          clicked count
-// url_page2        clicked count
-// topic            clicked count
-// result           clicked count
-// thumbed result           clicked count (dt)
-// nickname result          clicked count (df)
-// multinickname result     clicked count (dm)
-// comment result           clicked count (dc)
-// comment level > 0 result clicked count (dl)
-// starred > 1 result       clicked count (ds)
-// topic result             clicked count (dz)
-	
-	var slq;
-	for (i = 0; i < slclicks.length; i++)
-	{
-		var row = slclicks[i];
-		
-		slq = row.q;
-		
-		if (row.i < 10)
-		{
-			if (row.r && row.df)
-				index_friend_clicked[row.i]++;
-			else if (row.r)
-				index_clicked[row.i]++;
-		}
-		
-		if (row.u)
-			url_page1[slq] = (url_page1[slq]) ? (url_page1[slq] + 1) : 1;
-
-		if (row.p)
-			profile[slq] = (profile[slq]) ? (profile[slq] + 1) : 1;
-		
-		if (row.n)
-			url_page2[slq] = (url_page2[slq]) ? (url_page2[slq] + 1) : 1;
-		
-		if (row.z)
-			tag_page[slq] = (tag_page[slq]) ? (tag_page[slq] + 1) : 1;
-		
-		if (row.r)
-			result[slq] = (result[slq]) ? (result[slq] + 1) : 1;
-		
-		if (row.r && row.dt)
-			result_dt[slq] = (result_dt[slq]) ? (result_dt[slq] + 1) : 1;
-		
-		if (row.r && row.dc)
-			result_dc[slq] = (result_dc[slq]) ? (result_dc[slq] + 1) : 1;
-
-		if (row.r && (row.ds > 1))
-			result_ds[slq] = (result_ds[slq]) ? (result_ds[slq] + 1) : 1;
-
-		if (row.r && row.dl)
-			result_dl[slq] = (result_dl[slq]) ? (result_dl[slq] + 1) : 1;
-
-		if (row.r && row.df)
-			result_df[slq] = (result_df[slq]) ? (result_df[slq] + 1) : 1;
-
-		if (row.r && (row.df > 1))
-			result_dm[slq] = (result_dm[slq]) ? (result_dm[slq] + 1) : 1;
-
-		if (row.r && row.dz)
-			result_dz[slq] = (result_dz[slq]) ? (result_dz[slq] + 1) : 1;
-	}
-	
-	var stats = "";
-	for (i = 0; i < slstats.length; i++)
-	{
-		if (slstats[i] == "")
-			continue;
-		
-		slq = slstats[i].split("\t")[1];
-
-		if (! url_page1[slq])
-			url_page1[slq] = 0;
-		
-		if (! profile[slq])
-			profile[slq] = 0;
-		
-		if (! url_page2[slq])
-			url_page2[slq] = 0;
-		
-		if (! tag_page[slq])
-			tag_page[slq] = 0;
-		
-		if (! result[slq])
-			result[slq] = 0;
-		
-		if (! result_dt[slq])
-			result_dt[slq] = 0;
-		
-		if (! result_dc[slq])
-			result_dc[slq] = 0;
-
-		if (! result_ds[slq])
-			result_ds[slq] = 0;
-
-		if (! result_dl[slq])
-			result_dl[slq] = 0;
-
-		if (! result_df[slq])
-			result_df[slq] = 0;
-
-		if (! result_dm[slq])
-			result_dm[slq] = 0;
-
-		if (! result_dz[slq])
-			result_dz[slq] = 0;
-
-		stats += stumbleid + "\t" + slstats[i] + "\t" + 
-					url_page1[slq] + "\t" + profile[slq] + "\t" + 
-					url_page2[slq] + "\t" + tag_page[slq] + "\t" + 
-					result[slq] + "\t" + result_dt[slq] + "\t" + 
-					result_df[slq] + "\t" + result_dm[slq] + "\t" + 
-					result_dc[slq] + "\t" + result_dl[slq] + "\t" + 
-					result_ds[slq] + "\t" + result_dz[slq] + "\n";
-					
-	}
-	
-	var istats = "";
-	var slistats = su_ds.getValue("$slistats").split(":");
-	var slidfstats = su_ds.getValue("$slidfstats").split(":");
-	for (i = 0; i < 10; i++)
-	{
-		istats += (i + 1) + "\t" + slistats[i] + "\t" + 
-					slidfstats[i] + "\t" + index_clicked[i] + "\t" +
-					index_friend_clicked[i] + "\n"
-	}
-	
-	if (stats == "")
-		return;
-	
-	su_ds.globals.sls = new Array();
-	su_ds.globals.sluqh = new Object();
-	su_ds.globals.sltih = new Object();
-	su_ds.setValue("$slstats", "");
-	su_ds.setValue("$slistats", "0:0:0:0:0:0:0:0:0:0");
-	su_ds.setValue("$slidfstats", "0:0:0:0:0:0:0:0:0:0");
-	su_ds.deleteAllRows("slclick");
-	su_ds.flushPrefs();
-	
-	var params = "";
-	params = su_arp(params, "slstats", stats);
-	params = su_arp(params, "slindexstats", istats);
-	params = su_arp(params, "f", su_ds.getValue("$form"));
-	
-	var context = new Object();
-	context.quiet = true;
-	su_post_url_server_async(
-				"slstats.php",
-				params,
-				15000,
-				su_generic_done,
-				context);
-}
-
-function su_get_random_int(min, max)
-{
-	return Math.floor(Math.random() * (max - min + 1)) + min;
-}
-
-// initializes user-specific configuration that doesn't involve gui
-// elements
-function su_load_data1(new_profile)
-{
-	//!!! We can migrate from flat files to mozStorage after that
-	// feature is mature.  We ought to be able to get rid of the
-	// length limits on these data stores for clients that include
-	// the embedded database.  -- JW
-
-	stumbled_url = "";
-	su_redirect_url = "";
-	stumbled_redirect = "";
-//	su_dd("reset", 2);
-	stumbles = new Array();
-	su_ratings = new Object();
-	
-	su_migrate_profile(new_profile);
-	
-	// make random delay...
-	// this is to avoid a race condition in hitting stumbles.php
-	// and hitting recommend.php to check_referral
-	// after X+su_random_delay seconds ... ( up to 5 minutes)
-	su_random_delay = Math.floor(Math.random()*300);
-
-	su_stumble_action_count = 0;
-	try {
-		su_prefetcher.stop();
-		su_prefetcher.clearTargets();
-		su_prefetcher.passMax = su_ds.getValue("$prefetcher_pass_max");
-		su_prefetcher.pass1TimeoutInterval = su_ds.getValue("$prefetcher_pass_1_timeout_ms");
-		su_prefetcher.pass2TimeoutInterval = su_ds.getValue("$prefetcher_pass_2_timeout_ms");
-		su_prefetcher.pass3TimeoutInterval = su_ds.getValue("$prefetcher_pass_3_timeout_ms");
-		if (su_ds.getValue("$prefetcher_skip_resources"))
-			su_prefetcher.mode = "DOM";
-		else
-			su_prefetcher.mode = "complete";
-		su_prefetcher.addEventListener("progress-start", su_handle_prefetch_load_start);
-		
-		// If noscript is installed and the version is less than 1.9.8.4, then disable
-		// the prefetcher.  We do this because those versions have a bug which will cause
-		// the prefetcher to open up a bunch of extra tabs.  So we disable the
-		// prefetcher if one of those versions of noscript is installed.  Technically,
-		// the problematic versions are < 1.9.7.9, but then there was a regression around
-		// 1.9.8.1 that caused the problem again, but it was fixed again in 1.9.8.4, so we just
-		// disable prefetcher on anything earlier than 1.9.8.4.
-		var noscript_version = su_get_noscript_enabled_version();
-		if(noscript_version) 
-		{
-			var minVersion = su_ds.getValue("@min_noscript_for_prefetch");
-			var result = su_dotversion_compare(noscript_version, minVersion);
-			if(result && (result < 0))
-			{
-				su_prefetcher.setQueueLock(true);
-			}
-		}
-	} catch (e) { su_log_error("INIT PREFETCHER"); }
-
-	su_stumbleReporter.start();
-	
-	setTimeout(function (win) { win.su_load_ratings(); }, 0, window);
-
-	try {
-		su_load_stumbles(null);
-	} catch (e) { su_log_error("LOAD STUMBLES", e); }
-	try {
-		su_load_categories();
-	} catch (e) { su_log_error("LOAD CATEGORIES", e); }
-	try {
-		su_load_user_interests();
-	} catch (e) { su_log_error("LOAD INTERESTS", e); }
-	su_tags = new Array();
-	su_tag_lists_by_url = new Object();
-	setTimeout(function (win) { win.su_load_tags(null); }, 0, window);
-
-	su_queries = new Array();
-	setTimeout(function (win) { win.su_load_queries(); }, 0, window);
-	
-	if (su_ds.getValue("@whitelist_upon_load"))
-	{
-		try {
-			su_update_noscript_whitelists();
-		} catch (e) { su_log_error("INIT WHITELIST", e); }
-	}
-	
-	su_ds.flushPrefs();
-}
-
-function su_update_noscript_whitelists()
-{
-	if (! su_ds.isPrefDefined("noscript.filterXExceptions"))
-		return;
-	
-	var str = su_ds.getValue("noscript.filterXExceptions");
-	var exceptions = str.split("\n");
-	var regsafeServer = su_servername.replace(/\./g, "\\.");
-	var filter_str = "^(http|https)://[a-z0-9\\-]+\\." + regsafeServer + "/";
-	var i;
-	var found = false;
-	for (i = 0; i < exceptions.length; i++)
-	{
-		if (exceptions[i] == filter_str)
-		{
-			found = true;
-			break;
-		}
-	}
-	
-	if (! found)
-	{
-		exceptions.push(filter_str);
-		str = exceptions.join("\n");
-		su_ds.setValue("noscript.filterXExceptions", str);
-	}
-	
-	if ((typeof noscriptUtil) != "object")
-		return;
-	
-	if (noscriptUtil.service &&
-			noscriptUtil.service.setJSEnabled &&
-			((typeof noscriptUtil.service.setJSEnabled) == "function"))
-	{
-		noscriptUtil.service.setJSEnabled(su_servername, true);
-		noscriptUtil.service.setJSEnabled("recaptcha.net", true);
-	}
-	
-	su_ds.flushPrefs();
-}
-
-// populates the stumbles array using content from file 'stumbleurls'
-function su_load_stumbles(url_to_exclude)
-{
-	stumbles = new Array();
-	// Load stumbleurls (queue of urls to be stumbled upon)
-	var unseen = su_read_file_user("stumbleurls");
-	
-	var commands = unseen.split("\n");
-
-	try {
-		if (su_ds.getValue("$last_incat") == su_previous_query_category)
-			su_prefetcher.fetchAheadDepth = su_ds.getValue("$prefetcher_fetch_depth_in_query");
-		else
-			su_prefetcher.fetchAheadDepth = su_ds.getValue("$prefetcher_fetch_depth_in_topic");
-	} catch (e) {}
-	
-	var found_url_to_exclude = false;
-	var i;
-	var url_detail;
-	var target;
-	for (i = 0; i < commands.length; i++)
-	{
-		if ((commands[i].indexOf("http") != 0) &&
-			(commands[i].indexOf("https") != 0) &&
-			(commands[i].indexOf("ftp") != 0))
-			continue;
-		
-		url_detail = su_deserialize_url_command_params(commands[i], true);
-
-        // Skip any old stumbles that don't have a public id
-        if(!url_detail.publicid)
-            continue;
-		
-		target = url_detail.actual_url ? url_detail.actual_url : url_detail.url;
-		
-		if ((target == url_to_exclude) && (! found_url_to_exclude))
-		{
-			// exclude only the first instance of url_to_exclude
-			found_url_to_exclude = true;
-			continue;
-		}
-		
-		try {
-			if (su_is_404_status(su_prefetcher.getHttpResponseStatus(target)))
-			{
-				su_report_404(target, su_prefetcher.getHttpResponseStatus(target));
-				continue;
-			}
-		} catch (e) {}
-				
-		
-		stumbles.push(commands[i]);
-		
-		// Don't prefetch against stumbleupon.com.
-		if (target.indexOf(su_base_url) == 0)
-			continue;
-		
-		// Don't prefetch profiles.
-		if (su_get_profile_nickname(target))
-			continue;
-		
-		// Don't prefetch 'is_sound' urls.
-		if (su_is_sound(target))
-			continue;	
-		
-		// Don't prefetch sponsored stumbles.
-		if (url_detail.cluster_type == 3)
-			continue;
-		
-		// Don't prefetch referrals.
-		if (url_detail.cluster_type == 4)
-			continue;
-		
-		if (! url_detail.referrer)
-		{
-			if (su_is_adult_category(url_detail.catid))
-				url_detail.referrer = target;
-			else if (su_ds.getValue("@enable_refer"))
-				url_detail.referrer = "http://www.stumbleupon.com/refer.php?url=" + encodeURIComponent(target);
-			else
-				url_detail.referrer = "about:blank";
-		}
-		
-		try {
-			su_prefetcher.addTarget(url_detail);
-		} catch (e) { su_log_error("PREFETCHER 1", e); }
-	}
-}
-
-// populates su_ratings using content from file 'stumblerating'
-function su_load_ratings()
-{
-	su_ratings = new Object();
-	// load ratings
-	var stumblecat = su_read_file_user("stumblerating");
-	var splitcat = stumblecat.split("\n");
-	for (var i = 0; i < splitcat.length; i++)
-	{
-		if (splitcat[i] == "")
-			continue;
-		var split2 = splitcat[i].split(" ");
-		su_ratings[split2[0]] = split2[1];
-	}
-}	
-
-// populates su_user_interests using content from pref 'interests'
-function su_load_user_interests()
-{
-	su_user_interests = new Array();
-	
-	// Load su_user_interests
-	var stumbleseen = su_ds.getValue("$interests");
-	var splitseen = stumbleseen.split(" ");
-	var i;
-	for (i = 0; i < splitseen.length; i++)
-	{
-		if (splitseen[i] == "")
-			continue;
-		if (splitseen[i] == "toXMLRPCParam")
-			continue;
-		su_user_interests[splitseen[i]] = 1;
-	}
-}	
-
-// populates su_tags and su_tag_lists_by_url using content of the
-// stumbletags file
-function su_load_tags(url_to_exclude)
-{
-	su_tags = new Array();
-	su_tag_lists_by_url = new Object();
-	
-	var stumblecat = su_read_file_user("stumbletags");
-	var splitcat = stumblecat.split("\n");
-	
-	for (var i = 0; i < splitcat.length; i++)
-	{
-		if (splitcat[i] == "")
-			continue;
-		var split2 = splitcat[i].split("\t");
-		var o = new Object();
-		o.url = split2[0];
-		o.tag_list = split2[1];
-		if ((o.url != url_to_exclude) && (o.url.indexOf("about:") != 0))
-		{
-			su_tag_lists_by_url[o.url] = o.tag_list;
-			su_tags.push(o);
-		}
-	}
-}
-
-// stores content of su_tags into the stumbletags file
-function su_store_tags()
-{
-	var towrite = "";
-	for (var i = 0; (i < su_tags.length) && (i < su_ds.getValue("$tag_history_depth")); i++)
-		towrite += su_tags[i].url + "\t" + su_tags[i].tag_list + "\n";
-
-	su_write_file_user("stumbletags", towrite);
-}
-
-// populates su_queries using content of the stumblequeries file
-function su_load_queries()
-{
-	su_queries = new Array();
-	
-	var stumblequeries = su_read_file_user("stumblequeries");
-
-	if (stumblequeries != "")
-		su_queries = stumblequeries.split("\n");
-	
-	// !! This is an inefficient method to get rid of the empty last 
-	// element due to the trailing linefeed in the file, but we'll 
-	// leave it this way for now, as it contributes robustness. -- JW
-	for (var i = 0; i < su_queries.length; i++)
-	{
-		if (su_queries[i] == "")
-			su_queries.splice(i, 1);
-	}
-}
-
-// stores content of su_queries in the stumblequeries file
-function su_store_queries()
-{
-	var towrite = "";
-	for (var i = 0; (i < su_queries.length) && (i < su_ds.getValue("$query_history_depth")); i++)
-		towrite += su_queries[i] + "\n";
-
-	su_write_file_user("stumblequeries", towrite);
-}
-
-// initializes user-specific configuration that involves gui elements
-function su_load_data2(force_update)
-{
-	su_get_element("su_searchbox").autocompleteDatasource = 
-	{ 
-		getResults : function ()
-		{
-			var searchbox = su_get_element("su_searchbox");
-			return su_get_autocomplete_results(
-						su_ds.getValue("$autocomplete_type"),
-						searchbox.value,
-						searchbox.maxRows,
-						new Array());
-		}
-	};
-	
-//	su_update_verified_reporting(false);
-	su_update_referred(false);
-	
-	su_check_referral(force_update);
-	su_process_rarely(force_update, false);
-
-	if (force_update)
-	{
-		//!!! 1. Move contacts into getstate.php
-		//!!! 2. Sync tag & person subscriptions?
-		su_import_contacts();
-		su_get_state(false);
-	}
-	
-	// Store this stumbleid in the ids list.  The list is ordered from 
-	// most recently used to least recently used. -- JW
-	var id_list = su_ds.getValue("@id_list");
-	
-	var splitids = id_list.split(":");
-	var id_list_new = stumbleid + ":";
-	var i;
-	for (i = 0; i < splitids.length; i++)
-	{
-		if (splitids[i] == "")
-			continue;
-		
-		var line = splitids[i];
-		if (line != stumbleid)
-			id_list_new += splitids[i] + ":";
-	}
-	su_ds.setValue("@id_list", id_list_new);
-
-	su_ds.flushPrefs();
-
-	su_init_keybinding_globals();	
-
-	su_configure_toolbar(false);
-	
-	su_close_all_messages();
-
-	// Check to see when the url changes
-	su_add_progress_listener();
-
-	// Upload any pending old stumbles
-	su_upload_stumbles();
-	
-	window.addEventListener("keyup", su_handle_window_keyup, false);
-	window.addEventListener("keypress", su_handle_window_keypress, false);
-	window.addEventListener("mousedown", su_handle_window_mousedown, true);
-	su_ds.addEventListener("resourceinstalled", su_handle_resource_installed, false);
-	
-	su_download_favs(false);	
-	su_process_command_queue();
-}
-
-function su_process_command_queue()
-{
-	if (! su_host.places)
-		return;
-	
-	// wait for places migration to finish
-	if (su_ds.getValue("#migrating_places"))
-		return;
-	
-	var context;
-	
-	if (su_ds.getValue("#command_queue_context"))
-		return;
-	
-	var db = su_ds.getDatabase();
-	var sql;
-	var result;
-	sql = "SELECT seqid FROM command_queue WHERE priority>0 ORDER BY priority DESC, seqid LIMIT 1";
-	result = db.query(sql);
-	if (result.length == 0)
-	{
-		su_ds.setValue("#download_favs_detail", null);
-//		su_ds.setValue("#command_queue_context", null);
-		return;
-	}
-	
-	context = new Object();
-
-	su_ds.setValue("#command_queue_context", context);
-	
-	context.priority == null;
-	context.command_rows = null;
-	context.processed_idx = 0;
-	context.download_favs_detail = null;
-//	context.abort = false;
-	setTimeout(su_process_command_queue2, 200, context);
-}
-
-function su_process_command_queue2(context)
-{
-	var db = su_ds.getDatabase();
-	var sql;
-	var seqid;
-	var command;
-	var row;
-	var detail;
-	var val;
-	
-	// 1. grab a set of commands
-	if (! context.command_rows)
-	{
-		sql = "SELECT priority,seqid,command FROM command_queue WHERE priority>0 ORDER BY priority DESC, seqid LIMIT 1000";
-		context.command_rows = db.query(sql);
-		context.processed_idx = 0;
-	}
-	
-	// 2. check whether we're done.
-//	if ((context.command_rows.length == 0) || context.abort)
-	if (context.command_rows.length == 0) 
-	{
-		su_ds.setValue("#command_queue_context", null);
-		// moving out of favs
-		if (context.download_favs_detail)
-		{
-			su_set_download_favs_enabled(true);
-			context.download_favs_detail = null;
-		}
-		setTimeout(su_process_command_queue, 0);
-		return;
-	}
-	
-	row = context.command_rows[context.processed_idx];
-	
-	if (context.download_favs_detail && (row.priority != 16000))
-	{
-		// moving out of favs
-		su_set_download_favs_enabled(true);
-		
-		context.download_favs_detail = null;
-	}
-	else if ((context.priority != 16000) && (row.priority == 16000))
-	{
-		// moving into favs
-		su_set_download_favs_enabled(false);
-		
-		detail = su_ds.getValue("#download_favs_detail");
-		if (! detail)
-		{
-			detail = su_ds.getValue("$download_favs_detail");
-			su_ds.setValue("#download_favs_detail", detail);
-		}
-		context.download_favs_detail = detail;
-	}
-	
-	context.priority = row.priority;
-	
-	if (context.download_favs_detail)
-	{
-		detail = context.download_favs_detail;
-		detail.apply_count++;
-		if ((detail.applied_count % 1000) == 0)
-		{
-			su_ds.setValue("$download_favs_detail", detail);
-			su_ds.flushPrefs();
-		}
-		
-		if (su_preference_dialog)
-		{
-			val = 5 + Math.round((45 * (detail.download_count / detail.download_target_count)) + (45 * (detail.apply_count / detail.apply_target_count)));
-			
-			el = su_preference_dialog.ownerDocument.getElementById("download_progress");
-			if (el && (val != el.value))
-				el.setAttribute("value", val);
-		}
-	}
-	
-	// 3. process the command
-	su_process_command(row.command, context);
-	
-	// 4. remove it from the queue
-	sql = "DELETE FROM command_queue WHERE seqid=" + db.v(row.seqid);
-	db.query(sql);
-	context.processed_idx++;
-	
-	if (context.command_rows.length == context.processed_idx)
-		context.command_rows = null;
-	
-	setTimeout(su_process_command_queue2, 50, context);
-}
-
-function su_set_download_favs_enabled(enabled)
-{
-	var el;
-	var doc;
-	var sync;
-	
-	if (! su_preference_dialog)
-		return;
-	
-	doc = su_preference_dialog.ownerDocument; 
-	
-	sync = doc.getElementById("sync_bm_meta").checked;
-	
-	if (enabled)
-		doc.getElementById("download_progress").value = 0;
-
-	doc.getElementById("download_start").disabled = (! sync) || (! enabled);
-	
-	doc.getElementById("download_stop").disabled = (! sync) || enabled;
-}
-
-// used during init to set hidden states for top-level toolbar
-// element
-function su_init_toolbar_element_visibility()
-{
-	if ((stumbleid == 0) && su_promo_mode)
-	{
-		su_set_visible("su_start",         true);
-		su_set_visible("su_login",         true);
-		su_set_visible("su_stumble",       false);
-		su_set_visible("su_sites_promo",   true);
-		su_set_visible("su_friends",       true);
-		su_set_visible("su_thumbup",       true);
-		su_set_visible("su_thumbdown",     false);
-		su_get_element("su_thumbdown").type = "";
-		su_set_visible("su_separator2",    true);
-		su_set_visible("su_website_info_promo", true);
-		su_set_visible("su_separator_promo", true);
-		su_set_visible("su_referral_promo", true);
-		su_set_visible("su_separator_category", true);
-		su_set_visible("su_separator4",    true);
-		su_set_visible("su_video_promo",   true);
-		su_set_visible("su_separator6",    true);
-		su_set_visible("su_profile",       true);
-		su_set_visible("su_separator7",    false);
-		su_set_visible("su_mode",          false);	
-		su_set_visible("su_stumble_menu",  false);
-		su_set_visible("su_category",      false);
-		su_set_visible("su_website_info",  false);
-		su_set_visible("su_network",       false); // legacy network
-		su_set_visible("su_messages",      false);	
-		su_set_visible("su_field",         false);
-		su_has_searchbox = false;
-	
-		su_set_visible("su_filter",        false);
-		su_set_visible("su_aboutme",       false);
-		su_set_visible("su_matches",       false);
-		su_set_visible("su_groups",        false);
-		su_set_visible("su_myinfo",        false);
-		su_set_visible("su_forum",         false);   // legacy forums
-		su_set_visible("su_referral_menu", false);
-//		su_set_visible("su_inbox-count",   false);
-		su_set_visible("su_referred", false);
-	
-		su_set_visible("su_page_feature_prompt", false);
-		su_set_visible("firstrater",       false);
-		su_set_visible("su_stumble_topic", false);
-		su_set_visible("su_stumble_topic_menu_left", false);
-		su_set_visible("su_stumble_topic_menu_right", false);
-		su_set_visible("su_sponsor",       false);
-		su_set_visible("su_tag",           false);
-		su_set_visible("su_tag2",          false);
-		su_set_visible("su_splitter_search_right", false);
-	}
-	else if (stumbleid == 0)
-	{
-		su_set_visible("su_start",         true);
-		su_set_visible("su_login",         (! su_has_logged_in()));
-		su_set_visible("su_stumble",       false);
-		su_set_visible("su_sites_promo",   false);
-		su_set_visible("su_friends",       false);
-		su_set_visible("su_thumbup",       false);
-		su_set_visible("su_thumbdown",     false);
-		su_get_element("su_thumbdown").type = "";
-		su_set_visible("su_separator2",    false);
-		su_set_visible("su_website_info_promo", false);
-		su_set_visible("su_separator_promo", false);
-		su_set_visible("su_referral_promo", false);
-		su_set_visible("su_separator4",    false);
-		su_set_visible("su_separator_category", false);
-		su_set_visible("su_video_promo",   false);
-		su_set_visible("su_separator6",    false);
-		su_set_visible("su_separator7",    false);
-		su_set_visible("su_profile",       false);
-		su_set_visible("su_mode",          false);
-		su_set_visible("su_stumble_menu",  false);
-		su_set_visible("su_category",      false);
-		su_set_visible("su_website_info",  false);	
-		su_set_visible("su_network",       false); // legacy network
-		su_set_visible("su_messages",      false);	
-		su_set_visible("su_field",         false);
-		su_has_searchbox = false;
-		su_set_visible("su_filter",        false);
-		su_set_visible("su_aboutme",       false);	
-		su_set_visible("su_matches",       false);	
-		su_set_visible("su_groups",        false);	
-		su_set_visible("su_myinfo",        false);
-		su_set_visible("su_forum",         false);   // legacy forums
-		su_set_visible("su_referral_menu", false);
-//		su_set_visible("su_inbox-count",   false);
-		su_set_visible("su_referred", false);
-		su_set_visible("su_page_feature_prompt", false);
-		su_set_visible("firstrater",       false);
-		su_set_visible("su_stumble_topic", false);
-		su_set_visible("su_stumble_topic_menu_left", false);
-		su_set_visible("su_stumble_topic_menu_right", false);
-		su_set_visible("su_sponsor",       false);
-		su_set_visible("su_tag",           false);
-		su_set_visible("su_tag2",          false);
-		su_set_visible("su_splitter_search_right", false);
-	}
-	else
-	{
-		// show rating buttons, menu, etc...
-		su_set_visible("su_start",         false);
-		su_set_visible("su_login",         false);
-		su_set_visible("su_stumble",       true);
-		su_set_visible("su_separator4",    (
-			                                   (su_ds.getValue("$show_mode")  &&
-											   su_ds.getValue("$show_separators"))
-										   )
-			          );
-		su_set_visible("su_separator_category", su_ds.getValue("$show_topics") || !su_get_element("su_stumble_topic_menu_left").collapsed);
-		su_set_visible("su_thumbup",       true);
-		su_set_visible("su_thumbdown",     true);
-		su_get_element("su_thumbdown").type = "menu-button";
-		su_set_visible("su_separator2",    su_ds.getValue("$show_separators"));
-		su_set_visible("su_referral_promo", false);
-		su_set_visible("su_separator_promo",  false);
-		su_set_visible("su_website_info_promo", false);
-		su_set_visible("su_stumble_menu",  true);
-		su_set_visible("su_category",      su_ds.getValue("$show_topics"));
-		su_set_visible("su_website_info",  su_ds.getValue("$show_info"));
-		su_set_visible("su_field",         su_ds.getValue("$show_field"));
-		su_has_searchbox = su_ds.getValue("$show_field");
-		su_set_visible("su_splitter_search_right", su_ds.getValue("$show_field"));
-		su_set_visible("su_tag",           (su_ds.getValue("$show_tag") && su_ds.getValue("$show_field")) );
-		su_set_visible("su_tag2",  (su_ds.getValue("$show_tag") && (! su_ds.getValue("$show_field"))) );
-		su_set_visible("su_referral_menu", su_ds.getValue("$show_referral"));
-		su_set_visible("su_separator6",    (! (
-												(
-													(! su_ds.getValue("$show_field")) &&
-													(! su_ds.getValue("$show_info")) &&
-													(! su_ds.getValue("$show_referral")) &&
-													(! su_ds.getValue("$show_tag"))
-												) ||
-												(
-													su_ds.getValue("$show_field") &&
-													(!su_ds.getValue("$show_tag"))
-												) ||
-												(! su_ds.getValue("$show_separators"))
-											   )
-											)
-					  );
-		su_set_visible("su_aboutme",       su_ds.getValue("$show_aboutme"));
-		su_set_visible("su_sites_promo",   false);
-		su_set_visible("su_video_promo",   false);
-		su_set_visible("su_page_feature_prompt", false);
-		su_set_visible("su_filter",        su_ds.getValue("$show_filter"));
-		su_set_visible("firstrater",       false);
-		su_set_visible("su_separator7",    false);
-		su_set_visible("su_stumble_topic", false);
-		su_set_visible("su_stumble_topic_menu_left", false);
-		su_set_visible("su_stumble_topic_menu_right", false);
-		su_set_visible("su_sponsor",       false);
-		su_set_visible("su_profile",       su_ds.getValue("$show_home"));
-		su_set_visible("su_friends",       su_ds.getValue("$show_friends"));
-		su_set_inbox_status((su_ds.getValue("$newmessage")) ? '2' : '');
-//		su_set_visible("su_messages",      su_ds.getValue("$show_messages"));
-		su_set_visible("su_network",       su_ds.getValue("$show_legacy_network"));
-		su_set_visible("su_matches",       su_ds.getValue("$show_matches"));
-		su_set_visible("su_forum",         su_ds.getValue("$show_legacy_forums"));
-		su_set_visible("su_groups",        su_ds.getValue("$show_groups"));
-		su_set_visible("su_myinfo",        su_ds.getValue("$show_myinfo"));
-	
-		var mode_ids = [
-					"mode",
-	//				"mode_all",
-					"mode_friends",
-					"mode_news",
-					"mode_photo",
-					"mode_search",
-					"mode_stumblers",
-					"mode_video",
-					"mode_wiki",
-					"mode_more"];
-		var i;
-		for (i = 0; i < mode_ids.length; i++)
-			su_set_visible("su_" + mode_ids[i], su_ds.getValue("$show_" + mode_ids[i]));
-		su_set_visible("su_mode_all", true);
-
-		su_set_visible("su_recthumbup", su_ds.getValue("$dd_rec_rating") != 0);
-	}
-}
-
-function su_refresh_dyn_channels()
-{
-	su_invoke_global_event("dyn-channels-dirty", null);
-	
-	if (su_refreshing_dyn_channels)
-		return;
-	
-	su_refreshing_dyn_channels = true;
-	
-	setTimeout(
-				function (win) {
-					win.su_invoke_global_event("update-dyn-channels", null); },
-				500,
-				window);
-}
-
-function su_update_dyn_channels()
-{
-	su_refreshing_dyn_channels = false;
-
-	if (! su_dyn_channels_dirty)
-		return;
-	
-	if (su_mode_more_popup_open)
-		return;
-	
-	su_dyn_channels_dirty = false;
-	
-	var channels = su_ds.getThruDomainChannels(true);
-	
-	if (! channels)
-	{
-		if (! su_ds.getValue("#checked_dyn_channels"))
-			su_check_dyn_channels();
-		return;
-	}
-	
-	var parent = su_get_element("su_mode");
-	var brother_el = su_get_element("su_mode_all");
-	var id;
-	var channel_id;
-	var el;
-	var i;
-	for (i = 0; i < channels.length; i++)
-	{
-		channel_id = su_get_channel_id(channels[i].domain); 
-		id = "su_mode_dyn_" + channel_id;
-		el = su_get_element(id);
-		if (el)
-			el.parentNode.removeChild(el);
-
-		id = "su_mode_more_" + channel_id;
-		el = su_get_element(id);
-		if (el)
-			el.parentNode.removeChild(el);
-	}
-	
-	var more_popup = su_get_element("su_mode_more_popup");
-	while (more_popup.lastChild)
-		more_popup.removeChild(more_popup.lastChild);
-	
-	for (i = 0; i < channels.length; i++)
-	{
-		channel_id = su_get_channel_id(channels[i].domain); 
-		var icon_url = su_ds.getResourceURLFromName("favicons", 
-					channel_id + ".ico")
-		
-		id = "su_mode_more_" + channel_id;
-		el = document.createElement("menuitem");
-		el.setAttribute("id", id);
-		el.setAttribute("label", " " + channels[i].name);
-		el.setAttribute("onclick", "su_handle_domain_mode_click(event, '" + channels[i].domain + "');");
-		el.setAttribute("tooltiptext", "StumbleThru " + channels[i].name);
-		el.setAttribute("class", "menuitem-iconic");
-		el.setAttribute("image", icon_url);
-		more_popup.appendChild(el);
-		
-		if (channels[i].show)
-		{
-			// If they've added a dyn channel button, we don't need to
-			// educate via the info bubble. -- Jw
-			su_ds.setValue("$shown_thru_domain_info_count", su_ds.getValue("~shown_thru_domain_info_count_max"));
-			
-			id = "su_mode_dyn_" + channel_id;
-			el = document.createElement("toolbarbutton");
-			el.setAttribute("id", id);
-			el.setAttribute("class", "su-hidetext");
-			el.setAttribute("su_ismode", "1");
-			el.setAttribute("onclick", "su_handle_domain_mode_click(event, '" + channels[i].domain + "');");
-			el.setAttribute("tooltiptext", "StumbleThru " + channels[i].name);
-			el.setAttribute("image", icon_url);
-			parent.insertBefore(el, brother_el);
-			su_set_image(id, icon_url);
-		}
-	}
-	su_refreshing_dyn_channels = false;
-	su_update_thru_domain(su_get_browser_url(), null, null, null, true);
-	su_reflow_toolbar(14);
-}
-
-// used by move_toolbar() to initialize splitters
-function su_init_splitters()
-{
-	try {
-	var sidebar_splitter = su_get_element("sidebar-splitter");
-	
-	if (sidebar_splitter)
-	{
-		sidebar_splitter.addEventListener("DOMAttrModified", su_handle_sidebar_attr_modified, false);
-		sidebar_splitter.addEventListener("mouseup", su_handle_sidebar_mouseup, false);
-	}
-	
-	var width = su_ds.getValue("@search-width");
-	if (width == 0)
-	{
-		width = 156;
-		su_ds.setValue("@search-width", width);
-	}
-	if (width > 400)
-	{
-		width = 400;
-		su_ds.setValue("@search-width", width);
-	}
-	su_get_element("su_field").setAttribute("width", width + "px");
-
-	su_get_element("su_splitter_first_flexbox").collapsed = false;
-
-	setTimeout(function (win) { win.su_refresh_splitters(true); }, 0, window);
-	} catch (e) { su_log_error("INIT SPLITTERS", e, su_ds.getValue("@toolbar-position"), su_ds.getValue("@position-group")); }
-}	
-
-// used during init to initialize globals and to survey existing 
-// keybindings
-function su_init_keybinding_globals()
-{
-	su_init_key_const_dictionaries();
-
-	var keys = document.getElementsByTagName("key");
-	
-	for (var i = 0; i < keys.length; i++)
-		su_keys_by_keyspec[su_get_keyspec_from_key(keys[i])] = keys[i];
-}
-
-// used by init_keybinding_globals to populate
-// su_keyids_by_eventkeycode, su_chars_by_keyid and su_keyids_by_char
-function su_init_key_const_dictionaries()
-{
-	var keyid;
-	var property;
-	for (property in KeyEvent)
-	{
-		if (su_is_property_garbage(KeyEvent, property))
-			continue;
-		
-		keyid = property.replace("DOM_","");
-		su_keyids_by_eventkeycode[KeyEvent[property]] = keyid;
-		if (keyid.length == 4)
-			su_chars_by_keyid[keyid] = String.fromCharCode(KeyEvent[property]);
-	}
-	su_keyids_by_eventkeycode[8] = "VK_BACK";
-	
-	var o = su_chars_by_keyid;	
-	o["VK_SEMICOLON"] = ";";
-	o["VK_EQUALS]"] = "=";
-	o["VK_MULTIPLY"] = "*";
-	o["VK_ADD"] = "+";
-	o["VK_SUBTRACT"] = "-";
-	o["VK_DECIMAL"] = ".";
-	o["VK_DIVIDE"] = "/";
-	o["VK_COMMA"] = ",";
-	o["VK_PERIOD"] = ".";
-	o["VK_SLASH"] = "/"; // overwrites VK_DIVIDE in su_keyids_by_char
-	o["VK_BACK_QUOTE"] = "`";
-	o["VK_OPEN_BRACKET"] = "[";
-	o["VK_BACK_SLASH"] = "\\";
-	o["VK_CLOSE_BRACKET"] = "]";
-	o["VK_QUOTE"] = '"';
-
-	su_keyids_by_char = su_invert_dictionary(su_chars_by_keyid);
-}
-
-// used by init_keybinding_globals to get the keyspec from a key 
-// element
-function su_get_keyspec_from_key(key)
-{
-  var str = "";
-
-	var modifiers = key.getAttribute("modifiers").toLowerCase();
-
-	if (modifiers.indexOf("alt") != -1)     str += "Alt+";
-	if (modifiers.indexOf("control") != -1) str += "Ctrl+";
-	if (modifiers.indexOf("meta") != -1)    str += "Command+";
-	if (modifiers.indexOf("accel") != -1)
-	{
-		if (su_host.mac)
-			str += "Command+";
-		else
-			str += "Ctrl+"
-	}
-	if (modifiers.indexOf("shift") != -1)   str += "Shift+";
-
-	var keyid;
-	if (key.hasAttribute("key") && (key.getAttribute("key").length == 1))
-	{
-		keyid = key.getAttribute("key").toUpperCase();
-		var keyid_tmp = su_keyids_by_char[keyid];
-		if (keyid_tmp)
-			keyid = keyid_tmp;
-	}
-	else if (key.hasAttribute("keycode"))
-	{
-		keyid = key.getAttribute("keycode");
-	}
-	
-	if (! keyid)
-		keyid = "";
-	
-	str += keyid;
-
-	return str;
-}
-
-// called by the global configure-toolbar event and during init
-// to update the key bindings
-function su_refresh_keybindings()
-{
-	// It would be more friendly to other extensions if we'd add key
-	// elements rather than attach a keyup listener to the window.
-	// But we have to use a keyup listener in order to distinguish
-	// between 'numeral keys on the number row' and 'numeral keys on 
-	// the numeric keypad w/ numlock turned on'.  This is necessary to
-	// avoid a conflict between binding Alt+VK_1 and typing a special
-	// character via Alt+[keycode] using the numeric keypad on XP.
-	// We're supposed to be able to distinguish between the number row
-	// and the keypad keys using different keycodes (i.e. VK_1 vs 
-	// VK_NUMPAD1) [1], but if one of those keycodes is specified on a 
-	// key element, its command is never invoked (ref Firefox 1.5, XP).
-	// -- JW
-	// [1]
-	// http://www.xulplanet.com/tutorials/xultu/keyshort.html
-	
-	var stumble_default;
-	var reviews_default;
-	var thumbup_default;
-	var thumbdown_default;
-	var tag_default;
-//	var details_default;
-	var toolbar_default;
-	if (su_host.mac)
-	{
-		stumble_default = "Alt+VK_ESCAPE";
-		thumbup_default = "Alt+VK_F1";
-		thumbdown_default = "Alt+VK_F2";
-		tag_default =     "ALT+VK_SLASH";
-		reviews_default = "Alt+VK_F3";
-//		details_default = "Alt+VK_F4";
-		toolbar_default = "Command+VK_F11";
-	}
-	else if (su_host.win)
-	{
-		stumble_default = "Alt+VK_BACK_QUOTE";
-		thumbup_default = "Alt+VK_1";
-		thumbdown_default = "Alt+VK_2";
-		tag_default =     "ALT+VK_SLASH";
-		reviews_default = "Alt+VK_3";
-		//		details_default = "Alt+VK_4";
-		toolbar_default = "Ctrl+VK_F11";
-	}
-	else
-	{
-		stumble_default = "Alt+VK_ESCAPE";
-		thumbup_default = "Alt+VK_F1";
-		thumbdown_default = "Alt+VK_F2";
-		tag_default =     "ALT+VK_SLASH";
-		reviews_default = "Alt+VK_F3";
-//		details_default = "Alt+VK_F4";
-		toolbar_default = "Ctrl+VK_F11";
-	}
-	var keyspecs = new Array();
-	su_commands_by_keyspec = new Object();
-	var keyspec;
-	
-	var rating_enabled = su_ds.getValue("$shortcuts_enabled");
-	
-	keyspec = su_ds.getPrefValue("$shortcut_stumble", stumble_default);
-	if (rating_enabled && (keyspec != ""))
-	{
-		keyspecs.push(keyspec);
-		su_commands_by_keyspec[keyspec] = su_get_element("StumbleUpon:Stumble");
-	}
-
-	keyspec = su_ds.getPrefValue("$shortcut_thumbup", thumbup_default);
-	if (rating_enabled && (keyspec != ""))
-	{
-		keyspecs.push(keyspec);
-		su_commands_by_keyspec[keyspec] = su_get_element("StumbleUpon:RateThumbup");
-	}
-
-	keyspec = su_ds.getPrefValue("$shortcut_thumbdown", thumbdown_default);
-	if (rating_enabled && (keyspec != ""))
-	{
-		keyspecs.push(keyspec);
-		su_commands_by_keyspec[keyspec] = su_get_element("StumbleUpon:RateThumbdown");
-	}
-
-	keyspec = su_ds.getPrefValue("$shortcut_tag", tag_default);
-	if (rating_enabled && (keyspec != ""))
-	{
-		keyspecs.push(keyspec);
-		su_commands_by_keyspec[keyspec] = su_get_element("StumbleUpon:Tag");
-	}
-
-	keyspec = su_ds.getPrefValue("$shortcut_reviews", reviews_default);
-	if (rating_enabled && (keyspec != ""))
-	{
-		keyspecs.push(keyspec);
-		su_commands_by_keyspec[keyspec] = su_get_element("StumbleUpon:ViewReviews");
-	}
-
-//	keyspec = su_ds.getPrefValue("$shortcut_details", details_default);
-//	if (rating_enabled && (keyspec != ""))
-//	{
-//		keyspecs.push(keyspec);
-//		su_commands_by_keyspec[keyspec] = su_get_element("StumbleUpon:RateThumbupDetailed");
-//	}
-
-	keyspec = su_ds.getPrefValue("$shortcut_toolbar", toolbar_default);
-	if (keyspec != "")
-	{
-		keyspecs.push(keyspec);
-		su_commands_by_keyspec[keyspec] = su_get_element("StumbleUpon:ToggleToolbar");
-	}
-
-	if (su_ds.getValue("$shortcut_toolbar") != toolbar_default)
-	{
-		var toggle_key = su_get_element("key_StumbleUpon:ToggleToolbar");
-		
-		if (toggle_key.hasAttribute("command"))
-		{
-			toggle_key.setAttribute("savedcommand", toggle_key.getAttribute("command"));
-			toggle_key.removeAttribute("command");
-		}
-	}
-
-	if (su_get_element("stumbleupon"))
-	{
-		var toolbar_keyspec = su_ds.getValue("$shortcut_toolbar");
-		if (toolbar_keyspec == "")
-		{
-			su_get_element("stumbleupon").setAttribute("toolbarname", "StumbleUpon Toolbar");
-		}
-		else
-		{
-			su_get_element("stumbleupon").setAttribute("toolbarname", "StumbleUpon Toolbar (" + 
-						su_get_display_keyspec(su_ds.getValue("$shortcut_toolbar")) + 
-						")");
-		}
-	}
-
-	for (keyspec in su_removed_keybindings_by_keyspec)
-	{
-		if (su_is_property_garbage(su_removed_keybindings_by_keyspec, keyspec))
-			continue;
-		
-		if (su_removed_keybindings_by_keyspec[keyspec])
-		{
-			su_removed_keybindings_by_keyspec[keyspec].alive = false;
-		}
-	}
-	
-	for (var i = 0; i < keyspecs.length; i++)
-	{
-		var key;
-		var binding;
-		if (su_keys_by_keyspec[keyspecs[i]])
-		{
-			key = su_keys_by_keyspec[keyspecs[i]];
-			binding = new Object();
-			binding.alive = true;
-			binding.key = key;
-
-			if (key.hasAttribute("command"))
-			{
-				binding.command = key.getAttribute("command");
-				key.removeAttribute("command");
-			}
-
-			if (key.hasAttribute("oncommand"))
-			{
-				binding.oncommand = key.getAttribute("oncommand");
-				key.removeAttribute("oncommand");
-			}
-
-			if (key.hasAttribute("onkeypress"))
-			{
-				binding.onkeypress = key.getAttribute("onkeypress");
-				key.removeAttribute("onkeypress");
-			}
-
-			su_removed_keybindings_by_keyspec[keyspecs[i]] = binding;
-		}
-	}
-	
-	for (keyspec in su_removed_keybindings_by_keyspec)
-	{
-		if (su_is_property_garbage(su_removed_keybindings_by_keyspec, keyspec))
-			continue;
-		
-		if (su_removed_keybindings_by_keyspec[keyspec])
-		{
-			var binding = su_removed_keybindings_by_keyspec[keyspec];
-			
-			if (! binding.alive)
-			{
-				if (binding.command)
-					binding.key.setAttribute("command", binding.command);
-
-				if (binding.oncommand)
-					binding.key.setAttribute("oncommand", binding.oncommand);
-
-				if (binding.onkeypress)
-					binding.key.setAttribute("onkeypress", binding.onkeypress);
-
-				delete su_removed_keybindings_by_keyspec[keyspec];
-			}
-		}
-	}
-}
-
-// used by refresh_keybindings and the preferenceDialog to convert a
-// keyspec into its readable form
-function su_get_display_keyspec(keyspec)
-{
-	var keyid = su_get_keyid_from_keyspec(keyspec);
-	if (su_chars_by_keyid[keyid])
-	{
-		var regexp = new RegExp(su_escape_regexp_chars(keyid) + "$");
-		keyspec = keyspec.replace(regexp, su_chars_by_keyid[keyid]);
-	}
-	return keyspec.replace("VK_", "").replace(/BACK$/, "BACKSPACE");
-}
-
-// given a keyspec, returns a string that specifies the corresponding
-// modifiers for a key object
-function su_get_modifiers_from_keyspec(keyspec)
-{
-	var parts = keyspec.split("+")
-
-	var str = "";
-	for (var i = 0; i < parts.length; i++)
-	{
-		switch (parts[i])
-		{
-			case "Alt":     str += "alt ";     break;
-			case "Ctrl":    str += "control "; break;
-			case "Command": str += "meta ";    break;
-			case "Shift":   str += "shift ";   break;
-		}
-	}
-
-	if (str != "")
-	{
-		str = str.substring(0, str.length);
-	}
-	return str;
-}
-
-// given a keyspec, returns the keyid portion
-function su_get_keyid_from_keyspec(keyspec)
-{
-	var parts = keyspec.split("+");
-	if (parts[parts.length - 1] == "")
-		return "+";  // probably cruft -- JW
-	else
-		return parts[parts.length - 1];
-}
-
-function su_handle_content_click(event)
-{
-	if (stumbleid == 0)
-		return true;
-	
-//	getBrowser().selectedBrowser.su_content_clicked = true;
-	
-	try {
-		if (su_is_server_page(event.target.href, "login.php?logout=1"))
-		{
-			setTimeout(su_handle_page_logout_click, 0);
-			return su_cancel_event(event);
-		}
-	} catch (e) {}
-
-	var ondblclick = "";
-	
-	if (event.originalTarget.hasAttribute("ondblclick"))
-		ondblclick = event.originalTarget.getAttribute("ondblclick");
-	
-	var current_page = su_get_browser_url(event.target.ownerDocument, true);
-	
-	var slq = su_ds.globals.sluqh[current_page];
-	
-	if (slq && (ondblclick == ""))
-		ondblclick = "slr";
-	
-	if (ondblclick == "")
-		return true;
-	
-	var cancel_click = false;
-
-	if (ondblclick == "stumble_thru")
-		cancel_click = su_process_stumblethru_click(event);
-	else if(ondblclick == "whitelist_stumbleupon_with_noscript")
-	{
-		var tld = su_get_tld(current_page);
-		if (tld == su_servername)
-		{
-			su_update_noscript_whitelists();
-			cancel_click = true;
-			
-			var ps = su_get_service(
-						"@mozilla.org/embedcomp/prompt-service;1",
-						"nsIPromptService");
-			
-			ps.alert(window, "StumbleUpon", "NoScript configuration updated.  You may need to refresh the page or try the operation again.");
-		}
-	}
-	else
-		su_process_slstats_click(event, current_page, ondblclick, ((slq) ? slq : null));
-	
-	if (cancel_click)
-		return su_cancel_event(event);
-	
-	return true;
-}
-
-function su_process_stumblethru_click(event)
-{
-	var target_anchor = su_get_target_anchor(event.originalTarget, 5);
-	
-	if (! target_anchor)
-		return false;
-	
-	var target = target_anchor.getAttribute("href").toLowerCase();
-	
-	if (target.indexOf("http://www." + su_servername + "/through.php?") != 0)
-		return false;
-	//!!! add stumblevideo case
-
-	var through_match = target.match(/^http:\/\/[^\/]*\/through.php\?(.+)/);
-	
-	if (! through_match)
-		return false;
-	
-	if (! through_match.length >= 2)
-		return false;
-	
-	if (! su_ds.getValue("@toolbar-visible"))
-		su_toggle_toolbar();
-	
-	// parse out arguments			
-	var spliturl = through_match[1].split("&");
-	
-	su_process_stumble_now(spliturl)
-}
-
-function su_process_stumble_now(args)
-{
-	var topic_function = "";
-	var topic_displayed = "";
-
-	var mode = "";
-	var tag = "";
-	var user = "";
-	var topic = "";
-	
-	for (var i = 0; i < args.length; i++)
-	{
-		var thearg = args[i];
-		var argsplit = thearg.split("=");
-		if (argsplit.length > 1)
-		{
-			var key = decodeURIComponent(argsplit[0]);
-			var value = decodeURIComponent(argsplit[1]);
-	
-			if (key == "mode")
-				mode = value;
-			else if (key == "tag")
-				tag = value;
-			else if (key == "user")
-				user = value;								 		
-			else if (key == "topic")
-				topic = value;
-		}
-	}
-	
-	if (mode == "")
-		return false;
-	
-//						alert("MODE " + mode + " TAG " + tag + " USER " + user + " TOPIC " + topic);	
-	// we have something	
-	// news, all, tag, video, wiki, photo, language, incat	
-
-	su_unfocus_searchbox(); 
-	
-	// put it in the box
-	su_get_element("su_searchbox").value=tag;
-	su_get_element("su_searchbox").removeAttribute("mode");
-	su_old_search = tag;
-	su_last_typed_tag = 0;
-	su_visited_searchbox = 1;
-
-	var category;
-	var label;
-	// select and do it
-	if (mode == "all")
-	{
-		category = 0;
-		label = "All";
-	}
-	else if (mode == "news")
-	{
-		//!!! tagged news?
-		category = "news";
-		label = "News";
-	}
-	else if (mode == "tag" && tag != "")
-	{
-		category = "TAG_" + tag;
-		label = tag;
-	}
-	else if (mode == "user" && user != "" && tag == "")
-	{
-		category = user;
-		label = user;
-	}
-	else if (mode == "user" && user != "" && tag != "")
-	{
-			//!!!!!????
-		category = "USERTAG_" + user + "_" + tag;
-		label = user;
-	}
-	else if (mode == "subscriptions")
-	{
-		category = 'friends';
-		label = 'Stumblers';
-	}
-	else if (mode == "incat" && topic != "")
-	{
-		category = topic;
-		label = su_catnames[topic];
-		if(!label)
-		{
-			// Check for a tag as a backup when the topic id does not exist.
-			if(tag)
-			{
-				category = "TAG_" + tag;
-				label = tag;
-			}
-			else
-			{
-				su_set_location("http://www." + su_servername + "/tag/");
-				return true;
-			}
-		}
-	}
-	
-	setTimeout(su_select_topic, 0, category, label, false);
-	return true;
-}
-
-function su_process_slstats_click(event, current_page, ondblclick, slq)
-{
-	var target_anchor = su_get_target_anchor(event.originalTarget, 5);
-	if (! target_anchor)
-		return;
-
-	if ((! su_host.sha1) || (! su_ds.getValue("@enable_slstats")))
-		return;
-	
-	var sldetail = su_get_search_query_detail(null, current_page);
-	su_ds.setValue("#sldetail", sldetail); 
-	sldetail.target = target_anchor.getAttribute("href");
-	var slt;
-	if (target_anchor.hasAttribute("slt"))
-		slt = target_anchor.getAttribute("slt");
-	else if (slq)
-		slt = "" + slq + su_service.getSha1(target_anchor.getAttribute("href"));
-	
-	if (! slt)
-		return;
-	
-	if (typeof(su_ds.globals.sltih[slt]) == "undefined")
-		return;
-
-	var row;
-	var sli = su_ds.globals.sltih[slt];
-	var new_row;
-	if (typeof(sli.rowid) != "undefined")
-	{
-		new_row = false;
-		row = su_ds.selectRow("slclick", "_r", sli.rowid);
-	}
-	else if (sli.detail)
-	{
-		new_row = true;
-		row = sli.detail;
-	}
-	else
-	{
-		new_row = true;
-		row = new Object();
-		row.q = slq;
-		row.i = sli.i;
-	}
-	
-	switch (ondblclick)
-	{
-		case "slp":
-			row.p = 1;
-			break;
-		case "sln":
-			row.n = 1;
-			break;
-		case "slu":
-			row.u = 1;
-			break;
-		case "slz":
-			row.z = 1;
-			break;
-		case "slr":
-			row.r = 1;
-			break;
-	}
-	
-	if (new_row)
-		sli.rowid = su_ds.insertRow("slclick", row);
-	else
-		su_ds.updateRow(row);
-	
-	return;
-}
-
-function su_check_progress_listener()
-{
-	// Check whether the datastore object has buffered any errors.
-	setTimeout(function (win) { win.su_log_error(); }, 0, window);
-	
-	//!!! we have to keep doing this contantly because firefox likes to randomly
-	// drop our addprogresslisteners.  sad but true.
-	
-	// I think the progresslistener gets added to whichever browser
-	// currently has focus in the tabbrowser.  When a browser goes away,
-	// our listener disappears. -- JW 
-	
-	getBrowser().removeProgressListener(su_downloadProgressListener);
-	getBrowser().addProgressListener(su_downloadProgressListener);
-
-	// for instances where we still need a load listener ( such as interests_after.php )
-	// we can keep call this without removing it, that is part of the DOM spec
-	window.addEventListener("DOMContentLoaded", su_on_load_page, true);
-}
-
-function su_add_progress_listener()
-{
-	// We need this listener if we have tabs open
-	getBrowser().addProgressListener(su_downloadProgressListener);
-}
-
-//************** END INITIALIZATION ****************/
-
-//************** MODEL FUNCTIONS *******************/
-
-function su_set_legacy_user_interests(str)
-{
-	var blah3 = str.split("|");
-	var blah4 = blah3[1];
-	var blah5 = blah4.split(" ");
-	su_user_interests = new Array();
-	for (var i = 0; i < blah5.length; i++)
-	{
-		if (blah5[i] != "")
-			su_user_interests[blah5[i]] = 1;
-	}
-}
-
-function su_set_user_interests(str)
-{
-	var parts = str.split(" ");
-	var i;
-	su_user_interests = new Array();
-	for (i = 0; i < parts.length; i++)
-	{
-		if (parts[i] == "")
-			continue;
-		
-		if (! parseInt(parts[i]))
-			continue;
-		
-		su_user_interests[parts[i]] = 1;
-	}
-}
-
-function su_store_user_interests()
-{
-	var towrite = "";
-	var first = 0;
-	for (var ii in su_user_interests)
-	{
-		if (su_is_property_garbage(su_user_interests, ii))
-			continue;
-		
-		if (first == 0)
-			first = 1;
-		else
-			towrite += " ";
-		towrite += ii + " ";
-	}
-	su_ds.setValue("$interests", towrite);
-	su_ds.flushPrefs();
-}
-
-function su_legacy_interests_after_page(doc)
-{
-	var el = doc.getElementById("interests");
-	if (! el)
-		return;
-	
-	su_set_legacy_user_interests(el.innerHTML);
-	su_store_user_interests();
-	
-	su_refresh_category_selector_batched();
-	
-	clear_stumbles();
-}
-
-function su_interests_page(doc)
-{
-	var el = doc.getElementById("topic_list");
-
-	if (! el)
-		return;
-	
-	su_process_topic_list(el.innerHTML);
-}
-
-function su_prefs_page(doc)
-{
-	var el;
-	
-	el = doc.getElementById("changePassword");
-	
-	if (! el)
-		return;
-	
-	try {
-		el.wrappedJSObject.addEventListener(
-				"click",
-				su_handle_change_password,
-				false);
-	} catch (e) {}
-}
-
-function su_tag_page(doc)
-{
-	var el;
-	
-	el = doc.getElementById("thumbup");
-	if (el)
-	{
-		try {
-			el.wrappedJSObject.addEventListener(
-					"click",
-					su_handle_interests_change_click,
-					false);
-		} catch (e) {}
-	}
-	
-	el = doc.getElementById("thumbdown");
-	if (el)
-	{
-		try {
-			el.wrappedJSObject.addEventListener(
-					"click",
-					su_handle_interests_change_click,
-					false);
-		} catch (e) {}
-	}
-}
-
-function su_handle_interests_change_click()
-{
-	setTimeout(su_get_interests, 1000);
-	setTimeout(su_get_interests, 8000);
-}
-
-function su_portal_http_page(doc)
-{
-	var el = doc.getElementById("topic_list");
-	
-	if (! el)
-		return;
-	
-	su_process_topic_list(el.innerHTML);
-}
-
-function su_process_topic_list(str)
-{
-	if (str == su_ds.getValue("#prev_topic_list"))
-		return;
-		
-	su_ds.setValue("#prev_topic_list", str);
-
-	su_set_user_interests(str);
-	su_store_user_interests();
-	
-	su_refresh_category_selector_batched();
-	clear_stumbles();
-}
-
-//
-// su_update_topic_list
-//
-// This is the same as su_process_topic_list, except it isn't restricted
-// to only running once per session with #prev_topic_list.  To be honest,
-// I'm not sure why that is required, so I've created a new command so
-// topic updates can be driven by the web page via. the suLitebarApi.
-//
-function su_update_topic_list(str)
-{
-	su_set_user_interests(str);
-	su_store_user_interests();
-	
-	su_refresh_category_selector_batched();
-	clear_stumbles();
-}
-
-function su_process_friends_command(command_str)
-{
-	if (command_str == su_ds.getValue("#prev_friends"))
-		return;
-	
-	if (su_ds.getValue("#installing_all_avatars"))
-		return;
-
-	su_ds.setValue("#prev_friends", command_str);
-	
-	var friends = command_str.split(" ");
-	friends.shift();
-	
-	if(friends.length)
-	{
-		// If they have friends, then show the friends menu.
-		if(!su_ds.getValue("$show_friends_user_changed"))
-		{
-			su_ds.setValue("$show_friends", true);
-			su_set_visible("su_friends", true);
-		}
-	}
-	
-	var i;
-	var contact;
-	var mutuals = new Object();
-	var changed = false;
-	var has_avatars = su_ds.getValue("$has_avatars");
-	if (! has_avatars)
-		su_ds.setValue("#installing_all_avatars", true);
-	var contacts = su_ds.selectAllRows("contact");
-	var new_contacts = new Array();
-	var contacts_by_id = new Object();
-	for (i = 0; i < contacts.length; i++)
-	{
-		if (contacts[i].contactid)
-			contacts_by_id[contacts[i].contactid] = contacts[i];
-	}
-	
-	for (i = 0; i < friends.length; i++)
-	{
-		var nickname = friends[i].split(".")[0];
-		var contactid = friends[i].split(".")[1];
-		mutuals[contactid] = true;
-		
-		contact = null;
-		
-		if (contacts_by_id[contactid])
-			contact = contacts_by_id[contactid];
-			
-		if (contact)
-		{
-			contacts_by_id[contact.contactid] = null;
-			if (contact.contactid != contactid)
-			{
-				changed = true;
-				contact.contactid = contactid;
-			}
-			if (contact.nickname != nickname)
-			{
-				changed = true;
-				contact.nickname = nickname;
-			}
-			if (! contact.mutual)
-			{
-				changed = true;
-				contact.mutual = 1;
-			}
-			if (changed)
-				su_ds.updateRow(contact);
-			if (! has_avatars)
-				su_ds.refreshAvatar(contactid);
-			contacts_by_id[contactid] = contact;
-		}
-		else
-		{
-			changed = true;
-			contact = new Object();
-			contact.contactid = contactid;
-			contact.nickname = nickname;
-			contact.mutual = 1;
-			su_ds.refreshAvatar(contactid);
-			su_ds.insertRow("contact", contact);
-			contacts_by_id[contactid] = contact;
-		}
-	}
-
-	for (i = 0; i < contacts.length; i++)
-	{
-		if ((typeof (contacts[i])) == "undefined")
-		{
-			su_log_error("LEGACY FRIENDS");
-			contacts.splice(i, 1);
-			i--;
-			continue;
-		}
-		
-		if ((typeof (contacts[i].contactid)) != "undefined")
-		{
-			if (! mutuals[contacts[i].contactid])
-			{
-				if (contacts[i].mutual)
-				{
-					changed = true;
-					contacts[i].mutual = 0;
-					su_ds.updateRow(contacts[i]);
-				}
-			}
-		}
-	}
-	
-	if (changed)
-		su_refresh_referral_menu(1);
-}
-
-/*
-function su_process_fbfriends_command(command_str)
-{
-	var friends = command_str.split(" ");
-	friends.shift();
-	
-	var i;
-	var contact;
-	var contacts = su_ds.selectAllRows("contact");
-	var contacts_by_id = new Object();
-	var fbfriends = new Object();
-	for (i = 0; i < contacts.length; i++)
-	{
-		if (contacts[i].contactid)
-			contacts_by_id[contacts[i].contactid] = contacts[i];
-	}
-	
-	for (i = 0; i < friends.length; i++)
-	{
-		var contactid = friends[i].split(".")[0];
-		var nickname = friends[i].split(".")[1];
-		var facebookid = friends[i].split(".")[2];
-		
-		fbfriends[contactid] = true;
-
-		contact = null;
-		
-		if (contacts_by_id[contactid])
-			contact = contacts_by_id[contactid];
-		
-		if (contact)
-		{
-			contact.nickname = nickname;
-			contact.fbid = facebookid;
-			su_ds.updateRow(contact);
-		}
-		else
-		{
-			contact = new Object();
-			contact.contactid = contactid;
-			contact.nickname = nickname;
-			contact.fbid = facebookid;
-			su_ds.insertRow("contact", contact);
-			contacts_by_id[contactid] = contact;
-		}
-	}
-
-	for (i = 0; i < contacts.length; i++)
-	{
-		if ((typeof (contacts[i].contactid)) != "undefined")
-		{
-			if (contacts[i].fbid && (! fbfriends[contacts[i].contactid]))
-				contacts[i].fbid = 0;
-			
-			su_ds.updateRow(contacts[i]);
-		}
-	}
-}
-*/
-
-//************** END MODEL FUNCTIONS ***************/
-
-
-
-//************** UTILITY FUNCTIONS *****************/
-
-// See global.js for additional utility functions.
-
-function su_is_matching_domain(uri, domain, opt_parts_length_offset)
-{
-	var splituri = uri.split("/");
-	
-	if (splituri.length < 3)
-		return false;
-
-	var uri_domains = splituri[2].split(".");
-	var ref_domains = domain.split(".");
-	
-	if ((typeof(opt_parts_length_offset) != "undefined") &&
-				(uri_domains.length - ref_domains.length) != opt_parts_length_offset)
-		return false;
-		
-	else if (uri_domains.length < ref_domains.length)
-		return false;
-
-	var i = ref_domains.length-1;
-	var j = uri_domains.length-1;
-	while (i >= 0)
-	{
-		if (uri_domains[j] != ref_domains[i])
-			return false;
-		i--;
-		j--;
-	}
-	return true;
-}
-
-function su_get_domain(opt_url)
-{
-	var url;
-	if (opt_url)
-		url = opt_url;
-	else
-		url = su_get_browser_url();
-	
-	var url_parts = url.split("/");
-	
-	if (url_parts.length < 3)
-		return "";
-	
-	return url_parts[2];
-}
-
-function su_normalize_tag(str)
-{
-	str = str.replace(/\s+/g, " ");
-	str = str.replace(/\s*,+\s*/g, ", ");
-	str = str.replace(/^,/, "");
-	str = str.replace(/,\s$/, "");
-	return str;
-}
-
-function su_is_sound(url)
-{
-	// checks to see if url produces sound
-	var last3 = url.substr(url.length-3).toLowerCase();
-	var last4 = url.substr(url.length-4).toLowerCase();
-	var last5 = url.substr(url.length-5).toLowerCase();
-	if (    last3 == ".qt" || last3 == ".ra" || last3 == ".rm" 
-		|| last3 == ".rv" || last3 == ".au" || last3 == ".ul"
-  		|| last4 == ".avi" || last4 == ".asf" || last4 == ".mpg"
-   		|| last4 == ".wmf" || last4 == ".wmv" || last4 == ".wma"
-		|| last4 == ".wav" || last4 == ".mov" || last4 == ".mp3"
-		|| last4 == ".ram" || last4 == ".swf" || last4 == ".mp4"
-		|| last4 == ".mpe" || last4 == ".mpv" || last4 == ".mp2"
-		|| last4 == ".aac" || last4 == ".aif" || last4 == ".mid" 
-		|| last4 == ".ogg" || last4 == ".ogm" || last4 == ".ac3" 
-		|| last4 == ".fla" || last4 == ".awm" || last4 == ".ftk"
-		|| last4 == ".mod" || last4 == ".sid" || last4 == ".nap"
-		|| last4 == ".mmm"
-		|| last5 == ".aiff"
-		|| last5 == ".midi"
-		|| last5 == ".mpeg")
-	{
-		return 1;
-	}
-	else
-	{
-		return 0;
-	}
-}
-
-function su_is_url_rateable(url, tld)
-{
-	// Not enabled for about:, mailto:, etc.
-	if (url.indexOf("http:") != 0 && url.indexOf("https:") != 0 && url.indexOf("ftp:") != 0)
-		return false;
-
-	// Not enabled for url pages
-	
-	if (url.indexOf(su_base_url + "url/") == 0 || url.indexOf(su_base_url + "url.php") == 0)
-		return false;
-	
-	if (url == "http://video." + su_servername + "/")
-		return false;
-	
-	if (tld)
-		return true;
-	
-	return false;
-}
-
-function su_is_adult_category(cat)
-{
-	if (cat == null)
-		return false;
-	
-	cat += "";
-	
-	switch (cat)
-	{
-		case "6":    //  Pornography
-		case "159":  //  Fetish Sexuality
-		case "193":  //  Hentai Anime
-		case "510":  //  Gay Sex
-		case "513":  //  Lesbian Sex
-		case "521":  //  BDSM
-		case "522":  //  Bisexual Sex
-		case "531":  //  Transexual Sex
-			return true;
-			break;
-	}
-	return false;
-}
-
-function su_get_media_specs()
-{
-	var specs = new Array();
-	var collection;
-	var i;
-	var doc = getBrowser().contentDocument;
-	
-	collection = doc.getElementsByTagName("EMBED");
-	for (i = 0; i < collection.length; i++)
-		specs.push(su_get_media_spec(collection[i]));
-	
-	collection = doc.getElementsByTagName("OBJECT");
-	for (i = 0; i < collection.length; i++)
-		specs.push(su_get_media_spec(collection[i]));
-	
-	collection = doc.getElementsByTagName("APPLET");
-	for (i = 0; i < collection.length; i++)
-		specs.push(su_get_media_spec(collection[i]));
-	
-	collection = doc.getElementsByTagName("img");
-	for (i = 0; i < collection.length; i++)
-	{
-		var spec = su_get_media_spec(collection[i]);
-		if (spec)
-			specs.push(spec);
-	}
-
-	return specs;
-}
-
-function su_get_media_spec(el)
-{
-	var spec = su_get_property_map(el);
-	
-	spec.tagName = el.tagName.toLowerCase();
-
-	if (el.boxObject)
-	{
-		spec.width = el.boxObject.width;
-		spec.height = el.boxObject.height;
-		spec.top = el.boxObject.top;
-	}
-	else
-	{
-		spec.width = 0;
-		spec.height = 0;
-		spec.top = 0;
-	}
-
-	if (spec.tagName == "img")
-	{
-		var area = spec.width * spec.height;
-		if (area > 70000)
-			return spec;
-		else
-			return null;
-	}
-
-	if (spec.type)
-		return spec;
-	
-	if ((spec.tagName == "applet") || 
-				(spec.code && (spec.code.indexOf(".class") != -1)))
-		spec.type = "application/x-java-applet";
-
-	else if ((spec.src && (spec.src.indexOf(".swf") != -1)) || 
-				(spec.movie && (spec.movie.indexOf(".swf") != -1)))
-		spec.type = "application/x-shockwave-flash";
-
-	return spec;
-}
-
-function su_get_property_map(el)
-{
-	var map = new Object();
-	var i;
-	for (i = 0; i < el.attributes.length; i++)
-	{
-		// Add properties representing attributes. -- JW
-		map[el.attributes.item(i).nodeName.toLowerCase()] = el.attributes.item(i).nodeValue;
-	}
-	
-	var children = el.childNodes;
-	for (i = 0; i < children.length; i++)
-	{
-		// Add properties representing param entities. -- JW
-		if (children[i].tagName != "PARAM")
-			continue;
-		
-		if (children[i].hasAttribute("name") && children[i].hasAttribute("value"))
-			map[children[i].getAttribute("name").toLowerCase()] = children[i].getAttribute("value");
-	}
-	return map;
-}
-
-function su_get_target_anchor(el, search_depth)
-{
-	var found_el = null;
-	var i;
-	for (i = 0; i < search_depth; i++)
-	{
-		if (el.tagName && (el.tagName == "A"))
-		{
-			found_el = el;
-			break;
-		}
-		if (el.parentNode)
-			el = el.parentNode;
-		else
-			break;
-	}
-	return found_el;
-}
-
-function su_get_ancestor_by_prop_value(el, prop_name, prop_value, search_depth)
-{
-	var found_el = null;
-	var i;
-	for (i = 0; i < search_depth; i++)
-	{
-		if (el.parentNode)
-			el = el.parentNode;
-		else
-			break;
-		
-		if (el[prop_name] == prop_value)
-		{
-			found_el = el;
-			break;
-		}
-	}
-	return found_el;
-}
-
-function su_is_mutual_friend(nickname)
-{
-	if (! nickname)
-		return false;
-	
-	nickname += "";
-	
-	if (nickname == "")
-		return false;
-	
-	var query = nickname.toLowerCase();
-	
-	var contacts = su_ds.selectAllRows("contact");
-	var found = false;
-	var i;
-	for (i = 0; i < contacts.length; i++)
-	{
-		if ((contacts[i].nickname) && 
-					(contacts[i].mutual) &&
-					(contacts[i].nickname.toLowerCase() == query))
-		{
-			found = true;
-			break;
-		}
-	}
-	
-	return found;
-}
-
-function su_prefix_article(str)
-{
-	if (! str)
-		return "";
-	
-	if (str == "")
-		return "";
-	
-	var chr = str.charAt(0).toLowerCase();
-	
-	var article;
-	switch (chr)
-	{
-		case "a":
-		case "e":
-		case "i":
-		case "o":
-		case "u":
-			article = "an";
-			break;
-		default:
-			article = "a";
-			break;
-	}
-	
-	return article + " " + str;
-}
-
-function su_new_tab(event)
-{
-	if (! event)
-		return false;
-	
-	var platform_ctrl_key = (su_host.mac) ? event.metaKey : event.ctrlKey;
-	var new_tab = false;
-	if (event.button == 1 || (event.button == 0 && platform_ctrl_key))
-		new_tab = true;
-	return new_tab;
-}
-
-function su_is_about_blank()
-{
-	var doc = getBrowser().contentDocument;
-	if(doc && (doc.location.toString() == "about:blank"))
-		return true;
-	else
-		return false;
-}	
-		
-function su_cancel_event(event)
-{
-	event.stopPropagation();
-	if (event.cancelable)
-		event.preventDefault();			
-	event.cancelBubble = true;
-	return false;
-}
-
-// returns the number of browser windows
-function su_get_browser_window_count()
-{
-	var enumerator = su_get_service(
-				"@mozilla.org/appshell/window-mediator;1",
-				"nsIWindowMediator")
-				.getEnumerator("navigator:browser");
-	
-	var count = 0;
-	while (enumerator.hasMoreElements())
-	{
-		count++;
-		enumerator.getNext();
-	}
-	return count;
-}
-
-function su_get_rdf_resource(resource_id)
-{
-	return su_get_service(
-				"@mozilla.org/rdf/rdf-service;1",
-				"nsIRDFService")
-				.GetResource(resource_id)
-				.QueryInterface(Components.interfaces.nsIRDFResource)
-}
-
-function su_get_rdf_arc_literal(datasource, element, arc_id)
-{
-	try {
-		var arc = su_get_rdf_resource(arc_id);
-					
-		element.QueryInterface(Components.interfaces.nsIRDFResource);
-		
-		var target = datasource.GetTarget(element, arc ,true);
-		if (target)
-			return target.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
-	} catch (e) {}
-	return null;
-}
-
-function su_get_rdf_arc_int(datasource, element, arc_id)
-{
-	try {
-		var arc = su_get_rdf_resource(arc_id);
-					
-		element.QueryInterface(Components.interfaces.nsIRDFResource);
-		
-		var target = datasource.GetTarget(element, arc ,true);
-		if (target)
-			return target.QueryInterface(Components.interfaces.nsIRDFInt).Value;
-	} catch (e) {}
-	return null;
-}
-
-// returns a mime input stream, used primarily for wrapping POST data
-function su_get_mime_input_stream(str, content_type)
-{
-  var data_stream = su_create_instance(
-				"@mozilla.org/io/string-input-stream;1",
-				"nsIStringInputStream");
-  data_stream.setData(str, str.length);
-
-  var mime_stream = su_create_instance(
-				"@mozilla.org/network/mime-input-stream;1",
-				"nsIMIMEInputStream");
-  mime_stream.addHeader("Content-Type", content_type);
-  mime_stream.addContentLength = true;
-  mime_stream.setData(data_stream);
-  return mime_stream.QueryInterface(Components.interfaces.nsIInputStream);
-}
-
-function su_get_browser_url(opt_doc, opt_raw)
-{
-	var doc = (opt_doc) ? opt_doc : getBrowser().contentDocument;
-	var url = doc.location.toString();
-	if (url.indexOf("chrome://ietab/content/reloaded.html?url=") == 0)
-		url = url.substr(41);
-	
-	if (opt_raw)
-		return url;
-	
-	if (su_is_matching_domain(url, "video." + su_servername))
-	{
-		var detail = su_get_stumblevideo_detail(doc);
-		if (detail)
-			url = detail.url;
-	}
-	
-	return url;
-}
-
-function su_get_browser_referrer_url(opt_doc, opt_raw)
-{
-	var doc = (opt_doc) ? opt_doc : getBrowser().contentDocument;
-	var url = doc.referrer.toString();
-	if (url.indexOf("chrome://ietab/content/reloaded.html?url=") == 0)
-		url = url.substr(41);
-	
-	if (opt_raw)
-		return url;
-	
-//	if (su_is_matching_domain(url, "video." + su_servername))
-//	{
-//		var detail = su_get_stumblevideo_detail(doc);
-//		if (detail)
-//			url = detail.url;
-//	}
-	
-	return url;
-}
-
-function su_dispatch_click(doc, id)
-{
-	var el = doc.getElementById(id);
-	if (! el)
-		return;
-
-	var evt = doc.createEvent("MouseEvent");
-	evt.initMouseEvent(
-				"click",
-				true,
-				true,
-				doc.defaultView,
-				1,
-				0, // screenX
-				0, // screenY
-				0, // clientX
-				0, // clientY
-				false,
-				false,
-				false,
-				false,
-				0,
-				null);
-	el.dispatchEvent(evt);
-}
-
-/*
-function su_dispatch_mouseover(doc, id)
-{
-	var el = doc.getElementById(id);
-	if (! el)
-		return;
-
-	var evt = doc.createEvent("MouseEvent");
-	evt.initMouseEvent(
-				"mouseover",
-				true,
-				true,
-				doc.defaultView,
-				1,
-				0, // screenX
-				0, // screenY
-				0, // clientX
-				0, // clientY
-				false,
-				false,
-				false,
-				false,
-				0,
-				null);
-	el.dispatchEvent(evt);
-}
-*/
-
-const su_DEBUG_ENABLED = true;
-
-/*
-function su_insert_before(parent, new_el, after_el)
-{
-	if (parent && after_el && after_el.parentNode && (after_el.parentNode == parent))
-		after_el.insertBefore(new_el, after_el.nextSibling);
-	else if (parent)
-		parent.appendChild(new_el);
-}
-*/
-
-function su_get_element(id)
-{
-	return document.getElementById(id);
-}
-
-// When doing a 'for ([prop] in [obj])', use this to verify that the
-// property isn't pollution from another extension.
-function su_is_property_garbage(obj, prop)
-{
-	return ((typeof (obj[prop])) == "function");
-}
-
-function su_invert_dictionary(dict)
-{
-	var out = new Object();
-
-	var key;
-	for (key in dict)
-	{
-		if (su_is_property_garbage(dict, key))
-			continue;
-		
-		out[dict[key]] = key; 
-	}
-
-	return out;
-}
-
-function su_log_dd_uc(unseen)
-{
-	if (	su_ds.lookup("userid:uc_logger_flag", stumbleid) ||
-				su_ds.getValue("@dd_uc"))
-	{
-		var str = " " + su_ds.getValue("@dd_uc_server") + " " + unseen + "\n";
-		su_ds.writeFile(
-					su_ds.getLegacyNSIFile("stumbledd"),
-					(su_ds.getTimestampStr(0) + str),
-					true);
-		su_ds.writeFile(
-					su_ds.getLegacyNSIFile("stumbleddw"),
-					(su_ds.getTimestampStr(1) + str),
-					true);
-	}
-}
-
-function su_get_time_s()
-{
-	return Math.floor((new Date()).getTime() / 1000);
-}
-
-function su_trim(str)
-{
-	return str.replace(/^\s*|\s*$/g,"");
-}
-
-function su_escape_regexp_chars(str)
-{
-	return str.replace(/([\\\^\*\+\?\.\(\)\|\{\}\[\]])/g, "\\$1");
-}
-
-function su_clone(obj)
-{
-	return su_ds.deserialize(su_ds.serialize(obj, false));
-}
-
-// append request param
-function su_arp(param_str, name, value, opt_get_flag)
-{
-	var delimiter;
-	if (opt_get_flag && (param_str.indexOf("&") == -1) &&
-				(param_str.indexOf("?") == -1))
-		delimiter = "?";
-	else
-		delimiter = "&";
-	
-	return param_str + ((param_str == "") ? "" : delimiter) + name + "=" + 
-				encodeURIComponent(value);
-}
-
-function su_build_request_param_string(spec)
-{
-	var str = "";
-	var name;
-	for (name in spec)
-	{
-		if (su_is_property_garbage(spec, name))
-			continue;
-		
-		str += ((str == "") ? "" : "&") + name + "=" + 
-				encodeURIComponent(spec[name]);
-	}
-	return str;
-}
-
-function su_create_instance(nsclass, nsinterface)
-{
-	try {
-		return Components.classes[nsclass]
-					.createInstance(Components.interfaces[nsinterface]);
-	}
-	catch (e) {
-		return null;
-	}
-}
-
-function su_get_service(nsclass, nsinterface)
-{
-	try {
-		return Components.classes[nsclass]
-					.getService(Components.interfaces[nsinterface]);
-	}
-	catch (e) {
-		return null;
-	}
-}
-
-// returns an nsIURI object for the specified uri
-function su_get_nsiuri(uri_str)
-{
-	var uri = su_create_instance(
-				"@mozilla.org/network/standard-url;1",
-				"nsIURI");
-	uri.spec = uri_str;
-	return uri;
-}
-
-// writes all arguments to a console message
-function su_dd()
-{
-	if (! su_DEBUG_ENABLED)
-		return;
-
-	su_service.dd.apply(su_service, arguments);
-}
-
-function su_ddf()
-{
-	su_service.ddf.apply(su_service, arguments);
-}
-
-window.su_log = su_dd;
-
-window.su_logf = su_ddf;
-
-// writes all properties of an object to a console message
-function su_dump_object(o)
-{
-	var str = "";
-	var p;
-	
-	for (p in o)
-	{
-		try {
-			str += "[" + p + "]\n" + o[p] + "\n\n";
-		}
-		catch (e) {
-			str += "[" + p + "] ERROR\n" + e + "\n\n";
-		}
-	}
-	su_log(str);
-}
-
-function su_log_error()
-{
-	if (! su_DEBUG_ENABLED)
-		return;
-
-	su_service.logError.apply(su_service, arguments);
-}
-
-// send a notification to the event_observer for each window
-function su_invoke_global_event(event_id, detail, from)
-{
-	if (event_id == "update-referral-menu")
-	{
-		su_ds.flushPrefs();
-	}
-	else if ((event_id == "login") && detail && (! detail.skip_cookies)
-			&& detail.ignore_cookies)
-	{
-		su_process_cookies(true);
-		detail.skip_cookies = true;
-	}
-	
-	su_get_service(
-				"@mozilla.org/observer-service;1",
-				"nsIObserverService")
-				.notifyObservers(null, "su_" + event_id, su_ds.serialize(detail));
-}
-
-//************** END UTILITY FUNCTIONS ***************/
-
-
-//******** FILE FUNCTIONS **********//
-
-//
-// Note:  This code includes the ability to fallback to user prefs for file storage.
-//        But since prefs are written frequently, useFailsafe should NOT be used except
-//        when reading / writing very small files.
-//
-function _su_read_file_user(fname, useFailsafe)
-{
-	// We fall back to using prefs if they have asked for it for this specific
-	// operation, _and_ a previous file write operation failed _and_ the failsafe
-	// option is enabled.
-	//
-	if(useFailsafe &&
-	   su_ds.getValue("@userfile_write_failed") &&
-	   su_ds.getValue("@enable_userfile_failsafe"))
-	{
-		// A previous write failed, so we are using prefs.
-		var result = su_ds.getPrefValue("$file_" + fname + "_failsafe", "");
-		return result;
-	}
-	else
-	{
-		return su_ds.readFile(su_ds.getLegacyNSIFile(fname));
-	}
-}
-
-function _su_write_file_user(fname, data, useFailsafe)
-{
-	if(useFailsafe &&
-	   su_ds.getValue("@userfile_write_failed") &&
-	   su_ds.getValue("@enable_userfile_failsafe"))
-	{
-		// If we have failed writing to the filesystem, then we failover
-		// to using prefs for our user data storage.
-		su_ds.setValue("$file_" + fname + "_failsafe", data);
-		su_ds.flushPrefs();
-	}
-	else
-	{
-		try
-		{
-			// Try the normal file operation.
-			var file = su_ds.getLegacyNSIFile(fname);
-			su_ds.writeFile(file, data);
-			var result = su_ds.readFile(file);
-			if(result != data)
-			{
-				// This is a ZoneAlarm ForceField hack.  ForceField causes file writes to fail
-				// silently, so we double-check whether the write succeeded and throw our own error
-				// on failure.
-				throw "Data is different";
-			}
-		}
-		catch(ex)
-		{
-			su_log_error("USERFILE FAILURE: " + ex);
-			su_ds.setValue("$file_" + fname + "_failsafe", data);
-			su_ds.setValue("@userfile_write_failed", true);
-			su_ds.flushPrefs();
-		}
-	}
-}
-
-function su_read_file_user(fname)
-{
-	return _su_read_file_user(fname, fname == "stumbleurls");
-}
-
-function su_write_file_user(fname, data)
-{
-	_su_write_file_user(fname, data, fname == "stumbleurls");
-}
-		
-//***************** END FILE FUNCTIONS ******************//
-
-
-//***************** GUI HANDLERS ************************//
-
-// deals with interests if you select it from the menu item add more interests...
-function su_interests_pre()
-{
-	su_interests();
-	su_set_mode_all();
-}
-
-
-//!!! We probably ought to combine su_handle_mode_click and
-//    su_select_topic, but to mitigate risk, this change is deferred
-//    until after 3.0. -- JW
-function su_handle_mode_click(event, mode)
-{
-	var new_tab = su_new_tab(event);
-	
-	var tag;
-	switch (mode)
-	{
-		case "All":
-			su_select_topic(0, mode, new_tab);
-			break;
-		case "Videos":
-			su_select_topic("video", mode, new_tab);
-			break;
-		case "Photos":
-			su_select_topic(302, mode, new_tab);
-			break;
-		case "Friends":
-			su_select_topic("friends", mode, new_tab);
-			break;
-		case "Profiles":
-			su_select_topic(44, mode, new_tab);
-			break;
-		case "Search":
-			new_tab = new_tab || su_ds.getValue("$search_new_window");
-			setTimeout(su_show_search_dialog, 0, new_tab);
-			break;
-		case "News":
-			su_select_topic("news", mode, new_tab);
-			break;
-		case "Wiki":
-			su_select_topic("wiki", mode, new_tab);
-			break;
-		default:
-			su_select_topic(mode, mode, new_tab);
-			break;
-	}
-}
-
-function su_handle_domain_mode_click(event, domain)
-{
-	su_select_topic("TAG_" + domain, domain, su_new_tab(event));
-}
-
-function su_select_topic(topic, label, new_tab, opt_force_stumble)
-{
-	topic += "";
-	var lang = false;
-	switch (topic)
-	{
-		case "0":
-			su_set_mode(topic, label, "", "Stumble!", "Show next page");
-			break;
-		case "44":
-			su_set_mode(topic, label, 
-						"chrome://stumbleupon/content/skin/stumblers.png",
-						"Stumble! ", "Stumble a profile");
-			break;
-		case "302":
-			su_set_mode(topic, label, 
-						"chrome://stumbleupon/content/skin/icon_tb_photo_hover.png",
-						"Stumble! ", "Stumble a photo");
-			break;
-		case "friends":
-			su_set_mode(topic, label, 
-						"chrome://stumbleupon/content/skin/icon_tb_people.png",
-						"Stumble! ", "Stumble a favorite");
-			break;
-		case "video":
-			su_set_mode(topic, label, 
-						"chrome://stumbleupon/content/skin/video.png",
-						"Stumble! ", "Stumble a video");
-			break;
-		case "news":
-			su_set_mode(topic, label,
-						"chrome://stumbleupon/content/skin/icon_tb_news.png",
-						"Stumble! ", "Stumble a news item");
-			break;
-		case "wiki":
-			su_set_mode(topic, label,
-						"chrome://stumbleupon/content/skin/wiki.png",
-						"Stumble! ", "Stumble an article");
-			break;
-		default:
-			if (su_isInt(topic))
-			{
-				su_set_mode(topic, label,
-							"chrome://stumbleupon/content/skin/topic.png", 
-							"Stumble! ", "Stumble " + su_prefix_article(label) + " page");
-			}
-			else if (topic.indexOf("LANG_") == 0)
-			{
-				lang = true;
-				su_set_mode(topic, label,
-							"chrome://stumbleupon/content/skin/topic.png", 
-							"Stumble! ", "Stumble " + su_prefix_article(label) + " page");
-			}
-			else if (topic.indexOf("TAG_") == 0)
-			{
-				var tmp_topic = topic.substr(4).toLowerCase();
-				var favicon_url = null;
-				if (su_ds.isThruDomain(tmp_topic))
-				{
-					// If they've stumbled in a thru domain, we don't need to
-					// educate via an info bubble. -- JW
-//					su_ds.setValue("$shown_thru_domain_info_count", su_ds.getValue("~shown_thru_domain_info_count_max"));
-					
-					favicon_url = su_get_favicon_url(tmp_topic);
-				}
-				
-				if (favicon_url)
-				{
-					su_set_mode(topic, label, favicon_url,
-								"Stumble! ", "Stumble a page from " + label);
-				}
-				else
-				{
-					su_set_mode(topic, label,
-								"chrome://stumbleupon/content/skin/search.png",
-								"Stumble! ", "Stumble a '" + label + "' page");
-				}
-			}
-			else if (su_is_mutual_friend(topic))
-			{
-				su_set_mode(topic, label,
-							"chrome://stumbleupon/content/skin/mutual_favorites.png",
-							"Stumble! ", "Stumble a favorite from " + label);
-			}
-			else
-			{
-				su_set_mode(topic, label,
-							"chrome://stumbleupon/content/skin/stumbler_favorites.png",
-							"Stumble! ", "Stumble a favorite from " + label);
-			}
-			break;
-	}
-	
-//	if (! search)
-//	{
-//		su_get_element("su_searchbox").value = "";
-//		su_get_element("su_searchbox").removeAttribute("mode");
-//		su_old_search = "";
-//		su_last_typed_tag = 0;
-//		su_visited_searchbox = 1;
-//	}
-
-	if (su_ds.getValue("$stumble_upon_change") || opt_force_stumble)
-		stumble(new_tab);
-}
-
-function su_backup_places(error_label)
-{
-	// Make a snapshot of bookmarks in the standard backup location, but
-	// don't clobber an existing one.
-	try {
-	
-	var datestr = (new Date).toLocaleFormat("%Y-%m-%d");
-	var name = PlacesUIUtils.getFormattedString("bookmarksBackupFilenameJSON", [datestr]); 
-	var nsifile = su_ds.getResourceNSIFile("temp", name);
-	
-	su_ds.deleteFile(nsifile);
-	
-	nsifile.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0700);
-	
-	PlacesUtils.backupBookmarksToFile(
-			nsifile,
-			[PlacesUIUtils.leftPaneFolderId]);
-	
-	var target_dir = su_get_service( 
-			"@mozilla.org/file/directory_service;1",
-			"nsIProperties")
-			.get("ProfD", Components.interfaces.nsIFile);
-	target_dir.append("bookmarkbackups");
-	if (! target_dir.exists())
-		target_dir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0700);
-	
-	var target_file;
-	target_file = su_get_service(
-			"@mozilla.org/file/directory_service;1",
-			"nsIProperties")
-			.get("ProfD", Components.interfaces.nsIFile);
-	target_file.append("bookmarkbackups");
-	target_file.append(name);
-	if (target_file.exists())
-	{
-		var target_file2;
-		target_file2 = su_get_service(
-				"@mozilla.org/file/directory_service;1",
-				"nsIProperties")
-				.get("ProfD", Components.interfaces.nsIFile);
-		target_file2.append("bookmarkbackups");
-		target_file2.append(name + ".su.saved.json");
-		if (! target_file2.exists())
-			target_file.copyTo(target_dir, name + ".su.saved.json");
-		su_ds.deleteFile(target_file);
-	}
-	
-	if (! target_file.exists())
-		nsifile.copyTo(target_dir, name);
-	
-	} catch (e) { su_log_error(error_label, e); }
-}
-
-function su_handle_download_favs_command()
-{
-	var detail = new Object();
-	detail.browser_label = su_host.label;
-	
-	window.openDialog(
-			"chrome://stumbleupon/content/downloadFavsDialog.xul",
-			"su_downloadFavsDialog",
-			"chrome,dialog,centerscreen,dependent",
-			detail);
-}
-
-function su_download_favs(start_download)
-{
-	if (start_download)
-		su_ds.setValue("$sync_bm_meta", true);
-	
-	var state = su_ds.getValue("$download_favs_state");
-	var context;
-	var val;
-	if (((state == "a") || (state == "c")) && (! start_download))
-		return;
-	
-	context = su_ds.getValue("$download_favs_detail");
-	
-	if ((state == "a") || (state == "c") || (! context.mode))
-	{
-		context = new Object();
-		context.begin_s = su_get_time_s();
-		context.end_s = 0;
-		context.prekey = 0;
-		context.prekey2 = 0;
-		context.mode = 1;
-		context.first = 1;
-		context.download_target_count = 200;
-		context.download_count = 0;
-		context.apply_target_count = 200;
-		context.apply_count = 0;
-		context.count = 0;
-		context.done = false;
-		context.stopped = false;
-		su_ds.setValue("$download_favs_detail", context);
-		su_ds.setValue("#download_favs_detail", context);
-		su_ds.setValue("$download_favs_state", "b");
-		su_ds.flushPrefs();
-	}
-	else
-	{
-		su_ds.setValue("#download_favs_detail", context);
-	}
-	
-	if (su_preference_dialog)
-	{
-		val = 5;
-		
-		el = su_preference_dialog.ownerDocument.getElementById("download_progress");
-		if (val != el.value)
-			el.value = val;
-	}
-
-	su_set_download_favs_enabled(false);
-	
-	if (su_ds.getValue("#migrating_places"))
-		return;
-	
-	setTimeout(function (win, context) { win.su_download_favs_getmetafavs(context) }, 0, window, context);
-}
-
-function su_download_favs_getmetafavs(context)
-{
-	var params = "";
-	params = su_arp(params, "prekey", context.prekey);
-	params = su_arp(params, "prekey2", context.prekey2);
-	params = su_arp(params, "first", context.first);
-	params = su_arp(params, "mode", context.mode);
-	params = su_arp(params, "a", (su_ds.getValue("$sync_bm_adult") ? 1 : 0))
-	context.quiet = true;
-	su_post_url_server_async(
-				"getmetafavs.php",
-				params,
-				15000,
-				su_download_favs_getmetafavs_done,
-				context);
-}
-
-function su_download_favs_getmetafavs_done(res)
-{
-	try {
-		if (res.status != 200)
-			return;
-	} catch (e) { return; } 
-	
-	var context = res.detail;
-	
-	context.first = 0;
-	
-	su_ds.setValue("$download_favs_detail", context);
-	su_ds.flushPrefs();
-	
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-	
-	setTimeout(function (win, context, s) {
-				win.su_download_favs_getmetafavs_done2(context, s); },	
-			0,
-			window,
-			context,
-			s);		
-}
-
-function su_download_favs_getmetafavs_done2(context, s)
-{
-	if (context.stopped)
-		return;
-	
-//	if (context.paused)
-//	{
-//		setTimeout(function (win, context, s) {
-//				win.su_download_favs_getmetafavs_done2(context, s); },
-//				1000,
-//				window,
-//				context,
-//				s);
-//		return;
-//	}
-	
-	if (su_log_communication)
-		su_log("response getmetafavs.php", s);
-	
-	var commands = s.split("\n");
-	
-	window.setTimeout(function (win, context, commands) {
-			win.su_download_favs2(context, commands); },
-			0,
-			window,
-			context,
-			commands);
-}
-
-function su_download_favs2(context, commands)
-{
-	var command;
-	var command_parts; 
-	
-	if (su_ds.getValue("$download_favs_state") != "b")
-	{
-		// Download is done or stopped.
-		su_process_command_queue();
-	}
-	else if (commands.length)
-	{
-		command = commands.shift();
-		
-		if (command.indexOf("META ") == 0)
-		{	
-			context.download_count++;
-			su_enqueue_command(16000, command);
-		}
-		else if (command.indexOf("BATCH ") == 0)
-		{
-			command_parts = command.split(" ");
-			context.download_target_count = parseInt(command_parts[3]);
-			context.apply_target_count = parseInt(command_parts[3]);
-			su_ds.setValue("$download_favs_detail", context);
-			su_ds.flushPrefs();
-		}
-		else
-		{
-			su_process_command(command, context);
-		}
-		
-		setTimeout(function (win, context, commands) {
-					win.su_download_favs2(context, commands); },
-				10,
-				window,
-				context,
-				commands);
-	}
-	else if (! context.done)
-	{
-		setTimeout(function (win, context) {
-					win.su_download_favs_getmetafavs(context); },
-				0,
-				window,
-				context);
-		
-		su_process_command_queue();
-	}
-	else if (context.done && (context.mode == 1))
-	{
-		context.mode = 2;
-		context.prekey = 0;
-		context.done = false;
-		
-		setTimeout(function (win, context) {
-					win.su_download_favs_getmetafavs(context); },
-				0,
-				window,
-				context);
-
-		su_process_command_queue();
-	}
-	else if (context.done && (context.mode == 2))
-	{
-		context.apply_target_count = context.download_count;
-		context.apply_count = context.download_count - su_count_enqueued_commands(16000);
-		su_ds.setValue("$download_favs_detail", context);
-		su_ds.setValue("$download_favs_state", "c");
-		su_ds.flushPrefs();
-		su_ds.logEvent("dfth");
-		su_ds.setValue("#command_queue_context", null);
-		
-		su_process_command_queue();
-	}
-	else
-	{
-		su_log_error("DOWNLOADFAVS TERMINATION", context, commands.length);
-	}
-}
-
-function su_add_query_folder_bm(parent_folderid, target_folderids, tag, title, index)
-{
-	var hs = su_ds.getHistoryService();
-	var query = hs.getNewQuery();
-	var bms = su_ds.getBookmarksService();
-	query.setFolders(target_folderids, target_folderids.length);
-	query.searchTerms = tag;
-	var opt = hs.getNewQueryOptions();
-	opt.sortingMode = opt.SORT_BY_LASTMODIFIED_DESCENDING;
-	opt.resultType = opt.RESULTS_AS_URI;
-	opt.queryType = 1;
-	var query_str = hs.queriesToQueryString([query], 1, opt);
-	var ios = su_get_service(
-			"@mozilla.org/network/io-service;1",
-			"nsIIOService");
-	var nsiuri = ios.newURI(query_str, null, null);
-	
-	return bms.insertBookmark(
-			parent_folderid,
-			nsiuri,
-			index,
-			title);
-}
-
-function su_get_favicon_url(domain)
-{
-	if (! domain)
-		return null;
-	
-	filename = su_get_channel_id(domain) + ".ico";
-	
-	if (! su_ds.isResourceInstalled("favicons", filename))
-		return null;
-	
-	return su_ds.getResourceURLFromName("favicons", filename);
-}
-
-function su_get_channel_id(domain)
-{
-	return domain.replace(/\./g, "_");
-}
-
-function su_set_mode_all()
-{
-	su_set_mode("0", "All", "", "Stumble!", "Show next page");
-}
-
-function su_set_mode(cat, cat_label, src, label, tooltip)
-{
-	cat += "";
-	var el;
-	el = su_get_element("su_cat_langall");
-	if (el)
-		el.hidden = (cat.indexOf("LANG_") != 0);
-	
-	el = su_get_element("su_cat_" + cat);
-	if (el)
-		su_get_element("su_category").selectedItem = el;
-	
-	su_selected_category = cat + "";
-	
-	var tweakedCat = '';
-	if(cat_label)
-	{
-		tweakedCat = cat_label.replace(/\.com$/igm, "");
-		if(tweakedCat.length > 30)
-			tweakedCat = tweakedCat.slice(0, 27) + "...";
-	}
-	su_set_label("su_category", tweakedCat);
-
-	if (! ((stumbleid == 0) && (! su_promo_mode)))
-	{
-		su_set_label("su_stumble", label);
-		su_get_element("su_stumble").setAttribute("image2", src);
-		su_get_element("su_stumble").setAttribute("tooltiptext", tooltip);
-	}
-}
-
-function su_refresh_category_selector_batched()
-{
-	// By delaying for 500 ms, we batch sets of closely spaced menu 
-	// updates.
-	if (! su_refreshing_category_selector)
-	{
-		su_refreshing_category_selector = true;
-		su_blocked_category_selector_refresh_pending = false;
-		setTimeout(
-					function (win) {
-						win.su_invoke_global_event("refresh-category-selector", null); },
-					500,
-					window);
-	}
-	else if (su_refreshing_category_selector && 
-				(! su_blocked_category_selector_refresh_pending))
-	{
-		// If refresh is blocked, push back the refresh event.
-		su_blocked_category_selector_refresh_pending = true;
-		setTimeout(
-					function (win) {
-						win.su_refresh_category_selector_batched(); },
-					500,
-					window);
-	}
-}
-
-// This is the javascript way of creating an object and it's constructor:
-function su_CatObj(id, name)
-{
-	this.id = id;
-  this.name = name;
-}
-
-// Updates interest list in the in-cat stumble dialog, and saves current interests to disk (su_user_interests)
-function su_refresh_category_selector()
-{
-	// we need to completely *remove* the menupopup and readd it
-	// if we don't, the menupopup will be corrupt and it willl eventually 
-	// stop working.  this is a firefox specific problem	
-	var incat = su_get_element("su_category");
-
-	// delete the menupopup and regenerate it
-	var thechild;
-	thechild = incat.childNodes[0];
-	if (typeof(thechild.hidePopup) == "function")
-	{
-		thechild.hidePopup();
-		su_unfocus();
-	}
-	incat.removeChild(thechild);
-	
-	var ja = document.createElement("menupopup");
-	incat.appendChild(ja);
-
-	su_load_categories();
-
-	// Now add new children
-	var ints = new Array();
-	if (su_user_interests.length)
-	{
-		var cat2;
-		for (cat2 in su_user_interests)
-		{
-			if (su_is_property_garbage(su_user_interests, cat2))
-				continue;
-			
-			if (su_is_property_garbage(su_catnames, cat2))
-				continue;
-	
-			if ((typeof(su_catnames[cat2])) == "undefined")
-				continue;
-
-			ints.push(new su_CatObj(cat2, su_catnames[cat2]));
-		}
-	}
-	
-	ints.sort(function (a, b) 
-				{
-					if ( a.name < b.name ) return -1;
-					if ( a.name > b.name ) return 1;
-					return 0;
-				});
-
-	// ** An individual stumbler
-	ja = document.createElement("menuitem");
-	ja.setAttribute("class", "menuitem-iconic");
-	ja.setAttribute("label", "Pages from...");
-	ja.setAttribute("id", "su_cat_favorites_of2");
-	ja.setAttribute("tooltiptext", "Stumble someone's favorites");
-	ja.setAttribute("onclick", "su_favorites_of(event);");
-	ja.setAttribute("image", "chrome://stumbleupon/content/skin/stumbler_favorites.png");
-	ja.setAttribute("hidden", "true");
-	incat.childNodes[0].appendChild(ja);
-
-	// ** stumble in "all"
-
-	ja = document.createElement("menuitem");
-	ja.setAttribute("class", "menuitem-iconic");
-//	ja.setAttribute("label", su_ds.getValue("%menu.anytopic"));
-	ja.setAttribute("label", "All");
-	ja.setAttribute("id", "su_cat_0");
-	ja.setAttribute("tooltiptext", "Stumble all");
-	ja.setAttribute("oncommand", "su_select_topic(0, 'All', false);");
-	ja.setAttribute("image", "chrome://stumbleupon/content/skin/all.png");
-	incat.childNodes[0].appendChild(ja);
-
-	// ** Subscriptions
-	
-	ja = document.createElement("menuitem");
-	ja.setAttribute("class", "menuitem-iconic");
-//	ja.setAttribute("label", su_ds.getValue("%menu.anytopic"));
-	ja.setAttribute("label", "Subscriptions");
-	ja.setAttribute("id", "su_cat_friends");
-	ja.setAttribute("tooltiptext", "Sites from people I've subscribed to");
-	ja.setAttribute("oncommand", "su_select_topic('friends', 'Subscriptions', false);");
-	ja.setAttribute("image", "chrome://stumbleupon/content/skin/icon_tb_people.png");
-	incat.childNodes[0].appendChild(ja);
-
-	// ** StumbeThru
-	
-	ja = document.createElement("menuitem");
-	ja.setAttribute("class", "menuitem-iconic");
-	ja.setAttribute("label", "StumbleThru");
-	ja.setAttribute("id", "su_cat_stumblethru");
-	ja.setAttribute("tooltiptext", "StumbleThru a website");
-	ja.setAttribute("oncommand", 'su_set_server_location("stumblethru.php");');
-	ja.setAttribute("image", "chrome://stumbleupon/content/skin/domain.png");
-	incat.childNodes[0].appendChild(ja);
-
-	// ** Search
-	
-	ja = document.createElement("menuitem");
-	ja.setAttribute("class", "menuitem-iconic");
-	ja.setAttribute("label", "Search");
-	ja.setAttribute("id", "su_cat_stumble_tags");
-	ja.setAttribute("tooltiptext", "Stumble within a query");
-	ja.setAttribute("oncommand", 'su_handle_mode_click(event, "Search");');
-	ja.setAttribute("image", "chrome://stumbleupon/content/skin/search.png");
-	incat.childNodes[0].appendChild(ja);
-
-	// ** Photos
-	
-	ja = document.createElement("menuitem");
-	ja.setAttribute("class", "menuitem-iconic");
-//	ja.setAttribute("label", su_ds.getValue("%menu.anytopic"));
-	ja.setAttribute("label", "Photos");
-	ja.setAttribute("id", "su_cat_photos");
-	ja.setAttribute("tooltiptext", "Stumble an image");
-	ja.setAttribute("oncommand", "su_select_topic(302, 'Photos', false);");
-	ja.setAttribute("image", "chrome://stumbleupon/content/skin/icon_tb_photo_hover.png");
-	incat.childNodes[0].appendChild(ja);
-
-	// ** Videos
-	
-	ja = document.createElement("menuitem");
-	ja.setAttribute("class", "menuitem-iconic");
-//	ja.setAttribute("label", su_ds.getValue("@menu.anytopic"));
-	ja.setAttribute("label", "Videos");
-	ja.setAttribute("id", "su_cat_video");
-	ja.setAttribute("tooltiptext", "Stumble a video");
-	ja.setAttribute("oncommand", "su_select_topic('video', 'Videos', false);");
-	ja.setAttribute("image", "chrome://stumbleupon/content/skin/video.png");
-	incat.childNodes[0].appendChild(ja);
-
-	// ** News
-
-	ja = document.createElement("menuitem");
-	ja.setAttribute("class", "menuitem-iconic");
-//	ja.setAttribute("label", su_ds.getValue("%menu.anytopic"));
-	ja.setAttribute("label", "News");
-	ja.setAttribute("id", "su_cat_news");
-	ja.setAttribute("tooltiptext", "Stumble news");
-	ja.setAttribute("oncommand", "su_select_topic('news', 'News', false);");
-	ja.setAttribute("image", "chrome://stumbleupon/content/skin/icon_tb_news.png");
-	incat.childNodes[0].appendChild(ja);
-	
-	// ** contextual...
-	
-	// Create favorites of menu
-	var random_topic_id = 499;
-	var random_topic_name = 'StumbleUpon';
-		
-	ja = document.createElement("menuitem");
-	ja.setAttribute("class", "menuitem-iconic");	
-	ja.setAttribute("label", "More from " + random_topic_name);
-	ja.setAttribute("tooltiptext", "More from " + random_topic_name);
-	ja.setAttribute("id", "su_cat_morefrom");
-	ja.setAttribute("hidden", "true");
-	ja.setAttribute("oncommand", "su_select_topic(" + random_topic_id + ", '" + random_topic_name + "', false);");
-	ja.setAttribute("image", "chrome://stumbleupon/content/skin/topic.png");
-	incat.childNodes[0].appendChild(ja);
-
-	var preTopicsItem = ja;
-
-	var i;
-	if (ints.length < 21)
-	{
-		for (i = 0; i < ints.length; i++)
-		{
-			var newname
-			try {
-				newname = ints[i].name.replace(/'/g, "\\\'");
-			}
-			catch (e) {
-				su_log_error("CAT NEWNAME", ints[i], i);
-				continue;
-			}
-			ja = document.createElement("menuitem");
-			ja.setAttribute("label", ints[i].name);
-			ja.setAttribute("id", "su_cat_" + ints[i].id);
-			ja.setAttribute("tooltiptext", "Stumble " + ints[i].name);
-			ja.setAttribute("oncommand", "su_select_topic(" + ints[i].id + ",'" + newname + "', false);");
-			incat.childNodes[0].appendChild(ja);
-		}
-	}
-	else
-	{
-		var folders = new Array();
-		for (var cat in su_user_interests)
-		{
-			if (su_is_property_garbage(su_user_interests, cat))
-				continue;
-			
-			if (su_is_property_garbage(su_topicfolders, cat))
-				continue;
-			
-			if (su_is_property_garbage(su_catnames, cat))
-				continue;
-			
-			var folder = su_topicfolders[cat];
-			var name = su_catnames[cat];
-			if (typeof(folders[folder]) == "undefined")
-				folders[folder] = new Array();
-		
-			folders[folder][name]=cat;
-		}
-	
-		for (i = 0; i < su_foldernames.length; i++)
-		{
-			var key = su_foldernames[i];
-			if (typeof(folders[key]) == "undefined")
-					continue;
-			// topics = folders[key];
-
-			ja = document.createElement("menu");
-			ja.setAttribute("label", key);
-			ja.setAttribute("tooltiptext", "Stumble...");
-			var child = incat.childNodes[0].appendChild(ja);
-	
-			ja = document.createElement("menupopup");
-			var child2 = child.appendChild(ja);
-
-			var newtopics = new Array();
-			var counter = 0;
-			for (var catname in folders[key])
-			{
-				if (su_is_property_garbage(folders[key], catname))
-					continue;
-				
-				newtopics[counter] = catname;
-				counter++;	
-
-			}
-			newtopics.sort();
-			for (var j = 0; j < newtopics.length; j++)
-			{
-				name = newtopics[j];
-				var catid = su_catids[name];
-
-				ja = document.createElement("menuitem");
-				ja.setAttribute("class", "topic-selector");
-				ja.setAttribute("label", name);
-				ja.setAttribute("id", "su_cat_" + catid);
-				ja.setAttribute("tooltiptext", "Stumble " + name);
-				newname = name.replace(/'/g, "\\\'");
-				ja.setAttribute("oncommand", "su_select_topic(" + catid + ",'" + newname + "', false);");
-				child2.appendChild(ja);
-			}
-		}
-	}
-
-	if(preTopicsItem !== incat.childNodes[0].lastChild)
-	{
-		// If we have favorite topics, then include a separator before them
-		ja = document.createElement("menuseparator");
-		incat.childNodes[0].insertBefore(ja, preTopicsItem.nextSibling);
-	}
-
-	ja = document.createElement("menuseparator");
-	incat.childNodes[0].appendChild(ja);
-
-	ja = document.createElement("menuitem");
-//	ja.setAttribute("class", "topic-selector");
-//	ja.setAttribute("label", su_ds.getValue("%menu.addmoretopics"));
-	ja.setAttribute("label", "Update Topics");
-	ja.setAttribute("tooltiptext", "Select different topics");
-	ja.setAttribute("id", "su_cat_addmore");
-	ja.setAttribute("oncommand", "su_interests_pre();");
-	incat.childNodes[0].appendChild(ja);
-
-
-	// Create languages
-	ja = document.createElement("menu");
-//	ja.setAttribute("class", "topic-selector");
-	ja.setAttribute("label", "Languages");
-	ja.setAttribute("tooltiptext", "Stumble pages in a specific language");
-	ja.setAttribute("id", "su_languages");
-	var langs2 = incat.childNodes[0].appendChild(ja);
-
-	ja = document.createElement("menupopup");
-//	ja.setAttribute("class", "topic-selector");
-	ja.setAttribute("id", "su_languages-popup");
-	langs2.appendChild(ja);
-
-	// first check to see if favorites of is already there
-	var langs = su_get_element("su_languages-popup");
-
-	ja = document.createElement("menuitem");
-	ja.setAttribute("label", "All");
-//		ja.setAttribute("class", "topic-selector");
-	ja.setAttribute("id", "su_cat_langall");
-	ja.setAttribute("tooltiptext", "Stumble all");
-	ja.setAttribute("oncommand", "su_select_topic(0, 'All', false);");
-	langs.appendChild(ja);
-
-	var languages = new Array();
-
-	languages['ZH'] = "Chinese";
-	languages['DA'] = "Danish";
-	languages['NL'] = "Dutch";
-	languages['FI'] = "Finnish";
-	languages['FR'] = "French";
-	languages['DE'] = "German";
-	languages['EL'] = "Greek";
-	languages['IT'] = "Italian";
-	languages['JA'] = "Japanese";
-	languages['PT'] = "Portuguese";
-	languages['ES'] = "Spanish";
-	languages['SV'] = "Swedish";
-	languages['TR'] = "Turkish";
-
-	for (var langid in languages)
-	{
-		if (su_is_property_garbage(languages, langid))
-			continue;
-		
-		var langname = languages[langid];
-
-		ja = document.createElement("menuitem");
-		ja.setAttribute("label", langname);
-//		ja.setAttribute("class", "topic-selector");
-		ja.setAttribute("id", 'su_cat_LANG_' + langid);
-		ja.setAttribute("tooltiptext", "Stumble " + langname + " pages");
-		ja.setAttribute("oncommand", "su_select_topic('" + 'LANG_' + langid + "', '" + langname + "', false);");
-		langs.appendChild(ja);
-	}
-
-	su_set_mode_all();
-
-	su_refreshing_category_selector = false;
-}
-
-function su_favorites_of(event)
-{
-	su_unfocus_searchbox(); 
-	var stumbler = getBrowser().contentWindow.prompt("Enter the nickname of a stumbler:","");
-
-	// they clicked cancel
-	if (stumbler && (stumbler != ""))
-	{
-		// select and do it
-		su_select_topic(stumbler, stumbler, su_new_tab(event));
-	}
-	else
-	{
-		su_set_mode_all();
-	}
-	return true;
-}
-
-function su_unfocus_searchbox()
-{ 	 
-	// unfocus search box so we don't end up searching when they hit enter   	 
-	if (su_get_element("su_searchbox").getAttribute("focused") == "true")
-		su_unfocus();
-}
-
-function su_unfocus()
-{
-	if (! su_gui_initialized) return;
-	
-	if (document.commandDispatcher.focusedElement)
-	{
-		if ((document.commandDispatcher.focusedElement instanceof NSHTMLElement) || 
-					(document.commandDispatcher.focusedElement instanceof XULElement))
-		{
-			document.commandDispatcher.focusedElement.blur();
-		}
-		else
-		{
-			// non-HTML/XUL elements have no blur method; see bug 323805
-			document.commandDispatcher.focusedElement = null;
-		}
-	}
-}
-
-/*
-function su_tag_stumble()
-{
-	su_unfocus_searchbox(); 
-	var tag = getBrowser().contentWindow.prompt("Please enter a tag","");
-
-	// they clicked cancel
-	if (typeof(tag) == "undefined" || tag == "" || tag.length <= 0)
-	{
-		su_set_mode_all();
-		return false;
-	}
-
-	// put it in the box
-	su_get_element("su_searchbox").value=tag;
-	su_get_element("su_searchbox").removeAttribute("mode");
-	su_old_search = tag;
-	su_last_typed_tag = 0;
-	su_visited_searchbox = 1;
-
-	// select and do it
-	su_select_topic('TAG_' + tag, tag, false);
-	return true;
-}
-*/
-
-function su_handle_referral_throbber_click(event)
-{
-	su_stop_referred_throbber();
-	su_set_attribute("su_referred", "disabled", "true");
-	setTimeout(su_handle_referral_throbber_enable, su_ds.getValue("@click_throttle_ms"));
-	su_select_topic(0, "All", su_new_tab(event), true);
-}
-
-function su_handle_referral_throbber_enable()
-{
-	su_set_attribute("su_referred", "disabled", "false");
-	setTimeout(su_update_referred, 0);
-}
-
-/*
-function su_handle_report_dupe_command(url)
-{
-	if (su_enable_freereporting)
-	{
-		var media = su_ds.serialize(su_get_media_specs());
-	
-		var params = "";
-		params = su_arp(params, "url", stumbled_url);
-		params = su_arp(params, "redirect", su_redirect_url);
-		params = su_arp(params, "current", su_get_browser_url());
-		params = su_arp(params, "current_media", media);
-	
-		su_post_url_server_async(
-					"dupe.php",
-					params,
-					15000,
-					su_generic_done);
-	
-		var ps = su_get_service(
-					"@mozilla.org/embedcomp/prompt-service;1",
-					"nsIPromptService");
-		
-		ps.alert(window, "StumbleUpon", "Thanks for reporting this duplicate.\n\nIt will be reviewed by our support team.");
-	}
-	else
-	{
-		if (stumbled_url == "")
-		{
-			alert("You can't report pages that you haven't Stumbled upon."); 
-		}
-	
-		if (stumbleid == 0)
-			return;
-	
-		var params = "";
-		params = su_arp(params, "url", stumbled_url);
-		params = su_arp(params, "redirect", su_redirect_url);
-		params = su_arp(params, "current", su_get_browser_url());
-		params = su_arp(params, "verified", 1);
-
-		if (window.confirm("Are you sure that the following URL contains duplicate content?\n\n" + stumbled_url))
-		{
-			su_post_url_server_async(
-						"dupe.php",
-						params,
-						15000,
-						su_generic_done);
-		}
-	}
-}
-*/
-
-
-// Handler for menuitem "Report Miscat"
-function su_handle_report_miscat_command(tab_url)
-{
-	if (su_enable_freereporting)
-	{
-		var url_detail = su_ds.lookup("url:url_detail", tab_url);
-		
-		var loc = "misclassified.php";
-		if (url_detail)
-		{
-			loc = su_arp(loc, "url", url_detail.url, true);
-			loc = su_arp(loc, "redirect", url_detail.redirect_url, true);
-		}
-		else
-		{
-			loc = su_arp(loc, "url", tab_url, true);
-			loc = su_arp(loc, "redirect", tab_url, true);
-		}
-		loc = su_arp(loc, "current", su_get_browser_url(), true);
-		
-		su_set_server_location(loc, null, true);
-	}
-	else
-	{
-		if (stumbled_url == "")
-		{
-			alert("You can't report pages that you haven't Stumbled upon."); 
-			return;
-		}
-	
-		if (stumbleid == 0)
-			return;
-	
-		var loc = "misclassified.php";
-		loc = su_arp(loc, "url", stumbled_url, true);
-		loc = su_arp(loc, "redirect", su_redirect_url, true);
-		loc = su_arp(loc, "current", su_get_browser_url(), true);
-		loc = su_arp(loc, "verified", 1, true);
-		if (window.confirm("Are you sure that the following URL is in the wrong topic?\n\n" + stumbled_url))
-			su_set_server_location(loc, null, true);
-	}
-}
-
-
-// Handler for menuitem "Report Adult"
-function su_handle_report_adult_profile_command(tab_url)
-{
-	if (su_enable_freereporting)
-	{
-		var nickname = su_get_profile_nickname(tab_url);
-		
-		var loc = "adult.php";
-		loc = su_arp(loc, "stumbler", nickname);
-		
-		su_set_server_location(loc, null, true);
-	}
-	else
-	{
-		if (stumbled_url == "")
-		{
-			alert("You can't report pages that you haven't Stumbled upon."); 
-			return;
-		}
-	
-		if (stumbleid == 0)
-			return;
-	
-		var url = su_get_browser_url();
-		var nickname = su_get_profile_nickname(url);
-		
-		var loc;
-		if (nickname)
-		{
-			loc = "adult.php";
-			loc = su_arp(loc, "stumbler", nickname, true);
-			loc = su_arp(loc, "verified", 1, true);
-		}
-		else
-		{
-			loc = "misclassified.php";
-			loc = su_arp(loc, "adult_content", 1, true); 
-			loc = su_arp(loc, "url", stumbled_url, true);
-			loc = su_arp(loc, "redirect", su_redirect_url, true);
-			loc = su_arp(loc, "current", url, true);
-			loc = su_arp(loc, "verified", 1, true);
-		}
-
-		if (window.confirm("Are you sure that the following URL contains adult content?\n\n" + stumbled_url))
-			su_set_server_location(loc, null, true);
-	}
-}
-
-
-function su_handle_report_wrong_language_command(tab_url)
-{
-	if (su_enable_freereporting)
-	{
-		var url_detail = su_ds.lookup("url:url_detail", tab_url);
-		
-		var loc = "wrong_language.php";
-		if (url_detail)
-		{
-			loc = su_arp(loc, "url", url_detail.url, true);
-			loc = su_arp(loc, "redirect", url_detail.redirect_url, true);
-		}
-		else
-		{
-			loc = su_arp(loc, "url", tab_url, true);
-			loc = su_arp(loc, "redirect", tab_url, true);
-		}
-		
-		loc = su_arp(loc, "current", su_get_browser_url(), true);
-		
-		su_set_server_location(loc, null, true);
-	}
-	else
-	{
-		if (stumbled_url == "")
-		{
-			alert("You can't report pages that you haven't Stumbled upon."); 
-			return;
-		}
-	
-		if (stumbleid == 0)
-			return;
-	
-		var loc = "wrong_language.php";
-		loc = su_arp(loc, "url", stumbled_url, true);
-		loc = su_arp(loc, "redirect", su_redirect_url, true);
-		loc = su_arp(loc, "current", su_get_browser_url(), true);
-		loc = su_arp(loc, "verified", 1, true);
-		
-		if (window.confirm("Are you sure that the following URL is in the wrong language?\n\n" + stumbled_url))
-			su_set_server_location(loc, null, true);
-	}
-}
-
-// Handler for menuitem "Report Spam"
-function su_handle_report_spam_command(tab_url)
-{
-	if (su_enable_freereporting)
-	{
-		var url_detail = su_ds.lookup("url:url_detail", tab_url);
-		
-		var loc = "spam.php";
-		if (url_detail)
-		{
-			loc = su_arp(loc, "url", url_detail.url, true);
-			loc = su_arp(loc, "redirect", url_detail.redirect_url, true);
-		}
-		else
-		{
-			loc = su_arp(loc, "url", tab_url, true);
-			loc = su_arp(loc, "redirect", tab_url, true);
-		}
-		loc = su_arp(loc, "current", su_get_browser_url(), true);
-		
-		su_set_server_location(loc, null, true);
-
-//		ps.alert(window, "StumbleUpon", "Thanks for helping improve stumble selection.");
-	}
-	else
-	{
-		if (stumbled_url == "")
-		{
-			alert("You can't report pages that you haven't Stumbled upon."); 
-			return;
-		}
-	
-		if (stumbleid == 0)
-			return;
-	
-		var loc = "spam.php";
-		loc = su_arp(loc, "url", stumbled_url, true);
-		loc = su_arp(loc, "redirect", su_redirect_url, true);
-		loc = su_arp(loc, "current", su_get_browser_url(), true);
-		loc = su_arp(loc, "verified", 1, true);
-		
-		if (window.confirm("Are you sure that the following URL is spam?\n\n" + stumbled_url))
-			su_set_server_location(loc, null, true);
-	}
-}
-
-function su_handle_report_badware_command(tab_url)
-{
-	if (su_enable_freereporting)
-	{
-		var url_detail = su_ds.lookup("url:url_detail", tab_url);
-		
-		var params = "";
-		if (url_detail)
-		{
-			loc = su_arp(loc, "url", url_detail.url, true);
-			loc = su_arp(loc, "redirect", url_detail.redirect_url, true);
-		}
-		else
-		{
-			loc = su_arp(loc, "url", tab_url, true);
-			loc = su_arp(loc, "redirect", tab_url, true);
-		}
-		params = su_arp(params, "current", su_get_browser_url());
-		
-		su_post_url_server_async(
-				"badware.php",
-				params,
-				15000,
-				function (){});
-
-		var ps = su_get_service(
-					"@mozilla.org/embedcomp/prompt-service;1",
-					"nsIPromptService");
-		
-		ps.alert(window, "StumbleUpon", "Thanks for reporting this stumble.\n\nIt will be reviewed by our support team.");
-	}
-	else
-	{
-		if (stumbled_url == "")
-		{
-			alert("You can't report pages that you haven't Stumbled upon."); 
-		}
-	
-		if (stumbleid == 0)
-			return;
-	
-		var params = "";
-		params = su_arp(params, "url", stumbled_url);
-		params = su_arp(params, "redirect", su_redirect_url);
-		params = su_arp(params, "current", su_get_browser_url());
-		params = su_arp(params, "verified", 1);
-
-		if (window.confirm("Are you sure that the following URL contains hostile content?\n\n" + stumbled_url))
-		{
-			su_post_url_server_async(
-					"badware.php",
-					params,
-					15000,
-					su_generic_done);
-		}
-	}
-}
-
-// Handler for menuitem "Report 404"
-function su_handle_report_404_command(tab_url)
-{
-	//!!! we shouldn't really report 404, it should be something else (user 404?)
-	if (su_enable_freereporting)
-	{
-		var url_detail = su_ds.lookup("url:url_detail", tab_url);
-		
-		var params = "";
-		if (url_detail)
-		{
-			params = su_arp(params, "url", url_detail.url);
-			params = su_arp(params, "redirect", url_detail.redirect_url);
-		}
-		else
-		{
-			params = su_arp(params, "url", tab_url);
-			params = su_arp(params, "redirect", tab_url);
-		}
-		params = su_arp(params, "current", su_get_browser_url());
-		params = su_arp(params, "status", 404);
-	
-		su_post_url_server_async(
-				"404.php",
-				params,
-				15000,
-				su_generic_done);
-		
-		var ps = su_get_service(
-					"@mozilla.org/embedcomp/prompt-service;1",
-					"nsIPromptService");
-		
-		ps.alert(window, "StumbleUpon", "Thanks for reporting this broken page.\n\nIt will be reviewed by our support team.");
-	}
-	else
-	{
-		if (stumbled_url == "")
-		{
-			alert("You can't report pages that you haven't Stumbled upon."); 
-		}
-	
-		if (stumbleid == 0)
-			return;
-	
-		var params = "";
-		params = su_arp(params, "url", stumbled_url);
-		params = su_arp(params, "redirect", su_redirect_url);
-		params = su_arp(params, "current", su_get_browser_url());
-		params = su_arp(params, "status", 404);
-		params = su_arp(params, "verified", 1);
-
-		if (window.confirm("Are you sure that the following URL is 404 or broken?\n\n" + stumbled_url))
-		{
-			su_post_url_server_async(
-					"404.php",
-					params,
-					15000,
-					su_generic_done);
-			//alert("404 reported for page:\n\n" + stumbled_url);
-		}
-	}
-}
-
-function su_handle_report_inaccurate_command(tab_url)
-{
-	if (su_enable_freereporting)
-	{
-		var url_detail = su_ds.lookup("url:url_detail", tab_url);
-		
-		var params = "";
-		if (url_detail)
-		{
-			params = su_arp(params, "url", url_detail.url);
-			params = su_arp(params, "redirect", url_detail.redirect_url);
-		}
-		else
-		{
-			params = su_arp(params, "url", tab_url);
-			params = su_arp(params, "redirect", tab_url);
-		}
-		params = su_arp(params, "current", su_get_browser_url());
-		
-		su_post_url_server_async(
-					"inaccurate.php",
-					params,
-					15000,
-					su_generic_done);
-		
-		var ps = su_get_service(
-					"@mozilla.org/embedcomp/prompt-service;1",
-					"nsIPromptService");
-		
-		ps.alert(window, "StumbleUpon", "Thanks for helping improve stumble selection.");
-	}
-	else
-	{
-		if (stumbled_url == "")
-		{
-			alert("You can't report pages that you haven't Stumbled upon."); 
-		}
-	
-		if (stumbleid == 0)
-			return;
-	
-		var params = "";
-		params = su_arp(params, "url", stumbled_url);
-		params = su_arp(params, "redirect", su_redirect_url);
-		params = su_arp(params, "current", su_get_browser_url());
-		params = su_arp(params, "verified", 1);
-
-		if (window.confirm("Are you sure that the following URL contains inaccurate information?\n\n" + stumbled_url))
-		{
-			su_post_url_server_async(
-						"inaccurate.php",
-						params,
-						15000,
-						su_generic_done);
-		}
-	}
-}
-
-function su_handle_filter_command(tmp_adult)
-{
-	var params = "";
-	params = su_arp(params, "sadult", tmp_adult);
-	su_post_url_server_async(
-			"setoption.php",
-			params,
-			15000,
-			su_generic_done);
-}
-
-// Handler for menuitem "Change Current User" and used by newuserWindow
-function su_show_signin_dialog()
-{
-	su_unfocus_searchbox(); 
-	
-	var detail = new Object();
-	
-	detail.userid = "";
-	detail.password = "";
-	detail.nickname = "";
-	detail.enableg = 0;
-	detail.enableu = 0;
-	detail.disableu = 0;
-	detail.disableg = 0;
-	detail.autologout = false;
-	
-	window.openDialog(
-				"chrome://stumbleupon/content/signinDialog.xul", 
-				"su_sign_in",
-				"chrome,modal,dialog,centerscreen,dependent",
-				detail);
-}
-
-function su_get_autologout_for_user(str)
-{
-	var pref = "stumble." + str + ".autologout";
-	if (su_ds.isPrefDefined(pref))
-	{
-		// easy, uncommon case where str is the userid
-		return su_ds.getValue(pref);
-	}
-	
-	// more common case where str is the nickname
-	var ids = su_ds.getValue("@id_list").split(":");
-	
-	var i;
-	for (i = 0; i < ids.length; i++)
-	{
-		if (ids[i] == "") continue;
-		if (su_ds.isPrefDefined("stumble." + ids[i] + ".nick") &&
-					(str == su_ds.getValue("stumble." + ids[i] + ".nick")))
-		{
-			return su_ds.getPrefValue("stumble." + ids[i] + ".autologout", false);
-		}
-	}
-	return false;
-}
-
-function su_handle_signin_dialog_accept(detail)
-{
-	if (stumbleid != 0)
-		su_ds.deleteStoredPassword();
-	
-	stumbleid = detail.userid;
-	
-	su_ds.setValue("@current_user", detail.userid);
-	var new_profile = (! su_ds.isPrefDefined("$nick"));
-	
-	var unhashed_password = detail.password;
-	var password = null;
-	
-	if (su_enable_hashed_password)
-		password = su_ds.getEncodedPassword(unhashed_password, detail.userid);
-	
-	su_ds.storePassword(password, unhashed_password);
-
-	su_ds.setValue("$autologout", detail.autologout);
-	su_ds.setValue("$nick", detail.nickname);
-	if(detail.thumbup_count)
-	{
-		su_ds.setValue("$thumbup_count", detail.thumbup_count);
-		su_thumbup_count_changed();
-	}
-	if(detail.stumble_count)
-	{
-		su_ds.setValue("$stumble_count", detail.stumble_count);
-		su_stumble_count_changed();
-	}
-	
-	su_enable_client_features(detail.enableg);
-	su_enable_user_features(detail.enableu);
-	su_disable_client_features(detail.disableg);
-	su_disable_user_features(detail.disableu);
-	
-	// now sync this stuff before we crash
-	su_ds.flushPrefs();
-
-	var login_detail = new Object();
-	login_detail.skip_cookies = false;
-	login_detail.ignore_cookies = true;
-	login_detail.new_profile = new_profile;
-	login_detail.new_user_prompt = false;
-	su_invoke_global_event("login", login_detail);
-	
-	var loc = "discover/activity";
-	su_set_server_location(loc, null, !su_is_about_blank());
-}
-
-// Handler for menuitem "Change Password"
-function su_handle_change_password()
-{
-	su_unfocus_searchbox(); 
-	
-	var detail = new Object();
-	
-	detail.password = "";	
-	detail.id = stumbleid;
-	
-	window.openDialog(
-				"chrome://stumbleupon/content/passwordDialog.xul",
-				"su_password",
-				"chrome,modal,dialog,centerscreen,dependent",
-				detail);
-}
-
-function su_handle_password_dialog_accept(detail)
-{
-	// change local password
-	var unhashed_password = detail.password;
-	var password = null;
-	
-	if (su_enable_hashed_password)
-		password = su_ds.getEncodedPassword(unhashed_password, stumbleid);
-	
-	su_ds.storePassword(password, unhashed_password);
-	
-	var cookieManager = su_get_service(
-				"@mozilla.org/cookiemanager;1",
-				"nsICookieManager");
-	cookieManager.remove("." + su_servername, "PHPSESSID", "/", 0);
-	
-	su_invoke_global_event("change-password", null);
-	alert("Password changed");
-}
-
-// Handler for menuitem "Feedback"
-function su_feedback()
- {
-	if (stumbleid == 0)
-		return false;
-
-	// Redirect to the feedback page
-	getBrowser().contentDocument.location = su_base_url + "feedback.php";
-
-	return true;
-}
-
-// Handler for menuitem "Sign-out"
-function su_handle_logout(logout_from_website)
-{
-	var doc = getBrowser().contentDocument;
-
-	if (stumbleid == 0)
-		return false;
-
-	var detail = new Object();
-	detail.response = 0;
-	
-	window.openDialog(
-			"chrome://stumbleupon/content/signoutDialog.xul", 
-			"su_sign_out",
-			"chrome,modal,dialog,centerscreen,dependent",
-			detail);
-	if (detail.response == 1)
-	//if (window.confirm("Are you *sure* you would like to Sign-out?\n\n(Click CANCEL if you do not know your password,\nor you will LOSE THIS ACCOUNT)"))
-	{
-		su_invoke_global_event("logout", null)
-		if (logout_from_website)
-			su_set_location("http://www." + su_servername + "/login.php?logout=1", null, null, null);
-		else
-		{
-			var url = doc.location.toString();
-			if (su_is_matching_domain(url, su_servername))
-			{
-				su_set_location(url);
-			}
-		}
-	}
-
-	return true;
-}
-
-// handles the global login event
-function su_login(skip_cookies, ignore_cookies, new_profile, new_user_prompt)
-{
-	if (su_stumble_async_context && su_stumble_async_context._request)
-	{
-		// kill the pending action
-		su_service.abortPostAsync(su_stumble_async_context._request);
-	}
-	
-	su_init_login(skip_cookies, ignore_cookies); // clears user session globals
-
-	su_load_data1(new_profile);
-	
-	if (! new_user_prompt)
-		su_ds.setValue("$intro_count", 15);
-	
-	if (! su_ds.getValue("~visited_signup"))
-		su_show_searchlinks_dialog(new_user_prompt, false, false);
-
-	su_load_data2(true);  // calls su_configure_toolbar()
-	
-	su_ds.setValue("~visited_signup", false);
-}
-
-// handles the global change-password event
-function su_change_password()
-{
-	stumblepass = su_ds.getStoredPassword();
-}
-
-function su_has_logged_in()
-{
-	var ids = su_ds.getValue("@id_list").split(":");
-
-	var found = false;
-	var i;
-	for (i = 0; i < ids.length; i++)
-	{
-		if (ids[i] == "")
-			continue;
-		
-		found = true;
-		break;
-	}
-	return found;
-}
-
-// handles the global configure-toolbar event and is used by
-// load_data2()
-function su_configure_toolbar(from_preference_dialog)
-{
-	if (! from_preference_dialog)
-	{
-		try {
-			su_close_info();
-		} catch (e) { su_log_error("CONFIGURE CLOSEINFO", e, from_preference_dialog); } 
-		
-		try {
-			su_move_toolbar(true, 1);
-		} catch (e) { su_log_error("CONFIGURE MOVE", e, from_preference_dialog, su_ds.getValue("@toolbar-position"), su_ds.getValue("@position-group")); } 
-	
-		try {
-			su_refresh_toggle_button(true);
-		} catch (e) { su_log_error("CONFIGURE TOGGLE", e, from_preference_dialog); } 
-	}
-		
-	try {
-		su_set_mode_all();
-	} catch (e) { su_log_error("CONFIGURE SET MODE", e, from_preference_dialog); } 
-
-	try {
-		su_init_labels();
-	} catch (e) { su_log_error("CONFIGURE LABELS", e, from_preference_dialog); } 
-
-	try {	
-		if (su_host.mac)
-			su_set_attribute("su_thumbdown", "mac", "true");
-	} catch (e) { su_log_error("CONFIGURE THUMBDOWN", e, from_preference_dialog); }
-	
-	try {
-		su_init_toolbar_element_visibility();
-	} catch (e) { su_log_error("CONFIGURE HIDDEN STATES", e, from_preference_dialog); } 
-
-	if (stumbleid != 0)
-	{
-		try {
-			su_set_autocomplete_type(su_ds.getValue("$autocomplete_type"));
-		} catch (e) { su_log_error("CONFIGURE AUTOCOMPLETE", e, from_preference_dialog); } 
-
-		try {
-			su_dyn_channels_dirty = true;
-			su_update_dyn_channels();
-		} catch (e) { su_log_error("CONFIGURE DYN CHANNEL BUTTONS", e, from_preference_dialog); } 
-
-		try {
-			su_refresh_category_selector();
-		} catch (e) { su_log_error("CONFIGURE CATEGORY SELECTOR", e, from_preference_dialog); } 
-	
-		try {
-			su_referral_menu_dirty = true;
-			su_update_referral_menu();
-		} catch (e) { su_log_error("CONFIGURE REFERRAL MENU", e, from_preference_dialog); } 
-
-		try {
-			su_refresh_keybindings();
-		} catch (e) { su_log_error("CONFIGURE KEYBINDINGS", e, from_preference_dialog); }
-
-	}
-	
-	su_reflow_toolbar("CONFIGURE");
-
-	setTimeout(function (win, url) { win.su_refresh_pagemeta(false, 2); }, 0, window);
-	setTimeout(function (win) { win.su_reflow_toolbar("CONFIGURE2"); }, 500, window);
-	setTimeout(function (win) { win.su_reflow_toolbar("CONFIGURE3"); }, 2000, window);
-}
-
-function su_verify_bookmarks_folder()
-{
-	if (! su_host.places)
-		return;
-	
-	var bms = su_ds.getBookmarksService();
-	
-	var folderid = su_ds.getValue("$bm_folderid");
-	var tmpidx;
-	if (folderid != 0)
-	{
-		tmpidx = -1;
-		try {
-			tmpidx = bms.getItemIndex(folderid);
-		} catch (e) {}
-		if (tmpidx != -1)
-			return;
-	}
-	
-	var children = Application.bookmarks.menu.children;
-	var i;
-	var folders_by_label = new Object();
-	var nonfolders_by_label = new Object();
-	var item;
-	for (i = 0; i < children.length; i++)
-	{
-		item = children[i];
-
-		if ((typeof item.title) != "string")
-			continue;
-		
-		if (item.title.indexOf("StumbleUpon") == 0)
-		{
-			if (item.type == "folder")
-				folders_by_label[item.title] = item;
-			else
-				nonfolders_by_label[item.title] = item;
-		}
-	}
-	
-	item = null;
-
-	if ((! folders_by_label["StumbleUpon"])
-			&& (! nonfolders_by_label["StumbleUpon"]))
-	{
-		item = Application.bookmarks.menu.addFolder("StumbleUpon");
-	}
-	
-	var basename = "StumbleUpon - " + su_ds.getValue("$nick");
-	var i = 1;
-	var candidate_name;
-	while (! item)
-	{
-		if (i == 1)
-			candidate_name = basename;
-		else
-			candidate_name = basename + " (" + i + ")";
-			
-		if (folders_by_label[candidate_name])
-			item = folders_by_label[candidate_name];
-		else if (! nonfolders_by_label[candidate_name])
-			item = Application.bookmarks.menu.addFolder(candidate_name);
-		
-		i++;
-	}
-	
-	su_ds.setValue("$bm_folderid", item.id);
-	
-	su_ds.flushPrefs();
-}
-
-// handles the global logout event
-function su_logout()
-{
-	// 0. If we don't hide the popup, the menu get munged
-	var stumble_popup = su_get_element("su_stumble_popup");
-	if (typeof(stumble_popup.hidePopup) == "function")
-	{
-		stumble_popup.hidePopup();
-		su_unfocus();
-	}
-	
-	if (su_stumble_async_context && su_stumble_async_context._request)
-	{
-		// kill the pending action
-		su_service.abortPostAsync(su_stumble_async_context._request);
-	}
-	
-	su_stumbleReporter.stop();
-	
-	try {	
-		su_prefetcher.stop();
-		su_prefetcher.clearTargets();
-	} catch (e) { su_log_error("PREFETCHER 4", e); }
-	
-	try {
-		su_close_all_messages();
-	} catch (e) { su_log_error("LOGOUT CLOSEALLMSGS", e); }
-	
-	su_logout_auth(); // clears user session globals
-
-	su_init_labels();
-	
-	su_init_toolbar_element_visibility();
-	
-	su_refresh_pagemeta(false, 5);
-
-	su_get_element("su_stumble").setAttribute("image2", "");
-	
-	setTimeout(su_reflow_toolbar, 0, 2);
-
-	su_commands_by_keyspec = new Object();
-
-	window.removeEventListener("keyup", su_handle_window_keyup, false);
-	window.removeEventListener("keypress", su_handle_window_keypress, false);
-
-	var toggle_key = su_get_element("key_StumbleUpon:ToggleToolbar");
-	if (toggle_key)
-		toggle_key.setAttribute("command", toggle_key.getAttribute("savedcommand"));
-
-	var toolbar_el = su_get_element("stumbleupon");
-	if (toolbar_el)
-		toolbar_el.setAttribute("toolbarname", toolbar_el.getAttribute("savedtoolbarname"));
-	
-}
-
-// handles the Extension Manager uninstall event in Firefox 1.5+; 
-// prompts for uninstallation options
-function su_handle_em_uninstall()
-{
-	su_uninstall_scheduled = true;
-
-	var recent_window = su_get_service(
-				"@mozilla.org/appshell/window-mediator;1",
-				"nsIWindowMediator")
-				.getMostRecentWindow("navigator:browser");
-
-	if (window != recent_window)
-		return;
-	
-	var detail = new Object();
-	detail.logout = false;
-	detail.remove_data = false;
-	detail.delete_account = false;
-
-	su_unfocus_searchbox(); 
-
-	window.openDialog(
-				"chrome://stumbleupon/content/uninstallDialog.xul",
-				"su_uninstall_options",
-				"chrome,modal,dialog,centerscreen,dependent", 
-				detail);
-				
-	if (detail.delete_account)
-	{
-		if (su_enable_hashed_password)
-		{
-			su_post_url_server(
-						"delete_account.php",
-						"version=" + su_verstring + 
-							"&stumbler=" + stumbleid + 
-							"&password=" + stumblepass);
-		}
-		else
-		{
-			su_post_url_server(
-						"delete_account.php",
-						"version=" + su_verstring + 
-							"&stumbler=" + stumbleid + 
-							"&password=" + encodeURIComponent(stumblepass));
-		}
-	}
-
-	if (detail.logout)
-		su_invoke_global_event("logout", null);
-	
-	if (detail.remove_data)
-		su_invoke_global_event("schedule-remove-data", null);
-}
-
-
-// handles the global schedule-remove-data event
-function su_schedule_remove_data()
-{
-	// We remove the data now for good measure, then we remove it again
-	// when each window is closed and when the app quits. -- JW
-	su_remove_data_scheduled = true;
-	su_remove_data();
-}
-
-// removes all stumbleupon files and preferences
-function su_remove_data()
-{
-	var ids = new Array();
-	try {
-		ids = su_ds.getValue("@id_list").split(":");
-	} catch (e) {}
-	var i;
-	for (i = 0; i < ids.length; i++)
-	{
-		if (ids[i] == "")
-			continue;
-		
-		su_ds.deleteFile(su_ds.getLegacyNSIFile("stumbleurls", ids[i]));
-		su_ds.deleteFile(su_ds.getLegacyNSIFile("stumblerating", ids[i]));
-		su_ds.deleteFile(su_ds.getLegacyNSIFile("stumbletags", ids[i]));
-		su_ds.deleteFile(su_ds.getLegacyNSIFile("stumblequeries", ids[i]));
-	}
-
-	var file = su_get_service(
-				"@mozilla.org/file/directory_service;1",
-				"nsIProperties")
-				.get("ProfD", Components.interfaces.nsIFile);
-	file.append("StumbleUpon");
-	su_ds.deleteDirectory(file);
-	
-	var pref_names = su_ds.getPrefNames("stumble.");
-	for (i = 0; i < pref_names.length; i++)
-	{
-		try {
-			su_ds.clearPref(pref_names[i]);
-		} catch (e) {}
-	}
-
-	var cookieManager = su_get_service(
-			"@mozilla.org/cookiemanager;1",
-			"nsICookieManager");
-	cookieManager.remove("." + su_servername, "PHPSESSID", "/", 0);
-	cookieManager.remove("." + su_servername, "stumble_user", "/", 0);
-	cookieManager.remove("." + su_servername, "stumble_pass", "/", 0);
-	cookieManager.remove("." + su_servername, "tsuu", "/", 0);
-	cookieManager.remove("." + su_servername, "tsut", "/", 0);
-	cookieManager.remove("." + su_servername, "nickname", "/", 0);
-	cookieManager.remove("." + su_servername, "searchlinks", "/", 0);
-	cookieManager.remove("." + su_servername, "thru_domains", "/", 0);
-	cookieManager.remove("." + su_servername, "enableu", "/", 0);
-	cookieManager.remove("." + su_servername, "enableg", "/", 0);
-	cookieManager.remove("." + su_servername, "SU_REMEMBER", "/", 0);
-	
-	su_logout_server();
-}
-
-// Handler for menuitem "Chatroom"
-function su_chat()
-{
-	var doc = getBrowser().contentDocument;
-
-	if (stumbleid == 0)
-		return;
-
-	// Redirect to the chat page
-	getBrowser().contentDocument.location = su_base_url + "chat.php";
-}
-
-// Handler for button "FirstRater" (the happy face)
-function firstrater_func(event)
-{
-	var doc = getBrowser().contentDocument;
-
-	if (stumbleid == 0)
-		return;
-
-	var frater = su_get_element("firstrater");
-	var firstrater = frater.firstrater;
-
-	su_set_location(
-				"http://" + firstrater + "." + su_servername + "/",
-				null,
-				su_new_tab(event));
-}
-
-// sets the tabbrowser location, to one of the user's profile tabs
-function su_set_profile_location(profile_tab, new_tab)
-{
-	var nick = su_ds.getValue("$nick");
-
-	var go_url = '';
-	if (nick == '')
-		go_url = "http://" + stumbleid + "." + su_servername + "/";
-	else
-		go_url = "http://" + nick + "." + su_servername + "/";		
-
-	if (profile_tab != '')
-		go_url += profile_tab + "/";
-
-	su_set_location(go_url, null, new_tab);
-}
-
-// sets the tabbrowser location, when the location is beneath the 
-// www stumbleupon domain
-function su_set_server_location(url_suffix, postdata, new_tab)
-{
-	su_set_location(su_base_url + url_suffix, postdata, new_tab, null)
-}
-
-// sets the tabbrowser location
-function su_set_location(uri, postdata, new_tab, opt_detail)
-{
-	if ((typeof opt_detail) == "undefined")
-		opt_detail = null;
-	
-	var browser = getBrowser();
-	if (new_tab)
-	{
-		var tab = browser.addTab(
-					uri,
-					su_get_nsiuri(browser.contentDocument.referrer),
-					null, // charset
-					(postdata == null) ? null : su_get_mime_input_stream(postdata, "application/x-www-form-urlencoded"));
-		browser.selectedTab = tab;
-		
-		tab.su_detail = opt_detail;
-	}
-	else
-	{
-		browser.selectedTab.su_detail = opt_detail;
-		
-		browser.webNavigation.loadURI(
-					uri,
-					Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE,
-					su_get_nsiuri(browser.contentDocument.referrer),
-					(postdata == null) ? null : su_get_mime_input_stream(postdata, "application/x-www-form-urlencoded"),
-					null); // headers
-	}
-}
-
-// Handler for button "Website Info"
-function su_website_info(new_tab, theurl, firstrate)
-{
-	
-	if (su_ds.getValue("$review_new_window"))
-		new_tab = true;
-
-	if (stumbleid == 0)
-		return;
-
-	var current_page = theurl;
-	
-	if (theurl == "")
-	{
-		current_page = su_get_browser_url();		
-		if (stumbled_redirect != '' && current_page == stumbled_redirect)
-		{
-			// we have a redirect, rate the original url we stumbled on
-			current_page = stumbled_url;
-		}		
-	}
-	
-	var cmp_url = current_page.toLowerCase();
-	
-	if (cmp_url.indexOf("http://video." + su_servername + "/#p") == 0)
-		return;
-				
-	if (cmp_url.indexOf("http://video." + su_servername + "/?p") == 0)
-		return;
-	
-	var stumblevideo = (su_get_stumblevideo_detail() != null);
-	
-	if (current_page.indexOf("about:") == 0)
-		return;
-	
-	if ((su_quote == "") && getBrowser().contentWindow.getSelection)
-	{
-		quote = getBrowser().contentWindow.getSelection().toString();
-	}
-	else
-	{
-		quote = su_quote;
-		su_quote = "";
-	}
-	
-	var searchbox_value = su_get_element("su_searchbox").value;
-	if ((! su_ds.getValue("$show_field")) || 
-				(searchbox_value == su_tag_instructions) ||
-				su_validate_tagstring(searchbox_value))
-	{
-		searchbox_value = "";
-	}
-	
-	var current_page2 = current_page;
-	if (current_page2.length > 300)
-		current_page2 = current_page2.substr(0, 300);
-
-	if ((! stumblevideo) && su_photoblogimage)
-	{
-		su_set_server_location(
-					"url.php?url=" + encodeURIComponent(current_page2) + 
-						"&image=" + encodeURIComponent(su_photoblogimage.src) + 
-						"&width=" + su_photoblogimage.width + 
-						"&height=" + su_photoblogimage.height + 
-						"&firstrate=" + firstrate + 
-						"&tag=" + escape(searchbox_value),
-					null,
-					new_tab);
-		su_photoblogimage = null;
-	}
-	else if ((! stumblevideo) && (quote != ""))
-	{
-		su_set_server_location(
-					"url.php?url=" + encodeURIComponent(current_page2) + 
-						"&quote=" + encodeURIComponent(quote) + 
-						"&firstrate=" + firstrate + 
-						"&tag=" + escape(searchbox_value), 
-					null,
-					new_tab);
-	}
-	else
-	{
-		su_set_server_location(
-					"url/" + su_review_url(current_page),
-					null,
-					new_tab);
-//		setTimeout(
-//					su_set_server_location,
-//					3000,
-//					"url/" + su_review_url(current_page, true),
-//					null,
-//					new_tab);
-	}
-}
-
-function su_review_url(url, new_impl)
-{
-	// strip off the http://
-	if (url.indexOf("http://") == 0)
-		url = url.substr(7);
-	
-	url = encodeURIComponent(url);
-	
-	url = encodeURIComponent(url);
-
-	url = url.replace(/%252F/g, "/");
-
-	return url;
-}
-
-// Check to see if an email is valid
-function su_validate_email(str)
-{
-	// var filter=/^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
-	var filter  = /^([a-zA-Z0-9_\.\-+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
-	if (filter.test(str))
-		return(true);
-	else
-		return(false);
-}
-
-function su_remove_email(email)
-{
-	if (!(window.confirm("Are you sure that you want to delete the email address '" + email + "'")))
-		return;
-
-	var contact = su_ds.selectRow("contact", "email", email);
-	
-	if (! contact)
-		return;
-	
-	contact.hidden = true;
-	su_ds.updateRow(contact);
-	su_ds.flushPrefs();
-	
-	su_refresh_referral_menu(2);
-}
-
-// Handler for menuitem from mailto menu
-function su_mailit(recipient_email)
-{
-	if (stumbleid == 0)
-		return;
-
-	su_unfocus_searchbox(); 
-	// Now grab recipient and cache it
-	if (recipient_email == "")
-	{
-		recipient_email = getBrowser().contentWindow.prompt("Please enter the recipient's email address", "");
-		if (recipient_email == null || recipient_email == "" || typeof(recipient_email) == "undefined")
-			return;
-	}
-
-	// do an email sanity check
-	if (!su_validate_email(recipient_email))
-	{
-		alert("Recipient is not a valid email address!");
-		return;
-	}
-
-	// Cache the email
-	var contact = su_ds.selectRow("contact", "email", recipient_email);
-	
-	if (contact && contact.hidden)
-	{
-		contact.hidden = false;
-		su_ds.updateRow(contact);
-	}
-	else if (! contact)
-	{
-		contact = new Object();
-		contact.email = recipient_email;
-		su_ds.insertRow("contact", contact);
-	}
-
-	su_ds.flushPrefs();	
-
-	var current_page = su_get_browser_url();
-	
-	if (current_page.indexOf("about:") == 0)
-	{	
-		su_refresh_referral_menu(3);
-		return;
-	}
-
-	su_unfocus_searchbox(); 
-
-	
-	var detail = new Object();
-	detail.mode = "email";
-	detail.target = recipient_email;
-	detail.url = current_page;
-	detail.display_url = su_get_browser_url(null, true);
-	detail.stumblevideo = (su_get_stumblevideo_detail() != null);
-	detail.title = getBrowser().contentDocument.title;
-	detail.dialog_title = "Send to " + detail.target;
-	detail.show_target = su_host.mac;
-	detail.referrer_url = su_get_browser_referrer_url();
-
-	window.openDialog(
-				"chrome://stumbleupon/content/sendDialog.xul",
-				"",
-				"chrome,dialog,centerscreen,dependent", 
-				detail);
-}
-
-function su_generic_done(res)
-{
-	var context = res.detail;
-	
-	try {
-		if (res.status != 200)
-			return;
-	} catch (e) { return; } 
-	
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-	
-	if (su_log_communication)
-		su_log("response " + context.request_target, s);
-	
-	su_process_commands(s, context);
-}
-
-
-// Handler for menuitem "About"
-function su_about()
-{
-	// Redirect to about page
-	getBrowser().contentDocument.location = su_serverhttp + 'about.php?version=' + su_verstring;
-}
-
-function su_get_friends()
-{
-	var params = "";
-	params = su_arp(params, "now", su_get_time_s());
-	params = su_arp(params, "configured", su_ds.getValue("$friends_synced"));
-	
-	su_post_url_server_async(
-				"getfriends.php",
-				params,
-				null,
-				su_get_friends_done,
-				null);
-}
-
-function su_get_friends_done(res)
-{
-	try {
-		if (res.status != 200)
-			return;
-	} catch (e) { return; } 
-	
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-	
-	if (su_log_communication)
-		su_log("response getfriends.php", s);
-	
-	var context = new Object();
-	context.quiet = true;
-	su_process_commands(s, context);
-	
-	su_ds.setValue("$friends_synced", "" + su_get_time_s());
-}
-
-function su_get_facebook_userid()
-{
-	var fbuserid = su_ds.getValue("#facebook_userid"); 
-	if (fbuserid)
-		return fbuserid;
-	
-	var manager = su_get_service(
-				"@mozilla.org/cookiemanager;1",
-				"nsICookieManager");
-	var cookies = manager.enumerator;
-	var cookie;
-	
-	while (cookies.hasMoreElements())
-	{
-		cookie = cookies.getNext().QueryInterface(
-					Components.interfaces.nsICookie);
-					
-		if (cookie.host == ".facebook.com")
-		{
-			if (cookie.name == "c_user")
-			{
-				fbuserid = parseInt(cookie.value);
-				break;
-			}
-		}
-	}
-	su_ds.setValue("#facebook_userid", fbuserid);
-	return fbuserid;
-}
-
-function su_get_facebook(doc)
-{
-	if (stumbleid == 0)
-		return;
-	
-	if (su_ds.getValue("#checking_facebook"))
-		return;
-	
-	su_ds.setValue("#checking_facebook", true);
-	
-	var detail = new Object();
-	detail.doc = doc;
-	detail.stumbleid = stumbleid;
-	
-	var fbuserid = su_get_facebook_userid();
-	
-	if (! fbuserid)
-	{
-		su_ds.setValue("#checking_facebook", false);
-		return;
-	}
-	
-	su_post_url_server_async(
-				"getfacebook.php",
-				su_arp("", "id", fbuserid),
-				15000,
-				su_get_facebook_done,
-				detail);
-}
-
-function su_get_facebook_done(res)
-{
-	try {
-		if (res.status != 200)
-			return;
-	} catch (e) { return; } 
-	
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-	
-	var detail = res.detail;
-	
-	if (su_log_communication)
-		su_log("response getfacebook.php", s);
-	
-	if (detail.stumbleid != stumbleid)
-		return;
-	
-	su_ds.setValue("#checking_facebook", false);	
-	
-	if (! res.aborted)
-		su_ds.setValue("#checked_facebook", true);
-	
-	var context = new Object();
-	context.quiet = true;
-	su_process_commands(s, context);
-	
-	su_refresh_pagemeta(false, 6);
-	
-	if (detail.doc)
-		su_facebookhome_page(detail.doc);
-}
-
-function su_get_state(migrating)
-{
-	su_post_url_server_async(
-				"getstate.php",
-				su_arp("", "migrating", ((migrating) ? 1 : 0)),
-				null,
-				su_get_state_done,
-				null);
-}
-
-function su_get_state_done(res)
-{
-	try {
-		if (res.status != 200)
-			return;
-	} catch (e) { return; } 
-	
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-	
-	if (su_log_communication)
-		su_log("response getstate.php", s);
-	
-	var context = new Object();
-	context.quiet = true;
-	su_process_commands(s, context, true, 0);
-}
-
-function su_import_contacts()
-{
-	// hit getcontacts.php, parse, and add non-dupes to menu	
-	su_post_url_server_async(
-				"getcontacts.php",
-				null,
-				null,
-				su_import_contacts_done,
-				null);
-}
-
-function su_import_contacts_done(res)
-{
-	try {
-		if (res.status == 1)
-			return;
-	} catch (e) { return; }
-
-	if (res.status != 200)
-		return;
-	
-	var s = res.responseText;
-
-	if (typeof(s) != "object" && typeof(s) != "undefined" && s != "")
-	{
-		var newlines = s.split("\n");
-		for (var i = 0; i < newlines.length; i++)
-		{
-			if (newlines[i] == "")
-				continue;
-			
-			var lines = newlines[i].split(",");
-			if (lines.length>0)
-			{
-				var email = lines[0];
-
-				//invalid email address
-				if (!su_validate_email(email))
-					continue;
-				
-				var contact = su_ds.selectRow("contact", "email", email);
-				if (! contact)
-				{
-					contact = new Object();
-					contact.email = email;
-					su_ds.insertRow("contact", contact);
-				}
-			}
-		}
-		su_ds.flushPrefs();
-		su_refresh_referral_menu(4);	
-	}
-}
-
-function su_get_interests()
-{
-	su_post_url_server_async(
-				"getinterests.php",
-				null,
-				null,
-				su_get_interests_done,
-				null);
-}
-
-function su_get_interests_done(res)
-{
-	try {
-		if (res.status != 200)
-			return;
-	} catch (e) { return; } 
-	
-	var s = "";
-	
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-	
-	if (su_log_communication)
-		su_log("response getinterests.php", s);
-	
-	if (typeof(s) != "string")
-		return;
-		
-	su_process_topic_list(s);
-}
-
-function su_dist_time()
-{
-	var now = su_get_time_s();
-	var installed = su_ds.getIntValue("@installed");
-	if (installed == 0)
-	{
-		installed = now;
-		su_ds.setValue("@installed", "" + now);
-	}
-	
-	if (! su_host.dist)
-		return;
-	
-	if (su_dist_time_timer)
-	{
-		// if the user changes, this clears the timeout set for the
-		// previously logged in user
-		clearTimeout(su_dist_time_timer);
-	}
-	
-	var reg_prev = su_ds.getIntValue("@dist_reg");
-	var interval = 7 * 24 * 60 * 60 * 1000;
-	var id_list_prev = su_ds.getValue("@dist_id_list");  
-	var id_list = su_ds.getValue("@id_list");
-	if ((reg_prev < (now - interval)) && ((id_list_prev == "") || 
-				(id_list_prev != id_list)))
-	{
-		su_ds.setValue("@dist_reg", "" + now);
-		
-		var params = "";
-		params = su_arp(params, "dist", su_host.dist);
-		params = su_arp(params, "regid", su_ds.getValue("@dist_regid")); 
-		params = su_arp(params, "idlist", id_list); 
-		params = su_arp(params, "preidlist", id_list_prev);
-		params = su_arp(params, "age", (now - installed));
-		params = su_arp(params, "visible", 
-					(su_ds.getValue("@toolbar-visible")) ? 1 : 0);
-		su_post_url_server_async(
-					"disttime.php",
-					params,
-					null,
-					su_dist_time_done,
-					null);
-	}
-
-	su_dist_time_timer = setTimeout(su_dist_time, interval - (su_random_delay * 1000));
-}
-
-function su_dist_time_done(res)
-{
-	try {
-		if (res.status != 200)
-			return;
-	} catch (e) { return; } 
-	
-	su_ds.setValue("@dist_id_list", su_ds.getValue("@id_list"));
-	
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-	
-	if (su_log_communication)
-		su_log("response disttime.php", s);
-
-	var context = new Object();
-	context.quiet = true;
-	su_process_commands(s, context);
-}
-
-//
-// After a certain period of idle stumble activity, we want to reset
-// the stumble category back to "All".  This takes care of preventing users from
-// unknowingly being stuck in a category.
-//
-function su_test_category_reset()
-{
-	var last_stumbled = su_ds.getIntValue("$last_stumble");
-	if(su_selected_category == "0")
-	{
-		// We are already in "all"
-		return;
-	}
-	
-	var last_stumbled = su_ds.getIntValue("$last_stumble");
-	var category_reset_timeout = su_ds.getValue("@category_reset_timeout");
-	var timenow = (new Date()).getTime();
-	
-	var diff = timenow - last_stumbled;
-	if(diff >= category_reset_timeout)
-	{
-		su_set_mode_all();
-	}
-}
-
-function su_process_quarter_hourly()
-{
-	su_test_category_reset();
-}
-
-function su_process_rarely(force_dyn_channels, timeout)
-{
-	if (su_process_rarely_timer)
-	{
-		// if the user changes, this clears the timeout set for the
-		// previously logged in user
-		clearTimeout(su_process_rarely_timer);
-	}
-	var old_timestamp = su_ds.getIntValue("$process_rarely_timestamp");
-	var last_stumbled = su_ds.getIntValue("$last_stumble");
-	
-	var timenow = (new Date()).getTime();
-	
-	var interval = 48 * 60 * 60 * 1000; // two days
-	var oneweek = 7 * 24 * 60 * 60 * 1000;
-	
-	su_process_slclicks(timeout);
-	
-	if (force_dyn_channels)
-	{
-		su_ds.setValue("$process_rarely_timestamp", timenow);
-		su_check_dyn_channels();
-	}
-	else if ( ((timenow - old_timestamp) > interval) && 
-				((timenow - last_stumbled) < (8 * oneweek)) )
-	{
-		su_ds.setValue("$process_rarely_timestamp", timenow);
-		// Routines here run every second day unless the user hasn't 
-		// stumbled for two months. -- JW
-		su_check_dyn_channels();
-	}
-	su_process_rarely_timer = setTimeout(su_process_rarely, interval - (su_random_delay * 1000), false, true);
-}
-
-function su_check_dyn_channels()
-{
-	var url = "http://cdn.stumble-upon.com/stumblethru.csv";
-	
-	if (su_test_stumblethru_update)
-		url = su_serverhttp + "stumblethru.csv";
-	
-	su_ds.setValue("#checked_dyn_channels", true);
-	su_post_url_async(
-				url,
-				null,
-				null,
-				su_check_dyn_channels_done,
-				null);
-}
-
-function su_check_dyn_channels_done(res)
-{
-	try {
-		if (res.status != 200)
-			return;
-	} catch (e) { return; } 
-	
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-
-	if (su_log_communication)
-		su_log("response stumblethru.csv", s);
-
-	if (su_ds.getValue("#installing_favicons"))
-		return;
-	
-	su_ds.setValue("#installing_favicons", true);
-	
-	// Parse response text
-	var items = s.split("\n");
-
-	var default_domain_list = su_ds.getValue("$default_thru_domain_list");
-	var default_domain_flags = new Object();
-	if (default_domain_list != "")
-	{
-		var domains = default_domain_list.split(" ");
-		for (i = 0; i < domains.length; i++)
-			default_domain_flags[domains[i]] = 1;
-	}
-	
-	var i;
-
-	var j;
-	var channel;
-	var good_channels = new Object(); 
-	var has_favicons = su_ds.getValue("$has_favicons");
-	
-	var checked_sanity = false;
-	
-	for (i = 0; i < items.length; i++)
-	{
-		if (items[i] == "")
-			continue;
-		
-		// do a sanity check on the first nonempty row
-		if (! checked_sanity)
-		{
-			checked_sanity = true;
-			if (! items[i].match(/^.*\..*,\d+,/))
-				return;
-		}
-		
-		var domain = items[i].split(",")[0];
-		var name = items[i].split(",")[2];
-		good_channels[domain] = 1;
-		
-		channel = su_ds.getThruDomainChannel(domain);
-		
-		var filename = su_get_channel_id(domain) + ".ico";
-		var url = "http://cdn.stumble-upon.com/images/stumblethru/" + filename;
-		if (su_test_stumblethru_update)
-			url = su_serverhttp + "images/stumblethru/" + filename;
-		if (channel)
-		{
-			channel.name = name;
-			su_ds.updateRow(channel);
-			if ((! has_favicons) || (! su_ds.isResourceInstalled("favicons", filename)))
-			{
-				su_ds.installResource(
-						url,
-						"favicons",
-						filename);
-			}
-		}
-		else
-		{
-			channel = new Object();
-			channel.domain = domain;
-			channel.name = name;
-			if (default_domain_flags[domain])
-				channel.show = 1;
-			su_ds.installResource(
-					url,
-					"favicons",
-					filename);
-			su_ds.insertRow("dyn_channel", channel);
-		}
-	}
-	
-	var channels = su_ds.getThruDomainChannels(false);
-	for (i = 0; i < channels.length; i++)
-	{
-		if (! good_channels[channels[i].domain])
-			su_ds.deleteRow(channels[i]);
-	}
-}
-
-function su_sync(context)
-{
-	if (su_get_time_s() < su_ds.getIntValue("$sync_retry_time_s"))
-		return;
-	
-	var params = "";
-	
-	params = su_append_sync_params(params);
-	
-	var context = new Object();
-	context.quiet = true;
-	context.from_sync = true;
-	
-	su_post_url_server_async(
-				"sync.php",
-				params,
-				15000,
-				su_sync_done,
-				context);
-}
-
-function su_append_sync_params(params)
-{
-	params = su_arp(params, "ycur_q", su_ds.getValue("$sync_cur_q"));
-	params = su_arp(params, "ycur_t", su_ds.getValue("$sync_cur_t"));
-	params = su_arp(params, "ycur_s", su_ds.getValue("$sync_cur_s"));
-	params = su_arp(params, "ypre_q", su_ds.getValue("$sync_pre_q"));
-	params = su_arp(params, "ypre_t", su_ds.getValue("$sync_pre_t"));
-	params = su_arp(params, "ypre_s", su_ds.getValue("$sync_pre_s"));
-	params = su_arp(params, "yr", su_ds.getValue("$sync_retry"));
-	params = su_arp(params, "yts", su_ds.getValue("$sync_time_s"));
-	return params;
-}
-
-
-//!!! Would be better to store in a command buffer.
-function su_sync_done(res)
-{
-	var context = res.detail;
-	
-//	if (context.stopped)
-//		return;
-	
-	try {
-		if (res.status != 200)
-			return;
-	} catch (e) { return; } 
-	
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-	
-	if (su_log_communication)
-		su_log("response sync.php", s);
-	
-	su_process_commands(s, context, true, 10); 
-}
-
-function su_process_commands(str, opt_context, opt_async, opt_async_interval)
-{
-	var commands = str.split("\n");
-	var i;
-	var interval;
-	var context = (opt_context) ?  opt_context : new Object();
-	
-	if (opt_async)
-	{
-		context.async_commands = commands;
-		context.async_interval = (opt_async_interval) ? opt_async_interval : 0;
-		setTimeout(su_process_commands2, 0, context);
-	}		
-	else
-	{
-		for (i = 0; i < commands.length; i++)
-		{
-			if (commands[i] == "")
-				continue;
-			su_process_command(commands[i], context);
-		}
-		setTimeout(function () { su_ds.flushPrefs(); }, 100);
-	}
-}
-
-function su_process_commands2(context)
-{
-	var command = context.async_commands.shift();
-	
-	if (command != "")
-		su_process_command(command, context);
-	
-	if (context.async_commands.length)
-	{
-		setTimeout(su_process_commands2, context.async_interval, context);
-	}
-	else
-	{
-		su_ds.flushPrefs();
-		su_refresh_pagemeta(false, 10);
-	}
-}
-
-function su_process_command(command_str, context, opt_command_parts)
-{
-	try {
-	
-	var val;
-	var el;
-	var detail;
-	
-	var command_parts;
-	if (opt_command_parts)
-		command_parts = opt_command_parts;
-	else
-		command_parts = command_str.split(" ");
-	
-	switch (command_parts[0])
-	{
-		case "SYNC":
-			if (stumbleid == 0)
-				break;
-			if (su_disable_sync)
-				return;
-			if (command_parts.length >= 2)
-				su_ds.setValue("$sync_time_s", parseInt(command_parts[1]));
-			if (command_parts.length >= 3)
-				su_ds.setValue("$sync_retry", parseInt(command_parts[2]));
-			if (command_parts.length >= 4)
-			{
-				var retry_interval_s = parseInt(command_parts[3]);
-				var retry_time_s = su_get_time_s() + retry_interval_s;
-				su_ds.setValue("$sync_retry_time_s", retry_time_s);
-				setTimeout(su_sync, retry_interval_s * 1000);
-			}
-			break;
-		case "NICK":
-			if (stumbleid == 0)
-				break;
-			if (su_prev_nick != command_parts[1])
-			{
-				su_prev_nick = command_parts[1];
-				su_ds.setValue("$nick", command_parts[1]);
-			}
-			break;
-		case "MESSAGE":
-			if (stumbleid == 0)
-				break;
-			su_set_inbox_status('2');
-			su_register_activity("message-notify");
-			break;
-		case "FRIENDS":
-			setTimeout(su_process_friends_command, 0, command_str);
-			break;
-		case "SEENCONF":
-			su_process_seenconf_command(command_parts[1], context);
-			break;
-		case "DONE":
-			context.done = true;
-			break;
-		case "KEY":
-			if (context.mode == 1)
-			{
-				context.prekey = command_parts[1];
-			}
-			else if (context.mode == 2)
-			{
-				context.prekey = command_parts[1];
-				context.prekey2 = command_parts[2];
-			}
-			break;
-		case "SQCS":
-			if (stumbleid == 0)
-				break;
-			if (su_ds.getValue("$undelivered_count") == 0)
-				clear_stumbles();
-			break;
-		case "SQCF":
-			if (stumbleid == 0)
-				break;
-			clear_stumbles();
-			break;
-		case "META":
-			try {
-				su_process_meta_command(command_parts, context);
-				if (su_log_sync)
-					su_logf(command_str);
-			} catch (e) { su_log_error("META COMMAND", e); }
-			break;
-		case "MEDR":
-			try {
-				su_process_medr_command(command_parts, context);
-				if (su_log_sync)
-					su_logf(command_str);
-			} catch (e) { su_log_error("MEDR COMMAND", e); }
-			break;
-		case "MEDT":
-			try {
-				su_process_medt_command(command_parts, context);
-				if (su_log_sync)
-					su_logf(command_str);
-			} catch (e) { su_log_error("MEDT COMMAND", e); }
-			break;
-		case "BKDA":
-			try {
-				su_process_bkda_command(command_parts, context);
-				if (su_log_sync)
-					su_logf(command_str);
-			} catch (e) { su_log_error("BKDA COMMAND", e); }
-			break;
-		case "BKDR":
-			try {
-				su_process_bkdr_command(command_parts, context);
-				if (su_log_sync)
-					su_logf(command_str);
-			} catch (e) { su_log_error("BKDR COMMAND", e); }
-			break;
-		case "BKDC":
-			try {
-				su_process_bkdc_command();
-				if (su_log_sync)
-					su_logf(command_str);
-			} catch (e) { su_log_error("BKDC COMMAND", e); }
-			break;
-		case "TOPICS":
-			try {
-				su_process_topics_command(command_parts);
-			} catch (e) { su_log_error("TOPICS COMMAND", e); }
-			break;
-		case "UPDATETOPICS":
-			try {
-				su_update_topics_command(command_parts);
-			} catch(e) { su_log_error("UPDATETOPICS COMMAND", e); }
-			break;
-		case "OK":
-			if (stumbleid == 0)
-				break;
-			if (command_parts.length >= 2)
-				su_ds.setCC(command_parts[1]);
-			break;
-		case "SACK":
-			if (stumbleid == 0)
-				break;
-			context.sack = true;
-			if (command_parts.length >= 2)
-				su_ds.setValue("$sync_time_s", command_parts[1]);
-			if (command_parts.length >= 3)
-				su_ds.setValue("$sync_cur_q", command_parts[2]);
-			if (command_parts.length >= 4)
-				su_ds.setValue("$sync_cur_t", command_parts[3]);
-			if (command_parts.length >= 5)
-				su_ds.setValue("$sync_cur_s", command_parts[4]);
-			if (command_parts.length >= 6)
-				su_ds.setValue("$sync_pre_q", command_parts[5]);
-			if (command_parts.length >= 7)
-				su_ds.setValue("$sync_pre_t", command_parts[6]);
-			if (command_parts.length >= 8)
-				su_ds.setValue("$sync_pre_s", command_parts[7]);
-			break;
-		case "ENABLEG":
-			su_enable_client_features(parseInt(command_parts[1]));
-			break;
-		case "DISABLEG":
-			su_disable_client_features(parseInt(command_parts[1]));
-			break;
-		case "ENABLEU":
-			su_enable_user_features(parseInt(command_parts[1]));
-			break;
-		case "DISABLEU":
-			su_disable_user_features(parseInt(command_parts[1]));
-			break;
-		case "ALLAVATARS":
-			if (stumbleid == 0)
-				break;
-			su_ds.setValue("$has_avatars", false);
-			break;
-		case "TAGGER":
-			if (stumbleid == 0)
-				break;
-			su_enable_user_features(0x2);
-			break;
-		case "FACEBOOK":
-			if (stumbleid == 0)
-				break;
-			switch (command_parts[1])
-			{
-				case "1":
-					su_ds.setValue("$facebook_added", true);
-					su_ds.setValue("$facebook_linked", false);
-					break;
-				case "2":
-					su_ds.setValue("$facebook_added", true);
-					su_ds.setValue("$facebook_linked", true);
-					break;
-			}
-			break;
-		case "UPGRADE":
-			if (stumbleid == 0)
-				break;
-			su_set_visible("su_upgrade", true);
-			break;
-		case "FIRSTFRIEND": 
-			if (stumbleid == 0)
-				break;
-			su_ds.setValue("$firstfriends", command_str);
-			break;
-//		case "SPONSOR":
-//			su_ds.setValue("$sponsor", true);
-//			break;
-//		case "NOSPONSOR":
-//			su_ds.setValue("$sponsor", false);
-//			break;
-		case "REGID":
-			su_ds.setValue("@dist_regid", command_parts[1]);
-			break;
-		case "SETU":
-			if (stumbleid == 0)
-				break;
-			su_process_set_pref_command("$" + command_parts[1], command_parts[2]);
-			break;
-		case "SETG":
-			su_process_set_pref_command("@" + command_parts[1], command_parts[2]);
-			break;
-		case "STUMBLENOW":
-			su_process_stumble_now_command(command_str);
-			break;
-		case "SUPR_TWITTER_LINK":
-			if(stumbleid == 0)
-				break;
-			su_ds.setValue("$twitter_supr_linked", (command_parts[1] == "1") ? true : false);
-			su_refresh_referral_menu(10);
-			break;
-		case "SUPR_FACEBOOK_LINK":
-			if(stumbleid == 0)
-				break;
-			su_ds.setValue("$facebook_supr_linked", (command_parts[1] == "1") ? true : false);
-			su_refresh_referral_menu(11);
-			break;
-		case "SFC":
-			su_process_sync_favorites_count_command(parseInt(command_parts[1]));
-			break;
-		case "SSC":
-			su_process_sync_stumble_count_command(parseInt(command_parts[1]));
-			break;
-		case "ERROR":
-			su_process_error_command(command_parts, context);
-			break;
-	}
-	
-	} catch (e) { su_log_error("PROCESS " + command_parts[0], e, command_str); }  
-}
-
-function su_process_stumble_now_command(command_str)
-{
-	var parts = command_str.split(" ");
-	
-	if (parts.length < 2)
-		return;
-	
-	// Treat it just like we treat the through.php command
-	var args = parts[1].split("&");
-	su_process_stumble_now(args);
-}
-
-function su_process_sync_favorites_count_command(count)
-{
-	if(su_ds.getValue("@enable_server_counts") && (count != su_ds.getValue("$thumbup_count")))
-	{
-		su_ds.setValue("$thumbup_count", count);
-		su_thumbup_count_changed();
-	}
-}
-
-function su_process_sync_stumble_count_command(count)
-{
-	if(su_ds.getValue("@enable_server_counts") && (count != su_ds.getValue("$stumble_count")))
-	{
-		su_ds.setValue("$stumble_count", count);
-		su_stumble_count_changed();
-	}
-}
-
-function su_thumbup_count_changed()
-{
-	var count = su_ds.getValue("$thumbup_count");
-	if( (count >= 1) && !su_ds.getValue("$show_info") && !su_ds.getValue("$show_info_user_changed") )
-	{
-		// Show the info button after the first thumbup.
-		su_ds.setValue("$show_info", true);
-		su_set_visible("su_website_info", true);
-	}
-	
-	if( (count >= 3) && !su_ds.getValue("$show_home") && !su_ds.getValue("$show_home_user_changed") )
-	{
-		// Show the favorites button after the third thumbup.
-		su_ds.setValue("$show_home", true);
-		su_set_visible("su_profile", true);
-	}
-}
-
-function su_stumble_count_changed()
-{
-	var count = su_ds.getValue("$stumble_count");
-	if( (count > 99) && !su_ds.getValue("$show_friends") && !su_ds.getValue("$show_friends_user_changed") )
-	{
-		// After 100 stumbles, show the "Stumblers" button.
-		su_ds.setValue("$show_friends", true);
-		su_set_visible("su_friends", true);
-	}
-}
-
-function su_process_seenconf_command(ids, context)
-{
-	if(context && context.oldStumbleReport)
-	{
-	    su_process_old_seenconf_command(ids);
-		return;
-	}
-	
-	// It's not an old format stumble request so we expect this to just be a single
-	// publicid.
-	context.confirmed = ids;
-}
-
-function su_process_old_seenconf_command(conf_urlids_str)
-{
-	var conf_urlids;
-	var seen_urlids;
-	var stumbletimes;
-	var stumbletypes;
-	var stumblereferrals;
-	var str;
-	var i;
-	var j;
-	
-	if (conf_urlids_str == "")
-		return;
-	
-	if (su_ds.getValue("$stumblestats") == conf_urlids_str ||
-			conf_urlids_str == "[clear]")
-	{
-		seen_urlids = [];
-		stumbletimes = [];
-		stumbletypes = [];
-		stumblereferrals = [];
-	}
-	else
-	{
-		str = su_ds.getValue("$stumblestats");
-		seen_urlids = str.split(".");
-		str = su_ds.getValue("$stumbletimes");
-		stumbletimes = str.split(".");
-		str = su_ds.getValue("$stumbletypes");
-		stumbletypes = str.split(".");
-		str = su_ds.getValue("$stumblereferrals");
-		stumblereferrals = str.split(".");
-		
-		conf_urlids = conf_urlids_str.split(".");
-		
-		for (i = 0; i < conf_urlids.length; i++)
-		{
-			for (j = 0; j < seen_urlids.length; j++)
-			{
-				if (conf_urlids[i] == seen_urlids[j])
-				{
-					seen_urlids.splice(j, 1);
-					stumbletimes.splice(j, 1);
-					stumbletypes.splice(j, 1);
-					stumblereferrals.splice(j, 1);
-					break;
-				}
-			}
-		}
-	}
-
-	su_ds.setValue("$stumblestats", seen_urlids.join("."));
-	su_ds.setValue("$stumbletimes", stumbletimes.join("."));
-	su_ds.setValue("$stumbletypes", stumbletypes.join("."));
-	su_ds.setValue("$stumblereferrals", stumblereferrals.join("."));
-	su_ds.setValue("$last_uploaded", (new Date()).getTime());
-	su_ds.flushPrefs();
-}
-
-function su_enqueue_command(priority, command)
-{
-	if (! su_host.places)
-		return;
-	
-	var db = su_ds.getDatabase();
-	db.a("INSERT INTO command_queue (priority, command) VALUES (");
-	db.av(priority);
-	db.als(command);
-	db.query();
-}
-
-function su_count_enqueued_commands(priority)
-{
-	if (! su_host.places)
-		return;
-	
-	var db = su_ds.getDatabase();
-	var sql = "SELECT count(*) as count FROM command_queue WHERE priority=" + db.v(priority);
-	var result = db.query(sql);
-	var row;
-	if (row = result.shift())
-		return row.count;
-	else
-		return 0;
-}
-
-function su_process_topics_command(parts)
-{
-	if (parts.length < 2)
-		return;
-	
-	parts.shift();
-	
-	su_process_topic_list(parts.join(" "));
-}
-
-function su_update_topics_command(parts)
-{
-	if (parts.length < 2)
-		return;
-	
-	parts.shift();
-	
-	su_update_topic_list(parts.join(" "));
-}
-
-function su_process_error_command(parts, context)
-{
-	if (! context)
-	{
-		su_log("warning: missing context for error");
-		return;
-	}
-	
-	context.error = true;
-	
-	if (context.quiet)
-		return;
-	
-	su_handle_error(parts[1]);
-}
-
-function su_process_bkda_command(parts, context)
-{
-	if (! su_host.places)
-		return;
-	
-	if (parts.length < 3)
-		return;
-	
-	var spec = new Object();
-	spec.domain = parts[1];
-	spec.timestamp = parseInt(parts[2]);
-
-	var db = su_ds.getDatabase();
-	var row;
-	var result;
-	var sql;
-	
-	if (context.from_sync)
-	{
-		sql = "SELECT modified FROM blocked_domain WHERE domain=" + db.q(spec.domain);
-		result = db.query(sql);
-		if (row = result.shift())
-		{
-			// Ignore obsolete sync commands
-			var offset = spec.timestamp - row.modified;
-			if (offset < (- su_ds.getValue("@server_time_float_s")))
-				return;
-		}
-	}
-	
-	db.a("INSERT INTO blocked_domain (domain, modified, active) VALUES (");
-	db.as(spec.domain);
-	db.av(spec.timestamp);
-	db.alv(1);
-	db.query();
-}
-
-function su_process_bkdr_command(parts, context)
-{
-	if (! su_host.places)
-		return;
-	
-	if (parts.length < 3)
-		return;
-	
-	var spec = new Object();
-	spec.domain = parts[1];
-	spec.timestamp = parseInt(parts[2]);
-	
-	var db = su_ds.getDatabase();
-	var row;
-	var result;
-	var sql;
-	
-	if (context.from_sync)
-	{
-		sql = "SELECT modified FROM blocked_domain WHERE domain=" + db.q(spec.domain);
-		result = db.query(sql);
-		if (row = result.shift())
-		{
-			// Ignore obsolete sync commands
-			var offset = spec.timestamp - row.modified;
-			if (offset < (- su_ds.getValue("@server_time_float_s")))
-				return;
-		}
-	}
-	
-	db.a("INSERT INTO blocked_domain (domain, modified, active) VALUES (");
-	db.as(spec.domain);
-	db.av(spec.timestamp);
-	db.alv(0);
-	db.query();
-}
-
-function su_process_bkdc_command()
-{
-	if (! su_host.places)
-		return;
-	
-	var db = su_ds.getDatabase();
-	var sql;
-	
-	sql = "UPDATE blocked_domain SET active=0";
-	db.query(sql);
-}
-
-function su_process_medt_command(parts, context)
-{
-	if (! su_host.places)
-		return;
-	
-	var field_names = new Array(
-		"urlid",                  //  1
-		"tagid",                  //  2
-		"timestamp");             //  3
-
-	parts.shift();
-	
-	var spec = new Object();
-	var i;
-	for (i = 0; i < field_names.length; i++)
-	{
-		if (parts.length > 0)
-			spec[field_names[i]] = parts.shift();
-		else
-			spec[field_names[i]] = null;
-		
-		if (spec[field_names[i]] == "")
-			spec[field_names[i]] = null;
-	}
-	
-	spec.tagid = parseInt(spec.tagid);
-	
-	var result;
-	var row;
-	var result2;
-	var row2;
-	var id;
-	var ids;
-	var nsiuri;
-	var tags = new Array();
-	var db = su_ds.getDatabase();
-	var sql;
-	
-	if (context.from_sync)
-	{
-		sql = "SELECT tag_applied FROM url_tag WHERE urlid=" + db.q(spec.urlid) + " AND tagid=" + db.v(spec.tagid);
-		result = db.query(sql);
-		if (row = result.shift())
-		{
-			// Ignore obsolete sync commands
-			var offset = spec.timestamp - row.tag_applied;
-			if (offset < (- su_ds.getValue("@server_time_float_s")))
-				return;
-		}
-	}
-	
-	// if this tag has been applied to another url, keep the tag record
-	sql = "SELECT urlid FROM url_tag WHERE tagid=" + db.v(spec.tagid) + " AND urlid!=" + db.q(spec.urlid) + " LIMIT 1";
-	result = db.query(sql);
-	var keep_tag = false;
-	if (result.length)
-		keep_tag = true;
-	
-	// if this url has been rated, keep the url record  
-	sql = "SELECT rating FROM url WHERE urlid=" + db.q(spec.urlid) + " AND rating!=-1";
-	result = db.query(sql);
-	var keep_url = false;
-	if (result.length)
-		keep_url = true;
-	
-	if (! keep_url)
-	{
-		// if this url has a non-autotag other than the tag to be nuked, keep the url record  
-		sql = "SELECT tagid FROM url_tag WHERE urlid=" + db.q(spec.urlid) + " AND tagid!=" + db.v(spec.tagid) + " AND tagid>1000 AND tagid!=" + db.v(su_video_tagid) + " LIMIT 1";
-		result = db.query(sql);
-		if (result.length)
-			keep_url = true;
-	}
-	
-	if (su_ds.getValue("$sync_bm_meta"))
-	{
-		var ts = su_ds.getTaggingService();
-		
-		if (keep_url)
-		{
-			sql = "SELECT tag FROM tag_map WHERE tagid=" + db.v(spec.tagid);
-			result = db.query(sql);
-			while (row = result.shift())
-				tags.push(row.tag);
-		}
-		else
-		{
-			sql = "SELECT tag FROM url_tag NATURAL JOIN tag_map WHERE url_tag.urlid=" + db.q(spec.urlid);
-			result = db.query(sql);
-			while (row = result.shift())
-				tags.push(row.tag);
-			tags.push("SU"); // for good measure
-			
-			sql = "SELECT catid FROM url WHERE urlid=" + db.q(spec.urlid);
-			result = db.query(sql);
-			if (row = result.shift())
-			{
-				if (su_ds.getBMTagFromCatid(row.catid))
-					tags.push(su_ds.getBMTagFromCatid(row.catid));
-			}
-		}
-		
-		if (tags.length)
-		{
-			sql = "SELECT url FROM url_tag NATURAL JOIN url_map WHERE url_tag.urlid=" + db.q(spec.urlid) + " AND url_tag.tagid=" + db.v(spec.tagid);
-			result = db.query(sql);
-			for (j = 0; row = result[j]; j++)
-			{
-				nsiuri = su_get_nsiuri(row.url);
-				
-				ts.untagURI(nsiuri, tags);
-				
-				if (! keep_url)
-					su_remove_managed_bookmark(nsiuri);
-			}
-		}
-	}
-	
-	if (! keep_url)
-	{
-		sql = "DELETE FROM url_map WHERE urlid=" + db.q(spec.urlid);
-		db.query(sql);
-		sql = "DELETE FROM url WHERE urlid=" + db.q(spec.urlid);
-		db.query(sql);
-	}
-	
-	if (! keep_tag)
-	{
-		sql = "DELETE FROM tag_map WHERE tagid=" + db.v(spec.tagid);
-		db.query(sql);
-	}
-	
-	sql = "DELETE FROM url_tag WHERE urlid=" + db.q(spec.urlid) + " AND tagid=" + db.v(spec.tagid);
-	db.query(sql);
-}
-
-function su_process_medr_command(parts, context)
-{
-	if (! su_host.places)
-		return;
-
-	var field_names = new Array(
-		"urlid",                  //  1
-		"timestamp");             //  2
-
-	parts.shift();
-	
-	var spec = new Object();
-	var i;
-	var j;
-	for (i = 0; i < field_names.length; i++)
-	{
-		if (parts.length > 0)
-			spec[field_names[i]] = parts.shift();
-		else
-			spec[field_names[i]] = null;
-		
-		if (spec[field_names[i]] == "")
-			spec[field_names[i]] = null;
-	}
-	
-	var result;
-	var row;
-	var db = su_ds.getDatabase();
-	var sql;
-	
-	if (context.from_sync)
-	{
-		sql = "SELECT rating_applied FROM url WHERE urlid=" + db.q(spec.urlid);
-		result = db.query(sql);
-		if (row = result.shift())
-		{
-			// Ignore obsolete sync commands
-			var offset = spec.timestamp - row.rating_applied;
-			if (offset < (- su_ds.getValue("@server_time_float_s")))
-				return;
-		}
-	}
-	
-	if (context.ref_url)
-		su_delete_rating(context.ref_url);
-	
-	var usertags = su_get_db_tags(spec.urlid, false, true, true);
-	
-	if (su_ds.getValue("$sync_bm_meta"))
-		su_remove_thumbup_bookmark(spec.urlid, null, usertags);
-	
-	if (usertags)
-	{
-		sql = "UPDATE url SET rating=-1 WHERE urlid=" + db.q(spec.urlid);
-		db.query(sql);
-	}
-	else
-	{
-		sql = "DELETE FROM url WHERE urlid=" + db.q(spec.urlid);
-		db.query(sql);
-		sql = "DELETE FROM url_map WHERE urlid=" + db.q(spec.urlid);
-		db.query(sql);
-	}
-}
-
-function su_process_meta_command(parts, context)
-{
-	if (! su_host.places)
-		return;
-	
-//	if ((context.mode == 1) || (context.mode == 2))
-//		context.count++;
-	
-	var field_names = new Array(
-		"urlid",                  //  1
-		"ref_url",                //  2
-		"title",                  //  3
-		"catid",                  //  4
-		"comment_level",          //  5
-		"score",                  //  6
-		"rating",                 //  7
-		"rating_applied",         //  8
-		"tagid",                  //  9
-		"tag",                    // 10
-		"tag_applied");           // 11
-	
-	parts.shift();
-	
-	var spec = new Object();
-	var i;
-	for (i = 0; i < field_names.length; i++)
-	{
-		if (parts.length > 0)
-			spec[field_names[i]] = parts.shift();
-		else
-			spec[field_names[i]] = null;
-		
-		if (spec[field_names[i]] == "")
-			spec[field_names[i]] = null;
-	}
-	
-	if (context.ref_url)
-		spec.ref_url = context.ref_url;
-	
-	if (context.title)
-	{
-		spec.title = context.title;
-	}
-	else if (spec.title)
-	{
-		try {
-			spec.title = decodeURIComponent(spec.title);
-		} catch (e) { su_log_error("DECODE TITLE", e); }
-	}
-	
-	if (! spec.title)
-		spec.title = spec.ref_url;
-	
-	if (! spec.title)
-	{
-		su_log("missing title");
-		return;
-	}
-	
-	var db = su_ds.getDatabase();
-	var sql;
-	var result;
-	var row;
-	var tags = new Array();
-	var old_catid = null;
-	
-	sql = "SELECT catid FROM url WHERE urlid=" + db.q(spec.urlid);
-	result = db.query(sql);
-	
-	if (row = result.shift())
-		old_catid = row.catid;
-	
-	var local_catid = su_ds.lookup("url:local_catid", spec.ref_url);
-	
-	if (local_catid)
-		spec.catid = local_catid;
-	else if (spec.catid)
-		spec.catid = parseInt(spec.catid);
-	else if (old_catid)
-		spec.catid = old_catid;
-	else
-		spec.catid = 0;
-
-	if ((typeof context.rating) != "undefined")
-		spec.rating = context.rating;
-	
-	var tag;
-	if (spec.tag)
-	{
-		spec.tagid = parseInt(spec.tagid);
-		spec.tag_applied = parseInt(spec.tag_applied);
-		if (! spec.tagid)
-		{
-			su_log("missing tagid");
-			return;
-		}
-		
-		if (! spec.tag_applied)
-		{
-			su_log("missing tag_applied");
-			return;
-		}
-		
-		if (spec.tagid == su_video_tagid)
-			tag = "video";
-		else if (context.ref_tag)
-			tag = su_ds.getBMTagFromTag(context.ref_tag);
-		else if (spec.tagid < 1000)
-			tag = su_ds.getBMTagFromCatid(spec.tagid);
-		else
-			tag = su_ds.getBMTagFromTag(spec.tag);
-		
-		if (tag)
-			tags.push(tag);
-		
-		sql = "SELECT rating,rating_applied FROM url WHERE urlid=" + db.q(spec.urlid);
-		result = db.query(sql);
-		if (row = result.shift())
-		{
-			spec.rating = row.rating;
-			spec.rating_applied = row.rating_applied;
-			if ((spec.rating == 1) && (spec.tagid == su_video_tagid))
-				context.has_video_favs = true;
-		}
-		else
-		{
-			spec.rating = -1;
-			spec.rating_applied = 0;
-		}
-		
-	}
-	
-	if (spec.rating == null)
-	{
-		sql = "SELECT rating FROM url WHERE urlid=" + db.q(spec.urlid);
-		result = db.query(sql);
-		if (row = result.shift())
-			spec.rating = row.rating;
-		else
-			spec.rating = -1;
-	}
-	else
-	{
-		spec.rating = parseInt(spec.rating);
-	}
-	
-	if ((spec.rating == -1) && (! spec.tagid))
-		return; // equivalent to medr plus autotag info
-	
-	var bms = su_ds.getBookmarksService();
-	var timestamp_us;
-	var itemid;
-	var i;
-	var ts;
-	var nsiuri;
-	var urls;
-	var url;
-	var folderid;	
-
-/*	
-	if ((context.mode == 1) || (context.mode == 2))
-	{
-		// Mode 1 is the favs batch download
-		// Mode 2 is the custom tags batch download
-		
-		nsiuri = su_get_nsiuri(spec.ref_url);
-	
-		// Only create a bookmark if they don't have this url bookmarked
-		// already.  If they already have it somewhere, we'll just apply
-		// tags.
-		
-		if (! su_is_bookmarked(nsiuri))
-		{
-			//!!! Checking folderid every time is a bit expensive but
-			//    probably necessary since we allow interaction during
-			//    download.
-			
-			folderid = su_get_supertopic_folderid(spec.catid, true);
-			
-			if (folderid)
-			{
-				itemid = bms.insertBookmark(
-						folderid,
-						nsiuri,
-						bms.DEFAULT_INDEX,
-						spec.title);
-		
-				timestamp_us = spec.rating_applied * 1000000;
-				bms.setItemDateAdded(itemid, timestamp_us);
-				bms.setItemLastModified(itemid, timestamp_us);
-			}
-		}
-		
-		
-		// build the tag set
-		
-		var skip = (su_is_adult_category(spec.catid) && (! su_ds.getValue("$sync_bm_adult")));
-		
-		tag = su_ds.getBMTagFromCatid(spec.catid); 
-		if (tag && (! skip))
-			tags.push(tag);
-		
-		if ((spec.rating == 1) && (! skip))
-			tags.push("SU");
-		
-		// apply tags
-		
-		if (tags.length)
-		{
-			ts = su_ds.getTaggingService();
-			try {
-				ts.tagURI(nsiuri, tags);
-			} catch (e) { su_log_error("DOWNLOAD TAG", e); }
-		}
-	}
-*/
-	
-	if (su_ds.getValue("$sync_bm_meta"))
-	{
-		if (context.from_sync)
-		{
-			//!!! need to handle tag.modified when from_sync
-			sql = "SELECT rating,rating_applied FROM url WHERE urlid=" + db.q(spec.urlid);
-			result = db.query(sql);
-			if (row = result.shift())
-			{
-				var offset = spec.rating_applied - row.rating_applied;
-				if (offset < (- su_ds.getValue("@server_time_float_s")))
-				{
-					if (spec.tagid)
-					{
-						spec.rating = row.rating;
-						spec.rating_applied = row.rating_applied;
-					}
-					else
-					{
-						return;
-					}
-				}
-			}
-		}
-	}
-		
-	db.a("INSERT OR REPLACE INTO url (urlid,title,catid,rating,rating_applied,comment_level,score) VALUES (");
-	db.as(spec.urlid);
-	db.as(spec.title);
-	db.av(spec.catid);
-	db.av(spec.rating);
-	db.av(spec.rating_applied);
-	db.av(spec.comment_level);
-	db.alv(spec.score);
-	db.query();
-	
-	db.a("INSERT OR REPLACE INTO url_map (url,urlid) VALUES (");
-	db.as(spec.ref_url);
-	db.als(spec.urlid);
-	db.query();
-
-	if (spec.tagid && spec.tag && spec.tag_applied)
-	{
-		db.a("INSERT OR REPLACE INTO tag_map (tag,tagid) VALUES (");
-		db.as(spec.tag);
-		db.alv(spec.tagid);
-		db.query();
-		
-		db.a("INSERT OR REPLACE INTO url_tag (urlid,tagid,tag_applied) VALUES (");
-		db.as(spec.urlid);
-		db.av(spec.tagid);
-		db.alv(spec.tag_applied);
-		db.query();
-	}
-	
-	if ((context.mode == 1) || (context.mode == 2)
-			|| (! su_ds.getValue("$sync_bm_meta")))
-		return;
-	
-	if (old_catid && (spec.catid != old_catid))
-		su_remove_autotag(spec.urlid, old_catid);
-	
-	if ((spec.rating >= 1)
-			&& ((! su_is_adult_category(spec.catid))
-			|| su_ds.getValue("$sync_bm_adult")))
-	{
-		su_add_thumbup_bookmark(spec.urlid, spec.title, spec.catid);
-	}
-	else
-	{
-		var usertags = su_get_db_tags(spec.urlid, false, true, true);
-		su_remove_thumbup_bookmark(spec.urlid, spec.title, usertags);
-	}
-}
-
-function su_remove_autotag(urlid, catid)
-{
-	if (! su_host.places)
-		return;
-
-	var db = su_ds.getDatabase();
-	var tag = su_ds.getBMTagFromCatid(catid);
-	var tags = new Array();
-	tags.push(tag);
-	var ts = su_ds.getTaggingService();
-	var row;
-	var sql = "SELECT url FROM url_map WHERE urlid=" + db.q(urlid);
-	var result = db.query(sql);
-	while (row = result.shift())
-	{
-		nsiuri = su_get_nsiuri(row.url);
-		ts.untagURI(nsiuri, tags);
-	}
-}
-
-function su_change_local_catid(url, new_catid)
-{
-	if (! su_host.places)
-		return;
-	
-	var urlid = su_ds.getUrlid(url);
-	if (! urlid)
-	{
-		su_ds.define("url:local_catid", url, new_catid);
-		return;
-	}
-	
-	var db = su_ds.getDatabase();
-	var row;
-	var sql;
-	var result;
-	var old_catid;
-	sql = "SELECT catid FROM url WHERE urlid=" + db.q(urlid);
-	result = db.query(sql);
-	if (row = result.shift())
-		old_catid = row.catid;
-	else
-		return;
-	
-	if (new_catid == old_catid)
-		return;
-	
-	sql = "UPDATE url SET catid=" + db.v(new_catid) + " WHERE urlid=" + db.q(urlid);
-	db.query(sql);
-	
-	if (! su_ds.getValue("$sync_bm_meta"))
-		return;
-	
-	var old_tag = su_ds.getBMTagFromCatid(old_catid);
-	var old_tags = new Array();
-	old_tags.push(old_tag);
-	var new_tag = su_ds.getBMTagFromCatid(new_catid);
-	var new_tags = new Array();
-	new_tags.push(new_tag);
-	var ts = su_ds.getTaggingService();
-	var adult = su_is_adult_category(new_catid);
-	
-	sql = "SELECT url FROM url_map WHERE urlid=" + db.q(urlid);
-	result = db.query(sql);
-	while (row = result.shift())
-	{
-		nsiuri = su_get_nsiuri(row.url);
-		ts.untagURI(nsiuri, old_tags);
-		if ((! adult) || (adult && su_ds.getValue("$sync_bm_adult")))
-			ts.tagURI(nsiuri, new_tags);
-	}
-}
-
-function su_get_db_tags(urlid, include_autotags, include_usertags, include_adult_tags)
-{
-	var tags = new Array();
-	var db = su_ds.getDatabase();
-	var sql;
-	var result;
-	var row;
-	
-	if (include_autotags && (! include_usertags))
-		sql = "SELECT tag,tag_map.tagid FROM url_tag NATURAL JOIN tag_map WHERE url_tag.urlid=" + db.q(urlid) + " AND (url_tag.tagid<1000 OR url_tag.tagid=" + db.v(su_video_tagid) + ")";
-	else if ((! include_autotags) && include_usertags)
-		sql = "SELECT tag,tag_map.tagid FROM url_tag NATURAL JOIN tag_map WHERE url_tag.urlid=" + db.q(urlid) + " AND url_tag.tagid>=1000 AND url_tag.tagid!=" + db.v(su_video_tagid);
-	else
-		sql = "SELECT tag,tag_map.tagid FROM url_tag NATURAL JOIN tag_map WHERE url_tag.urlid=" + db.q(urlid);
-	
-	
-	result = db.query(sql);
-	while (row = result.shift())
-	{
-		if ((! include_adult_tags) && su_is_adult_category(row.tagid))
-			continue;
-		
-		tags.push(su_ds.getBMTagFromTag(row.tag));
-	}
-	
-	if (include_autotags)
-	{
-		tags.push("SU");
-		sql = "SELECT catid FROM url WHERE urlid=" + db.q(urlid);
-		result = db.query(sql);
-		if (row = result.shift())
-		{
-			if ((include_adult_tags || (! su_is_adult_category(row.catid)))
-					&& su_ds.getBMTagFromCatid(row.catid))
-				tags.push(su_ds.getBMTagFromCatid(row.catid));
-		}
-	}
-	
-	return (tags.length) ? tags : null;
-}
-
-function su_add_thumbup_bookmark(urlid, title, catid)
-{
-	var db = su_ds.getDatabase();
-	var bms = su_ds.getBookmarksService();
-	var ts = su_ds.getTaggingService();
-	var tags = su_get_db_tags(urlid, true, true, su_ds.getValue("$sync_bm_adult"));
-	var sql;
-	var result;
-	var row;
-	var result2;
-	var row2;
-	var folderid;
-	var bookmarked;
-	var itemid;
-	var ids;
-	var id;
-	
-	if (! tags)
-		tags = new Array();
-	
-	// get all urls mapped to this urlid
-	sql = "SELECT url FROM url_map WHERE urlid=" + db.q(urlid);
-	result = db.query(sql);
-	while (row = result.shift())
-	{
-		nsiuri = su_get_nsiuri(row.url);
-		
-		ids = bms.getBookmarkIdsForURI(nsiuri, []);
-		
-		bookmarked = false;
-		
-		while (id = ids.shift())
-		{
-			folderid = bms.getFolderIdForItem(id);
-			
-			// if the bookmark is in one of our managed bookmark folders,
-			// remove it
-			sql = "SELECT label FROM supertopic WHERE bm_folderid=" + db.v(folderid);
-			result2 = db.query(sql);
-			if (row2 = result2.shift())
-			{
-				if (row2.label == su_tagged_folder_name)
-				{
-					bms.removeItem(id);
-					su_check_managed_folder_emptiness(folderid);
-				}
-				else
-					bookmarked = true;
-			}
-		}
-		
-		if (! bookmarked)
-		{
-			folderid = su_get_supertopic_folderid(catid, true);
-			if(folderid)
-			{
-				itemid = bms.insertBookmark(
-						folderid,
-						nsiuri,
-						bms.DEFAULT_INDEX,
-						title);
-			}
-		}
-		
-		ts.tagURI(nsiuri, tags);
-	}
-}
-
-function su_remove_thumbup_bookmark(urlid, title, usertags)
-{
-	var db = su_ds.getDatabase();
-	var bms = su_ds.getBookmarksService();
-	var ts = su_ds.getTaggingService();
-	var autotags = su_get_db_tags(urlid, true, false, true);
-	var sql;
-	var result;
-	var row;
-	
-	// get all urls mapped to this urlid
-	sql = "SELECT url FROM url_map WHERE urlid=" + db.q(urlid);
-	result = db.query(sql);
-	while (row = result.shift())
-	{
-		nsiuri = su_get_nsiuri(row.url);
-		
-		var removed_spec = su_remove_managed_bookmark(nsiuri, autotags);
-		
-		// If the url still has tags and isn't bookmarked
-		// elsewhere, add it to the Unfiled/Tagged folder.
-		
-		if (usertags && (! su_is_bookmarked(nsiuri)))
-		{
-			var timestamp_us;
-			if (removed_spec)
-			{
-				title = removed_spec.title;
-				timestamp_us = removed_spec.timestamp_us;
-			}
-			else
-			{
-				title = (title) ? title : row.url;
-				timestamp_us = su_get_time_s() + 1000000;
-			}
-			// get all bookmark items mapped to the urlid
-		
-			folderid = su_get_supertopic_folderid(-1, true);
-			if(folderid)
-			{
-				itemid = bms.insertBookmark(
-						folderid,
-						nsiuri,
-						bms.DEFAULT_INDEX,
-						title);
-				
-				bms.setItemDateAdded(itemid, timestamp_us);
-				bms.setItemLastModified(itemid, timestamp_us);
-			}
-		}
-		
-		if (usertags)
-			ts.tagURI(nsiuri, usertags);
-		else if (autotags)
-			ts.untagURI(nsiuri, autotags);
-	}
-}
-
-function su_remove_managed_bookmark(nsiuri, autotags)
-{
-	var db = su_ds.getDatabase();
-	var bms = su_ds.getBookmarksService();
-	var hs = su_ds.getHistoryService();
-	var ts = su_ds.getTaggingService();
-	var folderid;
-	var sql;
-	var result;
-	var query;
-	var ids;
-	var id;
-	var removed_spec = null;
-	
-	ts.untagURI(nsiuri, ["SU"]);
-	if (autotags)
-		ts.untagURI(nsiuri, autotags);
-	
-	ids = bms.getBookmarkIdsForURI(nsiuri, []);
-	
-	while (id = ids.shift())
-	{
-		folderid = bms.getFolderIdForItem(id);
-		// if the bookmark is in one of our managed bookmark folders,
-		// remove it
-		sql = "SELECT label FROM supertopic WHERE bm_folderid=" + db.v(folderid);
-		result = db.query(sql);
-		if (result.length)
-		{
-			removed_spec = new Object();			
-			removed_spec.title = bms.getItemTitle(id);
-			removed_spec.timestamp_us = bms.getItemLastModified(id);
-			bms.removeItem(id);
-			
-			su_check_managed_folder_emptiness(folderid);
-		}
-	}
-	return removed_spec;
-}
-
-function su_check_managed_folder_emptiness(folderid)
-{
-	var hs = su_ds.getHistoryService();
-	var query;
-	var result;
-	var bms;
-	var db;
-	var sql;
-	// if the managed folder is now empty, remove it.
-	query = hs.getNewQuery();
-	query.setFolders([folderid], 1);
-	result = hs.executeQuery(query, hs.getNewQueryOptions());
-	result.root.containerOpen = true;
-	if (result.root.childCount == 0)
-	{
-		bms = su_ds.getBookmarksService();
-		bms.removeItem(folderid);
-		db = su_ds.getDatabase();
-		sql = "DELETE FROM supertopic WHERE bm_folderid=" + db.v(folderid);
-		db.query(sql);
-	}
-}
-
-function su_get_rating(url, stumblevideo, opt_url_detail)
-{
-	if (opt_url_detail)
-		return opt_url_detail.rating;
-	
-	if (su_host.places && ! stumblevideo)
-	{
-		var db = su_ds.getDatabase();
-		var result;
-		var row;
-		var sql;
-		sql = "SELECT rating FROM url_map NATURAL JOIN url WHERE url=" + db.q(url);
-		result = db.query(sql);
-		if (row = result.shift())
-		{
-			return (row.rating == -1) ? null : row.rating;
-		}
-		else if ((typeof su_ratings[url]) != "undefined")
-		{
-			// We're generating too many hits.
-			if (! su_ds.lookup("url:rating_getmeta_flag", url))
-			{
-				su_ds.define("url:rating_getmeta_flag", url, 1);
-				su_rate_getmeta(url, false);
-			}
-			
-			return su_ratings[url];
-		}
-		else
-		{
-			return null;
-		}
-	}
-	else
-	{
-		if ((typeof su_ratings[url]) == "undefined")
-			return null;
-		else
-			return su_ratings[url];
-	}
-}
-
-function su_get_tag_list(url)
-{
-	var retval = null;
-	if (((typeof (su_tag_lists_by_url[url])) != "undefined") &&
-			(su_tag_lists_by_url[url] != ""))
-	{
-		retval = su_tag_lists_by_url[url];
-	}
-	else if (su_host.places)
-	{
-		var db = su_ds.getDatabase();
-		var result;
-		var row;
-		var sql;
-		var tags = new Array();
-		sql = "SELECT tag FROM url_map NATURAL JOIN url_tag NATURAL JOIN tag_map WHERE url=" + db.q(url) + " AND url_tag.tagid>1000 AND url_tag.tagid!=" + db.v(su_video_tagid);
-		result = db.query(sql);
-		if (result.length)
-		{
-			while (row = result.shift())
-				tags.push(row.tag);
-			
-			retval = tags.join(", ");
-			su_tag_lists_by_url[url] = retval;
-		}
-	}
-	return retval;
-}
-
-// returns true/false is domain is blocked or not
-function su_is_domain_blocked(domain)
-{
-	if (! su_host.places)
-		return false;
-	
-	var out = false;
-	try {
-		var db = su_ds.getDatabase();
-		var sql;
-		var result;
-		sql = "SELECT active FROM blocked_domain WHERE domain=" + db.q(domain) + " AND active=1";
-		result = db.query(sql);
-		out = (result.length) ? true : false;
-	} catch (e) {} // be safe since this is within the stumbling path
-	return out;
-}	
-
-function su_is_bookmarked(nsiuri)
-{
-	return (PlacesUtils.getMostRecentBookmarkForURI(nsiuri) != -1)
-}
-
-function su_get_supertopic_folderid(catid, create)
-{
-	var folder_name;
-	if (catid == 0)
-		catid = -1;
-	else if (su_is_adult_category(catid)
-			&& (! su_ds.getValue("$sync_bm_adult")))
-		catid = -1;
-	
-	if (catid == -1)
-	{
-		folder_name = su_tagged_folder_name; 
-	}
-	else
-	{
-		folder_name = su_ds.lookup("catid:folder_name", catid);
-		if (! folder_name)
-			return null;
-	}
-			
-	su_verify_bookmarks_folder();
-	
-	var bms = su_ds.getBookmarksService();
-	
-	// If a folder with this name exists in their su bookmarks folder,
-	// use it.
-	
-	var folderid = bms.getChildFolder(
-			su_ds.getValue("$bm_folderid"),
-			folder_name);
-	
-	
-	if (folderid != 0)
-		return folderid;
-	
-	// Otherwise, try to use the most recent one that we created, even
-	// if they moved or renamed it.
-	
-	var db = su_ds.getDatabase();
-	var result;
-	var index;
-	var row;
-	var sql;
-	sql = "SELECT bm_folderid FROM supertopic WHERE label=" + db.q(folder_name);
-	result = db.query(sql);
-	index = -1;
-	if (row = result.shift())
-	{
-		folderid = row.bm_folderid;
-		index = bms.getItemIndex(folderid);
-	}
-	
-
-	if (index != -1)
-		return folderid;
-	
-	else if (! create)
-		return null;
-	
-	// Do a sanity check to make sure we're allowed to create it.
-	
-	if ((folder_name == "Adult") && (! su_ds.getValue("$sync_bm_adult")))
-		return null;
-	
-	
-	// Create a new one in alphabetical order with our other
-	// automatically generated supertopic folders; make the
-	// 'Other Tagged' folder always last.  
-	
-	index = -1;
-	
-	if (catid != -1)
-	{
-		sql = "SELECT label,bm_folderid FROM supertopic WHERE label>" + db.q(folder_name) + " AND label!="  + db.q(su_tagged_folder_name) + " ORDER BY label LIMIT 1";
-		result = db.query(sql);
-		if (row = result.shift())
-		{
-			try {
-				index = bms.getItemIndex(row.bm_folderid);
-			} catch (e) {}
-		}
-	}
-	
-	folderid = null;
-	
-	try {
-		folderid = bms.createFolder(
-				su_ds.getValue("$bm_folderid"),
-				folder_name,
-				index);
-		
-		var index2 = bms.getItemIndex(folderid);
-		db.a("INSERT OR REPLACE INTO supertopic (label,bm_folderid) VALUES (");
-		db.as(folder_name);
-		db.alv(folderid);
-		db.query();
-	} catch (e) { su_log_error("CREATE FOLDER", e); }
-	
-	
-	// Update the video query to include this new folder.
-
-	if (folderid)
-		su_refresh_video_folder_bm();
-	
-	return folderid;
-}
-
-
-function su_refresh_video_folder_bm()
-{
-	var db = su_ds.getDatabase();
-	var sql;
-	var result;
-	var row;
-	sql = "SELECT bm_folderid FROM supertopic ORDER BY label";
-	result = db.query(sql);
-	var i;
-	var folderids = new Array();
-	for (i = 0; row = result[i]; i++)
-		folderids.push(row.bm_folderid);
-	
-	var bms = su_ds.getBookmarksService();
-	
-	var itemid = su_ds.getValue("$bm_suvid_itemid");
-	var tmpidx;
-	if (itemid != 0)
-	{
-		tmpidx = -1;
-		try {
-		tmpidx = bms.getItemIndex(itemid);
-		} catch (e) {}
-		if (tmpidx != -1)
-			bms.removeItem(itemid);
-	}
-	
-	itemid = su_add_query_folder_bm(
-			su_ds.getValue("$bm_folderid"),
-			folderids,
-			"video",
-			"Video Favorites",
-			0);
-	
-	su_ds.setValue("$bm_suvid_itemid", itemid);
-	
-	su_ds.flushPrefs();
-}
-
-function su_get_error_object_dump(o)
-{
-	if (! o)
-		return "\n" + (typeof o);
-	
-	var str = "\n===== dump ===\n"; 
-	var p;
-	for (p in o)
-	{
-		if (p.match(/.*_ERR$/))
-			continue;
-		
-		try {
-			str += "[" + p + "]\n" + o[p] + "\n";
-		}
-		catch (e) {
-			str += "[" + p + "] ERROR\n" + e + "\n";
-		}
-	}
-	str += "========";
-	return str;
-}
-
-function su_enable_client_features(enable_mask)
-{
-	var old_bits = su_ds.getValue("@client_form");
-	
-	// add new enable routines immediately above
-	
-	su_ds.setValue("@client_form", (old_bits | enable_mask));
-}
-
-function su_disable_client_features(disable_mask)
-{
-	var old_bits = su_ds.getValue("@client_form");
-
-	// add new disable routines immediately above
-	
-	su_ds.setValue("@client_form", (old_bits & (~ disable_mask)));
-}
-
-function su_enable_user_features(enable_mask)
-{
-	var old_bits = su_ds.getValue("$form");
-	
-	if (su_ds.hasFeature("$sociallinks", enable_mask) &&
-			(! su_ds.hasFeature("$sociallinks", old_bits)))
-	{
-		var searchlinks_enabled = 
-				(su_ds.getValue("$show_searchlinks_score") ||
-				su_ds.getValue("$show_searchlinks_friends") ||
-				su_ds.getValue("$show_searchlinks_topic"));
-
-		su_ds.setValue("$shown_searchlinks_dialog", searchlinks_enabled);
-		if (! searchlinks_enabled)
-			su_ds.setValue("$intro_count", 0);
-	}
-	
-	if (su_ds.hasFeature("$adultrrecat", enable_mask) &&
-			(! su_ds.hasFeature("$adultrrecat", old_bits)))
-	{
-		su_ds.setValue("$recat_adult", 1);
-	}
-	
-	if (su_ds.hasFeature("$adultxrecat", enable_mask) &&
-			(! su_ds.hasFeature("$adultxrecat", old_bits)))
-	{
-		su_ds.setValue("$recat_adult", 2);
-	}
-	
-	if (su_ds.hasFeature("$tagger", enable_mask) &&
-			(! su_ds.hasFeature("$tagger", old_bits)))
-	{
-		su_ds.setValue("$show_tag", true);
-		su_ds.setValue("$show_flag", true);
-		su_ds.setValue("$shown_tag", true);
-		su_init_toolbar_element_visibility();
-	}
-	
-	if (su_ds.hasFeature("$has_subscriptions", enable_mask) &&
-			(! su_ds.hasFeature("$has_subscriptions", old_bits)))
-	{
-		// If they have subscribers, then turn on the stumblers menu.
-		if(!su_ds.getValue("$show_friends_user_changed"))
-		{
-			su_ds.setValue("$show_friends", true);
-			su_set_visible("su_friends", true);
-		}
-	}
-
-	// add new enable routines immediately above
-	su_ds.setValue("$form", (old_bits | enable_mask));
-}
-
-function su_disable_user_features(disable_mask)
-{
-	var old_bits = su_ds.getValue("$form");
-
-	// add new disable routines immediately above
-	
-	su_ds.setValue("$form", (old_bits & (~ disable_mask)));
-}
-
-function su_process_set_pref_command(name, val_str)
-{
-	switch (su_ds.getPrefType(name))
-	{
-		case "Int":
-			su_ds.setValue(name, parseInt(val_str));
-			break;
-		case "Bool":
-			su_ds.setValue(name, ((val_str == "1") || (val_str == "true")));
-			break;
-		case "Char":
-			su_ds.setValue(name, val_str);
-			break;
-		case "JSON":
-			su_ds.setValue(name, su_ds.deserialize(val_str));
-			break;
-	}
-}
-
-function su_http_error(error, status)
-{
-	alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to "
-		+ su_base_url + "feedback.php to report the problem\nError : " 
-		+ error + "\nStatus : " + status);
-}
-
-// initializes stumbleid and stumblepass; also sets the use_token
-// preference during migration
-function su_init_login(skip_cookies, ignore_cookies)
-{
-	try {
-		if (su_ds.isPrefDefined("@current_user"))
-		{
-			var tmp_id = su_ds.getValue("@current_user");
-			if (tmp_id == "")
-			{
-				stumbleid = 0;
-				stumblepass = "";
-			}
-			else
-			{
-				stumbleid = tmp_id;
-				stumblepass = su_ds.getStoredPassword();
-				if ((stumblepass == null) || (stumblepass == ""))
-				{
-					try {
-						su_log_error("NULL PASSWORD");
-					} catch (e) {}
-					su_ds.setValue("@current_user", "");
-					stumbleid = 0;
-					stumblepass = "";
-					return false;
-				}
-			}
-		}
-		else
-		{
-			stumbleid = 0;
-			stumblepass = "";
-		}
-	
-		if (! skip_cookies)
-		{
-			try {
-				su_process_cookies(ignore_cookies);
-			} catch (e) { su_log_error("INIT COOKIES", e); }
-		}
-		
-	} catch (e) { su_log_error("INIT LOGIN", e);
-		stumbleid = 0;
-		stumblepass = "";
-	}
-	su_ds.getValue("@current_user");
-	su_ds.flushPrefs();
-	return true;
-}
-
-function su_process_cookies(clear_only)
-{
-var manager = su_get_service(
-				"@mozilla.org/cookiemanager;1",
-				"nsICookieManager");
-	var cookies = manager.enumerator;
-	var cookie;
-	var userid1 = null;
-	var password1 = null;
-	var userid2 = null;
-	var password2 = null;
-	var now = (new Date()).getTime();
-	var searchlinks = null;
-	var nickname = null;
-	var enableg = null;
-	var enableu = null;
-	var disableg = null;
-	var disableu = null;
-	var thru_domains = null;
-	
-	while (cookies.hasMoreElements())
-	{
-		cookie = cookies.getNext().QueryInterface(
-					Components.interfaces.nsICookie);
-					
-		if ((cookie.host == ("." + su_servername)) &&
-					((cookie.expires * 1000) > now))
-		{
-			if (cookie.name == "tsuu")
-			{
-				userid1 = cookie.value;
-				manager.remove("." + su_servername, "tsuu", "/", 0);
-			}
-			else if (cookie.name == "tsut")
-			{
-				// As of 2008-04-15, this is always salted, hashed and
-				// not encoded.
-				password1 = cookie.value;
-				manager.remove("." + su_servername, "tsut", "/", 0);
-			}
-			else if (cookie.name == "stumble_user")
-			{
-				userid2 = cookie.value;
-				manager.remove("." + su_servername, "stumble_user", "/", 0);
-			}
-			else if (cookie.name == "stumble_pass")
-			{
-				// As of 2008-04-15, this is always salted, hashed and
-				// not encoded.
-				password2 = cookie.value;
-				manager.remove("." + su_servername, "stumble_pass", "/", 0);
-			}
-			else if (cookie.name == "nickname")
-			{
-				nickname = cookie.value;
-				manager.remove("." + su_servername, "nickname", "/", 0);
-			}
-			else if (cookie.name == "searchlinks")
-			{
-				searchlinks = true;
-				manager.remove("." + su_servername, "searchlinks", "/", 0);
-			}
-			else if (cookie.name == "thru_domains")
-			{
-				thru_domains = cookie.value;
-				manager.remove("." + su_servername, "thru_domains", "/", 0);
-			}
-			else if (cookie.name == "enableu")
-			{
-				enableu = parseInt(cookie.value);
-				manager.remove("." + su_servername, "enableu", "/", 0);
-			}
-			else if (cookie.name == "enableg")
-			{
-				enableg = parseInt(cookie.value);
-				manager.remove("." + su_servername, "enableg", "/", 0);
-			}
-			else if (cookie.name == "disableu")
-			{
-				disableu = parseInt(cookie.value);
-				manager.remove("." + su_servername, "disableu", "/", 0);
-			}
-			else if (cookie.name == "disableg")
-			{
-				disableg = parseInt(cookie.value);
-				manager.remove("." + su_servername, "disableg", "/", 0);
-			}
-			else if (clear_only && ((typeof cookie.name) == "string") &&
-					(cookie.name.indexOf("NSC_") == 0))
-			{
-				manager.remove("." + su_servername, cookie.name, "/", 0);
-			}
-		}
-	}
-	
-	if (clear_only)
-		return null;
-
-	var profile_change = null;
-	
-	if ((userid1 != null) && (password1 != null) &&
-				(userid1 != "") && (password1 != ""))
-	{
-		var login = true;
-		if ((stumbleid != 0) && (stumblepass != ""))
-		{
-			var name = su_ds.getValue("$nick");
-			if (name == "")
-				name += stumbleid;
-			
-			if (su_ds.getValue("~visited_signup"))
-			{
-				login = true;
-			}
-			else
-			{
-				login = window.confirm("Do you want to sign-in to this new account?\n\n")
-			}
-		}
-		
-		if (login)
-		{
-			profile_change = new Object();
-			stumbleid = userid1;
-			su_ds.setValue("@current_user", stumbleid);
-			profile_change.new_profile = (! su_ds.isPrefDefined("$nick"));
-			stumblepass = password1;
-			su_ds.storePassword(stumblepass, null);
-		}
-	}
-	else if ((userid2 != null) && (password2 != null) &&
-				(userid2 != "") && (password2 != ""))
-	{
-		profile_change = new Object();
-		stumbleid = userid2;
-		su_ds.setValue("@current_user", stumbleid);
-		profile_change.new_profile = (! su_ds.isPrefDefined("$nick"));
-		if (password2.length < 28)
-		{
-			if (su_enable_hashed_password)
-			{
-				stumblepass = su_ds.getEncodedPassword(password2, stumbleid);
-				su_ds.storePassword(stumblepass, null);
-			}
-			else
-			{
-				stumblepass = password2;
-				su_ds.storePassword(null, stumblepass);
-			}
-		}
-		else
-		{
-			stumblepass = password2;
-			su_ds.storePassword(stumblepass, null);
-		}
-	}
-	
-	if (stumbleid != 0)
-	{
-		if (searchlinks)
-		{
-			su_ds.setValue("$show_searchlinks_friends", true);
-			su_ds.setValue("$show_searchlinks_score", true);
-			su_ds.setValue("$shown_searchlinks", true);
-		}
-		
-		if (nickname)
-			su_ds.setValue("$nick", nickname);
-		
-		if (enableg)
-			su_enable_client_features(enableg);
-		
-		if (enableu)
-			su_enable_user_features(enableu);
-		
-		if (disableg)
-			su_disable_client_features(disableg);
-		
-		if (disableu)
-			su_disable_user_features(disableu);
-		
-		if (thru_domains)
-			su_ds.setValue("$default_thru_domain_list", thru_domains);
-		
-		manager.remove("." + su_servername, "SU_REMEMBER", "/", 0);
-	}
-	
-	if (profile_change)
-		su_visited_login_page = false;
-	
-	return profile_change;
-}
-
-// used by logout and handle_window_load to clear authentication
-function su_logout_auth()
-{
-	// 1. remove username and password
-	su_ds.setValue("@current_user", "");
-	su_ds.deleteStoredPassword();
-
-	// now sync this stuff before we crash
-	su_ds.flushPrefs();
-
-	// 2. change current user to 0
-	stumbleid = 0;
-	stumblepass = '';
-
-	// 3. remove cookies stumble_user, stumble_pass, and PHPSESSID
-	// ??? or maybe just all cookies from stumbleupon.com?
-
-	var cookieManager = su_get_service(
-				"@mozilla.org/cookiemanager;1",
-				"nsICookieManager");
-	cookieManager.remove("." + su_servername, "PHPSESSID", "/", 0);
-	cookieManager.remove("." + su_servername, "stumble_user", "/", 0);
-	cookieManager.remove("." + su_servername, "stumble_pass", "/", 0);
-	cookieManager.remove("." + su_servername, "SU_REMEMBER", "/", 0);
-	
-	su_logout_server();
-}
-
-
-function su_logout_server()
-{
-	su_post_url_server_async(
-				"session.php",
-				su_arp("", "logout", 1),
-				15000,
-				su_generic_done);
-}
-
-
-// used by signup_page() to grab a new stumbleid from the server
-// and to initialize stumbleid, stumblepass and nick
-function su_init_new_user(challenge, init_toolbar)
-{
-	var detail = new Object();
-	detail.init_toolbar = init_toolbar;
-	// We have no ID yet, hit getid.php
-	su_post_url_server_async(
-				"init_user.php",
-				"challenge=" + challenge + 
-					((su_enable_hashed_password) ? "&hashed=1" : ""), 
-				null,
-				su_init_new_user_done,
-				detail);
-}
-
-function su_init_new_user_done(res)
-{
-	var msg = "StumbleUpon was unable to create an account for you.  Please try again later.";
-	
-	try {
-		if (res.status == 1)
-		{
-			alert(msg);
-			return;
-		}
-	} catch (e) {
-		alert(msg);
-		return;
-	}
-
-	if (res.status != 200)
-	{
-		su_http_error(res.error, res.status);
-		return;
-	}
-	
-	var detail = res.detail;
-	
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-	
-	if (su_log_communication)
-		su_log("response init_user.php", s);
-	
-	var parsed = s.split("\n");
-	// Iterate through commands
-	
-	for (var i = 0; i < parsed.length; i++)
-	{
-		if (parsed[i] == "")
-			continue;
-
-		// Parse command structure
-		var command = parsed[i].split(" ");
-		switch(command[0])
-		{
-			case "USER":
-				stumbleid = command[1];
-				su_ds.setValue("@current_user", stumbleid);
-				break;
-			case "PASS":
-				stumblepass = command[1];
-				break;
-			default:
-				var context = new Object();
-				su_process_command(parsed[i], context, command);
-				if (context.error)
-					return;
-				break;
-		}
-	}
-	
-	if (su_isInt(stumbleid) && stumbleid != 0 && stumblepass != 0 && stumbleid != false && stumblepass != false && stumblepass.length>0)
-	{
-		su_ds.storePassword(stumblepass, null);
-		
-		su_store_user_interests();
-		
-		// sync prefs.js in case we crash
-		su_ds.flushPrefs();
-		
-		if (detail.init_toolbar)
-		{
-			var login_detail = new Object();
-			login_detail.skip_cookies = false;
-			login_detail.ignore_cookies = true;
-			login_detail.new_user_prompt = true;
-			login_detail.new_profile = true;
-			su_invoke_global_event("login", login_detail);
-		}
-	}
-	else
-	{
-		// spit out an error
-		alert("StumbleUpon was unable to create an account for you.  Please try again later.");
-	}
-}
-
-//!!! sometimes fails  0 = notint ???
-function su_isInt(elm) 
-{
-	elm = elm.toString();
-	var pattern = /[^0-9]/;
-	if (pattern.test(elm))
-		return false;
-	else
-		return true;
-}
-
-
-// user_cat = incat stumble category ID
-// Gets an url the users hasn't seen yet from stumbleurls
-function su_get_unseen_url(user_cat, hit_server, callback, context)
-{
-	// load stumbles...
-	try {
-		su_load_stumbles(null);
-	} catch (e) { su_log_error("UNSEEN LOAD", e); }
-	
-	if (stumbles.length == 0)
-	{
-		if (hit_server)
-		{
-			// We need to hit the server to get urls
-			if (! context)
-				context = new su_AsyncContext();
-
-			context.callbacks.push(callback);
-			
-			su_update_url_cache(
-						user_cat,
-						false,
-						su_get_unseen_url_done,
-						context);
-
-			// Did we get any urls from server?
-			if (stumbles.length == 0)
-				return false;
-		}
-		else
-		{
-			// we're out of stumbles and we're not hitting the server, so bail
-			return false;
-		}
-	}
-	else
-	{
-		// we have stumbles in our queue, carry on
-		su_get_unseen_url_done('', callback, context);
-	}
-	return true;
-}
-
-function su_get_unseen_url_done(error, callback, context)
-{
-	if (error == "error")
-	{
-		if (callback)
-			callback("error", context);
-		return;
-	}
-	su_load_stumbles(null);
-	
-	var i;
-	for (i = 0; i < stumbles.length; i++)
-	{
-		// Go through each seen url to see if there's one we haven't seen already
-		if (stumbles[i] == "")
-			continue;
-		
-		if (callback)
-			callback(stumbles[i], context);
-		return;
-	}
-
-	if (callback)
-		callback("", context);
-}
-
-function clickstumble(event)
-{
-	if (su_promo_mode && (stumbleid == 0))
-	{
-//		var user_cat = su_selected_category;
-//		user_cat += "";
-//		
-//		if (! user_cat)
-//			user_cat = "0";
-//		
-//		var new_cat_flag = (user_cat != su_ds.getValue("$last_incat"));
-//		su_ds.setValue("$last_incat", user_cat);
-//	
-//		var norm_cat = su_trim(user_cat.toLowerCase());
-//		if (((norm_cat == "video") || (norm_cat == "videos") || 
-//					(norm_cat == "tag_video") || (norm_cat == "tag_videos")) &&
-//					(su_host.version != "0.0"))
-//		{
-//			su_stumble_video(su_new_tab(event));
-//		}
-//		else
-//		{
-			su_handle_promo_click(event, "stumble");
-//		}
-		return;
-	}
-	
-	stumble(su_new_tab(event));
-}
-
-function su_AsyncContext()
-{
-	this.callbacks = new Array();
-}
-
-function su_cancel_stumble_throttle()
-{
-	su_stumble_throttled = false;
-}
-
-// Handler for button "Stumble"
-function stumble(stumble_new_tab, skip_searchlinks_dialog) 
-{
-	try {
-	var newDate = new Date();
-	var newTime = newDate.getTime();
-	var oldTime = su_ds.getIntValue("$last_stumble");
-	
-	// avoid double-click
-	if (! stumble_new_tab)
-	{
-//!!! Why does this get stuck intermittently for some users?
-//		if (newTime - oldTime < su_ds.getValue("@click_throttle_ms"))
-//			return;
-
-		if (su_stumble_throttled)
-		{
-			return;
-		}
-		else
-		{
-			su_stumble_throttled = true;
-			setTimeout(
-				su_cancel_stumble_throttle,
-				su_ds.getValue("@click_throttle_ms"));
-		}
-	}
-
-	if (su_cacheTimer != 0)
-	{
-		clearTimeout(su_cacheTimer);
-		su_cacheTimer = 0;
-	}
-
-	// See if they are not logged in
-	var getit = su_ds.getValue("@current_user");
-	if (! getit)
-	{
-		// okay, they are not logged in		
-
-		// see if they've already created/used an account with this toolbar
-		if (su_has_logged_in())
-		{
-			su_show_signin_dialog();
-		}
-		else
-		{
-			su_verify_cookie_perms(false);
-			var params = "";
-			var loc = "signup.php";
-			if (su_host.dist)
-				loc = "sign_up.php";
-			
-			params = su_arp(params, "version", su_useragent);
-			
-			if (su_host.dist)
-				loc = su_arp(loc, "dist", su_host.dist, true);
-			
-			if (su_ds.getValue("@facebook_user"))
-				loc = su_arp(loc, "pre", "facebook", true);
-			
-			su_set_server_location(
-						loc,
-						params,
-						false);		
-		}
-		su_check_progress_listener();
-		return;
-	}
-	su_check_progress_listener();
-
-	if (stumbleid == 0)
-		return;
-
-	if (! skip_searchlinks_dialog)
-	{
-		if (su_show_searchlinks_dialog(true, stumble_new_tab, true))
-			return;
-	}
-	
-	if (! su_ds.getValue("$shown_searchlinks_dialog"))
-		su_ds.incrementValue("$intro_count");
-	
-//	su_update_verified_reporting(true);
-	
-	var user_cat = su_selected_category;
-	
-	if (! user_cat)
-		user_cat = "0";
-	
-	var new_cat_flag = (user_cat != su_ds.getValue("$last_incat"));
-	su_ds.setValue("$last_incat", user_cat);
-	
-	var oldDate = new Date();
-	oldDate.setTime(oldTime);
-
-	su_ds.setValue("$last_stumble", newTime);
-	if (user_cat == "0")
-		su_ds.setValue("$poll_time_s", su_get_time_s());
-	
-	su_ds.flushPrefs();
-	
-	// change icon...
-	su_get_element("su_stumble").image="chrome://stumbleupon/content/skin/stumble2.png";
-	su_stumble_action_count++;
-	setTimeout(
-				su_reset_stumble_action_indicator,
-				su_ds.getValue("@stumble_action_timeout_ms"),
-				su_stumble_action_count);
-	
-	var norm_cat = su_trim(user_cat.toLowerCase());
-	if (((norm_cat == "video") || (norm_cat == "videos") || 
-				(norm_cat == "tag_video") || (norm_cat == "tag_videos")) &&
-				(su_host.version != "0.0"))
-	{
-		su_stumble_video(stumble_new_tab);
-		return;
-	}
-	
-	if (su_stumble_async_context && ((newTime - oldTime) <= 
-				su_ds.getValue("@recommend_timeout_ms")) &&
-				(! new_cat_flag))
-	{
-		// If a stumble action is in progress and the category hasn't 
-		// changed, we only simulate stumbling.  Ideally, the time 
-		// comparison above shouldn't be necessary, but we include it as a
-		// failsafe to avoid disabling stumbling if 
-		// su_stumble_async_context somehow doesn't get set to null. 
-		// -- JW
-
-		//!!! It would be better to queue stumble actions if they're in
-		// the same topic and if they're to be opened in new tabs.  But
-		// this would increase likelihood that a referral (and, more 
-		// importantly, a note attached to a referral) may not be seen.
-		// Here are a couple related options:
-		// o Don't consider a referral to have been seen unless the
-		//   person lingers on the relevant tab.
-		// o Highlight tabs featuring referrals that haven't been lingered
-		//   upon.
-		// o If a pending action not targeting a new tab exists, 
-		//   implicitly cancel the non-new-tab action, perhaps by 
-		//   converting it into a new-tab action.
-		// -- JW
-		
-		return;
-	}
-	else if (su_stumble_async_context)
-	{
-		try {
-			// Try shouldn't be necessary, but this eliminates possibility 
-			// of an error in the callback execution path breaking 
-			// stumbling. -- JW
-			if (su_stumble_async_context && su_stumble_async_context._request)
-				su_service.abortPostAsync(su_stumble_async_context._request);
-		} catch (e) { su_log_error("RECOMMEND ABORT ERROR", e); }
-	}
-
-	
-	// see if new day is the same as today
-	var newDay = newDate.getDate();
-	var oldDay = oldDate.getDate();
-	var newMonth = newDate.getMonth();
-	var oldMonth = oldDate.getMonth();
-	var newYear = newDate.getYear();
-	var oldYear = oldDate.getYear();
-
-	if (new_cat_flag)
-	{
-		clear_stumbles();
-	}
-	
-	var first_of_day = false;
-	if (oldTime != 0)
-	{
-		if (oldDay != newDay || oldMonth != newMonth || oldYear != newYear)
-		{
-			first_of_day = true;
-			// clear stumbles
-			clear_stumbles();
-		}
-		else if (newTime - oldTime > 1000 * 60 * 60 * 2)
-		{
-			// clear stumbles if you haven't stumbled in the last 2 hours
-			// so our stumbles are "fresh"
-			clear_stumbles();
-		}
-	}
-
-	
-	var target_browser = null;
-	if (! stumble_new_tab)
-		target_browser = getBrowser().selectedBrowser;
-
-
-	if (typeof(user_cat) == "number" || typeof(user_cat) == "undefined" || user_cat == null || user_cat.indexOf("TAG") == -1)
-	{
-		// clear search/tag box
-		su_old_search = '';
-		su_get_element("su_searchbox").value = '';
-		su_last_typed_tag = 0;
-	}
-	else
-	{
-		// put it in the box
-		if (user_cat.indexOf("TAG_") == 0)
-		{
-			var tmp_cat = user_cat.substr(4);
-
-			// Don't tag with thru domains.
-			tag = su_ds.isThruDomain(tmp_cat) ? "" : tmp_cat;
-		}
-		else if (user_cat.indexOf("USERTAG_") == 0)
-		{
-			var chunk = user_cat.substr(8);
-			chunks = chunk.split('_');
-			var tag = chunks[1];
-			var profile = chunks[0];
-		}
-		else
-		{
-			tag = '';	
-		}
-		su_get_element("su_searchbox").value=tag;
-		su_get_element("su_searchbox").removeAttribute("mode");
-		su_old_search = tag;
-		su_last_typed_tag = 0;
-		su_visited_searchbox = 1;
-	}
-	
-
-	var unseen = "";
-
-	var context = new su_AsyncContext();
-	context.user_cat = user_cat;
-	context.timestamp = newTime;
-	context.new_tab = stumble_new_tab;
-	context.target_browser = target_browser;
-	context.quiet = false;
-	context.stumblevideo = false;
-	context.first_of_day = first_of_day;
-	context.skip_count = 0;
-
-	su_stumble_async_context = context;
-	su_get_unseen_url(
-				user_cat,
-				1,
-				function(unseen, context) { window.stumble_done(unseen, context); },
-				context);
-	
-	
-	} catch (e) {
-		if (stumbleid == 0)
-			su_log_error("STUMBLE LOGGED-OUT", e);
-		else
-			su_log_error("STUMBLE LOGGED-IN", e, su_ds.getValue("$last_incat"), su_service.getErrorObjectDump(su_stumble_async_context));
-		su_stumble_async_context = null;
-	}
-}
-
-function su_stumble_video(new_tab)
-{
-	var label;
-	if (!(su_promo_mode && (stumbleid == 0)))
-	{
-		su_set_mode("video", "Video",
-					"chrome://stumbleupon/content/skin/video.png",
-					"Stumble! ", "Stumble a video");
-	}
-	
-	if (new_tab)
-	{
-		su_pending_stumblevideo_stumble = true;
-		su_set_location(
-					"http://video." + su_servername + "/",
-					null,
-					true);
-	}
-	else if (su_is_matching_domain(su_get_browser_url(null, true), 
-				"video." + su_servername))
-	{
-		su_dispatch_click(getBrowser().contentDocument, "stumbleButton");
-	}
-	else
-	{
-		su_pending_stumblevideo_stumble = true;
-		var params = null;
-		if (su_host.dist)
-			params = su_arp("", "dist", su_host.dist);
-		su_set_location(
-					"http://video." + su_servername + "/",
-					params,
-					false);
-	}
-}
-
-function su_update_message(tab_url_detail, url_detail, url, tld, stumblevideo)
-{
-	if (! tab_url_detail)
-		return;
-	
-	if (! tab_url_detail.messageid)
-		return;
-	
-	var id = "su_messageOuterBox" + tab_url_detail.messageid;
-	
-	if (su_drawer_timers[id])
-		return;
-	
-	var el;
-	if (url_detail == tab_url_detail)
-	{
-		el = su_get_element("su_bannerReloadButton" + tab_url_detail.messageid);
-		if (el)
-			el.disabled = true;
-	}
-	else if (stumblevideo && (url != tab_url_detail.url))
-	{
-		su_close_message(tab_url_detail.messageid, true);
-	}
-	else if ((! stumblevideo) && (tab_url_detail.tld != tld))
-	{
-		su_close_message(tab_url_detail.messageid, true);
-	}
-	else
-	{
-		el = su_get_element("su_bannerReloadButton" + tab_url_detail.messageid);
-		if (el)
-			el.disabled = false;
-	}
-}
-
-/*
-function su_update_verified_reporting(enable_reporting)
-{
-	if (su_enable_freereporting)
-		return;
-	
-	// people can't report a stumble as 404/spam until they actually stumble
-	var disabled = (enable_reporting) ? "false" : "true";
-	
-	su_get_element("su_report-menu").setAttribute("disabled", disabled);
-	su_get_element("su_flag_adult").setAttribute("disabled", disabled);
-	su_get_element("su_flag_wrongtopic").setAttribute("disabled", disabled);
-	su_get_element("su_flag_duplicate").setAttribute("disabled", disabled);
-	su_get_element("su_flag_inaccurate").setAttribute("disabled", disabled);
-	su_get_element("su_flag_spam").setAttribute("disabled", disabled);
-	su_get_element("su_flag_broken").setAttribute("disabled", disabled);
-	su_get_element("su_flag_wronglanguage").setAttribute("disabled", disabled);
-}
-*/
-
-function su_update_comment_level(url_detail, rateable)
-{
-	if (url_detail && url_detail.comment_level)
-		su_set_image("su_website_info", "chrome://stumbleupon/content/skin/bubble" + url_detail.comment_level + ".png");
-	
-	else if (rateable)
-		su_set_image("su_website_info", "chrome://stumbleupon/content/skin/bubble.png");
-	
-	else
-		su_set_image("su_website_info", "chrome://stumbleupon/content/skin/bubblex.png");
-}
-
-function su_update_referral_menu_tooltip(url_detail, stumblevideo)
-{
-	var el = su_get_element("su_referral_menu");
-	
-	if (! url_detail)
-	{
-		el.setAttribute("tooltiptext", "Share this page");
-		return;
-	}
-	
-	if (stumblevideo)
-		el.setAttribute("tooltiptext", "Share this video");
-	
-	else if (url_detail.catid == 302)
-		el.setAttribute("tooltiptext", "Share this picture");
-	
-	else
-		el.setAttribute("tooltiptext", "Share this page");
-}
-
-function su_update_firstrater(url_detail)
-{
-	if (! url_detail)
-	{
-		su_set_visible("firstrater", false);
-		su_set_visible("su_sponsor", false);
-		su_set_image("su_website_info",
-					"chrome://stumbleupon/content/skin/bubble.png");
-		su_set_image("su_referral_menu", 
-					"chrome://stumbleupon/content/skin/icon_tb_share.png");
-		return;
-	}
-
-	if ((url_detail.relationship == "sponsored") || 
-				(url_detail.relationship == "friend-sponsored"))
-	{
-		// sponsor
-	
-		// Set and show sponsor button
-		su_set_visible("su_sponsor", true);
-		frater = su_get_element("su_sponsor");
-		frater.setAttribute("tooltiptext", "This site is sponsored");
-	}
-	else
-	{
-		// nonsponsor
-	
-		// Hide sponsor button
-		su_set_visible("su_sponsor", false);
-	}
-
-	if (! url_detail.firstrater_nick)
-	{
-		// Hide firstrater button
-		su_set_visible("firstrater", false);
-		return;
-	}
-	
-	// Set and show firstrater button
-	frater = su_get_element("firstrater");
-	
-	su_set_visible("firstrater", true);
-	
-	var tooltip = url_detail.firstrater_nick;
-	
-	su_set_label("firstrater", url_detail.firstrater_nick);
-	
-	switch (url_detail.relationship)
-	{
-		case "referral":
-			// this site was sent directly to you by a friend	
-			frater.image = "chrome://stumbleupon/content/skin/redman.png";
-			tooltip += " who sent you: ";
-			break;
-			
-		case "friend":
-			// your friend rate this site	
-			frater.image = "chrome://stumbleupon/content/skin/redman.png";
-			tooltip += " who recommends: ";
-			break;
-		
-		case "friend-sponsored":
-			frater.image = "chrome://stumbleupon/content/skin/redman.png";
-			tooltip += " who suggested: ";
-			break;
-			
-		case "sponsored":
-			// a non friend rated this site	
-			frater.image = "chrome://stumbleupon/content/skin/firstrater.png";
-			tooltip += " who recommends: ";
-			break;
-	
-		case "firstrater":
-			// a non friend rated this site	
-			frater.image = "chrome://stumbleupon/skin/firstrater.png";
-			tooltip += " who suggested: ";
-			break;
-	}
-
-	tooltip += url_detail.url;
-
-	frater.firstrater = url_detail.firstrater_nick;
-	frater.setAttribute("tooltiptext", tooltip);
-}
-
-function su_update_thru_domain(url, tld, url_detail, stumblevideo, from_resource_installed)
-{
-	if (! url)
-		return;
-
-	if (! tld)
-		tld = su_get_tld(url);
-	
-	if ((! tld) || (url_detail && stumblevideo)) 
-	{
-		su_set_visible("su_mode_domain", false);
-		su_set_image("su_mode_domain",
-					"chrome://stumbleupon/content/skin/topic.png");
-		return;
-	}
-	
-	var tld_parts = tld.split(".");
-	
-	var i = 0;
-	var domain = null;
-	var cmp = "";
-	while (tld_parts.length)
-	{
-		var part = tld_parts.pop();
-		if (part == "")
-			return;
-		
-		if (i == 0)
-			cmp = "." + part;
-		else if (i == 1)
-			cmp = part + cmp;
-		else
-			cmp = part + "." + cmp;
-		
-		if (su_ds.isThruDomain(cmp))
-			domain = cmp;
-		
-		i++;
-	}
-
-	if (domain)
-	{
-		if (su_get_element("su_mode_dyn_" + su_get_channel_id(domain)))
-			domain = null;
-	}
-	
-	if ((domain == "wikipedia.org") && 
-				su_ds.getValue("$show_mode_wiki"))
-		domain = null;
-	
-	if (! domain)
-	{
-		su_set_visible("su_mode_domain", false);
-		su_set_image("su_mode_domain",
-					"chrome://stumbleupon/content/skin/topic.png");
-		
-		if (su_info_spec && su_info_spec.domain)
-			su_hide_info();
-		
-		return;
-	}
-	
-	var favicon_url = su_get_favicon_url(domain);
-	
-	if (favicon_url)
-	{
-		su_set_image("su_mode_domain", favicon_url);
-	}
-	else
-	{
-		su_set_image("su_mode_domain",
-					"chrome://stumbleupon/content/skin/domain.png");
-	}
-	su_set_visible("su_mode_domain", true);
-	var el = su_get_element("su_mode_domain");
-	el.setAttribute("onclick", "su_handle_domain_mode_click(event, '" + domain + "');");
-	el.setAttribute("tooltiptext", "Stumble a page from " + domain);
-	
-	if (stumblevideo)
-		return;
-	
-	if (from_resource_installed)
-		return;
-	
-	if (su_ds.getValue("$shown_thru_domain_info_count") >= su_ds.getValue("~shown_thru_domain_info_count_max"))
-		return;
-	
-	var domains = su_ds.getValue("$shown_thru_domain_info_list").split(":");
-	for (i = 0; i < domains.length; i++)
-	{
-		if (domains[i] == "")
-			continue;
-		
-		if (domains[i] == domain)
-			return;
-	}
-	
-	su_display_info("thru_domain", domain);
-}
-
-function su_update_topic_and_reporting(tab_url_detail, url_detail, tld, from_stumbled, rec_url)
-{
-	
-	var el = su_get_element("su_morefrom");
-
-	if (el && url_detail && url_detail.topic_name)
-	{
-		el.setAttribute("label", "More from " + url_detail.topic_name);
-		el.setAttribute("tooltiptext", "More from " + url_detail.topic_name);
-		el.setAttribute("hidden", "false");
-		el.setAttribute("oncommand", "su_select_topic(" + 
-					url_detail.catid + ",'" + url_detail.topic_name + "', false);");
-	}	
-	else if (el)
-	{
-		el.setAttribute("hidden", "true");
-	}
-
-	// Define the topic button used for display
-
-	var topics_style = su_ds.getValue("$stumble_topics_style");
-	
-	var menu_style = (topics_style != 2);
-	
-	// Set the information to the topic button
-	
-	var report_menu = su_get_element("su_stumble_report_menu"); 
-	
-	if (menu_style && su_ds.getValue("$stumble_topics"))
-	{
-		su_set_visible("su_stumble_topic", false);
-		
-		var widget_id;
-		
-		switch (topics_style)
-		{
-			case 0: widget_id = "su_stumble_topic_menu_left";  break;
-			case 1: widget_id = "su_stumble_topic_menu_right"; break;
-		}
-		
-		if ((url_detail && url_detail.cur_topic_name) ||
-				(tab_url_detail && (tab_url_detail.tld == tld) &&
-				tab_url_detail.cur_topic_name))
-		{
-			var url = (url_detail) ? url_detail.url : tab_url_detail.url;
-			var topic_name = (url_detail) ? url_detail.cur_topic_name : tab_url_detail.cur_topic_name;
-			su_get_element(widget_id + "_popup").removeAttribute("onpopupshowing");
-			su_get_element(widget_id + "_popup").setAttribute("onpopupshowing",
-					'su_prepare_stumble_topic_menu(event, "' + url + '");');
-			
-			if (tab_url_detail && (tab_url_detail == url_detail))
-				su_remove_attribute(widget_id, "style");
-			else
-				su_set_attribute(widget_id, "style", "color: #707070;");
-			
-			if (topics_style == 1)
-				su_set_visible("su_separator7", true);
-			
-			su_set_label(widget_id, topic_name);
-			su_set_visible(widget_id, true);
-		}
-		else
-		{
-			su_set_visible(widget_id, false);
-			su_set_visible("su_separator7", false);
-		}
-	}
-	else
-	{
-		su_set_visible("su_stumble_topic_menu_left", false);
-		su_set_visible("su_stumble_topic_menu_right", false);
-		
-		if (url_detail && url_detail.cur_topic_name && su_ds.getValue("$stumble_topics"))
-		{
-			su_set_label("su_stumble_topic", url_detail.cur_topic_name);
-			su_get_element("su_stumble_topic").removeAttribute("onclick");
-			su_get_element("su_stumble_topic").setAttribute("onclick", 
-					'su_handle_stumble_topic_click(event, "' + url_detail.url + '");');
-			su_set_visible("su_stumble_topic", true);
-			su_set_visible("su_separator7", true);
-		}
-		else
-		{
-			su_set_visible("su_stumble_topic", false);
-			su_set_visible("su_separator7", false);
-		}
-	}
-	
-		
-	if ((url_detail && url_detail.cur_topic_name) ||
-			(tab_url_detail && (tab_url_detail.tld == tld)) ||
-			rec_url)
-	{
-		var url;
-		if (url_detail)
-			url = url_detail.url;
-		else if (rec_url)
-			url = rec_url;
-		else
-			url = tab_url_detail.url;
-		
-		su_get_element("su_stumble_report_popup").removeAttribute("onpopupshowing");
-		su_get_element("su_stumble_report_popup").setAttribute("onpopupshowing",
-				'su_prepare_stumble_report_menu(event, "' + url + '");');
-		report_menu.disabled = false;
-		
-		if (tab_url_detail && (tab_url_detail == url_detail))
-			report_menu.removeAttribute("style");
-		else
-			report_menu.setAttribute("style", "color: #707070;");
-	}
-	else
-	{
-		report_menu.disabled = true;
-	}
-
-	// Update the separator that may be affected by whether the topic menu is visible.
-	su_set_visible("su_separator_category", su_ds.getValue("$show_topics") || !su_get_element("su_stumble_topic_menu_left").collapsed);
-}
-
-/*
-function su_update_language(url_detail, from_stumbled)
-{
-	if ((! from_stumbled) && (! su_enable_freereporting))
-		return;
-	
-	// Update language UI elements.
-	if (url_detail && url_detail.language)
-	{
-		su_get_element("su_wronglanguage").label='Wrong Language (currently ' + url_detail.language + ')';
-		su_get_element("su_flag_wronglanguage").label='Flag as Wrong Language (currently ' + url_detail.language + ')';
-	}
-	else
-	{
-		su_get_element("su_wronglanguage").label='Wrong Language';
-		su_get_element("su_flag_wronglanguage").label='Flag as Wrong Language';
-	}
-}
-*/
-
-function su_update_page_feature_prompt(url)
-{
-	var service_detail = su_get_service_meta(url, true);
-	
-	if (su_is_matching_domain("facebook.com"))
-	{
-		if (su_ds.getValue("#checked_facebook"))
-		{
-			if (su_ds.getValue("$facebook_linked"))
-			{
-				su_set_visible("su_page_feature_prompt", false);
-			}
-			else
-			{
-				su_set_image("su_page_feature_prompt", "chrome://stumbleupon/content/skin/favicon_facebook.gif");
-
-				if (su_ds.getValue("$facebook_added"))
-					su_set_label("su_page_feature_prompt", "Link your Facebook account");
-				else
-					su_set_label("su_page_feature_prompt", "Share using Facebook");
-					
-				su_get_element("su_page_feature_prompt").setAttribute("tooltiptext", "Share and browse using the StumbleUpon application on Facebook");
-				su_set_visible("su_page_feature_prompt", true);
-			}
-		}
-		else
-		{
-			su_get_facebook(null);
-		}
-	}
-	else if (service_detail)
-	{
-		if (0) //su_ds.hasFeature("$slbuttonprompt") &&
-//				(! su_ds.getValue("$show_searchlinks_score")) &&
-//				(! su_ds.getValue("$show_searchlinks_friends")) &&
-//				(! su_ds.getValue("$show_searchlinks_topic")) &&
-//				((! su_ds.getValue("$shown_searchlinks")) || 
-//				su_ds.hasFeature("$slbuttonpermaprompt")))
-		{
-			su_set_image("su_page_feature_prompt", service_detail.icon);
-			su_set_label("su_page_feature_prompt", service_detail.prompt_label);
-			su_get_element("su_page_feature_prompt").setAttribute("tooltiptext",  service_detail.prompt_tooltip);
-			su_set_visible("su_page_feature_prompt", true);
-		}
-		else
-		{
-			su_set_visible("su_page_feature_prompt", false);
-		}
-	}
-	else
-	{
-		su_set_visible("su_page_feature_prompt", false);
-	}
-}
-
-function su_update_website_info_promo(url)
-{
-	var service_detail = su_get_service_meta(url, false);
-	
-	if (url.indexOf(su_base_url + "url") == 0)
-		su_get_element("su_website_info_promo").disabled = true;
-	else
-		su_get_element("su_website_info_promo").disabled = false;
-
-	if (service_detail)
-	{
-		su_search_service_id = service_detail.id;
-		su_set_image("su_website_info_promo", service_detail.icon);
-		su_set_label("su_website_info_promo", service_detail.prompt_label);
-		su_get_element("su_website_info_promo").setAttribute("tooltiptext",  service_detail.prompt_tooltip);
-	}
-	else
-	{
-		su_search_service_id = null;
-		su_set_image("su_website_info_promo", "chrome://stumbleupon/content/skin/bubble.png");
-		su_set_label("su_website_info_promo", su_get_element("su_website_info_promo").getAttribute("showlabel"));
-		su_get_element("su_website_info_promo").setAttribute("tooltiptext",  "People who like this");
-	}
-}
-		
-function su_get_tld(url)
-{
-	return su_service.getEffectiveTLD(url);
-}
-
-function su_deserialize_url_command_params(unseen, for_load)
-{
-	var field_names = new Array(
-				"url",                //  1 .
-				"catid",              //  2
-				"referrer",           //  3 .
-				"actual_url",         //  4 .
-				"firstrater",         //  5
-				"firstrater_nick",    //  6
-				"lang_code",          //  7  not mime_type?
-				"cluster_type",       //  8 .
-				"urlid",              //  9 .
-				"publicid",           // 10
-				"comment_level",      // 11
-				"rec_type",           // 12
-				"referral_note",      // 13
-				"referralid",         // 14 .
-				"catid2",             // 15
-				"catid3"              // 16
-				);
-	
-	var a = unseen.split(" ");
-	var spec = new Object();
-	var i;
-	for (i = 0; i < field_names.length; i++)
-	{
-		if (a.length > 0)
-			spec[field_names[i]] = a.shift();
-		else
-			spec[field_names[i]] = null;
-		
-		if (spec[field_names[i]] == "")
-			spec[field_names[i]] = null;
-	}
-	
-	if (! spec.url)
-		return null;
-	
-//	spec.load_dateobj = null;
-	
-	spec.redirect_url = spec.url;
-	
-	if (spec.url && spec.url != "")
-		spec.tld = su_get_tld(spec.url);
-	
-	if (! spec.tld)
-		spec.tld = "";
-	
-	if (spec.cluster_type)
-		spec.cluster_type = parseInt(spec.cluster_type);
-	
-	if (! spec.urlid)
-		spec.urlid = 0;
-	
-
-	if (for_load)
-		return spec;
-	
-	
-	spec.sender = (spec.firstrater_nick) ? 
-				spec.firstrater_nick : spec.firstrater;
-	
-	spec.is_system_referral = ((spec.cluster_type == 4) &&
-				spec.sender && 
-				(spec.sender.toLowerCase() == "stumbleupon"));
-	
-	spec.is_friend_referral = ((spec.cluster_type == 4) && 
-				(! spec.is_system_referral));
-	
-	if (spec.referral_note)
-	{
-		try {
-			spec.referral_note = decodeURIComponent(spec.referral_note);
-			if (spec.referral_note.length > 5000)
-				spec.referral_note = spec.referral_note.substring(0, 4999);
-		}
-		catch (e) {
-			spec.referral_note = null;
-			su_log_error("BAD REFERRALNOTE", e);
-		}
-	}
-//		spec.referral_note = spec.referral_note.replace(/\|/g, ' ');
-	
-	if (! spec.rec_type)
-		spec.rec_type = 0;
-
-	if (spec.comment_level)
-		spec.comment_level = parseInt(spec.comment_level);
-	else
-		spec.comment_level = 0;
-	
-	// Augment with category_name, relationship, language
-	spec.display_url = spec.url;
-	
-	spec.stumblevideo = false;
-	
-	spec.cur_catid = spec.catid;
-	
-	spec.topic_name = su_catnames[spec.catid];
-	if (! spec.topic_name)
-		spec.topic_name = null;
-	
-	spec.cur_topic_name = spec.topic_name;
-	
-	spec.rating = null;
-	
-	var status;
-	// show user's comment (if it's not a referral, and there is a comment) using display_message
-	switch (spec.cluster_type)
-	{
-		case 1:   status = "friend"; break;
-		case 3:   
-			if (spec.firstrater_nick && su_is_mutual_friend(spec.firstrater_nick)) 
-				status = "friend-sponsored";
-			else
-				status = "sponsored";
-			break;
-		case 4:
-			status = "referral";
-			spec.rating = su_get_rating(spec.url, false, null);
-			break;
-		default:  status = "firstrater"; break;
-	}
-	spec.relationship = status;
-	
-	spec.language = su_ds.lookup("lang_code:language", spec.lang_code);
-	
-	if (spec.catid2)
-		spec.catid2 = parseInt(spec.catid2);
-
-	if (spec.catid3)
-		spec.catid3 = parseInt(spec.catid3);
-	
-	spec.eval_interval = 0;
-	
-	spec.shown_dateobj = null;
-	
-	return spec;
-}
-
-function stumble_done(unseen, context)
-{
-	try {
-	
-	su_stumble_async_context = null;
-	su_get_element("su_stumble").image="chrome://stumbleupon/content/skin/stumble.png";
-
-	// ignore excessively delayed responses
-	var delay_ms = ((new Date()).getTime()) - context.timestamp;
-	if (delay_ms > su_ds.getValue("@stumble_action_timeout_ms"))
-		return;
-	
-	if ((unseen == "error") || (unseen == "connection error"))
-		return;
-	
-	if (unseen == "")
-	{
-		su_stumble_done_no_stumbles(context);
-		return;
-	}
-	
-	// Build the url_detail spec.
-	
-	var url_detail = su_deserialize_url_command_params(unseen, false);
-	
-//	url_detail.url = "http://media.tumblr.com/mlsyKxOF8fzc9kd1zQ37q9b8o1_500.jpg";
-//	url_detail.urlid = "25624734";
-//	url_detail.tld = su_get_tld(url_detail.url);
-	
-	if (! url_detail)
-	{
-		su_log_error("STUMBLE DESERIALIZE", unseen);
-		clear_stumbles();
-		su_stumble_done_no_stumbles(context);
-		return;
-	}
-	
-	// These shouldn't be served, but it doesn't hurt to do a sanity
-	// check.
-	if ((url_detail.cluster_type != 4) && su_is_domain_blocked(url_detail.tld))
-	{
-		su_enqueue_stumblestats(url_detail);
-		su_load_stumbles(url_detail.url);
-		su_save_stumbles();
-		setTimeout(su_skip_stumble, 0, context);
-		return;
-	}
-	
-//	su_dd("setstumbled", 1, url_detail.url);
-	// Set globals.
-	stumbled_url = url_detail.url;
-	su_redirect_url = url_detail.url;
-//	su_dd("reset", 1);
-	stumbled_redirect = "";
-
-	// Record url details.
-	su_ds.define("url:url_detail", stumbled_url, url_detail);
-	
-//		if (url_detail.affiliate_url)
-//		{
-//			su_prefetch_url(
-//						url_detail.affiliate_url,
-//						su_base_url + "refer.php?url=" + escape(url_detail.affiliate_url),
-//						0);
-//		}
-	
-	// Show the stumble!
-	shown = su_stumble_done_show_stumble(url_detail, context);
-	
-	if (! shown)
-	{
-		su_check_progress_listener();
-		return;
-	}
-	
-	// Note that we still try to keep the count on the client, and just let the server 
-	// override it with SSC after the submission occurs, if necessary.  We are doing this primarily
-	// for testing purposes because the toolbar might be pointed at a server that doesn't yet 
-	// implement SSC and SFC
-	var stumble_count = su_ds.incrementValue("$stumble_count");
-	su_stumble_count_changed();
-	
-	su_enqueue_stumblestats(url_detail);
-	su_log_dd_uc(unseen);
-	
-	if (context.user_cat.indexOf("TAG_") == 0)
-	{
-		var str = context.user_cat.substr(4).toLowerCase();
-		if (su_ds.isThruDomain(str))
-		{
-			var spec = su_ds.getValue("#recent_info_spec");
-			
-			if (spec.domain && spec.domain == str)
-			{
-				if (! su_ds.getValue("$shown_toall_info"))
-					setTimeout(su_display_info, 0, "thru_domain_praise_toall", spec.domain);
-				else if (! su_ds.getValue("$shown_tomore_info")) 
-					setTimeout(su_display_info, 0, "thru_domain_praise_tomore", spec.domain);
-			}
-			
-			su_close_info();
-		}
-	}
-	else if (context.user_cat == "302")
-	{
-		su_ds.setValue("$shown_photo_info", true);
-		
-		var spec = su_ds.getValue("#recent_info_spec");
-		
-		
-		if ((spec.type == "photo") && (! su_ds.getValue("$shown_toall_info")))
-			setTimeout(su_display_info, 0, "photo_praise");
-		
-		su_close_info();
-	}
-	else if (su_is_image_url(url_detail.url) && (! su_ds.getValue("$shown_photo_info")))
-	{
-		setTimeout(su_display_info, 0, "photo");
-		
-		su_close_info();
-	}
-	else
-	{
-		su_close_info();
-	}
-	
-	// Remove the url from our local stumble queue.
-	//!!! We want to do
-	//    - removal from local queue
-	//    - stumbletimes recording
-	//    - referral count decriment
-	//    after both (a) the page loads enough for the user to have
-	//    reviewed content and (b) the user has visited the tab.  But
-	//    detecting those events is a relatively difficult problem. 
-	//    -- JW
-	
-	//!!! Are we removing multiple referrals for the same url? -- JW
-	su_load_stumbles(url_detail.url);
-	su_save_stumbles();
-	
-	// Update topic UI elements.
-	su_update_topic_and_reporting(url_detail, url_detail, url_detail.tld, true, null);
-//	su_update_language(url_detail, true);
-	
-	// Clear old sponsor or firstrater buttons
-//	su_set_visible("su_sponsor", false);
-//	su_set_visible("firstrater", false);
-
-	// If we have a message, display it.
-	if (url_detail.is_friend_referral || url_detail.referral_note)
-	{
-		setTimeout(
-					su_stumble_done_display_message,
-					0,
-					url_detail,
-					context.target_browser);
-	}
-	else if ((stumble_count >= 5) &&
-			((su_ds.getValue("$thumbup_count") + su_ds.getValue("$thumbdown_count")) <= 1) &&
-			(! su_ds.getValue("$shown_rate_info")))
-	{
-		su_display_info("rate");
-	}
-	
-	// If this is a referral, decriment referral count.
-	//!!! May get out of sync if we start sending referrals via the SV 
-	//    page. -- JW
-	if (url_detail.cluster_type == 4)
-		su_decriment_undelivered_count();
-	
-	
-	if ((! context.stumblevideo) && 
-				(stumbled_url.indexOf(su_serverhttp + "first_stumble.php") != 0))
-	{
-		// get unseen url, but don't hit the server to do it
-		su_get_unseen_url(
-					context.user_cat,
-					0,
-					null,
-					null);
-	}
-	
-	su_check_progress_listener();
-	
-	su_register_activity("stumble");
-	
-	} catch (e) { su_log_error("STUMBLE DONE", e); }
-}
-
-function su_is_image_url(url)
-{
-	//!!! Ideally, we should use the content type logic from the
-	// surveyor. -- JW
-	return (url.match(/\.(jpg|jpeg|png|gif)$/) ? true : false);
-}
-
-function su_stumble_done_show_stumble(url_detail, context)
-{
-	try {
-		su_prefetcher.advancePastTarget(stumbled_url);
-	} catch (e) { su_log_error("PREFETCHER 5", e); }
-	
-	var detail = su_get_async_target_browser(
-				context.target_browser,
-				context.new_tab);
-	
-	if (! detail)
-		return false;
-	
-	context.target_browser = detail.target_browser;
-	
-	if (context.target_browser.su_url_detail && context.target_browser.su_url_detail.messageid)
-	{
-		setTimeout(
-				su_close_message,
-				0,
-				context.target_browser.su_url_detail.messageid,
-				true);
-	}
-	
-	context.target_browser.su_url_detail = url_detail;
-	
-	//var referrer = su_base_url + "refer.html";
-	var referrer = su_base_url + "refer.php?url=" + encodeURIComponent(stumbled_url);
-	if (url_detail.referrer)
-		referrer = url_detail.referrer;
-	
-	if (! su_ds.getValue("@enable_refer"))
-		referrer = "about:blank";
-	
-	if (su_is_adult_category(url_detail.catid))
-		referrer = url_detail.url;
-	
-	var postdata = "";
-	if (url_detail.url.indexOf(su_base_url + "signup.php") == 0)
-		postdata = su_get_client_postdata(url_detail.url);
-	
-	var listener = new su_StumbleProgressListener(url_detail, context);
-	try {
-		context.target_browser.addProgressListener(listener);
-	} catch (e) {}
-	
-	//	context.target_browser.su_content_clicked = false;
-	try {
-		context.target_browser.webNavigation.loadURI(
-					url_detail.url,
-					0,
-					su_get_nsiuri(referrer),
-					(postdata == "") ? null : su_get_mime_input_stream(postdata, "application/x-www-form-urlencoded"),
-					null);
-	} catch (e) { su_log_error("LOADURI ERROR4", e, url_detail.url); }
-
-	return true;
-}
-
-function su_enqueue_stumblestats(url_detail)
-{
-	if (!url_detail.publicid)
-		return;
-
-	// Old urlids, don't store, just send
-    var recently_seen = su_ds.getValue("$recently_seen");
-	var seen_urlids;
-	if (recently_seen == "")
-		seen_urlids = new Array();
-	else
-		seen_urlids = recently_seen.split(".");
-    
-    // New format, public ids
-    var recently_seen_publicids = su_ds.getValue("$recently_seen_publicids");
-    var seen_publicids;
-    if(recently_seen_publicids == "")
-        seen_publicids = new Array();
-    else
-        seen_publicids = recently_seen_publicids.split(".");
-
-    // Add this public id to recentlyseen
-    seen_publicids.push(url_detail.publicid);
-    while (seen_publicids.length > 50)
-		seen_publicids.shift();
-	su_ds.setValue("$recently_seen_publicids", seen_publicids.join("."));
-	
-	// Recently seen referral ids
-	var recently_seen_referralids = su_ds.getValue("$recently_seen_referralids");
-	var seen_referralids;
-	if(recently_seen_referralids == "")
-		seen_referralids = new Array();
-	else
-		seen_referralids = recently_seen_referralids.split(".");
-	
-	// Add this referral id to recentlyseen referralids
-	seen_referralids.push(url_detail.referralid);
-	while (seen_referralids.length > 50)
-		seen_referralids.shift();
-	su_ds.setValue("$recently_seen_referralids", seen_referralids.join("."));
-	
-	su_ds.flushPrefs();
-
-	// Add the visited URL details to the visited table
-	su_stumbleReporter.addVisitedUrl(url_detail);
-}
-
-function su_get_async_target_browser(target_browser, new_tab)
-{
-	var detail = new Object();
-	
-	var browser = getBrowser();
-	
-	if (new_tab)
-	{
-		var characterSet = browser.contentDocument.characterSet;
-		try {
-			var tab = browser.addTab(
-						"about:blank",
-						stumbled_url,
-						null,
-						characterSet);
-			detail.target_browser = browser.getBrowserForTab(tab);
-			browser.selectedTab = tab;
-		} catch (e) { su_log_error("ADDTAB ERROR", e, stumbled_url); }
-	}
-	else
-	{
-		var found = false;
-		for (var i = 0; i < browser.browsers.length; i++)
-		{                                                         
-			if (browser.browsers[i] == target_browser)
-			{
-				detail.target_browser = target_browser;
-				found = true;
-				break;
-			}
-		}
-		
-		if (! found)
-		{
-			// Cancel the stumble if, by the time we get here, 
-			// they've closed the tab. -- JW
-			detail = null;
-		}
-	}
-	return detail;
-}
-
-function su_decriment_undelivered_count()
-{
-	// decriment referral count
-	var count = su_ds.getValue("$undelivered_count");
-	count--;
-	su_ds.setValue("$undelivered_count", count);
-	
-	su_update_referred(true);
-
-	setTimeout(su_test, 1000);
-}
-
-function su_test()
-{
-}
-
-function su_stumble_done_no_stumbles(context)
-{
-	var user_cat = context.user_cat + "";
-
-	var detail = su_get_async_target_browser(
-				context.target_browser,
-				context.new_tab);
-	
-	if (! detail)
-		return;
-	
-	var target_browser = detail.target_browser;
-	
-	var target_url;
-	// We couldn't find an unseen url...
-	// Check to make sure this isn't an incat stumble
-	if (user_cat == "0")
-	{
-		// If we got here, we're out of urls, and we're in "Any Topic"
-		//!!! first make sure we are not already here....
-		target_url = su_base_url + "interests.php?out=1"; 
-		
-		target_browser.webNavigation.loadURI(
-					target_url,
-					0,
-					null,
-					su_get_mime_input_stream(
-						su_get_client_postdata(target_url),
-						"application/x-www-form-urlencoded"),
-					null);
-
-		// change icon...
-		su_get_element("su_stumble").image = "chrome://stumbleupon/content/skin/stumble.png";
-
-		return;
-		//!!! eventually we should cycle through "great history" here
-	}
-	
-	var tag = "";
-	var mode = "";
-	var profile = "";
-	if (su_isInt(user_cat))
-	{
-		// mode = incat
-		mode = "incat";
-		su_load_categories();
-		if (typeof(su_catnames[user_cat]) != "undefined")
-			tag = su_catnames[user_cat];
-		else
-			tag = "";
-	}
-	else if (user_cat.indexOf("LANG_") == 0)
-	{
-		mode = "language";
-		tag = su_ds.lookup("lang_code:language", user_cat.substr(5));
-	} 
-	else if (user_cat.indexOf("TAG_") == 0)
-	{
-		mode = "tag";
-		tag = user_cat.substr(4);
-	}
-	else if (user_cat.indexOf("USERTAG_") == 0)
-	{
-		mode = "showfriendtag";
-		var chunk = user_cat.substr(8);
-		chunks = chunk.split('_');
-		var tag = chunks[1];
-		var profile = chunks[0];
-//				alert("tag " + tag + " profile " + profile);
-	}
-	else
-	{
-		if (user_cat == "news")
-		{
-			mode = "news";	
-			tag = "news";
-		}
-		else if (user_cat == "video")
-		{
-			mode = "video";	
-			tag = "video";
-		}
-		else if (user_cat == "friends")
-		{
-			mode = "friends";	
-			tag = "friends";
-		}
-		else if (user_cat == "wiki")
-		{
-			mode = "wiki";
-			tag = "wiki";
-		}
-		else
-		{
-			mode = "showfriend";	
-			profile = user_cat;
-		}
-	}	
-	
-	target_url = su_base_url + "explore.php?mode=" + mode;
-	if (tag != "")
-		target_url += "&tag=" + tag.toLowerCase();
-	if (profile != "")
-		target_url += "&showfriend=" + profile.toLowerCase();
-	if (mode == "incat")
-		target_url += "&topic=" + user_cat;
-		
-	// User is doing an incat stumble
-	// Set user_cat to 0
-	su_set_mode_all();
-	// Give them a message explaining they have run out in their particular cat.
-
-	// grab the current HTML window
-		
-	target_browser.webNavigation.loadURI(
-				target_url,
-				0,
-				null,
-				su_get_mime_input_stream(
-					su_get_client_postdata(target_url),
-					"application/x-www-form-urlencoded"),
-				null);
-
-	// change icon...
-	su_get_element("su_stumble").image = "chrome://stumbleupon/content/skin/stumble.png";
-}
-
-
-
-// used by a timeout to ensure that the stumble button icon returns
-// to vertical within 15 seconds
-function su_reset_stumble_action_indicator(stumble_action_id)
-{
-	if (stumble_action_id == su_stumble_action_count)
-		su_get_element("su_stumble").image="chrome://stumbleupon/content/skin/stumble.png";
-}
-
-// used load_data2
-function su_check_referral(force_update)
-{
-	if (stumbleid == 0)
-		return;
-	
-	var check_now = force_update;
-
-	if (su_check_referral_timer)
-	{
-		// if the user changes, this clears the timeout set for the
-		// previously logged in user
-		clearTimeout(su_check_referral_timer);
-	}
-	
-	var state = su_ds.getValue("$poll_state");
-	var interval = su_ds.lookup("state:poll_interval_s", state);
-	var poll_time_s = su_ds.getIntValue("$poll_time_s");
-	var now_s = su_get_time_s();
-	var elapsed = now_s - poll_time_s;
-	if (elapsed >= interval)
-		check_now = true;
-	
-	if (check_now)
-	{
-		elapsed = 0;
-		// advance state
-		var new_state = null;
-		switch (state)
-		{
-			case "b": new_state = "c"; break;
-			case "c": new_state = "d"; break;
-			case "d": new_state = "e"; break;
-			case "e": new_state = "f"; break;
-			case "a":
-			case "f":
-			case "g":
-				var activity_time_s = su_ds.getIntValue("$activity_time_s");
-				if (activity_time_s == 0)
-					activity_time_s = now_s;
-				
-				var idle_interval = now_s - activity_time_s;
-				if (idle_interval > (3600 * 24 * 60))
-					new_state = "h";
-				else if (idle_interval > (3600 * 24 * 10))
-					new_state = "g";
-				break;
-		}
-		
-		if (new_state)
-		{
-			su_ds.setValue("$poll_state", new_state);
-			interval = su_ds.lookup("state:poll_interval_s", new_state);
-		}
-		
-		su_ds.setValue("$poll_time_s", now_s);
-		
-		var context = new su_AsyncContext();
-		context.quiet = true;
-		context.user_cat = 0;
-		
-		su_update_url_cache(
-					0,
-					true, // check_referral
-					su_check_referral_done,
-					context);
-	}
-	
-	su_check_referral_timer = setTimeout(su_check_referral, ((interval - elapsed) * 1000), false);
-}
-
-function su_register_activity(type)
-{
-	if (stumbleid == 0)
-		return;
-	
-	su_ds.setValue("$activity_time_s", su_get_time_s());
-	
-	var state = su_ds.getValue("$poll_state");
-	var new_state = state;
-	switch (type)
-	{
-		case "referred":
-			if (state == "a" || state == "g" || state == "h")
-				new_state = "f";
-			break;
-		case "referral":
-			if (state == "a" || state == "d" || state == "e" || state == "g" || state == "h")
-				new_state = "b";
-			break;
-		case "stumble":
-		case "rate":
-		case "message-notify":
-			if (state == "g" || state == "h")
-				new_state = "a";
-			break;
-	}
-	
-	if (new_state != state)
-	{
-		su_ds.setValue("$poll_state", new_state);
-		su_check_referral(false);
-	}
-}
-
-function su_check_referral_done(error)
-{
-	if (error == "connection error")
-		setTimeout(su_check_referral_retry, 10000);
-}
-
-function su_check_referral_retry()
-{
-	// Retry once.  This mostly caters to DSL users who have to wait
-	// for the modem to reconnect. -- JW
-	var context = new su_AsyncContext();
-	context.quiet = true;
-	context.user_cat = 0;
-	
-	su_update_url_cache(
-				0,
-				true, // check_referral
-				null,
-				context);
-}
-
-function su_show_searchlinks_dialog(new_user_prompt, new_tab, stumble)
-{
-	var intro_count = su_ds.getValue("$intro_count");
-	if ((intro_count == 0) || ((intro_count % 15) != 0)) return false;
-	if (su_ds.getValue("$shown_searchlinks_dialog")) return false;
-	su_ds.setValue("$shown_searchlinks_dialog", true);
-	if (su_ds.getValue("$show_searchlinks_score")) return false;
-	if (su_ds.getValue("$show_searchlinks_friends")) return false;
-	if (su_ds.getValue("$show_searchlinks_topic")) return false;
-	window.setTimeout(su_show_searchlinks_dialog_wrapped, 100, new_user_prompt, new_tab, stumble);
-	return true;
-}
-
-function su_show_searchlinks_dialog_wrapped(new_user_mode, new_tab, stumble)
-{
-	var detail = new Object();
-	var filename;
-	var social = su_ds.hasFeature("$sociallinks");
-	if (social && new_user_mode)
-		filename = "social_searchlinks_newuser_prompt.gif";
-	else if (social)
-		filename = "social_searchlinks_prompt.gif";
-	else if (new_user_mode)
-		filename = "searchlinks_newuser_prompt.gif";
-	else
-		filename = "searchlinks_prompt.gif";
-	
-	if (new_user_mode)
-		detail.preview_serp_url = "http://www.google.com/search?q=StumbleUpon";
-	else
-		detail.preview_serp_url = null;
-	detail.new_tab = new_tab;
-	detail.prompt_filename = filename;
-	detail.stumble = stumble;
-	
-	su_ds.installResource(
-				"http://cdn.stumble-upon.com/images/" + filename,
-				"images",
-				filename);
-	
-	su_searchlinks_dialog_detail = detail;
-}
-
-function su_handle_searchlinks_dialog_resource_load(detail)
-{
-	detail.prompt_src = su_ds.getResourceURLFromName(
-				"images",
-				detail.prompt_filename);
-
-	window.openDialog(
-				"chrome://stumbleupon/content/searchlinksDialog.xul",
-				"",
-				"chrome,dialog,centerscreen,dependent,close=no",
-				detail);
-}
-
-function su_handle_searchlinks_dialog_close(detail)
-{
-	if (detail.result == "cancel-error")
-	{
-		detail.result = "";
-	
-		window.openDialog(
-					"chrome://stumbleupon/content/searchlinksDialog.xul",
-					"",
-					"chrome,dialog,centerscreen,dependent,close=no",
-					detail);
-	}
-	else if (detail.result == "yes")
-	{
-		su_ds.setValue("$show_searchlinks_score", true);
-		su_ds.setValue("$show_searchlinks_friends", true);
-		su_ds.setValue("$shown_searchlinks", true);
-		su_ds.flushPrefs();
-		
-		if (detail.preview_serp_url)
-		{
-			// The timeout and the su_ds.flushPrefs() above work around an 
-			// intermittent timing issue where the link behavior isn't
-			// enabled in time for searchlinks to appear in the demo. -- JW
-			setTimeout(
-						su_set_location,
-						150,
-						detail.preview_serp_url,
-						null, 
-						detail.new_tab);
-		}
-	}
-	else
-	{
-		su_ds.setValue("$show_searchlinks_score", false);
-		su_ds.setValue("$show_searchlinks_friends", false);
-		su_ds.setValue("$show_searchlinks_topic", false);
-	}
-}
-
-function su_check_show_position_dialog()
-{
-	if(su_ds.getValue("$shown_position_dialog")) return false;
-	su_ds.setValue("$shown_position_dialog", true);
-	if(su_ds.getValue("@toolbar-position") != su_ds.getDefaultValue("@toolbar-position")) return false;
-	if(su_ds.getValue("$stumble_count") < 5) return false;
-
-	var detail = new Object();
-	window.openDialog(
-				"chrome://stumbleupon/content/positionDialog.xul",
-				"",
-				"chrome,dialog,centerscreen,dependent,close=no",
-				detail);
-	return true;
-}
-
-function su_handle_position_dialog_close(detail)
-{
-	if (detail.result == "cancel-error")
-	{
-		detail.result = "";
-	
-		window.openDialog(
-					"chrome://stumbleupon/content/positionDialog.xul",
-					"",
-					"chrome,dialog,centerscreen,dependent,close=no",
-					detail);
-	}
-	else if (detail.result == "yes")
-	{
-		su_move_to_bookmark_bar();
-	}
-}
-
-function su_stumble_done_display_message(url_detail, target_browser)
-{
-	//!!! test in FF 1.5, Seamonkey, Flock
-	var box = target_browser.parentNode;
-	
-	var messageid = su_ds.incrementValue("~message_count");
-	
-	target_browser.su_url_detail.messageid = messageid;
-	
-	// This stack prevents reflow of the banner content upon show/hide.
-	// We could reuse it, but there's no compelling reason to. -- JW
-	var stack = document.createElement("stack");
-	
-	var outerbox = document.createElement("vbox");
-	var outerbox_id = "su_messageOuterBox" + messageid;
-	outerbox.setAttribute("id", outerbox_id);
-	outerbox.style.position = "fixed";
-	outerbox.style.top = "100%";
-	if (su_host.mac)
-		outerbox.setAttribute("class", "su_pinstripe_bannerBox outset");
-	else
-		outerbox.setAttribute("class", "su_winstripe_bannerBox outset");
-	
-	stack.appendChild(outerbox);
-	
-	var grid = document.createElement("grid");
-	grid.setAttribute("flex", "1");
-	outerbox.appendChild(grid);
-	var columns = document.createElement("columns");
-	grid.appendChild(columns);
-	var el;
-	el = document.createElement("column");
-	columns.appendChild(el);
-	el = document.createElement("column");
-	el.setAttribute("flex", "1");
-	columns.appendChild(el);
-	el = document.createElement("column");
-	columns.appendChild(el);
-	var rows = document.createElement("rows");
-	rows.setAttribute("flex", "1");
-	grid.appendChild(rows);
-	
-	var firstrow = document.createElement("row");
-	if (su_host.mac)
-		firstrow.setAttribute("class", "su_pinstripe_bannerInnerBox");
-	rows.appendChild(firstrow);
-	
-	var hboxaa = document.createElement("hbox");
-	hboxaa.setAttribute("align", "center");
-	firstrow.appendChild(hboxaa);
-	
-	el = document.createElement("image");
-	el.setAttribute("src", su_get_message_icon_src(url_detail));
-	el.setAttribute("class", "su_bannerImage");
-	if (! url_detail.is_system_referral)
-	{
-		el.setAttribute("style", "cursor: pointer;");
-		el.setAttribute("onclick", "su_handle_message_sender_click(event, " + messageid + ")");
-	}
-	hboxaa.appendChild(el);
-	el = document.createElement("label");
-	el.setAttribute("value", url_detail.sender);
-	if (! url_detail.is_system_referral)
-	{
-		el.setAttribute("style", "color: rgb(0,0,238); text-decoration: underline; margin-right:0; cursor: pointer;");
-		el.setAttribute("onclick", "su_handle_message_sender_click(event, " + messageid + ")");
-	}
-	hboxaa.appendChild(el);
-	el = document.createElement("label");
-	el.setAttribute("style", "margin-left: 0");
-	el.setAttribute("value", su_get_message_label(url_detail));
-	hboxaa.appendChild(el);
-
-	var hboxab = document.createElement("hbox");
-	hboxab.setAttribute("flex", "1");
-	hboxab.setAttribute("align", "center");
-	firstrow.appendChild(hboxab);
-
-	messagedeck = document.createElement("deck");
-	messagedeck.setAttribute("flex", "1");
-	messagedeck.setAttribute("align", "center");
-	hboxab.appendChild(messagedeck);
-	
-	el = document.createElement("textbox");
-	el.setAttribute("id", "su_bannerLineTextbox" + messageid);
-	el.setAttribute("multiline", "false");
-	el.setAttribute("value", "");
-	el.setAttribute("readonly", "true");
-	el.setAttribute("hidden", "true");
-	if (su_host.mac)
-		el.setAttribute("class", "su_pinstripe_bannerMessage");
-	else
-		el.setAttribute("class", "su_winstripe_bannerMessage");
-	messagedeck.appendChild(el);
-	
-	el = document.createElement("textbox");
-	el.setAttribute("id", "su_bannerMultilineTextbox" + messageid);
-	el.setAttribute("multiline", "true");
-	el.setAttribute("value", "");
-	el.setAttribute("readonly", "true");
-	el.setAttribute("hidden", "true");
-	if (su_host.mac)
-		el.setAttribute("class", "su_pinstripe_bannerMessage");
-	else
-		el.setAttribute("class", "su_winstripe_bannerMessage");
-	messagedeck.appendChild(el);
-
-	el = document.createElement("description");
-	el.setAttribute("id", "su_bannerTextMeasurer" + messageid);
-	el.setAttribute("flex", "1");
-	el.setAttribute("crop", "end");
-	el.setAttribute("style", "margin-left: 8px; margin-right: 8px;");
-	messagedeck.appendChild(el);
-
-	if (url_detail.is_friend_referral)
-	{
-		el = document.createElement("button");
-		el.setAttribute("id", "su_bannerReplyButton" + messageid);
-		el.setAttribute("label", "Reply Now");
-		el.setAttribute("accesskey", "R");
-		el.setAttribute("oncommand", "su_handle_message_reply_command(" + messageid + ")");
-		hboxab.appendChild(el);
-	}
-	el = document.createElement("spacer");
-	el.setAttribute("flex", "1000");
-	hboxab.appendChild(el);
-	
-	el = document.createElement("button");
-	el.setAttribute("id", "su_bannerReloadButton" + messageid);
-	if (url_detail.is_friend_referral || url_detail.is_system_referral)
-		el.setAttribute("label", "Reload Sent Page");
-	else
-		el.setAttribute("label", "Reload Stumbled Page");
-	el.setAttribute("accesskey", "L");
-	el.setAttribute("disabled", "true");
-	el.setAttribute("oncommand", "su_handle_message_reload_command(" + messageid + ")");
-	hboxab.appendChild(el);
-
-	var elac = document.createElement("toolbarbutton");
-	if (su_host.mac)
-		elac.setAttribute("class", "su_pinstripe_messageCloseButton");
-	else
-		elac.setAttribute("class", "su_winstripe_messageCloseButton");
-	elac.setAttribute("oncommand", "su_handle_message_close_command(" + messageid + ")");
-	firstrow.appendChild(elac);
-	
-	var secondrow = document.createElement("row");
-	secondrow.setAttribute("id", "su_messageSendRow" + messageid); 
-	secondrow.setAttribute("hidden", "true");
-	rows.appendChild(secondrow);
-	
-	var hboxba = document.createElement("hbox");
-	hboxba.setAttribute("pack", "end");
-	hboxba.setAttribute("align", "center");
-	secondrow.appendChild(hboxba);
-	
-	el = document.createElement("label");
-	el.setAttribute("value", "Reply:");
-	hboxba.appendChild(el);
-	
-	var hboxbb = document.createElement("hbox");
-	hboxbb.setAttribute("flex", "1");
-	secondrow.appendChild(hboxbb);
-	
-	el = document.createElement("textbox");
-	el.setAttribute("flex", "1");
-	el.setAttribute("id", "su_messageTextbox" + messageid);
-	el.setAttribute("class", "su_messageTextbox");
-	el.setAttribute("maxlength", 5000);
-	el.setAttribute("onkeypress", "su_handle_message_keypress(event, " + messageid + ")");
-	hboxbb.appendChild(el);
-	el = document.createElement("button");
-	el.setAttribute("label", "Send");
-	el.setAttribute("accesskey", "S");
-	el.setAttribute("oncommand", "su_handle_message_send_command(" + messageid + ")");
-	hboxbb.appendChild(el);
-	el = document.createElement("button");
-	el.setAttribute("label", "Cancel");
-	el.setAttribute("accesskey", "C");
-	el.setAttribute("oncommand", "su_handle_message_cancel_command(" + messageid + ")");
-	hboxbb.appendChild(el);
-	
-	box.insertBefore(stack, target_browser);
-	
-	if (url_detail.referral_note)
-	{
-		var measurer = su_get_element("su_bannerTextMeasurer" + messageid);
-		measurer.textContent = url_detail.referral_note + "  ";
-
-		su_set_drawer_open(
-			outerbox_id,
-			true,
-			su_init_message_textbox,
-			messageid);
-	}
-	else
-	{
-		su_set_drawer_open(outerbox_id, true, null);
-	}
-}
-
-function su_init_message_textbox(messageid)
-{
-	var target_browser = null;
-	var browsers = getBrowser().browsers;
-	for (i = 0; i < browsers.length; i++)
-	{
-		if (browsers[i].su_url_detail && browsers[i].su_url_detail.messageid &&
-					(browsers[i].su_url_detail.messageid == messageid))
-		{
-			target_browser = browsers[i];
-			break;
-		}
-	}
-	
-	var measurer = target_browser.ownerDocument.getElementById("su_bannerTextMeasurer" + messageid);
-	var height = measurer.boxObject.height; 
-	var line_count = Math.round(height / 17);
-	if (line_count > 1)
-	{
-		target_browser.ownerDocument.getElementById("su_bannerLineTextbox" + messageid).hidden = true;
-		var textbox = target_browser.ownerDocument.getElementById("su_bannerMultilineTextbox" + messageid);
-		textbox.setAttribute("rows", line_count - 1);
-		textbox.setAttribute("height", (height + 5) + "px");
-		textbox.value = target_browser.su_url_detail.referral_note;
-		textbox.hidden = false;
-	}
-	else
-	{
-		var width = measurer.boxObject.width;
-		var textbox = target_browser.ownerDocument.getElementById("su_bannerLineTextbox" + messageid);
-		textbox.setAttribute("width", (width + 10) + "px");
-		textbox.value = target_browser.su_url_detail.referral_note;
-		textbox.hidden = false;
-	}
-}
-
-function su_get_message_icon_src(url_detail)
-{
-	var src;
-	if (url_detail.is_friend_referral)
-	{
-		var contact = su_ds.selectRow("contact", "nickname", url_detail.sender);
-		if (! contact)
-			contact = su_ds.selectRow("contact", "contactid", url_detail.sender);
-		
-		if (contact && contact.contactid)
-		{
-			var filename = contact.contactid + ".jpg";
-			
-			if (su_ds.isResourceInstalled("iconpics", filename))
-				src = su_ds.getResourceURLFromName("iconpics", filename);
-			else
-				src = "http://cdn.stumble-upon.com/iconpics/" + filename;
-			
-			su_ds.refreshAvatar(contact.contactid);
-		}
-		else
-		{
-			src = "chrome://stumbleupon/content/skin/arrow.png";
-		}
-	}
-	else if (url_detail.is_system_referral)
-	{
-		src = "chrome://stumbleupon/content/skin/arrow.png";
-	}
-	else
-	{
-		src = "chrome://stumbleupon/content/skin/bubble3.png";
-	}
-	return src;
-}	
-
-function su_get_message_label(url_detail)
-{
-	var label = "";
-	if (url_detail.is_friend_referral || url_detail.is_system_referral)
-	{
-		if (url_detail.referral_note)
-			label += " says:"; 
-		else
-			label += " sent you this page";
-	}
-	else if (url_detail.referral_note)
-	{
-		label += " reviewed saying:";
-	}
-	
-	return label;
-}
-
-function su_handle_message_sender_click(event, messageid)
-{
-	var url_detail = su_get_message_url_detail(messageid);
-	var new_tab = true;
-	if (su_ds.getValue("$sender_click_platform"))
-		new_tab = su_new_tab(event);
-	su_set_location(
-				"http://" + url_detail.sender + "." + su_servername + "/",
-				null,
-				new_tab);
-}
-
-function su_handle_message_keypress(event, messageid)
-{
-	if (event.keyCode != KeyEvent.DOM_VK_RETURN)
-		return;
-	
-	su_send_reply_message(messageid);
-}
-
-function su_handle_message_reply_command(messageid)
-{
-	su_get_element("su_bannerReplyButton" + messageid).disabled = true;	
-	su_get_element("su_messageSendRow" + messageid).hidden = false;
-	setTimeout(
-				function (messageid) {
-					su_get_element("su_messageTextbox" + messageid).focus(); },
-				0,
-				messageid);
-}
-
-function su_handle_message_reload_command(messageid)
-{
-	var browser = su_get_message_browser(messageid);
-	var url_detail = su_get_message_url_detail(messageid);
-	
-	su_set_location(
-				url_detail.url,
-				null,
-				false);
-}
-
-function su_get_message_browser(messageid)
-{
-	return su_get_element("su_messageOuterBox" + messageid).parentNode.nextSibling;
-}
-
-function su_get_message_url_detail(messageid)
-{
-	return su_get_message_browser(messageid).su_url_detail;
-}
-
-function su_handle_message_cancel_command(messageid)
-{
-	su_get_element("su_bannerReplyButton" + messageid).disabled = false;	
-	su_get_element("su_messageSendRow" + messageid).hidden = true;
-}
-
-function su_handle_message_send_command(messageid)
-{
-	su_send_reply_message(messageid);
-}
-
-function su_send_reply_message(messageid)
-{
-	var url_detail = su_get_message_url_detail(messageid);
-	var note = su_get_element("su_messageTextbox" + messageid).value;
-	note = su_trim(note);
-	if (note == "")
-	{
-		alert("The reply is blank.");
-		return;
-	}
-	
-	var url = su_get_browser_url();
-	
-	var params = "";
-	
-	params = su_arp(params, "url", url);
-	params = su_arp(params, "friend", url_detail.sender);
-	params = su_arp(params, "note", note);
-	params = su_arp(params, "referer", su_get_browser_referrer_url())
-	
-	var cmp_url = su_get_browser_url(null, true);
-	if ((cmp_url.indexOf("http://video." + su_servername + "/#p") == 0) ||
-			(cmp_url.indexOf("http://video." + su_servername + "/?p") == 0))
-		params = su_arp(params, "videoperma", 1);
-	
-	su_post_url_server_async(
-			"referral.php",
-			params,
-			15000,
-			su_generic_done);
-	
-	var contact = su_ds.selectRow("contact", "nickname", url_detail.sender);
-	if (contact && contact.contactid)
-		su_ds.refreshAvatar(contact.contactid);
-	
-	su_close_message(messageid, true);
-
-	su_increment_sendto("friend", url_detail.sender);
-	su_register_activity("referral");
-	
-	var contact = su_ds.selectRow("contact", "nickname", url_detail.sender);
-	if (contact && contact.contactid)
-		su_ds.refreshAvatar(contact.contactid);
-	su_refresh_referral_menu(5);
-}
-
-function su_handle_message_close_command(messageid)
-{
-	su_close_message(messageid, true);
-}
-
-function su_close_message(messageid, animate)
-{
-	var id = "su_messageOuterBox" + messageid;
-	var el = su_get_element(id);
-	if (! el)
-		return;
-	
-	if (animate)
-	{
-		su_set_drawer_open(
-					id,
-					false,
-					function () { el.parentNode.removeChild(el); });
-	}
-	else
-	{
-		el.parentNode.removeChild(el);
-	}
-}
-
-// called upon logout
-function su_close_all_messages()
-{
-	var browsers = getBrowser().browsers;
-	var i;
-	var url_detail;
-	for (i = 0; i < browsers.length; i++)
-	{
-		var browser = browsers[i];
-		
-		if (! browser.su_url_detail)
-			continue;
-		
-		url_detail = browser.su_url_detail;
-		
-		delete browser.su_url_detail;
-		
-		if (! url_detail.messageid)
-			continue;
-		
-		var id = "su_messageOuterBox" + url_detail.messageid;
-		var el = su_get_element(id);
-		if (el)
-			el.parentNode.removeChild(el);
-	}
-}
-
-// [kudos:] This xul-specific sliding code is derived from the
-// _showNotification method of the Firefox notificationbox widget in
-// source file mozilla/toolkit/content/widgets/notification.xml.
-function su_set_drawer_open(id, state, callback, messageid)
-{
-	var el = su_get_element(id);
-	var height = el.boxObject.height;
-	var steps = 4;
-	var delta = height / steps;
-	var opacity_delta = 1 / steps;
-	
-	if (state)
-	{
-		el.style.removeProperty("position");
-		el.style.removeProperty("top");
-		el.style.marginTop = -height + "px";
-		el.style.opacity = 0;
-	}
-	else
-	{
-		delta = -delta;
-		opacity_delta = -opacity_delta;
-	}
-	
-	var slide = function (callback, messageid)
-	{
-		var done = false;
-		var style = window.getComputedStyle(el, null);
-		var margin = style.getPropertyCSSValue("margin-top").
-					getFloatValue(CSSPrimitiveValue.CSS_PX);
-
-		if (delta > 0 && margin + delta >= 0)
-		{
-			el.style.marginTop = "0px";
-			el.style.opacity = 1;
-			done = true;
-		}
-		else if (delta < 0 && margin + delta <= -height)
-		{
-			el.style.marginTop = -height + "px";
-			done = true;
-		}
-		else
-		{
-			el.style.marginTop = (margin + delta).toFixed(4) + "px";
-			el.style.opacity = Number(el.style.opacity) + opacity_delta;
-		}
-
-		if (done)
-		{
-			clearInterval(su_drawer_timers[id]);
-			delete su_drawer_timers[id];
-			if (callback)
-				setTimeout(callback, 100, messageid);
-		}
-	}
-	
-	su_drawer_timers[id] = setInterval(slide, 50, callback, messageid);
-}
-
-function su_display_info(info_type, optDomain)
-{
-	if (! su_host.ff3plus)
-		return;
-	
-	if (! su_ds.getValue("$show_tutorial_info"))
-		return;
-
-	if ((! su_ds.hasFeature("$info_tutorial")) && (! su_test_info))
-		return;
-	
-	// display info only if the toolbar is in default position
-	if (su_ds.getValue("@toolbar-position") != "stumbleupon")
-		return;
-	
-	if (! su_ds.getValue("@toolbar-visible"))
-		return;
-	
-	// close the info if we change thru domain
-	if (su_info_spec && optDomain && su_info_spec.domain && (su_info_spec.domain != optDomain))
-	{
-		su_close_info();
-		return;
-	}
-	
-	// Show only one info bubble per day.
-	var now_s = su_get_time_s();
-	var min_interval = 4 * 3600; // 4 hours
-	var time_s = su_ds.getIntValue("$info_time_s"); 
-
-	var spec = new Object();
-	
-	spec.closed = false;
-	spec.type = info_type;
-	spec.shown_interval_s = 0;
-	spec.shown_time_s = null;
-	
-	switch (info_type)
-	{
-		case "rate":			
-			if ((time_s && ((now_s - time_s) < min_interval)) && (! su_test_info))
-				return;
-			spec.bubble_offset = (su_host.win) ? 0 : 2;
-			spec.leader_offset = (su_host.win) ? -2 : 0;
-			spec.target_id = "su_thumbup";
-			spec.shown_pref = "$shown_rate_info";
-			spec.message = "Friendly reminder:  If you rate pages as you go, the toolbar learns what you like and delivers more.";
-			break;
-		case "reviews":
-			if ((time_s && ((now_s - time_s) < min_interval)) && (! su_test_info))
-				return;
-			spec.bubble_offset = 7;
-			spec.leader_offset = 5;
-			spec.target_id = "su_website_info";
-			spec.shown_pref = "$shown_reviews_info";
-			spec.message = "Tip: The Reviews button lets you see what other Stumblers think of this site.";
-			break;
-		case "referral":
-			if ((time_s && ((now_s - time_s) < min_interval)) && (! su_test_info))
-				return;
-			spec.bubble_offset = (su_host.win) ? 0 : 2;
-			spec.leader_offset = (su_host.win) ? -2 : 0;
-			spec.target_id = "su_referral_menu";
-			spec.shown_pref = "$shown_referral_info";
-			spec.message = "Tidbit: You can share a good website with friends or any email address.";
-			break;
-		case "thru_domain":
-			if ((time_s && ((now_s - time_s) < min_interval)) && (! su_test_info))
-				return;
-			spec.bubble_offset = (su_host.win) ? 5 : 7;
-			spec.leader_offset = (su_host.win) ? 3 : 5;
-			spec.domain = optDomain;
-			spec.target_id = "su_mode_domain";
-			spec.shown_pref = null;
-			if (su_ds.getValue("$shown_thru_domain_info_count"))
-				spec.message = su_ds.lookup("domain:info_message", optDomain);
-			else
-				spec.message = su_ds.lookup("domain:info_message_simple", optDomain);
-			if (! spec.message)
-				spec.message = "Click here to Stumble thru " + su_ds.getThruDomainChannel(optDomain).name + ".";
-			break;
-		case "photo":
-			if ((time_s && ((now_s - time_s) < min_interval)) && (! su_test_info))
-				return;
-			spec.bubble_offset = (su_host.win) ? 5 : 7;
-			spec.leader_offset = (su_host.win) ? 3 : 5;
-			spec.target_id = "su_mode_photo";
-			spec.shown_pref = "$shown_photo_info";
-			spec.message = "Tip: You can discover more of the web's best images in the Photos channel.";
-			break;
-		case "video":
-			
-			break;
-		case "photo_praise":
-			spec.bubble_offset = (su_host.win) ? 5 : 7;
-			spec.leader_offset = (su_host.win) ? 3 : 5;
-			spec.target_id = "su_mode_all";
-			spec.shown_pref = "$shown_toall_info";
-			spec.message = "Enjoy the photos!  The globe button changes back to the 'All' channel.";
-			su_close_info();
-			setTimeout(su_refresh_info, 3000);
-			break;
-		case "thru_domain_praise_toall":
-			spec.bubble_offset = (su_host.win) ? 5 : 7;
-			spec.leader_offset = (su_host.win) ? 3 : 5;
-			spec.target_id = "su_mode_all";
-			spec.shown_pref = "$shown_toall_info";
-			spec.message = "Have fun with " + su_ds.getThruDomainChannel(optDomain).name + " pages!  The globe button changes back to the 'All' channel.";
-			su_close_info();
-			setTimeout(su_refresh_info, 3000);
-			break;
-		case "thru_domain_praise_tomore":
-			spec.bubble_offset = (su_host.win) ? 0 : 2;
-			spec.leader_offset = (su_host.win) ? -2 : 0;
-			spec.domain = optDomain;
-			spec.target_id = "su_mode_more";
-			spec.shown_pref = "$shown_tomore_info";
-			spec.message = null; // overridden
-			su_close_info();
-			setTimeout(su_refresh_info, 3000);
-			break;
-		default:
-			return;
-	}
-	
-	su_info_spec = spec;
-	su_ds.setValue("#recent_info_spec", spec);
-	
-	try {
-		su_refresh_info();
-	} catch (e) { su_log_error("REFRESH INFO", e); } 
-}
-
-function su_refresh_info()
-{
-	var toolbar = su_get_element("su_info_toolbar");
-	if (! su_info_spec)
-	{
-		toolbar.collapsed = true;
-		return;
-	}
-	
-	var spec = su_info_spec;
-	var target_el = su_get_element(spec.target_id);
-	
-	if ((target_el.boxObject.width == 0) || spec.closed)
-	{
-		su_hide_info();
-		return;
-	}
-	
-	
-	// record the 'shown info' event
-	
-	var i;
-	var found;
-	var first_thru_domain = false;
-	if (spec.shown_pref)
-	{
-		su_ds.setValue(spec.shown_pref, true);
-	}
-	else if (spec.type == "thru_domain")
-	{
-		var domains = su_ds.getValue("$shown_thru_domain_info_list").split(":");
-		if (domains.length)
-		{
-			found = false;
-			for (i = 0; i < domains.length; i++)
-			{
-				if (domains[i] == spec.domain)
-					found = true;
-			}
-			
-			if (! found)
-			{
-				var count = su_ds.incrementValue("$shown_thru_domain_info_count");
-				if (count == 1)
-				{
-					su_ds.setValue("$shown_thru_domain_info_list", spec.domain);
-				}
-				else
-				{
-					domains.push(spec.domain);
-					su_ds.setValue("$shown_thru_domain_info_list", domains.join(":"));
-				}	
-			}
-		}	
-		else
-		{
-			su_ds.incrementValue("$shown_thru_domain_info_count");
-			su_ds.setValue("$shown_thru_domain_info_list", spec.domain);
-		}
-	}
-
-	var now_s = su_get_time_s();
-	
-	su_ds.setValue("$info_time_s", now_s);
-	
-	su_ds.flushPrefs();
-	
-	spec.shown_time_s = now_s;
-	
-	// If an old container exists, fix the toolbar height to avoid
-	// collapse/reflow upon browser resize.  Then nuke the old
-	// container.  
-	
-	var container = su_get_element("su_info_container");	
-
-	if (container)
-	{
-		toolbar.style.height = toolbar.boxObject.height + "px";
-		toolbar.removeChild(container);
-	}	
-	
-	
-	// construct the speech bubble
-	
-	var x = target_el.boxObject.screenX - toolbar.boxObject.screenX + Math.round(target_el.boxObject.width / 2);
-	
-	var el;
-	var vbox;
-	var hbox;
-	var text;
-	var style;
-	var vbox;
-	var content_el;
-	
-	container = document.createElement("hbox");
-	container.setAttribute("id", "su_info_container");
-	container.setAttribute("style", "position: absolute; height: 0; width: 0; margin-bottom: 2px;");
-	toolbar.appendChild(container);
-	
-	var bubble_outerbox = document.createElement("hbox");
-	style = "position: absolute; left: " + (x + spec.bubble_offset) + "px; top: 1px;";
-	bubble_outerbox.setAttribute("style", style);
-	container.appendChild(bubble_outerbox);
-	
-	var bubble_midbox = document.createElement("hbox");
-	bubble_outerbox.appendChild(bubble_midbox);
-	
-	var bubble = document.createElement("hbox");
-	style = "border-color: rgb(247,182,0); border-style: solid; border-width: 3px; font-weight: normal; font-size: 12pt; color: black; background-color: rgb(255,255,189); -moz-border-radius-topright: 15px; -moz-border-radius-bottomright: 15px; -moz-border-radius-bottomleft: 15px; -moz-border-radius-topleft: 15px; padding-top: 2px; padding-bottom: 2px; padding-left: 15px; padding-right: 12px;";
-	bubble.setAttribute("id", "su_info_bubble");
-	bubble.setAttribute("style", style);
-	if (su_host.mac)
-		bubble.setAttribute("class", "su_pinstripe_infoMessage");
-	else
-		bubble.setAttribute("class", "su_winstripe_infoMessage");
-	bubble_midbox.appendChild(bubble);
-	
-	vbox = document.createElement("vbox");
-	bubble_midbox.appendChild(vbox);
-	
-	el = document.createElement("spacer");
-	el.setAttribute("flex", "1");
-	vbox.appendChild(el);
-	
-	var optout = document.createElement("checkbox");
-	optout.setAttribute("label", "Show tips");
-	optout.setAttribute("checked", su_ds.getValue("$show_tutorial_info"));
-	optout.setAttribute("style", "margin-left: 15px;");
-	optout.setAttribute("hidden", "true");
-	optout.setAttribute("oncommand", "su_handle_info_optout_command(this)");
-	vbox.appendChild(optout);
-	
-	var bubble_hbox = document.createElement("hbox");
-	bubble.appendChild(bubble_hbox);
-
-	// construct bubble content
-	switch (spec.type)
-	{
-		case "thru_domain_praise_tomore":
-			vbox = document.createElement("vbox");
-			vbox.setAttribute("pack", "top");
-			bubble_hbox.appendChild(vbox);
-			content_el = document.createElement("label");
-			if (su_host.win)
-				content_el.setAttribute("style", "margin-right: 20px; font-size: 17px;");
-			else
-				content_el.setAttribute("style", "margin-right: 20px; font-size: 15px;");
-			vbox.appendChild(content_el);
-			var seq = su_ds.lookup("domain:tomore_favicon_list", spec.domain);
-			if (seq)
-			{
-				text = document.createTextNode("Have fun with " + su_ds.getThruDomainChannel(spec.domain).name + " pages! You can StumbleThru this and other websites ");
-				content_el.appendChild(text);
-				var domains = seq.split(",");
-				for (i = 0; i < domains.length; i++)
-				{
-					hbox = document.createElement("hbox");
-					hbox.setAttribute("style", "padding-right:4px;");
-					content_el.appendChild(hbox);
-					if (i == 0)
-					{
-						text = document.createTextNode("(");
-						hbox.appendChild(text);
-					}
-					vbox = document.createElement("vbox");
-					if (i == 0)
-						vbox.setAttribute("style", "padding-top:2px; padding-left:2px;");
-					else
-						vbox.setAttribute("style", "padding-top:2px;");
-					hbox.appendChild(vbox);
-					el = document.createElement("image");
-					el.setAttribute("width", "16");
-					el.setAttribute("height", "16");
-					el.setAttribute("src", su_get_favicon_url(domains[i]));
-					el.setAttribute("tooltiptext", su_ds.getThruDomainChannel(domains[i]).name);
-					vbox.appendChild(el);
-					text = document.createTextNode(",");
-					hbox.appendChild(text);
-				}
-				text = document.createTextNode("etc.) anytime.");
-				content_el.appendChild(text);
-			}
-			else
-			{
-				text = document.createTextNode("You can StumbleThru " + su_ds.getThruDomainChannel(spec.domain).name + " anytime.");
-				content_el.appendChild(text);
-			}
-			vbox = document.createElement("vbox");
-			vbox.setAttribute("pack", "top");
-			bubble_hbox.appendChild(vbox);
-			break;
-		default:
-			vbox = document.createElement("vbox");
-			vbox.setAttribute("pack", "top");
-			bubble_hbox.appendChild(vbox);
-			content_el = document.createElement("label");
-			if (su_host.win)
-				content_el.setAttribute("style", "margin-right: 20px; margin-top: 2px; font-size: 17px;");
-			else
-				content_el.setAttribute("style", "margin-right: 20px; margin-top: 4px; font-size: 15px;");
-			vbox.appendChild(content_el);
-			text = document.createTextNode(spec.message);
-			content_el.appendChild(text);
-			vbox = document.createElement("vbox");
-			vbox.setAttribute("pack", "top");
-			bubble_hbox.appendChild(vbox);
-			break;
-	}
-	
-	el = document.createElement("toolbarbutton");
-	if (su_host.mac)
-		el.setAttribute("class", "su_pinstripe_messageCloseButton");
-	else
-		el.setAttribute("class", "su_winstripe_messageCloseButton");
-	el.setAttribute("style", "margin-top: 4px;");
-	el.setAttribute("oncommand", "su_handle_close_info_command()");
-	bubble_hbox.appendChild(el);
-	
-	// If the bubble overflows with window.innerWidth, narrow the label.
-	var toolbox = su_get_element("navigator-toolbox");
-	var right_edge = (bubble_outerbox.boxObject.screenX - toolbox.boxObject.screenX) + bubble_outerbox.boxObject.width;
-	var width = content_el.boxObject.width;
-	bubble_outerbox.hidden = true;
-	var right_margin_width = window.innerWidth - right_edge;
-	if (right_margin_width < 0)
-		content_el.style.width = (width + right_margin_width) + "px";
-	else if (right_margin_width > 110)
-		optout.hidden = false;
-	bubble_outerbox.hidden = false;
-	
-	// Add the arrow leader.
-	el = su_create_html_element("img");
-	if (su_host.win)
-		style = "position: absolute; left: " + (x - Math.round(25 / 2) + spec.leader_offset) + "px; top: -5px; width: 18px; height: 34px";
-	else
-		style = "position: absolute; left: " + (x - Math.round(25 / 2) + spec.leader_offset) + "px; top: -10px; width: 18px; height: 34px";
-	el.setAttribute("style", style);
-	if (su_host.win)
-		el.setAttribute("src", "chrome://stumbleupon/content/skin/arrow_green-c.png");
-	else
-		el.setAttribute("src", "chrome://stumbleupon/content/skin/arrow_green-b.png");
-	el.setAttribute("onclick", "su_handle_info_leader_click()");
-	container.appendChild(el);
-	
-	if (right_margin_width <= 110)
-	{
-		// Add the optout2 box.
-		el = su_create_html_element("div");
-		style = "position: absolute; left: " + (x - Math.round(25 / 2) + spec.leader_offset - 100) + "px; top: " + (bubble_outerbox.boxObject.height - 20) + "px;";
-		el.setAttribute("style", style)
-		container.appendChild(el);
-		
-		var optout2 = document.createElement("checkbox");
-		optout2.setAttribute("label", "Show tips");
-		optout2.setAttribute("checked", su_ds.getValue("$show_tutorial_info"));
-		optout2.setAttribute("oncommand", "su_handle_info_optout_command(this)");
-		el.appendChild(optout2);
-	}
-	
-	toolbar.style.height = "auto";
-	toolbar.collapsed = false;
-}
-
-function su_handle_info_leader_click()
-{
-	su_dispatch_click(document, su_info_spec.target_id);
-}
-
-function su_create_html_element(lowercase_tag_name)
-{
-	return document.createElementNS("http://www.w3.org/1999/xhtml", "html:" + lowercase_tag_name);
-}
-
-function su_handle_close_info_command()
-{
-	su_close_info();
-}
-
-function su_handle_info_optout_command(el)
-{
-	su_ds.setValue("$show_tutorial_info", el.checked);
-}
-
-function su_hide_info()
-{
-	if (! su_info_spec)
-		return;
-	
-	var spec = su_info_spec;
-	if (spec.shown_time_s)
-	{
-		spec.shown_interval_s += su_get_time_s() - spec.shown_time_s;
-		spec.shown_time_s = null;
-	}
-	if (spec.shown_interval_s >= 8)
-		su_close_info();
-	else
-		toolbar.collapsed = true;
-	return;
-}
-
-function su_close_info()
-{
-	var el = su_get_element("su_info_container");	
-	if (el)
-		el.parentNode.removeChild(el);
-	
-	if (su_info_spec)
-		su_info_spec.closed = true;
-	
-	su_get_element("su_info_toolbar").collapsed = true;
-}
-
-function su_handle_send_dialog_accept(detail)
-{
-	var url = detail.url;
-	
-	var params = "";
-	var contact;
-	
-	switch (detail.mode)
-	{
-		case "send":
-			
-			params = su_arp(params, "url", detail.url);
-			params = su_arp(params, "friend", detail.target);
-			params = su_arp(params, "note", detail.message);
-			params = su_arp(params, "referer", detail.referrer_url);
-			
-			if (detail.stumblevideo)
-				params = su_arp(params, "videoperma", 1);
-	
-			su_post_url_server_async(
-					"referral.php",
-					params,
-					15000,
-					su_generic_done);
-			su_increment_sendto("friend", detail.target);
-			su_register_activity("referral");
-			contact = su_ds.selectRow("contact", "nickname", detail.target);
-			if (contact && contact.contactid)
-				su_ds.refreshAvatar(contact.contactid);
-			su_refresh_referral_menu(6);
-			break;
-		case "email":
-			
-			params = su_arp(params, "url", detail.url);
-			params = su_arp(params, "recipient", detail.target);
-			params = su_arp(params, "title", detail.title);
-			params = su_arp(params, "note", detail.message);
-			params = su_arp(params, "referer", detail.referrer_url);
-			
-			if (detail.stumblevideo)
-				params = su_arp(params, "videoperma", 1);
-	
-			su_post_url_server_async(
-					"mailit.php",
-					params,
-					15000,
-					su_generic_done);
-
-			// We increment here rather than in email_done() because we don't
-			// want the menupopup closing that occurs in 
-			// refresh_referral_menu() to occur after a network delay of 
-			// indeterminant length by which time the user may already be 
-			// attempting to send to someone else. -- JW
-			su_increment_sendto("email", detail.target);
-			su_refresh_referral_menu(7);
-			break;
-	}
-}
-
-// Handler for menitem "Suggest New Interests"
-function su_suggest()
-{
-	getBrowser().contentDocument.location = su_serverhttp + "suggest_interests.php";
-}
-
-// Handler for menuitem "Update Interests"
-function su_interests()
-{
-	if (stumbleid == 0)
-		return;
-	
-	// Redirect to interests page
-	var loc = su_serverhttp + "interests.php";
-	
-	//!!! disabled because it screws up history
-	// if (su_get_browser_url() != loc)
-	
-	getBrowser().contentDocument.location = loc;
-}
-
-// Handler for button "Toolbar Preferences"
-function su_preferences(opt_initial_tab)
-{
-	if (stumbleid == 0)
-		return;
-	
-	var detail = new Object();
-	detail.initial_tab = (opt_initial_tab) ? opt_initial_tab : null;
-	
-	su_unfocus_searchbox(); 
-	window.openDialog(
-				"chrome://stumbleupon/content/preferenceDialog.xul",
-				"su_preferences",
-				"chrome,dialog,centerscreen,dependent",
-				detail);
-}
-
-function su_handle_preference_dialog_accept()
-{
-	var toolbar_position = su_ds.getValue("@toolbar-position");
-	var toolbar = su_get_element(toolbar_position);
-	if (! toolbar)
-	{
-		su_log_error(
-					"MOVE FAILSAFE3",
-					new Object(),
-					toolbar_position,
-					su_ds.getValue("@position-group"));
-		
-		setTimeout(alert, 50, 
-					"The specified toolbar movement cannot be completed.\n\n" +
-					"The default position will be used.\n\n");
-		
-		su_ds.setValue("@toolbar-position", "stumbleupon");
-		su_ds.setValue("@position-group", "first");
-	}
-	
-	try {
-		su_move_toolbar(true, 6);
-	} catch (e) { su_log_error("PREFERENCE MOVE", e, su_ds.getValue("@toolbar-position"), su_ds.getValue("@position-group")); } 
-	
-	try {
-		su_refresh_toggle_button(true);
-	} catch (e) { su_log_error("PREFERENCE TOGGLE", e); } 
-
-	var detail = new Object();
-	detail.from_preference_dialog = true;
-	su_invoke_global_event("configure-toolbar", detail);
-	su_preference_dialog = null;
-	
-	setTimeout(su_verify_toolbar_move, 0, 6);
-}
-
-// called during the global configure-toolbar event and during init
-// to set labels for top-level toolbar elements
-function su_init_labels()
-{
-	var ids;
-	if (su_promo_mode && (stumbleid == 0))
-	{
-		ids = new Array(
-			"su_thumbup",
-			"su_referral_promo",
-			"su_website_info_promo",
-			"su_sites_promo",
-			"su_video_promo",
-			"su_profile",
-			"su_friends",
-			"su_referral_menu");
-	}
-	else
-	{
-		ids = new Array(
-			"su_stumble",
-			"su_thumbup",
-			"su_recthumbup",
-			"su_profile",
-			"su_friends",
-			"su_page_feature_prompt",
-			"su_referral_menu",
-			"su_website_info",
-			"su_mode",
-			"su_sponsor",
-			"firstrater",
-			"su_stumble_menu");
-	}
-	
-	for (var i = 0; i < ids.length; i++)
-	{
-		if (ids[i] == "su_thumbup")
-		{
-			var element = su_get_element("su_thumbup");
-			
-			if (element.label == element.getAttribute("showlabel2"))
-				su_set_label("su_thumbup", element.getAttribute("showlabel2"));
-			else
-				su_set_label("su_thumbup", null);
-		}
-		else if (ids[i] == "su_recthumbup")
-		{
-			if (stumbleid)
-				su_set_label("su_recthumbup", su_ds.getValue("$dd_rec_label"));
-		}
-		else
-		{
-			su_set_label(ids[i], null);
-		}
-	}
-}
-
-// Handler for button "Invite Friends"
-function su_invite(event)
-{
-	// Redirect to home
-	var loc = "find_friends.php";
-	var params = null;
-	if (su_ds.getValue("@facebook_user"))
-	{
-		loc = su_arp(loc, "pre", "facebook", true);
-		var client_count = su_ds.getValue("@facebook_client_invite_count");
-		client_count++;
-		su_ds.setValue("@facebook_client_invite_count", client_count);
-		params = su_arp("", "fbclientcount", client_count);
-		params = su_arp(params, "fbsessioncount",
-					su_ds.incrementValue("#find_friends_facebook_count"));
-		
-		if (stumbleid != 0)
-		{
-			var count = su_ds.getValue("$facebook_invite_count");
-			count++;
-			su_ds.setValue("$facebook_invite_count", count);
-			params = su_arp(params, "fbcount", count);
-		}
-	}
-	
-	if (stumbleid != 0)
-		su_ds.setValue("$shown_find_friends", true);
-	
-	if (su_host.dist)
-		loc = su_arp(loc, "dist", su_host.dist, true);
-	
-	su_set_server_location(
-				loc,
-				params,
-				su_new_tab(event));
-}
-
-// Handler for button "Upgrade Now"
-function su_sponsor(extra)
-{
-	if (stumbleid == 0)
-		return;
-
-	// Redirect to sponsor page
-	getBrowser().contentDocument.location = su_serverhttp + "sponsors.php" + extra;
-}
-
-// handler for profile tab buttons
-function su_redir_tab(event, tab)
-{
-	try {
-	
-	if (su_promo_mode && (stumbleid == 0))
-	{
-		if (tab == "")
-			tab = "favorites";
-		su_handle_promo_click(event, tab);
-		return true;
-	}
-	
-	if (su_overflow_popup_open)
-	{
-		var popup = su_get_element("su_overflow_popup");
-		if ((typeof popup.hidePopup) == "function")
-			popup.hidePopup();
-
-		su_unfocus();
-	}
-	
-	if (stumbleid == 0)
-		return true;
-
-	su_set_profile_location(tab, su_new_tab(event));
-	
-	} catch (e) { su_log_error("HANDLE TAB", e); }
-	
-	return true;
-}
-
-// Sends stumble stats to server (urls and dates you've stumbled upon)
-function su_upload_stumbles()
-{
-	if (su_ds.getValue("$stumblestats") == "")
-	{
-		return;
-	}
-	
-	var context = new su_AsyncContext();
-	context.oldStumbleReport = true;
-	context.quiet = true;
-	
-	var params = "";
-	params = su_arp(params, "urlids", su_ds.getValue("$stumblestats")); 
-	params = su_arp(params, "timestamps", su_ds.getValue("$stumbletimes")); 
-	params = su_arp(params, "types", su_ds.getValue("$stumbletypes")); 
-	params = su_arp(params, "referralids", su_ds.getValue("$stumblereferrals"));
-	params = su_arp(params, "clienttime", su_get_time_s());
-	params = su_arp(params, "houroffset", Math.floor((new Date()).getTimezoneOffset() / 60));
-	su_post_url_server_async(
-				"stumbles.php",
-				params,
-				15000,
-				su_upload_stumbles_done,
-				context);
-}
-
-function su_upload_stumbles_done(res)
-{
-	var context = res.detail;
-
-	if (res.status != 200)
-		return;
-	
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-	
-	if (su_log_communication)
-		su_log("response stumbles.php", s);
-	
-	su_process_commands(s, context);
-}
-
-// Get rid of the stumble queue
-function clear_stumbles()
-{
-	stumbles = new Array();
-//	su_fu.remove(su_prefDir + "stumbleurls");
-	su_write_file_user("stumbleurls", "");
-	try {
-		su_prefetcher.clearTargets();
-	} catch (e) { su_log_error("PREFETCHER 5", e); }
-}
-
-function su_set_inbox_status(icon)
-{
-	var message_element = su_get_element("su_messages");
-	var newimage = "chrome://stumbleupon/content/skin/mail" + icon + ".png";
-	su_set_image("su_messages", newimage);
-	
-	// right now we don't save between sessions
-	if (icon == 2)
-	{
-		su_ds.setValue("$newmessage", true);
-		if ((! su_ds.getValue("$show_messages")) && (! su_new_user))
-			su_set_visible("su_messages", true);
-	}
-	else
-	{
-		su_set_visible("su_messages", su_ds.getValue("$show_messages"));
-		su_ds.setValue("$newmessage", false);
-	}
-	su_ds.flushPrefs();
-}
-
-function su_sendto(friend)
-{
-	if (stumbleid == 0)
-		return;
-	
-	var current_page = su_get_browser_url();
-
-	if (current_page.indexOf("about:") == 0)
-		return;
-
-	su_unfocus_searchbox(); 
-
-	var detail = new Object();
-	detail.mode = "send";
-	detail.target = friend;
-	detail.url = current_page;
-	detail.display_url = su_get_browser_url(null, true);
-	detail.stumblevideo = (su_get_stumblevideo_detail() != null);
-	detail.dialog_title = "Send to " + detail.target;
-	detail.show_target = su_host.mac;
-	detail.referrer_url = su_get_browser_referrer_url();
-
-	window.openDialog(
-				"chrome://stumbleupon/content/sendDialog.xul",
-				"",
-				"chrome,dialog,centerscreen,dependent", 
-				detail);
-}
-
-// called by sendto() and mailit() to increment the sendto count in 
-// sendto_stats
-function su_increment_sendto(key_type, key)
-{
-	var contact;
-	var field_name;
-	if (key_type == "friend")
-		field_name = "nickname";
-	else if (key_type == "email")
-		field_name = "email";
-	
-	contact = su_ds.selectRow("contact", field_name, key);
-	var new_contact = false;
-	if (! contact)
-	{
-		new_contact = true;
-		contact = new Object()
-		contact[field_name] = key;
-	}
-
-	if (contact.referral_count)
-		contact.referral_count++;
-	else
-		contact.referral_count = 1;
-
-	contact.referral_timestamp = (new Date()).getTime();
-
-	if (new_contact)
-		su_ds.insertRow("contact", contact);
-	else
-		su_ds.updateRow(contact);
-
-	su_ds.flushPrefs();
-}
-
-function su_share_twitter_facebook()
-{
-	var doc = getBrowser().contentWindow.document;
-	var src = "http://" + su_ds.getValue("@supr_domain") + "/supr_shortcut.php?action=js_post";
-	var el = doc.createElement('script');
-	el.setAttribute('type','text/javascript');
-	el.setAttribute('src', src);
-	doc.body.appendChild(el);
-}
-
-function su_append_twitter_facebook_menuitem(menu, has_avatar)
-{
-	var item = document.createElement("menuitem");
-	item.setAttribute("label", "Facebook / Twitter");
-	item.setAttribute("tooltiptext", "Share on Facebook or Twitter");
-	item.setAttribute("oncommand", "su_share_twitter_facebook()");
-	item.setAttribute("image", "chrome://stumbleupon/content/skin/favicon_facebook.gif");
-	if (has_avatar)
-		item.setAttribute("class", "menuitem-iconic su-iconic-referral");
-	else
-		item.setAttribute("class", "menuitem-iconic");
-	menu.appendChild(item);
-}
-
-function su_refresh_referral_menu(from)
-{
-	su_invoke_global_event("referral-menu-dirty", null, from);
-	
-	if (su_refreshing_referral_menu)
-		return;
-
-	su_refreshing_referral_menu = true;
-	
-	setTimeout(
-				function (win, from) {
-					win.su_invoke_global_event("update-referral-menu", null, from); },
-				1000,
-				window,
-				from);
-}
-
-// utility object for refresh_referral_menu()
-function su_SendObj(type, contact)
-{
-	this.type = type;
-	if (type == "friend")
-		this.name = contact.nickname;
-	else if (type == "email")
-		this.name = contact.email;
-	
-	this.count = (contact.referral_count) ? contact.referral_count : 0;
-	this.timestamp = (contact.referral_timestamp) ? contact.referral_timestamp : 0;
-	this.compare_name = this.name.toLowerCase();
-	
-	this.avatar_url = "";
-	
-	if (contact.iconpic)
-	{
-		if (su_ds.isResourceInstalled("iconpics", contact.contactid + ".jpg"))
-			this.avatar_url = su_ds.getResourceURLFromName("iconpics", contact.contactid + ".jpg");
-	}
-}
-
-function su_update_referral_menu()
-{
-	su_refreshing_referral_menu = false;
-	if (! su_referral_menu_dirty)
-		return;
-	
-	if (su_referral_popup_open)
-		return;
-	
-	setTimeout(su_update_referral_menu2, 0);
-}
-
-function su_update_referral_menu2()
-{
-	if (su_referral_popup_open)
-		return;
-
-	su_refreshing_referral_menu = false;
-	su_referral_menu_dirty = false;
-	
-	try {
-
-	var i, j, ja, count;
-	
-	var menu = su_get_element("su_referral_menu");
-	// Delete it if it already exists.
-	var el = su_get_element("su_referral_popup");
-	if (el)
-		el.parentNode.removeChild(el);
-	
-	var referral_popup = document.createElement("menupopup");
-	var popup;
-	
-	referral_popup.setAttribute("id", "su_referral_popup");
-	referral_popup.setAttribute("onpopupshowing", "su_handle_popupshowing(event);");
-	referral_popup.setAttribute("onpopuphidden", "su_handle_popuphidden(event);");
-	menu.appendChild(referral_popup);
-	
-	if (su_referral_popup_open)
-	{
-		referral_popup.hidePopup();
-		su_unfocus();
-	}
-	
-	
-	var has_avatar = false;
-	var has_email = false;
-	var mains = new Array();
-	var mutuals = new Array();
-	var emails = new Array();
-	var virgin_avatar_mutuals = new Array();
-	var virgin_avatarless_mutuals = new Array();
-	var virgin_gmails = new Array();
-	var virgin_emails = new Array();
-	
-	var contacts = su_ds.selectAllRows("contact");
-	var i;
-	
-	if (! contacts)
-		return;
-	
-	for (i = 0; i < contacts.length; i++)
-	{
-		var send_obj;
-		if (contacts[i].mutual)
-		{
-			send_obj = new su_SendObj("friend", contacts[i]);
-			mutuals.push(send_obj);
-			
-			if (send_obj.count)
-			{
-				has_avatar = (has_avatar || (send_obj.avatar_url != ""));
-				mains.push(send_obj);
-			}
-			else if (send_obj.avatar_url == "")
-			{
-				virgin_avatarless_mutuals.push(send_obj);
-			}
-			else
-			{
-				virgin_avatar_mutuals.push(send_obj);
-			}
-		}
-		else if (contacts[i].email && (! contacts[i].hidden))
-		{
-			send_obj = new su_SendObj("email", contacts[i]);
-			emails.push(send_obj);
-			
-			if (send_obj.count)
-			{
-				has_email = true;
-				mains.push(send_obj);
-			}
-			else if (send_obj.compare_name.indexOf("@gmail.com") != -1)
-			{
-				virgin_gmails.push(send_obj);
-			}
-			else
-			{
-				virgin_emails.push(send_obj);
-			}
-		}
-	}
-	
-	emails.sort(function (a, b)
-				{
-					if ( a.compare_name > b.compare_name ) return 1;
-					if ( a.compare_name < b.compare_name ) return -1;
-					return 0;
-				});
-		
-	mutuals.sort(function (a, b)
-				{
-					if ( a.compare_name > b.compare_name ) return 1;
-					if ( a.compare_name < b.compare_name ) return -1;
-					return 0;
-				});
-	
-	var sendtos_count_max = su_ds.getValue("$sendtos_menu_depth");
-	
-	if (mains.length > sendtos_count_max)
-	{
-		// Add and populate the Recent submenu. -- JW
-		mains.sort(function (a, b)
-					{
-						if ( a.timestamp < b.timestamp ) return 1;
-						if ( a.timestamp > b.timestamp ) return -1;
-						return 0;
-					});
-		
-		menu = document.createElement("menu");
-		menu.setAttribute("label", "Recent");
-		menu.setAttribute("tooltiptext", "Recent recipients");
-		referral_popup.appendChild(menu);
-		popup = document.createElement("menupopup");
-		menu.appendChild(popup);
-
-		var recent_count_max = su_ds.getValue("$recent_sendtos_menu_depth");
-		for (i = 0; (i < mains.length) && (i < recent_count_max); i++)
-		{
-			ja = document.createElement("menuitem");
-			ja.setAttribute("label", mains[i].name + " (" + mains[i].count + ")");
-			ja.setAttribute("oncommand", "su_sendto(\"" + mains[i].name + "\");");
-			ja.setAttribute("tooltiptext", "Send to " + mains[i].name);
-			popup.appendChild(ja);
-		}
-		
-		// separator
-		ja = document.createElement("menuseparator");
-		referral_popup.appendChild(ja);
-	}
-
-	virgin_avatar_mutuals.sort(function (a, b)
-				{
-					return ((Math.random() > 0.5) ? 1 : -1);
-				});
-	
-	virgin_avatarless_mutuals.sort(function (a, b)
-				{
-					return ((Math.random() > 0.5) ? 1 : -1);
-				});
-	
-	virgin_gmails.sort(function (a, b)
-				{
-					return ((Math.random() > 0.5) ? 1 : -1);
-				});
-	
-	virgin_emails.sort(function (a, b)
-				{
-					return ((Math.random() > 0.5) ? 1 : -1);
-				});
-	
-	var gmail_quota = (sendtos_count_max - (mains.length + 
-				virgin_avatar_mutuals.length + 
-				virgin_avatarless_mutuals.length)) * 0.5;
-	
-	var gmail_quota_i = 0;
-	
-	while ((mains.length < sendtos_count_max) && 
-				((virgin_avatar_mutuals.length > 0) ||
-				(virgin_avatarless_mutuals.length > 0) ||
-				(virgin_gmails.length > 0) ||
-				(virgin_emails.length > 0)))
-	{
-		if (virgin_avatar_mutuals.length > 0)
-		{
-			mains.push(virgin_avatar_mutuals.shift());
-			has_avatar = true;
-		}
-		else if (virgin_avatarless_mutuals.length > 0)
-		{
-			mains.push(virgin_avatarless_mutuals.shift());
-		}
-		else if ((gmail_quota_i < gmail_quota) && (virgin_gmails.length > 0))
-		{
-			mains.push(virgin_gmails.shift());
-			gmail_quota_i++;
-			has_email = true;
-		}
-		else if (virgin_emails.length > 0)
-		{
-			mains.push(virgin_emails.shift());
-			has_email = true;
-		}
-		else
-		{
-			mains.push(virgin_gmails.shift());
-			has_email = true;
-		}
-	}
-	
-	// Sort the main Share menu by decreasing count and increasing
-	// name. -- JW
-	mains.sort(function (a, b)
-				{
-					if ( a.count < b.count ) return 1;
-					if ( a.count > b.count ) return -1;
-					if ( a.compare_name > b.compare_name ) return 1;
-					if ( a.compare_name < b.compare_name ) return -1;
-					return 0;
-				});
-
-	var abbr_send_array = new Array();
-	var abbr_work_array = new Array();
-	var max_abbr_idx = 0;
-	for (i = 0; (i < mains.length) && (i < sendtos_count_max); i++)
-	{
-		// Build the abbr_send_array, and begin calcuating e-mail 
-		// abbreviations. -- JW
-		var item = mains[i];
-		var at_idx = item.name.indexOf("@");
-		if (at_idx == -1)
-		{
-			item.abbr_idx = item.name.length - 1;
-			if (item.abbr_idx > max_abbr_idx)
-			{
-				max_abbr_idx = item.abbr_idx;
-			}
-		}
-		else if (at_idx <= 14)
-		{
-			item.abbr_idx = su_truncate_at(item.name, 14);
-			abbr_work_array.push(item);
-		}
-		else
-		{
-			item.abbr_idx = at_idx;
-			abbr_work_array.push(item);
-		}
-		abbr_send_array.push(item);
-	}		
-	
-	var j;
-	var item_a, item_b;
-	for (i = 0; i < abbr_work_array.length; i++)
-	{
-		// Eliminate duplicate e-mail abbreviations. -- JW
-		item_a = abbr_work_array[i];
-		for (j = i + 1; j < abbr_work_array.length; j++)
-		{
-			item_b = abbr_work_array[j];
-			
-			var common_idx = (item_a.abbr_idx > item_b.abbr_idx) ? item_b.abbr_idx : item_a.abbr_idx;
-
-			if (common_idx > 3)
-				common_idx -= 2;
-			
-			while ((item_a.name.substring(0, common_idx + 1) == item_b.name.substring(0, common_idx + 1)) && (common_idx <= item_a.name.length) && (common_idx <= item_b.name.length))
-				common_idx++;
-			
-			item_a.abbr_idx = (common_idx > item_a.abbr_idx) ? common_idx : item_a.abbr_idx;
-			item_a.abbr_idx = su_truncate_at(item_a.name, item_a.abbr_idx);
-			item_b.abbr_idx = (common_idx > item_b.abbr_idx) ? common_idx : item_b.abbr_idx;
-			item_b.abbr_idx = su_truncate_at(item_b.name, item_b.abbr_idx);
-		}
-
-		if (item_a.abbr_idx > max_abbr_idx)
-			max_abbr_idx = item_a.abbr_idx
-	}
-	
-	// If twitter or fb are supr linked, then add the link at the top.
-	var twitter_facebook_ontop = su_ds.getValue("$twitter_supr_linked") || su_ds.getValue("$facebook_supr_linked");
-	if (twitter_facebook_ontop)
-	{
-		su_append_twitter_facebook_menuitem(referral_popup, has_avatar);
-	}
-
-	if (abbr_send_array.length > 0)
-	{
-		// Populate the main Share menu. -- JW
-		
-		var item_count_max = su_ds.getValue("$sendtos_menu_depth");
-		for (i = 0; i < abbr_send_array.length; i++)
-		{
-			var item = abbr_send_array[i];
-			ja = document.createElement("menuitem");
-			var label;
-			if (item.abbr_idx == item.name.length - 1)
-				label = item.name;
-			else
-				label = item.name.substring(0, item.abbr_idx + ((item.count == 0) ? 4 : 1)) + "...";
-
-			if (item.count > 0)
-				label += " (" + item.count + ")";
-			
-			ja.setAttribute("label", label);
-			ja.setAttribute("tooltiptext", "Send to " + item.name);
-			if (item.type == "friend")
-			{
-				ja.setAttribute("oncommand", "su_sendto(\"" + item.name + "\");");
-				if (item.avatar_url == "")
-				{
-					if (has_email)
-					{
-						ja.setAttribute("image", "chrome://stumbleupon/content/skin/greyman.png");
-						if (has_avatar) //!!! create larger image
-							ja.setAttribute("class", "menuitem-iconic su-iconic-referral");
-						else
-							ja.setAttribute("class", "menuitem-iconic");
-					}
-				}
-				else
-				{
-					ja.setAttribute("image", item.avatar_url);
-					ja.setAttribute("class", "menuitem-iconic su-iconic-referral");
-				}
-			}
-			else if (item.type == "email")
-			{
-				ja.setAttribute("oncommand", "su_mailit(\"" + item.name + "\");");
-				if (has_avatar) //!!! create larger image
-				{
-					ja.setAttribute("image", "chrome://stumbleupon/content/skin/arrow.png");
-					ja.setAttribute("class", "menuitem-iconic su-iconic-referral");
-				}
-			}
-			referral_popup.appendChild(ja);
-		}
-	}
-	
-	// If twitter or fb are not supr linked, then add the link to the bottom.
-	if (!twitter_facebook_ontop)
-	{
-		su_append_twitter_facebook_menuitem(referral_popup, has_avatar);
-	}
-	
-	ja = document.createElement("menuseparator");
-	referral_popup.appendChild(ja);
-
-	if (mutuals.length > 0)
-	{
-		menu = document.createElement("menu");
-		menu.setAttribute("label", "Stumblers");
-		menu.setAttribute("tooltiptext", "All of the stumblers you can share with");
-		referral_popup.appendChild(menu);
-		
-		popup = document.createElement("menupopup");
-		menu.appendChild(popup);
-		
-		for (i = 0; i < mutuals.length; i++)
-		{
-			ja = document.createElement("menuitem");
-			if (mutuals[i].count)
-				ja.setAttribute("label", mutuals[i].name + " (" + mutuals[i].count + ")");
-			else
-				ja.setAttribute("label", mutuals[i].name);
-	
-			ja.setAttribute("oncommand", "su_sendto(\"" + mutuals[i].name + "\");");
-			ja.setAttribute("tooltiptext", "Send to " + mutuals[i].name);
-			popup.appendChild(ja);
-		}
-	}
-		
-	if (emails.length > 0)
-	{
-		menu = document.createElement("menu");
-		menu.setAttribute("label", "All Emails");
-		menu.setAttribute("tooltiptext", "All email addresses");
-		referral_popup.appendChild(menu);
-
-		popup = document.createElement("menupopup");
-		menu.appendChild(popup);
-		
-		menu = document.createElement("menu");
-		menu.setAttribute("label", "Remove Email");
-		menu.setAttribute("tooltiptext", "Remove an email address");
-		popup.appendChild(menu);
-		
-		var remove_popup = document.createElement("menupopup");
-		menu.appendChild(remove_popup);
-		
-		ja = document.createElement("menuseparator");
-		popup.appendChild(ja);
-		
-		for (i = 0; i < emails.length; i++)
-		{
-			var name = emails[i].name;
-			ja = document.createElement("menuitem");
-			if (emails[i].count)
-				ja.setAttribute("label", name + " (" + emails[i].count + ")");
-			else
-				ja.setAttribute("label", name);
-	
-			ja.setAttribute("tooltiptext", "Send to " + name);
-			ja.setAttribute("oncommand", "su_mailit(\"" + name + "\");");
-			popup.appendChild(ja);
-			
-			ja = document.createElement("menuitem");
-			ja.setAttribute("label", name);
-			ja.setAttribute("oncommand", "su_remove_email(\"" + name + "\");");
-			ja.setAttribute("tooltiptext", "Remove this address");
-			remove_popup.appendChild(ja);
-		}
-	}
-	
-	ja = document.createElement("menuitem");
-	ja.setAttribute("label", "New Email Address...");
-	ja.setAttribute("image", "chrome://stumbleupon/content/skin/arrow.png");
-	ja.setAttribute("class", "menuitem-iconic");
-	ja.setAttribute("tooltiptext", "Send to a new e-mail address");
-	ja.setAttribute("oncommand", 'su_mailit("");');
-	referral_popup.appendChild(ja);
-
-	ja = document.createElement("menuseparator");
-	referral_popup.appendChild(ja);
-
-	ja = document.createElement("menuitem");
-	ja.setAttribute("label", "Find people you know...");
-	ja.setAttribute("class", "menuitem-iconic");
-	ja.setAttribute("image", "chrome://stumbleupon/content/skin/friend.png");
-	ja.setAttribute("tooltiptext", "Import contacts from an address book");
-	ja.setAttribute("onclick", "su_invite(event);");
-	
-	referral_popup.appendChild(ja);
-	
-	
-	} catch (e) { su_log_error("REFERRAL MENU", e); }
-}
-
-// utility function for update_referral_menu()
-function su_truncate_at(str, idx)
-{
-	if (str.length < idx + 6)
-		idx = str.length - 1;
-	
-	return idx;
-}
-
-// This function grabs urls from recommend.php and stores them in stumbleurls (user_cat is either category id of incat stumble or 0)
-function su_update_url_cache(user_cat, check_referral, callback, context)
-{
-	try {
-	
-	var res;
-	var postspec = new Object();
-	var now = su_get_time_s();
-	
-	if (context.first_of_day)
-		postspec.first_of_day = 1;
-	
-	postspec.houroffset = Math.floor((new Date()).getTimezoneOffset() / 60);
-	
-	if (su_isInt(user_cat))
-	{
-		postspec.category = user_cat;
-	}
-	else
-	{
-		if (user_cat.indexOf("LANG_") == 0)
-		{
-			postspec.language = user_cat.substr(5);
-		}
-		else if (user_cat.indexOf("TAG_") == 0)
-		{
-			postspec.tag = user_cat.substr(4);
-		}
-		else if (user_cat.indexOf("USERTAG_") == 0)
-		{
-			var chunk = user_cat.substr(8);
-			chunks = chunk.split('_');
-			var tag = chunks[1];
-			var profile = chunks[0];
-			postspec.showfriend = profile;
-			postspec.tag = tag;
-		}
-		else
-		{
-			if (user_cat == "news")
-				postspec.shownews = 1;
-			
-			else if (user_cat == "video")
-				postspec.mode = "video";
-			
-			else if (user_cat == "friends")
-				postspec.mode = "friends";
-			
-			else if (user_cat == "wiki")
-				postspec.mode = "wiki";
-			
-			else	
-				postspec.showfriend = user_cat;
-		}
-	}
-	
-	if (check_referral)
-		postspec.check_referral = 1;
-	
-	// if we need to upload_stumbles, do it
-	if (su_ds.getValue("$stumblestats") != "")
-	{
-		postspec.urlids = su_ds.getValue("$stumblestats");
-		postspec.timestamps = su_ds.getValue("$stumbletimes");
-		postspec.types = su_ds.getValue("$stumbletypes");
-		postspec.referralids = su_ds.getValue("$stumblereferrals");
-		postspec.clienttime = now;
-        context.oldStumbleReport = true;
-	}
-	
-	postspec.recentlyseen = su_ds.getValue("$recently_seen");
-    postspec.recentlyseen_publicids = su_ds.getValue("$recently_seen_publicids");
-	postspec.recentlyseen_referralids = su_ds.getValue("$recently_seen_referralids");
-	
-	var params = su_build_request_param_string(postspec);
-	
-	params = su_append_sync_params(params);
-	
-	if (callback)
-		context.callbacks.push(callback);
-	
-	context.dd_uc_server = su_servername;
-	context.check_referral = check_referral;
-
-	su_post_url_server_async(
-				"recommend.php",
-				params,
-				su_ds.getValue("@recommend_timeout_ms"),
-				su_update_url_cache_done,
-				context);
-	
-	} catch (e) { su_log_error("RECOMMEND BEGIN", e); }
-}
-
-function su_update_url_cache_done(res)
-{
-	try {
-	
-	var context = res.detail;
-	var callback = null;
-	var ancestor_callback = null;
-	if (context)
-	{
-		callback = context.callbacks.pop();
-		ancestor_callback = context.callbacks.pop();
-	}
-
-	if (res.aborted)
-	{
-		if (callback)
-			callback("error", ancestor_callback, context);
-		return;
-	}
-
-	try {
-		if (res.status == 1)
-		{
-			if (callback)
-				callback("error", ancestor_callback, context);
-			return;
-		}
-	} catch (e) {}
-
-	try {
-		if (res.status != 200)
-		{
-			// Maintenance mode returns 503 with "ERROR xxx" set.
-			// In that case, let the "ERROR" command be handled.
-			var isMaintenanceMode = false;
-			if(res.status == 503)
-			{
-				var commands = res.responseText.split(" ");
-				if(commands.length && (commands[0] == "ERROR"))
-				{
-					// Let it fall through 
-					isMaintenanceMode = true;
-				}
-			}
-			if(!isMaintenanceMode)
-			{
-				if (! context.quiet)
-					alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to "
-						+ su_base_url + "feedback.php to report the problem\nError : " + res.error + "\nStatus : " + res.status);
-				if (callback)
-					callback("connection error", ancestor_callback, context);
-				return;
-			}
-		}
-	}
-	catch (e) {
-		if (! context.quiet)
-			alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to "
-				+ su_base_url + "feedback.php to report the problem.\nError : connection error");
-		if (callback)
-			callback("connection error", ancestor_callback, context);
-	}
-	
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-	
-	if (su_log_communication && ((! context.quiet) || su_log_polling))
-		su_log("response recommend.php", s);
-	
-	// Parse response text
-	var parsed = s.split("\n");
-	
-	var undelivered_count = 0;
-
-	var pre_stumbles = new Array(); // temporary variable for storing stumbles if we are checking referrals
-
-	// Iterate through commands
-	var i;
-	for (i = 0; i < parsed.length; i++)
-	{
-		if (parsed[i] == "")
-			continue;
-
-		// Parse command structure
-		var command = parsed[i].split(" ");
-		if (command[0] == "")
-			continue;
-		
-		switch(command[0])
-		{
-			case "ERROR":
-				if (command[1] == "INCORRECT_PASSWORD" && context.quiet)
-				{
-					// auth failed during polling, so poll less frequently
-					
-					// note that iebar signs out when it receives INCORRECT_PASSWORD
-					
-					su_invoke_global_event("logout", null)
-					return;
-				}
-				else if (command[1] == "NO_INTERESTS")
-				{
-					// Redirect to interests page
-					var loc = su_serverhttp + "interests.php";
-					//!!! disabled because it screws up history
-					// if (su_get_browser_url() != loc)
-
-					getBrowser().contentDocument.location = loc;
-
-					if (callback)
-						callback("error", ancestor_callback, context);
-					return;
-				}
-				else if (command[1] == "NO_SITES")
-				{
-					// do nothing
-				}
-				else
-				{
-					if (! context.quiet)
-						su_handle_error(command[1]);
-					
-					if (callback)
-						callback("error", ancestor_callback, context);
-					return;
-				}
-				break;
-			case "URL":
-				pre_stumbles.push(parsed[i].substr(4));
-				// Check to see if we have a referral
-				if (typeof(command[8]) != "undefined" && command[8] == 4)
-					undelivered_count++;
-				break;
-			default:
-				su_process_command(parsed[i], context, command);
-				break;
-		}
-	}
-	su_ds.flushPrefs();
-
-	// save referral count
-
-	if (context.user_cat == 0)
-		su_ds.setValue("$undelivered_count", undelivered_count);
-
-	// might as well clear old stumbles, they are old
-	// and there really should only be 1 of them anyway
-	if (!(context.check_referral && undelivered_count == 0))
-	{
-		clear_stumbles();
-	}
-	
-	su_update_referred(false);
-	
-	// populate the stumbles array
-	su_load_stumbles(null);
-	
-	// dump the new stumbles onto the end of stumbles
-	for (i = 0; i < pre_stumbles.length; i++)
-		stumbles.push(pre_stumbles[i]);
-	
-	// Now dump the new stumble queue to disk
-	su_save_stumbles();
-	
-	if (stumbles.length && (su_ds.lookup("userid:uc_logger_flag", stumbleid) ||
-				su_ds.getValue("@dd_uc")))
-		su_ds.setValue("@dd_uc_server", context.dd_uc_server);
-	
-	if (callback)
-		callback("", ancestor_callback, context);
-	
-	} catch (e) { su_log_error("RECOMMEND DONE", e); }
-}
-
-function su_update_referred(disable_animation)
-{
-	setTimeout(su_update_referred2, 0, disable_animation);
-}
-
-function su_update_referred2(disable_animation)
-{
-	var undelivered_count = su_ds.getValue("$undelivered_count"); 
-	
-	su_set_label("su_referred", undelivered_count);
-	
-	if (su_get_element("su_referred").disabled)
-		return;
-	
-	if (undelivered_count > 0)
-	{
-		su_register_activity("referred");
-		if (! disable_animation)
-			su_set_attribute("su_referred", "busy", "true");
-		su_set_visible("su_referred", true);
- 	}
-	else
-	{
-		su_set_visible("su_referred", false);
-	}
-}
-	
-function su_save_stumbles()
-{
-	var towrite = "";
-	for (var ii = 0; ii < stumbles.length; ii++)
-		towrite += stumbles[ii] + "\n";
-	
-	su_write_file_user("stumbleurls", towrite);
-}
-
-// Saves a rating to the rating history (so we can grey out rating buttons later)
-function su_store_rating(u, c)
-{
-	var url_detail = su_ds.lookup("url:url_detail", u)
-	if (url_detail)
-		url_detail.rating = c;
-	
-	// Load rating history (in case the user has rated something in another window)
-	stumblecat = su_read_file_user("stumblerating");
-	splitcat = stumblecat.split("\n");
-	for (var i = 0; i < splitcat.length; i++)
-	{
-		if (splitcat[i] == "")
-			continue;
-		split2 = splitcat[i].split(" ");
-		su_ratings[split2[0]] = split2[1];
-	}
-
-	// Add the new rating
-	su_ratings[u] = c;
-
-	// Now dump it to disk
-	var towrite = "";
-	for (var ii in su_ratings)
-	{
-		if (su_is_property_garbage(su_ratings, ii))
-			continue;
-		
-		towrite += ii + " " + su_ratings[ii] + "\n";
-	}
-	su_write_file_user("stumblerating", towrite); 
-}
-
-function su_delete_rating(u)
-{
-	var url_detail = su_ds.lookup("url:url_detail", u)
-	if (url_detail)
-		url_detail.rating = null;
-
-	// Load rating history (in case the user has rated something in another window)
-	stumblecat = su_read_file_user("stumblerating");
-	splitcat = stumblecat.split("\n");
-	su_ratings = new Array();
-	for (var i = 0; i < splitcat.length; i++)
-	{
-		if (splitcat[i] == "")
-			continue;
-		split2 = splitcat[i].split(" ");
-		if (split2[0] != u)
-			su_ratings[split2[0]] = split2[1];
-	}
-
-	// Now dump it to disk
-	var towrite = "";
-	for (var ii in su_ratings)
-	{
-		if (su_is_property_garbage(su_ratings, ii))
-			continue;
-		
-		towrite += ii + " " + su_ratings[ii] + "\n";
-	}
-	su_write_file_user("stumblerating", towrite); 
-}
-
-// performs a synchronous POST, when the interface is beneath the www
-// stumbleupon domain
-function su_post_url_server(uri_suffix, postdata)
-{
-	return su_post_url(
-				su_serverhttp + uri_suffix + "?username=" + stumbleid,
-				postdata);
-}
-
-function su_post_url_server_secure(uri_suffix, postdata)
-{
-	return su_post_url(
-				su_serverhttps + uri_suffix + "?username=" + stumbleid,
-				postdata);
-}
-
-// performs a synchronous POST
-function su_post_url(uri, postdata)
-{
-	var script_timeout_saved;
- 	try {
-		if (su_ds.isPrefDefined("dom.max_chrome_script_run_time"))
-		{
-			script_timeout_saved = su_ds.getValue("dom.max_chrome_script_run_time");
-			su_ds.setValue("dom.max_chrome_script_run_time", 120);
-		}
-	} catch (e) {}
-	
-	// This function trys to post 3 times (since there is 
-	// something screwy with xmlhttprequest).
-	var ret2 = new Object();
-	var x;
-	var status;
-	var retries = 3;
-
-	if (! postdata)
-		postdata = "";
-	
-	var client_postdata = su_get_client_postdata(uri);
-	if (client_postdata != "")
-		postdata += ((postdata == "") ? "" : "&") + client_postdata;
-	
-	for (var i = 1; i <= retries; i++)
-	{
-		x = new XMLHttpRequest();
-		netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
-		x.open("POST", uri, false);
-//		x.setRequestHeader("User-Agent" , su_useragent); // unnecessary since we set X-SU-Version
-		x.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
-		try { 
-			if (su_log_communication && (uri.indexOf("topics.csv") == -1))
-				su_log("post sync", uri, postdata, "attempt: " + i);
-			x.send(postdata); 
-			status = x.status;
-			break;
-		}
-		catch (e) {
-			if (i == retries) 
-			{
-				// Failed on 3nd try, bail out
-				ret2.error = e;
-				ret2.response = "";
-				ret2.status = 1;
-				try {
-					if (su_ds.isPrefDefined("dom.max_chrome_script_run_time"))
-					{
-						su_ds.setValue(
-									"dom.max_chrome_script_run_time",
-									script_timeout_saved);
-					}
-				} catch (e) {}
-				return ret2;
-			}
-		}
-	}
-	ret2.error = "";
-	ret2.response = x.responseText;
-	if (typeof(ret2.response) == "undefined")
-		ret2.response = "";
-	ret2.status = x.status;
-	var mime = '';
-	try {
-		mime = x.getResponseHeader("Content-Type");
-	}
-	catch (e) {
-		mime = '';
-	}
-	
-	if (mime != null && typeof(mime) != "undefined" && mime != '')
-	{
-		var mimes = mime.split(";");
-		ret2.mimetype	= mimes[0];
-	}
-	else
-		ret2.mimetype = '';
-	try {
-		if (su_ds.isPrefDefined("dom.max_chrome_script_run_time"))
-		{
-			su_ds.setValue(
-						"dom.max_chrome_script_run_time",
-						script_timeout_saved);
-		}
-	} catch (e) {}
-	return ret2;
-}
-
-// begins an asynchronous POST, when the interface is beneath the www
-// stumbleupon domain
-function su_post_url_server_async(uri_suffix, postdata, timeout_interval_ms, callback, detail)
-{
-	if (! detail)
-		detail = new Object();
-	detail.request_target = uri_suffix;
-	
-	su_post_url_async(
-				su_serverhttp + uri_suffix + 
-					((stumbleid && (uri_suffix != "stumblethru.csv")) ? 
-					("?username=" + stumbleid) : ""),
-				postdata,
-				timeout_interval_ms,
-				callback,
-				detail);
-}
-
-function su_post_url_server_async_secure(uri_suffix, postdata, timeout_interval_ms, callback, detail)
-{
-	if (! detail)
-		detail = new Object();
-	detail.request_target = uri_suffix;
-	
-	su_post_url_async(
-				su_serverhttps + uri_suffix + 
-					((stumbleid && (uri_suffix != "stumblethru.csv")) ? 
-					("?username=" + stumbleid) : ""),
-				postdata,
-				timeout_interval_ms,
-				callback,
-				detail);
-}
-
-// begins an asynchronous POST
-function su_post_url_async(uri, postdata, timeout_interval_ms, callback, detail)
-{
-	// This ensures that our request objects are created in the context
-	// of this window.  This is necessary for the first stumble after
-	// new account creation. -- JW
-	setTimeout(function (window, uri, postdata, timeout_interval_ms, callback, detail) { window.su_post_url_async_wrapped(uri, postdata, timeout_interval_ms, callback, detail); }, 0, window, uri, postdata, timeout_interval_ms, callback, detail);
-}
-
-// do not call this; call post_url_async instead
-function su_post_url_async_wrapped(uri, postdata, timeout_interval_ms, callback, detail)
-{
-	if (! postdata)
-		postdata = "";
-	
-	postdata += ((postdata == "") ? "" : "&") + su_get_client_postdata(uri);
-	
-	su_service.postAsync(su_useragent, uri, postdata, timeout_interval_ms, callback, detail);
-}
-
-// Used by post_url, post_url_async and stumble_done to
-// construct version and authentication portions of postdata
-function su_get_client_postdata(uri)
-{
-	var postdata = "";
-	
-	if (uri.indexOf(su_serverhttp) == 0)
-		postdata += "version=" + su_verstring;
-
-	if (su_is_auth_allowed(uri))
-	{
-		if (su_enable_hashed_password)
-		{
-			postdata += ((postdata == "") ? "" : "&") + 
-						"username=" + stumbleid + 
-						"&password=" + stumblepass +
-						"&ycc=" + su_ds.getCC();
-		}
-		else
-		{
-			postdata += ((postdata == "") ? "" : "&") + 
-						"username=" + stumbleid + 
-						"&password=" + encodeURIComponent(stumblepass) +
-						"&ycc=" + su_ds.getCC();
-		}
-	}
-	return postdata;
-}
-
-// used by the http_observer and get_client_postdata to determine
-// whether we're allowed to send authentication to the page
-function su_is_auth_allowed(url)
-{
-	if (! su_is_matching_domain(url, su_servername))
-		return false;
-	
-	if ((url.indexOf(su_serverhttp == 0)) || (url.indexOf(su_serverhttps == 0)))
-	{
-		// These get special authentication sent in postdata.
-		if ((su_is_server_page(url, "userexists.php")) ||
-					(su_is_server_page(url, "delete_account.php")) ||
-					(su_is_server_page(url, "change_password.php")) ||
-					(su_is_server_page(url, "sign_up.php")) ||
-					(su_is_server_page(url, "getid.php")) ||
-					(su_is_server_page(url, "init_user.php")) ||
-					(su_is_server_page(url, "signup.php")))
-			return false;
-
-		// Don't bother with obvious non-pages....
-		if ((su_is_server_page(url, "images/")) ||
-					(su_is_server_page(url, "pics/")) ||
-					(su_is_server_page(url, "iconpics/")) ||
-					(su_is_server_page(url, "superminipics/")) ||
-					(su_is_server_page(url, "groupsuperminipics/")) ||
-					(su_is_server_page(url, "topicsuperminipics/")) ||
-					(su_is_server_page(url, "mediumpics/")) ||
-					(su_is_server_page(url, "thumb/")) ||
-					(su_is_server_page(url, "css/")) ||
-					(su_is_server_page(url, "js/")) ||
-					(su_is_server_page(url, "favicon.ico")) ||
-					(su_is_server_page(url, "stumble.js")) ||
-					(su_is_server_page(url, "post.js")) ||
-					(su_is_server_page(url, "help.js")))
-			return false;
-	}
-	return true;
-}
-
-function su_handle_page_feature_prompt_click(event)
-{
-	var url = su_get_browser_url();
-	var search_service_id = su_get_service_id(url, true);
-	
-	if (su_is_matching_domain(url, "facebook.com"))
-	{
-		if (su_ds.getValue("$facebook_added"))
-		{
-			su_ds.setValue("$facebook_linked", true);
-			
-			su_set_server_location(
-						"facebook/index.php?link",
-						null,
-						su_new_tab(event));
-		}
-		else
-		{
-			su_set_location(
-						"http://apps.facebook.com/stumbleupon/",
-						null,
-						su_new_tab(event));
-		}
-	}
-	else if (search_service_id)
-	{
-		su_ds.setValue("$show_searchlinks_score", true);
-		su_ds.setValue("$show_searchlinks_friends", true);
-		su_ds.setValue("$shown_searchlinks", true);
-		if (su_new_tab(event))
-		{
-			su_set_location(url, null, true);
-		}
-		else
-		{
-			su_search_results_page(
-						getBrowser().contentDocument,
-						search_service_id);
-		}
-	}
-	su_set_visible("su_page_feature_prompt", false);
-}
-
-// handles the click event for the website_info button
-function su_handle_website_info_click(event)
-{	
-	// button is disabled
-	if (su_get_element("su_website_info").getAttribute("image") == "chrome://stumbleupon/content/skin/bubblex.png")
-		return;
-
-	su_website_info(su_new_tab(event), "", 0);
-}
-
-function su_handle_website_info_promo_click(event, from_control_id)
-{	
-	if (su_search_service_id)
-	{
-		su_handle_promo_click(event, 	"search");
-		return;
-	}
-	
-	// button is disabled
-	if (su_get_element("su_website_info_promo").disabled)
-		return;
-
-	var url = su_get_browser_url();		
-	
-	var cmp_url = url.toLowerCase();
-	
-	if (cmp_url.indexOf("http://video." + su_servername + "/#p") == 0)
-		return;
-				
-	if (cmp_url.indexOf("http://video." + su_servername + "/?p") == 0)
-		return;
-	
-	var loc;
-	var params = null;
-	
-	if (url.indexOf("about:") == 0)
-	{
-		su_verify_cookie_perms(false);
-		loc = "sign_up.php";
-		if (su_ds.getValue("@facebook_user"))
-			loc = su_arp(loc, "pre", "facebook", true);
-		
-		loc = su_arp(loc, "pre2", from_control_id, true); 
-		
-		if (su_host.dist)
-			loc = su_arp(loc, "dist", su_host.dist, true);
-	}
-	else
-	{
-		loc = "url/" + su_review_url(url);
-		params = "";
-		if (su_ds.getValue("@facebook_user"))
-			params = su_arp(params, "pre", "facebook");
-		
-		params = su_arp(params, "pre2", from_control_id); 
-		
-		if (su_host.dist)
-			params = su_arp(params, "dist", su_host.dist);
-		
-		params = su_arp(params, "retry_url", url);
-	}
-	
-	su_set_server_location(
-				loc,
-				params,
-				su_new_tab(event));
-}
-
-function su_handle_promo_click(event, from_control_id)
-{	
-	var is_search = false;
-	var url = su_get_browser_url();
-	var detail = new Object();
-	if (from_control_id == "search")
-	{
-		is_search = true;
-		from_control_id = su_search_service_id;
-		detail = su_get_search_query_detail(su_search_service_id, url); 
-	}
-	
-	su_verify_cookie_perms(false);
-	var loc = "sign_up.php";
-	var params = null;
-	if (su_ds.getValue("@facebook_user"))
-		loc = su_arp(loc, "pre", "facebook", true);
-	
-	loc = su_arp(loc, "pre2", from_control_id, true); 
-	
-	if (su_host.dist)
-		loc = su_arp(loc, "dist", su_host.dist, true);
-	
-	if (detail.is_short_query_results)
-		params = su_arp("", "post_url", url);
-	else if (detail.is_query_results)
-		params = su_arp("", "post_url2", url);
-	else if (from_control_id == "referral")
-		loc = su_arp(loc, "url", url, true);
-
-	su_set_server_location(
-				loc,
-				params,
-				su_new_tab(event));
-}
-
-function su_handle_video_promo_click(event)
-{
-
-	su_get_element("su_stumble").image="chrome://stumbleupon/content/skin/stumble2.png";
-	su_stumble_action_count++;
-	setTimeout(
-				su_reset_stumble_action_indicator,
-				su_ds.getValue("@stumble_action_timeout_ms"),
-				su_stumble_action_count);
-	
-	su_stumble_video(su_new_tab(event));
-}
-
-function su_handle_tag_command(force_dialog)
-{
-	var searchbox = su_get_element("su_searchbox");
-	if (searchbox.open)
-		searchbox.closePopup();
-	
-	setTimeout(su_handle_tag_command2, 0, force_dialog);	
-}
-
-function su_get_title(opt_doc, opt_raw_url)
-{
-	var doc = (opt_doc) ? opt_doc : getBrowser().contentDocument;
-	
-	if (doc.title != "")
-		return doc.title;
-	
-	if (opt_raw_url)
-		return opt_raw_url;
-		
-	return su_get_browser_url(doc, true)
-}
-
-function su_handle_tag_command2(force_dialog)
-{
-	//!!! canonize tag?
-	var current_url = su_get_browser_url();
-	
-	if (su_url_has_tag)
-	{
-		var tag = su_get_tag_list(current_url);
-		
-		if (tag)
-		{
-			su_tagit(current_url, tag, true, su_get_title(), su_get_browser_url(null, true));
-			return;
-		}
-	}
-	
-	su_unfocus_searchbox(); 
-	// see if searchbox is hidden
-	var tag = '';
-	if (force_dialog || (su_get_element("su_field").collapsed == true))
-	{
-		var detail = new Object();
-		detail.url = current_url;
-		detail.tags_default = su_get_element("su_searchbox").value;
-		if (detail.tags_default == su_tag_instructions)
-			detail.tags_default = "";
-
-		window.openDialog(
-					"chrome://stumbleupon/content/taggingDialog.xul",
-					"",
-					"chrome,dialog,centerscreen,dependent",
-					detail);
-	}
-	else
-	{	
-		tag = su_get_element("su_searchbox").value;
-		if (tag == su_tag_instructions)
-			tag = "";
-		
-		if (tag == "")
-		{
-			// put a little instruction thing up
-			var alerttext = "To tag a page, type some tags into the text box before clicking the tag button.\nTags are descriptive keywords you can use to organize and share useful websites.\nTags may contain spaces, letters, and numbers and must be separated by commas.\nFor example, you might tag page of travel photos as \"photos, traveling, costa rica\".\n\nYou can lookup sites you've tagged using the 'Find pages you liked' button on your Favorites page.";
-			alert(alerttext);
-			
-			// put focus in search box
-			su_get_element("su_searchbox").focus();
-			return;	
-		}	
-		
-		var tagerror = su_validate_tagstring(tag);
-		if (tagerror != null)
-		{
-			alert(tagerror);
-			return;
-		}	
-		su_tagit(current_url, tag, false, su_get_title(), su_get_browser_url(null, true));
-	}	
-}
-
-function su_validate_tagstring(str)
-{
-	// validate tag...
-	var tags = str.split(',');
-	var tagerror = null;
-	// Itetag through commands
-	var tagcount = 0;
-	for (var i = 0; i < tags.length; i++)
-	{
-		if (tags[i] == "")
-			continue;
-		tagcount++;
-		if (tagcount > 5)
-		{
-			tagerror = 'You cannot apply more than 5 tags to a page.';
-			break;
-		}
-		
-		var thetag = tags[i];
-		
-		if (thetag.indexOf('http://') != -1)
-		{
-			tagerror = 'If you want to search for a site, enter some search terms then click \'enter\'.\nTo tag a page, type in some keywords before clicking this icon.';
-			break;	
-		}
-		
-		if (thetag.length > 32)
-		{
-			tagerror = 'Each tag cannot be longer than 32 characters.\nYour tag \'' + thetag + '\' is ' + thetag.length + ' characters long.';
-			break;
-		}
-		var tagpieces = thetag.split(/[^A-Za-z0-9]/);
-//		alert(tagpieces.length);
-		var tagpiececount = 0;
-		for (var j = 0; j < tagpieces.length; j++)
-		{
-			if (tagpieces[j] == "")
-				continue;
-			//alert(tagpieces[j]);
-			tagpiececount++;
-			if (tagpiececount > 3)
-			{
-				tagerror = 'Each tag cannot have more than 3 words. For example,\n \'costa rica trip\' is a valid tag, but \'costa rica trip photos\' is not.\nYour tag \'' + thetag + '\' has ' + tagpiececount + ' words.';
-				break;	
-			}
-		}
-		if (tagpiececount > 3)
-			break;	
-	}
-	return tagerror;
-}
-
-function su_tagit(url, tag, untag, opt_title, opt_raw_url)
-{
-	// when you tag, we know it's not a tag on i-likeit
-	su_last_typed_tag = 0;
-	
-	if ((url == "") || (url.indexOf("about:") == 0))
-		return;
-
-	var context = new su_AsyncContext();
-	context.url = url;
-	context.tag = tag;
-	context.ref_url = (opt_raw_url) ? opt_raw_url : su_get_browser_url(null, true);
-	context.untagging = untag;
-	if (! untag)
-		context.title = (opt_title) ? opt_title : su_get_title();
-	
-	var params = "tag=" + escape(tag) + "&url=" + encodeURIComponent(url);
-	
-	params = su_arp(params, "referer", su_get_browser_referrer_url());
-	
-	params = su_append_sync_params(params);
-	
-	if (untag)
-	{
-		// we want to undo this tag	
-		su_post_url_server_async(
-					"untagit.php",
-					params,
-					null,
-					su_untag_done,
-					context);
-	}
-	else
-	{
-		su_post_url_server_async(
-					"tagit.php",
-					params,
-					null,
-					su_tag_done,
-					context);
-	}
-	return;
-}
-
-
-function su_untag_done(res)
-{
-	try {
-		if (res.status == 1)
-			return;
-	} catch (e) { return; }
-	
-	if (res.status != 200)
-	{
-		su_http_error(res.error, res.status);
-		return;
-	}
-	
-	var context = res.detail;
-	
-	// success!
-	// !!! go to info page? (middle click or option?)
-	
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-
-	if (su_log_communication)
-		su_log("response untagit.php", s);
-	
-	su_process_commands(s, context);
-	if (context.error)
-		return;
-	
-	su_load_tags(context.url);
-	su_store_tags();
-	
-	su_enable_tag_toolbar();
-	
-	return;
-}
-
-
-function su_tag_done(res)
-{
-	try {
-		if (res.status == 1)
-			return;
-	} catch (e) { return; }
-	
-	if (res.status != 200)
-	{
-		su_http_error(res.error, res.status);
-		return;
-	}
-	
-	var context = res.detail;
-	
-	// success!
-	// !!! go to info page? (middle click or option?)
-
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-	
-	if (su_log_communication)
-		su_log("response tagit.php", s);
-	
-	su_process_commands(s, context);
-	if (context.error)
-		return;
-	
-	var tag = su_normalize_tag(context.tag);
-	
-	su_load_tags(context.url);
-	
-	// Add the new tag
-	var o = new Object();
-	o.url = context.url;
-	o.tag_list = tag;
-	su_tag_lists_by_url[context.url] = tag;
-	su_tags.unshift(o);
-	
-	su_store_tags();
-	
-	su_disable_tag_toolbar(tag);
-	su_old_search = tag;
-	
-	su_get_element("su_tag").image="chrome://stumbleupon/content/skin/tag2.png";
-	su_get_element("su_tag2").image="chrome://stumbleupon/content/skin/tag2.png";
-}
-
-
-// Returns the size of the URL in bytes; must be cached and therefore an HTTP or FTP URL
-function su_get_size(url) 
-{
-	var cacheService = su_get_service(
-				"@mozilla.org/network/cache-service;1",
-				"nsICacheService");
-	var httpCacheSession = cacheService.createSession("HTTP", 0, true);
-	httpCacheSession.doomEntriesIfExpired = false;
-	var ftpCacheSession = cacheService.createSession("FTP", 0, true);
-	ftpCacheSession.doomEntriesIfExpired = false;
-	
-	try
-	{
-		var cacheEntryDescriptor = httpCacheSession.openCacheEntry(url, Components.interfaces.nsICache.ACCESS_READ, false);
-		if (cacheEntryDescriptor)
-			return cacheEntryDescriptor.dataSize;
-	}
-	catch(ex) {}
-	try
-	{
-		cacheEntryDescriptor = ftpCacheSession.openCacheEntry(url, Components.interfaces.nsICache.ACCESS_READ, false);
-		if (cacheEntryDescriptor)
-			return cacheEntryDescriptor.dataSize;
-	}
-	catch(ex) {}
-	return -1;
-}
-
-// Handler for photoblog
-function su_blogImage(rating)
-{
-	su_photoblogimage = document.popupNode;
-
-	if (su_get_size(su_photoblogimage.src) > 250000)
-	{
-		su_photoblogimage = null;
-		alert("Image too large (250kb max size)");
-		return;
-	}
-
-	if (su_photoblogimage.width > 715)
-	{
-		su_photoblogimage = null;
-		alert("Image too large (715px max width)");
-		return;
-	}
-
-	if (su_photoblogimage.height > 715)
-	{
-		su_photoblogimage = null;
-		alert("Image too large (715px max height)");
-		return;
-	}
-
-/*
-	// see if we need to grab the referring page for this image
-	var current_page = su_get_browser_url();
-	alert("currente page: " + current_page + " su_photoblogimage: " + su_photoblogimage.src);
-	if (current_page == su_photoblogimage.src)
-	{
-		// we want to find the referring page...
-		var referer = getBrowser().contentDocument.referrer;
-		alert("referer " + referer);
-		if (typeof(referer) != "undefined" && referer != null && referer != "" && referer.indexOf('http://') != -1)
-		{
-			// we need to rate the referering page.. 	
-			alert("refering page: " + referer);
-			return;
-		}
-	}
-
-	alert("no referring page");
-	return;
-*/
-
-	// first do rating...
-	su_rate(rating, false, true, false, 0);	
-}
-
-// pre-Handler for button "rate"
-function su_handle_rate_click(event, r)
-{
-	if (su_promo_mode && (stumbleid == 0) && (! su_get_stumblevideo_detail()))
-	{
-		if (r > 0)
-			su_handle_website_info_promo_click(event, "thumbup");
-		else
-			su_handle_website_info_promo_click(event, "thumbdown");
-			
-		return;
-	}
-	
-	if (r == 2)
-	{
-		r = 1;
-		su_d_rec_rating = true;
-	}
-	else
-	{
-		su_d_rec_rating = false;
-	}
-	
-	var url = su_get_browser_url();
-	var old_rating = su_get_rating(url, (su_get_stumblevideo_detail() != null));
-	
-	// see if they are unrating an old rating
-	
-	if ((old_rating != null) && 
-			((old_rating == r) || (r == 0 && (old_rating <= 0))))
-	{
-		setTimeout(su_unrate, 0);
-		return;
-	}
-	
-	if (su_get_element("su_thumbup").disabled == true)
-		return;
-	
-	if (typeof(event.button) == "undefined")
-		event.button = 0; // For menu entries, simulate left button
-
-	var platform_ctrl_key = (su_host.mac) ? event.metaKey : event.ctrlKey;
-	
-	if (((event.button == 0) && (! platform_ctrl_key)) && 
-				(! su_ds.getValue("$rate_new_window")))
-		su_rate(r, false, false, false, 0);
-	
-	else if ((event.button == 1) || ((event.button == 0) && 
-				platform_ctrl_key) || su_ds.getValue("$rate_new_window"))
-		su_rate(r, true, false, false, 0);
-}
-
-
-// Handler for button "rate"
-function su_unrate()
-{
-	su_check_progress_listener();
-
-	if ((stumbleid == 0) && (! su_promo_mode))
-		return;
-	
-	var theurl = su_get_browser_url();
-	if (stumbled_redirect != '' && theurl == stumbled_redirect)
-	{
-		// we have a redirect, rate the original url we stumbled on
-		theurl = stumbled_url;
-	}
-
-	var sv_detail = su_get_stumblevideo_detail();
-				
-	if (sv_detail)
-	{
-		var doc = getBrowser().contentDocument;
-		
-		su_stumblevideo_toolbar_rate = true;
-		var thumbup = doc.getElementById("thumbUp");
-		var thumbdown = doc.getElementById("thumbDown");
-		if (thumbup.src.indexOf("_sel") != -1)
-			su_dispatch_click(doc, "thumbUp");
-		else if (thumbdown.src.indexOf("_sel") != -1)
-			su_dispatch_click(doc, "thumbDown");
-		return;
-	}
-	
-	// grey out the buttons until the rating goes through
-	su_get_element("su_thumbup").disabled=true;
-	su_get_element("su_thumbdown").disabled=true;
-	su_get_element("su_thumbup").setAttribute("onclick", "");
-
-	var params = "";
-	params = su_arp(params, "url", theurl); 
-	params = su_append_sync_params(params);
-	
-	var context = new su_AsyncContext();
-	context.url = theurl;
-	context.ref_url = context.url;
-	su_post_url_server_async(
-				"unrate.php",
-				params,
-				null,
-				su_unrate_done,
-				context);
-
-	su_check_progress_listener();
-}
-
-function su_unrate_done(res)
-{
-	try {
-		if (res.status == 1)
-		{
-			su_enable_toolbar();
-			return;
-		}
-	} catch (e) { return; }
-	
-	if (res.status != 200)
-	{
-		su_http_error(res.error, res.status);
-		su_enable_toolbar();
-		return;
-	}
-	
-	var context = res.detail;
-	context.unrating = true;
-
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-
-	if (su_log_communication)
-		su_log("response unrate.php", s);
-
-	su_process_commands(s, context);
-	if (context.error && !context.discoveryCancelled)
-	{
-		su_enable_toolbar();
-		return;
-	}
-	
-	// Store in list of rated urls
-	su_delete_rating(context.url);
-
-	su_refresh_pagemeta(false, 3);
-	
-	su_check_progress_listener();
-}
-
-// Handler for button "rate"
-function su_block_domain()
-{
-	var url = su_get_browser_url();
-	
-	var rating = su_get_rating(url, (su_get_stumblevideo_detail() != null));
-	
-	var domain = su_get_tld(url);
-	
-	var blk_domain = su_is_domain_blocked(domain) ? -1 : 1;
-	
-	if (rating == null && blk_domain == 1)
-		rating = -2;
-	
-	if (rating == null && blk_domain == -1)
-	{
-		var context = new su_AsyncContext();
-		context.url = url;
-		context.ref_url = url;
-		var params = "";
-		params = su_arp(params, "url", url); 
-		params = su_arp(params, "blkdomain", -1); 
-		params = su_append_sync_params(params);
-		su_post_url_server_async(
-					"unrate.php",
-					params,
-					null,
-					su_unrate_done,
-					context);
-	}
-	else
-	{
-		su_rate(rating, false, true, false, blk_domain, url);
-	}
-}
-
-// Handler for button "rate"
-function su_rate(r, open_reviews, force_nostumble, force_comment, blk_domain, opt_url) 
-{
-	su_register_activity("rate");
-	su_check_progress_listener();
-	try {
-		su_close_info();
-	} catch (e) {}
-	
-	// If we are opening a comment button in a new tab
-	// we shouldn't be stumbling
-	if (open_reviews)
-		force_nostumble = true;
-
-	if ((stumbleid == 0) && (! su_promo_mode))
-		return;
-	
-	var rating = r;
-
-	var theurl = (opt_url) ? opt_url : su_get_browser_url();
-
-//	su_dd("rate", theurl, stumbled_redirect);
-	
-//	return;
-	
-	
-	if (stumbled_redirect != '' && theurl == stumbled_redirect)
-	{
-		// we have a redirect, rate the original url we stumbled on
-		theurl = stumbled_url;
-	}
-
-	if (rating > 0)
-	{
-		// We try to keep our own local thumbup count but defer to the server when it sends an
-		// SFC command
-		su_ds.incrementValue("$thumbup_count");
-		su_thumbup_count_changed();
-	}
-	else
-		su_ds.incrementValue("$thumbdown_count");
-	
-	var sv_detail = su_get_stumblevideo_detail();
-				
-	if (sv_detail &&
-				(! ((su_ds.getValue("$bad_stumble", false) && rating <= 0)
-				|| (su_ds.getValue("$great_stumble", false) && rating == 1))))
-	{
-		var doc = getBrowser().contentDocument;
-
-		su_stumblevideo_toolbar_rate = true;
-		if (rating == 1)
-			su_dispatch_click(doc, "thumbUp");
-		else if (rating <= 0)
-			su_dispatch_click(doc, "thumbDown");
-
-		return;
-	}
-	else if (sv_detail)
-	{
-		theurl = sv_detail.url;
-	}
-	
-	var cmp_url = theurl.toLowerCase();
-	if (cmp_url.indexOf("http://video." + su_servername + "/#p") == 0)
-		return;
-				
-	if (cmp_url.indexOf("http://video." + su_servername + "/?p") == 0)
-		return;
-
-	// grey out the buttons until the rating goes through
-	su_get_element("su_thumbup").disabled=true;
-	su_get_element("su_thumbdown").disabled=true;
-	su_get_element("su_thumbup").setAttribute("onclick", "");
-
-	su_quote = "";
-	if (getBrowser().contentWindow.getSelection)
-		su_quote = getBrowser().contentWindow.getSelection().toString();
-
-	var charset = "";
-	var webShell = getBrowser().docShell.QueryInterface(Components.interfaces.nsIDocCharset);
-	if (webShell)
-		charset = webShell.charset;
-	
-	var doc = getBrowser().contentDocument;
-	var context = new su_AsyncContext();
-	context.rating = rating;
-	context.url = theurl;
-	context.ref_url = su_get_browser_url(doc, true);
-	context.browser = getBrowser().selectedBrowser;
-	context.title = su_get_title(doc, context.ref_url);
-	context.force_nostumble = force_nostumble;
-	context.force_comment = force_comment;
-	context.timestamp = (new Date()).getTime();
-	context.open_reviews = open_reviews;
-	context.charset = charset;
-	context.referrer = doc.referrer;
-	context.stumblevideo_mode = null;
-	context.blk_domain = blk_domain;
-	
-	var postdata = "rating=" + rating + 
-					'&url=' + encodeURIComponent(theurl) + 
-					"&charset=" + encodeURIComponent(charset) + 
-					"&referer=" + encodeURIComponent(context.referrer) +
-					"&blkdomain=" + blk_domain;
-	
-	if (sv_detail)
-		postdata += "&videoperma=1";
-	
-	postdata = su_append_sync_params(postdata);
-	
-	su_post_url_server_async(
-				"rate.php",
-				postdata,
-				null,
-				su_rate_done,
-				context);
-	
-	su_check_progress_listener();
-}
-
-function su_rate_done(res)
-{
-	try {
-		if (res.status == 1)
-		{
-			su_enable_toolbar();
-			return;
-		}
-	} catch (e) { return; }
-	
-	if (res.status != 200)
-	{
-		su_http_error(res.error, res.status);
-		su_enable_toolbar();
-		return;
-	}
-	
-	var context = res.detail;
-	
-	if (context.browser == getBrowser().selectedBrowser)
-	{
-		if ((context.stumblevideo_mode == "page") || 
-					(! su_ds.getValue("$bad_stumble") && 
-						(context.rating <= 0)) || 
-					(! su_ds.getValue("$great_stumble") && 
-						(context.rating == 1))) 
-			su_disable_toolbar(context.rating);
-	}
-	
-	
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-	
-	if (su_log_communication)
-		su_log("response rate.php", s);
-	
-	// Parse response text
-	var parsed = s.split("\n");
-	var prepend = "";
-	var discovery = false;
-	var firstrate = 0;
-	var canceled = false;
-	
-	// Iterate through commands
-	for (var i = 0; i < parsed.length; i++)
-	{
-		if (parsed[i] == "")
-			continue;
-
-		// Parse command structure
-		var command = parsed[i].split(" ");
-		switch(command[0])
-		{
-			case "URL": prepend += command[1] + "\n"; break;
-			case "FIRSTRATER": firstrate = command[1]; break;
-			case "NEWURL" : 
-				// do 800x600+
-				if (context.rating == 1)
-				{
-					discovery = true;
-					su_disable_toolbar(context.rating);
-					var detail = new Object();
-					detail.finalized = false;
-					detail.submitted = false;
-					detail.url = context.url;
-					detail.uri_suffix = "newurl.php";
-					detail.tagtext = "";
-					detail.postdata = "url=" + encodeURIComponent(context.url) + 
-								"&title=" + encodeURIComponent(context.title) + 
-								"&charset=" + encodeURIComponent(context.charset) + 
-								"&rating=" + context.rating + 
-								"&quote=" + encodeURIComponent(su_quote) + 
-								"&referer=" + encodeURIComponent(context.referrer) +
-								"&catidlist=" + encodeURIComponent('');
-	
-					if (su_photoblogimage)
-					{
-						detail.postdata += "&image=" + encodeURIComponent(su_photoblogimage.src) + 
-									"&width=" + su_photoblogimage.width + 
-									"&height=" + su_photoblogimage.height;
-						su_photoblogimage = null;
-					}
-		
-					var width = (command.length >= 2) ? parseInt(command[1]) : 700;
-					var height = (command.length >= 3) ? parseInt(command[2]) : 450;
-					
-					var dialog_url = "chrome://stumbleupon/content/discoveryDialog.xul";
-					dialog_url += "#d" + su_ds.incrementValue("~discovery_count");
-					
-					su_ds.define("disc_dialog_url:disc_detail", dialog_url, detail);
-					su_ds.addEventListener(
-							"discdlgclose",
-							function (event) {
-								window.su_handle_discovery_dialog_close(event); });
-					
-					window.openDialog(
-								dialog_url,
-								"",
-								"chrome,dialog,centerscreen,width=" + width + 
-									",height=" + height + 
-									",resizable=1",
-								detail);
-					
-					// calculate this before we get the add comment
-					var da = new Date();
-					var now = da.getTime();
-					// Store in list of rated urls
-					
-					su_store_rating(context.url, (su_d_rec_rating) ? 2 : context.rating);
-				}
-				else if ((context.rating <= 0) && 
-							(context.browser == getBrowser().selectedBrowser))
-				{
-					var tmpres = new Object();
-					tmpres.detail = new su_AsyncContext();
-					tmpres.detail.url = context.url;
-					tmpres.status = 200;
-					tmpres.responseText = "";
-					su_unrate_done(tmpres);
-					canceled = true;
-					if (context.blk_domain == 0)
-						setTimeout(su_show_thumbdown_discovery_alert, 0);
-				}
-				
-				var time_between_tagging = now - su_last_typed_tag;
-				var i_just_stumbled = false;
-								
-				return;
-			default:
-				su_process_command(parsed[i], context, command);
-				if (context.error)
-				{
-					su_enable_toolbar();
-					return;
-				}
-				break;
-		}
-	}
-	
-	setTimeout(su_refresh_pagemeta, 0, false, 9);
-	
-	if (canceled)
-		return;
-	
-	if ((context.rating == 1) && (! discovery))
-	{
-		if (! su_ds.getValue("$shown_reviews_info"))
-			su_display_info("reviews");
-		else if (! su_ds.getValue("$shown_referral_info"))
-			su_display_info("referral");
-	}
-	
-	// Store in list of rated urls
-	su_store_rating(context.url, (su_d_rec_rating) ? 2 : context.rating);
-
-	// Prepend URLs if we got any
-	if (prepend != "")
-	{
-		prior = su_read_file_user("stumbleurls");
-		su_write_file_user("stumbleurls", prepend + prior);
-	}
-
-	var searchbox_value = su_get_element("su_searchbox").value;
-	if ((! su_ds.getValue("$show_field")) || (searchbox_value == su_tag_instructions))
-		searchbox_value = "";
-		
-	// calculate this before we get the add comment
-	var now = (new Date()).getTime();
-	var time_between_tagging = now - su_last_typed_tag;
-	var opened_website_info = false;
-	if (su_photoblogimage)
-	{
-		opened_website_info = true;
-		su_website_info(false, context.url, firstrate);
-	}
-//	else if (context.force_comment || ((! context.open_reviews) && 
-//				su_ds.getValue("$comment_firstrating") && firstrate != 0))
-//	{
-//		su_unfocus_searchbox();
-//
-//		window.openDialog(
-//					"chrome://stumbleupon/content/ratingDialog.xul",
-//					"StumbleUpon Review",
-//					"chrome,modal,dialog,centerscreen,dependent", 
-//					context.url, 
-//					firstrate, 
-//					searchbox_value,
-//					su_quote);
-//	}
-	
-	var tag_term = su_get_element('su_searchbox').value;
-	
-	// if they've typed a tag in within the last 10 seconds, tag it
-	if (context.rating == 1 && tag_term != '' && su_last_typed_tag != 0 && time_between_tagging < 1000 * 6)
-	{
-		su_tagit(context.url, tag_term, false, context.title, context.ref_url);
-		
-		// clear it once we are done..
-		su_last_typed_tag = 0;
-		su_old_search = '';
-		//su_get_element('su_searchbox').value = '';
-	}
-		
-	var i_just_stumbled = false;
-	
-	// Stumble-On-Rate
-	if ( (! context.force_nostumble) && 
-		((su_ds.getValue("$bad_stumble") && context.rating <= 0)
-		|| (su_ds.getValue("$great_stumble") && context.rating == 1)) ) 
-	{
-		stumble(0);	
-		i_just_stumbled = true;
-	}
-	
-	if ((! opened_website_info) && (! i_just_stumbled) && 
-				context.open_reviews && (context.rating == 1) && 
-				(context.stumblevideo_mode != "page"))
-	{
-		su_website_info(0, context.url, 0);
-	}
-	
-	su_check_progress_listener();
-}
-
-function su_prepare_thumbdown_menu()
-{
-	var url = su_get_browser_url();
-	
-	var rating = su_get_rating(url, (su_get_stumblevideo_detail() != null));
-		
-	// Handle checks
-	su_get_element('su_thumbdown_menu_notforme').setAttribute("checked", ((rating == -2) || (rating == 0))); 
-	su_get_element('su_thumbdown_menu_spam').setAttribute("checked", (rating == -5));
-	su_get_element('su_thumbdown_menu_dupe').setAttribute("checked", (rating == -3));
-//	su_get_element('su_thumbdown_menu_saturation').setAttribute("checked", (rating == -4));
-
-	if (! su_host.places)
-	{
-		su_get_element('su_thumbdown_menu_blockdomain').hidden = true;
-		su_get_element("su_thumbdown_menu_separator").hidden = true;
-		return;
-	}
-	su_get_element("su_thumbdown_menu_separator").hidden = false;
-	
-	var el = su_get_element('su_thumbdown_menu_blockdomain');
-	el.hidden = false; // for good measure
-
-	// Handle block domain label
-	
-	var domain = su_get_tld(url);
-
-	if (domain == null)
-	{
-		el.disabled = true;
-		el.label = "Website: ''";
-		el.setAttribute("checked", "false");
-	}
-	else if (domain == su_servername)
-	{
-		el.disabled = true;
-		el.label = "Website: '" + domain + "'";
-		el.setAttribute("checked", "false");
-	}
-	else if (su_is_domain_blocked(domain))
-	{
-		el.disabled = false
-		el.label = "Unblock website: '" + domain + "'";
-		el.setAttribute("checked", "true");
-	}
-	else
-	{
-		el.disabled = false
-		el.label = "Block website: '" + domain + "'";
-		el.setAttribute("checked", "false");
-	}
-}
-
-function su_show_thumbdown_discovery_alert()
-{
-
-	var promptService = su_get_service(
-				"@mozilla.org/embedcomp/prompt-service;1",
-				"nsIPromptService");
-	
-	promptService.alert(
-			window,
-			"Rating Canceled",
-			"This page is new to StumbleUpon.  Use the \n" +
-				"'I like it!' button to add it.");
-}
-
-function su_handle_discovery_dialog_close(event)
-{
-	var detail = su_ds.lookup("disc_dialog_url:disc_detail", event.URL);
-	
-	if (detail.finalized)
-		return;
-	
-	detail.finalized = true;
-	
-	if (detail.submitted)
-	{
-		su_rate_getmeta(detail.url, true);
-		
-		if (detail.tagtext != "")
-		{
-			var count = su_ds.getValue("$tagged_discovery_count");
-			count ++;
-			su_ds.setValue("$tagged_discovery_count", count);
-			if (count == 3)
-			{
-				su_ds.setValue("$show_tag", true);
-				su_ds.setValue("$shown_tag", true);
-				su_ds.setValue("$show_flag", true);
-				su_set_visible("su_tag",  su_ds.getValue("$show_field"));
-				su_set_visible("su_tag2", (! su_ds.getValue("$show_field")));
-	//			setTimeout(
-	//						alert,
-	//						500,
-	//						"For convenience, the Tag control has been added to the toolbar.\nIf this is unwelcome, you can remove it via:\ntoolbar->Tools->Toolbar Options.");
-			}
-			
-			var tag = su_normalize_tag(detail.tagtext);
-		
-			su_load_tags(detail.url);
-			
-			// Add the new tag
-			var o = new Object();
-			o.url = detail.url;
-			o.tag_list = tag;
-			su_tag_lists_by_url[detail.url] = tag;
-			su_tags.unshift(o);
-			
-			su_store_tags();
-		
-			su_disable_tag_toolbar(tag);
-			su_old_search = tag;
-		}
-	}
-	else
-	{
-		var context = new su_AsyncContext();
-		context.url = detail.url;
-		context.ref_url = context.url;
-		context.quiet = true;
-		context.discoveryCancelled = true;
-		var params = "url=" + encodeURIComponent(context.url); 
-	
-		params = su_append_sync_params(params);
-	
-		su_post_url_server_async(
-					"unrate.php",
-					params,
-					null,
-					su_unrate_done,
-					context);
-	}
-	su_check_progress_listener();
-}
-
-function su_prepare_reporting_menu(submenu, url_detail, tools_menu, url)
-{
-	var stumbler_name = su_get_profile_nickname(url);
-	
-	var item;
-	if (! tools_menu)
-	{
-		item = document.createElement("menuitem");
-		item.setAttribute("label", "This stumble is:");
-		item.setAttribute("style", "font-weight: bold; color: #404040;");
-		item.setAttribute("disabled", "true");
-		submenu.appendChild(item);
-	}
-	
-	if (! stumbler_name)
-	{
-		item = document.createElement("menuitem");
-		item.setAttribute("label", " Broken or 404");
-		item.setAttribute("tooltiptext", "Report that this page is broken");
-		item.setAttribute("oncommand", "su_handle_report_404_command('" + url + "');");
-		submenu.appendChild(item);
-	}
-
-	item = document.createElement("menuitem");
-	item.setAttribute("label", " Factually incorrect");
-	item.setAttribute("tooltiptext", "Report that this page contains bogus info");
-	item.setAttribute("oncommand", "su_handle_report_inaccurate_command('" + url + "');");
-	submenu.appendChild(item);
-	
-	if (tools_menu)
-	{
-		if (stumbler_name)
-		{
-			item = document.createElement("menuitem");
-			item.setAttribute("label", " Adult content...");
-			item.setAttribute("tooltiptext", "Report that the " + stumbler_name + " profile contains adult content");
-			item.setAttribute("oncommand", "su_handle_report_adult_profile_command('" + url + "');");
-			submenu.appendChild(item);
-		}
-		else
-		{
-			item = document.createElement("menuitem");
-			if (url_detail)
-				item.setAttribute("label", " Not about " + url_detail.cur_topic_name + "...");
-			else
-				item.setAttribute("label", " Suggest topic change...");
-			item.setAttribute("tooltiptext", "Choose a different topic for this page");
-			item.setAttribute("oncommand", "su_handle_report_miscat_command('" + url + "');");
-			submenu.appendChild(item);
-		}
-	}
-	
-	if (url_detail && url_detail.language)
-	{
-		item = document.createElement("menuitem");
-		item.setAttribute("label", " Not in " + url_detail.language + "...");
-		item.setAttribute("tooltiptext", "Choose a different language for this page");
-		item.setAttribute("oncommand", "su_handle_report_wrong_language_command('" + url + "');");
-		submenu.appendChild(item);
-	}
-
-	item = document.createElement("menuitem");
-	item.setAttribute("label", " Spam...");
-	item.setAttribute("tooltiptext", "Report this as bad solicitation");
-	item.setAttribute("oncommand", "su_handle_report_spam_command('" + url + "');");
-	submenu.appendChild(item);
-
-	item = document.createElement("menuitem");
-	item.setAttribute("label", " Unsafe");
-	item.setAttribute("tooltiptext", "Report that this page is a security risk");
-	item.setAttribute("oncommand", "su_handle_report_badware_command('" + url + "');");
-	submenu.appendChild(item);
-}
-
-function su_prepare_stumble_report_menu(event, url)
-{
-	if (event.originalTarget.id != "su_stumble_report_popup")
-		return;
-	
-	var submenu = su_get_element("su_stumble_report_popup");
-
-	if (submenu.getAttribute("data-url") == url)
-		return;
-	
-	submenu.removeAttribute("data-url");
-	submenu.setAttribute("data-url", url);
-
-	// Check if a menu already exists -> If so, we need to remove it
-	var url_detail = su_ds.lookup("url:url_detail", url);
-	
-	while(submenu.childNodes.length)
-		submenu.removeChild(submenu.firstChild);
-	
-	su_prepare_reporting_menu(submenu, url_detail, true, url);
-}
-
-/*
-// handles discovery dialog accept
-function su_handle_discovery_dialog_accept(detail)
-{
-	if (detail.tagtext != "")
-	{
-		var count = su_ds.getValue("$tagged_discovery_count");
-		count ++;
-		su_ds.setValue("$tagged_discovery_count", count);
-		if (count == 3)
-		{
-			su_ds.setValue("$show_tag", true);
-			su_ds.setValeu("$shown_tag", true);
-			su_ds.setValue("$show_flag", true);
-			su_set_visible("su_tag",  su_ds.getValue("$show_field"));
-			su_set_visible("su_tag2", (! su_ds.getValue("$show_field")));
-//			setTimeout(
-//						alert,
-//						500,
-//						"For convenience, the Tag control has been added to the toolbar.\nIf this is unwelcome, you can remove it via:\ntoolbar->Tools->Toolbar Options.");
-		}
-	}
-}
-
-// handles discovery dialog cancel
-function su_handle_discovery_dialog_cancel(detail, state)
-{
-	var context = new su_AsyncContext();
-	context.url = detail.rated_uri;
-	context.ref_url = context.url;
-	var params = "url=" + encodeURIComponent(context.url); 
-
-	params = su_append_sync_params(params);
-
-	su_post_url_server_async(
-				"unrate.php",
-				params,
-				null,
-				su_unrate_done,
-				context);
-
-	su_check_progress_listener();
-}
-*/
-
-// used by ratingDialog to add a comment
-//function su_add_review(urlid, review)
-//{
-//	su_post_url_server_async(
-//				"addcomment.php",
-//				"urlid=" + urlid + 
-//					"&comment=" + encodeURIComponent(review),
-//				null,
-//				null,
-//				null);
-//}
-
-function su_handle_error(error)
-{
-	su_set_server_location('error.php?error=' + error, null, false);
-}
-
-var su_disabled_button_color = null;
-
-//
-// Get the color used by the current theme for disabled buttons because we want to
-// use that same color for an active thumbup button (but without disabling it)
-//
-function su_get_disabled_button_color()
-{
-	if(!su_disabled_button_color)
-	{
-		try
-		{
-			// Get the current thumbup state 
-			var elThumbup = su_get_element("su_thumbup");
-			var oldMode = elThumbup.getAttribute("mode");
-			var oldDisabled = elThumbup.disabled;
-			
-			// Disable the button and remove the mode so we can compute the disabled style
-			su_remove_attribute("su_thumbup", "mode");
-			elThumbup.disabled = true;
-			var disabledStyle = document.defaultView.getComputedStyle(elThumbup, "");
-			
-			// Restore the thumbup button to its original state
-			if(oldMode)
-				elThumbup.setAttribute("mode", oldMode);
-			elThumbup.disabled = oldDisabled;
-			
-			// And grab the disabled button color from the computed stylesheet
-			if(disabledStyle.color)
-			{
-				su_disabled_button_color = disabledStyle.color;
-			}
-		}
-		catch(ex)
-		{
-			// We are being defensive here because this code is being added late in a release cycle and I'm nervous
-			// about support for getComputedStyle
-		}
-		
-		if(!su_disabled_button_color)
-		{
-			su_disabled_button_color = "GrayText";
-		}
-	}
-	return su_disabled_button_color;
-}
-			
-
-// Greys out one of the rating buttons
-function su_disable_toolbar(rating)
-{
-	// enable everything first so we don't get su_website_info collisions?
-	
-	su_set_image("su_website_info",
-				"chrome://stumbleupon/content/skin/comment.png");
-	
-	// We use the disabled color for the thumbup button text when the user has already 
-	// rated the site
-	var disabledColor = su_get_disabled_button_color();
-	su_get_element("su_thumbup").style.color = disabledColor;
-	
-	if (rating > 0)
-	{
-		su_set_attribute("su_thumbup", "mode", "thumbup");
-		su_set_attribute("su_thumbdown", "mode", "thumbup");
-		su_set_image("su_referral_menu", 
-					"chrome://stumbleupon/content/skin/icon_tb_share2.png");
-	}
-	else
-	{
-		su_set_attribute("su_thumbup", "mode", "thumbdown");
-		su_set_attribute("su_thumbdown", "mode", "thumbdown");
-		su_set_image("su_referral_menu", 
-					"chrome://stumbleupon/content/skin/icon_tb_share.png");
-	}
-
-	su_toolbar_disabled = true;
-}
-
-// Un-greys all the rating buttons
-function su_enable_toolbar()
-{
-	su_toolbar_disabled = false;
-	su_remove_attribute("su_thumbup", "mode");
-	su_get_element("su_thumbup").style.color = '';
-	su_remove_attribute("su_thumbdown", "mode");
-	su_get_element("su_thumbup").disabled = false;
-	su_get_element("su_thumbdown").disabled = false;
-	if (!su_get_element("su_website_info").image.indexOf('bubble'))
-		su_get_element("su_website_info").image="chrome://stumbleupon/content/skin/bubble.png";
-	
-	su_set_image("su_referral_menu", 
-				"chrome://stumbleupon/content/skin/icon_tb_share.png");
-}
-
-// called by the global configure-toolbar event, during init and by
-// the searchbox context menuitem listeners to set the autocomplete
-// type for the searchbox
-function su_set_autocomplete_type(type)
-{
-	var oldval = su_ds.getValue("$autocomplete_type");
-	
-	var searchbox = su_get_element('su_searchbox');
-	if ((type == "auto") && (oldval == "query"))
-		type = "query,tag";
-	else if ((type == "auto") && (oldval == "tag"))
-		type = "tag,query";
-	
-	if (type == "query,tag")
-	{
-		searchbox.contextItemAChecked = true;
-		searchbox.contextItemBChecked = false;
-		searchbox.contextItemCChecked = false;
-		su_ds.setValue("$autocomplete_type", "query,tag");
-	}
-	else if (type == "tag,query")
-	{
-		searchbox.contextItemAChecked = true;
-		searchbox.contextItemBChecked = false;
-		searchbox.contextItemCChecked = false;
-		su_ds.setValue("$autocomplete_type", "tag,query");
-	}
-	else if (type == "query")
-	{
-		su_ds.setValue("$autocomplete_type", "query");
-		searchbox.contextItemAChecked = false;
-		searchbox.contextItemBChecked = true;
-		searchbox.contextItemCChecked = false;
-	}
-	else if (type == "tag")
-	{
-		su_ds.setValue("$autocomplete_type", "tag");
-		searchbox.contextItemAChecked = false;
-		searchbox.contextItemBChecked = false;
-		searchbox.contextItemCChecked = true;
-	}
-
-	if (oldval != type)
-		searchbox.open = false;
-}
-
-// handles the click event for the searchbox
-function su_searchbox_click_kludge(eventId)
-{
-	// This handles value selection in the case where the user is 
-	// clicking back and forth between the searchbox and another field 
-	// (like urlbar).  Without this kludge, the text is selected only
-	// every second time.  (ref: Firefox 1.5, XP) -- JW
-	
-	switch (eventId)
-	{
-		case "click":
-			var searchbox = su_get_element('su_searchbox');
-			var selected = (searchbox.value.length != 0)
-						&& ((searchbox.selectionEnd - searchbox.selectionStart) == searchbox.value.length);
-
-			if ((! su_searchbox_was_focused) && (! selected))
-				searchbox.select();
-			
-			su_searchbox_was_focused = true;
-		break;
-		case "blur":
-			su_searchbox_was_focused = false;
-		break;
-	}
-
-	return true;
-}
-
-// handles the focus event for the searchbox
-function su_handle_searchbox_focus(event)
-{
-	var searchbox = su_get_element('su_searchbox');
-
-	su_visited_searchbox = 1;
-	
-	if (searchbox.value == su_tag_instructions)
-	{
-		searchbox.value = '';
-		searchbox.removeAttribute("mode");
-	}
-	else
-	{
-		if (su_url_has_tag)
-		{	
-			su_old_search = searchbox.value;
-
-			su_enable_tag_toolbar();
-		}
-		
-		if (! su_keep_searchbox_focus)
-			searchbox.select();
-	}
-}
-
-// handles the blur event for the searchbox
-function su_handle_searchbox_blur()
-{
-	su_searchbox_click_kludge("blur");
-}
-
-// handles the keyup event for the searchbox
-function su_handle_searchbox_keyup(evt)
-{
-	var searchbox = su_get_element('su_searchbox');
-
-	if(searchbox.value == su_old_search)
-		return false;
-	
-	su_old_search = searchbox.value;
-	
-	// save the time we last did this        	
-	var da = new Date();
-	su_last_typed_tag = da.getTime();
-
-	searchbox.removeAttribute("mode");
-	
-	if (su_old_search == "")
-		su_get_element('su_tag').setAttribute("tooltiptext", su_get_element('su_tag').getAttribute("tooltiptext2"));
-	else
-		su_get_element('su_tag').setAttribute("tooltiptext", "Tag this page as '" + 	su_get_element('su_searchbox').value + "'");
-
-	return true;
-}
-
-// handles the textentered event for the searchbox
-function su_handle_searchbox_textentered(event)
-{
-	var autocomplete_type = su_ds.getValue("$autocomplete_type");
-	if (event.shiftKey)
-	{	
-		if (autocomplete_type == "query,tag")
-			su_ds.setValue("$autocomplete_type", "tag,query");
-		
-		// Shift+Enter tags
-		su_handle_tag_command(false);
-	}
-	else
-	{
-		if (autocomplete_type == "tag,query")
-			su_ds.setValue("$autocomplete_type", "query,tag");
-		
-		su_old_search = su_get_element('su_searchbox').value;
-
-		// when you search, we know it's not a tag on i-like-it
-		su_last_typed_tag = 0;
-
-		var new_tab = false;
-		var platform_ctrl_key = (su_host.mac) ? ((event.keyCode == 77) ? event.ctrlKey : event.metaKey) : event.ctrlKey;
-
-		if ((event.button == 1) || platform_ctrl_key)
-			new_tab = true;
-		new_tab = new_tab || su_ds.getValue("$search_new_window");
-	
-		var query = su_get_element("su_searchbox").value;
-	
-		su_stumble_in_tag(su_get_element('su_searchbox').value, new_tab);	
-	}
-}
-
-// handles the textreverted event for the searchbox
-function su_handle_searchbox_textreverted()
-{
-	if (su_old_search != "")
-	{
-		su_get_element("su_searchbox").value = su_old_search;
-		su_get_element("su_searchbox").select();
-		su_get_element("su_searchbox").removeAttribute("mode");
-	}
-	else if (su_url_has_tag)
-	{
-		su_disable_tag_toolbar(su_tag_lists_by_url[su_get_browser_url()]);
-	}
-}
-
-/*
-function su_handle_searchbox_pagenavigationkey(event)
-{
-	su_keep_searchbox_focus = false;
-	su_unfocus_searchbox();
-	setTimeout(function (win, event) { win.su_handle_searchbox_pagenavigationkey_wrapped(event); } , 1000, window, event.keyCode);
-}
-
-function su_handle_searchbox_pagenavigationkey_wrapped(keyCode)
-{
-	var evt = document.createEvent("KeyboardEvent");
-	evt.initKeyEvent(
-				"keypress",        //  in DOMString typeArg,
-				true,             //  in boolean canBubbleArg,
-				true,             //  in boolean cancelableArg,
-				null,             //  in nsIDOMAbstractView viewArg,  Specifies UIEvent.view. This value may be null.     
-				false,            //  in boolean ctrlKeyArg,
-				false,            //  in boolean altKeyArg,
-				false,            //  in boolean shiftKeyArg,
-				false,            //  in boolean metaKeyArg,
-				keyCode,         //  in unsigned long keyCodeArg,
-				0);              //  in unsigned long charCodeArg);
-	getBrowser().dispatchEvent(evt);
-//	su_get_element("su_searchbox").focus();
-}
-*/
-
-function su_get_autocomplete_results(autocomplete_type, str, max_item_count, supplemental_candidates)
-{
-	var types = autocomplete_type.split(",");
-	
-	var i;
-	var items = new Array();
-	for (i = 0; i < types.length; i++)
-		items = su_get_autocomplete_results2(types[i], str, max_item_count, items, supplemental_candidates);
-	
-	return items;
-}
-
-// ultimately called by the searchbox to get an array of items to
-// populate the autocomplete list
-function su_get_autocomplete_results2(autocomplete_type, str, max_item_count, items, supplemental_candidates)
-{
-	// Each array item is an object with properties that are analogous
-	// to attributes of the autocomplete list item.  In other words, 
-	// item.label results in the search widget doing something like:
-	// autocomplete-item.setAttribute("label", item.label);
-	// -- JW
-	
-	// Supplemental candidate matches are placed at the top of the 
-	// results.  Other items are ranked in the autocomplete list in the
-	// same order as they appear in the queries and tags files, which 
-	// is to say in reverse chronological order.  But we may want to 
-	// add a heuristic that places more frequently used tags & queries 
-	// near the top. -- JW
-	var pre_items_count = items.length;
-	var source;
-	var o;
-
-	if ((str == "") || (str == su_tag_instructions))
-	{
-		// add recent items
-
-		if (autocomplete_type == "query")
-		{
-			su_load_queries();
-			source = su_queries;
-		}
-		else if (autocomplete_type == "tag")
-		{
-			su_load_tags(null);
-			source = su_tags;
-		}
-
-		for (var i = (- supplemental_candidates.length); (i < source.length) && (items.length <= max_item_count); i++)
-		{
-			var candidate;
-			if (i < 0)
-			{
-				candidate = supplemental_candidates[-i - 1];
-			}
-			else
-			{
-				if (source == su_queries)
-					candidate = source[i];
-				else if (source == su_tags)
-					candidate = source[i].tag_list;
-			}
-				
-			if (candidate.search(/^\s*$/) != -1)
-				continue;
-
-			var duplicate = false;
-			for (var j = 0; j < items.length; j++)
-			{
-				if (candidate == items[j].label)
-				{
-					duplicate = true;
-					if (j < pre_items_count)
-						items[j].style = "color:#ff3300;";
-					break;
-				}
-			}
-			if (! duplicate)
-			{
-				o = new Object();
-				o.label = candidate;
-				if (autocomplete_type == "tag")
-					o.style = "color:#ff3300;";
-				items.push(o);
-			}
-		}
-	}
-	else 
-	{
-		// add the subset of items
-		
-		if (autocomplete_type == "query")
-		{
-			if (str.length == 1)
-				su_load_queries();
-			source = su_queries;
-		}
-		else if (autocomplete_type == "tag")
-		{
-			if (str.length == 1)
-				su_load_tags(null);
-			source = su_tags;
-		}
-
-		str = su_normalize_tag(str);
-		str = su_escape_regexp_chars(str);
-
-		var pattern = new RegExp("^" + str + "|, " + str, "i");
-
-		for (var i = (- supplemental_candidates.length); (i < source.length) && (items.length <= max_item_count); i++)
-		{
-			var candidate
-			if (i < 0)
-			{
-				candidate = supplemental_candidates[-i - 1];
-			}
-			else
-			{
-				if (source == su_queries)
-					candidate = source[i];
-				else if (source == su_tags)
-					candidate = source[i].tag_list;
-			}
-
-			if (candidate.search(/^\s*$/) != -1)
-				continue;
-
-			if (candidate.search(pattern) != -1)
-			{
-				
-				var duplicate = false;
-				for (var j = 0; j < items.length; j++)
-				{
-					if (candidate == items[j].label)
-					{
-						duplicate = true;
-						if (j < pre_items_count)
-							items[j].style = "color:#ff3300;";
-						break;
-					}
-				}
-				if (! duplicate)
-				{
-					o = new Object();
-					o.label = candidate;
-					if (autocomplete_type == "tag")
-						o.style = "color:#ff3300;";
-					items.push(o);
-				}
-			}
-		}
-	}
-	
-//	o = new Object();
-//	o.style = "-moz-binding: url(chrome://global/content/bindings/menu.xml#menuitem-iconic);";
-//	o.image = "chrome://stumbleupon/content/skin/icon_tb_photo_hover.png";
-//	o.label = "Photos";
-//	items.push(o);
-	
-	return items;
-	
-}
-
-// adds tag to toolbar
-function su_disable_tag_toolbar(tag)
-{
-	if (!su_url_has_tag)
-		su_old_search = su_get_element("su_searchbox").value;
-
-	su_url_has_tag = true;
-	
-	su_get_element("su_searchbox").value = tag;
-
-	// This timeout kludge fixes a bug where DOM change events aren't being 
-	// generated when setAttribute is called within the execution path of a
-	// textreverted event handler for the su_searchbox.  (ref: Firefox 1.5, 
-	// XP) -- JW
-	setTimeout('su_get_element("su_searchbox").setAttribute("mode", "tag")', 0);
-
-	su_get_element("su_tag").image="chrome://stumbleupon/content/skin/tag2.png";
-	su_get_element('su_tag').setAttribute("tooltiptext", "Page tagged as '" + tag + "'. Click to remove.");
-	su_get_element("su_tag2").image="chrome://stumbleupon/content/skin/tag2.png";
-	su_get_element('su_tag2').setAttribute("tooltiptext", "Page tagged as '" + tag + "'. Click to remove.");
-}
-
-// removes tag from toolbar
-function su_enable_tag_toolbar()
-{
-	su_url_has_tag = false;
-
-	if (su_visited_searchbox == 0)
-	{
-		su_get_element("su_searchbox").value = su_tag_instructions;
-		su_get_element("su_searchbox").setAttribute("mode", "prompt");
-	}
-	else if (su_old_search != "")
-	{
-		su_get_element("su_searchbox").value = su_old_search;
-		su_get_element("su_searchbox").removeAttribute("mode");
-	}
-	else
-	{
-		su_get_element("su_searchbox").removeAttribute("mode");
-	}
-
-	su_get_element("su_tag").image="chrome://stumbleupon/content/skin/tag.png";
-	su_get_element("su_tag2").image="chrome://stumbleupon/content/skin/tag.png";
-
-	if (su_old_search == "")
-	{
-		su_get_element('su_tag').setAttribute("tooltiptext", su_get_element('su_tag').getAttribute("tooltiptext2"));
-		su_get_element('su_tag2').setAttribute("tooltiptext", su_get_element('su_tag2').getAttribute("tooltiptext2"));
-	}
-	else
-	{
-		su_get_element('su_tag').setAttribute("tooltiptext", "Tag this page as '" + su_old_search + "'");
-		su_get_element('su_tag2').setAttribute("tooltiptext", "Tag this page as '" + su_old_search + "'");
-	}
-
-	return true;
-}
-
-// su_sign_up_page is the web site's sign up page
-function su_sign_up_page(url)
-{
-	su_visited_login_page = true;
-	su_verify_cookie_perms(false);
-	su_ds.setValue("~visited_signup", true);
-	if (su_is_server_page(url, "sign_up.php?pre2=login"))
-		su_login_behavior_page();
-}
-
-function su_login_behavior_page()
-{
-	su_visited_login_page = true;
-	setTimeout(su_show_signin_dialog, 0);
-}
-
-function su_attach_api(doc)
-{
-	try
-	{
-		var win = doc.defaultView.wrappedJSObject;
-		win.suToolbarApi = su_toolbar_api;
-		if(win.onSuToolbarApiReady)
-		{
-			win.onSuToolbarApiReady();
-		}
-	}
-	catch(ex)
-	{
-		// Older browsers might not support wrappedJSObject, be defensive here.
-	}
-}
-
-function su_wire_portal_links(doc)
-{
-	var el;
-	var links;
-	var i;
-	
-	//!!! This could be pretty expensive on pages with large link count.
-	//    Unfortunately, we link to login.php many places besides the
-	//    header (i.e. a send message error on the public view of
-	//    a Favorites page).
-//	el = doc.getElementById("headerLoginLink");
-//	if (el)
-//		el.addEventListener("click", su_handle_page_login_click, true);
-	
-	el = doc.getElementById("downloadFavoritesLink");
-	if (el)
-		el.addEventListener("click", su_handle_page_favorites_download_click, true);
-	
-	el = doc.getElementById("stumble_search");
-	if (el)
-		el.addEventListener("click", su_handle_page_search_click, true);
-}
-
-function su_handle_page_login_click(event)
-{
-	setTimeout(su_show_signin_dialog, 0);
-	return su_cancel_event(event);
-}
-
-function su_handle_page_logout_click(event)
-{
-	if (stumbleid == 0)
-		return true;
-	
-	setTimeout("su_handle_logout(true)", 0);
-	
-	return su_cancel_event(event);
-}
-
-function su_handle_page_favorites_download_click(event)
-{
-	var ps;
-	
-	if (! su_host.places)
-	{
-		ps = su_get_service(
-				"@mozilla.org/embedcomp/prompt-service;1",
-				"nsIPromptService");
-		ps.alert(window, "StumbleUpon", "You must have Firefox 3 or greater to download favorites.");
-		return;
-	}	
-	
-	if (stumbleid == 0)
-	{
-		ps = su_get_service(
-				"@mozilla.org/embedcomp/prompt-service;1",
-				"nsIPromptService");
-		ps.confirm(window, "StumbleUpon", "You must be signed-in to download favorites.");
-		return;
-	}
-	
-	setTimeout(su_handle_download_favs_command, 0);
-	
-	return su_cancel_event(event);
-}
-
-function su_handle_page_search_click(event)
-{
-	var el;
-	var doc = event.target.ownerDocument;
-	
-	el = doc.getElementById("search_q");
-	
-	if (el.value != "")
-		su_stumble_in_tag(el.value, su_new_tab(event));
-	
-	return su_cancel_event(event);
-}
-
-// su_signup_page is the sign up page that the toolbars sends them to.
-function su_signup_page(doc)
-{
-	su_verify_cookie_perms(false);
-
-	var el;
-	el = doc.getElementById("interests");
-	if (el)
-		su_set_legacy_user_interests(el.innerHTML);
-	
-	var init_toolbar = (doc.getElementById("signup_success") != null);
-	
-	el = doc.getElementById("challenge");
-	if (el && el.hasAttribute("value") && (el.getAttribute("value") != ""))
-	{
-		su_init_new_user(el.getAttribute("value"), init_toolbar);
-	}
-	else if (init_toolbar)
-	{
-		su_new_user = false;
-		var detail = new Object();
-		detail.skip_cookies = false;
-		detail.ignore_cookies = true;
-		detail.new_profile = true;
-		detail.new_user_prompt = true;
-		su_invoke_global_event("login", detail);
-	}
-	else if (stumbleid != 0)
-	{
-		su_store_user_interests();
-		su_refresh_category_selector_batched();
-	}
-}
-
-function su_login_page_after()
-{
-	var userid_saved = stumbleid;
-	var profile_change = su_process_cookies(false);
-	
-	if (profile_change && (stumbleid != userid_saved))
-	{
-		var detail = new Object();
-		detail.skip_cookies = true;
-		detail.ignore_cookies = true;
-		detail.new_profile = profile_change.new_profile;
-		detail.new_user_prompt = false;
-		su_invoke_global_event("login", detail);
-	}
-}
-
-function su_find_friends_page(url)
-{
-	su_ds.setValue("~visited_find_friends", true);
-	var userid_saved = stumbleid;
-	var profile_change = su_process_cookies(false);
-	if (profile_change && (stumbleid != userid_saved))
-	{
-		var detail = new Object();
-		detail.skip_cookies = true;
-		detail.ignore_cookies = true;
-		detail.new_profile = true;
-		detail.new_user_prompt = true;
-		su_invoke_global_event("login", detail);
-	}
-	else
-	{
-		if (su_ds.getValue("#find_friends_optin"))
-		{
-			su_ds.incrementValue("$shown_find_friends_clicks");
-			if ((! su_ds.getValue("$show_searchlinks_score")) &&
-						(! su_ds.getValue("$show_searchlinks_friends")))
-			{
-				su_ds.setValue("$show_searchlinks_score", true);
-				su_ds.setValue("$show_searchlinks_friends", true);
-			}
-			else
-			{
-				su_ds.setValue("$show_searchlinks_friends", true);
-			}
-			su_ds.setValue("#find_friends_optin", false);
-		}
-	}
-	
-	if (stumbleid)
-		su_ds.setValue("$shown_find_friends", true);
-
-	su_ds.flushPrefs();
-}
-
-function su_find_friends_after_page()
-{
-	su_ds.setValue("$shown_find_friends", true);
-	
-	var now_s = su_get_time_s();
-	var pre = su_ds.getValue("#find_friends_pre");
-	if (pre == "facebook")
-		su_ds.setValue("$imported_fbcontacts_time_s", now_s);
-	
-	else
-		su_ds.setValue("$imported_contacts_time_s", now_s);
-	
-	su_ds.setValue("#find_friends_pre", "");
-	
-	su_ds.flushPrefs();
-	setTimeout("su_import_contacts();", 15000);
-}
-
-function su_stumblevideo_page(doc, from_load)
-{
-	var el = doc.getElementById("url_command");
-
-	if (! el)
-		return;
-
-	su_handle_stumblevideo_change(null, doc);
-
-	el.removeEventListener("DOMAttrModified", su_handle_stumblevideo_change, false);
-	el.addEventListener("DOMAttrModified", su_handle_stumblevideo_change, false);
-	
-	var el2 = doc.getElementById("login_count");
-	if (el2)
-	{
-		el2.removeEventListener("DOMAttrModified", su_handle_stumblevideo_login, false);
-		el2.addEventListener("DOMAttrModified", su_handle_stumblevideo_login, false);
-	}
-	
-	el = doc.getElementById("thumbUp");
-	if (el)
-	{
-		el.removeEventListener("DOMAttrModified", su_handle_stumblevideo_rate, false);
-		el.addEventListener("DOMAttrModified", su_handle_stumblevideo_rate, false)
-	}
-	
-	el = doc.getElementById("thumbDown");
-	if (el)
-	{
-		el.removeEventListener("DOMAttrModified", su_handle_stumblevideo_rate, false);
-		el.addEventListener("DOMAttrModified", su_handle_stumblevideo_rate, false)
-	}
-
-//	if (su_pending_stumblevideo_stumble)
-//		su_dispatch_click(doc, "stumbleButton");
-//	
-//	su_pending_stumblevideo_stumble = false;
-}
-
-function su_handle_stumblevideo_login(event)
-{
-	if (event.target.id != "login_count")
-		return true;
-	
-	var userid_saved = stumbleid;
-	var profile_change = su_process_cookies(false);
-	if (profile_change && (stumbleid != userid_saved))
-	{
-		var detail = new Object();
-		detail.skip_cookies = true;
-		detail.ignore_cookies = true;
-		detail.new_profile = profile_change.new_profile;
-		detail.new_user_prompt = false;
-		su_invoke_global_event("login", detail);
-	}
-	return true;
-}
-
-function su_get_browser_from_doc(doc)
-{
-	var browsers = getBrowser().browsers;
-	var i;
-	var browser = null;
-	for (i = 0; i < browsers.length; i++)
-	{
-		if (browsers[i].contentDocument == doc)
-		{
-			browser = browsers[i];
-			break;
-		}
-	}
-	if (! browser)
-		su_log("MISSING BROWSER");
-	return browser;
-}
-
-function su_handle_stumblevideo_change(opt_event, opt_doc)
-{
-	su_stumble_async_context = null;
-	su_get_element("su_stumble").image="chrome://stumbleupon/content/skin/stumble.png";
-	var command;
-	var doc;
-	if (opt_event)
-	{
-		if (opt_event.target.id != "url_command")
-			return true;
-		
-		command = opt_event.newValue;
-		doc = opt_event.target.ownerDocument;
-	}
-	else if (opt_doc)
-	{
-		doc = opt_doc;
-		var el = doc.getElementById("url_command");
-		if (! el)
-			return true;
-		
-		if (! el.hasAttribute("value"))
-			return true;
-		
-		command = el.getAttribute("value");
-	}
-
-	if (command.indexOf("URL ") != 0)
-		return true;
-	
-	var target_browser = su_get_browser_from_doc(doc);
-	if (! target_browser)
-		return true;
-	
-	var overlay_url_detail = su_deserialize_url_command_params(command.substr(4), false);
-	
-	var display_url = su_get_browser_url(doc, true);
-	var url_detail = su_ds.lookup("url:url_detail", display_url);
-	if (url_detail)
-	{
-		url_detail.url = overlay_url_detail.url;
-		url_detail.display_url = display_url;
-	}
-	else
-	{
-		url_detail = overlay_url_detail;
-		url_detail.display_url = display_url;
-	}
-	
-	if (target_browser.su_url_detail &&
-			(url_detail != target_browser.su_url_detail) &&
-			target_browser.su_url_detail.messageid)
-		su_close_message(target_browser.su_url_detail.messageid, true);
-	
-	target_browser.su_url_detail = url_detail; 
-	
-//	su_dd("setstumbled", 2, url_detail.url);
-	stumbled_url = url_detail.url;
-	su_redirect_url = url_detail.url;
-	stumbled_redirect = "";
-//	su_dd("reset", 3);
-	su_refresh_pagemeta(true, 4);
-	
-	return true;
-}
-
-function su_get_stumblevideo_detail(opt_doc)
-{
-	var browser = null;
-	
-	if (opt_doc)
-	{
-		browser = su_get_browser_from_doc(opt_doc);
-		if (! browser)
-			return null;
-	}
-	else
-	{
-		browser = getBrowser().selectedBrowser;
-	}
-	
-	if (! browser.su_url_detail)
-		return null;
-
-	var cmp_url = browser.currentURI.asciiSpec;
-	
-//	su_log("svdetail.1");
-	if (! ((cmp_url.indexOf("http://video." + su_servername + "/#p") == 0) ||
-			(cmp_url.indexOf("http://video." + su_servername + "/?p") == 0)))
-		return null;
-//	su_log("svdetail.2");
-	return browser.su_url_detail;
-}
-
-function su_handle_stumblevideo_rate(opt_event, opt_doc)
-{
-	// Determine the rating
-	var rating = null;
-	var unrate = false;
-	var other_button;
-	var doc;
-	if (opt_event)
-	{
-		var event = opt_event;
-		
-		if (event.attrName != "src")
-			return true;
-	
-		doc = event.target.ownerDocument;
-		
-		if (event.target.id == "thumbUp")
-		{
-			other_button = doc.getElementById("thumbDown");
-			if (event.newValue.indexOf("_sel") != -1)
-				rating = 1;
-			else if ((event.prevValue.indexOf("_sel") != -1) && 
-						(event.newValue.indexOf("_sel") == -1) &&
-						(other_button.src.indexOf("_sel") == -1))
-				unrate = true;
-		}	
-		else if (event.target.id == "thumbDown")
-		{
-			other_button = doc.getElementById("thumbUp");
-			if (event.newValue.indexOf("_sel") != -1)
-				rating = 0;
-			else if ((event.prevValue.indexOf("_sel") != -1) && 
-						(event.newValue.indexOf("_sel") == -1) &&
-						(other_button.src.indexOf("_sel") == -1))
-				unrate = true;
-		}
-	}
-	else if (opt_doc)
-	{
-		var doc = opt_doc;
-		var thumbup = 	doc.getElementById("thumbUp");
-		var thumbdown = doc.getEementById("thumbDown");
-		if (thumbup && thumbup.src && (thumbup.src.indexOf("_sel") != -1))
-			rating = 1;
-		else if (thumbdown && thumbdown.src && (thumbdown.src.indexOf("_sel") != -1))
-			rating = 0;
-		else if (thumbup && thumbdown && thumbup.src && thumbdown.src &&
-			(thumbup.src.indexOf("_sel") == -1) && (thumbdown.src.indexOf("_sel") == -1))
-			unrate = true;
-	}
-
-	if (! (unrate || (rating != null)))
-		return true;
-	
-	// Record the rating
-	
-	var url_detail = su_get_stumblevideo_detail(doc);
-	
-//	su_log(1);
-	if (! url_detail)
-	{
-		return true;
-	}
-//	su_log(2);
-	
-	var context = new su_AsyncContext();
-	context.rating = rating;
-	context.url = url_detail.url;
-
-	if (rating != null)
-	{
-		if (doc == getBrowser().contentDocument)
-			context.browser = getBrowser().selectedBrowser;
-		else
-			contect.browser = null;
-		context.title = null;
-		context.force_nostumble = true;
-		context.force_comment = null;
-		context.timestamp = null;
-		context.open_reviews = null;
-		context.charset = null;
-		context.referrer = null;
-		context.stumblevideo_mode = (su_stumblevideo_toolbar_rate) ? 
-					"toolbar" : "page";
-	}
-
-	var res = new Object();
-	res.detail = context;
-	res.status = 200;
-	res.responseText = "";
-	
-	if (context.rating == null)
-	{
-		url_detail.rating = -1;
-		setTimeout(su_unrate_done, 0, res);
-		setTimeout(su_rate_getmeta, 0, context.url, true);
-	}
-	else
-	{
-		url_detail.rating = rating;
-		setTimeout(su_rate_done, 0, res);
-		setTimeout(su_rate_getmeta, 0, context.url, true);
-	}
-	
-	return true;
-}
-
-function su_rate_getmeta(url, new_rating)
-{
-	if (! su_host.places)
-		return;
-	
-	var params = "";
-	params = su_arp(params, "url", url); 
-	params = su_append_sync_params(params);
-	
-	var context = new su_AsyncContext();
-	context.url = url;
-	context.ref_url = url;
-	context.quiet = true;
-	
-	var loc = (new_rating) ? "getmetanew.php" : "getmetahist.php";
-	
-	su_post_url_server_async(
-				loc,
-				params,
-				null,
-				su_rate_getmeta_done,
-				context);
-}
-
-function su_rate_getmeta_done(res)
-{
-	var context = res.detail;
-	
-	try {
-		if (res.status != 200)
-			return;
-	} catch (e) { return; }
-
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-	
-	if (su_log_communication)
-		su_log("response " + context.request_target, s);
-	
-	su_process_commands(s, context);
-	
-	su_refresh_pagemeta(false, 8);
-}
-
-function su_facebook_page(doc, url)
-{
-	if (url.match(/^http.*?\/\/[^\/]*?\.facebook\.com\/home\.php/))
-		su_facebookhome_page(doc);
-	
-	else if (url.match(/^http.*?\/\/[^\/]*?\.facebook\.com\/friends\.php\?r/))
-		su_facebookfriends_page(doc);
-	
-	if (su_ds.getValue("@facebook_user") &&
-				(su_ds.getValue("@id_list") == "") && 
-				(! su_ds.getValue("~shown_prompt2")) &&
-				su_ds.getValue("@enable_prompt2") &&
-				(! su_ds.getValue("~visited_find_friends")))
-	{
-		su_ds.setValue("~shown_prompt2", true);
-		
-		var detail = new Object();
-		detail.post_url = url;
-		
-		su_show_banner(
-					"Join StumbleUpon to share you discoveries with your friends on Facebook",
-					"chrome://stumbleupon/content/skin/stumble.png",
-					function () { su_handle_prompt_click("prompt2", "accept", detail); },
-					function () { su_handle_prompt_click("prompt2", "decline", detail); });
-
-//		var detail = new Object();
-//		detail.target = "prompt2";
-//		detail.post_url = doc.location.toString();
-//		su_show_notifier(
-//					"Create a StumbleUpon account to see ratings, reviews and recommendations by Facebook friends.",
-//					"chrome://stumbleupon/content/skin/logo32.png",
-//					"notifierIcon32",
-//					5000,
-//					detail);
-	}
-	
-	var fbuserid = su_get_facebook_userid();
-	if (fbuserid)
-	{
-		su_ds.setValue("#facebook_userid", fbuserid); 
-		su_ds.setValue("#checked_facebook", false);
-		su_ds.setValue("@facebook_user", true);
-	}
-}
-
-function su_facebookhome_page(doc)
-{
-	if (stumbleid == 0)
-		return;
-	
-	var now_s;
-	var shown_time_s;
-	
-	if (! su_test_facebookhome_prompt)
-	{
-		if (su_ds.getValue("$facebook_added"))
-			return;
-		
-		if (su_ds.getValue("$facebook_homeprompt_optout"))
-			return;
-		
-		if (! su_ds.getValue("@toolbar-visible"))
-			return;
-	
-		now_s = su_get_time_s();
-		shown_time_s = su_ds.getValue("$facebook_homeprompt_time_s"); 
-		
-		if (shown_time_s && ((now_s - shown_time_s) > (2 * 7 * 24 * 60 * 60)))
-			return;
-		
-		if (! su_ds.getValue("#checked_facebook"))
-		{
-			su_get_facebook(doc);
-			return;
-		}
-		
-		if (! su_get_facebook_userid())
-			return;
-	}
-	
-	var target = null;
-	
-	var el = doc.getElementById("home_main");
-	if (! el)
-		return;
-	
-	var hs = el.getElementsByTagName("h2");
-	var i;
-	for (i = 0; i < hs.length; i++)
-	{
-		if (hs[i].innerHTML.indexOf("News Feed") != -1)
-		{
-			target = hs[i];
-			break;
-		}
-	}
-	
-	if (! target)
-		return;
-	
-	if (! target.parentNode)
-		return;
-	
-	var sibling = target.nextSibling;
-	
-	if (sibling != target.parentNode.lastChild)
-		return;
-	
-//	var sibling = sibling.firstChild;
-	
-	if (! sibling)
-		return;
-	
-	var tooltip = "Share websites with friends";
-	
-	var str = "";
-	
-	str += '      ';
-
-	str += '<a style="text-decoration:none;" title="' + tooltip +
-				'" href="http://apps.facebook.com/stumbleupon/"><img border="0" width="13" height="13" style="display:inline;position:relative;top:2px;" src="chrome://stumbleupon/content/skin/smallstumble.png"/>  </a><a title="' + tooltip +
-				'" href="http://apps.facebook.com/stumbleupon/">Add StumbleUpon</a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-c.png"/>';
-	
-//	str += "   <span style="text-size:small;">·</span>   ";
-	
-	el = doc.createElement("span");
-	el.innerHTML = str;
-	el.setAttribute("style", "float:left;");
-	
-	sibling.parentNode.insertBefore(el, sibling);
-	
-	el.lastChild.addEventListener("click", su_handle_facebook_homeprompt_optout_click, false);
-
-	if (! su_test_facebookhome_prompt)
-	{
-		if (! shown_time_s)
-			su_ds.setValue("$facebook_homeprompt_time_s", now_s);
-	}
-}
-
-function su_handle_searchpageprompt_optout_click(event)
-{
-	su_handle_prompt_optout_click(event, "search");
-}
-
-function su_handle_facebook_homeprompt_optout_click(event)
-{
-	su_handle_prompt_optout_click(event, "fbhome");
-}
-
-function su_handle_prompt_optout_click(event, promptid)
-{
-	var ps = su_get_service(
-				"@mozilla.org/embedcomp/prompt-service;1",
-				"nsIPromptService");
-	var out = ps.confirmEx(
-				window,
-				"StumbleUpon Confirm",
-				"Do you want to permanently remove this StumbleUpon link?",
-				ps.STD_YES_NO_BUTTONS,
-				null,
-				null,
-				null,
-				null,
-				{});
-	if (out == 0)
-	{
-		switch (promptid)
-		{
-			case "fbhome":
-				var target = event.target.parentNode;
-				target.parentNode.removeChild(target);
-				su_ds.setValue("$facebook_homeprompt_optout", true);
-				break;
-			case "search":
-				var target = event.target.parentNode;
-				target.parentNode.removeChild(target);
-				su_ds.setValue("$shown_find_friends_optout", true);
-				break;
-		}
-	}
-}
-
-function su_facebookfriends_page(doc)
-{
-	if (! su_ds.getValue("@toolbar-visible"))
-		return;
-	
-	var el = doc.getElementById("friendtables");
-	if (! el)
-		return;
-	var as = el.getElementsByTagName("a");
-	var targets = new Array();
-	var userids = new Array();
-	for (i = 0; i < as.length; i++)
-	{
-		var match = as.item(i).href.match(/http\:\/\/[^\/]*\.facebook\.com\/addfriend\.php\?id=(.*)/);
-
-		if (! match)
-			match = as.item(i).href.match(/http\:\/\/[^\/]*\.facebook\.com\/friends\.php\?remove_friend=1\&friend_id=(.*)/);
-		
-		if (! match)
-			continue;
-
-		var target = as.item(i).parentNode;
-		
-		if (! target)
-			continue;
-		
-		if (target.className != "actions")
-			continue;
-		
-		userids.push(match[1]);
-		targets.push(target);
-	}
-	
-	if (userids.length == 0)
-		return;
-	
-	
-	// su_check_facebook_contacts(userids, targets);
-}
-
-/*
-function su_check_facebook_contacts(fb_userids, targets)
-{
-	var i;
-	var contact;
-	var contacts = su_ds.selectAllRows("contact");
-	var contacts_by_fbid = new Object();
-	var now_s = su_get_time_s();
-	var checked_time_s = su_ds.getValue("$facebook_contacts_time_s"); 
-	var refresh_cache = (checked_time_s && ((now_s - checked_time_s) > (18 * 60 * 60)));
-	var anonymize_nonmutuals = refresh_cache;
-
-	for (i = 0; i < contacts.length; i++)
-	{
-		contact = contacts[i];
-		if (contact.fbid)
-		{
-			contacts_by_fbid[contact.fbid] = contact;
-			if (anonymize_nonmutuals && contact.contactid && (! contact.mutual))
-			{
-				contact.contactid = "";
-				contact.nickname = "";
-				su_ds.updateRow(contact);
-			}
-		}
-	}
-	
-	for (i = 0; i < fb_userids.length; i++)
-	{
-		if (contacts_by_fbid[fb_userids[i]])
-			contact
-		
-		var contactid = friends[i].split(".")[0];
-		var nickname = friends[i].split(".")[1];
-		var facebookid = friends[i].split(".")[2];
-		
-		fbfriends[contactid] = true;
-
-		contact = null;
-		
-		if (contacts_by_id[contactid])
-			contact = contacts_by_id[contactid];
-		
-		if (contact)
-		{
-			contact.nickname = nickname;
-			contact.fbid = facebookid;
-			su_ds.updateRow(contact);
-		}
-		else
-		{
-			contact = new Object();
-			contact.contactid = contactid;
-			contact.nickname = nickname;
-			contact.fbid = facebookid;
-			su_ds.insertRow("contact", contact);
-			contacts_by_id[contactid] = contact;
-		}
-	}
-
-	for (i = 0; i < contacts.length; i++)
-	{
-		if ((typeof (contacts[i].contactid)) != "undefined")
-		{
-			if (contacts[i].fbid && (! fbfriends[contacts[i].contactid]))
-				contacts[i].fbid = 0;
-			
-			su_ds.updateRow(contacts[i]);
-		}
-	}
-	
-	if (userids)
-	{
-		
-	}
-	
-}
-*/
-
-function su_search_results_page(doc, service_id)
-{
-	su_search_service_page(doc, service_id);
-	su_augment_links(doc, service_id);
-}
-
-function su_search_service_page(doc, service_id)
-{
-	var now_s;
-	var shown_time_s;
-	if (! su_test_searchpage_prompt)
-	{
-		if (! su_ds.hasFeature("$sociallinks"))
-			return;
-		
-		if (! su_ds.getValue("@toolbar-visible"))
-			return;
-		
-		if (su_ds.getValue("$imported_contacts_time_s"))
-			return;
-		
-		if (su_ds.getValue("$shown_find_friends_optout"))
-			return;
-		
-//		if ((! su_ds.hasFeature("$unlimitedslpromptclicks") &&
-//					(su_ds.getValue("$shown_find_friends_clicks") >= 3)))
-//			return;
-	
-		now_s = su_get_time_s();
-		shown_time_s = su_ds.getValue("$shown_find_friends_time_s"); 
-	
-		if (shown_time_s && ((now_s - shown_time_s) > (3 * 7 * 24 * 60 * 60)))
-			return;
-	}
-	
-	var tooltip = "Add StumbleUpon friends to see which search results they prefer";
-	var str = '<a style="text-decoration:none;" title="' + 
-				tooltip + '" href="' + su_serverhttp + 
-				'find_friends.php?pre3=' + service_id + '">';
-	
-	if (su_ds.getValue("$show_searchlinks_logo"))
-		str += '<img border="0" width="13" height="13" style="display:inline;position:relative;top:1px;" src="http://cdn.stumble-upon.com/images/embed/smallstumble.png"> <u style="position:relative;top:-1px;">See friend reviews</u></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-c.png"/>';
-	else
-		str += '<u>See StumbleUpon friend reviews</u></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-c.png"/>';
-	
-	switch (service_id)
-	{
-//		case "google":
-//			str = " " + str;
-//			var target = null;
-//			var el = doc.getElementById("gbar");
-//			if (! el)
-//				return;
-//			var us = el.getElementsByTagName("u");
-//			var i;
-//			for (i = 0; i < us.length; i++)
-//			{
-//				if (us[i].innerHTML == "more")
-//				{
-//					target = us[i];
-//					break;
-//				}
-//			}
-//			if (! target)
-//				return;
-//			
-//			target = target.parentNode;
-//			
-//			if (! target)
-//				return;
-//			
-//			target = target.parentNode;
-//			
-//			if (! target)
-//				return;
-//
-//			target = target.nextSibling;
-//			
-//			if (! target)
-//				return;
-//		
-//			if (! target.parentNode)
-//				return;
-//			
-//			el = doc.createElement("span");
-//			el.innerHTML = str;
-//			
-//			target.parentNode.insertBefore(el, target);
-//			el.lastChild.addEventListener("click", su_handle_searchpageprompt_optout_click, false);
-//			break;
-		case "google":
-		case "google-ajax":
-		case "googlenews":
-			// Add listeners for results that are populated by Ajax.
-			if(service_id == "google-ajax")
-			{
-				// Google classic uses ajax to populate the search results, so we need to do 
-				// our augmentation work when the results are all inserted, which is whenever the xfoot
-				// element is inserted.
-				if(!doc.__su__listening_ff)
-				{
-					doc.__su__listening_ff = true;
-					doc.addEventListener("DOMNodeInserted", function(event) {
-						if(event.target.id == "xfoot")
-						{
-							if(!doc.getElementById("__su__service_ff"))
-							{
-								su_search_service_page(doc, service_id);
-							}
-						}
-					}, false);
-				}
-			}
-			var el = doc.getElementById("gbar");
-			if (! el)
-				return;
-			var us = el.getElementsByTagName("u");
-			var target = null;
-			var i;
-			for (i = 0; i < us.length; i++)
-			{
-				if (us[i].innerHTML == "more")
-				{
-					target = us[i];
-					break;
-				}
-			}
-			if (! target)
-				return;
-			
-			target = target.parentNode;
-			
-			if (! target)
-				return;
-			
-//			target = target.parentNode;
-			
-//			if (! target)
-//				return;
-		
-			if (! target.parentNode)
-				return;
-			
-			el = doc.createElement("td");
-			el.id = "__su__service_ff";
-			el.setAttribute("nowrap", "nowrap");
-			el.innerHTML = str;
-			target.parentNode.appendChild(el);
-			el.lastChild.addEventListener("click", su_handle_searchpageprompt_optout_click, false);
-			break;
-		case "googleindex":
-		case "googlevideo":
-			var el = doc.getElementById("gbar");
-			if (! el)
-				return;
-			var us = el.getElementsByTagName("u");
-			var target = null;
-			var i;
-			for (i = 0; i < us.length; i++)
-			{
-				if (us[i].innerHTML == "more")
-				{
-					target = us[i];
-					break;
-				}
-			}
-			if (! target)
-				return;
-			
-			target = target.parentNode;
-			
-			if (! target)
-				return;
-			
-			target = target.parentNode;
-			
-			if (! target)
-				return;
-		
-			if (! target.parentNode)
-				return;
-			
-			el = doc.createElement("td");
-			el.setAttribute("nowrap", "nowrap");
-			el.innerHTML = str;
-			target.parentNode.appendChild(el);
-			el.lastChild.addEventListener("click", su_handle_searchpageprompt_optout_click, false);
-			break;
-		case "yahoo":
-			str = '    <a style="text-decoration:none;" title="' + 
-						tooltip + '" href="' + su_serverhttp + 
-						'find_friends.php?pre3=' + service_id + '">';
-						
-			if (su_ds.getValue("$show_searchlinks_logo"))
-				str += '<img border="0" width="13" height="13" style="display:inline;position:relative;top:2px;" src="http://cdn.stumble-upon.com/images/embed/smallstumble.png"> <u style="color:rgb(21,73,193);">See friend reviews</u></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-c.png"/>';
-			else
-				str += '<u style="color:rgb(21,73,193);">See StumbleUpon friend reviews</u></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-c.png"/>';
-	
-			var target = doc.getElementById("tabs");
-			var style = "white-space:nowrap;position:relative;top:-1px;"
-			if (! target)
-			{
-				target = doc.getElementById("eb");
-				style = "white-space:nowrap;position:relative;top:-2px;";
-			}
-			if (! target)
-				return;
-			target.setAttribute("style", "white-space:nowrap;");
-			var el = doc.createElement("span");
-			el.setAttribute("style", style);
-			el.innerHTML = str;
-			target.appendChild(el);
-			el.lastChild.addEventListener("click", su_handle_searchpageprompt_optout_click, false);
-			break;
-		case "ask":
-			str = '  <a style="text-decoration:none;" title="' + 
-						tooltip + '" href="' + su_serverhttp + 
-						'find_friends.php?pre3=' + service_id + '">';
-				
-			if (su_ds.getValue("$show_searchlinks_logo"))
-				str += '<img border="0" width="13" height="13" style="display:inline;position:relative;top:1px;" src="http://cdn.stumble-upon.com/images/embed/smallstumble.png"> <span style="color:blue;">See friend reviews</span></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-d.png"/>';
-			else
-				str += '<span style="color:blue;">See StumbleUpon friend reviews</span></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-d.png"/>';
-			var target = doc.getElementById("navbar_tabs");
-			if (! target)
-				return;
-			var el = doc.createElement("span");
-			el.innerHTML = str;
-			target.appendChild(el);
-			el.lastChild.addEventListener("click", su_handle_searchpageprompt_optout_click, false);
-			break;
-		case "aol":
-			var target = doc.getElementById("morecsb");
-			if (! target)
-				return;
-			target = target.parentNode;
-			if (! target)
-				return;
-			target = target.parentNode;
-			if (! target)
-				return;
-			var el = doc.createElement("span");
-			el.innerHTML = str;
-			target.appendChild(el);
-			el.lastChild.addEventListener("click", su_handle_searchpageprompt_optout_click, false);
-			break;
-	}
-	if (! su_test_searchpage_prompt)
-	{
-		if (! shown_time_s)
-			su_ds.setValue("$shown_find_friends_time_s", now_s);
-	}
-}
-	
-// extracts links from a page and calls links.php
-function su_augment_links(doc, service_id)
-{
-	if ((! su_ds.getValue("$show_searchlinks_score")) &&
-				(! su_ds.getValue("$show_searchlinks_friends")) &&
-				(! su_ds.getValue("$show_searchlinks_topic")))
-		return;
-
-	if (! su_ds.getValue("@toolbar-visible"))
-		return;
-	
-	var as;
-	var target;
-	var el;
-	switch (service_id)
-	{
-		
-		case "wikipedia":
-			el = doc.getElementById("top");
-			while (el)
-			{
-				if (el.className == "firstHeading")
-					break;
-				el = el.nextSibling;
-			}
-			if (! el)
-				return;
-			var title = el;
-			var title_text = title.innerHTML;
-			title.innerHTML = "";
-			var inline = doc.createElement("span");
-			title.appendChild(inline);
-			target = doc.createElement("span");
-			target.innerHTML = title_text;
-			inline.appendChild(target);
-			break;
-		case "cnn":
-			var el = doc.getElementById("cnnSearchResults");
-			if (! el)
-				return;
-			as = el.getElementsByTagName("a");
-			break;
-		default:
-			as = doc.getElementsByTagName("a");
-			break;
-	}
-	var urls = new Array();
-	var targets = new Array();
-	var hrefs = urls;
-	var i;
-	
-	var linked_color = "rgb(130, 132, 204)";
-	var unlinked_color = "rgb(0, 0, 0)";
-	var underline = true;
-	var font_size = "100%";
-	var force_no_logo = false;
-	var force_inline = false;
-	var soft_wrap = false;
-	var hard_wrap = false;
-	var force_logo = false;
-	var before_targets = targets;
-	var after_targets = targets;
-	var include_topic = false;
-	var image_baseline = false;
-	var enable_click_tracking = true;
-	
-	// Check whether we need to add listeners for results that are populated by Ajax.
-	if( (service_id == "google-ajax") ||
-		(service_id == "googlevideo") )
-	{
-		// Google classic uses ajax to populate the search results, so we need to do 
-		// our augmentation work when the results are all inserted, which is whenever the xfoot
-		// element is inserted.
-		var idlast = "";
-		if(service_id == "google-ajax")
-		{
-			idlast = "xfoot";
-		}
-		else if(service_id == "googlevideo")
-		{
-			idlast = "pagi";
-		}
-		if(!doc.__su__listening)
-		{
-			doc.__su__listening = true;
-			doc.addEventListener("DOMNodeInserted", function(event) {
-				if(event.target.id == idlast)
-				{
-					su_augment_links(doc, service_id);
-				}
-			}, false);
-		}
-	}
-	
-	switch (service_id)
-	{
-		case "google-ajax":
-		case "google":
-			after_targets = new Array();
-			linked_color = "#7777cc";
-			unlinked_color = linked_color;
-			font_size = "smaller";
-			for (i = 0; i < as.length; i++)
-			{
-				if (as.item(i).className == "l")
-				{
-					if (as.item(i).firstChild && (as.item(i).firstChild.tagName == "IMG") &&
-								(as.item(i).firstChild.src.indexOf("/mapfiles/") != -1))
-						continue; // at top
-					
-					var redir_match = as.item(i).href.match(/^http.*?\/\/[^\/]*?(google\.[^\.]+|google\.co\.[^\.]+)\/(url.*[?&]q=)([^&]+)/);
-					if (redir_match && redir_match.length >= 4)
-						urls.push(decodeURIComponent(redir_match[3]));
-					else
-						urls.push(as.item(i).href);
-					targets.push(as.item(i));
-					if (as.item(i).parentNode.nextSibling && as.item(i).parentNode.nextSibling.tagName == "FONT" && as.item(i).parentNode.nextSibling.firstChild && as.item(i).parentNode.className != "r")
-						after_targets.push(as.item(i).parentNode.nextSibling.firstChild);
-					else
-						after_targets.push(as.item(i));
-				}
-			}
-			break;
-		case "googlenews":
-		case "googlenewsindex":
-			after_targets = new Array();
-			enable_click_tracking = su_ds.hasFeature("$newsclicktracking");
-			linked_color = "#7777cc";
-			unlinked_color = linked_color;
-			font_size = "smaller";
-			for (i = 0; i < as.length; i++)
-			{
-				if (as.item(i).parentNode.className == "title")
-				{
-					if (as.item(i).href.indexOf("http://news.google.co") == 0)
-						continue;
-					urls.push(as.item(i).href);
-					targets.push(as.item(i));
-					after_targets.push(as.item(i));
-				}
-			}
-			break;
-		case "googlevideo":
-			linked_color = "#7777cc";
-			font_size = "small";
-			force_logo = su_ds.getValue("$show_searchlinks_logo");
-			hrefs = new Array();
-			for (i = 0; i < as.length; i++)
-			{
-				var anchor = as.item(i);
-				if (anchor.parentNode.className == "rl-title")
-				{
-					urls.push(anchor.href);
-					targets.push(anchor);
-				}
-			}
-			break;
-		case "ask":
-			linked_color = "auto";
-			for (i = 0; i < as.length; i++)
-			{
-				if (as.item(i).className == "L4")
-				{
-					var matches = as.item(i).href.match(/&u=([^&]*)/);
-					if(matches && matches[1])
-					{
-						urls.push(decodeURIComponent(matches[1]));
-					}
-					else
-					{
-						urls.push(as.item(i).href);
-					}
-					targets.push(as.item(i));
-				}
-			}
-			break;
-		case "bing":
-			var h3s = doc.getElementsByTagName("h3");
-			for (var i = 0; i < h3s.length; i++)
-			{
-				var anchors = h3s[i].getElementsByTagName("a");
-				if (anchors.length == 1)
-				{
-					var a = anchors[0];
-					urls.push(a.href);
-					targets.push(a);
-				}
-			}
-			break;
-		case "bing-news":
-			var headlines = doc.getElementsByClassName("Headline");
-			for (var i = 0; i < headlines.length; i++)
-			{
-				var anchors = headlines[i].getElementsByTagName("a");
-				if (anchors.length == 1)
-				{
-					var a = anchors[0];
-					urls.push(a.href);
-					targets.push(a);
-				}
-			}
-			break;
-		case "nyt":
-			force_inline = true;
-			var h3s = doc.getElementsByTagName("h3");
-			for (var i = 0; i < h3s.length; i++)
-			{
-				var anchors = h3s[i].getElementsByTagName("a");
-				if (anchors.length == 1)
-				{
-					var href = anchors[0].href;
-					// They include search referral and search term information at the end of the URL, 
-					// past the ?scp=, so we strip that out if it exists.
-					var match = href.match(/(.*?)(\?scp=.*)/);
-					if(match)
-					{
-						href = match[1];
-					}
-					urls.push(href);
-					targets.push(anchors[0]);
-				}
-			}
-			break;
-		case "yahoo":
-			// Yahoo changes the href with global script, so we have to wait for
-			// the "load" event at which point the href will have been set to the final URL.
-			if(!doc.__su__listening)
-			{
-				doc.__su__listening = true;
-				doc.defaultView.addEventListener("load", function(event) {
-					if(event.target.__su__listening)
-					{
-						su_augment_links(doc, service_id);
-					}
-				}, false);
-				return;
-			}
-			
-			// We got back in here from the load event, now do our work.
-			soft_wrap = true;
-			hrefs = new Array();
-			for (i = 0; i < as.length; i++)
-			{
-				if ((as.item(i).className.indexOf("yschttl") != -1) )// && as.item(i).href.match(/\*\*(.*)/))
-				{
-					var href = as.item(i).href;
-					var match = href.match(/http\:\/\/rds.yahoo.com.*?\*\*(.*)/);
-					if(match && match[1])
-					{
-						href = decodeURIComponent(match[1]);
-					}
-					urls.push(href);
-					hrefs.push(href);
-					targets.push(as.item(i));
-				}
-			}
-			break;
-		case "aol":
-			font_size = "larger";
-			hrefs = new Array();
-			for (i = 0; i < as.length; i++)
-			{
-				if (as.item(i).className == "find")
-				{
-					hrefs.push(as.item(i).href);
-					urls.push(as.item(i).href);
-					targets.push(as.item(i));
-				}
-			}
-			break;
-		case "myspace":
-			for (i = 0; i < as.length; i++)
-			{
-				var anchor = as.item(i);
-				if( anchor.parentNode &&
-					anchor.parentNode.parentNode &&
-					(anchor.parentNode.parentNode.className.indexOf("searchResults") != -1) )
-				{
-					urls.push(anchor.href);
-					targets.push(anchor);
-				}
-			}
-			break;
-		case "youtube":
-			underline = false;
-			soft_wrap = true;
-			font_size = "small";
-			for (i = 0; i < as.length; i++)
-			{
-				if (as.item(i).id.indexOf("video-long-title") == 0)
-				{
-					urls.push(as.item(i).href);
-					targets.push(as.item(i));
-				}
-			}
-			break;
-		case "wikipedia":
-			font_size = "small";
-			underline = false;
-			image_baseline = true;
-			// include_topic = true;
-			enable_click_tracking = su_ds.hasFeature("$titleclicktracking");
-			urls.push(doc.location.href);
-			targets.push(target);
-			break;
-		case "flickr":
-			underline = false;
-			hard_wrap = true;
-			soft_wrap = true;
-			linked_color = "auto";
-			font_size = "small";
-			for (i = 0; i < as.length; i++)
-			{
-				var anchor = as.item(i);
-				var ancestor = su_get_ancestor_by_prop_value(anchor,
-							"className", "ResultsThumbsChild", 4);
-				if (ancestor && anchor.firstChild && 
-					anchor.firstChild.className &&
-				    (anchor.firstChild.className.indexOf("pc_img") != -1))
-				{
-					urls.push(anchor.href);
-					targets.push(anchor);
-				}
-			}
-			break;
-		case "cnn":
-			for (i = 0; i < as.length; i++)
-			{
-				if (as[i].className == "cnnSearchResultsHeadline")
-				{
-					var redir_match = as.item(i).href.match(/arProcessing\.jsp.*?[?&]dest=([^?&]+)/);
-					if (redir_match && redir_match.length >= 0)
-						urls.push(redir_match[1]);
-					else
-						urls.push(as.item(i).href);
-					targets.push(as.item(i));
-				}
-			}
-			break;
-		case "cbsnews":
-			for (i = 0; i < as.length; i++)
-			{
-				if (as.item(i).className == "storyTitle")
-				{
-					urls.push(as.item(i).href);
-					targets.push(as.item(i));
-				}
-			}
-			break;
-		case "cnetnews":
-			force_inline = true;
-			for (i = 0; i < as.length; i++)
-			{
-				if (as.item(i).className == "resultName")
-				{
-					urls.push(as.item(i).href);
-					targets.push(as.item(i));
-				}
-			}
-			break;
-		case "abcnews":
-			for (i = 0; i < as.length; i++)
-			{
-				if (as.item(i).className == "title")
-				{
-					urls.push(as.item(i).href);
-					targets.push(as.item(i));
-				}
-			}
-			break;
-		case "msnbc":
-			for (i = 0; i < as.length; i++)
-			{
-				var anchor = as.item(i);
-				if(anchor.parentNode.tagName == "H4")
-				{
-					urls.push(anchor.href);
-					targets.push(anchor);
-				}
-			}
-			break;
-	}
-	
-	if (urls.length == 0)
-		return;
-	
-	var url = su_get_browser_url(doc);
-	
-	var query_detail = su_get_search_query_detail(service_id, url);
-	
-	var now = (new Date()).getTime();
-	
-	var slstats = new Object();
-	slstats.timestamp = now;
-	slstats.slq = 0;
-	slstats.term_count = query_detail.term_count;
-	slstats.url_count = hrefs.length;
-	slstats.decorated_count = 0;
-	slstats.first_decorated_num = 0;
-
-	if (enable_click_tracking)
-	{
-		su_ds.globals.sls.push(slstats);
-		var slq = su_ds.globals.sls.length;
-		slstats.slq = slq;
-		su_ds.globals.sluqh[url] = slq;
-		var slistats = su_ds.getValue("$slistats").split(":");
-		for (i = 0; i < urls.length; i++)
-		{
-			var slt = "" + slq + su_service.getSha1(hrefs[i]);
-			var sli = new Object();
-			sli.i = i;
-			su_ds.globals.sltih[slt] = sli;
-			if (i < 10)
-				slistats[i] = parseInt(slistats[i]) + 1;
-		}
-		su_ds.setValue("$slistats", slistats.join(":"));
-	}
-	
-	
-	var context = new Object();
-	context.slstats = slstats;
-	context.done = false;
-	context.batch_count = 0;
-	context.url_start_index = 0;
-	context.doc = doc;
-	context.timestamp = now;
-	context.query_detail = query_detail;
-	context.before_targets = before_targets;
-	context.after_targets = after_targets;
-	context.urls = urls;
-	context.hrefs = hrefs;
-	context.linked_color = linked_color;
-	context.underline = underline;
-	context.unlinked_color = unlinked_color;
-	context.font_size = font_size;
-	context.force_logo = force_logo;
-	context.soft_wrap = soft_wrap;
-	context.hard_wrap = hard_wrap;
-	context.include_topic = include_topic || su_ds.getValue("$show_searchlinks_topic");
-	context.image_baseline = image_baseline;
-	context.enable_click_tracking = enable_click_tracking;
-	context.force_inline = force_inline;
-	
-	su_augment_links2(context);
-}
-
-function su_augment_links2(context)
-{
-	var query = "";
-	if (0) //(su_ds.hasFeature("$unbatchedlinks"))
-	{
-		context.done = true;
-		for (i = 0; i < context.urls.length; i++)
-		{
-			if (query != "")
-				query += '%09';
-			query += encodeURIComponent(context.urls[i]);
-		}
-	}
-	else
-	{
-		var url_count = 0;
-		var i = (context.batch_count * 10);
-		context.url_start_index = i;
-		while ((url_count < 10) && (i < context.urls.length))
-		{
-			url_count++;
-			if (query != "")
-				query += '%09';
-			query += encodeURIComponent(context.urls[i]);
-			i++;
-		}
-		context.batch_count++;
-		if (su_ds.hasFeature("$limitedlinks"))
-			context.done = true;
-		else
-			context.done = (i == context.urls.length);
-	}
-	
-	if (query == "")
-		return;
-	
-	var params = "u=" + query;
-	params = su_arp(params, "f",
-				su_ds.getValue("$show_searchlinks_friends") ? 1 : 0);
-	params = su_arp(params, "s",
-				su_ds.getValue("$show_searchlinks_score") ? 1 : 0);
-	params = su_arp(params, "t",
-				su_ds.getValue("$show_searchlinks_topic") ? 1 : 0);
-	params = su_arp(params, "m", su_ds.getValue("@dd_links_m"));
-	params = su_arp(params, "domain", context.query_detail.domain);
-	params = su_arp(params, "termcount", context.query_detail.term_count);
-	params = su_arp(params, "firstpage", context.query_detail.is_first_page ? 1 : 0);
-	params = su_arp(params, "timestamp", context.timestamp);
-	params = su_arp(params, "batch", context.batch_count);
-	
-	var loc = "links.php";
-	if (su_ds.getValue("@dd_links_m") == "alt")
-		loc = "test_links.php";
-	
-	su_post_url_server_async(
-				loc, 
-				params,
-				60000,
-				su_augment_links_done,
-				context);
-}
-
-// handles response to links.php; adds content for the links
-function su_augment_links_done(res)
-{
-	try {
-		if ((res.status != 200) || res.aborted)
-			return;
-	} catch (e) { return; }
-
-	var context = res.detail;
-
-	var s = "";
-	if (typeof(res.responseText) != "undefined")
-		s = res.responseText;
-
-	if (su_log_communication)
-		su_log("response links.php", s);
-
-	if (s == "")
-		return;
-	
-	var ss;
-
-	ss = s.split("\n");
-
-	var sss = ss[0].split(" ");
-
-	if (sss[0] == "ERROR")
-		return;
-
-	var i;
-	var slt;
-	var slistats = su_ds.getValue("$slistats").split(":");
-	var slidfstats = su_ds.getValue("$slidfstats").split(":");
-	for (i = 0; i < ss.length; i++)
-	{
-		if (ss[i] == "")
-			continue;
-		
-		var url_index = context.url_start_index + i;
-		
-		context.slstats.decorated_count++;
-		if (! context.slstats.first_decorated_num)
-			context.slstats.first_decorated_num = (i + 1);
-		
-		var fields = ss[i].split("\t");
-		var comment_level = parseInt(fields[0]);
-		var thumbed = fields[1];
-		if (su_ratings[context.hrefs[url_index]])
-			thumbed = "1";
-		var score = parseInt(fields[2]);
-		var topic = fields[3];
-
-		var friends = new Array();
-		var j;
-		if (typeof(fields[4]) != "undefined" && fields[4] != "" && su_ds.getValue("$show_searchlinks_friends"))
-		{
-			var f = fields[4].split(",");
-			for (j = 0; j < f.length; j++)
-			{
-				if (f[j] == '')
-					continue;
-				friends.push(f[j]);
-			}
-		}
-		
-		var comment_count = null;
-		if (typeof(fields[5]) != "undefined" && fields[5] != "")
-			comment_count = parseInt(fields[5]);
-		
-		var comment_id = null;
-		if (typeof(fields[6]) != "undefined" && fields[6] != "")
-			comment_id = fields[6];
-		
-		var comment_text = null;
-		if (typeof(fields[7]) != "undefined" && fields[7] != "")
-			comment_text = fields[7].replace(/\|/g, " ");
-		
-		slt = "";
-		if (su_host.sha1 && su_ds.getValue("@enable_slstats") && context.enable_click_tracking)
-		{
-			slt = "" + context.slstats.slq + su_service.getSha1(context.hrefs[url_index]);
-			var sli = su_ds.globals.sltih[slt];
-			var detail = new Object();
-			sli.detail = detail;
-			detail.q = context.slstats.slq;
-			detail.d = 1;
-			detail.i = url_index;
-			detail.dt = (thumbed) ? 1 : 0;
-			detail.dc = (comment_count) ? comment_count : 0;
-			detail.ds = score;
-			detail.dl = comment_level;
-			detail.df = friends.length;
-			detail.dr = (comment_text) ? 1 : 0;
-			detail.dz = (context.include_topic && (typeof(su_catnames[topic]) != "undefined")) ? 1 : 0;
-			
-			if (url_index < 10 && detail.df)
-			{
-				slistats[url_index] = parseInt(slistats[url_index]) - 1;
-				slidfstats[url_index] = parseInt(slidfstats[url_index]) + 1;
-			}
-		}
-		
-		if (! score)
-			score = 1;
-		
-		var after;
-		var before;
-		var after_parts =  new Array();
-		var reviewHref = su_base_url + "url/" + su_review_url(context.urls[url_index]);
-
-		
-		// The 'float:none;padding:0;' and 'display:inline;' css rules in
-		// here mostly cater to AOL.
-		
-		before = "";
-		if (thumbed == "1")
-		{
-			before = '<img border="0" width="13" height="13" style="display:inline;';
-			if (context.image_baseline)
-				before += 'vertical-align:baseline;';
-			before += '" src="chrome://stumbleupon/content/skin/smallgreenthumbup.png"> ';
-		}
-		
-		after = '';
-		if (context.hard_wrap)
-		{
-			after_parts.push("<br />");
-		}
-		else if ((score <= 0) && (! su_ds.getValue("$show_searchlinks_logo")))
-		{
-			after += '<span style="font-size:' + context.font_size + 
-				';color:' + context.unlinked_color +
-				';float:none;padding:0;"> ·</span>';
-		}
-		else
-		{
-			after += ' ';
-		}
-
-		after += '<a ondblclick="slu" slt="' + slt + '"';
-
-		if ((! context.include_topic) && (typeof(su_catnames[topic]) != "undefined"))
-		{
-			after += ' title="';
-			if (comment_count)
-			{
-				if (comment_count == 1)
-					after += 'Read 1 review';
-				else
-					after += 'Read ' + comment_count + ' reviews';
-				after += ' in topic ' + su_catnames[topic] + '"';
-			}
-			else
-			{
-				after += 'See who liked this"';
-			}
-		}
-		else if (comment_count)
-		{
-			after += ' title="';
-			if (comment_count == 1)
-				after += 'Read 1 review"';
-			else
-				after += 'Read ' + comment_count + ' reviews"';
-		}
-		else
-		{
-			after += ' title="See who liked this"';
-		}
-
-		after += ' style="text-decoration:none;float:none;padding:0;font-size:' + 
-					context.font_size + ';color:' + 
-					context.linked_color + ';" href="' + reviewHref + '">';
-
-		var imgStyle = "display:inline;float:none;border:none;margin:0px;padding:0px;";
-		if (context.force_logo || su_ds.getValue("$show_searchlinks_logo"))
-		{
-			after += '<img ondblclick="slu" border="0" width="13" height="13" style="' + imgStyle;
-			if (context.image_baseline)
-				after += 'vertical-align:baseline;';
-			after += '" src="chrome://stumbleupon/content/skin/smallstumble.png">';
-		}
-		
-		if ((score > 0) && su_ds.getValue("$show_searchlinks_score"))
-		{
-			after += ' ';
-		
-			for (j = 0; j < score; j++)
-			{
-				after += '<img ondblclick="slu" border="0" width="10" height="10" style="' + imgStyle;
-				if (context.image_baseline)
-					after += 'vertical-align:baseline;';
-				after += '" src="chrome://stumbleupon/content/skin/star.png">';
-			}
-		}
-//		else if ((friends.length == 0) || 
-//					(! su_ds.getValue("$show_searchlinks_friends")))
-//		{
-//			if (context.underline)
-//				after += ' <u ondblclick="slu">Reviews</u>';
-//			else
-//				after += ' Reviews';
-//		}
-
-		if ((comment_level > 0) && su_ds.getValue("$show_searchlinks_comment_icon"))
-		{
-			after += ' <img ondblclick="slu" border="0" width="13" height="13" style="' + imgStyle;
-			if (context.image_baseline)
-				after+= 'vertical-align:baseline;';
-			after += '" src="chrome://stumbleupon/content/skin/smallbubble' + comment_level + '.png">';
-		}
-
-		after += '</a>';			
-		after_parts.push(after);
-		
-		after = '';
-		if (friends.length && su_ds.getValue("$show_searchlinks_friends"))
-		{
-			for (j = 0; j < friends.length; j++)
-			{
-				if (j == 0)
-				{
-					after = '<span style="text-decoration:none;float:none;padding:0;font-size:' + 
-								context.font_size + ';color:' + 
-								context.unlinked_color + ';"> · </span><a ondblclick="slp" slt="' +
-								slt + '" style="text-decoration:none;float:none;padding:0;font-size:' + 
-								context.font_size + ';color:' + 
-								context.linked_color + ';" title="'; 
-					
-					if (comment_text)
-						after += comment_text;
-					else
-						after += friends[j] + ' likes this page';
-					
-					after += '" href="' + reviewHref + '">';
-					
-					after += '<img ondblclick="slp" border="0" width="13" height="13" style="' + imgStyle;
-					if (context.image_baseline)
-						after += 'vertical-align:baseline;';
-					
-					after += '" src="chrome://stumbleupon/content/skin/smallredman.png"> ';
-					
-					if (context.underline)
-						after += '<u ondblclick="slp">' + friends[j] + '</u>';
-					else
-						after += friends[j];
-					
-					after += '</a>';
-					
-//					after_parts.push(after);
-					
-				}
-				else if (j == 1)
-				{
-					after += '<span style="text-decoration:none;float:none;padding:0;font-size:' + 
-								context.font_size + ';color:' + 
-								context.unlinked_color + ';"> + </span>';
-					
-					after += '<a ondblclick="sln" slt="' + slt + 
-								'" style="text-decoration:none;float:none;padding:0;font-size:' + 
-								context.font_size + ';color:' + 
-								context.linked_color + ';" href="' + reviewHref + '" title="' + 
-								friends[0] + ', ' + friends[1];
-				}
-				else
-				{
-					after += ', ' + friends[j];
-				}
-			}
-			
-			if (friends.length > 1)
-			{
-				after += ' like';
-			
-				if (friends.length == 1)
-					after += 's';
-				
-				after += ' this page">' + (friends.length - 1) + '</a>';
-			}
-		}
-		
-		if (context.include_topic && (typeof(su_catnames[topic]) != "undefined"))
-		{
-			after += '<span style="text-decoration:none;float:none;padding:0;font-size:' + 
-						context.font_size + ';color:' + 
-						context.unlinked_color + ';"> · </span><a ondblclick="slz" slt="' + slt + 
-						'" title="See related pages" style="text-decoration:none;float:none;padding:0;font-size:' + 
-						context.font_size + ';color:' + 
-						context.linked_color + ';"href="' + su_serverhttp + 
-						'tag/' + su_catnames[topic].toLowerCase() + '/">';
-			if (context.underline)
-				after += '<u ondblclick="slz">' + su_catnames[topic] + '</u>';
-			else
-				after += su_catnames[topic];
-			after += '</a>';
-		}
-		
-		if (after != '')
-			after_parts.push(after);
-	
-		var el;
-		if (before != "")
-		{
-			el = context.doc.createElement("SPAN");
-			el.style.cssText = "white-space:nowrap!important; float:none!important; padding:0!important; text-decoration:none!important;";
-			el.innerHTML = before;
-			context.before_targets[url_index].parentNode.insertBefore(el, context.before_targets[url_index]);
-		}
-		
-		var after_target = context.after_targets[url_index];
-		
-		if (! context.soft_wrap)
-			after_parts = new Array(after_parts.join(""));
-		
-		for (j = 0; j < after_parts.length; j++)
-		{
-			el = context.doc.createElement("SPAN");
-			var cssText = "white-space:nowrap!important; float:none!important; padding:0!important; text-decoration:none!important;";
-			if(context.force_inline)
-			{
-				cssText += "display:inline!important;";
-			}
-			if (context.soft_wrap)
-				el.innerHTML = after_parts[j].replace(/ /g, " ");
-			else
-				el.innerHTML = after_parts[j];
-			if (after_target.nextSibling)
-				after_target.parentNode.insertBefore(el, after_target.nextSibling);
-			else
-				after_target.parentNode.appendChild(el);
-			after_target = el;
-			el.style.cssText = cssText;
-		}
-	}
-	
-	if (context.enable_click_tracking)
-	{
-		var str = "";
-		var sls = su_ds.globals.sls;
-		for (i = 0; i < sls.length; i++)
-		{
-			var slstats = sls[i]
-			str += slstats.timestamp + "\t" + slstats.slq + "\t" + 
-					slstats.term_count + "\t" + slstats.url_count + "\t" +
-					slstats.decorated_count + "\t" + 
-					slstats.first_decorated_num + "\t:";
-		}
-		
-		su_ds.setValue("$slstats", str);
-		su_ds.setValue("$slistats", slistats.join(":"));
-		su_ds.setValue("$slidfstats", slidfstats.join(":"));
-	}
-	
-	if (! context.done)
-		su_augment_links2(context);
-}
-
-function su_handle_upgrade_click(event)
-{
-	var target = "https://addons.mozilla.org/firefox/138/";
-	su_set_location(target, null, su_new_tab(event));
-	su_set_visible("su_upgrade", false);
-}
-
-function su_handle_stumble_topic_click(event, url)
-{
-	su_set_server_location(
-				"url/" + su_review_url(url),
-				null,
-				su_new_tab(event));
-}
-
-// Generates the topic menu
-function su_prepare_stumble_topic_menu(event, url)
-{
-	var menuEl;
-	if (su_ds.getValue("$stumble_topics_style") == 1)
-		menuEl = su_get_element("su_stumble_topic_menu_right_popup")
-	else
-		menuEl = su_get_element("su_stumble_topic_menu_left_popup");
-	
-	if (event.originalTarget != menuEl)
-		return;
-	
-	if (menuEl.getAttribute("data-url") == url)
-		return;
-	
-	menuEl.removeAttribute("data-url");
-	menuEl.setAttribute("data-url", url);
-
-	// Check if a menu already exists -> If so, we need to remove it
-	while(menuEl.childNodes.length)
-		menuEl.removeChild(menuEl.firstChild);
-	
-	var url_detail = su_ds.lookup("url:url_detail", url);
-	var item;
-	var submenu;
-
-	item = document.createElement("menu");
-	item.setAttribute("label", " Report a problem");
-	item.setAttribute("tooltiptext", "Report...");
-	menuEl.appendChild(item);
-	submenu = document.createElement("menupopup");
-	submenu.setAttribute("id", "su_report_popup");
-	item.appendChild(submenu);
-	
-	su_prepare_reporting_menu(submenu, url_detail, false, url_detail.url);
-	
-	item = document.createElement("menuseparator");
-	menuEl.appendChild(item);
-	
-	item = document.createElement("menuitem");
-	item.setAttribute("label", "This page is about:");
-	item.setAttribute("tooltiptext", "Change topic to...");
-	item.setAttribute("style", "font-weight: bold; color: #404040;");
-	item.setAttribute("disabled", "true");
-	menuEl.appendChild(item);
-	
-	var stumbler_name = su_get_profile_nickname(url);
-	
-	if (stumbler_name)
-	{
-		item = document.createElement("menuitem")
-		item.setAttribute("label", "Stumbler"); // note: actual name is 'Stumblers'
-		if (url_detail.cur_catid == 44)
-		{
-			item.setAttribute("type", "checkbox");
-			item.setAttribute("checked", "true");
-			item.setAttribute("tooltiptext", "This is a stumbler profile");
-			item.setAttribute("oncommand", 'su_handle_recat_reset_checkbox();');
-			item.style.fontWeight = 'bold';
-			item.style.color = "#008B00";
-		}
-		else
-		{
-			item.setAttribute("tooltiptext", "Request topic change from " + url_detail.cur_topic_name + " to Stumblers");
-			item.setAttribute("oncommand",
-					'su_handle_recat_page(event, "' + url + '", 44, "Stumbler");');
-		}
-		menuEl.appendChild(item);
-		
-		item = document.createElement("menuitem")
-		item.setAttribute("label", "Adult Stumbler");
-		if (url_detail.cur_catid == 520)
-		{
-			item.setAttribute("type", "checkbox");
-			item.setAttribute("checked", "true");
-			item.setAttribute("tooltiptext", "This is an adult stumbler profile");
-			item.setAttribute("oncommand", 'su_handle_recat_reset_checkbox();');
-			item.style.fontWeight = 'bold';
-			item.style.color = "#008B00";
-		}
-		else
-		{
-			item.setAttribute("tooltiptext", "Request topic change from " + url_detail.cur_topic_name + " to Adult Stumbler");
-			item.setAttribute("oncommand",
-					'su_handle_recat_page(event, "' + url + '", 520, "Adult Stumbler");');
-		}
-		menuEl.appendChild(item);
-		
-		return;
-	}
-
-	var recat_adult = su_ds.getValue("$recat_adult");
-	
-	// Add list of topics
-	var folders = new Array();
-	var folders_sorted = new Array();
-	var cats_sorted = new Array();
-	for (var cat in su_catnames)
-	{
-		if (typeof(su_topicfolders[cat]) == "undefined")
-			continue;
-		var folder = su_topicfolders[cat];
-		var name = su_catnames[cat];
-		if (typeof(folders[folder]) == "undefined")
-		{
-			folders[folder] = new Array();
-			folders_sorted.push(folder);
-			cats_sorted[folder] = new Array();
-		}
-	
-		folders[folder][name]=cat;
-		cats_sorted[folder].push(name);
-	}
-	
-	folders_sorted.sort();
-	
-	var nickname = su_get_profile_nickname(url);
-	
-	for (var i = 0 ; i < folders_sorted.length ; i++)
-	{
-		var folder = folders_sorted[i];
-		
-		if (folder == "0")
-			continue; // Special treatment for the "StumbleUpon news" cat
-		
-		var item = document.createElement("menu");
-		item.setAttribute("label", folder);
-		item.setAttribute("tooltiptext", "Change topic to...");
-		//item.setAttribute("oncommand",
-		//		'su_handle_stumble_topic_click(event, "' + url + '");');
-		menuEl.appendChild(item);
-		var foldermenu = document.createElement("menupopup");
-		item.appendChild(foldermenu);
-		
-		cats_sorted[folder].sort();
-		for ( var j = 0 ; j < cats_sorted[folder].length ; j++)
-		{
-			var cat = cats_sorted[folder][j];
-			var jcatid = folders[folder][cat];
-			if (folder == "Adult")
-			{
-				if (recat_adult == 0 && nickname && jcatid != 520)
-					continue;
-				else if (recat_adult == 0 && jcatid != 6 && jcatid != 500)
-					continue;
-				else if (recat_adult == 1 && jcatid != 6 && su_ds.lookup("catid:x_flag", jcatid))
-					continue;
-			}
-			
-			var itemCat = document.createElement("menuitem")
-			itemCat.setAttribute("label", cat);
-			if (jcatid == url_detail.cur_catid)
-			{
-				itemCat.setAttribute("type", "checkbox");
-				itemCat.setAttribute("checked", "true");
-				itemCat.setAttribute("tooltiptext", "This page is about " + url_detail.cur_topic_name);
-				itemCat.setAttribute("oncommand", 'su_handle_recat_reset_checkbox();');
-				item.style.fontWeight = 'bold';
-				item.style.color = "#008B00";
-			}
-			else
-			{
-				itemCat.setAttribute("tooltiptext", "Request topic change from " + url_detail.cur_topic_name + " to " + cat);
-				itemCat.setAttribute("oncommand",
-						'su_handle_recat_page(event, "' + url + '", "' + jcatid + '", "' + cat + '");');
-			}
-			foldermenu.appendChild(itemCat);
-			
-			if (jcatid == url_detail.cur_catid)
-			{
-				itemCat.style.fontWeight = 'bold';
-				itemCat.style.color = "#008B00";
-			}
-		}
-	}
-	
-	var catid2 = url_detail.catid2;
-	var catid3 = url_detail.catid3;
-	var has_cat2 = (catid2 && catid2 != url_detail.cur_catid && su_catnames[catid2] && su_catnames[catid2] != '');
-	var has_cat3 = (catid3 && catid3 != url_detail.cur_catid && catid3 != catid2 && su_catnames[catid3] && su_catnames[catid3] != '');
-	
-	if (has_cat2 || has_cat3)
-	{
-		item = document.createElement("menuitem");
-		item.setAttribute("label", "Suggested:");
-		item.setAttribute("tooltiptext", "Change topic to...");
-//		if (has_cat2 && has_cat3)
-//			item.setAttribute("label", "Suggested alternates:");
-//		else
-//			item.setAttribute("label", "Suggested alternate:");
-		item.setAttribute("disabled", "true");
-		item.setAttribute("style", "font-weight: bold; color: #707070;");
-		menuEl.appendChild(item);
-	}
-	
-	// Add possible choices
-	if (has_cat2)
-	{
-		var itemCat = document.createElement("menuitem")
-		itemCat.setAttribute("label", " " + su_catnames[catid2]);
-		itemCat.setAttribute("tooltiptext", "Request topic change from " + url_detail.cur_topic_name + " to " + su_catnames[catid2]);
-		itemCat.setAttribute("oncommand",
-			'su_handle_recat_page(event, "' + url + '", "' + catid2 + '", "' + su_catnames[catid2] + '");');
-		menuEl.appendChild(itemCat);
-	}
-	
-	if (has_cat3)
-	{
-		var itemCat = document.createElement("menuitem")
-		itemCat.setAttribute("label", " " + su_catnames[catid3]);
-		itemCat.setAttribute("tooltiptext", "Request topic change from " + url_detail.cur_topic_name + " to " + su_catnames[catid3]);
-		itemCat.setAttribute("oncommand",
-			'su_handle_recat_page(event, "' + url + '", "' + catid3 + '", "' + su_catnames[catid3] + '");');
-		menuEl.appendChild(itemCat);
-	}
-
-}
-
-function su_handle_recat_reset_checkbox()
-{
-	su_check_progress_listener();
-	
-	var menuEl;
-	if (su_ds.getValue("$stumble_topics_style") == 1)
-		menuEl = su_get_element("su_stumble_topic_menu_right_popup")
-	else
-		menuEl = su_get_element("su_stumble_topic_menu_left_popup");
-	
-	// Menu will be recreated
-	menuEl.removeAttribute("data-url");
-}
-
-// Handle recat of a stumble page using the topic menu
-function su_handle_recat_page(event, url, catid, topic_name)
-{
-	su_check_progress_listener();
-	
-	var detail = new Object();
-	detail.url = url;
-	detail.new_catid = catid;
-	detail.new_topic_name = topic_name;
-
-	var url_detail = su_ds.lookup("url:url_detail", url);
-	if (url_detail)
-	{
-		detail.old_catid = url_detail.cur_catid;
-		detail.old_topic_name = url_detail.cur_topic_name;
-	}
-	else
-	{
-		detail.old_catid = 0;
-		detail.old_topic_name = "unknown";
-	}
-	
-	window.openDialog(
-				"chrome://stumbleupon/content/reportTopicDialog.xul",
-				"",
-				"chrome,titlebar,close,dialog,centerscreen,dependent",
-				detail);
-}
-
-function su_handle_report_topic_dialog_accept(detail)
-{
-	var url_detail = su_ds.lookup("url:url_detail", detail.url);
-	url_detail.cur_catid = detail.new_catid;
-	url_detail.cur_topic_name = detail.new_topic_name;
-	su_change_local_catid(detail.url, detail.new_catid);
-	
-	var menuEl;
-	if (su_ds.getValue("$stumble_topics_style") == 1)
-		menuEl = su_get_element("su_stumble_topic_menu_right_popup")
-	else
-		menuEl = su_get_element("su_stumble_topic_menu_left_popup");
-	
-	// Menu will be recreated
-	menuEl.removeAttribute("data-url");
-	menuEl.setAttribute("onpopupshowing",
-			'su_prepare_stumble_topic_menu(event, "' + detail.url + '");');
-	menuEl.parentNode.setAttribute("label", detail.new_topic_name);
-	
-	// Tell the server to recat the page
-	var doc = getBrowser().contentDocument;
-	var context = new su_AsyncContext();
-	context.url = detail.url;
-	context.ref_url = su_get_browser_url(doc, true);
-	context.title = su_get_title(doc, context.ref_url);
-	
-	var params = "";
-	params = su_arp(params, "url", detail.url);
-	params = su_arp(params, "redirect", url_detail.redirect_url);
-	params = su_arp(params, "current", su_get_browser_url());
-	params = su_arp(params, "newcatid", detail.new_catid);
-	
-	params = su_append_sync_params(params);
-	
-	su_post_url_server_async(
-				"recat.php",
-				params,
-				null,
-				su_generic_done,
-				context);
-
-	su_check_progress_listener();
-}
-
-function su_handle_sponsor_click(event)
-{
-	var target = "sponsored_page.html";
-	su_set_server_location(target, null, su_new_tab(event));
-}
-
-function su_handle_bug_command()
-{
-	var email = "joe at stumbleupon.com";
-	var date = new Date();
-	var str;
-	
-	str = "";
-	str += "The toolbar will now open two tabs:\n\n";
-	str += "o The first tab will attempt to open your e-mail application.\n\n";
-	str += "o The second tab will display the error report.  Use this if you\n";
-	str += "   prefer to copy-and-paste into a web-based e-mail account.\n";
-	str += " ";
-	var response = confirm(str);
-	
-	if (! response)
-		return;
-	
-	str = "[";
-	if ((stumbleid != 0) && su_ds && (su_ds.getValue("$nick") != "")) 
-		str += su_ds.getValue("$nick") + ":";
-	if (stumbleid != 0)
-		str += stumbleid + "] ";
-	str += "toolbar bug report";
-	var subject = str;
-	
-	
-	str = "=== behavior ===\n";
-	str += "\n";
-	str += "Please describe the action(s) you performed.\n";
-	str += "\n";
-	str += "Then describe how the toolbar responded.\n";
-	str += "\n";
-	str += "Feel free to attach screenshots if applicable.\n";
-	str += "\n";
-	str += "\n";
-	str += "=== platform ===\n";
-	str += su_host.desc + "\n";
-	str += navigator.userAgent + "\n";
-	str += su_useragent + "\n";
-	str += date.toUTCString() + "\n";
-	if (su_service && (su_service._messageLog != ""))
-	{
-		str += "\n";
-		str += "\n";
-		str += "=== log ===";
-		str += su_service._messageLog;
-	}
-	try {
-		str += "\n\n" + su_get_addons_desc();
-	} catch (e) {}
-	var body = str;
-	
-	
-	str = "mailto:" + email + "?subject=";
-	str += encodeURIComponent(subject) + "&body=";
-	str += encodeURIComponent(body);
-	
-	su_set_location(str, null, true);
-	
-	str = "\n     TO: " + email + "\n";
-	str += "SUBJECT: " + subject + "\n\n\n" 
-	str += body;
-	
-	var filename = date.getTime() + ".txt"; 
-	su_ds.writeFile(
-				su_ds.getResourceNSIFile("reports", filename), 
-				str);
-	
-	su_set_location(
-				su_ds.getResourceURLFromName("reports", filename),
-				null,
-				true);
-}
-
-function su_get_addons_desc()
-{
-	var i;
-	var datasource = su_get_service(
-				"@mozilla.org/extensions/manager;1",
-				"nsIExtensionManager")
-				.datasource;
-	var root = su_get_rdf_resource("urn:mozilla:item:root");
-	var container = su_create_instance(
-				"@mozilla.org/rdf/container;1",
-				"nsIRDFContainer");
-	container.Init(datasource, root);
-	var elements = container.GetElements();
-
-	var attributes = new Array(
-				"name",
-				"version",
-				"appDisabled",
-				"userDisabled",
-				"internalName");
-				
-	var extensions = new Array();
-	var themes = new Array();
-
-	while(elements.hasMoreElements())
-	{
-		var element = elements.getNext();
-		var item = new Object();
-		for (i = 0; i < attributes.length; i++)
-		{
-			item[attributes[i]] = su_get_rdf_arc_literal(
-						datasource,
-						element,
-						"http://www.mozilla.org/2004/em-rdf#" + attributes[i]);
-		}
-
-		var type_id = su_get_rdf_arc_int(
-					datasource,
-					element,
-					"http://www.mozilla.org/2004/em-rdf#type");
-					
-		switch (type_id)
-		{
-			case 2: extensions.push(item); break;
-			case 4: themes.push(item); break;
-		}
-	}
-	
-	extensions.sort(function (a, b)
-				{ 
-					return a.name.toLowerCase() > b.name.toLowerCase();
-				});
-
-	themes.sort(function (a, b)
-				{
-					return a.name.toLowerCase() > b.name.toLowerCase();
-				});
-	
-	var str = "=== extensions ===\n";
-	for (i = 0; i < extensions.length; i++)
-	{
-		str += extensions[i].name + " ";
-		str += extensions[i].version;
-		if (extensions[i].appDisabled || extensions[i].userDisabled)
-			str += " [disabled]";
-		str += "\n";
-	}
-	
-	var current_theme = null;
-	try {
-		current_theme = su_ds.getValue("general.skins.selectedSkin");
-	} catch(e) {}
-
-	str += "\n\n=== themes ===\n";
-	for (i = 0; i < themes.length; i++)
-	{
-		str += themes[i].name + " ";
-		str += themes[i].version;
-		if (themes[i].internalName == current_theme)
-			str += " [selected]";
-		str += "\n";
-	}
-	return str;
-}
-
-
-function su_refresh_pagemeta(from_stumblevideo_page, from)
-{
-	if (su_refreshing_pagemeta)
-		return;
-	
-	su_refreshing_pagemeta = true;
-	
-	setTimeout(
-				su_update_pagemeta,
-				100,
-				from_stumblevideo_page,
-				from);
-}
-
-
-// Handler for when the page being viewed changes.
-function su_update_pagemeta(from_stumblevideo_page, from)
-{
-	//!!! This needs either (a) to get some code documentation or (b)
-	//    to be refactored into several functions with descriptive
-	//    names. -- JW
-	// Refactoring into several functions is in progress. -- JW
-	su_refreshing_pagemeta = false;
-
-	if (su_new_user)
-		return;
-	
-	var doc = getBrowser().contentDocument;
-	var new_url = su_get_browser_url(doc);
-	var raw_url = su_get_browser_url(doc, true);
-	var new_tld;
-	var rateable = false;
-	var rec_url = null;
-	var url_detail = null;
-	var stumblevideo = su_is_matching_domain(raw_url, "video." + su_servername);
-	if (stumblevideo && (! from_stumblevideo_page))
-		su_stumblevideo_page(doc, false);
-	
-	try {
-		if (! url_detail)
-			url_detail = su_ds.lookup("url:url_detail", new_url);
-		
-		if (url_detail)
-		{
-			new_url = url_detail.url;
-			new_tld = url_detail.tld;
-			rateable = true;
-			rec_url = url_detail.url;
-		}
-		else if (stumbleid)
-		{
-			new_tld = su_get_tld(new_url);
-			rateable = su_is_url_rateable(new_url, new_tld);
-			if (su_ds.lookup("url:from_portal_flag", new_url))
-			{
-				rec_url = new_url;
-			}
-			else if (su_get_tld(su_get_browser_referrer_url(doc)) == su_servername)
-			{
-				su_ds.define("url:from_portal_flag", new_url, 1);
-				rec_url = new_url;
-			}
-		}
-	} catch (e) { su_log_error("PAGEVIEW DETAILLOOKUP", e); }
-	
-    if (su_promo_mode && (stumbleid == 0))
-	{
-		
-		try {
-			su_update_website_info_promo(new_url);
-		} catch (e) { su_log_error("PAGEVIEW INFOPROMO", e); }
-		
-		try {
-			if (su_get_stumblevideo_detail())
-				su_set_visible("su_thumbdown", true);
-			else
-				su_set_visible("su_thumbdown", false);
-	
-			//!!! we do enable all the time to fix thet problem where sometimes the comment button doesn't get cleared?
-			if (typeof(su_ratings[new_url]) != "undefined")
-				su_disable_toolbar(su_ratings[new_url]);
-			else
-				su_enable_toolbar();
-		} catch (e) { su_log_error("PAGEVIEW PROMORATEBUTTONS", e); }
-		
-		return;
-	}
-	else if (stumbleid == 0)
-	{
-		return;	
-	}
-	
-	var stumbler_name = null; 
-	
-	if ((new_tld == su_servername) || (new_tld == 'stumbleupon.com'))
-		stumbler_name = su_get_profile_nickname(new_url);
-	
-	if (stumbler_name)
-		rec_url = new_url;
-	
-	var non_self_stumbler = (stumbler_name &&
-			(stumbler_name != stumbleid) &&
-			(stumbler_name != su_ds.getValue("$nick")));
-
-	var browser = getBrowser().selectedBrowser;
-	
-	var tab_url_detail = (browser.su_url_detail) ? browser.su_url_detail : null;
-	
-	try {
-		su_update_thru_domain(new_url, new_tld, url_detail, stumblevideo, false);
-	} catch (e) { su_log_error("PAGEVIEW FAVICON", e); }
-	try {
-		su_update_message(tab_url_detail, url_detail, new_url, new_tld, stumblevideo);
-	} catch (e) { su_log_error("PAGEVIEW MESSAGE", e); }
-	try {
-		su_update_page_feature_prompt(new_url);
-	} catch (e) { su_log_error("PAGEVIEW FEATUREPROMPT", e); }
-	try {
-		su_update_firstrater(url_detail);
-	} catch (e) { su_log_error("PAGEVIEW FIRSTRATER", e); }
-	try {
-		su_update_topic_and_reporting(tab_url_detail, url_detail, new_tld, false, rec_url);
-	} catch (e) { su_log_error("PAGEVIEW TOPIC", e); }
-//	try {
-//		su_update_language(url_detail, false);
-//	} catch (e) { su_log_error("PAGEVIEW LANGUAGE", e); }
-	try {
-		su_update_comment_level(url_detail, rateable);
-	} catch (e) { su_log_error("PAGEVIEW COMMENT", e); }
-	try {
-		su_update_referral_menu_tooltip(url_detail, stumblevideo);
-	} catch (e) { su_log_error("PAGEVIEW TOOLTIP", e); }
-	try {
-		su_update_thumbs(new_url, rateable, non_self_stumbler, stumblevideo, url_detail);
-	} catch (e) { su_log_error("PAGEVIEW THUMBS", e); }
-	try {
-		su_update_stumbling_options(non_self_stumbler, stumbler_name); 
-	} catch (e) { su_log_error("PAGEVIEW STUMBLER", e); }
-	try {
-		su_update_tags(new_url)
-	} catch (e) { su_log_error("PAGEVIEW TAGS", e); }
-	
-	
-	// See if this is a tag page
-	// only do this is text is on
-	var tag_page = 0;
-	var tag_name = '';
-
-	try {
-		if (new_url.indexOf(su_base_url + "tag/") == 0)
-		{
-			spliturl = new_url.split("/");
-			if (spliturl.length > 4 && spliturl[4] != '')
-			{
-				tag_name = spliturl[4];
-				//alert("tag " + tag_name);
-				tag_page = 1;
-			}
-		}
-	
-		if (tag_page)
-		{
-			// change favorites of
-			el = su_get_element("su_cat_stumble_tags");
-			if (el)
-			{
-				el.setAttribute("label", "Through " + tag_name + "...");
-				el.setAttribute("oncommand", "su_select_topic('TAG_" + tag_name + "', '" + tag_name + "', false);");
-				el.setAttribute("tooltiptext", stumbler_name + "'s Pages");				
-			}
-			su_set_image("su_category", "chrome://stumbleupon/content/skin/tag.png");
-		}
-		else
-		{
-			el = su_get_element("su_cat_stumble_tags");
-			if (el)
-			{
-				el.setAttribute("label", "Search");
-				el.setAttribute("oncommand", 'su_handle_mode_click(event, "Search");');
-				el.setAttribute("tooltiptext", "Stumble within a query");
-			}
-		}
-	} catch (e) { su_log_error("PAGEVIEW TAG", e); }
-
-
-	try {
-		// Reset message when we hit the message page
-		if (new_url.indexOf("." + su_servername + "/inbox/")!=-1)
-		{
-			su_ds.setValue("$newmessage", false);
-			su_set_inbox_status('');
-		}
-	} catch (e) { su_log_error("PAGEVIEW INBOX", e); }
-
-
-	setTimeout("su_reflow_toolbar(15)", 80);
-	
-}
-
-function su_update_thumbs(url, rateable, non_self_stumbler, stumblevideo, url_detail)
-{
-	if (stumblevideo)
-		su_get_element("su_thumbdown").type = "";
-	else
-		su_get_element("su_thumbdown").type = "menu-button";
-	
-	var rating;
-	if (rateable)
-		rating = su_get_rating(url, stumblevideo, url_detail);
-	else
-		rating = null;
-	
-	//!!! we do enable all the time to fix thet problem where sometimes the comment button doesn't get cleared?
-	if (rating == null)
-		su_enable_toolbar();
-	else
-		su_disable_toolbar(rating);
-		
-	// disable rating buttons on url pages
-	if (rateable)
-	{
-//			su_get_element("su_thumbdown").disabled=false;
-		// if the thumb isn't green, we should enable it
-		su_get_element("su_thumbup").disabled=false;
-		su_get_element("su_thumbdown").disabled=false;
-		su_get_element("su_thumbup").setAttribute("onclick", su_get_element("su_thumbup").getAttribute("onclick2"));
-	}
-	else
-	{
-		// disable rating buttons
-		su_get_element("su_thumbup").disabled=true;
-		su_get_element("su_thumbdown").disabled=true;
-		su_get_element("su_thumbup").setAttribute("onclick", "");
-	}
-	
-	if (su_ds.getValue("$icons") != "icons-only")
-	{
-		if (non_self_stumbler)
-			su_set_label("su_thumbup", su_get_element("su_thumbup").getAttribute('showlabel2'));
-		
-		else			
-			su_set_label("su_thumbup", su_get_element("su_thumbup").getAttribute('showlabel'));
-	}
-}
-
-function su_update_tags(new_url)
-{
-	var tag_list = su_get_tag_list(new_url);
-	
-	if (tag_list)
-		su_disable_tag_toolbar(tag_list);
-	else
-		su_enable_tag_toolbar();
-}
-
-function su_update_stumbling_options(non_self_stumbler, stumbler_name)
-{
-	var el;
-	
-	if (non_self_stumbler)
-	{
-		el = su_get_element("su_cat_favorites_of2");
-		if (el)
-		{
-			el.setAttribute("label", stumbler_name + "'s Favorites");
-			el.setAttribute("onclick", 'su_handle_mode_click(event, "' + stumbler_name + '");');
-			el.setAttribute("tooltiptext", stumbler_name + "'s favorites");				
-			if (su_is_mutual_friend(stumbler_name))
-				el.setAttribute("image", "chrome://stumbleupon/content/skin/mutual_favorites.png");
-			else
-				el.setAttribute("image", "chrome://stumbleupon/content/skin/stumbler_favorites.png");
-			el.setAttribute("hidden", "false");
-		}
-
-		el = su_get_element("su_mode_stumbler");
-		el.setAttribute("tooltiptext", "Stumble " + stumbler_name + "'s favorites");
-		el.setAttribute("onclick", 'su_handle_mode_click(event, "' + stumbler_name + '");');
-		if (su_is_mutual_friend(stumbler_name))
-			su_set_image("su_mode_stumbler", "chrome://stumbleupon/content/skin/mutual_favorites.png");
-		else
-			su_set_image("su_mode_stumbler", "chrome://stumbleupon/content/skin/stumbler_favorites.png");
-		su_set_visible("su_mode_stumbler", true);
-	}
-	else
-	{
-		el = su_get_element("su_cat_favorites_of2");
-		if(el)
-		{
-			el.setAttribute("hidden", "true");
-		}
-		
-		su_set_visible("su_mode_stumbler", (! su_ds.getValue("$show_mode_stumbler")));
-	}
-}
-
-function su_get_profile_nickname(url)
-{
-	var domain = su_get_tld(url);
-	
-	if (domain == 'stumbleupon.com')
-	{
-		var spliturl = url.split("/");
-		
-		var domains = spliturl[2].split(".");
-		
-		if (domains.length != 3)
-			return null;
-			
-		if (su_ds.lookup("nickname:bad_nick_flag", domains[0]))
-			return null;
-		
-		return domains[0];
-	}
-	else if ((su_servername != 'stumbleupon.com')
-			&& (domain == su_servername))
-	{
-		var spliturl = url.split("/");
-		
-		var domains = spliturl[2].split(".");
-		
-		var serverparts = su_servername.split(".");
-
-		if (domains.length != (serverparts.length + 1))
-			return null;
-			
-		if (su_ds.lookup("nickname:bad_nick_flag", domains[0]))
-			return null;
-		
-		return domains[0];
-	}
-	else
-	{
-		return null;
-	}
-}
-
-function su_get_service_id(url, results_page_only)
-{
-	if (! url.match(/(google|yahoo|ask|myspace|youtube|flickr|wikipedia|aol|cnn|bing|nytimes|cbsnews|cnet|abcnews|msnbc)/i))
-		return null;
-	
-	url = url.toLowerCase();
-	
-	if (url.match(/^http.*?\/\/[^\/]*?(news\.google\.[^\.]+|news\.google\.co\.[^\.]+)\/(news.*[?&]q=)/))
-		return "googlenews";
-
-	else if (url.match(/^http.*?\/\/(news\.google\.[^\.]+|news\.google\.co\.[^\.]+)/))
-		return "googlenewsindex";
-
-	else if (url.match(/^http.*?\/\/[^\/]*?(video\.google\.[^\.]+|video\.google\.co\.[^\.]+)\/(videosearch.*[?&]q=)/))
-		return "googlevideo";
-	
-	if (url.match(/^http.*?\/\/[^\/]*?(google\.[^\.]+|google\.co\.[^\.]+)\/((search|custom).*[?&](q|as_q)=)/))
-		return "google";
-
-	else if (url.match(/^http.*?\/\/[^\/]*?(google\.[^\.]+|google\.co\.[^\.]+)(\/$|webhp|#hl)/))
-		return "google-ajax";
-
-	else if (url.match(/^http.*?\/\/[^\/]*?(www\.ask\.com)\/(web.*[?&]q=)/))
-		return "ask";
-	
-	else if (url.match(/^http.*?\/\/[^\/]*?(www\.bing\.com)\/(search.*?q=)/))
-		return "bing";
-	
-	else if (url.match(/^http.*?\/\/[^\/]*?(www\.bing\.com)\/news\/(search.*?q=)/))
-		return "bing-news";
-	
-	else if (url.match(/^http.*?\/\/[^\/]*?((search|custom)(\.)(.*(\.))?yahoo(\.).*)\/(search.*[?&]p=)/))
-		return "yahoo";
-
-	else if (url.match(/^http.*?\/\/[^\/]*?(search(\.)(.*(\.))?aol(\.).*)\/(search.*[?&]query=)/))
-		return "aol";
-	
-	else if (url.match(/^http.*?\/\/[^\/]*?(searchservice\.myspace\.com)\/.*[?&]fuseaction=sitesearch\.results/))
-		return "myspace";
-	
-	else if (url.match(/^http.*?\/\/[^\/]*?(youtube\.com)\/results.*[?&]search_query=/))
-		return "youtube";
-	
-	else if (url.match(/^http.*?\/\/[^\/]*?flickr\.[^\.]+\/(search|.*[?&]q=)/))
-		return "flickr";
-	
-	else if (url.match(/^http.*?\/\/[^\/]*\.wikipedia\.org\/wiki\//))
-		return "wikipedia";
-	
-	else if (url.match(/^http:\/\/search\.cnn\.com\/search.*[?&]query=/))
-		return "cnn";
-	
-	else if (url.match(/^http:\/\/query\.nytimes\.com\/search\/.*[?&]query=/))
-		return "nyt";
-	
-	else if (url.match(/^http.*?\/\/(search|www)\.cbsnews\.com.*[?&]query=/))
-		return "cbsnews";
-	
-	else if (url.match(/^http.*?\/\/news\.cnet\.com.*[?&]query=/))
-		return "cnetnews";
-	
-	else if (url.match(/^http.*?\/\/abcnews\.go\.com.*[?&]searchtext=/))
-		return "abcnews";
-	
-	else if (url.match(/^http:\/\/([^\.]*?\.)?msnbc\.msn\.com\/.*[?&]q=/))
-		return "msnbc";
-	
-	else if (results_page_only)
-		return null;
-
-	else if (url.match(/^http.*?\/\/((www|news|video)\.google\.[^\.]+|(www|news|video)\.google\.co\.[^\.]+)/))
-		return "google";
-	
-	else if (url.indexOf("http://www.ask.com") == 0)
-		return "ask";
-	
-	else if (url.indexOf("http://www.yahoo.com") == 0)
-		return "yahoo";
-	
-	else if (url.indexOf("http://www.aol.com") == 0)
-		return "aol";
-    
-	else
-		return null;
-
-	
-// Porting search page filters from the iebar follows the general 
-// pattern below.  Note that migrating from strings to literal regular
-// expressions involves changing some escaping.
-//	    else if (url.match(/^http.*?\/\/[^/]*?(URL_HOST_MATCH)/(PATH_MATCH)/))
-// -- JW
-}
-
-function su_get_service_meta(url, results_page_only)
-{
-	var service_id = su_get_service_id(url, results_page_only);
-
-	if (! service_id)
-		return null;
-
-	var detail = new Object();
-	
-	detail.id = service_id;	
-	switch (service_id)
-	{
-		case "google":
-		case "google-ajax":
-		case "googlevideo":
-		case "googlenews":
-		case "googlenewsindex":
-			detail.name = "Google";
-			detail.icon = "chrome://stumbleupon/content/skin/favicon_google.png";
-			break;
-		case "ask":
-			detail.name = "Ask";
-			detail.icon = "chrome://stumbleupon/content/skin/favicon_ask.png";
-			break;
-        case "bing":
-            detail.name = "Bing";
-            detail.icon = "chrome://stumbleupon/content/skin/bubble.png";
-            break;
-		case "yahoo":
-			detail.name = "Yahoo";
-			detail.icon = "chrome://stumbleupon/content/skin/favicon_yahoo.png";
-			break;
-		case "aol":
-			detail.name = "AOL";
-			detail.icon = "chrome://stumbleupon/content/skin/favicon_aol.png";
-			break;
-		case "youtube":
-			detail.name = "YouTube";
-			detail.icon = "chrome://stumbleupon/content/skin/favicon_youtube.png";
-			break;
-		case "flickr":
-			detail.name = "Flickr";
-			detail.icon = "chrome://stumbleupon/content/skin/favicon_flickr.png";
-			break;
-		default:
-			detail = null;
-			break;
-	}
-	
-	if (detail)
-	{
-		detail.prompt_label = "See ratings on " + detail.name;
-		detail.prompt_tooltip = "See who likes your " + detail.name + " search results";
-	}
-	
-	return detail;
-}
-
-function su_get_search_query_detail(opt_service_id, opt_url)
-{
-	var url;
-	if (opt_url)
-		url = opt_url;
-	else
-		url = su_get_browser_url();
-	
-	var service_id;
-	if (opt_service_id)
-		service_id = opt_service_id;
-	else
-		service_id = su_get_service_id(url, true);
-	
-	var detail = new Object();
-	detail.term_count = 0;
-	detail.is_query_results = false;
-	detail.is_short_query_results = false;
-	detail.is_first_page = true;
-	detail.domain = su_get_domain(url);
-	detail.service_id = service_id;
-	
-	var query_match;
-	var page_match;
-	switch (service_id)
-	{
-		case "google":
-		case "google-ajax":
-		case "googlenews":
-		case "googleindex":
-		case "googlevideo":
-			page_match = url.match(/[?&](start=)/);
-			query_match = url.match(/[?&]q=([^&]*)/);
-			break;
-		case "ask":
-			page_match = url.match(/[?&](page=)/);
-			query_match = url.match(/[?&]q=([^&]*)/);
-			break;
-        case "bing":
-            page_match = url.match(/[?&](first=)/);
-            query_match = url.match(/[?&]q=([^&]*)/);
-            break;
-		case "yahoo":
-			page_match = url.match(/[?&](b=)/);
-			query_match = url.match(/[?&]p=([^&]*)/);
-			break;
-		case "aol":
-			page_match = url.match(/[?&](page=)/);
-			query_match = url.match(/[?&]query=([^&]*)/);
-			break;
-	}
-	
-	if (query_match && query_match[1])
-		detail.term_count = query_match[1].split("+").length;
-
-	if (query_match)
-		detail.is_query_results = true;
-	
-	if ((detail.term_count > 0) && (detail.term_count < 3))
-		detail.is_short_query_results = true;
-	
-	if (page_match && page_match[1])
-		detail.is_first_page = false;
-	
-	return detail;
-}
-
-// handles the DOMContentLoaded event
-function su_on_load_page(event)
-{
-	var doc = event.target;
-	var url;
-	try {
-		url = su_get_browser_url(doc).toLowerCase();
-	} catch (e) { return; }
-	
-	try {
-		var win = doc.defaultView.wrappedJSObject;
-		if (win.top != win)
-			return;
-	} catch (e) {}
-	
-	var tld = su_get_tld(url);
-	var portal_http = false;
-	var portal_tld = false;
-	
-	if (tld == su_servername)
-	{
-		portal_tld = true;
-		
-		su_attach_api(doc);
-		
-		su_wire_portal_links(doc);
-
-		if (su_visited_login_page)
-			su_login_page_after();
-		
-		if (su_is_server_page(url, ""))
-		{
-			portal_http = true;
-			
-			// signup.php -- the page we send them to
-			if (su_is_server_page(url, "signup.php"))
-				su_signup_page(doc);
-			
-			// sign_up.php -- the page they go to if they click "Join stumbleupon"
-			// from the web site
-			else if (su_is_server_page(url, "sign_up.php"))
-				su_sign_up_page(url);
-			
-			else if (su_is_server_page(url, "find_friends.php"))
-				su_find_friends_page(url);
-			
-			else if (su_is_server_page(url, "login.php"))
-				su_login_behavior_page();
-		}
-		else if (su_is_matching_domain(url, "video." + su_servername))
-		{
-			su_stumblevideo_page(doc, true);
-		}
-	}
-	else if (tld == "facebook.com")
-	{
-		su_facebook_page(doc, url);
-	}
-	
-	setTimeout(su_check_progress_listener, 0);
-	
-	if (stumbleid == 0)
-		return;
-	
-	if (su_has_searchbox)
-	{
-		setTimeout(su_restore_searchbox_focus, 100);
-		setTimeout(su_restore_searchbox_focus, 300);
-		setTimeout(su_restore_searchbox_focus, 1000);
-		setTimeout(su_restore_searchbox_focus, 3000);
-	}
-	
-	var search_results_service_id = su_get_service_id(url, true);
-	var search_service_id =  su_get_service_id(url, false);
-	
-	if (search_results_service_id)
-		su_search_results_page(doc, search_results_service_id);
-	
-	else if (search_service_id)
-		su_search_service_page(doc, search_service_id);
-	
-	else if (portal_http)
-	{
-		su_portal_http_page(doc);
-		
-		if (url.indexOf(su_serverhttp + "tag/") == 0)
-			su_tag_page(doc);
-
-		else if (url.indexOf(su_serverhttp + "find_friends_after.php") == 0)
-			su_find_friends_after_page();
-	
-		else if (url.indexOf(su_serverhttp + "interests_after.php") == 0)
-			su_legacy_interests_after_page(doc);
-		
-		else if (url.indexOf(su_serverhttp + "topic/") == 0)
-			su_tag_page(doc);
-	}
-	
-	else if (portal_tld)
-	{
-		var host = su_ds.getValue("$nick").toLowerCase() + "." + su_servername + "/";
-		var profilehttp = "http://" + host;
-		var profilehttps = "https://" + host;
-		if ((url.indexOf(profilehttp + "prefs/interests")==0) ||
-			(url.indexOf(profilehttps + "prefs/interests")==0))
-			su_interests_page(doc);
-		else if ((url.indexOf(profilehttp + "prefs/" )==0) ||
-				(url.indexOf(profilehttps + "prefs/" )==0))
-			su_prefs_page(doc);
-	}
-	
-	su_refresh_pagemeta(false, 7);
-}
-
-function su_get_debug_header()
-{
-	var datasource = su_get_service(
-				"@mozilla.org/extensions/manager;1",
-				"nsIExtensionManager")
-				.datasource;
-	
-	var root = su_get_rdf_resource("urn:mozilla:item:root");
-	var container = su_create_instance(
-				"@mozilla.org/rdf/container;1",
-				"nsIRDFContainer");
-	container.Init(datasource, root);
-	var elements = container.GetElements();
-
-	var attributes = new Array(
-				"name",
-				"version",
-				"appDisabled",
-				"userDisabled");
-				
-	var gm_detail = null;
-	var ns_detail = null;
-	while(elements.hasMoreElements())
-	{
-		var element = elements.getNext();
-		var item = new Object();
-		for (i = 0; i < attributes.length; i++)
-		{
-			item[attributes[i]] = su_get_rdf_arc_literal(
-						datasource,
-						element,
-						"http://www.mozilla.org/2004/em-rdf#" + attributes[i]);
-		}
-
-		var type_id = su_get_rdf_arc_int(
-					datasource,
-					element,
-					"http://www.mozilla.org/2004/em-rdf#type");
-		
-		if (type_id == 2 && item.name && item.name == "Greasemonkey")
-		{
-			gm_detail = new Object();
-			gm_detail.version = item.version;
-			gm_detail.enabled = (item.appDisabled || item.userDisabled) ? 0 : 1;
-		}
-		else if (type_id == 2 && item.name && item.name == "NoScript")
-		{
-			ns_detail = new Object();
-			ns_detail.version = item.version;
-			ns_detail.enabled = (item.appDisabled || item.userDisabled) ? 0 : 1;
-		}
-		
-		if (gm_detail && ns_detail)
-			break;
-	}
-	
-	if ((! gm_detail) && (! ns_detail))
-		return null;
-	
-	var obj = new Object();
-
-	if (gm_detail)
-	{
-		if (su_ds.isPrefDefined("greasemonkey.enabled"))
-			gm_detail.running = (su_ds.getValue("greasemonkey.enabled")) ? 1 : 0;
-			
-		var scripts = su_get_gm_scripts();
-		if (scripts)
-			gm_detail.scripts = scripts;
-
-		obj.greasemonkey = gm_detail;
-	}
-	
-	if (ns_detail)
-	{
-		if (su_ds.isPrefDefined("noscript.global"))
-			ns_detail.running = (su_ds.getValue("noscript.global")) ? 0 : 1;
-
-		obj.noscript = ns_detail;
-	}
-	
-	return su_ds.serialize(obj, false);
-}
-
-function su_get_noscript_enabled_version()
-{
-	if ((typeof noscriptUtil) != "object")
-		return false;
-	
-	var datasource = su_get_service(
-				"@mozilla.org/extensions/manager;1",
-				"nsIExtensionManager")
-				.datasource;
-	
-	var root = su_get_rdf_resource("urn:mozilla:item:root");
-	var container = su_create_instance(
-				"@mozilla.org/rdf/container;1",
-				"nsIRDFContainer");
-	container.Init(datasource, root);
-	var elements = container.GetElements();
-
-	var attributes = new Array(
-				"name",
-				"version",
-				"appDisabled",
-				"userDisabled");
-				
-	while(elements.hasMoreElements())
-	{
-		var element = elements.getNext();
-		var item = new Object();
-		for (i = 0; i < attributes.length; i++)
-		{
-			item[attributes[i]] = su_get_rdf_arc_literal(
-						datasource,
-						element,
-						"http://www.mozilla.org/2004/em-rdf#" + attributes[i]);
-		}
-
-		var type_id = su_get_rdf_arc_int(
-					datasource,
-					element,
-					"http://www.mozilla.org/2004/em-rdf#type");
-		
-		if (type_id == 2 && item.name && item.name == "NoScript" &&
-				(! item.appDisabled) && (! item.userDisabled))
-		{
-			return item.version;
-		}
-	}
-	return null;
-}
-
-//
-// su_dotversion_compare
-//
-// Compares two version numbers of the form a.b.c.d.
-// Results are:
-//    ver1 > ver2  : +1
-//    ver1 < ver2  : -1
-//    ver1 == ver2 : 0
-//    poorly formatted version number : null
-//
-// If they are different lengths, for example:
-//     1.9.3
-//     1.9.3.4
-// Then the longer version is considered larger.
-//
-function su_dotversion_compare(ver1, ver2)
-{
-	var parts1 = ver1.split(".");
-	var parts2 = ver2.split(".");
-	
-	for(var i=0; (i < parts1.length) && (i < parts2.length); i++)
-	{
-		var n1 = parseInt(parts1[i]);
-		var n2 = parseInt(parts2[i]);
-		if(isNaN(n1) || isNaN(n2))
-			return null;
-		
-		if(n1 > n2)
-			return 1;
-		else if(n1 < n2)
-			return -1;
-	}
-	
-	if(i == 0)
-		return null;
-	
-	if(parts1.length > parts2.length)
-		return 1;
-	else if(parts1.length < parts2.length)
-		return -1;
-	else
-		return 0;
-}
-
-function su_get_gm_scripts()
-{
-	var file = su_get_service(
-				"@mozilla.org/file/directory_service;1",
-				"nsIProperties")
-				.get("ProfD", Components.interfaces.nsILocalFile);
-	file.append("gm_scripts");
-	
-	if (! file.exists())
-	{
-		file = su_ds.getChromeNSIFile("chrome://greasemonkey/content").parent;
-		file.append("scripts");
-	}
-	
-	file.append("config.xml");
-	
-	if (! file.exists())
-		return null;
-	
-	var str = su_ds.readFile(file);
-	
-	if (str == "")
-		return null;
-	
-	var doc = su_create_instance(
-				"@mozilla.org/xmlextras/domparser;1",
-				"nsIDOMParser")
-				.parseFromString(str, "text/xml");
-	
-	var nodes = doc.evaluate("/UserScriptConfig/Script", doc, null, 0, null);
-
-	var scripts = new Array();
-	var node;
-	for (node = null; (node = nodes.iterateNext()); )
-	{
-		var detail = new Object();
-
-		var i;
-		var childNode;
-//		detail.su = 0;
-//		for (i = 0, childNode = null; (childNode = node.childNodes[i]); i++)
-//		{
-//			if (childNode.nodeName == "Include") 
-//				detail.su = (childNode.firstChild.nodeValue.toLowerCase().indexOf("stumbleupon") != -1) ? 1 : 0;
-//			
-//			if (detail.su)
-//				break;
-//		}
-		detail.name = node.getAttribute("name");
-		detail.enabled = (node.getAttribute("enabled") == true.toString()) ? 1 : 0;
-
-		scripts.push(detail);
-	}
-	
-	return scripts;
-}
-
-function su_handle_prefetch_load_start()
-{
-	var original_target = su_prefetcher.getCurrentTarget();
-	var ultimate_target = su_prefetcher.getRedirectTarget(original_target);
-	var status = su_prefetcher.getHttpResponseStatus(original_target);
-	
-	if ((status == 301) || ((status == 302) && 
-				(su_get_tld(original_target) != su_get_tld(ultimate_target))))
-	{
-		// The url is a permanent redirect (301) or a 302 redirect
-		// to a different domain.
-		su_report_redirect(url, status, ultimate_target);
-	}
-}
-
-function su_report_redirect(url, status, new_target)
-{
-	if (su_ds.lookup("url:reported_404_flag", url))
-		return;
-
-	su_ds.define("url:reported_404_flag", url, 1);
-
-	var context = new Object();
-	context.quiet = true;
-	
-	var params = "";
-	params = su_arp(params, "url", url);
-	params = su_arp(params, "status", status);
-	params = su_arp(params, "newurl", new_target);
-	
-	su_post_url_server_async(
-			"404.php",
-			params,
-			15000,
-			su_generic_done,
-			context);
-}
-
-function su_report_404(url, status)
-{
-	if (su_ds.lookup("url:reported_404_flag", url))
-		return;
-	
-	su_ds.define("url:reported_404_flag", url, 1);
-
-	var context = new Object();
-	context.quiet = true;
-	
-	var params = "";
-	params = su_arp(params, "url", url);
-	params = su_arp(params, "status", status);
-	
-	su_post_url_server_async(
-			"404.php",
-			params,
-			15000,
-			su_generic_done,
-			context);
-}
-
-function su_preload_images()
-{
-	var el = document.createElement("image");
-	var id = "su_image_loader" + su_load_image_count;
-	su_load_image_count++;
-	el.setAttribute("id", id);
-	el.setAttribute("src", "chrome://stumbleupon/content/skin/arrow_green-b.png");
-	el.setAttribute("style", "visibility:hidden;border:0px solid black;width:0px;height:0px;");
-}
-
-function su_handle_resource_installed(event)
-{
-	var el = document.createElement("image");
-	var id = "su_image_loader" + su_load_image_count;
-	su_load_image_count++;
-	el.setAttribute("src", 
-				su_ds.getResourceURLFromSourceURL(event.URL));
-	el.setAttribute("id", id);
-	el.setAttribute("style", "visibility:hidden;border:0px solid black;width:0px;height:0px;");
-	el.setAttribute("onload", 'su_handle_resource_image_load(event, "' + event.URL + '", "' + id + '");');
-	el.setAttribute("onerror", 'su_handle_resource_image_load(event, "' + event.URL + '", "' + id + '");');
-	document.getElementById("main-window").appendChild(el);
-}
-
-function su_handle_resource_image_load(event, source_url, testid)
-{
-	var iconpic_regex = new RegExp("^http://cdn.stumble-upon.com/iconpics/(\\d*)\\.jpg$");
-	var iconpic_match = source_url.match(iconpic_regex);
-	var favicon_regex = new RegExp("^http://cdn.stumble-upon.com/images/stumblethru/(.*\\.ico)$");
-	if (su_test_stumblethru_update)
-		favicon_regex = new RegExp("^" + su_serverhttp + "images/stumblethru/(.*\\.ico)$");
-	var favicon_match = source_url.match(favicon_regex);
-	var searchlinks_regex = new RegExp("^http://cdn.stumble-upon.com/images/(.*searchlinks.*_prompt.gif)$");
-	var searchlinks_match = source_url.match(searchlinks_regex);
-	if (iconpic_match)
-	{
-		var contactid = iconpic_match[1];
-		var contact = su_ds.selectRow("contact", "contactid", contactid);
-		if (event.type == "load")
-		{
-			if (contact)
-			{
-				contact.iconpic = su_get_time_s();
-				su_ds.updateRow(contact);
-				su_refresh_referral_menu(9);
-			}
-		}
-		else
-		{
-			if (contact)
-			{
-				contact.iconpic = 0;
-				su_ds.updateRow(contact);
-			}
-			su_ds.deleteFile(
-						su_ds.getResourceNSIFile("iconpics", contactid + ".jpg"));
-		}
-	}
-	else if (searchlinks_match)
-	{
-		var filename = searchlinks_match[1];
-		if (event.type == "load")
-		{
-			if (su_searchlinks_dialog_detail)
-			{
-				var detail = su_searchlinks_dialog_detail;
-				su_searchlinks_dialog_detail = null;
-				su_handle_searchlinks_dialog_resource_load(detail);
-			}
-		}
-		else
-		{
-			su_ds.setValue("$shown_searchlinks_dialog", false);
-			su_ds.setValue("$show_searchlinks_score", false);
-			su_ds.setValue("$show_searchlinks_friends", false);
-			su_ds.setValue("$show_searchlinks_topic", false);
-			su_ds.flushPrefs();
-			su_ds.deleteFile(
-						su_ds.getResourceNSIFile("images", filename));
-			if (su_searchlinks_dialog_detail)
-			{
-				var detail = su_searchlinks_dialog_detail;
-				su_searchlinks_dialog_detail = null;
-				if (detail.stumble)
-					stumble(stumble.new_tab, true);
-			}
-		}
-	}
-	else if (favicon_match)
-	{
-		if (event.type == "load")
-		{
-			su_refresh_dyn_channels();
-		}
-		else
-		{
-			var filename = favicon_match[1];
-			su_ds.deleteFile(
-						su_ds.getResourceNSIFile("favicons", filename));
-		}
-	}
-	
-	var el = document.getElementById(testid);
-	el.parentNode.removeChild(el);
-}
-
-// in Firefox 1.5+, this observer service listener detects application
-// event, like uninstalling the toolbar or quitting the application
-var su_host_observer =
-{
-	observe : function(subject,topic,data)
-	{
-		subject = subject.QueryInterface(Components.interfaces.nsIUpdateItem);
-
-		if ((topic == "em-action-requested") && (subject.name == "StumbleUpon") && 
-					(data == "item-uninstalled"))
-		{
-			su_handle_em_uninstall();
-		}
-	}
-}
-
-// each window's load() registers an event_observer; when a window 
-// invokes an event using invoke_global_event(), the observerService 
-// dispatches a notification to each event_observer
-var su_event_observer =
-{
-	observe : function (subject, topic, data)
-	{
-		var detail = null;
-		if (data && data != "")
-			detail = su_ds.deserialize(data);
-		
-		switch (topic)
-		{
-			case "su_login":
-				var skip_cookies = (detail && detail.skip_cookies);
-				var ignore_cookies = (detail && detail.ignore_cookies);
-				var new_profile = (detail && detail.new_profile);
-				var new_user_prompt = (detail && detail.new_user_prompt);
-				su_login(skip_cookies, ignore_cookies, new_profile, new_user_prompt);
-				break;
-			case "su_logout":
-				su_logout();
-				break;
-			case "su_change-password":
-				su_change_password();
-				break;
-			case "su_configure-toolbar":
-				var from_preference_dialog = (detail && detail.from_preference_dialog);
-				su_configure_toolbar(from_preference_dialog);
-				break;
-			case "su_referral-menu-dirty":
-				su_referral_menu_dirty = true;
-				break;
-			case "su_update-referral-menu":
-				su_update_referral_menu();
-				break;
-			case "su_refresh-category-selector":
-				su_refresh_category_selector();
-				break;
-			case "su_dyn-channels-dirty":
-				su_dyn_channels_dirty = true;
-				break;
-			case "su_update-dyn-channels":
-				su_update_dyn_channels();
-				break;
-			case "su_schedule-remove-data":
-				su_schedule_remove_data();
-				break;
-			case "su_message-button-click":
-				su_handle_message_button_click(subject);
-				break;
-		}
-	}
-}
-
-function su_verify_cookie_perms(notify_upon_modify)
-{
-	if (! su_ds.isPrefDefined("network.cookie.cookieBehavior") || !su_ds.getValue("@auto_cookie_exceptions"))
-		return;
-	
-	var supr_domain = su_ds.getValue("@supr_domain");
-	var domains = new Array(su_servername, "video." + su_servername, supr_domain);
-	
-	var perm_man = su_get_service(
-				"@mozilla.org/permissionmanager;1",
-				"nsIPermissionManager");
-	
-	var modified = false;
-	if (su_ds.getValue("network.cookie.cookieBehavior") != 0)
-	{
-		modified = true;
-		var i;
-		for (i = 0; i < domains.length; i++)
-		{
-			var nsiuri = su_get_nsiuri(domains[i]);
-			perm_man.add(nsiuri, "cookie", perm_man.ALLOW_ACTION);
-		}
-	}
-	
-	if (modified && notify_upon_modify)
-	{
-		setTimeout(su_alert_cookie_change, 100);
-	}
-}
-
-function su_alert_cookie_change()
-{
-	var ps = su_get_service(
-				"@mozilla.org/embedcomp/prompt-service;1",
-				"nsIPromptService");
-	
-	ps.alert(window,
-				"StumbleUpon",
-				"Exceptions to allow StumbleUpon cookies have been added.\n\n" + 
-				"This is required for the StumbleUpon toolbar to be fully functional.\n\n");
-}
-
-function su_gui_render()
-{
-	var test_ids = [
-				"su_render",
-				"su_overflow_popup",
-				"su_stumble_topic",
-				"su_page_feature_prompt",
-				"su_messages",
-				"firstrater",
-				"su_searchbox",
-				"su_category",
-				"su_referral_menu",
-				"su_website_info",
-				"su_thumbdown",
-				"su_thumbup",
-//				"su_inbox-count",
-				"su_referred",
-				"su_stumble",
-				"su_splitter_first_flexbox",
-				"su_spacer"];
-				
-	// keep trying until we find the gui
-	var i;
-	for (i = 0; i < test_ids.length; i++)
-	{
-		if (! su_get_element(test_ids[i]))
-		{
-			setTimeout("su_gui_render()", 100);
-			return;
-		}
-	}
-
-	
-//	if ((su_get_element("su_render") == null) ||
-//				(su_get_element("su_category") == null))
-//	{
-//		setTimeout("su_gui_render()", 100);
-//		return;
-//	}
-	
-	su_set_visible("su_bug", su_enable_message_log);
-	
-	// These configure toolbars correctly when opening a new browser
-	// window after changing toolbar elements but before persisting.
-	// There may be a better way to handle this, by figuring out how
-	// to persist without breaking urlbar; for now it works. -- JW
-//	try {
-//		su_prevent_toolbar_sharing();
-//	} catch (e) { su_log_error("INIT SHARING", e); }
-	try {
-		su_refresh_toggle_button(true);
-	} catch (e) { su_log_error("INIT TOGGLE", e); }
-	
-	// Netscape 8.0.x needs a separator to push the stumble button past
-	// the NS logo.
-	if (su_host.netscape && (su_host.version.indexOf("8.0") != -1))
-		su_get_element("su_spacer").collapsed = false;
-
-	try {
-		su_verify_cookie_perms(su_new_install);
-	} catch (e) { su_log_error("ALLOW COOKIES", e); }
-
-	if (su_new_install)
-	{
-		var loc = "firefox_start.php";
-		if (su_host.dist)
-			loc = "campus_start.php";
-		
-		su_set_server_location(loc, null, true);
-
-		try {
-			// block popups from external applications ( a major new source of unwanted popups )
-			// Only do this once, in case they have a reason to set it back
-			su_ds.setValue("privacy.popups.disable_from_plugins", 2);
-			
-		} catch (e) { su_log_error("PREPARE BROWSER", e); }
-	}
-	else if (su_new_upgrade && (su_private_label.indexOf("ALPHA") != 0) && 
-				(su_private_label.indexOf("BETA") != 0))
-	{
-		su_new_upgrade = false;
-	}
-	
-	su_new_install = false;
-	su_dist_time();
-	
-	var installed = su_ds.getIntValue("@installed");
-	var now_s = su_get_time_s();
-//	if ((now_s - installed) > (3600 * 24))
-//		su_promo_mode = true;
-
-	if (stumbleid == 0)
-	{
-		su_move_toolbar(true, 2);
-		su_configure_toolbar(false);
-		su_check_progress_listener();
-	}
-	else
-	{
-		su_show_searchlinks_dialog(false, false, false);
-		su_load_data2(false);  // calls configure_toolbar()
-	}
-	
-	if (window.onViewToolbarsPopupShowing)
-	{
-		// This is a bit tricky.  Basically, we're replacing a browser-
-		// defined function with our own function.  For details, see the
-		// comments in function 
-		// su_replacement_onViewToolbarsPopupShowing.
-		window.su_saved_onViewToolbarsPopupShowing = window.onViewToolbarsPopupShowing;
-		window.onViewToolbarsPopupShowing = window.su_replacement_onViewToolbarsPopupShowing;
-	}
-	
-	if (window.BrowserCustomizeToolbar)
-	{
-		// This is a bit tricky.  Basically, we're replacing a browser-
-		// defined function with our own function.  For details, see the
-		// comments in function 
-		// su_replacement_onViewToolbarsPopupShowing.
-		window.su_saved_BrowserCustomizeToolbar = window.BrowserCustomizeToolbar;
-		window.BrowserCustomizeToolbar = window.su_replacement_BrowserCustomizeToolbar;
-	}
-
-	if (window.BrowserToolboxCustomizeDone)
-	{
-		// This hack is similar to the one above.  See function
-		// su_replacement_BrowserToolboxCustomizeDone.
-		window.su_saved_BrowserToolboxCustomizeDone = window.BrowserToolboxCustomizeDone;
-		var toolbox = document.getElementById("navigator-toolbox");
-		toolbox.customizeDone = window.su_replacement_BrowserToolboxCustomizeDone;
-	}
-	
-	if (window.foxytunesSetFoxyTunesPosition)
-	{
-		window.su_saved_foxytunesSetFoxyTunesPosition = window.foxytunesSetFoxyTunesPosition;
-		window.foxytunesSetFoxyTunesPosition = window.su_replacement_foxytunesSetFoxyTunesPosition;
-	}	
-	
-	window.addEventListener("resize", su_handle_window_resize, false);
-	window.addEventListener("focus", su_handle_window_focus, true);
-	
-	// for instances where we still need a load listener (such as interests_after.php)
-	window.addEventListener("DOMContentLoaded", su_on_load_page, true);
-
-	getBrowser().addEventListener("click", su_handle_content_click, false);
-	
-//	We may have to do this if onLocationChange stops working.
-//	if (su_host.ff2plus)
-//		getBrowser().tabContainer.addEventListener("TabSelect", su_handle_tabselect, false);
-	
-	su_gui_initialized = true;
-	su_ds.prefRetries = 15;
-	setTimeout("su_reflow_toolbar(3);", 0);
-	setTimeout("su_reflow_toolbar(3);", 500);
-	setTimeout("su_cleanup_toolbox(true, false)", 550);
-	setInterval("su_process_quarter_hourly()", 15 * 60 * 1000);
-}
-
-//	We may have to do this if onLocationChange stops working.
-//function su_handle_tabselect(event)
-//{
-//  su_refresh_pagemeta(false, 11);
-//}
-
-function su_photoBlogContext() 
-{
-	if (gContextMenu) 
-	{
-		menuitem = su_get_element('context-photoblog-ilikeit');
-
-		if (menuitem)
-		{
-			menuitem.hidden = !gContextMenu.onImage;
-			//alert("photo " + !gContextMenu.onImage);
-			
-		}
-		// menuitem = su_get_element('context-photoblog-notforme');
-		// if(menuitem)
-		// 	menuitem.hidden = !gContextMenu.onImage;
-		
-		// look for selected text
-		var selectedText = su_getSelectedText(" ");
-//		alert("?" + selectedText);
-
-		if (selectedText != "")
-		{
-			// tag button	
-			//!!! only do this if size isn't greater than maximum tag size...
-			menuitem = su_get_element('context-stumble-tagit');
-			menuitem.hidden = false;
-			var selectedText2 = selectedText;
-			if (selectedText2.length > 15)
-				selectedText2 = selectedText.substring(0, 15) + "...";	
-			menuitem.label = "Tag this page as '" + selectedText2 + "'";
-			menuitem.setAttribute("class", "menuitem-iconic");
-			menuitem.setAttribute("image", "chrome://stumbleupon/content/skin/tag.png");		
-			
-			// search
-			//!!! only do this if absolute enable_search == yes
-			
-			//!!! We've stopped prompting for enable_search, so we'll leave
-			// it as is for now.
-			
-			menuitem = su_get_element('context-stumble-search');
-			menuitem.hidden = false;
-			selectedText2 = selectedText;
-			if (selectedText2.length > 15)
-				selectedText2 = selectedText.substring(0, 15) + "...";	
-			menuitem.label = "StumbleThru '" + selectedText2 + "'";
-			menuitem.setAttribute("class", "menuitem-iconic");
-			menuitem.setAttribute("image", "chrome://stumbleupon/content/skin/stumble.png");
-		}
-		else
-		{
-			menuitem = su_get_element('context-stumble-tagit');
-			menuitem.hidden = true;
-			
-			menuitem = su_get_element('context-stumble-search');
-			menuitem.hidden = true;
-		}	     
-	}
-}
-
-function su_contextTag()
-{
-	var current_url = su_get_browser_url();
-	var selectedText = su_getSelectedText(" ");
-	su_get_element("su_searchbox").value = selectedText;
-	su_tagit(current_url, selectedText, 0, su_get_title(), su_get_browser_url(null, true));
-}
-
-function su_contextSearch(event)
-{
-	var selectedText = su_getSelectedText(" ");
-	su_old_search = selectedText;
-	su_visited_searchbox = 1;
-	
-	su_get_element('su_searchbox').removeAttribute("mode");
-
-	if (su_url_has_tag)
-	{	
-		su_url_has_tag = false;
-		su_get_element('su_searchbox').value = '';
-		su_get_element('su_searchbox').removeAttribute("mode");
-
-		su_get_element("su_tag").image="chrome://stumbleupon/content/skin/tag.png";
-		su_get_element('su_tag').setAttribute("tooltiptext", su_get_element('su_tag').getAttribute("tooltiptext2"));
-		su_get_element("su_tag2").image="chrome://stumbleupon/content/skin/tag.png";
-		su_get_element('su_tag2').setAttribute("tooltiptext", su_get_element('su_tag2').getAttribute("tooltiptext2"));
-	}
-	
-	var searchbox = su_get_element("su_searchbox");
-	searchbox.value = selectedText;
-	if (! (searchbox.hasAttribute("focused") && 
-				(searchbox.getAttribute("focused") == "true")))
-	{
-		searchbox.focus();
-	}
-	
-	var new_tab = su_new_tab(event);
-	new_tab = new_tab || su_ds.getValue("$search_new_window");
-	su_stumble_in_tag(selectedText, new_tab);	
-}
-
-function su_getSelectedText(concationationChar)
-{
-	var node = document.popupNode;
-	var selection = "";
-
-	if ((node instanceof HTMLTextAreaElement) || (node instanceof HTMLInputElement && node.type == "text"))
-	{
-		selection = node.value.substring(node.selectionStart, node.selectionEnd);
-	} 
-	else {
-		var focusedWindow = new XPCNativeWrapper(document.commandDispatcher.focusedWindow, 'document', 'getSelection()');
-		selection = focusedWindow.getSelection().toString();
-	}
-
-	// Limit length to 150 to optimize performance. Longer does not make sense
-	if (selection.length>=150)
-		selection = selection.substring(0, 149);
-
-	selection = selection.replace(/(\n|\r|\t)+/g, " ");
-	// Strip spaces at start and end.
-	selection = selection.replace(/(^\s+)|(\s+$)/g, "");
-
-	selection = selection.split(" ");
- 
-	// Remove certain characters at the beginning and end of every word
-	for (i=0; i<selection.length; i++)
-	{
-		selection[i]=selection[i].replace(/^(\&|\(|\)|\[|\]|\{|\}|"|,|\.|!|\?|'|:|;)+/, "");
-		selection[i]=selection[i].replace(/(\&|\(|\)|\[|\]|\{|\}|"|,|\.|!|\?|'|:|;)+$/, "");
-	}   
-	selection = selection.join(concationationChar);   
-	return selection; 
-}
-
-function su_show_banner(prompt, icon, accept_callback, decline_callback)
-{
-	var box = getBrowser().getNotificationBox();
-	var notification = box.getNotificationWithValue("su_message");
-	if (notification)
-		return;
-	
-	var buttons = new Array();
-	
-	buttons.push({
-				label: "Join StumbleUpon Now",
-				accessKey: "J",
-				popup: null,
-				callback: accept_callback});
-	
-	buttons.push({
-				label: "No thanks",
-				accessKey: "N",
-				popup: null,
-				callback: decline_callback});
-	
-	buttons.push({
-				label: "Later",
-				accessKey: "L",
-				popup: null,
-				callback: function(){}});
-	
-	const priority = box.PRIORITY_WARNING_MEDIUM;
-	
-	box.appendNotification(
-				prompt,
-				"su_prompt",
-				icon,
-				priority,
-				buttons);
-}
-
-function su_handle_prompt_click(prompt, button_name, detail)
-{
-	if (button_name == "accept")
-	{
-		su_verify_cookie_perms(false);
-		var params = "";
-		var loc = "sign_up.php"; 
-		params = su_arp(params, "version", su_useragent);
-		
-		if (su_host.dist)
-			loc = su_arp(loc, "dist", su_host.dist, true);
-		
-		if (su_ds.getValue("@facebook_user"))
-			loc = su_arp(loc, "pre", "facebook", true);
-		
-		loc = su_arp(loc, "pre2", prompt, true);
-		
-		params = su_arp(params, "post_url", detail.post_url);
-
-		su_set_server_location(
-					loc,
-					params,
-					detail.new_tab);
-	}
-	else if ((button_name == "decline") && (prompt == "prompt1"))
-	{
-		su_ds.setValue("@enable_prompt1", false);
-	}
-	else if ((button_name == "decline") && (prompt == "prompt2"))
-	{
-		su_ds.setValue("@enable_prompt2", false);
-	}
-}
-
-
-// handles the window load event
-function su_handle_window_load()
-{
-	if (! su_login_initialized)
-	{
-		setTimeout(su_handle_window_load, 1000);
-		return;
-	}
-
-	if (stumbleid != 0)
-	{
-		if ((su_get_browser_window_count() == 1) && su_ds.getValue("$autologout"))
-			su_logout_auth();
-		else
-			su_load_data1(false);
-	}
-
-	// we need to wait until the gui is rendered before we do most things
-	setTimeout("su_gui_render()", 100);
-
-	// Initialize photoblog context menu
-	var menu = su_get_element("contentAreaContextMenu");
-	menu.addEventListener("popupshowing", su_photoBlogContext, false); 
-}
-
-// handles the window unload event
-function su_handle_window_unload()
-{
-	try {
-	// To avoid a memory leak, this block needs to run per XUL window.
-	// -- JW
-	var observer_service = su_get_service(
-				"@mozilla.org/observer-service;1",
-				"nsIObserverService");
-
-	observer_service.removeObserver(su_http_observer, "http-on-modify-request");
-	observer_service.removeObserver(su_http_observer, "http-on-examine-response");
-	observer_service.removeObserver(su_host_observer, "em-action-requested");
-	observer_service.removeObserver(su_event_observer, "su_login");
-	observer_service.removeObserver(su_event_observer, "su_logout");
-	observer_service.removeObserver(su_event_observer, "su_change-password");
-	observer_service.removeObserver(su_event_observer, "su_configure-toolbar");
-	observer_service.removeObserver(su_event_observer, "su_referral-menu-dirty");
-	observer_service.removeObserver(su_event_observer, "su_update-referral-menu");
-	observer_service.removeObserver(su_event_observer, "su_dyn-channels-dirty");
-	observer_service.removeObserver(su_event_observer, "su_update-dyn-channels");
-	observer_service.removeObserver(su_event_observer, "su_refresh-category-selector");
-	observer_service.removeObserver(su_event_observer, "su_schedule-remove-data");
-	observer_service.removeObserver(su_event_observer, "su_message-button-click");
-
-	var processed_ids = new Object();
-	while (su_persist_queue.length)
-	{
-		// Doing document.persist can break the urlbar, so we do it upon
-		// window close (ref: Firefox 2RC1). -- JW
-		var id = su_persist_queue.pop();
-		if (processed_ids[id])
-			continue;
-		
-		processed_ids[id] = true;
-
-		document.persist(id, "currentset");
-	}
-	
-	if (su_get_browser_window_count() == 0)
-		su_handle_last_browser_window_unload()
-	
-	} catch (e) {}
-}
-
-function su_handle_last_browser_window_unload()
-{
-	var i;
-	if (su_ds.getValue("@clear_favicons"))
-	{
-		su_ds.setValue("@clear_favicons", false);
-		var channels = su_ds.getThruDomainChannels(false);
-		
-		if (channels)
-		{
-			for (i = 0; i < channels.length; i++)
-			{
-				su_ds.deleteResource(
-							"favicons",
-							su_get_channel_id(channels[i].domain) + ".ico");
-			}
-		}
-	}
-
-	if (su_is_uninstall_scheduled())
-	{
-		su_remove_searchplugin();
-	}
-	else if(!su_remove_data_scheduled)
-	{
-		var ids = su_ds.getValue("@id_list").split(":");
-
-		for (i = 0; i < ids.length; i++)
-		{
-			if (ids[i] == "")
-				continue;
-			
-			stumbleid = ids[i];
-			
-			if (su_ds.getUserPrefValue(ids[i], "$search_clear_queries"))
-			{
-				// If they've elected to clear queries, remove them.
-				su_queries = new Array();
-				su_store_queries();
-			}
-		}
-		if (su_preference_dialog)
-			su_preference_dialog.cancelDialog();
-
-		if ((stumbleid != 0) &&	su_ds.getValue("$autologout"))
-			su_logout();
-		
-		su_ds.flushPrefs();
-	}
-	
-	if (su_remove_data_scheduled)
-		su_remove_data();
-}
-
-// used by the window unload listener to determine whether the 
-// extension has been scheduled to be uninstalled
-function su_is_uninstall_scheduled()
-{
-	var root;
-	if (su_uninstall_scheduled)
-	{
-		// In Firefox 1.5+, we use the su_uninstall_observer to detect a
-		// scheduled uninstallation. -- JW
-		return true;
-	}
-	else
-	{
-		try {
-			root = su_get_rdf_resource("urn:mozilla:extension:root");
-		}
-		catch (e) {
-			// This datasource has been renamed in Firefox 1.5+ and no
-			// longer features the toBeUninstalled arcs. -- JW
-			return false;
-		}
-	}
-	
-	// [kudos:] This is derived from the FirefoxView extension by Alex
-	// Sirota. -- JW
-	var container = su_get_service(
-				"@mozilla.org/rdf/container;1",
-				"nsIRDFContainer");
-	var extension_ds = su_get_service(
-				"@mozilla.org/extensions/manager;1",
-				"nsIExtensionManager")
-				.datasource;
-
-	try {
-		container.Init(extension_ds, root);
-	}
-	catch (e) {
-		return false;
-	}
-
-	var found = false;
-	var elements = container.GetElements();
-	while (elements.hasMoreElements())
-	{
-		var element = elements.getNext();
-
-		var name = su_get_rdf_arc_literal(
-					extension_ds,
-					element,
-					"http://www.mozilla.org/2004/em-rdf#name"); 
-
-		var to_be_uninstalled = su_get_rdf_arc_literal(
-					extension_ds,
-					element,
-					"http://www.mozilla.org/2004/em-rdf#toBeUninstalled");
-
-		if ((to_be_uninstalled == "true") && (name == "StumbleUpon"))
-			found = true;
-	} 
-	return found;
-}
-
-// if the extension is scheduled to be uninstalled, the window unload
-// listener calls this routine to uninstall the search plugin
-function su_remove_searchplugin()
-{
-	// [kudos:] This is derived from the SearchPluginHacks extension by
-	// Alex Sirota. -- JW
-
-	var i;
-	var searchbar = su_get_element('searchbar');
-	
-	if (! searchbar)
-		return;
-
-	var searchbar_popup = document.getAnonymousElementByAttribute(
-				searchbar,
-				'anonid',
-				'searchbar-popup');
-	var menuitems = searchbar_popup.getElementsByTagName("menuitem");
-	
-	var menuitem = null;
-	
-	for (i = 0; i < menuitems.length; i++)
-	{
-		if (menuitems[i].label == "StumbleUpon")
-		{
-			menuitem = menuitems[i];
-			break;
-		}
-	}
-	
-	if (! menuitem)
-		return;
-
-	var plugin_uri = unescape(menuitem.value);
-	var plugin_path;
-	if (plugin_uri.indexOf("engine://") == 0)
-		plugin_path = plugin_uri.substr(9);
-	else
-		su_log_error("SEARCHPLUGIN URI FORMAT ERROR", plugin_uri);
-
-	var image_uri = unescape(menuitem.getAttribute('src'));
-	var image_path;
-	if (image_uri.indexOf("file:///") == 0)
-	{
-		var handler = su_create_instance(
-					"@mozilla.org/network/protocol;1?name=file",
-					"nsIFileProtocolHandler");
-		image_path = handler.getFileFromURLSpec(image_uri).path;
-	}
-	else
-	{
-		su_log_error("SEARCHPLUGIN IMAGE URI FORMAT ERROR", image_uri);
-	}
-
-	try {
-		su_ds.deleteFile(su_ds.getFileFromPath(plugin_path));
-		su_ds.deleteFile(su_ds.getFileFromPath(image_path));
-	} catch (e) {}
-
-	try {
-		if (typeof(searchbar_popup.hidePopup) == "function")
-			searchbar_popup.hidePopup();
-		menuitem.parentNode.removeChild(menuitem);
-	} catch (e) {}
-}
-
-// handles the window click event
-function su_handle_window_mousedown(event)
-{
-	if (! su_has_searchbox)
-		return true;
-	//	su_recent_platform_ctrl_key_state = (su_host.mac) ? event.metaKey : event.ctrlKey;
-
-	if (! event.target.id)
-		return;
-	
-	switch (event.target.id)
-	{
-		case "su_searchbox":
-			su_keep_searchbox_focus = true;
-			break;
-		case "su_stumble":
-		case "su_category":
-		case "su_thumbup":
-		case "su_thumbdown":
-		case "su_website_info":
-		case "su_tag":
-		case "su_tag2":
-			break;
-		default:
-			su_keep_searchbox_focus = false;
-			break;
-	}
-	return true;
-}
-
-// handles the window focus event
-function su_handle_window_focus(event)
-{
-	if (! su_has_searchbox)
-		return true;
-
-	if (su_keep_searchbox_focus && event.target.location && 
-				(event.target.location.href == "chrome://browser/content/browser.xul"))
-	{
-		setTimeout(su_restore_searchbox_focus, 100);
-	}
-	else if (su_keep_searchbox_focus && event.target.id && 
-				(event.target.id == "content"))
-	{
-		setTimeout(su_restore_searchbox_focus, 100);
-	}
-}
-
-// restores the searchbox
-function su_restore_searchbox_focus()
-{
-	if (su_keep_searchbox_focus)
-	{
-		var searchbox = su_get_element("su_searchbox");
-		if (! (searchbox.hasAttribute("focused") && (searchbox.getAttribute("focused") == "true")))
-			searchbox.focus();
-	}
-}
-
-// handles the window keypress event; see also handle_window_keyup
-function su_handle_window_keypress(event)
-{
-//	su_recent_platform_ctrl_key_state = (su_host.mac) ? event.metaKey : event.ctrlKey;
-	
-  var str = "";
-
-	if (event.altKey)   str += "Alt+";
-	if (event.ctrlKey)  str += "Ctrl+";
-	if (event.metaKey)  str += "Command+";
-	if (event.shiftKey) str += "Shift+";
-
-	su_recent_keypress_modifiers = str;
-
-	return true;
-}
-
-// handles the window keyup event using commands defined by 
-// refresh_keybindings(); note that we need both a keypress listener
-// and a keyup listener because the former gives us modifiers and the
-// latter gives us keyCodes that distinquish between the numeric
-// keypad w/ numlock on and the number row
-function su_handle_window_keyup(event)
-{
-	var keyid;
-	if (event.charCode)
-		keyid = su_keyids_by_eventkeycode[event.charCode];
-	else
-	  	keyid = su_keyids_by_eventkeycode[event.keyCode];
-
-	var keyspec = su_recent_keypress_modifiers + keyid;
-	
-	if (su_commands_by_keyspec[keyspec])
-		su_commands_by_keyspec[keyspec].doCommand();
-
-	return true;
-}
-
-function su_move_to_bookmark_bar()
-{
-	su_ds.setValue("@toolbar-position", "PersonalToolbar");
-	su_ds.setValue("@position-group", "first");
-	
-	su_move_toolbar(true, 9);
-}
-
-// called by the global configure-toolbar event and during init to
-// move the top-level toolbar elements
-function su_move_toolbar(force, from)
-{
-	var toolbar_position = su_ds.getValue("@toolbar-position");
-	var position_group = su_ds.getValue("@position-group");
-	var toolbar = su_get_element(toolbar_position);
-	var toolbaritem;
-	var new_parent;
-	var popup;
-	if (! toolbar)
-	{
-		toolbar_position = "stumbleupon";
-		position_group = "first";
-		su_ds.setValue("@toolbar-position", toolbar_position);
-		su_ds.setValue("@position-group", position_group);
-		toolbar = su_get_element(toolbar_position);
-		su_ds.flushPrefs();
-	}
-	
-	if (force && (toolbar.tagName == "toolbar") && 
-				window.BrowserCustomizeToolbar && 
-				((position_group == "first") || (position_group == "last")))
-	{
-		var splitter = su_get_element("su_right-justify-splitter");
-		if (splitter)
-			splitter.collapsed = true;
-	
-		// If we don't hide the popup, the menu gets munged if we move the
-		// toolbar somewhere else.
-		popup = su_get_element("su_stumble_popup");
-		if (typeof(popup.hidePopup) == "function")
-			popup.hidePopup();
-		if (su_overflow_popup_open)
-		{
-			popup = su_get_element("su_overflow_popup"); 
-			if (typeof(popup.hidePopup) == "function")
-				popup.hidePopup();
-		}
-		new_parent = su_get_element("su_container");
-		new_parent.hidden = true;
-//		su_dp("moving to hbox");
-		su_move_toolbar_elements(new_parent, null, 1);
-		
-		var toolbars = document.getElementsByTagName("toolbar");
-		var target_index = -1;
-		var prev_index = -1;
-		var i;
-
-		// First, find the toolbar locations
-		for (i = 0; i < toolbars.length; i++)
-		{
-			if(su_is_item_in_toolbox(false, "su_toolbaritem", toolbars[i]))
-			{
-				prev_index = i;
-				if(target_index != -1) break;
-			}
-
-			if (! toolbars[i].hasAttribute("customizable"))
-				continue;
-			
-			if (toolbars[i].getAttribute("customizable").toLowerCase() != "true")
-				continue;
-
-			if (toolbars[i].id == toolbar_position)
-			{
-				target_index = i;
-				if(prev_index != -1) break;
-			}
-		}
-
-		if(target_index != -1)
-		{
-			// Add it to the new
-			su_place_toolbaritem(toolbars[target_index], position_group);
-			// Remove it from the old
-			if(target_index != prev_index)
-			{
-				try {
-					su_is_item_in_toolbox(true, "su_toolbaritem", toolbars[prev_index]);
-				} catch (e) {};
-			}
-		}
-		
-		if((target_index == -1)  && (toolbar_position != "status-bar"))
-		{
-			// If we didn't find a valid (customizable) toolbar parent, then force our
-			// toolbar to the default location.
-			toolbar_position = "stumbleupon";
-			position_group = "first";
-			su_ds.setValue("@toolbar-position", toolbar_position);
-			su_ds.setValue("@position-group", position_group);
-			toolbar = su_get_element(toolbar_position);
-			su_place_toolbaritem(toolbar, position_group);
-			su_ds.flushPrefs();
-		}
-	}
-
-	toolbaritem = su_get_element("su_toolbaritem");
-	
-	var drop = false;
-	var new_bar;
-	if ((toolbar_position == "status-bar") || 
-				(toolbar_position == "yahoo-toolbar"))
-	{
-		new_parent = su_get_element(toolbar_position);
-		new_bar = new_parent;
-	}
-	else if (toolbaritem)
-	{
-		new_bar = toolbaritem.parentNode;
-		var drop = true;
-		if (su_is_element_on_bar(false, "gtbToolbar", "su_toolbaritem"))
-		{
-			toolbar_position = "gtbToolbar";
-			new_parent = su_get_element("gtbToolbar");
-//			su_dp("toolbaritem is on gtbToolbar", new_parent.id);
-			position_group = "first";
-			
-			if (toolbaritem.hasAttribute("flex"))
-				toolbaritem.removeAttribute("flex");
-			
-			toolbaritem.setAttribute("width", 0);
-			su_ds.setValue("@toolbar-position", toolbar_position);
-		}
-		else
-		{
-			new_parent = su_get_element("su_toolbar_container");
-			try {
-				position_group = "drop";
-				toolbar_position = su_get_parent_toolbar_id(new_parent);
-			}
-			catch (e) {
-				//!!! This is a failsafe case that gets hit by some seamonkey
-				//    1.1 and Firefox 2.0.0.2 users.
-				if ((toolbar_position == "stumbleupon") && (position_group == "first"))
-					su_log_error("MOVE ERROR1", e);
-				else
-					su_log_error("MOVE FAILSAFE1", e, toolbar_position, position_group);
-				toolbar_position = "stumbleupon";
-				position_group = "first";
-				new_parent = su_get_element("su_container");
-				new_bar = new_parent.parentNode;
-				new_parent.hidden = false;
-			}
-			su_ds.setValue("@toolbar-position", toolbar_position);
-			su_ds.setValue("@position-group", position_group);
-		}
-	}
-	else if (toolbar_position == "stumbleupon")
-	{
-		new_parent = su_get_element("su_container");
-		position_group = "first";
-		su_ds.setValue("@toolbar-position", toolbar_position);
-		su_ds.setValue("@position-group", position_group);
-		new_bar = new_parent.parentNode;
-		new_parent.hidden = false;
-	}
-	else
-	{
-//		su_dp("no toolbaritem");
-		new_parent = su_get_element(toolbar_position);
-		new_bar = new_parent;
-	}
-
-	// If the selected toolbar is missing, use the default location.
-	if (! new_parent)
-	{
-//		su_dp("no new parent");
-		toolbar_position = "stumbleupon";
-		position_group = "first";
-		su_ds.setValue("@toolbar-position", toolbar_position);
-		su_ds.setValue("@position-group", position_group);
-		new_parent = su_get_element("su_container");
-		new_bar = new_parent.parentNode;
-		force = true;
-	}
-
-	// if force, then make sure the toolbar they are moving to is not hidden
-	if (force)
-	{
-		new_bar.hidden = false;
-		new_bar.collapsed = false;
-	}
-
-	var hidden_state = ! su_ds.getValue("@toolbar-visible");
-
-	if (toolbar_position == "stumbleupon")
-	{
-		su_get_element("stumbleupon").collapsed = hidden_state;
-	}
-	else
-	{
-		su_get_element("stumbleupon").collapsed = true;
-		if (hidden_state)
-		{
-//			su_dp("hidden");
-			// To hide the toolbar elements, we move them to the collapsed
-			// toolbar. -- JW
-			if (toolbaritem)
-			{
-				if (toolbaritem.hasAttribute("flex"))
-					toolbaritem.removeAttribute("flex");
-				
-				toolbaritem.setAttribute("width", 0);
-			}
-			toolbar_position = "stumbleupon";
-			new_parent = su_get_element("su_container");
-		}
-	}
-	
-	var old_parent = su_get_element("su_splitter_first_flexbox").parentNode;
-	
-	
-	if ((toolbar_position == su_old_toolbar_position) && 
-				(position_group == su_old_toolbar_position_group) &&
-				(old_parent.id != "su_container"))
-	{
-		setTimeout(
-					function (win) {
-						win.su_cleanup_toolbox(true, false); },
-					0,
-					window);
-	
-		su_init_splitters();
-		return;
-	}
-
-/*	
-	if (toolbaritem)
-	{
-		if (toolbaritem.hasAttribute("width"))
-			toolbaritem.removeAttribute("width");
-		
-		if (! toolbaritem.hasAttribute("flex"))
-			toolbaritem.setAttribute("flex", 1);
-	}
-*/
-
-	su_bookmarks_sibling_loc = null;
-	su_old_toolbar_position = toolbar_position;
-	su_old_toolbar_position_group = position_group;
-	
-	su_moving_toolbar = true;
-	
-
-	// If we don't hide the popup, the menu gets munged if we move the
-	// toolbar somewhere else.
-	popup = su_get_element("su_stumble_popup");
-	if (typeof(popup.hidePopup) == "function")
-		popup.hidePopup();
-	if (su_overflow_popup_open)
-	{
-		popup = su_get_element("su_overflow_popup"); 
-		if (typeof(popup.hidePopup) == "function")
-			popup.hidePopup();
-	}
-
-	if (toolbar_position == "stumbleupon")
-	{
-		su_toolbar_justification = "left";
-//		su_dp("id", su_get_parent_toolbar_id(new_parent));
-		su_move_toolbar_elements(new_parent, null, 2);
-		
-		// The following contains workarounds to fix the bug where the
-		// toolbar appears 150px tall in old browsers (ref: Netscape 7.2,
-		// XP and Firefox 1.0RC1, XP) -- JW
-		if (new_parent.parentNode.boxObject.height > 100)
-		{
-			su_get_element("su_field").style.height = "32px";
-			new_parent.style.height = "32px";
-			new_parent.parentNode.style.height = "32px";
-		}
-		new_parent.hidden = false;
-	}
-	else if (toolbar_position == "gtbToolbar")
-	{
-//		su_dp("moving toolbar to gtbToolbar", new_parent.id);
-		su_toolbar_justification = "left";
-		hbox = document.createElement("hbox");
-		hbox.setAttribute("id", "su_googlebar_container");
-		new_parent.insertBefore(hbox, new_parent.firstChild);
-		hbox.__defineSetter__("collapsed", function() {});
-		new_parent = hbox;
-		su_move_toolbar_elements(new_parent, null, 3);
-	}
-	else if ((position_group == "last") || (position_group == "drop"))
-	{
-		var sibling;
-		if (position_group == "drop")
-		{
-//			su_dp("survey");
-			try {
-				su_survey_toolbar_siblings(toolbaritem);
-				sibling = toolbaritem.previousSibling;
-			}
-			catch (e) {
-				if ((toolbar_position == "stumbleupon") && (position_group == "first"))
-					su_log_error("MOVE ERROR2", e);
-				else
-					su_log_error("MOVE FAILSAFE2", e, toolbar_position, position_group);
-				su_ds.setValue("@toolbar-position", "stumbleupon");
-				su_ds.setValue("@position-group", "first");
-				su_ds.setValue("@toolbar-visible", true);
-			}	
-		}
-		else
-		{
-			sibling = new_parent.lastChild;
-		}
-		
-		if ((toolbar_position == "PersonalToolbar") && 
-					(position_group == "last"))
-			su_toolbar_justification = "right";
-		else
-			su_toolbar_justification = (su_test_previous_sibling_flexibility(sibling)) ? "right" : "left";
-		
-//		su_dp("justification", su_toolbar_justification);
-		if (su_toolbar_justification == "left")
-		{
-			if (old_parent.id != "su_toolbar_container")
-				su_move_toolbar_elements(new_parent, null, 4);
-		}
-		else if (su_toolbar_justification == "right")
-		{
-			if ((old_parent.id == "su_toolbar_container") && 
-						(su_ds.getValue("@toolbar-position") != "status-bar"))
-			{
-				if ((old_parent.parentNode.id != new_parent.id) && 
-							(position_group == "last"))
-					new_parent.appendChild(old_parent);
-			}
-			else
-			{
-				if (position_group == "last")
-				{
-					var hbox;
-					if (su_ds.getValue("@toolbar-position") == "status-bar")
-						hbox = su_get_element("su_statusbar_container");
-					else
-						hbox = su_get_element("su_otherbar_container");
-					
-					if (! hbox)
-					{
-						hbox = document.createElement("hbox")
-						if (su_ds.getValue("@toolbar-position") == "status-bar")
-							hbox.setAttribute("id", "su_statusbar_container");
-						else
-							hbox.setAttribute("id", "su_otherbar_container");
-						hbox.setAttribute("flex", "1");
-					
-						new_parent.appendChild(hbox);
-					}
-					new_parent = hbox;
-				}
-				su_move_toolbar_elements(new_parent, null, 5);
-				
-				var outer_container = su_get_toolbar_outer_container();
-				var width = outer_container.boxObject.width;
-				width = su_ds.getPrefValue("@right-justify-width", width);
-				outer_container.setAttribute("width", width + "px");
-				if (outer_container.hasAttribute("flex"))
-					outer_container.removeAttribute("flex");
-				
-				if (su_bookmarks_sibling_loc)
-					setTimeout(su_move_toolbar_bookmarks, 1000, new_parent);
-			}
-		}
-	}
-	else
-	{
-		su_toolbar_justification = "left";
-		su_move_toolbar_elements(new_parent, new_parent.firstChild, 6);
-	}
-	
-	su_moving_toolbar = false;
-
-	// change state of mozilla suite menuitem
-	var menuitem = su_get_element("view_stumble_menuitem");
-	if (menuitem)
-	{
-		if (hidden_state)
-			menuitem.removeAttribute("checked");
-		else
-			menuitem.setAttribute("checked", "true");
-	}
-
-	setTimeout(
-				function (win) {
-					win.su_cleanup_toolbox(true, false); },
-				0,
-				window);
-
-	su_init_splitters();
-}
-
-function su_verify_toolbar_move(from)
-{
-	if (su_get_element("su_stumble"))
-		return;
-	
-	// If we can't find the stumble button, recover upon browser
-	// restart.
-	su_log_error(
-				"MOVE FAILSAFE4",
-				new Object(),
-				from,
-				su_ds.getValue("@toolbar-position"),
-				su_ds.getValue("@position-group"));
-	
-	su_ds.setValue("@toolbar-position", "stumbleupon");
-	su_ds.setValue("@position-group", "first");
-	
-	if (from == 5)
-	{
-		setTimeout(alert, 50, 
-				"StumbleUpon cannot accommodate this new configuration.\n\n" +
-				"Please restart the browser to recover from this error.\n\n");
-	}
-	else if (from == 6)
-	{
-		setTimeout(alert, 50, 
-				"The specified toolbar movement cannot be completed.\n\n" +
-				"Please restart the browser to recover from this error.\n\n");
-	}
-}
-
-function su_place_toolbaritem(toolbar, position_group)
-{
-	var currents;
-	if ((typeof toolbar.currentSet) == "string")
-		currents = toolbar.currentSet.split(",");
-	else if (toolbar.hasAttribute("currentset"))
-		currents = toolbar.getAttribute("currentset").split(",");
-	else
-		currents = new Array();
-	
-	if (position_group == "first")
-	{
-		if ((toolbar.id == "toolbar-menubar") && 
-					(currents[0] == "menubar-items"))
-		{
-			currents.splice(1, 0, "su_toolbaritem");
-			var previous = su_get_element("menubar-items");
-			if (previous)
-			{
-				try {
-					toolbar.insertItem(
-								"su_toolbaritem",
-								previous.nextSibling,
-								null,
-								false);
-				} catch (e) { su_log("PLACE ERROR1", toolbar.id, position_group); }
-			}
-			else
-			{
-				try {
-					toolbar.insertItem(
-								"su_toolbaritem",
-								toolbar.firstChild,
-								null,
-								true);
-				} catch (e) { su_log("PLACE ERROR2", toolbar.id, position_group); }
-			}
-		}
-		else
-		{
-			currents.splice(0, 0, "su_toolbaritem");
-			try {
-				toolbar.insertItem(
-							"su_toolbaritem",
-							toolbar.firstChild,
-							null,
-							true);
-			} catch (e) { su_log("PLACE ERROR3", toolbar.id, position_group); }
-		}
-	}
-	else if (position_group == "last")
-	{
-		currents.push("su_toolbaritem");
-		
-		toolbar.insertItem(
-					"su_toolbaritem",
-					null,
-					null,
-					false);
-	}
-	
-	toolbar.setAttribute("currentset", currents.join(","));
-	su_persist_queue.push(toolbar.id);
-}
-
-function su_move_toolbar_bookmarks(container)
-{
-	var width = su_ds.getValue("@right-justify-width");
-	container.setAttribute("width", width + "px");
-	if (container.hasAttribute("flex"))
-		container.removeAttribute("flex");
-
-	setTimeout(su_reflow_toolbar, 1000, 4);
-}
-
-function su_get_parent_toolbar_id(el)
-{
-	var toolbar = su_get_parent_toolbar(el);
-	if (toolbar)
-		return toolbar.id;
-	else
-		return null;
-}
-
-function su_get_parent_toolbar(el)
-{
-	var depth = 0;
-	while ((el.tagName != "toolbar") && (el.tagName != "statusbar"))
-	{
-		depth++;
-		if (depth == 1000)
-		{
-			break;
-		}
-		
-		el = el.parentNode;
-	}
-	
-	if (depth == 1000)
-	{
-		su_log_error("PARENT FIND", ((el && el.id) ? el.id : ("no id " + (typeof el))), su_ds.getValue("@toolbar-position"), su_ds.getValue("@position-group"));
-		su_ds.setValue("@toolbar-position", "stumbleupon");
-		su_ds.setValue("@position-group", "first");
-		su_ds.setValue("@toolbar-visible", true);
-		return null;
-	}
-	return el;
-}
-
-function su_survey_toolbar_siblings(outer_container)
-{
-	su_bookmarks_sibling_loc = null;
-	if (! outer_container)
-		return;
-	var sibling = outer_container.parentNode.firstChild;
-	var seen_container = false;
-	while (sibling)
-	{
-		if (! sibling.id)
-			continue;
-		
-		if (sibling == outer_container)
-			seen_container = true;
-		if (sibling.id == "personal-bookmarks")
-		{
-			su_bookmarks_sibling_loc = (seen_container) ? "right" : "left";
-			break;
-		}
-		sibling = sibling.nextSibling;
-	}
-}
-
-// used by move_toolbar() to determine whether any previous sibling
-// of the toolbar is a flexible element; if one is, then the toolbar
-// is right-justified
-function su_test_previous_sibling_flexibility(previous_sibling)
-{
-	var sibling = previous_sibling;
-	var regexp = new RegExp("^spring\\d+$");
-	
-	var found_flexible_element = false;
-	while (sibling)
-	{
-		if (sibling.hasAttribute("flex") || (sibling.id && (sibling.id.search(regexp) == 0)))
-		{
-			found_flexible_element = true;
-			break;
-		}
-		sibling = sibling.previousSibling;
-	}
-	return found_flexible_element;
-}
-
-
-// moves the top-level toolbar elements from
-// su_splitter_first_flexbox through either su_site-box-count or
-// su_overflow_menu to a new location subsequent to argument 
-// target_next_sibling
-function su_move_toolbar_elements(target_parent, target_next_sibling, from)
-{
-	try {
-//	throw("t");
-
-	var sibling = su_get_element("su_splitter_first_flexbox");
-	var previous_sibling_id = "";
-	var old_parent = sibling.parentNode;
-//	su_dp("move elements", old_parent.id, target_parent.id, from);
-	
-	var depth = 0;
-	
-	while (previous_sibling_id != "su_overflow_menu")
-	{
-		depth++;
-		if (depth == 1000)
-		{
-			break;
-		}
-		
-		previous_sibling_id = sibling.id;
-		var element = sibling;
-		sibling = sibling.nextSibling;
-		var new_element;
-		if ((element.id == "su_stumble_menu") || (element.id =="su_category") ||
-					(element.id == "su_field") || (element.id == "su_referral_menu") ||
-					(element.id == "su_overflow_menu"))
-		{
-			new_element = element;
-		}
-		else
-		{
-			new_element = element.cloneNode(true);
-			element.parentNode.removeChild(element);
-		}
-		
-		if (target_next_sibling)
-			target_parent.insertBefore(new_element, target_next_sibling);
-		else
-			target_parent.appendChild(new_element);
-		
-		if (new_element.id == "su_field")
-		{
-			var width = su_ds.getValue("@search-width");
-			new_element.setAttribute("width", width + "px");
-		}
-	}
-	
-	if (depth == 1000)
-	{
-		su_log_error("MOVE LOOP", from, su_ds.getValue("@toolbar-position"), su_ds.getValue("@position-group"));
-		su_ds.setValue("@toolbar-position", "stumbleupon");
-		su_ds.setValue("@position-group", "first");
-		su_ds.setValue("@toolbar-visible", true);
-	}
-	
-	if ((old_parent.id == "su_statusbar_container") && 
-				(target_parent.id != "su_statusbar_container"))
-		old_parent.parentNode.removeChild(old_parent);
-	
-	if ((old_parent.id == "su_googlebar_container") && 
-				(target_parent.id != "su_googlebar_container"))
-		old_parent.parentNode.removeChild(old_parent);
-	
-	if ((old_parent.id == "su_otherbar_container") && 
-				(target_parent.id != "su_otherbar_container"))
-		old_parent.parentNode.removeChild(old_parent);
-	
-	} catch (e) {
-		su_log_error("MOVE TOOLBAR", e, from, su_ds.getValue("@toolbar-position"), su_ds.getValue("@position-group"));
-		
-		su_ds.setValue("@toolbar-position", "stumbleupon");
-		su_ds.setValue("@position-group", "first");
-		su_ds.setValue("@toolbar-visible", true);
-	}
-}
-
-function su_refresh_toggle_button(force)
-{
-	if (! window.BrowserCustomizeToolbar)
-		return;
-	
-	var visible = su_ds.getValue("@toolbar_toggle_visible");
-	var found = false;
-
-	found = su_is_item_in_toolbox((force && (! visible)), "su_toggle");
-	
-	if (! force)
-		su_ds.setValue("@toolbar_toggle_visible", found);
-
-	if (force && (! found) && visible)
-		su_add_toggle_button();
-}
-
-function su_add_toggle_button()
-{
-	if (document.getElementById("su_toggle"))
-		return;
-	
-	var urlbar = su_get_element("urlbar-container");
-	
-	var target = null;
-	if (urlbar)
-		target = urlbar.parentNode;
-	
-	if (target && target.collapsed)
-		target = null;
-	
-	var preferred_target = (target) ? true : false;
-	
-	if (! target)
-		target = su_get_element("nav-bar");
-	
-	if (target && target.collapsed)
-		target = null;
-	
-	if (! target)
-		target = su_get_element("toolbar-menubar");
-	
-	if (target && target.collapsed)
-		target = null;
-	
-	if (target && target.hasAttribute("customizable") && 
-				(target.getAttribute("customizable").toLowerCase() == "true"))
-	{
-		var currents = target.currentSet.split(",");
-		if (preferred_target)
-		{
-			var i;
-			for (i = 0; i < currents.length; i++)
-			{
-				if (currents[i] == "urlbar-container")
-				{
-					currents.splice(i, 0, "su_toggle");
-					break;
-				}
-			}
-			target.insertItem("su_toggle", urlbar, null, false);
-		}
-		else
-		{
-			currents.push("su_toggle");
-			
-			target.insertItem("su_toggle", null, null, false);
-		}
-		
-		target.setAttribute("currentset", currents.join(","));
-		su_persist_queue.push(target.id);
-	}
-	else
-	{
-		su_ds.setValue("@toolbar_toggle_visible", false);
-	}
-}
-
-function su_is_item_in_toolbox(remove, id, opt_toolbar)
-{
-	var toolbars;
-	if (opt_toolbar)
-	{
-		toolbars = new Array();
-		toolbars.push(opt_toolbar);
-	}
-	else
-	{
-		toolbars = document.getElementsByTagName("toolbar");
-	}
-
-	var found = false;
-	var i;
-	for (i = 0; i < toolbars.length; i++)
-	{
-		var item = su_get_element(id);
-		
-		if (remove)
-			su_is_element_on_bar(true, toolbars[i].id, id);
-
-		if (! toolbars[i].hasAttribute("customizable"))
-			continue;
-		
-		if (! toolbars[i].getAttribute("customizable").toLowerCase() == "true")
-			continue;
-		
-		var currents;
-		if ((typeof toolbars[i].currentSet) == "string")
-			currents = toolbars[i].currentSet.split(",");
-		else
-			currents = new Array();
-
-		var new_currents = new Array();
-		while(currents.length)
-		{
-			if (currents[0] == id)
-			{
-				found = true;
-				if (remove)
-					currents.shift();
-				else
-					new_currents.push(currents.shift());
-			}
-			else
-			{
-				new_currents.push(currents.shift());
-			}
-		}
-		
-		var current_set = new_currents.join(",");
-		
-		var old_set;
-		if (toolbars[i].hasAttribute("currentset"))
-			old_set = toolbars[i].getAttribute("currentset");
-		else
-			old_set = "";
-		
-		toolbars[i].setAttribute("currentset", current_set);
-		if (current_set != old_set)
-			su_persist_queue.push(toolbars[i].id);
-	}
-	return found;
-}
-
-function su_is_element_on_bar(remove, toolbar_id, id)
-{
-	// This works around a browser bug where el.parentNode.id can report
-	// the wrong id when parentNode is a toolbar (ref: Firefox 2.0rc1, 
-	// Linux).  --  JW
-	var toolbar = su_get_element(toolbar_id);
-	
-	if (! toolbar)
-		return false;
-	
-	var found = false;
-	var sibling = toolbar.firstChild;
-	var count = 0;
-	var el;
-	while (sibling)
-	{
-		count++;
-		if (count == 1000)
-		{
-			break;
-		}
-		el = sibling;
-		sibling = sibling.nextSibling;
-		if (el.id == id)
-		{
-			found = true;
-			if (remove)
-				toolbar.removeChild(el);
-		}
-	}
-	
-	if (count == 1000)
-		su_log_error("ON LOOP");
-	
-	return found;
-}
-
-
-// this is part of a hack that redefines behavior of the view->
-// toolbars->StumbleUpon menuitem in Firefox-derived browsers
-function su_replacement_onViewToolbarsPopupShowing(event)
-{
-	// During initialization, we make 
-	// window.su_saved_onViewToolbarsPopupShowing point to the browser-
-	// defined function window.onViewToolbarsPopupShowing (ref Firefox
-	// 1.5).  Then we make window.onViewToolbarsPopupShowing point to
-	// this function.  So this function runs when the browser invokes
-	// window.onViewToolbarsPopupShowing(..).
-	//
-	// This function executes the original browser-defined routine 
-	// before locating and modifying the StumbleUpon Toolbar menuitem. 
-	// -- JW
-	
-	window.su_saved_onViewToolbarsPopupShowing(event);
-	
-	var sibling = event.target.firstChild;
-	
-	var found = false;
-	while (sibling)
-	{
-		if (sibling.getAttribute("label").indexOf("StumbleUpon Toolbar") == 0)
-		{
-			found = true;
-			break;
-		}
-		sibling = sibling.nextSibling;
-	}
-	
-	if (found)
-	{
-		var menuitem = sibling;
-		menuitem.setAttribute("checked", su_ds.getValue("@toolbar-visible"));
-		menuitem.removeEventListener("command", onViewToolbarCommand, false);
-		menuitem.addEventListener("command", su_handle_view_toolbar_command, false);
-	}
-}
-
-function su_replacement_BrowserCustomizeToolbar()
-{
-	var toolbars = document.getElementsByTagName("toolbar");
-	var i;
-	var found = false;
-	for (i = 0; i < toolbars.length; i++)
-	{
-		if (toolbars[i].hasAttribute("currentset"))
-		{
-			var currents = toolbars[i].getAttribute("currentset").split(",");
-			var j;
-			for (j = 0; j < currents.length; j++)
-			{
-				if (currents[j] == "su_toolbaritem")
-				{
-					found = true;
-					break;
-				}
-			}
-		}
-	}
-	
-	if (! found)
-	{
-		var item = su_get_element("su_toolbaritem");
-		var toolbar = su_get_element("stumbleupon");
-		toolbar.setAttribute("currentset", "su_toolbaritem");
-		toolbar.insertItem("su_toolbaritem", null, null, true);
-		su_persist_queue.push("stumbleupon");
-	}
-	
-	setTimeout("su_replacement_BrowserCustomizeToolbar2();", 200);
-
-	var position = su_ds.getValue("@toolbar-position"); 
-	
-	if ((position == "status-bar") || (position == "yahoo-toolbar"))
-		return;
-	
-	
-	var el = su_get_element("bookmarks-ptf");
-	if (el)
-		el.hidden = true;
-
-	var new_parent = su_get_element("su_container");
-	new_parent.hidden = true;
-
-	var splitter = su_get_element("su_right-justify-splitter");
-	if (splitter)
-		splitter.collapsed = true;
-
-	su_move_toolbar_elements(new_parent, null, 7);
-	
-	var needs_cleanup = false;
-
-	var container = su_get_element("su_googlebar_container");
-	if (container)
-	{
-		needs_cleanup = true;
-		container.parentNode.removeChild(container);
-	}
-
-	var toolbaritem = su_get_element("su_toolbaritem");
-	if (toolbaritem)
-	{
-		needs_cleanup = true;
-		if (toolbaritem.hasAttribute("width"))
-			toolbaritem.removeAttribute("width");
-		
-		if (toolbaritem.hasAttribute("flex"))
-			toolbaritem.removeAttribute("flex");
-	}
-	
-	if (needs_cleanup)
-		su_cleanup_toolbox(true, true);
-}
-
-function su_replacement_BrowserCustomizeToolbar2()
-{
-	window.su_saved_BrowserCustomizeToolbar();
-	
-	var position = su_ds.getValue("@toolbar-position"); 
-	if ((position == "status-bar") || (position == "yahoo-toolbar"))
-	{
-		su_get_element("stumbleupon").collapsed = true;
-		su_get_element("su_toolbar_customize_label").value = "";
-	}
-	else
-	{
-		var shortcut = su_ds.getValue("$shortcut_toolbar");
-		var label = "StumbleUpon Toolbar Items";
-		if (shortcut != "")
-		{
-			label += " (" + 
-						su_get_display_keyspec(shortcut) + 
-						")";
-		}
-		
-		su_get_element("stumbleupon").collapsed = false;
-		su_get_element("su_toolbar_customize_label").value = label;
-	}
-}
-
-function su_replacement_BrowserToolboxCustomizeDone(aToolboxChanged)
-{
-	if (window.su_saved_BrowserToolboxCustomizeDone)
-		window.su_saved_BrowserToolboxCustomizeDone(aToolboxChanged);
-	
-	su_refresh_toggle_button(false);
-	
-	var position = su_ds.getValue("@toolbar-position");
-	if ((position == "status-bar") || (position == "yahoo-toolbar"))
-		return;
-	
-	var el = su_get_element("bookmarks-ptf");
-	if (el)
-		el.hidden = false;
-	
-	var outer_container = su_get_element("su_toolbaritem");
-	if (outer_container)
-	{
-		setTimeout(su_replacement_BrowserToolboxCustomizeDone2, 0);
-	}
-	else
-	{
-		su_get_element("stumbleupon").collapsed = true;
-		var toolbar = su_get_element("stumbleupon");
-		var currents = toolbar.currentSet.split(",");
-		currents.push("su_toolbaritem");
-		toolbar.setAttribute("currentset", currents.join(","));
-		toolbar.insertItem("su_toolbaritem", null, null, true); 
-		su_ds.setValue("@toolbar-visible", false);
-		su_persist_queue.push("stumbleupon");
-	}
-	if (su_customize_invoked_from_preference_dialog)
-	{
-		su_customize_invoked_from_preference_dialog = false;
-		setTimeout(su_preferences, 1000);
-	}
-
-	su_get_element("su_toolbar_customize_label").value = "";
-}
-
-function su_replacement_BrowserToolboxCustomizeDone2()
-{
-	su_move_toolbar(false, 5)
-	su_reflow_toolbar(5);
-	setTimeout(su_verify_toolbar_move, 0, 5);
-}
-
-function su_replacement_foxytunesSetFoxyTunesPosition()
-{
-	try {
-		su_saved_foxytunesSetFoxyTunesPosition();
-	} catch (e) {}
-	setTimeout(su_replacement_BrowserToolboxCustomizeDone2, 200);
-}
-
-function su_is_toolbar_shared()
-{
-	var toolbar = su_get_element("stumbleupon");
-	var sibling = toolbar.firstChild;
-	var count = 0;
-	var el;
-	while (sibling)
-	{
-		count++;
-		if (count == 1000)
-			break;
-		
-		el = sibling;
-		sibling = sibling.nextSibling;
-		switch (el.id)
-		{
-			case "su_toolbaritem":
-			case "stringbundleset":
-			case "bundle_stumble":
-			case "su_commandset":
-			case "su_keyset":
-			case "su_container":
-			case "su_render":
-				break;
-			default:
-				return true;
-		}
-	}
-	
-	return false;
-}
-
-function su_prevent_toolbar_sharing()
-{
-	if (! window.BrowserCustomizeToolbar)
-		return;
-	
-	var toolbar = su_get_element("stumbleupon");
-	var currents = toolbar.currentSet.split(",");
-	var new_currents = new Array();
-	var i;
-	var modified = false;
-	var el;
-	for (i = 0; i < currents.length; i++)
-	{
-		switch (currents[i])
-		{
-			case "__empty":
-			case "su_toolbaritem":
-				new_currents.push(currents[i]);
-				break;
-			default:
-				modified = true;
-				break;
-		}
-	}
-	
-	var sibling = toolbar.firstChild;
-	var count = 0;
-	while (sibling)
-	{
-		count++;
-		if (count == 1000)
-		{
-			break;
-		}
-		el = sibling;
-		sibling = sibling.nextSibling;
-		switch (el.id)
-		{
-			case "su_toolbaritem":
-			case "stringbundleset":
-			case "bundle_stumble":
-			case "su_commandset":
-			case "su_keyset":
-			case "su_container":
-			case "su_render":
-				break;
-			default:
-				toolbar.removeChild(el);
-		}
-	}
-	
-	if (count == 1000)
-		su_log_error("SHARING LOOP");
-	
-	if (modified)
-	{
-		var new_parent = su_get_element("stumbleupon-hbox");
-		new_parent.hidden = true;
-		su_move_toolbar_elements(new_parent, null, 8);
-
-		toolbar.setAttribute("currentset", currents.join(","));
-		su_persist_queue.push("stumbleupon");
-		setTimeout("su_move_toolbar(false, 3);", 0);
-		setTimeout(su_reflow_toolbar, 0, 6);
-	}
-}
-
-function su_customize_toolbox()
-{
-	su_customize_invoked_from_preference_dialog = true;
-	document.getElementById("cmd_CustomizeToolbars").doCommand();
-}
-
-// forwards the view->toolbars menuitem command event in Firefox-
-// derived browsers
-function su_handle_view_toolbar_command(event)
-{
-	setTimeout("su_toggle_toolbar();", 0);
-}
-
-// ultimately called by the view->toolbars menuitem in Firefox-
-// derived browsers
-function su_toggle_toolbar()
-{
-	su_toggling_toolbar = true;
-
-	var toolbar_position = su_ds.getValue("@toolbar-position");
-
-	var new_visible_state;
-	if (toolbar_position == "stumbleupon")
-		new_visible_state = su_get_element("stumbleupon").collapsed;
-	else
-		new_visible_state = ! su_ds.getValue("@toolbar-visible");
-
-	su_ds.setValue("@toolbar-visible", new_visible_state);
-	
-	su_move_toolbar(false, 4);
-
-	su_toggling_toolbar = false;
-
-	if (new_visible_state)
-		su_reflow_toolbar(7);
-
-/*
-	if (su_new_install && (! su_ds.getValue("@shown_toolbar")))
-	{
-		su_ds.setValue("@shown_toolbar", true);
-		stumble(0);
-	}
-*/
-
-	su_ds.flushPrefs();
-}
-
-// handles the mousedown event for the splitter to the right of the 
-// search box
-function su_handle_splitter_search_right_mousedown(event)
-{
-	su_moving_splitter = true;
-	var outer_container = su_get_element("su_toolbaritem");
-	if (outer_container || (su_toolbar_justification == "right"))
-		su_shorten_toolbar_to_element("su_splitter_search_right");
-	su_set_toolbar_element_widths(su_get_element("su_stumble"));
-
-	return true;
-}
-
-// handles the mouseup event for the splitter to the right of the 
-// search box
-function su_handle_splitter_search_right_mouseup(event)
-{
-	setTimeout('su_remove_toolbar_element_widths(su_get_element("su_stumble"))', 0);		
-	su_moving_splitter = false;
-	if (su_get_element("su_field").boxObject.width > 400)
-		setTimeout('su_get_element("su_field").setAttribute("width", "400px")');
-
-	setTimeout("su_refresh_splitters(false)", 0);
-	return true;
-}
-
-function su_get_toolbar_outer_container()
-{
-	var position = su_ds.getValue("@toolbar-position");
-	var container;
-	if ((position == "status-bar") && 
-				(su_ds.getValue("@position-group") == "last"))
-	{
-		container = su_get_element("su_statusbar_container");
-	}
-	else if (su_ds.getValue("@position-group") == "last")
-	{
-		container = su_get_element("su_otherbar_container");
-	}
-	else if (position == "gtbToolbar")
-	{
-		container = su_get_element("su_googlebar_container");
-	}
-	
-	if (! container)
-	{
-		container = su_get_element("su_stumble").parentNode;
-	}
-	
-	if (container.id == "su_toolbar_container")
-	{
-		container = su_get_element("su_toolbaritem");
-	}
-	return container;
-}
-
-// handles the mouseup event for the dynamic splitter that's created
-// when the toolbar is right-justified
-function su_handle_right_justify_splitter_mousedown(event)
-{
-	su_moving_splitter = true;
-	
-	su_shorten_toolbar_to_element("su_thumbdown");
-	
-	su_set_toolbar_element_widths(su_get_toolbar_outer_container());
-	
-	return true;
-}
-
-// handles the mousedown event for the dynamic splitter that's
-// created when the toolbar is right-justified
-function su_handle_right_justify_splitter_mouseup(event)
-{
-	var hbox = su_get_toolbar_outer_container();
-
-	su_ds.setValue("@right-justify-width", hbox.boxObject.width);
-	
-	setTimeout('su_remove_toolbar_element_widths(su_get_element("' + 
-				hbox.id + '"))', 0);		
-	su_moving_splitter = false;
-	setTimeout("su_refresh_splitters(false)", 0);
-	
-	return true;
-}
-
-// used by splitter mousedown listeners to set temporary minwidths 
-// for adjacent elements
-function su_set_toolbar_element_widths(sibling)
-{
-	sibling = sibling.parentNode.firstChild;
-
-	while (sibling != null)
-	{
-		if (sibling.id == "personal-bookmarks")
-		{
-			var el = su_get_element("bookmarks-stack");
-			if (el)
-				el.hidden = true;
-		}
-		else if (sibling.id && (sibling.id.indexOf("spring") != 0) && 
-					(sibling.id != "su_splitter_first_flexbox") &&
-					(sibling.id != "su_field") &&
-					(sibling.id != "su_toolbar_container") &&
-					(sibling.id != "su_toolbaritem") &&
-					(sibling.id != "su_statusbar_container") &&
-					(sibling.id != "su_otherbar_container") &&
-					(sibling.id != "su_googlebar_container") &&
-					(sibling.tagName != "tooltip") &&
-					(! sibling.hasAttribute("flex")))
-		{
-			if (sibling.hasAttribute("minwidth"))
-				sibling.setAttribute("su_savedminwidth", sibling.getAttribute("minwidth"));
-
-			if (sibling.hasAttribute("width"))
-				sibling.setAttribute("su_hadwidth", "true");
-			
-			sibling.setAttribute("minwidth", sibling.boxObject.width + "px");
-		}
-		
-		sibling = sibling.nextSibling;
-	}
-}
-
-
-// used by splitter mouseup listeners to remove the temporary 
-// minwidths set by set_toolbar_element_widths
-function su_remove_toolbar_element_widths(sibling)
-{
-	sibling = sibling.parentNode.firstChild;
-
-	while (sibling != null)
-	{
-		if (sibling.hasAttribute("su_savedminwidth"))
-			sibling.setAttribute("minwidth", sibling.getAttribute("su_savedminwidth"));
-		else
-			sibling.removeAttribute("minwidth");
-
-		if (sibling.id == "personal-bookmarks")
-		{
-			var el = su_get_element("bookmarks-stack");
-			if (el)
-			{
-				el.hidden = false;
-				setTimeout("BookmarksToolbar.resizeFunc(null);", 0);
-			}
-		}
-		else if ((sibling.id != "su_splitter_first_flexbox") && 
-					(sibling.id != "su_field") &&
-					(sibling.id != "su_toolbar_container") && 
-					(sibling.id != "su_toolbaritem") &&
-					(sibling.id != "su_statusbar_container") &&
-					(sibling.id != "su_otherbar_container") &&
-					(sibling.id != "su_googlebar_container") &&
-					(sibling.tagName != "tooltip"))
-		{
-			if (sibling.hasAttribute("su_hadwidth"))
-				sibling.removeAttribute("su_hadwidth");
-			else
-				sibling.removeAttribute("width");
-		}
-		sibling = sibling.nextSibling;
-	}
-}
-
-function su_shorten_toolbar_to_element(stop_id)
-{
-	var popup = su_get_element("su_overflow_popup");
-	var i;
-	var item;
-	for (i = 0; i < popup.childNodes.length; i++)
-	{
-		item = popup.childNodes[i];
-		if (item.id && (item.id == stop_id))
-			return;
-	}
-	
-	var container = su_get_element("su_stumble").parentNode;
-	
-	var menuified_one = false;
-	for (i = container.childNodes.length - 2; i >= 0; i--)
-	{
-		item = container.childNodes[i];
-		if (item.id && (item.id == stop_id))
-			break;
-		su_menuify_toolbar_element(item);
-		menuified_one = true;
-	}
-	if (menuified_one)
-	{
-		var menu = su_get_element("su_overflow_menu");
-		menu.collapsed = false;
-		menu.hidden = false;
-	}
-	su_cleanup_overflow_flexbox()
-}
-
-// handles the left margin splitter mousedown event
-function su_handle_splitter_first_mousedown(event)
-{
-	su_moving_splitter = true;
-	return true;
-}
-
-// handles the left margin splitter mouseup event
-function su_handle_splitter_first_mouseup(event)
-{
-	su_moving_splitter = false;
-	setTimeout("su_refresh_splitters(false)", 0);
-	return true;
-}
-
-// handles the sidebar splitter mouseup event
-function su_handle_sidebar_mouseup(event)
-{
-	setTimeout("su_refresh_splitters(false)", 0);
-	return true;
-}
-
-// handles the sidebar splitter attr modified event
-function su_handle_sidebar_attr_modified(event)
-{
-	if (event.attrName == "hidden")
-		setTimeout("su_refresh_splitters(false)", 0);
-
-	return true;
-}
-
-// queues a change to the hidden state of a top-level toolbar element
-function su_set_visible(id, state)
-{
-	state = ! state;
-	var element = su_get_element(id);
-	var changed = false;
-	if (element.parentNode.id == "su_overflow_popup")
-	{
-		if (element.hasAttribute("savedhidden"))
-			element.setAttribute("savedhidden", state);
-		else
-			element.collapsed = state;
-	}
-	else
-	{
-		if (element.hasAttribute("su_ismode"))
-		{
-			changed = (element.hidden != state);
-			element.hidden = state;
-		}
-		else
-		{
-			changed = (element.collapsed != state);
-			element.collapsed = state;
-		}
-	}
-	
-	if ((! state) && (id == "su_referred"))
-		setTimeout(su_stop_referred_throbber, su_ds.getValue("$referral_throbber_interval_ms")) 
-	
-	if (changed)
-		setTimeout("su_reflow_toolbar(8)", 10);
-}
-
-function su_stop_referred_throbber()
-{
-	su_set_attribute("su_referred", "busy", "false");
-}
-
-// for future use, to fix the textonly bug
-//function su_is_toolbar_textonly()
-//{
-//	var toolbar = su_get_parent_toolbar(su_get_element("su_stumble"));
-//	if (! toolbar)
-//		return false;
-//	
-//	if (toolbar.hasAttribute("mode") &&
-//				(toolbar.getAttribute("mode") == "text"))
-//		return true;
-//}
-
-// queues a change to the label of a top-level toolbar element
-function su_set_label(id, str)
-{
-	var element = su_get_element(id);
-	var menuified = (element.parentNode.id == "su_overflow_popup");
-
-	if (id == "su_mode")
-	{
-		su_get_element("su_mode_label").collapsed = (! su_get_label_visibility(id, menuified));
-		return;
-	}
-	else if (id == "su_category")
-	{
-		str += " ";
-	}
-
-	// When str is null, use the value in the showlabel attribute.
-	// -- JW
-
-	if (su_get_label_visibility(id, menuified))
-	{
-		if ((! str) && element.hasAttribute("showlabel"))
-			str = element.getAttribute("showlabel");
-	}
-	else
-	{
-		str = "";
-	}
-
-	var changed = (element.label != str);
-	str = (str) ? str : "";
-	
-	if (str == "")
-	{
-		if (menuified)
-			element.className = "su-hidetext-menuified";
-		else
-			element.className = "su-hidetext";
-	}
-	else
-	{
-		if (menuified)
-			element.className = "su-showtext-menuified";
-		else
-		{
-			if ((element.id == "su_category") || 
-				(element.id == "su_stumble_topic"))
-				element.className = "su-hideicon-showtext";
-			else
-				element.className = "su-showtext";
-		}
-		element.label = str;
-	}
-	
-	if (changed)
-		setTimeout("su_reflow_toolbar(9)", 10);
-}
-
-function su_set_attribute(id, attr_name, value)
-{
-	var el = su_get_element(id);
-	if (! el)
-		return;
-	el.setAttribute(attr_name, value);
-}
-
-function su_remove_attribute(id, attr_name, value)
-{
-	var el = su_get_element(id);
-	if (! el)
-		return;
-	if (el.hasAttribute(attr_name))
-		el.removeAttribute(attr_name);
-}
-
-// used by the toolbar refresh routines to determine whether the 
-// label associated with a top-level toolbar element is to be 
-// displayed when it has the specified menuified state
-function su_get_label_visibility(id, menuified)
-{
-	var always_visible_ids = ",su_login,su_start,su_referred,su_site-count-box,su_recthumbup,su_category,su_stumble_topic," +
-				"su_stumble_topic_menu_left,su_stumble_topic_menu_right," +
-				"su_page_feature_prompt,su_grab,su_approve,su_idx,su_tld,";
-	var text_icons_mode_visible_ids = ",su_stumble,su_thumbup,su_profile," + 
-				"su_friends,su_referral_menu,firstrater,su_sponsor," + 
-				"su_mode,su_stumble_menu,su_website_info,";
-	var element = su_get_element(id);
-	var query = "," + id + ",";
-	
-	if ((stumbleid != 0) && su_ds.getValue("$show_firstrater_label_always"))
-		always_visible_ids += "firstrater,su_sponsor,";
-	
-	if (su_promo_mode && (stumbleid == 0))
-		always_visible_ids += "su_referral_promo,su_website_info_promo,su_sites_promo,su_video_promo,"
-	
-	var text_icons = true;
-	
-	if (stumbleid != 0)
-		text_icons = (su_ds.getValue("$icons") == "text-icons"); 
-	
-	// Visible if:
-	// (1) it's always visible
-	// (2) we're configured to text-icons, and this is in the visible subset
-	// (3) it's in the overflow popup, and it has a showlabel attribute
-	// -- JW
-	return (always_visible_ids.indexOf(query) != -1) ||
-				(text_icons && 
-				(text_icons_mode_visible_ids.indexOf(query) != -1)) ||
-				(menuified && element.hasAttribute("showlabel") && 
-					(id != "su_mode"));
-}
-
-// queues a change to the image of a top-level toolbar element
-function su_set_image(id, uri)
-{
-	var element = su_get_element(id);
-
-	var changed = (element.image != uri);
-	if (changed)
-	{
-		element.image = uri;
-		setTimeout("su_reflow_toolbar(10)", 10);
-	}
-}
-
-// used by splitter mouseup handlers and the splitter init routine to
-// set splitter visibility and to store new state
-function su_refresh_splitters(use_saved_latch_state)
-{
-	try {
-	var content_x = su_get_element("content").boxObject.x;
-	var toolbar_x = su_get_element("su_stumble").boxObject.x;
-	var sidebar_hidden = su_get_element("sidebar-splitter").hidden || 
-				su_get_element("sidebar-box").collapsed;
-	var align_with_content = su_ds.getValue("@latch-to-sidebar");
-	var splitter_first = su_get_element("su_splitter_first");
-	var first_flexbox = su_get_element("su_splitter_first_flexbox");
-	
-	var splitter = su_get_element("su_right-justify-splitter")
-
-	if ((su_toolbar_justification == "left") && (splitter))
-	{
-		splitter.parentNode.removeChild(splitter);
-	}
-	else if ((su_toolbar_justification == "right") && (! splitter))
-	{
-		var splitter = document.createElement("splitter");
-		splitter.setAttribute("id", "su_right-justify-splitter");
-		splitter.setAttribute("class", "su_splitter");
-		splitter.setAttribute("state", "open");
-		splitter.setAttribute("collapse", "none");
-		splitter.setAttribute("resizebefore", "grow");
-		splitter.setAttribute("resizeafter", "closest");
-		splitter.setAttribute("onmousedown", "return su_handle_right_justify_splitter_mousedown(event);");
-		splitter.setAttribute("onmouseup", "return su_handle_right_justify_splitter_mouseup(event);");
-		
-		var sibling = su_get_toolbar_outer_container();
-		sibling.parentNode.insertBefore(splitter, sibling);
-	}
-	else if ((su_toolbar_justification == "right") && (splitter))
-	{
-		splitter.collapsed = false;
-		var sibling = su_get_toolbar_outer_container();
-		
-		sibling.parentNode.insertBefore(splitter, sibling);
-	}
-	
-	// Determine whether the toolbar should be latched to the sidebar.
-	if (su_is_toolbar_shared())
-	{
-		align_with_content = false;
-		splitter_first.collapsed = true;
-	}
-	else if (su_ds.getValue("@toolbar-position") == "stumbleupon")
-	{
-		splitter_first.collapsed = sidebar_hidden;
-		if (! use_saved_latch_state)
-		{
-			if ((su_sidebar_was_hidden == sidebar_hidden) && (su_old_toolbar_x != toolbar_x))
-			{
-				var latch_to_sidebar = su_ds.getValue("@latch-to-sidebar");
-				
-				if (latch_to_sidebar)
-					align_with_content = (toolbar_x >= (content_x - 20));
-				else
-					align_with_content = (first_flexbox.boxObject.width > 20);
-			}
-			su_ds.setValue("@latch-to-sidebar", align_with_content);
-		}
-	}
-	else
-	{
-		align_with_content = false;
-		splitter_first.collapsed = true;
-	}
-
-	var new_width;
-	if (align_with_content)
-	{
-		// If latched, move the toolbar to match.
-	
-		if (sidebar_hidden)
-		{
-			new_width = 0;
-		}
-		else
-		{
-			// This hidden statement works around an apparent browser bug
-			// (ref: Firefox 2.0.0.2, Linux). -- JW
-			splitter_first.hidden = false;
-			new_width = content_x - first_flexbox.boxObject.x - splitter_first.boxObject.width;
-			if (new_width < 0)
-				new_width = 0;
-		}
-	}
-	else
-	{
-		new_width = 0;
-	}
-	first_flexbox.setAttribute("width", new_width + "px");
-	
-	var search = su_get_element("su_field");
-	if (! search.collapsed)
-	{
-		var width = search.boxObject.width;
-		if (width != 0)
-		{
-			// The zero test above fixes an issue where the search box 
-			// width gets set to zero upon toggling visibility (ref: 
-			// Firefox 1.5, XP). -- JW
-			su_ds.setValue("@search-width", width);
-		}
-	}
-	su_old_toolbar_x = su_get_element("su_stumble").boxObject.x;
-	su_sidebar_was_hidden = sidebar_hidden;
-	su_reflow_toolbar(11);
-	if (su_bookmarks_sibling_loc)
-		su_reflow_bookmarks_toolbar();
-	
-	} catch (e) { su_log_error("REFRESH SPLITTERS", e, su_ds.getValue("@toolbar-position"), su_ds.getValue("@position-group")); }
-}
-	
-// handles the window resize event
-function su_handle_window_resize(event)
-{
-	var width = window.innerWidth;
-	
-	if (width != su_resize_window_width)
-	{
-		su_resize_window_width = width;
-		su_reflow_toolbar(12);
-	}
-	else if (! su_resize_window_dirty)
-	{
-		// handles window maximize case
-		su_resize_window_dirty = true;
-		setTimeout(su_handle_window_resize2, 500);
-	}
-
-	return true;
-}
-
-function su_handle_window_resize2()
-{
-	if (! su_resize_window_dirty)
-		return;
-	
-	su_reflow_toolbar(14);
-	
-	su_resize_window_dirty = false;
-}
-
-function su_reflow_toolbar(from)
-{
-	try {
-	if (! su_gui_initialized)
-		return;	
-
-	// Nuke the flexbox.
-	var flexbox = su_get_element("su_overflow_flexbox"); 
-	if (flexbox)
-		flexbox.parentNode.removeChild(flexbox);
-	
-	var container = su_get_element("su_stumble").parentNode;
-	var outer_container = su_get_toolbar_outer_container();
-	
-	if (container.id == "su_container")
-	{
-		container.setAttribute("flex", "1");
-	}
-	else
-	{
-		var hbox = su_get_element("su_container");
-		if (hbox.hasAttribute("flex"))
-			hbox.removeAttribute("flex");
-	}
-
-	// If we're invisible, hide the outer_container.
-	if (! su_ds.getValue("@toolbar-visible"))
-	{
-		outer_container.setAttribute("width", 0);
-		return;
-	}
-	
-	// Demenuify everything.
-	var popup = su_get_element("su_overflow_popup"); 
-	while (popup.hasChildNodes())
-		su_demenuify_toolbar_element(popup.firstChild);
-	
-	var sibling;
-	sibling = su_get_element("su_stumble").parentNode.firstChild;
-	while (sibling)
-	{
-		sibling.hidden = false;
-		sibling = sibling.nextSibling;
-	}
-
-	var position = su_ds.getValue("@toolbar-position");
-	if ((position == "gtbToolbar") && (! su_reflow_delayed))
-	{
-		// If we're on the google toolbar, expand to max width, and allow
-		// the toolbar to reflow.
-		outer_container.setAttribute("width", 
-					container.lastChild.boxObject.x + 
-					container.lastChild.boxObject.width - 20 + "px");
-		su_reflow_delayed = true;
-		setTimeout(su_reflow_toolbar, 0, 13);
-		return;
-	}
-	su_reflow_delayed = false;
-
-	var menu = su_get_element("su_overflow_menu");
-	menu.collapsed = false;
-	var chevron_width = menu.boxObject.width;
-	menu.collapsed = true;
-	
-
-	// Compute available width.
-
-	var toolbar = su_get_element(su_get_parent_toolbar_id(container));
-	var available = window.innerWidth;
-	var regexp = new RegExp("^spring\\d+$");
-	var i;
-	var in_toolbar_elements = false;
-	var google_sibling_found = false;
-	var has_flexible_sibling = false;
-	var max;
-	for (i = 0; i < toolbar.childNodes.length; i++)
-	{
-		var sibling = toolbar.childNodes[i];
-		var pre = available;
-		var id = (sibling.id) ? sibling.id : "";
-		if (id == "su_splitter_first_flexbox")
-		{
-			in_toolbar_elements = true;
-		}
-		else if (in_toolbar_elements)
-		{
-//			if (su_host.mac)
-//				sibling.hidden = false;
-			
-			if (id == "su_overflow_menu")
-			{
-				in_toolbar_elements = false;
-				max = sibling.boxObject.x + sibling.boxObject.width;
-			}
-		}
-		else if (id == "nav-bar-inner")
-		{
-			available -= 300;  // Seamonkey url bar
-		}
-		else if (id == "urlbar-container")
-		{
-			available -= 300;  // Firefox url bar
-		}
-		else if ((id == "search-container") && sibling.hasAttribute("flex"))
-		{
-			available -= 185;  // Firefox search box for 2.0+
-		}
-		else if (id == "statusbar-display")
-		{
-			available -= 185;  // Status bar content
-		}
-		else if ((id != "su_toolbaritem") && 
-					(id != "su_toolbar_container") &&
-					(id != "su_statusbar_container") &&
-					(id != "su_otherbar_container") &&
-					(id != "su_googlebar_container") &&
-					(id != "su_container") &&
-					(id != "bookmarks-ptf") &&        // Seamonkey bookmarks
-					(id != "personal-bookmarks") &&   //   Firefox bookmarks
-					(sibling.tagName != "tooltip") && // Seamonkey tooltips
-					(id.search(regexp) != 0))
-		{
-			if (sibling.boxObject.width != 0)
-				google_sibling_found = true;
-			available -= sibling.boxObject.width;
-		}
-	}
-	
-	if (su_toolbar_justification == "right")
-	{
-		// If we're right-justified, limit to @right-justify-width.
-		var justify_width = su_ds.getValue("@right-justify-width");
-
-		if (available > justify_width)
-			available = justify_width;
-	}
-	else if (position == "gtbToolbar")
-	{
-		var gtb_chevron = su_get_element("gtbChevron");
-		if (google_sibling_found)
-		{
-			// Leave the previously set max width.
-			if (gtb_chevron)
-				gtb_chevron.collapsed = false;
-			return;
-		}
-		else
-		{
-			// Limit width to window width.
-			if (gtb_chevron)
-				gtb_chevron.collapsed = true;
-
-			available = window.innerWidth;
-			container.setAttribute("width", available + "px");
-		}
-	}
-	else
-	{
-		if (su_ds.getValue("@position-group") == "first")
-		{
-			// Push companion elements to the right.
-			available = document.getElementById("main-window").boxObject.width;
-		}
-		
-//		if ((! max) && (su_ds.getValue("@toolbar-position") != "stumbleupon"))
-		if (! max)
-		{
-			var box = su_get_element("su_overflow_menu").boxObject;
-			max = box.x + box.width;
-		}
-		
-//		if ((outer_container.id != "status-bar") && 
-//					(su_ds.getValue("@toolbar-position") != "stumbleupon"))
-		if (outer_container.id != "status-bar")
-		{
-			if (available > max)
-				available = max;
-			outer_container.setAttribute("width", available + "px");
-		}
-	}
-
-	// For each element that won't fit, move it into the overflow menu.
-	var overflowed = false;
-	var first = true;
-	in_toolbar_elements = false;
-	for (i = container.childNodes.length - 2; i >= 0; i--)
-	{
-		var item = container.childNodes[i];
-
-		var consumed = item.boxObject.x - container.boxObject.x + 
-					item.boxObject.width + ((first) ? 0 : chevron_width);
-		
-		first = false;
-		
-		var id = (item.id) ? item.id : "";
-		
-		if ((id == "su_overflow_menu") || (id == "su_site-count-box"))
-		{
-			in_toolbar_elements = true;
-			if (id == "su_overflow_menu")
-				continue;
-		}
-		if (! in_toolbar_elements)
-		{
-			continue;
-		}
-		else if ((consumed > available) && (id != "su_thumbdown"))
-		{
-			overflowed = true;
-			su_menuify_toolbar_element(item);
-		}
-		else
-		{
-			if (id.indexOf("su_separator") == 0)
-				su_menuify_toolbar_element(item);
-			break;
-		}
-	}
-	
-	if (overflowed)
-	{
-		menu.collapsed = false;
-		su_cleanup_overflow_menuseparators();
-	}
-	su_cleanup_overflow_flexbox();
-
-	sibling = su_get_element("su_stumble").parentNode.firstChild;
-	while (sibling)
-	{
-		sibling.hidden = sibling.collapsed;
-		sibling = sibling.nextSibling;
-	}
-	
-	setTimeout(su_refresh_info, 0);
-	
-	if (from != "retry")
-		setTimeout(su_verify_reflow, 500);
-	
-	}
-	catch (e) {
-		var toolbar_position = su_ds.getValue("@toolbar-position");
-		var position_group = su_ds.getValue("@position-group");
-		if ((toolbar_position == "stumbleupon") && (position_group == "first"))
-		{
-			su_log_error("REFLOW ERROR", e, from);
-		}
-		else
-		{
-			su_log_error("REFLOW FAILSAFE", e, from, toolbar_position, position_group);
-			su_ds.setValue("@toolbar-position", "stumbleupon");
-			su_ds.setValue("@position-group", "first");
-		}
-	}
-	
-}
-
-function su_reflow_bookmarks_toolbar()
-{
-	if (su_get_element("bookmarks-ptf") && window.BMSVC
-			&& ((typeof (window.BMSVC.getBookmarksToolbarFolder)) == "function")
-			&& window.BookmarksToolbarRDFObserver)
-	{
-		// ref: Firefox 2.0
-		var bt = su_get_element("bookmarks-ptf");
-		var btf = BMSVC.getBookmarksToolbarFolder().Value;
-		var btchevron = document.getElementById("bookmarks-chevron");
-		bt.ref = btf;
-		btchevron.ref = btf;
-		// no uniqueness is guaranteed, so we have to remove first
-		try {
-			bt.database.RemoveObserver(BookmarksToolbarRDFObserver);
-		} catch (ex) {
-			// ignore
-		}
-		bt.database.AddObserver(BookmarksToolbarRDFObserver);
-		bt.builder.rebuild();
-		btchevron.builder.rebuild();
-
-		// fake a resize; this function takes care of flowing bookmarks
-		// from the bar to the overflow item
-		BookmarksToolbar.resizeFunc(null);
-	}
-	else if (su_get_element("bookmarksBarContent")
-		&& (typeof (su_get_element("bookmarksBarContent").updateChevron) == "function"))
-			
-	{
-		// ref: Firefox 3.6rc
-		var bar_content = su_get_element("bookmarksBarContent");
-		bar_content.updateChevron();
-	}
-}	
-
-function su_verify_reflow()
-{
-	//!!! This is very primitive; it only helps when the stumbleupon 
-	// elements are the last time on the bar.  This is the most common
-	// case.  Eventually, we have to discover why it's necessary at all
-	// an why it's off by 2 px every time.
-	var box = su_get_element("su_overflow_menu").boxObject;
-	
-	if (((box.x + box.width) - window.innerWidth) > 3)
-	{
-		setTimeout(su_reflow_toolbar, 0, "retry");
-	}
-}
-
-function su_cleanup_toolbox(force, update_urlbar)
-{
-	var position = su_ds.getValue("@toolbar-position");
-
-	if ((force || (position == "gtbToolbar")) && 
-				((typeof GTB_GoogleToolbarOverlay) != "undefined") && 
-				GTB_GoogleToolbarOverlay.chevron && 
-				((typeof GTB_GoogleToolbarOverlay.chevron.doResize) == 
-				"function"))
-	{
-		try {
-			GTB_GoogleToolbarOverlay.chevron.doResize();
-		} catch (e) {};
-	}
-	
-	if ((force || (position == "yahoo-toolbar")) &&
-				((typeof yahooToolbarOverflowDelay) == "function"))
-	{
-		try {
-			yahooToolbarOverflowDelay();
-		} catch (e) {};
-	}
-	
-	try {
-		su_reflow_bookmarks_toolbar();
-	} catch (e) { su_log("BOOKMARKS CLEANUP", e); }
-	
-	if ((force || (position == "prefbar")) &&
-				((typeof prefbarUpdateToolbar) == "function"))
-	{
-		setTimeout(prefbarUpdateToolbar, 0);
-	}
-
-	if (update_urlbar)
-	{
-		try {
-		// Update the urlbar
-			var url = getWebNavigation().currentURI.spec;
-			if (window.gURLBar)
-			{
-				if (url == "about:blank")
-				{
-					gURLBar.value = "";
-					SetPageProxyState("invalid");
-				}
-				else
-				{
-					gURLBar.value = url;
-					SetPageProxyState("valid");
-				}
-				FeedHandler.updateFeeds();
-			}
-		} catch (e) {}
-	}
-}
-
-// used by shorten_toolbar to move an element from the toolbar to the
-// overflow menu
-function su_menuify_toolbar_element(element)
-{
-	var popup = su_get_element("su_overflow_popup");
-	
-	var new_element;
-	if ((element.id == "su_referral_menu") || (element.id == "su_stumble_menu"))
-	{
-		new_element = element;
-		new_element.label = new_element.getAttribute("showlabel");
-	}
-	else if (element.id == "su_mode")
-	{
-		new_element = element;
-		su_get_element("su_mode_label").collapsed = true;
-	}
-	else if (element.id == "su_field")
-	{
-		new_element = element;
-		new_element.setAttribute("savedhidden", new_element.collapsed);
-		new_element.collapsed = true;
-	}
-	else if (element.tagName == "splitter")
-	{
-		new_element = element.cloneNode(true);
-		new_element.setAttribute("savedhidden", new_element.collapsed);
-		new_element.collapsed = true;
-	}
-	else if ((element.tagName == "toolbarbutton") && element.hasAttribute("showlabel"))
-	{
-		new_element = element.cloneNode(true);
-		new_element.label = new_element.getAttribute("showlabel");
-	}
-	else if (element.id.indexOf("su_separator") == 0)
-	{
-		new_element = document.createElement("menuseparator");
-		new_element.id = element.id;
-		new_element.collapsed = element.collapsed;
-	}
-	else
-	{
-		new_element = element.cloneNode(true);
-//		new_element.hidden = element.collapsed;
-//		new_element.collapsed = false;
-	}
-
-	element.parentNode.removeChild(element);
-
-	if (new_element.className == "su-showtext")
-		new_element.className =  "su-showtext-menuified";
-
-	else if (new_element.className == "su-hidetext")
-		new_element.className = "su-hidetext-menuified";
-	
-	new_element.hidden = new_element.collapsed;
-	
-	popup.insertBefore(new_element, popup.firstChild);
-}
-
-// used by lengthen_toolbar to move an element from the overflow menu
-// to the toolbar
-function su_demenuify_toolbar_element(element)
-{
-	var new_element;
-
-	if (element.id == "su_field")
-	{
-		new_element = element;
-		new_element.collapsed = (new_element.getAttribute("savedhidden") == "true");
-		new_element.removeAttribute("savedhidden");
-	}
-	else if (element.id == "su_mode")
-	{
-		new_element = element;
-		su_get_element("su_mode_label").collapsed = (su_ds.getValue("$icons") == "icons-only");
-	}
-	else if (element.tagName == "splitter")
-	{
-		new_element = element.cloneNode(true);
-		new_element.collapsed = (new_element.getAttribute("savedhidden") == "true");
-		new_element.removeAttribute("savedhidden");
-	}
-	else if (element.id.indexOf("su_separator") == 0)
-	{
-		// These DIVs fix the bug where spurious separators were appearing
-		// after the user Customizes the toolbar area in Firefox.
-		// Analysis:
-		// Customize stores element ids in localstore.rdf, but it doesn't
-		// save the ids of separators (since they have identical 
-		// rendering).  Upon restart, ids duplicated elsewhere by our 
-		// toolbar elements are ignored, but the unlabeled separators
-		// remain where Customize recorded them to be.  Workaround is to
-		// wrap our separators so that an id will be recorded. -- JW
-
-		new_element = document.createElement("div");
-		new_element.id = element.id;
-		var tmp = document.createElement("toolbarseparator");
-		new_element.appendChild(tmp);
-
-		if (element.hasAttribute("savedhidden"))
-			new_element.collapsed = (element.getAttribute("savedhidden") == "true");
-		else
-			new_element.collapsed = element.collapsed;
-	}
-	else if (element.tagName == "toolbarbutton")
-	{
-		new_element = element.cloneNode(true);
-		if (! su_get_label_visibility(element.id, false))
-			new_element.label = "";
-	}
-	else
-	{
-		new_element = element.cloneNode(true);
-//		new_element.collapsed = element.hidden;
-//		new_element.hidden = false;
-	}
-	
-	var next_sibling = su_get_element("su_overflow_menu");
-
-	if (next_sibling.previousSibling.id == "su_overflow_flexbox")
-	{
-		// Skip the flexbox.
-		next_sibling = next_sibling.previousSibling;
-	}
-
-	if (new_element.hasAttribute("savedwidth"))
-		new_element.removeAttribute("savedwidth");
-
-	element.parentNode.removeChild(element);
-	
-	next_sibling.parentNode.insertBefore(new_element, next_sibling);
-	
-	//!!! This may be causing a reflow bug; new width may not be
-	//    set soon enough for it to be used in the reflow calculation.
-	//    -- JW
-	if (new_element.className == "su-showtext-menuified")
-		new_element.className = "su-showtext";
-
-	if (new_element.className == "su-hidetext-menuified")
-		new_element.className = "su-hidetext";
-}
-
-// used by refresh_toolbar_gated() to add or destroy the overflow 
-// flexbox as required
-function su_cleanup_overflow_flexbox()
-{
-	var menu = su_get_element("su_overflow_menu");
-	// The overflow flexbox right-justifies the overflow menu when the 
-	// toolbar elements are in the stumbleupon toolbar or are 
-	// right-justified. -- JW
-	if (((menu.parentNode.id == "su_container") || 
-				(menu.parentNode.id == "su_toolbar_container") || 
-				(menu.parentNode.id == "su_statusbar_container") || 
-				(menu.parentNode.id == "su_otherbar_container") || 
-				(menu.parentNode.id == "su_googlebar_container")) && 
-				(menu.previousSibling.id != "su_overflow_flexbox"))
-	{
-		var flexbox = document.createElement("vbox");
-		flexbox.setAttribute("id", "su_overflow_flexbox");
-		flexbox.setAttribute("flex", "1");
-
-		menu.parentNode.insertBefore(flexbox, menu);
-	}
-	else if ((menu.parentNode.id != "su_container") && 
-				(menu.parentNode.id != "su_toolbar_container") && 
-				(menu.parentNode.id != "su_statusbar_container") &&
-				(menu.parentNode.id != "su_otherbar_container") &&
-				(menu.parentNode.id != "su_googlebar_container") &&
-				(menu.previousSibling.id == "su_overflow_flexbox"))
-	{
-		menu.parentNode.removeChild(menu.previousSibling);
-	}
-}
-
-// used by refresh_toolbar_gated() to make sure the top item in the 
-// overflow menu isn't a menuseparator
-function su_cleanup_overflow_menuseparators()
-{
-	try {
-	var sibling = su_get_element("su_overflow_popup").firstChild;
-
-	var before_first_visible_element = true;
-
-	while (sibling)
-	{
-		if (sibling.collapsed)
-		{
-			sibling = sibling.nextSibling;
-			continue;
-		}
-		else if (sibling.tagName == "menuseparator")
-		{
-			if (before_first_visible_element)
-			{
-				before_first_visible_element = false;
-				sibling.setAttribute("savedhidden", "false");
-				sibling.collapsed = true;
-			}
-			else
-			{
-				if (sibling.hasAttribute("savedhidden"))
-				{
-					sibling.collapsed = (sibling.getAttribute("savedhidden") == "true");
-					sibling.removeAttribute("savedhidden");
-				}
-			}
-		}
-		else
-		{
-			before_first_visible_element = false;
-		}
-		sibling = sibling.nextSibling;
-	}
-	} catch (e) { su_log_error("CLEANUP MENUSEPARATORS", e, su_ds.getValue("@toolbar-position"), su_ds.getValue("@position-group")); }
-}
-
-// handles the popuphiding event for the overflow menu popup; sets a
-// flag that delays toolbar refresh
-function su_handle_popupshowing(event)
-{
-	switch (event.target.id)
-	{
-		case "su_referred_popup":  su_referred_popup_open = true; break;
-		case "su_referral_popup":  su_referral_popup_open = true; break;
-		case "su_mode_more_popup": su_mode_more_popup_open = true; break;
-		case "su_overflow_popup":  su_overflow_popup_open = true; break;
-	}
-}
-
-// handles the popuphidden event for the overflow menu popup; clears
-// a flag that otherwise delays toolbar refresh
-function su_handle_popuphidden(event)
-{
-	switch (event.target.id)
-	{
-		case "su_referred_popup":
-			su_referred_popup_open = false;
-			break;
-		case "su_referral_popup":
-			su_referral_popup_open = false;
-			su_refresh_referral_menu(8);
-			break;
-		case "su_mode_more_popup":
-			su_mode_more_popup_open = false;
-			su_refresh_dyn_channels();
-			break;
-		case "su_overflow_popup":
-			su_overflow_popup_open = false;
-			break;
-	}
-}
-
-function su_show_search_dialog(new_tab)
-{
-	var detail = new Object();
-	detail.query = "";
-	detail.query_default = su_get_element("su_searchbox").value;
-	detail.new_tab = new_tab;
-	if (detail.query_default == su_tag_instructions)
-		detail.query_default = "";
-
-	window.openDialog(
-				"chrome://stumbleupon/content/searchDialog.xul",
-				"",
-				"chrome,dialog,centerscreen,dependent",
-				detail);
-}
-
-function su_search_dialog_accept(detail)
-{
-	su_stumble_in_tag(su_trim(detail.query), detail.new_tab);
-}
-
-// old search implementations
-//var theurl = "http://www.google.ca/search?q=" + escape(query);
-//var theurl = "http://www.google.com/custom?q=" + escape(query) + "&sa=Search&client=pub-1501742633103790&forid=1&channel=3900634926&cof=" + escape("GFNT:#7777cc;GL:0;VLC:663399;AH:left;BGC:white;LC:#0000FF;ALC:#0000FF;T:000000;FORID:1;");
-//var theurl = "http://search.stumbleupon.com/?q=" + escape(query);
-
-
-function su_stumble_in_tag(tag, new_tab)
-{
-	if (tag == "")
-		return;
-
-	// put it in the box
-	su_get_element("su_searchbox").value = tag;
-	su_get_element("su_searchbox").removeAttribute("mode");
-	su_old_search = tag;
-	su_last_typed_tag = 0;
-	su_visited_searchbox = 1;
-
-	// select and do it
-	su_select_topic('TAG_' + tag, tag, new_tab);
-	
-	su_previous_query_category = "TAG_" + tag;
-	
-	su_queries.unshift(tag);
-	
-	var i;
-	for (i = 1; i < su_queries.length; i++)
-	{
-		if (su_queries[i] == tag)
-		{
-			// nuke duplicate
-			su_queries.splice(i, 1);
-			break;
-		}
-	}
-	
-	su_store_queries();
-}
-
-function su_skip_stumble(context)
-{
-//	su_dd("skip");
-	// losing connectivity could cause many skips, so we stop at 3
-	context.skip_count++;
-	
-	if (context.skip_count >= 3)
-		return;
-	
-	su_get_unseen_url(
-			context.user_cat,
-			1,
-			function(unseen, context) { window.stumble_done(unseen, context); },
-			context);
-}
-
-function su_is_404_status(status)
-{
-	if (status == null)
-		return false;
-	
-	switch (status)
-	{
-		case 401:
-		case 403:
-		case 404:
-		case 0:
-			return true;
-	}
-	return false;
-}
-
-var su_StumbleProgressListener = function (url_detail, context)
-{
-	this.url_detail = url_detail;
-	this.context = context;
-	this.skipping_stumble = false;
-}
-
-su_StumbleProgressListener.prototype =
-{
-	QueryInterface: function (iid)
-	{
-		if (!iid.equals(Components.interfaces.nsIWebProgressListener) &&
-				!iid.equals(Components.interfaces.nsISupportsWeakReference) && // not implemented
-				!iid.equals(Components.interfaces.nsISupports))
-		{
-			throw Components.errors.NS_ERROR_NO_INTERFACE;
-		}
-		
-		return this;
-	},
-	
-	onStateChange: function (aWebProgress, aRequest, aStateFlags, aStatus)
-	{
-		const nsIWPL = Components.interfaces.nsIWebProgressListener;
-		var original_url;
-		// do a try, we don't want to mess with state change...
-		try {
-			if (aWebProgress.DOMWindow != aWebProgress.DOMWindow.top)
-				return;
-			
-			aRequest.QueryInterface(Components.interfaces.nsIChannel);
-			
-			original_url = aRequest.originalURI.asciiSpec;
-			
-			if (original_url != this.url_detail.url)
-				return;
-			
-		} catch (e) { return; } // ignore error accessing DOMWindow.top
-		
-		try {
-			if (aStateFlags & nsIWPL.STATE_STOP)
-			{			
-				try {
-					var channel = this.context.target_browser.docShell.currentDocumentChannel;
-					var status = channel.responseStatus;
-					if (su_is_404_status(status))
-					{
-						if ((this.url_detail.cluster_type != 3) &&
-								(this.url_detail.cluster_type != 4))
-						{
-							this.skipping_stumble = true;
-							setTimeout(su_skip_stumble, 0, this.context);
-						}
-						su_report_404(this.url_detail.url, status);
-					}
-				} catch (e) {}
-				this.destroy();
-				return;
-			}
-			
-			if (this.skipping_stumble)
-				return;
-			
-			var redirect_url = aRequest.URI.asciiSpec;
-			
-			if (this.url_detail.redirect_url == redirect_url)
-				return;
-			
-			this.url_detail.redirect_url = redirect_url;
-			
-			su_ds.define("url:url_detail", redirect_url, this.url_detail);
-			
-			var domain = su_get_tld(redirect_url);
-			
-			if ((this.url_detail.cluster_type != 4) && su_is_domain_blocked(domain))
-			{
-				this.skipping_stumble = true;
-				setTimeout(su_skip_stumble, 0, this.context);
-			}
-			else if (domain != this.url_detail.tld)
-			{
-				if ((this.url_detail.cluster_type != 3) && (this.url_detail.cluster_type != 4))
-				{
-					this.skipping_stumble = true;
-					setTimeout(su_skip_stumble, 0, this.context);
-				}
-				su_report_redirect(original_url, 302, redirect_url);
-			}
-		} catch (e) { su_log_error("FILTER ERROR", e); }
-		
-	},
-	
-	destroy: function ()
-	{
-		if (! this.context)
-			return;
-
-		this.context.target_browser.removeProgressListener(this);
-		this.context = null;
-		this.url_detail = null;
-	},
-	
-	onProgressChange: function (aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {},
-	
-	// see: http://developer.mozilla.org/en/docs/nsIDownloadProgressListener#onLocationChange.28.29
-	onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {},
-	
-	onSecurityChange: function (aWebProgress, aRequest, aState) {},
-	
-	// required only for tabbrowser?
-	onLinkIconAvailable: function (aBrowser, aHref) {},
-	
-	// required only for tabbrowser?
-	// also: http://developer.mozilla.org/en/docs/nsIDownloadProgressListener#onLocationChange.28.29
-	onLocationChange: function (aWebProgress, aRequest, aLocation) {}
-}
-
-var su_downloadProgressListener = 
-{
-	QueryInterface : function (iid)
-	{
-		if (!iid.equals(Components.interfaces.nsIWebProgressListener) &&
-			!iid.equals(Components.interfaces.nsISupportsWeakReference) && // not implemented
-			!iid.equals(Components.interfaces.nsISupports))
-		{
-			throw Components.errors.NS_ERROR_NO_INTERFACE;
-		}
-
-		return this;
-	},
-
-	onLocationChange : function(aWebProgress, aRequest, aLocation)
-	{
-		// Supposedly removed in ff3, but it's still being called by
-		// ff3 tabbrowser.
-		// 
-		// See:
-		// http://developer.mozilla.org/en/docs/nsIDownloadProgressListener#onLocationChange.28.29
-		var domWindow = aWebProgress.DOMWindow;
-	
-		// Update urlbar only if a new page was loaded on the primary content area
-		// this helps us weed out frames loading...
-		if (domWindow == domWindow.top && aLocation != null) 
-			su_refresh_pagemeta(false, 1);
-	},
-	
-	onProgressChange : function (aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {},
-	
-	onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus)
-	{
-		const nsIWPL = Components.interfaces.nsIWebProgressListener;
-		
-		// do a try, we don't want to mess with state change...
-		try {
-			if (stumbleid == 0)
-				return;
-			
-			if (aWebProgress.DOMWindow != aWebProgress.DOMWindow.top)
-				return;
-		} catch (e) { return; }
-		
-		if ((aStateFlags & nsIWPL.STATE_START) && (aStateFlags & nsIWPL.STATE_IS_REQUEST))
-		{
-			try {
-				su_prefetcher.pause();
-			} catch (e) { su_log_error("PREFETCHER 2", e); }
-			
-			try {
-				aRequest.QueryInterface(Components.interfaces.nsIChannel);
-			}
-			catch (e) { return; }
-			
-			var redirect_url = aRequest.URI.asciiSpec;
-			var original_url = aRequest.originalURI.asciiSpec;
-			
-			if (original_url == stumbled_url)
-				su_redirect_url = redirect_url;
-						
-			// make sure url is beginning of request!!!!
-			if (original_url.indexOf(su_base_url + "stumble/") == 0)
-			{
-				// pull out the tag...
-				var spliturl = original_url.split("/");
-				if (spliturl.length >= 5)
-				{
-					var tag = spliturl[4];
-					var new_url = su_get_browser_url(null, true);
-					
-					// make sure new_url is "http://www.stumbleupon.com/explore.php"
-					if (new_url.indexOf(su_base_url + "explore.php") == 0)
-					{
-						aRequest.cancel(0);
-										
-						su_unfocus_searchbox(); 
-						
-						var searchtag = (su_ds.isThruDomain(tag)) ? "" : tag;
-
-						// put it in the box
-						su_get_element("su_searchbox").value = searchtag;
-						su_get_element("su_searchbox").removeAttribute("mode");
-						su_old_search = searchtag;
-						su_last_typed_tag = 0;
-						su_visited_searchbox = 1;
-
-						// select and do it
-						setTimeout(su_select_topic, 100, "TAG_" + tag, tag, false);
-					}
-				}
-			}
-			else if (original_url.indexOf(su_base_url + "through.php?") == 0)
-			{
-				aRequest.cancel(0);
-			}
-		}
-		else if ((aStateFlags & nsIWPL.STATE_STOP) && (su_stumble_action_count > 0))
-		{
-// Note: The following causes execution to stop without throwing an
-// error (ref: FF3, linux): 
-//				if (aWebProgress)
-//					aWebProgress.su_loaded = true;
-			try {
-				if (su_ds.getValue("$prefetch")	)
-					su_prefetcher.start();
-			} catch (e) { su_log_error("PREFETCHER 3", e); }
-		}
-
-		
-	},
-
-	onLinkIconAvailable : function(aBrowser, aHref)
-	{},
-
-	onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
-	{
-		try {
-			// Removed in ff3  See:
-			// http://developer.mozilla.org/en/docs/nsIDownloadProgressListener#onStatusChange.28.29		if (aRequest)
-			aRequest.QueryInterface(Components.interfaces.nsIChannel);
-			var original_url = aRequest.originalURI.asciiSpec;
-			
-			// auto-stumble, done in click
-			if (original_url.indexOf(su_base_url + "through.php?") != 0)
-				aRequest.cancel(0);
-		} catch (e) {}
-	},
-
-	onSecurityChange : function(aWebProgress, aRequest, aState)
-	{}
-};
-
-var su_http_observer = 
-{
-	// This is the observerService's observe listener.
-	observe: function(aSubject, aTopic, aData) 
-	{
-		if (aTopic == 'http-on-modify-request') 
-		{
-			//!!! sometimes we get "Components is not defined" here? (why?)
-			if (typeof(Components) != "undefined")
-			{
-				aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
-				this.onModifyRequest(aSubject);
-			}
-		} 
-		else if (aTopic == 'http-on-examine-response') 
-		{
-			//!!! sometimes we get "Components is not defined" here? (why?)
-			if (typeof(Components) != "undefined")
-			{
-				aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
-				this.onExamineResponse(aSubject);
-			}
-		}
-	},
-
-	onModifyRequest : function (oHttp)
-	{
-		var has_version = false;
-		if (su_is_server_page(oHttp.URI.asciiSpec, ""))
-		{
-			has_version = true;
-			oHttp.setRequestHeader("X-SU-Version", su_useragent, 0);
-			if(stumbleid == 0)
-			{
-				var first = su_ds.getValue("@first_version");
-				if(first != "")
-				{
-					first += " " + su_ds.getValue("@first_run_time");
-					oHttp.setRequestHeader("X-SU-First", first, 0);
-				}
-				var nowUtc = su_get_time_s();
-				oHttp.setRequestHeader("X-SU-Client-Time", nowUtc, 0);
-			}
-		}
-
-		if (! su_is_auth_allowed(oHttp.URI.asciiSpec))
-			return;
-	
-		// send authentication headers
-		if (stumbleid == 0)
-		{
-			if (su_host && su_host.dist)
-			{
-				if (! has_version)
-					oHttp.setRequestHeader("X-SU-Version", su_useragent, 0);
-				oHttp.setRequestHeader('X-SU-Dist', su_host.dist, 0);
-			}
-			return;
-		}
-		
-		var url = oHttp.URI.asciiSpec;
-		var sldetail = su_ds.getValue("#sldetail");
-		if (sldetail && (url == sldetail.target))
-		{
-			oHttp.setRequestHeader('X-SU-Sldomain', sldetail.domain, 0);
-			oHttp.setRequestHeader('X-SU-Sltermcount', sldetail.term_count + "", 0);
-			oHttp.setRequestHeader('X-SU-Slfirstpage', ((sldetail.is_first_page) ? 1 : 0) + "", 0);
-			su_ds.setValue("#sldetail", null);
-		}
-		
-		url = url.toLowerCase();
-		
-		// 0 = do not merge header with old headers, replace them
-		oHttp.setRequestHeader('X-SU-Username', stumbleid, 0);
-		oHttp.setRequestHeader('X-SU-Password', stumblepass, 0);
-		if (! has_version)
-			oHttp.setRequestHeader("X-SU-Version", su_useragent, 0);
-		if (su_host && su_host.dist)
-			oHttp.setRequestHeader('X-SU-Dist', su_host.dist, 0);
-		
-		if (url.indexOf(su_serverhttp + "find_friends.php") != -1)
-		{
-			if (url.indexOf("pre3=") != -1)
-			{
-				su_ds.setValue("#find_friends_optin", true);
-				su_ds.setValue("#find_friends_pre", "socialsearch");
-			}
-			else if (url.indexOf("pre=facebook") != -1)
-			{
-				su_ds.setValue("#find_friends_pre", "facebook");
-			}
-		}
-		
-		if (oHttp.requestMethod != "POST")
-			return;
-		
-		if (url.indexOf(su_serverhttp + "thanks.php") == 0)
-		{
-			try {
-				var str = su_get_debug_header();
-				if (str)
-					oHttp.setRequestHeader("X-SU-Debug", str, 0);
-			} catch (e) { su_log_error("DEBUG HEADER", e); }
-			return;
-		}
-		
-		var bug_groups = ["stumbleupon", "help", "bugs", "beta", "firefox", "ie" ];
-		var i;
-		for (i = 0; i < bug_groups.length; i++)
-		{
-			if (url.indexOf("http://" + bug_groups[i] + ".group." + 
-						su_servername + "/forum/") == 0)
-			{
-				try {
-					var str = su_get_debug_header();
-					if (str)
-						oHttp.setRequestHeader("X-SU-Debug", str, 0);
-				} catch (e) { su_log_error("DEBUG HEADER", e); }
-				break;
-			}
-		}
-	},
-	
-	onExamineResponse : function (oHttp)
-	{
-		if (stumbleid == 0)
-			return;
-		
-		//!!! grab oHttp.loadFlags and look for LOAD_FLAGS_IS_REFRESH to grab meta refreshes?
-		var redirect_url = oHttp.URI.asciiSpec;
-		var original_url = oHttp.originalURI.asciiSpec;
-		
-		if (su_log_mimetype)
-			su_log("mimetype", original_url, redirect_url, oHttp.contentType);
-		
-//		if (original_url == "http://media.tumblr.com/mlsyKxOF8fzc9kd1zQ37q9b8o1_500.jpg")
-//			su_dd("response", stumbled_url, original_url, redirect_url);
-		
-		var status = oHttp.responseStatus;
-		if (stumbled_url != "" && original_url == stumbled_url && original_url != redirect_url)
-		{
-//			su_dd("set", 1, originval_url, redirect_url);
-			// we have a stumble that has redirected to another page
-			// NOTE: this will fire once for each redirect in a chain of redirects
-			stumbled_redirect = redirect_url;
-			// su_dp("STUMBLE REDIRECT", "ORIGINAL" + stumbled_url, "REDIRECT " + stumbled_redirect, "STATUS " + status);
-		}
-		
-//		if (original_url == "http://media.tumblr.com/mlsyKxOF8fzc9kd1zQ37q9b8o1_500.jpg")
-//			su_dd("after", stumbled_url, original_url, redirect_url);
-		
-		if (!su_is_server_page(original_url, ""))
-			return;
-		
-		if (status != 200)
-			return;
-		
-		if ((original_url.indexOf(su_serverhttp + "user.php?friend=") == 0) ||
-					(original_url.indexOf(su_serverhttp + "user.php?removefriend=") == 0))
-		{
-			setTimeout(su_get_friends, 0);
-		}
-		else if (original_url.match(/^http:\/\/[^\/]*\/badge\/badge_controller\.php\?a=thumbupurl&u=([^&]+)/))
-		{
-			var badge_match = original_url.match(/^http:\/\/[^\/]*\/badge\/badge_controller\.php\?a=thumbupurl&u=([^&]+)/);			
-			if (badge_match.length < 2)
-				return;
-			var url = decodeURIComponent(badge_match[1]);
-			
-			var url_detail = su_ds.lookup("url:url_detail", url);
-			if (url_detail)
-			{
-				url_detail.rating = 1;
-				su_refresh_pagemeta(12);
-			}
-			su_rate_getmeta(url, true);
-		}
-	}
-};
-
-try {
-	su_service = Components.classes["@stumbleupon.com/stumbleupon-service;1"].getService().wrappedJSObject;
-}
-catch (e) {
-	// seamonkey kludge
-	su_include("chrome://stumbleupon/content/stumbleuponService.js");
-	su_service = new su_Service();
-}
-
-su_service.setAgentDesc(su_useragent);
-su_service.setLogCommunicationEnabled(su_log_communication);
-
-su_service.setLogResourceCFD(su_log_resource_cfd);
-su_service.setMessageLogEnabled(su_enable_message_log);
-su_service.setForceCampusDistEnabled(su_test_campus_dist);
-su_service.setLogErrorDomain(su_servername);
-
-su_ds = su_service.getDatastore();
-	
-su_host = su_service.getHostSpec(navigator);
-
-su_stumbleReporter = su_service.getStumbleReporter();
-
-su_enable_hashed_password = su_host.sha1;
-
-// current_user was used as far back as 4/2004, and ids was used between that and the usage of id_list.
-su_new_install =(!su_ds.isPrefDefined("@first_version") && !su_ds.isPrefDefined("@id_list") && !su_ds.isPrefDefined("@ids") &&
-				 (!su_ds.isPrefDefined("@current_user") || (su_ds.getValue("@current_user") == "")));
-
-var su_useragent = "mozbar " + mozbar_version + " xpi";
-
-su_useragent += " " + su_private_label;
-su_useragent += " " + su_source_label;
-
-var su_verstring = escape(su_useragent);
-
-if (su_new_install)
-{
-	var first_info = su_useragent;
-	var utc = su_get_time_s();
-	su_ds.setValue("@first_version", first_info);
-	su_ds.setValue("@first_run_time", utc);
-	su_ds.setValue("javascript.options.showInConsole", true);
-//		su_ds.setValue("javascript.options.strict", true);
-}
-
-window.addEventListener("load", su_handle_window_load, false);
-window.addEventListener("unload", su_handle_window_unload, false);
-
-su_init_login(false, false);
-
-su_login_initialized = true;
-
-su_migrate_version();
-
-try {
-	su_prefetcher = new su_Prefetcher();
-} catch (e) { su_log_error("INSTANTIATE PREFETCHER", e); }
-
-var su_observer_service = su_get_service(
-			"@mozilla.org/observer-service;1",
-			"nsIObserverService");
-
-// We should move the http and em-action-requested observers into
-// stumbleuponService.js after the FF3 release. -- JW
-
-// Register the request and response observer.
-su_observer_service.addObserver(su_http_observer, "http-on-modify-request", false);
-su_observer_service.addObserver(su_http_observer, "http-on-examine-response", false);
-
-// Register the host observer.
-su_observer_service.addObserver(su_host_observer, "em-action-requested", false);
-
-// Register the global event observer.
-su_observer_service.addObserver(su_event_observer, "su_login", false);
-su_observer_service.addObserver(su_event_observer, "su_logout", false);
-su_observer_service.addObserver(su_event_observer, "su_change-password", false);
-su_observer_service.addObserver(su_event_observer, "su_configure-toolbar", false);
-su_observer_service.addObserver(su_event_observer, "su_referral-menu-dirty", false);
-su_observer_service.addObserver(su_event_observer, "su_update-referral-menu", false);
-su_observer_service.addObserver(su_event_observer, "su_refresh-category-selector", false);
-su_observer_service.addObserver(su_event_observer, "su_dyn-channels-dirty", false);
-su_observer_service.addObserver(su_event_observer, "su_update-dyn-channels", false);
-su_observer_service.addObserver(su_event_observer, "su_schedule-remove-data", false);
-su_observer_service.addObserver(su_event_observer, "su_message-button-click", false);
-
-// su_include extra.js
-su_include("chrome://stumbleupon/content/extra.js");
-
-// Enable sidebar (conversation bar) if needed
-if (su_sidebar_enabled)
-	su_include("chrome://stumbleupon/content/sidebar.js");
-
-
diff --git a/chrome/stumbleupon.jar!/content/stumbleuponOverlay.xul b/chrome/stumbleupon.jar!/content/stumbleuponOverlay.xul
deleted file mode 100644
index ed63174..0000000
--- a/chrome/stumbleupon.jar!/content/stumbleuponOverlay.xul
+++ /dev/null
@@ -1,735 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-
-<?xml-styleshe href="chrome://global/skin/" type="text/css"?>
-<?xml-stylesheet href="chrome://stumbleupon/content/skin/stumbleuponOverlay.css" type="text/css"?>
-
-<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
-
-<overlay id="stumbleuponToolbar" 
-	xmlns:html="http://www.w3.org/1999/xhtml"
-	xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-	xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-	orient="vertical">
-
-
-<popup id="contentAreaContextMenu">
-	<menuitem id="context-photoblog-ilikeit"
-		label="StumbleUpon PhotoBlog It!"
-		image="chrome://stumbleupon/content/skin/thumbup.png"
-		class="menuitem-iconic" 
-		oncommand="su_blogImage(1);"/>
-	<menuitem id="context-stumble-tagit" oncommand="su_contextTag()" insertafter="context-searchselect"/>
-	<menuitem id="context-stumble-search" oncommand="su_contextSearch(event)" insertafter="context-searchselect"/>
-</popup>
-
-<menupopup id="view_toolbars_popup">
-<menuitem id="view_stumble_menuitem" 
-	label="&menu.stumbleupon;"
-	class="menuitem-iconic" 
-	type="checkbox"
-	oncommand="su_toggle_toolbar();"
-	persist="checked"/>
-</menupopup>
-
-<keyset id="mainKeyset">
-	<key id="key_StumbleUpon:ToggleToolbar"
-		keycode="VK_F11"
-		modifiers="accel"
-		command="StumbleUpon:ToggleToolbar"
-		savedcommand="StumbleUpon:ToggleToolbar"/>
-</keyset>
-
-<popupset id="mainPopupSet">
-	<popup id="su_intropopup" style="background:transparent;width:50px;height:50px;">
-	</popup>
-</popupset>
-
-<!--
-<script type="application/x-javascript" src="datastore.js"/>
-<script type="application/x-javascript" src="migrate.js"/>
-<script type="application/x-javascript" src="prefetcher.js"/>
-
-<hbox id="su_toolbar_info"
-	flex="1"
-	hidden="true">
-	<vbox>
-		<spacer height="15px"/>
-		<label value="bob"/>
-	</vbox>
-</hbox>
--->
-<script type="application/x-javascript" src="stumbleuponOverlay.js"/>
-
-<toolbarpalette id="BrowserToolbarPalette">
-	<toolbarbutton id="su_toggle"
-		class="chromeclass-toolbar-additional toolbarbutton-1"
-		label="StumbleUpon"
-		tooltiptext="StumbleUpon"
-		command="StumbleUpon:ToggleToolbar"/>
-	<toolbaritem id="su_toolbaritem">
-		<stack id="su_toolbar-stack"
-			flex="1">
-			<toolbarbutton class="su_toolbar-palette"
-				image="chrome://stumbleupon/skin/thumbup.png"
-				label="StumbleUpon Bar"/>
-			<hbox id="su_toolbar_container"
-				class="su_toolbar-container"
-				flex="1"/>
-			<hbox class="su_toolbar-customize"
-				flex="1">
-				<vbox>
-					<spacer flex="1"/>
-					<image src="chrome://stumbleupon/skin/stumble.png"
-						width="16px"
-						height="16px"/>
-					<spacer flex="1"/>
-				</vbox>
-				<vbox flex="1">
-					<spacer flex="1"/>
-					<label id="su_toolbar_customize_label" value=""/>
-					<spacer flex="1"/>
-				</vbox>
-			</hbox>
-		</stack>	
-	</toolbaritem>
-</toolbarpalette>
-<!--
-			style="min-width:0px; width:0px;"
--->
-
-<toolbox id="navigator-toolbox">
-<toolbar id="stumbleupon" 
-	class="chromeclass-toolbar"
-	persist="collapsed,hidden" 
-	hidden="false" 
-	inherits="hidden"
-	collapsed="false"
-	toolbarname="StumbleUpon Toolbar (Ctrl-F11)"
-	savedtoolbarname="StumbleUpon Toolbar (Ctrl-F11)"
-	accesskey="S"
-	context="toolbar-context-menu"
-	customizable="true"
-	fullscreentoolbar="true"
-	defaultset="su_toolbaritem"
-	currentset="su_toolbaritem"
-	pack="start">
-
-<stringbundleset id="stringbundleset">
-	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
-</stringbundleset>
-
-<commandset id="su_commandset">
-	<command id="StumbleUpon:Stumble"             oncommand="stumble(0);"/>
-	<command id="StumbleUpon:ViewReviews"         oncommand="su_website_info(0,'', 0);"/>
-	<command id="StumbleUpon:RateThumbup"         oncommand="su_rate(1, false, false, false, 0);"/>
-	<command id="StumbleUpon:RateThumbdown"       oncommand="su_rate(0, false, false, false, 0);"/>
-	<command id="StumbleUpon:Tag"                 oncommand="su_handle_tag_command(true);"/>
-	<command id="StumbleUpon:ToggleToolbar"       oncommand="su_toggle_toolbar();"/>
-<!--
-	<command id="StumbleUpon:RateThumbupDetailed" oncommand="su_rate(1, 0, 1, 1);"/>
--->
-</commandset>
-
-<keyset id="su_keyset"/>
-
-<hbox id="su_container"
-	class="chromeclass-toolbar-additional"
-	hidden="true"
-	flex="1">
-
-<toolbarbutton id="su_spacer" label="                    " collapsed="true"/>
-
-<hbox id="su_splitter_first_flexbox"
-	collapsed="true"/>
-
-<splitter id="su_splitter_first"
-	state="open"
-	class="chromeclass-toolbar-additional"
-	collapsed="true"
-	collapse="none"
-	resizebefore="grow"
-	resizeafter="grow"
-	onmousedown="su_handle_splitter_first_mousedown(event);"
-	onmouseup="su_handle_splitter_first_mouseup(event);"/>
-
-<toolbarbutton id="su_start"
-	class="su-showtext"
-	onclick="clickstumble(event)"
-	tooltiptext="Create an account"
-	label="Start Stumbling..."
-	showlabel="Start Stumbling..."
-	image="chrome://stumbleupon/content/skin/stumble.png"/>
-
-<toolbarbutton id="su_stumble"
-	collapsed="true"
-	class="su-showtext"
-	onclick="clickstumble(event)"
-	tooltiptext="Show next page"
-	showlabel="Stumble!"
-	label="Stumble!"
-	image="chrome://stumbleupon/content/skin/stumble.png"
-	image2=""
-	validate2="never"/>
-
-<hbox id="su_login"
-	collapsed="true">
-	<vbox>
-		<spacer flex="1"/>
-		<label value=" or "/>
-		<spacer flex="1"/>
-	</vbox>
-	<toolbarbutton
-		class="su-showtext"
-		image="chrome://stumbleupon/content/skin/icon_signin.png"
-		oncommand="su_show_signin_dialog();"
-		showlabel="Sign-in"
-		label="Sign-in"/>
-</hbox>
-
-<toolbarbutton id="su_referred"
-	collapsed="true"
-	class="su-showtext"
-	onclick="su_handle_referral_throbber_click(event);">
-</toolbarbutton>
-
-<!--
-<vbox id="su_inbox-count"
-	collapsed="true"
-	onclick='su_handle_mode_click(event, "All");'>
-	<spacer flex="1"/>
-	<description id="su_inbox-count-label"
-		class="inbox"
-		value="10"
-		tooltiptext="&button.inbox-count.tooltip;"/>
-	<spacer flex="1"/>
-</vbox>
--->
-
-<toolbarbutton id="su_upgrade"
-	class="su-showtext"
-	collapsed="true"
-	tooltiptext="A new version of StumbleUpon is available.  Click here to upgrade."
-	image="chrome://stumbleupon/content/skin/upgrade.png"
-	oncommand="su_handle_upgrade_command();"/>
-
-<toolbarbutton id="su_thumbup" 
-	class="su-showtext" 
-	collapsed="true" 
-	label="" 
-	showlabel="&button.ilikeit;" 
-	showlabel2="&button.ilikethem;"
-	onclick="su_handle_rate_click(event, 1)" 
-	onclick2="su_handle_rate_click(event, 1)" 
-	tooltiptext="Add to favorites, show more like this" 
-	showtooltiptext="Add to favorites, show more like this"/>
-
-<toolbarbutton id="su_recthumbup" 
-	class="su-showtext" 
-	collapsed="true" 
-	label=""
-	showlabel="&button.ilikeit;" 
-	onclick="su_handle_rate_click(event, 2)" 
-	onclick2="su_handle_rate_click(event, 2)" 
-	tooltiptext="Recthumb 2" 
-	image="chrome://stumbleupon/content/skin/bug.png"/>
-
-<toolbarbutton id="su_thumbdown"
-	class="su-hidetext"
-	collapsed="true"
-	oncommand="if (event.target == this) su_handle_rate_click(event, 0);"
-	oncommand2="if (event.target == this) su_handle_rate_click(event, 0);"
-	onclick=""
-	onclick2=""
-	tooltiptext="&button.notforme.tooltip;"
-	showtooltiptext="&button.notforme.tooltip;">
-	<menupopup onpopupshowing="su_prepare_thumbdown_menu();">
-		<menuitem id="su_thumbdown_menu_notforme"
-			label="&menu.notforme;"
-			type="checkbox" 
-			autocheck="false"
-			tooltiptext=""
-			oncommand="su_handle_rate_click(event, -2);" />
-		<menuseparator />
-		<menuitem id="su_thumbdown_menu_spam"
-			label="&menu.spam;"
-			type="checkbox"
-			authocheck="false"
-			tooltiptext=""
-			oncommand="su_handle_rate_click(event, -5);" />
-		<menuitem id="su_thumbdown_menu_dupe"
-			label="&menu.dupe;"
-			type="checkbox" 
-			autocheck="false"
-			tooltiptext=""
-			oncommand="su_handle_rate_click(event, -3);" />
-		<menuseparator
-			id="su_thumbdown_menu_separator"/>
-		<menuitem id="su_thumbdown_menu_blockdomain"
-			label="&menu.blockdomain;"
-			type="checkbox" 
-			tooltiptext=""
-			oncommand="su_block_domain();" />
-	</menupopup>
-</toolbarbutton>
-
-<div id="su_separator_category"
-	style="height: 100%;"
-	collapsed="true">
-	<toolbarseparator
-		style="height: 100%;"/>
-</div>
-
-<toolbarbutton id="su_category"
-	type="menu"
-	class="su-hideicon-showtext"
-	container="true"
-	collapsed="true"
-	label="All "
-	showlabel="All "
-	tooltiptext="Choose your stumble mode">
-	<menupopup/>
-</toolbarbutton>
-
-<toolbarbutton 
-    id="su_stumble_topic_menu_left" 
-    class="su-hideicon-showtext" 
-    collapsed="true" 
-    label="" 
-    type="menu"
-    tooltiptext="Report a problem with this page">
-    <menupopup id="su_stumble_topic_menu_left_popup">
-    </menupopup>
-</toolbarbutton>
-
-<!--
-<toolbarbutton id="su_thumbdown_dupe"
-	class="su-showtext"
-	collapsed="true"
-	label="Dupe Content"
-	onclick="su_handle_rate_click(event, 3)"
-	image="chrome://stumbleupon/content/skin/thumbdown2.png"/>
-
-<toolbarbutton id="su_thumbdown_targeting"
-	class="su-showtext"
-	collapsed="true"
-	label="Bad Targeting"
-	onclick="su_handle_rate_click(event, 4)"
-	image="chrome://stumbleupon/content/skin/thumbdown2.png"/>
-
-<toolbarbutton id="su_thumbdown_spam"
-	class="su-showtext"
-	collapsed="true"
-	label="Spammy"
-	onclick="su_handle_rate_click(event, 5)"
-	image="chrome://stumbleupon/content/skin/thumbdown2.png"/>
--->
-
-<div id="su_separator2"
-	style="height: 100%;"
-	collapsed="true">
-	<toolbarseparator
-		style="height: 100%;"/>
-</div>
-
-<toolbarbutton id="su_tag2"
-	class="su-hidetext"
-	collapsed="true"
-	label=""
-	showlabel="&button.tag;"
-	tooltiptext="Tag this page"
-	tooltiptext2="Tag this page"
-	image="chrome://stumbleupon/content/skin/tag.png"
-	oncommand="su_handle_tag_command(true);"/>
-
-<toolbarbutton id="su_referral_menu"
-	class="su-showtext"
-	type="menu"
-	collapsed="true"
-	label=""
-	showlabel="Share"
-	container="true"
-	tooltiptext="Send this page to friends"
-	popup="su_referral_popup"
-	image="chrome://stumbleupon/content/skin/icon_tb_share.png">
-</toolbarbutton>
-
-<toolbarbutton id="su_referral_promo"
-	class="su-showtext"
-	collapsed="true"
-	label=""
-	showlabel="Share"
-	tooltiptext="Send this page to a friend"
-	image="chrome://stumbleupon/content/skin/icon_tb_share.png"
-	onclick="su_handle_promo_click(event, 'referral');"/>
-	
-<toolbarbutton id="su_website_info"
-	class="su-showtext"
-	collapsed="true"
-	label="&button.info;"
-	showlabel="&button.info;"
-	tooltiptext="People who like this"
-	image="chrome://stumbleupon/content/skin/bubble.png"
-	onclick="su_handle_website_info_click(event);"/>
-
-<toolbarseparator
-	id="su_separator_promo"
-	collapsed="true"
-	style="height: 100%;"/>
-
-<toolbaritem id="su_field"
-	align="center"
-	collapsed="true"
-	title="search">
-	<popupset id="su_searchpopupset">
-		<popup id="su_searchpopup"/>
-	</popupset>
-	<textbox id="su_searchbox"
-		maxrows="14"
-		flex="1"
-		autocompletepopup="su_searchpopup"
-		inputtooltiptext="Enter Search or Tag Terms separated by Commas"
-		ontextentered="su_handle_searchbox_textentered(arguments[1]);"
-		ontextreverted="su_handle_searchbox_textreverted()"
-		onpagenavigationkey="su_handle_searchbox_pagenavigationkey(arguments[1]);"
-		onkeyup="su_handle_searchbox_keyup(event)"
-		onfocus="su_handle_searchbox_focus()"
-		onclick="su_searchbox_click_kludge('click')"
-		onblur="su_handle_searchbox_blur()"
-		contextitemalabel="Auto"
-		contextitemaaccesskey="A"
-		contextitemaoncommand="su_set_autocomplete_type('auto');"
-		contextitemblabel="&menu.autocompletequeries;"
-		contextitembaccesskey="&menu.autocompletequeries.accesskey;"
-		contextitemboncommand="su_set_autocomplete_type('query');"
-		contextitemclabel="&menu.autocompletetags;"
-		contextitemcaccesskey="&menu.autocompletetags.accesskey;"
-		contextitemconcommand="su_set_autocomplete_type('tag');"
-		reflectpopuplabel="true"
-		sizetopopup="none"
-		minwidth="50"
-		width="150"/>	
-</toolbaritem>
-<!--
-	oninput="su_onSearchInput(event);"
-	oncommand="su_onSearchSelect(event);"
-	onmousedown="su_onSearchBoxMouseDown(event, this);"
-	onclick="su_onSearchBoxClick(event,this);"
--->
-
-<splitter id="su_splitter_search_right"
-	class="su_splitter"
-	state="open"
-	collapsed="true"
-	collapse="none"
-	resizebefore="closest"
-	resizeafter="grow"
-	onmousedown="return su_handle_splitter_search_right_mousedown(event);"
-	onmouseup="return su_handle_splitter_search_right_mouseup(event);"/>
-	
-<toolbarbutton id="su_tag"
-	class="su-hidetext"
-	collapsed="true"
-	label=""
-	showlabel="&button.tag;"
-	tooltiptext="Tag this page"
-	tooltiptext2="Tag this page"
-	image="chrome://stumbleupon/content/skin/tag.png"
-	oncommand="su_handle_tag_command(false);"/>
-
-<toolbarbutton id="su_website_info_promo"
-	class="su-showtext"
-	collapsed="true"
-	label=""
-	showlabel="People who like this"
-	tooltiptext="People who like this"
-	image="chrome://stumbleupon/content/skin/bubble.png"
-	onclick="su_handle_website_info_promo_click(event, 'info');"/>
-	
-<toolbarseparator id="su_separator6"
-	collapsed="true"
-	style="height: 100%;"/>
-
-
-<hbox id="su_mode"
-	collapsed="true">
-	<vbox id="su_mode_label">
-		<spacer flex="1"/>
-		<label value="Channels:"/>
-		<spacer flex="1"/>
-	</vbox>
-	<toolbarbutton id="su_mode_stumbler"
-		class="su-hidetext"
-		su_ismode="1"
-		hidden="true"/>
-	<toolbarbutton id="su_mode_domain"
-		class="su-hidetext"
-		su_ismode="1"
-		hidden="true"
-		validate="never"/>
-	<toolbarbutton id="su_mode_all"
-		class="su-hidetext"
-		hidden="true"
-		su_ismode="1"
-		tooltiptext="Stumble all"
-		image="chrome://stumbleupon/content/skin/all.png"
-		onclick='su_handle_mode_click(event, "All");'/>
-	<toolbarbutton id="su_mode_friends"
-		class="su-hidetext"
-		hidden="true"
-		su_ismode="1"
-		tooltiptext="Sites from people I've subscribed to"
-		image="chrome://stumbleupon/content/skin/icon_tb_people.png"
-		onclick='su_handle_mode_click(event, "Friends");'/>
-	<toolbarbutton id="su_mode_photo"
-		class="su-hidetext"
-		hidden="true"
-		su_ismode="1"
-		tooltiptext="Stumble images"
-		image="chrome://stumbleupon/content/skin/icon_tb_photo_hover.png"
-		onclick='su_handle_mode_click(event, "Photos");'/>
-	<toolbarbutton id="su_mode_video"
-		class="su-hidetext"
-		hidden="true"
-		su_ismode="1"
-		tooltiptext="Stumble videos"
-		image="chrome://stumbleupon/content/skin/video.png"
-		onclick='su_handle_mode_click(event, "Videos");'/>
-	<toolbarbutton id="su_mode_more"
-		type="menu"
-		class="su-hidetext"
-		su_ismode="1"
-		hidden="true"
-		tooltiptext="StumbleThru a website"
-		image="chrome://stumbleupon/content/skin/domain.png">
-		<menupopup id="su_mode_more_popup"
-			onpopupshowing="su_handle_popupshowing(event);"
-			onpopuphidden="su_handle_popuphidden(event);"/>
-	</toolbarbutton>
-	<toolbarbutton id="su_mode_stumblers"
-		class="su-hidetext"
-		hidden="true"
-		su_ismode="1"
-		tooltiptext="Stumble profiles"
-		image="chrome://stumbleupon/content/skin/stumblers.png"
-		onclick='su_handle_mode_click(event, "Profiles");'/>
-	<toolbarbutton id="su_mode_search"
-		class="su-hidetext"
-		hidden="true"
-		su_ismode="1"
-		tooltiptext="Stumble within a query"
-		image="chrome://stumbleupon/content/skin/search.png"
-		onclick='su_handle_mode_click(event, "Search");'/>
-	<toolbarbutton id="su_mode_news"
-		class="su-hidetext"
-		hidden="true"
-		su_ismode="1"
-		tooltiptext="Stumble news items"
-		image="chrome://stumbleupon/content/skin/icon_tb_news.png"
-		onclick='su_handle_mode_click(event, "News");'/>
-	<toolbarbutton id="su_mode_wiki"
-		class="su-hidetext"
-		hidden="true"
-		su_ismode="1"
-		tooltiptext="Stumble wiki articles"
-		image="chrome://stumbleupon/content/skin/wiki.png"
-		onclick='su_handle_mode_click(event, "Wiki");'/>
-</hbox>
-
-<toolbarbutton id="su_sites_promo"
-	class="su-showtext"
-	collapsed="true"
-	label=""
-	showlabel="Sites"
-	tooltiptext="Stumble a website"
-	image="chrome://stumbleupon/content/skin/all_disabled.png"
-	onclick="su_handle_promo_click(event, 'sites');"/>
-	
-<toolbarbutton id="su_video_promo"
-	class="su-showtext"
-	collapsed="true"
-	label=""
-	showlabel="Videos"
-	tooltiptext="Stumble videos"
-	image="chrome://stumbleupon/content/skin/video.png"
-	onclick="su_handle_video_promo_click(event);"/>
-	
-<toolbarseparator id="su_separator4"
-	collapsed="true"
-	style="height: 100%;"/>
-
-<hbox id="su_filter"
-	collapsed="true">
-	<toolbarbutton
-		label="X"
-		image="chrome://stumbleupon/content/skin/x.png"
-		oncommand="su_handle_filter_command(2);"/>
-	<toolbarbutton
-		label="R"
-		image="chrome://stumbleupon/content/skin/r.png"
-		oncommand="su_handle_filter_command(1);"/>
-	<toolbarbutton
-		label="G"
-		image="chrome://stumbleupon/content/skin/g.png"
-		oncommand="su_handle_filter_command(0);"/>
-	<toolbarseparator id="su_separator8"/>
-</hbox>
-
-<toolbarbutton id="firstrater"  class="su-showtext" collapsed="true" label="" tooltiptext="" image="chrome://stumbleupon/content/skin/firstrater.png" onclick="firstrater_func(event);"/>
-
-<toolbarbutton id="su_stumble_topic" class="su-hideicon-showtext" collapsed="true" label="" tooltiptext="This is the category of the current page"/>
-
-<toolbarbutton 
-    id="su_stumble_topic_menu_right" 
-    class="su-hideicon-showtext" 
-    collapsed="true" 
-    label="" 
-    type="menu"
-    tooltiptext="Report a problem with this page">
-    <menupopup id="su_stumble_topic_menu_right_popup">
-    </menupopup>
-</toolbarbutton>
-
-<toolbarseparator id="su_separator7"
-	collapsed="true"
-	style="height: 100%;"/>
-
-<!-- <toolbarbutton id="su_aboutme"  class="su-hidetext" collapsed="true" label="" showlabel="&button.profile;" tooltiptext="&button.profile.tooltip;" image="chrome://stumbleupon/content/skin/profile.png" onclick="su_redir_tab(event,'home');"/> -->
-<toolbarbutton id="su_profile"  class="su-hidetext" collapsed="true" label="" showlabel="Favorites" tooltiptext="Things I have liked" image="chrome://stumbleupon/content/skin/icon_tb_favorites_hover.png" onclick="su_redir_tab(event,'');"/>
-<toolbarbutton id="su_aboutme"  class="su-hidetext" collapsed="true" label="" showlabel="What's New" tooltiptext="Recent activity from subscriptions" image="chrome://stumbleupon/content/skin/icon_tb_user_comment.png" onclick="su_redir_tab(event,'home');"/>
-<toolbarbutton id="su_friends"  class="su-showtext" collapsed="true" label="" showlabel="&button.friends;" tooltiptext="&button.friends.tooltip;" image="chrome://stumbleupon/content/skin/friend.png" onclick="su_redir_tab(event,'friends');"/>
-<toolbarbutton id="su_messages" class="su-hidetext" collapsed="true" label="" showlabel="&button.messages;" tooltiptext="&button.messages.tooltip;" image="chrome://stumbleupon/content/skin/mail.png" onclick="su_redir_tab(event,'inbox');"/>
-
-<toolbarbutton id="su_page_feature_prompt"
-	class="su-showtext"
-	collapsed="true"
-	label=""
-	showlabel="See ratings on results"
-	tooltiptext="See who likes your search results"
-	image="chrome://stumbleupon/content/skin/bubble.png"
-	onclick="su_handle_page_feature_prompt_click(event);"/>
-	
-<toolbarbutton id="su_groups"   class="su-hidetext" collapsed="true" label="" showlabel="&button.groups;" tooltiptext="Group conversations" image="chrome://stumbleupon/content/skin/forum.png" onclick="su_redir_tab(event,'groups');"/>
-<toolbarbutton id="su_network"  class="su-hidetext" collapsed="true" label="" showlabel="Classic Network" tooltiptext="Classic network" image="chrome://stumbleupon/content/skin/stumblers.png" onclick="su_redir_tab(event, 'network');"/>
-<toolbarbutton id="su_forum"    class="su-hidetext" collapsed="true" label="" showlabel="Classic Forums" tooltiptext="Classic forums" image="chrome://stumbleupon/content/skin/legacy_forum.png" onclick="su_redir_tab(event,'forum');"/>
-<toolbarbutton id="su_matches"  class="su-hidetext" collapsed="true" label="" showlabel="Find People" tooltiptext="Browse people by interest, age, location" image="chrome://stumbleupon/content/skin/icon_tb_search_user.png" onclick="su_redir_tab(event,'matches');"/>
-
-<!-- may be obsolete -->
-<toolbarseparator id="su_separator5"
-	collapsed="true"
-	style="height: 100%;"/>
-
-
-<toolbarbutton id="su_sponsor"  class="su-hidetext" collapsed="true" tooltiptext="" image="chrome://stumbleupon/content/skin/sponsor.png" onclick="su_handle_sponsor_click(event);"/>
-
-<toolbarbutton id="su_myinfo" class="su-showtext" collapsed="true" label="" showlabel="Preferences" tooltiptext="&button.edit.tooltip;" image="chrome://stumbleupon/content/skin/editinfo.png" onclick="su_redir_tab(event,'prefs');"/>
-
-<toolbarbutton id="su_bug"
-	class="su-hidetext"
-	collapsed="true"
-	tooltiptext="Submit a bug report via e-mail"
-	image="chrome://stumbleupon/content/skin/bug.png"
-	oncommand="su_handle_bug_command();"/>
-	
-<toolbarbutton id="su_stumble_menu"
-	type="menu"
-	class="su-showtext"
-	container="true"
-	collapsed="true"
-	label="Tools"
-	showlabel="Tools"
-	tooltiptext="Configuration and reporting tools">
-	<menupopup id="su_stumble_popup">
-		<menu id = "su_stumble_report_menu"
-			label="Report this stumble as"
-			tooltiptext="Report...">
-			<menupopup id="su_stumble_report_popup"
-				onpopupshowing="su_prepare_stumble_report_menu(event, null);"/>
-		</menu>
-		<menuitem label="Toolbar Options..." tooltiptext="Change preferences for this toolbar" oncommand="su_preferences();"/>
-		<menuitem label="Account Settings" tooltiptext="Change your StumbleUpon account settings" onclick="su_redir_tab(event,'prefs');"/>
-		<menuitem label="&menu.updateinterests;" tooltiptext="Sign up for new topics" oncommand="su_interests();"/>
-		<menuitem label="View Suggested Topics" tooltiptext="Suggest additional topics you may be interested in" oncommand="su_suggest();"/>
-		<menuitem class="menuitem-iconic" image="chrome://stumbleupon/content/skin/friend.png" label="Find people you know..." tooltiptext="Invite friends to join StumbleUpon" onclick="su_invite(event);"/>
-		<menuseparator/>
-		
-		<menuitem label="Change Password..." tooltiptext="Change your password" oncommand="su_handle_change_password();"/>
-		<menuitem type="checkbox" autocheck="false" checked="true" label="Sign-in..." tooltiptext="Sign in to a different StumbleUpon account" oncommand="su_show_signin_dialog();"/>
-		<menuitem label="Sign-out..." tooltiptext="Sign out from this account" oncommand="su_handle_logout(false);"/>
-	
-		<menuseparator/>
-
-		<menuitem label="Toolbar Guide" tooltiptext="View the toolbar primer" oncommand="getBrowser().contentDocument.location=(su_private_label=='DEB'?su_localdoc + 'guide.html':su_serverhttp + 'guide.html')"/>
-		<menuitem label="Help" tooltiptext="Frequently Asked Questions" oncommand="getBrowser().contentDocument.location=(su_private_label=='DEB'? su_localdoc + 'faq.html' : su_serverhttp + 'faq.html')"/>
-		<menu label="About StumbleUpon" tooltiptext="Get help with StumbleUpon">
-			<menupopup>
-				<menuitem label="&menu.stumblehome;" tooltiptext="StumbleUpon.com Home Page" oncommand="getBrowser().contentDocument.location=su_serverhttp"/>
-				<menuitem label="Help Forum" tooltiptext="Get help from other stumblers" oncommand="getBrowser().contentDocument.location='http://getsatisfaction.com/stumbleupon/products/stumbleupon_stumbleupon_toolbar'"/>
-				<menuitem label="Stumble News" tooltiptext="Read the latest news about StumbleUpon services" oncommand="getBrowser().contentDocument.location=su_serverhttp + 'news.php'"/>
-				<menuitem label="&menu.topstumblers;" tooltiptext="See the most helpful stumblers" oncommand="getBrowser().contentDocument.location=su_serverhttp + 'topstumblers.php'"/>
-				<menuseparator/>
-				<menuitem label="&menu.contact;" tooltiptext="Send questions or comments to StumbleUpon" oncommand="su_feedback();"/>
-				<menuitem label="Privacy Policy" tooltiptext="View StumbleUpon's privacy policy" oncommand="getBrowser().contentDocument.location=su_serverhttp + 'privacy.html'"/>
-				<menuitem label="Toolbar Version" tooltiptext="Your current toolbar version, along with new versions" oncommand="su_about();"/>
-			</menupopup>
-		</menu>
-	</menupopup>
-</toolbarbutton>
-
-<toolbarseparator id="su_separator3"
-	collapsed="true"
-	style="height: 100%;"/>
-
-
-<toolbarbutton id="su_grab"     class="su-showtext" label="G" collapsed="true" tooltiptext="Next" image="chrome://stumbleupon/content/skin/stumble.png" oncommand="su_grab();"/>
-<toolbarbutton id="su_approve"  class="su-showtext" label="OK" collapsed="true" tooltiptext="Approve" image="chrome://stumbleupon/content/skin/thumbup.png" oncommand="su_approve();"/>
-
-<toolbarbutton id="su_idx"                          label="IDX" collapsed="true" tooltiptext="Direct to IDX" image="chrome://stumbleupon/content/skin/thumbup.png" oncommand="toidx();"/>
-<toolbarbutton id="su_tld"                          label="TLD" collapsed="true" tooltiptext="Go to TLD for this page" image="chrome://stumbleupon/content/skin/arrow.png" oncommand="grab_tld();"/>
-
-<toolbarbutton id="su_grab_category"
-	type="menu"
-	class="su-showtext"
-	contain="true"
-	collapsed="true"
-	label='topic'>
-	<menupopup class="topic-selector">
-	</menupopup>
-</toolbarbutton>
-
-<vbox id="su_site-count-box"
-	collapsed="true">
-	<spacer flex="1"/>
-	<description id="su_site-count"
-		class="inbox"
-		value=""
-		tooltiptext=""/>
-	<spacer flex="1"/>
-</vbox>
-
-<toolbarbutton id="su_overflow_menu"
-	type="menu"
-	width="20px"
-	collapsed="true"
-	image="chrome://stumbleupon/content/skin/chevron.png">
-	
-	<menupopup id="su_overflow_popup"
-		onpopupshowing="su_handle_popupshowing(event)"
-		onpopuphidden="su_handle_popuphidden(event)"/>
-	
-</toolbarbutton>
-
-</hbox>
-
-<hbox id="su_render"
-	class="chromeclass-extrachrome"
-	width="0"
-	height="0"/>
-
-</toolbar>
-<toolbar id="su_info_toolbar"
-	class="chromeclass-toolbar"
-	customizable="false"
-	collapsed="true"/>
-</toolbox>
-
-</overlay>
diff --git a/chrome/stumbleupon.jar!/content/stumbleuponService.js b/chrome/stumbleupon.jar!/content/stumbleuponService.js
deleted file mode 100755
index c2c1209..0000000
--- a/chrome/stumbleupon.jar!/content/stumbleuponService.js
+++ /dev/null
@@ -1,885 +0,0 @@
-// component defined in this file
-const su_EXTENSION_ID="{AE93811A-5C9A-4d34-8462-F7B864FC4696}";
-const su_SERVICE_NAME="StumbleUpon Service";
-const su_SERVICE_ID="{b97c288d-917d-4d26-bd24-3adf14f5aea3}";
-const su_SERVICE_CTRID = "@stumbleupon.com/stumbleupon-service;1";
-
-const su_SERVICE_CID = Components.ID(su_SERVICE_ID);
-
-//const SERVICE_CATS = ["app-startup"];
-
-// Factory object
-var su_SERVICE_FACTORY = {
-	_instance: null,
-	
-	createInstance: function (outer, iid)
-	{
-		if (outer != null)
-			throw Components.results.NS_ERROR_NO_AGGREGATION;
-		
-		if (! (iid.equals(Components.interfaces.nsISupports) ||
-				iid.equals(Components.interfaces.nsISupportsWeakReference)))
-			throw Components.results.NS_ERROR_INVALID_ARG;
-		
-		if (! this._instance)
-			this._instance = new su_Service();
-		
-		return this._instance;
-  }
-};
-
-var su_Module = {
-  _registered: false,
-	
-	registerSelf: function(componentManager, fileSpec, location, type)
-	{
-		if (this._registered)
-			return;
-	
-		var registrar = componentManager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
-		
-		registrar.registerFactoryLocation(
-				su_SERVICE_CID,
-				su_SERVICE_NAME,
-				su_SERVICE_CTRID,
-				fileSpec,
-				location,
-				type);
-
-//		const categoryManager = Components.classes['@mozilla.org/categorymanager;1']
-//				.getService(Components.interfaces.nsICategoryManager);
-//		
-//		var i;
-//		for (i = 0; i < SERVICE_CATS.length; i++)
-//		{
-//			categoryManager.addCategoryEntry(
-//					SERVICE_CATS[i],
-//					su_SERVICE_CTRID,
-//					su_SERVICE_CTRID,
-//					true,
-//					true);
-//		}
-
-		this._registered = true;
-  },
-  
-	unregisterSelf: function(componentManager, fileSpec, location)
-	{
-    var registrar = componentManager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
-		
-		registrar.unregisterFactoryLocation(su_SERVICE_CID, fileSpec);
-  },
-
-	getClassObject: function (compMgr, cid, iid)
-	{
-		if (cid.equals(su_SERVICE_CID))
-			return su_SERVICE_FACTORY;
-		
-		if (!iid.equals(Components.interfaces.nsIFactory))
-			throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-		
-		throw Components.results.NS_ERROR_NO_INTERFACE;
-	},
-	
-	canUnload: function(componentManager)
-	{
-		return true;
-	}
-}
-function NSGetModule(componentManager, fileSpec)
-{
-  return su_Module;
-}
-
-var su_Service = function ()
-{
-	this._hostSpec = null;
-	this._datastore = null;
-	this._stumbleReporter = null;
-	this._tldService = null;
-	this._globals = {}; // same as this._datastore.globals
-	this._globals.batched_error_log = "";
-	this._globals.batched_pref_error_log = "";
-	this._startupTimeMs = (new Date()).getTime();
-	this._batchingLog = false;
-	this._blockedLogErrorPending = false;
-	this._messageCount = 0;
-	this._messageLog = "";
-	this._messageLogEnabled = false;
-	this._agentDesc = "";
-	this._refs = [];
-	this._logCommunicationEnabled = false;
-	this._forceCampusDistEnabled = false;
-	this._logErrorDomain = "stumbleupon.com";
-	this._persistLCFD = false;
-}
-su_Service.prototype = 
-{
-	QueryInterface: function (iid)
-	{
-		if (iid.equals(Components.interfaces.nsISupports) ||
-				iid.equals(Components.interfaces.nsISupportsWeakReference))
-			return this;
-		else
-			throw Components.results.NS_ERROR_NO_INTERFACE;
-	},
-
-  get wrappedJSObject() {
-    return this;
-  },
-	
-	_createInstance: function (nsclass, nsinterface)
-	{
-		try {
-			return Components.classes[nsclass].createInstance(Components.interfaces[nsinterface]);
-		} catch (e) {
-			return null;
-		}
-	},
-	
-	_getService: function (nsclass, nsinterface)
-	{
-		try {
-			return Components.classes[nsclass].getService(Components.interfaces[nsinterface]);
-		} catch (e) {
-			return null;
-		}
-	},
-	
-	_loadScript: function (filename)
-	{
-		var uri = "chrome://stumbleupon/content/" + filename;
-		try {
-			this._getService(
-						"@mozilla.org/moz/jssubscript-loader;1",
-						"mozIJSSubScriptLoader")
-						.loadSubScript(uri);
-		}
-		catch (e) {
-			this.logError("INCLUDE", e, uri);
-		}
-	},
-	
-	_addref: function (obj)
-	{
-		this._refs.push(obj);
-	},
-	
-	_release: function (obj)
-	{
-		var i;
-		for (i = 0; i < this._refs.length; i++)
-		{
-			if (this._refs[i] == obj)
-			{
-				this._refs.splice(i, 1);
-				return;
-			}
-		}
-	},
-	
-	_setTimeout: function ()
-	{
-		var timer = this._createInstance(
-						"@mozilla.org/timer;1",
-						"nsITimer");
-		
-		this._addref(timer);
-		var i;
-		var args = [];
-		for (i = 2; i < arguments.length; i++)
-			args.push(arguments[i]);
-
-		var this_ = this;
-		var fn = arguments[0];
-		timer.initWithCallback(
-				{
-					QueryInterface: function (iid) {
-						if (iid.equals(Components.interfaces.nsISupports) ||
-								iid.equals(Components.interfaces.nsITimerCallback))
-							return this;
-						else
-							throw Components.results.NS_ERROR_NO_INTERFACE;
-					},	
-					notify: function (timer) {
-						this_._release(timer);
-						fn.apply(fn, args);
-					}
-				},
-				arguments[1],
-				timer.TYPE_ONE_SHOT);
-		return timer;
-	},
-	
-	_clearTimeout: function (timer)
-	{
-		timer.cancel();
-		this._release(timer);
-	},
-
-	_setInterval: function ()
-	{
-		var timer = this._createInstance(
-						"@mozilla.org/timer;1",
-						"nsITimer");
-		
-		this._addref(timer);
-		var i;
-		var args = [];
-		for (i = 2; i < arguments.length; i++)
-			args.push(arguments[i]);
-
-		var this_ = this;
-		var fn = arguments[0];
-		timer.initWithCallback(
-				{
-					QueryInterface: function (iid) {
-						if (iid.equals(Components.interfaces.nsISupports) ||
-								iid.equals(Components.interfaces.nsITimerCallback))
-							return this;
-						else
-							throw Components.results.NS_ERROR_NO_INTERFACE;
-					},	
-					notify: function (timer) {
-						this_._release(timer);
-						fn.apply(fn, args);
-					}
-				},
-				arguments[1],
-				timer.TYPE_REPEATING_SLACK);
-		return timer;
-	},
-	
-	_clearInterval: function (timer)
-	{
-		timer.cancel();
-		this._release(timer);
-	},
-
-	getErrorObjectDump: function (o)
-	{
-		if (! o)
-			return "\n" + (typeof o);
-		
-		var str = "\n===== dump ===\n"; 
-		var p;
-		for (p in o)
-		{
-			if (p.match(/.*_ERR$/))
-				continue;
-			
-			try {
-				str += "[" + p + "]\n" + o[p] + "\n";
-			}
-			catch (e) {
-				str += "[" + p + "] ERROR\n" + e + "\n";
-			}
-		}
-		str += "========";
-		return str;
-	},
-	
-	getSessionTimeMs: function ()
-	{
-		return (new Date()).getTime() - this._startupTimeMs;
-	},
-	
-	setMessageLogEnabled: function (enabled)
-	{
-		this._messageLogEnabled = enabled;
-	},
-	
-	setLogCommunicationEnabled: function (enabled)
-	{
-		this._logCommunicationEnabled = enabled;
-	},
-	
-	setLogResourceCFD: function (enabled)
-	{
-		this._logResourceCFD = enabled
-	},
-	
-	setAgentDesc: function (desc)
-	{
-		this._agentDesc = desc;
-	},
-	
-	setForceCampusDistEnabled: function (enabled)
-	{
-		this._forceCampusDistEnabled = enabled;	
-	},
-	
-	setLogErrorDomain: function (domain)
-	{
-		this._logErrorDomain = domain;
-	},
-	
-	getWindow: function ()
-	{
-		var enumerator = this._getService(
-				"@mozilla.org/appshell/window-mediator;1",
-				"nsIWindowMediator").getEnumerator("navigator:browser");
-
-		if (! enumerator.hasMoreElements())
-			return null;
-		
-		return enumerator.getNext();
-	},
-	
-	callWindow: function ()
-	{
-		var win = this.getWindow();
-		if (! win)
-			return null;
-		
-		var args = [];
-		var i;
-		for (i = 1; i < arguments.length; i++)
-			args.push(arguments[i]);
-		
-		return win[arguments[0]].apply(win, args);
-	},
-	
-	logError: function ()
-	{
-		var i;
-		var str = "";
-		if (arguments.length != 0)
-		{
-			str += "\n";
-			str += this.getSessionTimeMs() + "\n";
-		}
-		for (i = 0; i < arguments.length; i++)
-		{
-			var type = typeof(arguments[i]);
-			if ((i == 1) && (type != "string") && (type != "number"))
-				str += this.getErrorObjectDump(arguments[i]);
-			
-			else
-				str += "\n" + arguments[i];
-		}
-		
-		this._globals.batched_error_log += (this._globals.batched_error_log == "") ? str : ("\n" + str);
-	
-		if ((this._globals.batched_error_log == "") && (this._globals.batched_pref_error_log == ""))
-			return;
-		
-		// By delaying for 1000 ms, we batch sets of closely spaced errors.
-		if (! this._batchingLog)
-		{
-			this._batchingLog = true;
-			this._blockedLogErrorPending = false;
-			this._setTimeout(function (this_) { this_._logErrorGated(); }, 1000, this);
-		}
-		else if (this._batchingLog && 
-					(! this._blockedLogErrorPending))
-		{
-			// If logging is blocked, push back the logging event. -- JW
-			this._blockedLogErrorPending = true;
-			this._setTimeout(function (this_) { this_._logErrorGated(); }, 1000, this);
-		}
-	},
-
-	_logErrorGated: function ()
-	{
-		if ((this._globals.batched_error_log == "") && (this._globals.batched_pref_error_log == ""))
-		{
-			this._batchingLog = false;
-			return;
-		}
-		
-		var consoleService =
-					Components.classes["@mozilla.org/consoleservice;1"]
-					.getService(Components.interfaces.nsIConsoleService);
-	
-		if (! consoleService)
-			return;
-		
-		var str = "StumbleUpon error message:\n";
-		if (this._datastore)
-			str += this.getHostSpec().desc;
-		str += this._globals.batched_error_log;
-		str += this._globals.batched_pref_error_log;
-		consoleService.logStringMessage(str);
-		
-		if (this._messageLogEnabled)
-		{
-			this._messageCount++;
-			this._messageLog += "\n--- " + this._messageCount;
-			this._messageLog += this._globals.batched_error_log + this._globals.batched_pref_error_log;
-		}
-		
-		var prefService = this._getService(
-					"@mozilla.org/preferences-service;1",
-					"nsIPrefService");
-	
-		var prefBranch = prefService.getBranch("");
-	
-		var errorCount;
-		if (prefBranch.getPrefType("stumble.report_error_count") == 0)
-			errorCount = 0;
-		
-		else
-			errorCount = prefBranch.getIntPref("stumble.report_error_count");
-	
-		errorCount++;
-		prefBranch.setIntPref("stumble.report_error_count", errorCount);
-		prefService.savePrefFile(null);
-		
-		var errorCountMax;
-		if (prefBranch.getPrefType("stumble.report_error_count_max") == 0)
-			errorCountMax = 3;
-		
-		else
-			errorCountMax = prefBranch.getIntPref("stumble.report_error_count_max");
-		
-		if (errorCount <= errorCountMax)
-		{
-			var params = "";
-			params += "host=" + encodeURIComponent(this.getHostSpec().desc);
-			params += "&count=" + errorCount;
-			if (this._datastore)
-			{
-				var userid = this._datastore._userid;
-				if (userid == "")
-					userid = 0;
-				else
-					params += "&password=" + encodeURIComponent(this._datastore.getStoredPassword());
-				params += "&username=" + encodeURIComponent(userid);
-				params += "&nick=" + encodeURIComponent(this._datastore.getValue("$nick"));
-			}
-			else
-			{
-				params += "&username=0";
-			}
-			params += "&version=" + encodeURIComponent(this._agentDesc);
-			
-			var simultPref = (this._globals.batched_pref_error_log == "") ? 0 : 1;
-			var simultOther = (this._globals.batched_error_log == "") ? 0 : 1;
-			
-			if (this._globals.batched_error_log != "")
-			{
-				this.postAsync(
-						this._agentDesc,
-						"http://www." + this._logErrorDomain + "/mozbar_error.php",
-						params +
-							"&pref=0" +
-							"&error=" + encodeURIComponent(this._globals.batched_error_log) + 
-							"&simultpref=" + simultPref,
-						null,
-						null,
-						null);
-			}
-			
-			if (this._globals.batched_pref_error_log != "")
-			{
-				this.postAsync(
-						this._agentDesc,
-						"http://www." + this._logErrorDomain + "/mozbar_error.php",
-						params +
-							"&pref=1" +
-							"&error=" + encodeURIComponent(this._globals.batched_pref_error_log) +
-							"&simultother=" + simultOther,
-						null,
-						null,
-						null);
-			}
-		}
-		this._globals.batched_error_log = "";
-		this._globals.batched_pref_error_log = "";
-		this._batchingLog = false;
-	},
-	
-	dd: function ()
-	{
-		var i;
-		var str = "";
-	
-		for (i = 0; i < arguments.length; i++)
-			str += "\n" + arguments[i];
-	
-		var consoleService = this._getService(
-					"@mozilla.org/consoleservice;1",
-					"nsIConsoleService");
-		consoleService.logStringMessage("StumbleUpon debug message: " + str);
-	},
-	
-	ddf: function ()
-	{
-		var i;
-		var str = "";
-	
-		for (i = 0; i < arguments.length; i++)
-			str += " >" + arguments[i];
-		
-		var ds = this.getDatastore();
-		ds.writeFile(
-				ds.getLegacyNSIFile("stumbledd"),
-				(ds.getTimestampStr() + str + "\n"),
-				true);
-	},
-	
-	postAsync: function (useragent, uri, postdata, timeoutIntervalMs, callback, detail)
-	{
-		if (! postdata)
-			postdata = "";
-		
-		var x = this._createInstance(
-					"@mozilla.org/xmlextras/xmlhttprequest;1",
-					"nsIXMLHttpRequest");
-		var this_ = this;
-		if (callback)
-		{
-			x = x.QueryInterface(Components.interfaces.nsIDOMEventTarget);
-		
-			// This ensures that our detail property doesn't get garbage
-			// collected.  We release in the callback function. -- JW
-			this._addref(x);
-			
-			x.callback = callback;
-			x.addEventListener(
-					"load",
-					function (event) {
-						this_._postAsyncDone(event); },
-					false);
-		}
-		
-		if (detail)
-		{
-			x.detail = detail;
-			// This creates an ugly circular reference that we must be sure
-			// to remove. -- JW
-			x.detail._request = x;
-		}
-		
-//		netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
-		try {
-			x.open("POST", uri, true);
-//			x.setRequestHeader("User-Agent" , useragent);
-			x.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
-		} catch (e) { this.logError("POST ASYNC", e); }
-		x.aborted = false;
-		if (timeoutIntervalMs)
-		{
-			x.done = false;
-			
-			this._setTimeout(
-					function (this_, request) { this_.abortPostAsync(request); },
-					timeoutIntervalMs,
-					this,
-					x);
-		}
-		
-		if (this._logCommunicationEnabled)
-			this.dd("post async", uri, postdata);
-		
-		x.send(postdata);
-	},
-
-	_postAsyncDone: function (event)
-	{
-		var request = event.target;
-		if (request.readyState != 4)
-			return;
-	
-		this._release(request);
-		if (request.detail)
-			delete request.detail._request;
-		var callback = request.callback;
-		callback(request);
-	
-		if (request.status == 200)
-			request.done = true;
-	},
-	
-	abortPostAsync: function (request)
-	{
-		if (request.done)
-			return;
-		
-		request.aborted = true;
-		this._release(request);
-	
-		if (request.detail)
-			delete request.detail._request;
-	
-		request.abort();
-	
-		if (! request.callback) return;
-	
-		var callback = request.callback;
-		callback(request);
-	},
-	
-	getHostSpec: function (optNavigatorObject)
-	{
-		if (this._hostSpec)
-			return this._hostSpec;
-		
-		if (! this._datastore)
-			this.getDatastore();
-		
-		var spec = {};
-		try {
-		
-		const MOZILLA   = "{86c18b42-e466-45a9-ae7a-9b95ba6f5640}";
-		const FIREFOX   = "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
-		const SEAMONKEY = "{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}";
-		const NETSCAPE  = "{3db10fab-e461-4c80-8b97-957ad5f8ea47}";
-		const FLOCK     = "{a463f10c-3994-11da-9945-000d60ca027b}";
-	
-		var os_str = "";
-		if ("@mozilla.org/xre/app-info;1" in Components.classes)
-		{
-			// running under Mozilla 1.8 or later
-			var appinfo = this._getService(
-				"@mozilla.org/xre/app-info;1",
-				"nsIXULAppInfo");
-			
-			spec.id = appinfo.ID;
-			spec.version = appinfo.version;
-			try {
-				appinfo = appinfo.QueryInterface(Components.interfaces.nsIXULRuntime);
-				os_str = appinfo.OS.toLowerCase();
-			}
-			catch (e) {
-				os_str = navigator.userAgent.toLowerCase();
-			}
-		}
-		else
-		{
-			if (optNavigatorObject)
-				os_str = optNavigatorObject.userAgent.toLowerCase();
-			else
-				os_str = "win";
-			
-			try {
-				spec.id = this._datastore.getValue("app.id");
-				spec.version = this._datastore.getValue("app.version");
-			} catch(e) {
-			// very old version
-				spec.id = MOZILLA;
-				spec.version = "0.0";
-			}
-		}
-		spec.win = (os_str.indexOf("win") != -1);
-		spec.mac = ((os_str.indexOf("mac") != -1)  || 
-					(os_str.indexOf("darwin") != -1));
-		
-		spec.mozilla = false;
-		spec.firefox = false;
-		spec.seamonkey = false;
-		spec.netscape = false;
-		spec.flock = false;
-		
-		spec.label = "the browser";
-		switch (spec.id)
-		{
-			case MOZILLA:   spec.mozilla = true;   spec.label = "Mozilla";   break;
-			case FIREFOX:   spec.firefox = true;   spec.label = "Firefox";   break;
-			case SEAMONKEY: spec.seamonkey = true; spec.label = "Seamonkey"; break;
-			case NETSCAPE:  spec.netscape = true;  spec.label = "Netscape";  break;
-			case FLOCK:     spec.flock = true;     spec.label = "Flock";     break;
-		}
-		
-		spec.desc = spec.label.toLowerCase();
-		
-		spec.desc += "/" + spec.version + "/[[" + os_str + "]]";
-		
-		spec.toolkit = spec.firefox || spec.flock || (spec.netscape && 
-				spec.version.match(/^[89]\./));
-		
-		spec.places = (spec.firefox && Components.interfaces.nsINavBookmarksService &&
-				Components.interfaces.nsITaggingService);
-		
-		spec.ff2plus = false;
-		
-		spec.ff3plus = false;
-		
-		try {
-			// introduced in ff 1.5
-			var vc = this._getService(
-					"@mozilla.org/xpcom/version-comparator;1",
-					"nsIVersionComparator");
-			
-			if (vc.compare(spec.version, "2.0") >= 0)
-				spec.ff2plus = true;
-			
-			if (vc.compare(spec.version, "3.0") >= 0)
-				spec.ff3plus = true;
-		} catch (e) {}
-		
-		
-		spec.sha1 = (Components.interfaces.nsICryptoHash) ? true : false;
-		
-	//	var file = this._getService(
-	//				"@mozilla.org/file/directory_service;1",
-	//				"nsIProperties")
-	//				.get("ProfD", Components.interfaces.nsIFile);
-	//
-	//	file.append("extensions");
-	//	file.append("{AE93811A-5C9A-4d34-8462-F7B864FC4696}");
-	//	
-	//	if (file.exists())
-	//		return null;
-		
-		spec.dist = null;
-		if (this._datastore.isPrefDefined("app.distributor.channel"))
-		{
-			var dist = "ff" + this._datastore.getValue("app.distributor.channel");
-			if (dist == "ffcampus")
-				spec.dist = dist;
-		}
-		
-		if (this._forceCampusDistEnabled)
-			spec.dist = "ffcampus";
-		
-		}
-		catch (e) {
-			spec.desc = os_str;
-		}
-	
-		if (optNavigatorObject)
-			this._hostSpec = spec;
-		
-		return spec;
-	},
-	
-	getDatastore: function ()
-	{
-		if (this._datastore)
-			return this._datastore;
-		
-		this._loadScript("datastore.js");
-		
-		var enabledb = (Components.interfaces.nsINavBookmarksService 
-				&& Components.interfaces.nsITaggingService); 
-		
-		if (enabledb) 
-			this._loadScript("DatabaseConnection.js"); 
-		
-		this._datastore = new su_Datastore(this, enabledb);
-		
-		return this._datastore;
-	},
-	
-	getStumbleReporter: function ()
-	{
-		if (this._stumbleReporter)
-			return this._stumbleReporter;
-		
-		this._loadScript("stumbleReporter.js"); 
-
-		this._stumbleReporter = new su_StumbleReporter(this);
-
-		return this._stumbleReporter;
-	},
-	
-	getEffectiveTLD: function (url)
-	{
-		if (! url.match(/^(http:|https:|ftp:)/))
-			return null;
-		
-		var spliturl = url.split("/");
-		if (spliturl.length < 3)
-			return null;
-		
-		var alt = spliturl[2].match(/([^\.]*\.homeip\.net|[^\.]*\.stumble\.net)$/);
-		if (alt)
-			return alt[1];
-		
-		if (! this._tldService)
-		{
-			if (Components.interfaces.nsIEffectiveTLDService)
-			{
-				this._tldService = this._getService(
-						"@mozilla.org/network/effective-tld-service;1",
-						"nsIEffectiveTLDService");
-			}
-			else
-			{
-				this._loadScript("tldEmulation.js");
-				this._tldService = su_EmulatedTLDService;
-			}
-		}
-		
-		var out = null;
-		
-		try {
-			out = this._tldService.getBaseDomainFromHost(spliturl[2], 0);
-		} catch (e) {}
-		return out;
-	},
-	
-	getSha1: function (str) 
-	{
-		var engine;
-		try {
-			engine = this._createInstance(
-						"@mozilla.org/security/hash;1",
-						"nsICryptoHash");
-			
-			if (! engine)
-				return null;
-			
-			engine.init(engine.SHA1);
-			var charcodes = new Array();
-			for (var i = 0; i < str.length; i++)
-				charcodes.push(str.charCodeAt(i));
-		
-			engine.update(charcodes, str.length);
-			return engine.finish(true);
-		}
-		catch (e) {
-			return null;
-		}
-	}
-};
-
-function su_dd()
-{
-	var service;
-	try {
-		service = Components.classes["@stumbleupon.com/stumbleupon-service;1"].getService().wrappedJSObject;
-	}
-	catch (e) {
-		service = su_service;
-	}
-	
-	service.dd.apply(service, arguments);
-}
-
-var su_log = su_dd;
-
-function su_ddf()
-{
-	var service;
-	try {
-		service = Components.classes["@stumbleupon.com/stumbleupon-service;1"].getService().wrappedJSObject;
-	}
-	catch (e) {
-		service = su_service;
-	}
-	
-	service.ddf.apply(service, arguments);
-}
-
-var su_logf = su_ddf;
-
-function su_dump_object(o)
-{
-	var str = "";
-	var p;
-	
-	for (p in o)
-	{
-		try {
-			str += "[" + p + "]\n" + o[p] + "\n\n";
-		}
-		catch (e) {
-			str += "[" + p + "] ERROR\n" + e + "\n\n";
-		}
-	}
-	
-	su_dd(str);
-}
diff --git a/chrome/stumbleupon.jar!/locale/de-DE/contents.rdf b/chrome/stumbleupon.jar!/locale/de-DE/contents.rdf
deleted file mode 100755
index 85d7d2c..0000000
--- a/chrome/stumbleupon.jar!/locale/de-DE/contents.rdf
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0"?>
-<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-         xmlns:chrome="http://www.mozilla.org/rdf/chrome#">
-
-  <!-- list all the packages being supplied by this jar -->
-  <RDF:Seq about="urn:mozilla:locale:root">
-    <RDF:li resource="urn:mozilla:locale:de-DE"/>
-  </RDF:Seq>
-
-  <!-- locale information -->
-  <RDF:Description about="urn:mozilla:locale:de-DE"
-        chrome:displayName="Deutsch (Germany)"
-        chrome:author="stumbleupon.mozdev.org"
-        chrome:name="de-DE">
-    <chrome:packages>
-      <RDF:Seq about="urn:mozilla:locale:de-DE:packages">
-        <RDF:li resource="urn:mozilla:locale:de-DE:stumbleupon"/>
-      </RDF:Seq>
-    </chrome:packages>
-  </RDF:Description>
-
-  <!-- Version Information. -->
-  <RDF:Description about="urn:mozilla:locale:de-DE:stumbleupon"
-	chrome:localeVersion="1.4"/>
-</RDF:RDF>
diff --git a/chrome/stumbleupon.jar!/locale/en-US/stumbleupon.dtd b/chrome/stumbleupon.jar!/locale/en-US/stumbleupon.dtd
deleted file mode 100644
index 77ac6b7..0000000
--- a/chrome/stumbleupon.jar!/locale/en-US/stumbleupon.dtd
+++ /dev/null
@@ -1,140 +0,0 @@
-<!ENTITY button.notforme "">
-<!ENTITY button.notforme.tooltip "No more like this">
-<!ENTITY button.ilikeit "I like it!">
-<!ENTITY button.ilikethem "I like them!">
-<!ENTITY button.ilikeit.tooltip "Share this Page!">
-<!ENTITY button.info "Info">
-<!ENTITY button.info.tooltip "Reviews of this Page">
-<!ENTITY button.tag "Tag">
-<!ENTITY button.tag.tooltip "Enter text then Click to Tag this Page">
-<!ENTITY button.forum "Forum">
-<!ENTITY button.forum.tooltip "Forums">
-<!ENTITY button.friends "Stumblers">
-<!ENTITY button.friends.tooltip "Your Stumblers">
-<!ENTITY button.network "Network">
-<!ENTITY button.network.tooltip "My Network">
-<!ENTITY button.pages "Pages">
-<!ENTITY button.pages.tooltip "My Pages">
-<!ENTITY button.messages "Inbox">
-<!ENTITY button.messages.tooltip "Inbox">
-<!ENTITY button.matches "Matches">
-<!ENTITY button.matches.tooltip "Matches">
-<!ENTITY button.profile "Profile">
-<!ENTITY button.profile.tooltip "Profile">
-<!ENTITY button.groups "Groups">
-<!ENTITY button.groups.tooltip "Groups">
-<!ENTITY button.edit "Prefs">
-<!ENTITY button.edit.tooltip "Preferences">
-<!ENTITY button.email "Email">
-<!ENTITY button.email.tooltip "Email Page to...">
-<!ENTITY button.selector.tooltip "Within">
-
-<!ENTITY button.referral "Share">
-<!ENTITY button.referral.tooltip "Send this Page to">
-<!ENTITY button.inbox-count.tooltip "Pages Waiting">
-
-<!ENTITY button.menu "Menu">
-
-<!ENTITY menu.notforme "Not-for-me">
-<!ENTITY menu.spam "Report Spam">
-<!ENTITY menu.dupe "Duplicate Content">
-<!--<!ENTITY menu.saturation "Too much like this lately">-->
-<!ENTITY menu.blockdomain "Block website: ''">
-
-<!ENTITY menu.stumbleupon "StumbleUpon Toolbar">
-<!ENTITY button.stumble.tooltip "Show Next Site">
-<!ENTITY button.sponsor "Sponsor">
-<!ENTITY button.menu.tooltip "Stumble Menu">
-<!ENTITY menu.newemail "New Email Address...">
-<!ENTITY menu.changeemail "Change My Email...">
-<!ENTITY menu.suggestedtopics "Suggested Topics">
-<!ENTITY menu.invitefriends "Invite Friends">
-<!ENTITY menu.updateinterests "Update Topics">
-<!ENTITY menu.updateinfo "Preferences">
-<!ENTITY menu.mystumblers "Network">
-<!ENTITY menu.myprofile "Reviews">
-<!ENTITY menu.topstumblers "Top Stumblers">
-<!ENTITY menu.forums "Community Forums">
-<!ENTITY menu.chat "Chat">
-<!ENTITY menu.toolbaroptions "Toolbar Options">
-<!ENTITY menu.changeuser "Sign-in">
-<!ENTITY menu.changepassword "Change Password">
-<!ENTITY menu.stumblehistory "Stumble History">
-<!ENTITY menu.greatsites "My Favorites">
-<!ENTITY menu.clearhistory "Clear History">
-<!ENTITY menu.report "Report Last Stumble">
-<!ENTITY menu.reportspam "as Spam">
-<!ENTITY menu.report404 "as 404">
-<!ENTITY menu.version "Toolbar Version">
-<!ENTITY menu.help "Help">
-<!ENTITY menu.faq "FAQ">
-<!ENTITY menu.uninstall "Uninstall">
-<!ENTITY menu.privacy "Privacy Policy">
-<!ENTITY menu.stumblehome "StumbleUpon Home">
-<!ENTITY menu.donate "Upgrade Now">
-<!ENTITY menu.contact "Contact Us">
-<!ENTITY menu.logout "Sign-out">
-
-<!ENTITY menu.autocompletequeries "Autocomplete Search Queries">
-<!ENTITY menu.autocompletequeries.accesskey "S">
-<!ENTITY menu.autocompletetags "Autocomplete Tags">
-<!ENTITY menu.autocompletetags.accesskey "T">
-
-<!ENTITY cutCmd.label "Cut">
-<!ENTITY cutCmd.accesskey "t">
-<!ENTITY copyCmd.label "Copy">
-<!ENTITY copyCmd.accesskey "c">
-<!ENTITY pasteCmd.label "Paste">
-<!ENTITY pasteCmd.accesskey "p">
-<!ENTITY undoCmd.label "Undo">
-<!ENTITY undoCmd.accesskey "u">
-<!ENTITY selectAllCmd.label "Select All">
-<!ENTITY selectAllCmd.accesskey "a">
-<!ENTITY deleteCmd.label "Delete">
-<!ENTITY deleteCmd.accesskey "d">
-
-<!ENTITY caption.appearance "Appearance">
-<!ENTITY radio.texticons "Text and Icons">
-<!ENTITY radio.iconsonly "Icons Only">
-<!ENTITY radio.extratext "Extra Text">
-<!ENTITY button.showtopics "Show Topic Menu">
-<!ENTITY button.showemail "Show Email">
-<!ENTITY button.showinfo "Show Page Review">
-<!ENTITY button.showsearch "Show Search Box">
-<!ENTITY button.showtag "Show Tag Button">
-<!ENTITY button.showstumblers "Show Network">
-<!ENTITY button.showprofile "Show Pages">
-<!ENTITY button.showeditinfo "Show Prefs">
-<!ENTITY button.showforums "Show Forums">
-<!ENTITY button.showfriends "Show Stumblers">
-<!ENTITY button.showaboutme "Show Profile">
-<!ENTITY button.showmatches "Show Matches">
-<!ENTITY button.showgroups "Show Groups">
-<!ENTITY button.showmessages "Show Inbox">
-<!ENTITY button.showreferral "Show Share">
-<!ENTITY caption.stumblerate "Stumble After Rating">
-<!ENTITY button.stumblenotforme "Not-for-me">
-<!ENTITY button.stumbleilikeit "I like it!">
-<!ENTITY caption.other "Other">
-<!ENTITY button.searchplugin "Include StumbleUpon in Search Engines">
-<!ENTITY button.prefetch "Prefetch Stumbles (makes stumbling faster)">
-<!ENTITY button.commentfirstrating "Show Comment Box if you Rate a New Site">
-<!ENTITY button.reviewnewwindow "Show Page Review in New Tab">
-<!ENTITY button.ratenewwindow "Show Page Reviews after Rating">
-<!ENTITY button.searchnewwindow "Show Search Results in New Tab">
-<!ENTITY button.stumbletopics "Show Topic for Stumble">
-<!ENTITY label.autocomplete "Auto-complete Search Box with:">
-<!ENTITY radio.queries "Search Queries">
-<!ENTITY radio.tags "Tags">
-<!ENTITY button.clearhistoryonexit "Clear Search History on Exit">
-
-<!ENTITY caption.searchlinks "SearchLinks">
-<!ENTITY button.showsearchlinks "Show SearchLinks">
-<!ENTITY button.searchlinklogos "Show Logos on SearchLinks">
-
-<!ENTITY button.tv "Add to my TV Shows">
-<!ENTITY button.music "Add to my Music">
-<!ENTITY button.movie "Add to my Movies">
-<!ENTITY button.book "Add to my Books">
-
-<!ENTITY dialog.keyPreferenceDialog.title "StumbleUpon Keyboard Shortcuts">
diff --git a/chrome/stumbleupon.jar!/locale/en-US/stumbleupon.properties b/chrome/stumbleupon.jar!/locale/en-US/stumbleupon.properties
deleted file mode 100644
index 6dbb2a4..0000000
--- a/chrome/stumbleupon.jar!/locale/en-US/stumbleupon.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-menu.anytopic=All
-menu.mynews=News
-menu.addmoretopics=Update Topics
diff --git a/chrome/stumbleupon.jar!/locale/fr-FR/contents.rdf b/chrome/stumbleupon.jar!/locale/fr-FR/contents.rdf
deleted file mode 100644
index d4f335f..0000000
--- a/chrome/stumbleupon.jar!/locale/fr-FR/contents.rdf
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0"?>
-<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-         xmlns:chrome="http://www.mozilla.org/rdf/chrome#">
-
-  <!-- list all the packages being supplied by this jar -->
-  <RDF:Seq about="urn:mozilla:locale:root">
-    <RDF:li resource="urn:mozilla:locale:fr-FR"/>
-  </RDF:Seq>
-
-  <!-- locale information -->
-  <RDF:Description about="urn:mozilla:locale:fr-FR"
-        chrome:displayName="Francais (France)"
-        chrome:author="stumbleupon.mozdev.org"
-        chrome:name="fr-FR">
-    <chrome:packages>
-      <RDF:Seq about="urn:mozilla:locale:fr-FR:packages">
-        <RDF:li resource="urn:mozilla:locale:fr-FR:stumbleupon"/>
-      </RDF:Seq>
-    </chrome:packages>
-  </RDF:Description>
-
-  <!-- Version Information. -->
-  <RDF:Description about="urn:mozilla:locale:fr-FR:stumbleupon"
-	chrome:localeVersion="1.4"/>
-</RDF:RDF>
diff --git a/chrome/stumbleupon.jar!/locale/fr-FR/stumbleupon.dtd b/chrome/stumbleupon.jar!/locale/fr-FR/stumbleupon.dtd
deleted file mode 100644
index 77ac6b7..0000000
--- a/chrome/stumbleupon.jar!/locale/fr-FR/stumbleupon.dtd
+++ /dev/null
@@ -1,140 +0,0 @@
-<!ENTITY button.notforme "">
-<!ENTITY button.notforme.tooltip "No more like this">
-<!ENTITY button.ilikeit "I like it!">
-<!ENTITY button.ilikethem "I like them!">
-<!ENTITY button.ilikeit.tooltip "Share this Page!">
-<!ENTITY button.info "Info">
-<!ENTITY button.info.tooltip "Reviews of this Page">
-<!ENTITY button.tag "Tag">
-<!ENTITY button.tag.tooltip "Enter text then Click to Tag this Page">
-<!ENTITY button.forum "Forum">
-<!ENTITY button.forum.tooltip "Forums">
-<!ENTITY button.friends "Stumblers">
-<!ENTITY button.friends.tooltip "Your Stumblers">
-<!ENTITY button.network "Network">
-<!ENTITY button.network.tooltip "My Network">
-<!ENTITY button.pages "Pages">
-<!ENTITY button.pages.tooltip "My Pages">
-<!ENTITY button.messages "Inbox">
-<!ENTITY button.messages.tooltip "Inbox">
-<!ENTITY button.matches "Matches">
-<!ENTITY button.matches.tooltip "Matches">
-<!ENTITY button.profile "Profile">
-<!ENTITY button.profile.tooltip "Profile">
-<!ENTITY button.groups "Groups">
-<!ENTITY button.groups.tooltip "Groups">
-<!ENTITY button.edit "Prefs">
-<!ENTITY button.edit.tooltip "Preferences">
-<!ENTITY button.email "Email">
-<!ENTITY button.email.tooltip "Email Page to...">
-<!ENTITY button.selector.tooltip "Within">
-
-<!ENTITY button.referral "Share">
-<!ENTITY button.referral.tooltip "Send this Page to">
-<!ENTITY button.inbox-count.tooltip "Pages Waiting">
-
-<!ENTITY button.menu "Menu">
-
-<!ENTITY menu.notforme "Not-for-me">
-<!ENTITY menu.spam "Report Spam">
-<!ENTITY menu.dupe "Duplicate Content">
-<!--<!ENTITY menu.saturation "Too much like this lately">-->
-<!ENTITY menu.blockdomain "Block website: ''">
-
-<!ENTITY menu.stumbleupon "StumbleUpon Toolbar">
-<!ENTITY button.stumble.tooltip "Show Next Site">
-<!ENTITY button.sponsor "Sponsor">
-<!ENTITY button.menu.tooltip "Stumble Menu">
-<!ENTITY menu.newemail "New Email Address...">
-<!ENTITY menu.changeemail "Change My Email...">
-<!ENTITY menu.suggestedtopics "Suggested Topics">
-<!ENTITY menu.invitefriends "Invite Friends">
-<!ENTITY menu.updateinterests "Update Topics">
-<!ENTITY menu.updateinfo "Preferences">
-<!ENTITY menu.mystumblers "Network">
-<!ENTITY menu.myprofile "Reviews">
-<!ENTITY menu.topstumblers "Top Stumblers">
-<!ENTITY menu.forums "Community Forums">
-<!ENTITY menu.chat "Chat">
-<!ENTITY menu.toolbaroptions "Toolbar Options">
-<!ENTITY menu.changeuser "Sign-in">
-<!ENTITY menu.changepassword "Change Password">
-<!ENTITY menu.stumblehistory "Stumble History">
-<!ENTITY menu.greatsites "My Favorites">
-<!ENTITY menu.clearhistory "Clear History">
-<!ENTITY menu.report "Report Last Stumble">
-<!ENTITY menu.reportspam "as Spam">
-<!ENTITY menu.report404 "as 404">
-<!ENTITY menu.version "Toolbar Version">
-<!ENTITY menu.help "Help">
-<!ENTITY menu.faq "FAQ">
-<!ENTITY menu.uninstall "Uninstall">
-<!ENTITY menu.privacy "Privacy Policy">
-<!ENTITY menu.stumblehome "StumbleUpon Home">
-<!ENTITY menu.donate "Upgrade Now">
-<!ENTITY menu.contact "Contact Us">
-<!ENTITY menu.logout "Sign-out">
-
-<!ENTITY menu.autocompletequeries "Autocomplete Search Queries">
-<!ENTITY menu.autocompletequeries.accesskey "S">
-<!ENTITY menu.autocompletetags "Autocomplete Tags">
-<!ENTITY menu.autocompletetags.accesskey "T">
-
-<!ENTITY cutCmd.label "Cut">
-<!ENTITY cutCmd.accesskey "t">
-<!ENTITY copyCmd.label "Copy">
-<!ENTITY copyCmd.accesskey "c">
-<!ENTITY pasteCmd.label "Paste">
-<!ENTITY pasteCmd.accesskey "p">
-<!ENTITY undoCmd.label "Undo">
-<!ENTITY undoCmd.accesskey "u">
-<!ENTITY selectAllCmd.label "Select All">
-<!ENTITY selectAllCmd.accesskey "a">
-<!ENTITY deleteCmd.label "Delete">
-<!ENTITY deleteCmd.accesskey "d">
-
-<!ENTITY caption.appearance "Appearance">
-<!ENTITY radio.texticons "Text and Icons">
-<!ENTITY radio.iconsonly "Icons Only">
-<!ENTITY radio.extratext "Extra Text">
-<!ENTITY button.showtopics "Show Topic Menu">
-<!ENTITY button.showemail "Show Email">
-<!ENTITY button.showinfo "Show Page Review">
-<!ENTITY button.showsearch "Show Search Box">
-<!ENTITY button.showtag "Show Tag Button">
-<!ENTITY button.showstumblers "Show Network">
-<!ENTITY button.showprofile "Show Pages">
-<!ENTITY button.showeditinfo "Show Prefs">
-<!ENTITY button.showforums "Show Forums">
-<!ENTITY button.showfriends "Show Stumblers">
-<!ENTITY button.showaboutme "Show Profile">
-<!ENTITY button.showmatches "Show Matches">
-<!ENTITY button.showgroups "Show Groups">
-<!ENTITY button.showmessages "Show Inbox">
-<!ENTITY button.showreferral "Show Share">
-<!ENTITY caption.stumblerate "Stumble After Rating">
-<!ENTITY button.stumblenotforme "Not-for-me">
-<!ENTITY button.stumbleilikeit "I like it!">
-<!ENTITY caption.other "Other">
-<!ENTITY button.searchplugin "Include StumbleUpon in Search Engines">
-<!ENTITY button.prefetch "Prefetch Stumbles (makes stumbling faster)">
-<!ENTITY button.commentfirstrating "Show Comment Box if you Rate a New Site">
-<!ENTITY button.reviewnewwindow "Show Page Review in New Tab">
-<!ENTITY button.ratenewwindow "Show Page Reviews after Rating">
-<!ENTITY button.searchnewwindow "Show Search Results in New Tab">
-<!ENTITY button.stumbletopics "Show Topic for Stumble">
-<!ENTITY label.autocomplete "Auto-complete Search Box with:">
-<!ENTITY radio.queries "Search Queries">
-<!ENTITY radio.tags "Tags">
-<!ENTITY button.clearhistoryonexit "Clear Search History on Exit">
-
-<!ENTITY caption.searchlinks "SearchLinks">
-<!ENTITY button.showsearchlinks "Show SearchLinks">
-<!ENTITY button.searchlinklogos "Show Logos on SearchLinks">
-
-<!ENTITY button.tv "Add to my TV Shows">
-<!ENTITY button.music "Add to my Music">
-<!ENTITY button.movie "Add to my Movies">
-<!ENTITY button.book "Add to my Books">
-
-<!ENTITY dialog.keyPreferenceDialog.title "StumbleUpon Keyboard Shortcuts">
diff --git a/chrome/stumbleupon.jar!/locale/fr-FR/stumbleupon.properties b/chrome/stumbleupon.jar!/locale/fr-FR/stumbleupon.properties
deleted file mode 100644
index 6dbb2a4..0000000
--- a/chrome/stumbleupon.jar!/locale/fr-FR/stumbleupon.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-menu.anytopic=All
-menu.mynews=News
-menu.addmoretopics=Update Topics
diff --git a/components/stumbleuponService.js b/components/stumbleuponService.js
old mode 100755
new mode 100644
index c2c1209..d36cb16
--- a/components/stumbleuponService.js
+++ b/components/stumbleuponService.js
@@ -1,15 +1,26 @@
-// component defined in this file
-const su_EXTENSION_ID="{AE93811A-5C9A-4d34-8462-F7B864FC4696}";
-const su_SERVICE_NAME="StumbleUpon Service";
-const su_SERVICE_ID="{b97c288d-917d-4d26-bd24-3adf14f5aea3}";
-const su_SERVICE_CTRID = "@stumbleupon.com/stumbleupon-service;1";
+//
+// The StumbleUpon component is defined in this file
+//
 
-const su_SERVICE_CID = Components.ID(su_SERVICE_ID);
+if(typeof(StumbleGlobals) == "undefined")
+{
+	var StumbleGlobals = {};
+}
+
+StumbleGlobals.EXTENSION_ID="{AE93811A-5C9A-4d34-8462-F7B864FC4696}";
+StumbleGlobals.SERVICE_NAME="StumbleUpon Service";
+StumbleGlobals.SERVICE_ID="{b97c288d-917d-4d26-bd24-3adf14f5aea3}";
+StumbleGlobals.SERVICE_CTRID = "@stumbleupon.com/stumbleupon-service;1";
+
+StumbleGlobals.SERVICE_CID = Components.ID(StumbleGlobals.SERVICE_ID);
+
+if(Components.utils && Components.utils.import)
+	Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 //const SERVICE_CATS = ["app-startup"];
 
 // Factory object
-var su_SERVICE_FACTORY = {
+StumbleGlobals.SERVICE_FACTORY = {
 	_instance: null,
 	
 	createInstance: function (outer, iid)
@@ -22,13 +33,13 @@ var su_SERVICE_FACTORY = {
 			throw Components.results.NS_ERROR_INVALID_ARG;
 		
 		if (! this._instance)
-			this._instance = new su_Service();
+			this._instance = new StumbleGlobals.Service();
 		
 		return this._instance;
   }
 };
 
-var su_Module = {
+StumbleGlobals.Module = {
   _registered: false,
 	
 	registerSelf: function(componentManager, fileSpec, location, type)
@@ -39,9 +50,9 @@ var su_Module = {
 		var registrar = componentManager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
 		
 		registrar.registerFactoryLocation(
-				su_SERVICE_CID,
-				su_SERVICE_NAME,
-				su_SERVICE_CTRID,
+				StumbleGlobals.SERVICE_CID,
+				StumbleGlobals.SERVICE_NAME,
+				StumbleGlobals.SERVICE_CTRID,
 				fileSpec,
 				location,
 				type);
@@ -54,8 +65,8 @@ var su_Module = {
 //		{
 //			categoryManager.addCategoryEntry(
 //					SERVICE_CATS[i],
-//					su_SERVICE_CTRID,
-//					su_SERVICE_CTRID,
+//					StumbleGlobals.SERVICE_CTRID,
+//					StumbleGlobals.SERVICE_CTRID,
 //					true,
 //					true);
 //		}
@@ -67,13 +78,13 @@ var su_Module = {
 	{
     var registrar = componentManager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
 		
-		registrar.unregisterFactoryLocation(su_SERVICE_CID, fileSpec);
+		registrar.unregisterFactoryLocation(StumbleGlobals.SERVICE_CID, fileSpec);
   },
 
 	getClassObject: function (compMgr, cid, iid)
 	{
-		if (cid.equals(su_SERVICE_CID))
-			return su_SERVICE_FACTORY;
+		if (cid.equals(StumbleGlobals.SERVICE_CID))
+			return StumbleGlobals.SERVICE_FACTORY;
 		
 		if (!iid.equals(Components.interfaces.nsIFactory))
 			throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
@@ -88,10 +99,10 @@ var su_Module = {
 }
 function NSGetModule(componentManager, fileSpec)
 {
-  return su_Module;
+  return StumbleGlobals.Module;
 }
 
-var su_Service = function ()
+StumbleGlobals.Service = function ()
 {
 	this._hostSpec = null;
 	this._datastore = null;
@@ -113,20 +124,34 @@ var su_Service = function ()
 	this._logErrorDomain = "stumbleupon.com";
 	this._persistLCFD = false;
 }
-su_Service.prototype = 
+StumbleGlobals.Service.prototype = 
 {
+	classID: Components.ID("{b97c288d-917d-4d26-bd24-3adf14f5aea3}"),
+	
 	QueryInterface: function (iid)
 	{
 		if (iid.equals(Components.interfaces.nsISupports) ||
-				iid.equals(Components.interfaces.nsISupportsWeakReference))
+			iid.equals(Components.interfaces.nsISupportsWeakReference) ||
+			iid.equals(Components.interfaces.nsIObserver) )
+		{
 			return this;
+		}
 		else
+		{
 			throw Components.results.NS_ERROR_NO_INTERFACE;
+		}
 	},
 
-  get wrappedJSObject() {
-    return this;
-  },
+	// nsIObserver -- This is only implemented to silence a silly warning message that is thrown
+	//                for profile-after services that don't implement nsIObserver.
+	observe: function(subject, topic, data)
+	{
+		return;
+	},
+
+	get wrappedJSObject() {
+		return this;
+	},
 	
 	_createInstance: function (nsclass, nsinterface)
 	{
@@ -336,8 +361,17 @@ su_Service.prototype =
 		var i;
 		for (i = 1; i < arguments.length; i++)
 			args.push(arguments[i]);
+
+		// Evaluate multi-dot calls properly, e.g. StumbleGlobals.get_time_s
+		var parent = win;
+		var fname = arguments[0];
+		while((i = fname.indexOf(".")) != -1)
+		{
+			parent = parent[fname.substr(0,i)];
+			fname = fname.substr(i+1);
+		}
 		
-		return win[arguments[0]].apply(win, args);
+		return parent[fname].apply(win, args);
 	},
 	
 	logError: function ()
@@ -552,10 +586,8 @@ su_Service.prototype =
 			x.detail._request = x;
 		}
 		
-//		netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
 		try {
 			x.open("POST", uri, true);
-//			x.setRequestHeader("User-Agent" , useragent);
 			x.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
 		} catch (e) { this.logError("POST ASYNC", e); }
 		x.aborted = false;
@@ -750,6 +782,8 @@ su_Service.prototype =
 		if (this._datastore)
 			return this._datastore;
 		
+		// We need to load JSON and then the datastore
+		this._loadScript("json_sans_eval.js");
 		this._loadScript("datastore.js");
 		
 		var enabledb = (Components.interfaces.nsINavBookmarksService 
@@ -758,7 +792,7 @@ su_Service.prototype =
 		if (enabledb) 
 			this._loadScript("DatabaseConnection.js"); 
 		
-		this._datastore = new su_Datastore(this, enabledb);
+		this._datastore = new StumbleGlobals.Datastore(this, enabledb);
 		
 		return this._datastore;
 	},
@@ -770,21 +804,21 @@ su_Service.prototype =
 		
 		this._loadScript("stumbleReporter.js"); 
 
-		this._stumbleReporter = new su_StumbleReporter(this);
+		this._stumbleReporter = new StumbleGlobals.StumbleReporter(this);
 
 		return this._stumbleReporter;
 	},
 	
 	getEffectiveTLD: function (url)
 	{
-		if (! url.match(/^(http:|https:|ftp:)/))
+		if (! url.match(/^(http:|https:|ftp:)/i))
 			return null;
 		
 		var spliturl = url.split("/");
 		if (spliturl.length < 3)
 			return null;
 		
-		var alt = spliturl[2].match(/([^\.]*\.homeip\.net|[^\.]*\.stumble\.net)$/);
+		var alt = spliturl[2].match(/([^\.]*\.stumble\.net)$/);
 		if (alt)
 			return alt[1];
 		
@@ -799,7 +833,7 @@ su_Service.prototype =
 			else
 			{
 				this._loadScript("tldEmulation.js");
-				this._tldService = su_EmulatedTLDService;
+				this._tldService = StumbleGlobals.EmulatedTLDService;
 			}
 		}
 		
@@ -836,37 +870,41 @@ su_Service.prototype =
 	}
 };
 
-function su_dd()
+// Gecko 2 component registration
+if ((typeof(XPCOMUtils) != "undefined") && XPCOMUtils.generateNSGetFactory)
+	var NSGetFactory = XPCOMUtils.generateNSGetFactory([StumbleGlobals.Service]);
+
+StumbleGlobals.dd = function()
 {
 	var service;
 	try {
 		service = Components.classes["@stumbleupon.com/stumbleupon-service;1"].getService().wrappedJSObject;
 	}
 	catch (e) {
-		service = su_service;
+		service = StumbleGlobals.service;
 	}
 	
 	service.dd.apply(service, arguments);
 }
 
-var su_log = su_dd;
+StumbleGlobals.log = StumbleGlobals.dd;
 
-function su_ddf()
+StumbleGlobals.ddf = function()
 {
 	var service;
 	try {
 		service = Components.classes["@stumbleupon.com/stumbleupon-service;1"].getService().wrappedJSObject;
 	}
 	catch (e) {
-		service = su_service;
+		service = StumbleGlobals.service;
 	}
 	
 	service.ddf.apply(service, arguments);
 }
 
-var su_logf = su_ddf;
+StumbleGlobals.logf = StumbleGlobals.ddf;
 
-function su_dump_object(o)
+StumbleGlobals.dump_object = function(o)
 {
 	var str = "";
 	var p;
@@ -881,5 +919,5 @@ function su_dump_object(o)
 		}
 	}
 	
-	su_dd(str);
+	StumbleGlobals.dd(str);
 }
diff --git a/chrome/stumbleupon.jar!/content/DatabaseConnection.js b/content/DatabaseConnection.js
similarity index 95%
rename from chrome/stumbleupon.jar!/content/DatabaseConnection.js
rename to content/DatabaseConnection.js
index 220d988..355164e 100644
--- a/chrome/stumbleupon.jar!/content/DatabaseConnection.js
+++ b/content/DatabaseConnection.js
@@ -1,1121 +1,1121 @@
-/*
-    [IP:]
-    ***** BEGIN LICENSE BLOCK *****
-    
-    Copyright (c) 2006  Center for History and New Media
-                        George Mason University, Fairfax, Virginia, USA
-                        http://chnm.gmu.edu
-    
-    Licensed under the Educational Community License, Version 1.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-    
-    http://www.opensource.org/licenses/ecl1.php
-    
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-    
-    ***** END LICENSE BLOCK *****
-		
-		StumbleUpon revisions include:
-		1.  Changes namespace.
-		2.  Changes prototype syntax.
-		3.  Changes bracket convention.
-		4.  Adds missing semicolons.
-		5.  Replaces 	Zotero.getZoteroDatabase() with new method
-		    this.getDBFile().
-		6.  Replaces Zotero.getZoteroDirectory() with new method
-		    this._getStorageDirectory().
-		7.  Replaces Zotero.moveToUnique() with new method
-		    this._moveToUniqueFile().
-		8.  New debug logging that doesn't rely on the Zotero object.
-		9.  New user interaction that doesn't rely on the Zotero object.
-		10. Adds this._query and the a, as, av, als, alv, q, avr and v
-		    methods.
-		11. Makes query() always return an array for SELECT queries.
-		12. Added _parent and automatic backup disabling.
-		13. Added _modified and made automatic backup dependent on
-		    _modified.
-		14. Disabled prompt for restart upon detecting corruption.
-		15. Added _hostIsWindows().
-*/
-
-var su_DatabaseConnection = function(parent, dbName)
-{
-	this.skipBackup = false;
-	
-	// Private members
-	this._parent = parent;
-	this._dbName = dbName;
-	this._modified = false;
-	this._shutdown = false;
-	this._connection = null;
-	this._transactionRollback = null;
-	this._transactionNestingLevel = 0;
-	this._callbacks = { begin: [], commit: [], rollback: [] };
-	this._dbIsCorrupt = null;
-	this._self = this;
-	this._query = "";
-}
-su_DatabaseConnection.prototype =
-{ // BEGIN prototype
-
-/////////////////////////////////////////////////////////////////
-//
-// Public methods
-//
-/////////////////////////////////////////////////////////////////
-
-/*
- * Run an SQL query
- *
- *  Optional _params_ is an array of bind parameters in the form
- *		[1,"hello",3] or [{'int':2},{'string':'foobar'}]
- *
- * 	Returns:
- *  	 - Associative array (similar to mysql_fetch_assoc) for SELECT's
- *	 - lastInsertId for INSERT's
- *	 - TRUE for other successful queries
- *	 - FALSE on error
- */
-query: function (sql,params)
-{
-	var db = this._getDBConnection();
-	if (! sql)
-		sql = this._query;
-	
-	try {
-		// Parse out the SQL command being used
-		var op = sql.match(/^[^a-z]*[^ ]+/i);
-		if (op)
-			op = op.toString().toLowerCase();
-		
-		// If SELECT statement, return result
-		if (op=='select')
-		{
-			// Until the native dataset methods work (or at least exist),
-			// we build a multi-dimensional associative array manually
-			
-			var statement = this.getStatement(sql, params);
-			
-			var dataset = new Array();
-			while (statement.executeStep())
-			{
-				var row = new Array();
-				
-				for(var i=0, len=statement.columnCount; i<len; i++)
-					row[statement.getColumnName(i)] = this._getTypedValue(statement, i);
-				dataset.push(row);
-			}
-			statement.reset();
-			
-			return dataset;
-		}
-		else
-		{
-			this._modified = true;
-			if (params)
-			{
-				var statement = this.getStatement(sql, params);
-				statement.execute();
-			}
-			else
-			{
-				this._debug(sql,5);
-				db.executeSimpleSQL(sql);
-			}
-			
-			if (op=='insert')
-				return db.lastInsertRowID;
-			// DEBUG: Can't get affected rows for UPDATE or DELETE?
-			else
-				return true;
-		}
-	}
-	catch (e) {
-		this.checkException(e);
-		
-		var dberr = (db.lastErrorString!='not an error')
-			? ' [ERROR: ' + db.lastErrorString + ']' : '';
-		throw(e + ' [QUERY: ' + sql + ']' + dberr);
-	}
-},
-
-
-/*
- * Query a single value and return it
- */
-valueQuery: function (sql,params)
-{
-	var statement = this.getStatement(sql, params);
-	
-	// No rows
-	if (!statement.executeStep())
-	{
-		statement.reset();
-		return false;
-	}
-	
-	var value = this._getTypedValue(statement, 0);
-	statement.reset();
-	return value;
-},
-
-
-/*
- * Run a query and return the first row
- */
-rowQuery: function (sql,params)
-{
-	var result = this.query(sql,params);
-	if (result.length)
-		return result[0];
-	else
-		return new Array();
-},
-
-
-/*
- * Run a query and return the first column as a numerically-indexed array
- */
-columnQuery: function (sql,params)
-{
-	var statement = this.getStatement(sql, params);
-	
-	if (statement)
-	{
-		var column = new Array();
-		while (statement.executeStep())
-			column.push(this._getTypedValue(statement, 0));
-		
-		statement.reset();
-		return column.length ? column : false;
-	}
-	return false;
-},
-
-a: function (str)
-{
-	this._query = str;
-},
-
-av: function (str)
-{
-	str = ((parseInt(str)) + "");
-	if (str == "NaN")
-		str = "0";
-	this._query += str + ",";	
-},
-
-avr: function (str)
-{
-	str = ((parseInt(str)) + "");
-	if (str == "NaN")
-		str = "0";
-	this._query += str;
-},
-
-as: function (str)
-{
-	this._query += "'" + str.replace(/'/g, "''") + "',";
-},
-
-alv: function (str)
-{
-	str = ((parseInt(str)) + "");
-	if (str == "NaN")
-		str = "0";
-	this._query += str + ")";	
-},
-
-als: function (str)
-{
-	this._query += "'" + str.replace(/'/g, "''") + "')";
-},
-
-escapeString: function (str)
-{
-	this._query += str.replace(/'/g, "''");
-},
-
-q: function (str)
-{
-	return "'" + str.replace(/'/g, "''") + "'";
-},
-
-v: function (str)
-{
-	str = ((parseInt(str)) + "");
-	if (str == "NaN")
-		str = "0";
-	return str;
-},
-
-/*
-/*
- * Get a raw mozStorage statement from the DB for manual processing
- *
- * This should only be used externally for manual parameter binding for
- * large repeated queries
- *
- *  Optional _params_ is an array of bind parameters in the form
- *		[1,"hello",3] or [{'int':2},{'string':'foobar'}]
- */
-getStatement: function (sql, params)
-{
-	var db = this._getDBConnection();
-	
-	try {
-		this._debug(sql,5);
-		var statement = db.createStatement(sql);
-	}
-	catch (e) {
-		var dberr = (db.lastErrorString!='not an error')
-			? ' [ERROR: ' + db.lastErrorString + ']' : '';
-		throw(e + ' [QUERY: ' + sql + ']' + dberr);
-	}
-	
-	if (params)
-	{
-		// If single scalar value or single non-array object, wrap in an array
-		if (typeof params != 'object' || params===null ||
-				(params && typeof params == 'object' && !params.length))
-			params = [params];
-		
-		for (var i=0; i<params.length; i++)
-		{
-			// Integer
-			if (params[i]!==null && typeof params[i]['int'] != 'undefined')
-			{
-				var type = 'int';
-				var value = params[i]['int'];
-			}
-			// String
-			else if (params[i]!==null && typeof params[i]['string'] != 'undefined')
-			{
-				var type = 'string';
-				var value = params[i]['string'];
-			}
-			// Null
-			else if (params[i]!==null && typeof params[i]['null'] != 'undefined')
-			{
-				var type = 'null';
-			}
-			// Automatic (trust the JS type)
-			else
-			{
-				switch (typeof params[i])
-				{
-					case 'string':
-						var type = 'string';
-						break;
-					case 'number':
-						var type = 'int';
-						break;
-					// Object
-					default:
-						if (params[i]===null)
-						{
-							var type = 'null';
-						}
-						else
-						{
-							throw('Invalid bound parameter ' + params[i]);
-//							throw('Invalid bound parameter ' + params[i] +
-//								' in ' + Zotero.varDump(params));
-						}
-				}
-				var value = params[i];
-			}
-			
-			// Bind the parameter as the correct type
-			switch (type)
-			{
-				case 'int':
-					this._debug('Binding parameter ' + (i+1)
-						+ ' of type int: ' + value, 5);
-					statement.bindInt32Parameter(i, value);
-					break;
-					
-				case 'string':
-					this._debug('Binding parameter ' + (i+1)
-						+ ' of type string: "' + value + '"', 5);
-					statement.bindUTF8StringParameter(i, value);
-					break;
-					
-				case 'null':
-					this._debug('Binding parameter ' + (i+1)
-						+ ' of type NULL', 5);
-					statement.bindNullParameter(i);
-					break;
-			}
-		}
-	}
-	return statement;
-},
-
-
-/*
- * Only for use externally with this.getStatement()
- */
-getLastInsertID: function ()
-{
-	var db = this._getDBConnection();
-	return db.lastInsertRowID;
-},
-
-
-/*
- * Only for use externally with this.getStatement()
- */
-getLastErrorString: function ()
-{
-	var db = this._getDBConnection();
-	return db.lastErrorString;
-},
-
-
-beginTransaction: function ()
-{
-	var db = this._getDBConnection();
-	
-	if (db.transactionInProgress)
-	{
-		this._transactionNestingLevel++;
-		this._debug('Transaction in progress -- increasing level to '
-			+ this._transactionNestingLevel, 5);
-	}
-	else
-	{
-		this._debug('Beginning DB transaction', 5);
-		db.beginTransaction();
-		
-		// Run callbacks
-		for (var i=0; i<this._callbacks.begin.length; i++)
-		{
-			if (this._callbacks.begin[i])
-				this._callbacks.begin[i]();
-		}
-	}
-},
-
-
-commitTransaction: function ()
-{
-	var db = this._getDBConnection();
-	
-	if (this._transactionNestingLevel)
-	{
-		this._transactionNestingLevel--;
-		this._debug('Decreasing transaction level to ' + this._transactionNestingLevel, 5);
-	}
-	else if (this._transactionRollback)
-	{
-		this._debug('Rolling back previously flagged transaction', 5);
-		this.rollbackTransaction();
-	}
-	else
-	{
-		this._debug('Committing transaction',5);
-		try {
-			db.commitTransaction();
-			
-			// Run callbacks
-			for (var i=0; i<this._callbacks.commit.length; i++)
-			{
-				if (this._callbacks.commit[i])
-					this._callbacks.commit[i]();
-			}
-		}
-		catch(e) {
-			var dberr = (db.lastErrorString!='not an error')
-				? ' [ERROR: ' + db.lastErrorString + ']' : '';
-			throw(e + dberr);
-		}
-	}
-},
-
-
-rollbackTransaction: function ()
-{
-	var db = this._getDBConnection();
-	
-	if (!db.transactionInProgress)
-	{
-		this._debug("Transaction is not in progress in rollbackTransaction()", 2);
-		return;
-	}
-	
-	if (this._transactionNestingLevel)
-	{
-		this._transactionNestingLevel--;
-		this._transactionRollback = true;
-		this._debug('Flagging nested transaction for rollback', 5);
-	}
-	else
-	{
-		this._debug('Rolling back transaction', 5);
-		this._transactionRollback = false;
-		try {
-			db.rollbackTransaction();
-			
-			// Run callbacks
-			for (var i=0; i<this._callbacks.rollback.length; i++)
-			{
-				if (this._callbacks.rollback[i])
-					this._callbacks.rollback[i]();
-			}
-		}
-		catch(e) {
-			var dberr = (db.lastErrorString!='not an error')
-				? ' [ERROR: ' + db.lastErrorString + ']' : '';
-			throw(e + dberr);
-		}
-	}
-},
-
-
-addCallback: function (type, cb)
-{
-	switch (type)
-	{
-		case 'begin':
-		case 'commit':
-		case 'rollback':
-			break;
-			
-		default:
-			throw ("Invalid callback type '" + type + "' in DB.addCallback()");
-	}
-	
-	var id = this._callbacks[type].length;
-	this._callbacks[type][id] = cb;
-	return id;
-},
-
-
-removeCallback: function (type, id)
-{
-	switch (type)
-	{
-		case 'begin':
-		case 'commit':
-		case 'rollback':
-			break;
-			
-		default:
-			throw ("Invalid callback type '" + type + "' in DB.removeCallback()");
-	}
-	
-	delete this._callbacks[type][id];
-},
-
-
-transactionInProgress: function ()
-{
-	var db = this._getDBConnection();
-	return db.transactionInProgress;
-},
-
-
-/**
- * Safety function used on shutdown to make sure we're not stuck in the
- * middle of a transaction
- *
- * NOTE: No longer used
- */
-commitAllTransactions: function ()
-{
-	if (this.transactionInProgress())
-	{
-		var level = this._transactionNestingLevel;
-		this._transactionNestingLevel = 0;
-		try {
-			this.commitTransaction();
-		}
-		catch (e) {}
-		return level ? level : true;
-	}
-	return false;
-},
-
-
-/*
- * Used on shutdown to rollback all open transactions
- */
-rollbackAllTransactions: function ()
-{
-	if (this.transactionInProgress())
-	{
-		var level = this._transactionNestingLevel;
-		this._transactionNestingLevel = 0;
-		try {
-			this.rollbackTransaction();
-		}
-		catch (e) {}
-		return level ? level : true;
-	}
-	return false;
-},
-
-
-tableExists: function (table)
-{
-	return this._getDBConnection().tableExists(table);
-},
-
-
-getColumns: function (table)
-{
-	var db = this._getDBConnection();
-	
-	try {
-		var sql = "SELECT * FROM " + table + " LIMIT 1";
-		var statement = this.getStatement(sql);
-		var cols = new Array();
-		for (var i=0,len=statement.columnCount; i<len; i++)
-			cols.push(statement.getColumnName(i));
-		statement.reset();
-		return cols;
-	}
-	catch (e) {
-		this._debug(e,1);
-		return false;
-	}
-},
-
-
-getColumnHash: function (table)
-{
-	var cols = this.getColumns(table);
-	var hash = {};
-	if (cols.length)
-	{
-		for (var i=0; i<cols.length; i++)
-			hash[cols[i]] = true;
-	}
-	return hash;
-},
-
-
-/**
-* Find the lowest unused integer >0 in a table column
-*
-* Note: This retrieves all the rows of the column, so it's not really
-*	meant for particularly large tables.
-**/
-getNextID: function (table, column)
-{
-	var sql = 'SELECT ' + column + ' FROM ' + table + ' ORDER BY ' + column;
-	var vals = this.columnQuery(sql);
-	
-	if (!vals)
-		return 1;
-	
-	if (vals[0] === '0')
-		vals.shift();
-	
-	for (var i=0, len=vals.length; i<len; i++)
-	{
-		if (vals[i] != i+1)
-			break;
-	}
-	
-	return i+1;
-},
-
-
-/**
-* Find the next lowest numeric suffix for a value in table column
-*
-* For example, if "Untitled" and "Untitled 2" and "Untitled 4",
-* returns "Untitled 3"
-*
-* DEBUG: doesn't work once there's an "Untitled 10"
-*
-* If _name_ alone is available, returns that
-**/
-getNextName: function (table, field, name)
-{
-	var sql = "SELECT " + field + " FROM " + table + " WHERE " + field
-		+ " LIKE ? ORDER BY " + field + " COLLATE NOCASE";
-	var untitleds = this.columnQuery(sql, name + '%');
-	
-	if (!untitleds || untitleds[0]!=name)
-		return name;
-	
-	var i = 1;
-	var num = 2;
-	while (untitleds[i] && untitleds[i]==(name + ' ' + num))
-	{
-		while (untitleds[i+1] && untitleds[i]==untitleds[i+1])
-		{
-			this._debug('Next ' + i + ' is ' + untitleds[i]);
-			i++;
-		}
-		
-		i++;
-		num++;
-	}
-	
-	return name + ' ' + num;
-},
-
-
-/*
- * Shutdown observer -- implements nsIObserver
- */
-observe: function(subject, topic, data)
-{
-	switch (topic)
-	{
-		case 'xpcom-shutdown':
-			this.destroy();
-			
-			break;
-	}
-},
-
-destroy: function ()
-{
-	if (this._shutdown)
-	{
-		this._debug('returning');
-		return;
-	}
-	
-	// NOTE: disabled
-	//var level = this.commitAllTransactions();
-	var level = this.rollbackAllTransactions();
-	if (level)
-	{
-		level = level === true ? '0' : level;
-		this._debug("A transaction in DB '" + this._dbName + "' was still open! (level " + level + ")", 2);
-	}
-	
-	this._shutdown = true;
-	
-	this.skipBackup = (this.skipBackup || (! this._modified) || (! this._parent.getValue("@enable_db_backup"))); 
-	
-	this.backupDatabase();
-	
-	this._parent = null;
-},
-
-integrityCheck: function ()
-{
-	var ok = this.valueQuery("PRAGMA integrity_check");
-	return ok == 'ok';
-},
-
-
-checkException: function (e)
-{
-	if (e.name && e.name == 'NS_ERROR_FILE_CORRUPTED')
-	{
-		// Write corrupt marker to data directory
-		var file = this.getDBFile(this._dbName, 'is.corrupt');
-		var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
-						 .createInstance(Components.interfaces.nsIFileOutputStream);
-		foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate
-		foStream.write('', 0);
-		foStream.close();
-		
-		this._dbIsCorrupt = true;
-		
-//		var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
-//								.getService(Components.interfaces.nsIPromptService);
-//		
-//		var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
-//			+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_IS_STRING);
-//		
-//		var index = ps.confirmEx(null,
-//			Zotero.getString('general.error'),
-//			Zotero.getString('db.dbCorrupted', this._dbName) + '\n\n' + Zotero.getString('db.dbCorrupted.restart'),
-//			buttonFlags,
-//			Zotero.getString('general.restartNow'),
-//			Zotero.getString('general.restartLater'),
-//			null, null, {});
-//		
-//		if (index == 0)
-//		{
-//			var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
-//					.getService(Components.interfaces.nsIAppStartup);
-//			appStartup.quit(Components.interfaces.nsIAppStartup.eRestart);
-//			appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit);
-//		}
-//		
-//		Zotero.skipLoading = true;
-//		return false;
-	}
-	return true;
-},
-
-
-backupDatabase: function (suffix)
-{
-	if (this.transactionInProgress())
-	{
-		this._debug("Transaction in progress--skipping backup of DB '" + this._dbName + "'", 2);
-		return false;
-	}
-	
-	var corruptMarker = this.getDBFile(this._dbName, 'is.corrupt').exists();
-	
-	if (this.skipBackup)
-	{
-		this._debug("Skipping backup of database '" + this._dbName + "'", 1);
-		return false;
-	}
-	else if (this._dbIsCorrupt || corruptMarker)
-	{
-		this._debug("Database '" + this._dbName + "' is marked as corrupt--skipping backup", 1);
-		return false;
-	}
-	
-	this._debug("Backing up database '" + this._dbName + "'");
-	
-	var file = this.getDBFile(this._dbName);
-	var backupFile = this.getDBFile(this._dbName,
-		(suffix ? suffix + '.' : '') + 'bak');
-	
-	// Copy via a temporary file so we don't run into disk space issues
-	// after deleting the old backup file
-	var tmpFile = this.getDBFile(this._dbName, 'tmp');
-	if (tmpFile.exists())
-		tmpFile.remove(null);
-	
-	try {
-		file.copyTo(file.parent, tmpFile.leafName);
-	}
-	catch (e){
-		// TODO: deal with low disk space
-		throw (e);
-	}
-	
-	// Opened database files can't be moved on Windows, so we have to skip
-	// the extra integrity check (unless we wanted to write two copies of
-	// the database, but that doesn't seem like a great idea)
-	if (!this._hostIsWindows())
-	{
-		try {
-			var store = Components.classes["@mozilla.org/storage/service;1"].
-				getService(Components.interfaces.mozIStorageService);
-				
-			var connection = store.openDatabase(tmpFile);
-		}
-		catch (e){
-			this._debug("Database file '" + tmpFile.leafName + "' is corrupt--skipping backup");
-			if (tmpFile.exists())
-				tmpFile.remove(null);
-			return false;
-		}
-	}
-	
-	// Remove old backup file
-	if (backupFile.exists())
-		backupFile.remove(null);
-	
-	tmpFile.moveTo(tmpFile.parent, backupFile.leafName);
-	
-	return true;
-},
-
-_hostIsWindows: function ()
-{
-	var outval = true;
-	try {
-		var appinfo = Components.classes["@mozilla.org/xre/app-info;1"]
-				.getService(Components.interfaces.nsIXULAppInfo);
-		appinfo = appinfo.QueryInterface(Components.interfaces.nsIXULRuntime);
-
-//		spec.id = appinfo.ID;
-//		spec.version = appinfo.version;
-		outval = (appinfo.OS.toLowerCase().indexOf("win") != -1);
-	} catch (e) {}
-	
-	return outval;
-},
-
-/*
- * Keep the SQLite shared cache live between transactions with a dummy statement,
- * which speeds up DB access dramatically (at least on Windows and Linux--OS X
- * seems to be much faster already, perhaps due to its own disk cache)
- *
- * This is the same technique used by Mozilla code. The one downside is that it
- * prevents schema changes, so this is called after schema updating. If the
- * schema really needs to be updated at another point, use stopDummyStatement().
- *
- * See http://developer.mozilla.org/en/docs/Storage:Performance for more info.
- */
-startDummyStatement: function ()
-{
-//	try {
-		if (!this._dummyConnection)
-		{
-			this._debug("Opening database '" + this._dbName + " for dummy statement");
-			// Get the storage service
-			var store = Components.classes["@mozilla.org/storage/service;1"].
-				getService(Components.interfaces.mozIStorageService);
-			var file = this.getDBFile(this._dbName);
-			this._dummyConnection = store.openDatabase(file);
-		}
-		
-		if (this._dummyStatement)
-		{
-			this._debug("Dummy statement is already open");
-			return;
-		}
-		
-		this._debug("Initializing dummy statement for '" + this._dbName + "'");
-		
-		var sql = "CREATE TABLE IF NOT EXISTS dummyTable (id INTEGER PRIMARY KEY)";
-		this._dummyConnection.executeSimpleSQL(sql);
-		
-		sql = "INSERT OR IGNORE INTO dummyTable VALUES (1)";
-		this._dummyConnection.executeSimpleSQL(sql);
-		
-		sql = "SELECT id FROM dummyTable LIMIT 1";
-		this._dummyStatement = this._dummyConnection.createStatement(sql);
-		this._dummyStatement.executeStep();
-	
-//	}
-//	catch (e) {
-//		Components.utils.reportError(e);
-//		this._debug(e);
-//	}
-},
-
-
-/*
- * Stop the dummy statement temporarily to allow for schema changess
- *
- * The statement needs to be started again or performance will suffer.
- */
-stopDummyStatement: function ()
-{
-	if (!this._dummyStatement)
-		return;
-	
-	this._debug("Stopping dummy statement for '" + this._dbName + "'");
-	this._dummyStatement.reset();
-	this._dummyStatement = null;
-},
-
-
-getDBFile: function (name, ext)
-{
-	var str;
-	
-	if (name)
-		str = name;
-	else if (this._dbName)
-		str = this._dbName;
-	else
-		str = 'stumbleupon';
-	
-	str += '.sqlite';
-	
-	str += (ext) ? ('.' + ext) : '';
-	
-	var file = this._getStorageDirectory();
-	
-	file.append(str);
-	
-	return file;
-},
-
-
-/////////////////////////////////////////////////////////////////
-//
-// Private methods
-//
-/////////////////////////////////////////////////////////////////
-
-_getStorageDirectory: function ()
-{
-	var file = Components.classes["@mozilla.org/file/directory_service;1"]
-				.getService(Components.interfaces.nsIProperties)
-				.get("ProfD", Components.interfaces.nsIFile);
-
-	file.append("StumbleUpon");
-	if (! file.exists())
-		file.create(file.DIRECTORY_TYPE, 0700);
-	
-	return file;	
-},
-
-_moveToUniqueFile: function (file, newFile)
-{
-	newFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0644);
-	var newName = newFile.leafName;
-	newFile.remove(null);
-	
-	// Move file to unique name
-	file.moveTo(newFile.parent, newName);
-	return file;
-},
-
-/*
- * Retrieve a link to the data store
- */
-_getDBConnection: function ()
-{
-	if (this._connection)
-		return this._connection;
-	
-	this._debug("Opening database '" + this._dbName + "'");
-	
-	// Get the storage service
-	var store = Components.classes["@mozilla.org/storage/service;1"].
-		getService(Components.interfaces.mozIStorageService);
-	
-	var file = this.getDBFile(this._dbName);
-	var backupFile = this.getDBFile(this._dbName, 'bak');
-	
-	var fileName = this._dbName + '.sqlite';
-	
-//	if (this._dbName == 'zotero' && ZOTERO_CONFIG['DB_REBUILD'])
-//	{
-//		if (confirm('Erase all user data and recreate database from schema?'))
-//		{
-//			// Delete existing Zotero database
-//			if (file.exists())
-//				file.remove(null);
-//			
-//			// Delete existing storage folder
-//			var dir = Zotero.getStorageDirectory();
-//			if (dir.exists())
-//				dir.remove(true);
-//		}
-//	}
-	
-	catchBlock: try {
-		var corruptMarker = this.getDBFile(this._dbName, 'is.corrupt');
-		if (corruptMarker.exists())
-			throw({ name: 'NS_ERROR_FILE_CORRUPTED' })
-		this._connection = store.openDatabase(file);
-	}
-	catch (e) {
-		if (e.name=='NS_ERROR_FILE_CORRUPTED')
-		{
-			this._debug("Database file '" + file.leafName + "' corrupted", 1);
-			
-			// No backup file! Eek!
-			if (!backupFile.exists())
-			{
-				this._debug("No backup file for DB '" + this._dbName + "' exists", 1);
-				
-				// Save damaged filed
-				this._debug('Saving damaged DB file with .damaged extension', 1);
-				var damagedFile = this.getDBFile(this._dbName, 'damaged');
-				this._moveToUniqueFile(file, damagedFile);
-				
-				// Create new main database
-				var file = this.getDBFile(this._dbName);
-				this._connection = store.openDatabase(file);
-				
-				if (corruptMarker.exists())
-					corruptMarker.remove(null);
-				
-//				alert(Zotero.getString('db.dbCorruptedNoBackup', fileName));
-				break catchBlock;
-			}
-			
-			// Save damaged file
-			this._debug('Saving damaged DB file with .damaged extension', 1);
-			var damagedFile = this.getDBFile(this._dbName, 'damaged');
-			this._moveToUniqueFile(file, damagedFile);
-			
-			// Test the backup file
-			try {
-				this._connection = store.openDatabase(backupFile);
-			}
-			// Can't open backup either
-			catch (e) {
-				// Create new main database
-				var file = this.getDBFile(this._dbName);
-				this._connection = store.openDatabase(file);
-				
-//				alert(Zotero.getString('db.dbRestoreFailed', fileName));
-				
-				if (corruptMarker.exists())
-					corruptMarker.remove(null);
-				
-				break catchBlock;
-			}
-			
-			this._connection = undefined;
-			
-			// Copy backup file to main DB file
-			this._debug("Restoring database '" + this._dbName + "' from backup file", 1);
-			try {
-				backupFile.copyTo(backupFile.parent, fileName);
-			}
-			catch (e) {
-				// TODO: deal with low disk space
-				throw (e);
-			}
-			
-			// Open restored database
-			var file = this._getStorageDirectory();
-			file.append(fileName);
-			this._connection = store.openDatabase(file);
-			this._debug('Database restored', 1);
-//			var msg = Zotero.getString('db.dbRestored', [
-//				fileName,
-//				Zotero.Date.getFileDateString(backupFile),
-//				Zotero.Date.getFileTimeString(backupFile)
-//			]);
-//			alert(msg);
-			
-			if (corruptMarker.exists())
-				corruptMarker.remove(null);
-			
-			break catchBlock;
-		}
-		
-		// Some other error that we don't yet know how to deal with
-		throw (e);
-	}
-	
-	// Register shutdown handler to call this.onShutdown() for DB backup
-	var observerService = Components.classes["@mozilla.org/observer-service;1"]
-		.getService(Components.interfaces.nsIObserverService);
-	observerService.addObserver(this, "xpcom-shutdown", false);
-	observerService = null;
-	
-	return this._connection;
-},
-
-
-_debug: function (str, level)
-{
-	//this._parent._logError(false, {}, "DB ", str);
-},
-
-
-_getTypedValue: function (statement, i)
-{
-	var type = statement.getTypeOfIndex(i);
-	switch (type)
-	{
-		case statement.VALUE_TYPE_INTEGER:
-			return statement.getInt64(i);
-		case statement.VALUE_TYPE_TEXT:
-			return statement.getUTF8String(i);
-		case statement.VALUE_TYPE_NULL:
-			return null;
-		case statement.VALUE_TYPE_FLOAT:
-			return statement.getDouble(i);
-		case statement.VALUE_TYPE_BLOB:
-			return statement.getBlob(i);
-		default:
-			return null;
-	}
-}
-
-} // END prototype
+/*
+    [IP:]
+    ***** BEGIN LICENSE BLOCK *****
+    
+    Copyright (c) 2006  Center for History and New Media
+                        George Mason University, Fairfax, Virginia, USA
+                        http://chnm.gmu.edu
+    
+    Licensed under the Educational Community License, Version 1.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+    
+    http://www.opensource.org/licenses/ecl1.php
+    
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+    
+    ***** END LICENSE BLOCK *****
+		
+		StumbleUpon revisions include:
+		1.  Changes namespace.
+		2.  Changes prototype syntax.
+		3.  Changes bracket convention.
+		4.  Adds missing semicolons.
+		5.  Replaces 	Zotero.getZoteroDatabase() with new method
+		    this.getDBFile().
+		6.  Replaces Zotero.getZoteroDirectory() with new method
+		    this._getStorageDirectory().
+		7.  Replaces Zotero.moveToUnique() with new method
+		    this._moveToUniqueFile().
+		8.  New debug logging that doesn't rely on the Zotero object.
+		9.  New user interaction that doesn't rely on the Zotero object.
+		10. Adds this._query and the a, as, av, als, alv, q, avr and v
+		    methods.
+		11. Makes query() always return an array for SELECT queries.
+		12. Added _parent and automatic backup disabling.
+		13. Added _modified and made automatic backup dependent on
+		    _modified.
+		14. Disabled prompt for restart upon detecting corruption.
+		15. Added _hostIsWindows().
+*/
+
+StumbleGlobals.DatabaseConnection = function(parent, dbName)
+{
+	this.skipBackup = false;
+	
+	// Private members
+	this._parent = parent;
+	this._dbName = dbName;
+	this._modified = false;
+	this._shutdown = false;
+	this._connection = null;
+	this._transactionRollback = null;
+	this._transactionNestingLevel = 0;
+	this._callbacks = { begin: [], commit: [], rollback: [] };
+	this._dbIsCorrupt = null;
+	this._self = this;
+	this._query = "";
+}
+StumbleGlobals.DatabaseConnection.prototype =
+{ // BEGIN prototype
+
+/////////////////////////////////////////////////////////////////
+//
+// Public methods
+//
+/////////////////////////////////////////////////////////////////
+
+/*
+ * Run an SQL query
+ *
+ *  Optional _params_ is an array of bind parameters in the form
+ *		[1,"hello",3] or [{'int':2},{'string':'foobar'}]
+ *
+ * 	Returns:
+ *  	 - Associative array (similar to mysql_fetch_assoc) for SELECT's
+ *	 - lastInsertId for INSERT's
+ *	 - TRUE for other successful queries
+ *	 - FALSE on error
+ */
+query: function (sql,params)
+{
+	var db = this._getDBConnection();
+	if (! sql)
+		sql = this._query;
+	
+	try {
+		// Parse out the SQL command being used
+		var op = sql.match(/^[^a-z]*[^ ]+/i);
+		if (op)
+			op = op.toString().toLowerCase();
+		
+		// If SELECT statement, return result
+		if (op=='select')
+		{
+			// Until the native dataset methods work (or at least exist),
+			// we build a multi-dimensional associative array manually
+			
+			var statement = this.getStatement(sql, params);
+			
+			var dataset = new Array();
+			while (statement.executeStep())
+			{
+				var row = new Array();
+				
+				for(var i=0, len=statement.columnCount; i<len; i++)
+					row[statement.getColumnName(i)] = this._getTypedValue(statement, i);
+				dataset.push(row);
+			}
+			statement.reset();
+			
+			return dataset;
+		}
+		else
+		{
+			this._modified = true;
+			if (params)
+			{
+				var statement = this.getStatement(sql, params);
+				statement.execute();
+			}
+			else
+			{
+				this._debug(sql,5);
+				db.executeSimpleSQL(sql);
+			}
+			
+			if (op=='insert')
+				return db.lastInsertRowID;
+			// DEBUG: Can't get affected rows for UPDATE or DELETE?
+			else
+				return true;
+		}
+	}
+	catch (e) {
+		this.checkException(e);
+		
+		var dberr = (db.lastErrorString!='not an error')
+			? ' [ERROR: ' + db.lastErrorString + ']' : '';
+		throw(e + ' [QUERY: ' + sql + ']' + dberr);
+	}
+},
+
+
+/*
+ * Query a single value and return it
+ */
+valueQuery: function (sql,params)
+{
+	var statement = this.getStatement(sql, params);
+	
+	// No rows
+	if (!statement.executeStep())
+	{
+		statement.reset();
+		return false;
+	}
+	
+	var value = this._getTypedValue(statement, 0);
+	statement.reset();
+	return value;
+},
+
+
+/*
+ * Run a query and return the first row
+ */
+rowQuery: function (sql,params)
+{
+	var result = this.query(sql,params);
+	if (result.length)
+		return result[0];
+	else
+		return new Array();
+},
+
+
+/*
+ * Run a query and return the first column as a numerically-indexed array
+ */
+columnQuery: function (sql,params)
+{
+	var statement = this.getStatement(sql, params);
+	
+	if (statement)
+	{
+		var column = new Array();
+		while (statement.executeStep())
+			column.push(this._getTypedValue(statement, 0));
+		
+		statement.reset();
+		return column.length ? column : false;
+	}
+	return false;
+},
+
+a: function (str)
+{
+	this._query = str;
+},
+
+av: function (str)
+{
+	str = ((parseInt(str)) + "");
+	if (str == "NaN")
+		str = "0";
+	this._query += str + ",";	
+},
+
+avr: function (str)
+{
+	str = ((parseInt(str)) + "");
+	if (str == "NaN")
+		str = "0";
+	this._query += str;
+},
+
+as: function (str)
+{
+	this._query += "'" + str.replace(/'/g, "''") + "',";
+},
+
+alv: function (str)
+{
+	str = ((parseInt(str)) + "");
+	if (str == "NaN")
+		str = "0";
+	this._query += str + ")";	
+},
+
+als: function (str)
+{
+	this._query += "'" + str.replace(/'/g, "''") + "')";
+},
+
+escapeString: function (str)
+{
+	this._query += str.replace(/'/g, "''");
+},
+
+q: function (str)
+{
+	return "'" + str.replace(/'/g, "''") + "'";
+},
+
+v: function (str)
+{
+	str = ((parseInt(str)) + "");
+	if (str == "NaN")
+		str = "0";
+	return str;
+},
+
+/*
+/*
+ * Get a raw mozStorage statement from the DB for manual processing
+ *
+ * This should only be used externally for manual parameter binding for
+ * large repeated queries
+ *
+ *  Optional _params_ is an array of bind parameters in the form
+ *		[1,"hello",3] or [{'int':2},{'string':'foobar'}]
+ */
+getStatement: function (sql, params)
+{
+	var db = this._getDBConnection();
+	
+	try {
+		this._debug(sql,5);
+		var statement = db.createStatement(sql);
+	}
+	catch (e) {
+		var dberr = (db.lastErrorString!='not an error')
+			? ' [ERROR: ' + db.lastErrorString + ']' : '';
+		throw(e + ' [QUERY: ' + sql + ']' + dberr);
+	}
+	
+	if (params)
+	{
+		// If single scalar value or single non-array object, wrap in an array
+		if (typeof params != 'object' || params===null ||
+				(params && typeof params == 'object' && !params.length))
+			params = [params];
+		
+		for (var i=0; i<params.length; i++)
+		{
+			// Integer
+			if (params[i]!==null && typeof params[i]['int'] != 'undefined')
+			{
+				var type = 'int';
+				var value = params[i]['int'];
+			}
+			// String
+			else if (params[i]!==null && typeof params[i]['string'] != 'undefined')
+			{
+				var type = 'string';
+				var value = params[i]['string'];
+			}
+			// Null
+			else if (params[i]!==null && typeof params[i]['null'] != 'undefined')
+			{
+				var type = 'null';
+			}
+			// Automatic (trust the JS type)
+			else
+			{
+				switch (typeof params[i])
+				{
+					case 'string':
+						var type = 'string';
+						break;
+					case 'number':
+						var type = 'int';
+						break;
+					// Object
+					default:
+						if (params[i]===null)
+						{
+							var type = 'null';
+						}
+						else
+						{
+							throw('Invalid bound parameter ' + params[i]);
+//							throw('Invalid bound parameter ' + params[i] +
+//								' in ' + Zotero.varDump(params));
+						}
+				}
+				var value = params[i];
+			}
+			
+			// Bind the parameter as the correct type
+			switch (type)
+			{
+				case 'int':
+					this._debug('Binding parameter ' + (i+1)
+						+ ' of type int: ' + value, 5);
+					statement.bindInt32Parameter(i, value);
+					break;
+					
+				case 'string':
+					this._debug('Binding parameter ' + (i+1)
+						+ ' of type string: "' + value + '"', 5);
+					statement.bindUTF8StringParameter(i, value);
+					break;
+					
+				case 'null':
+					this._debug('Binding parameter ' + (i+1)
+						+ ' of type NULL', 5);
+					statement.bindNullParameter(i);
+					break;
+			}
+		}
+	}
+	return statement;
+},
+
+
+/*
+ * Only for use externally with this.getStatement()
+ */
+getLastInsertID: function ()
+{
+	var db = this._getDBConnection();
+	return db.lastInsertRowID;
+},
+
+
+/*
+ * Only for use externally with this.getStatement()
+ */
+getLastErrorString: function ()
+{
+	var db = this._getDBConnection();
+	return db.lastErrorString;
+},
+
+
+beginTransaction: function ()
+{
+	var db = this._getDBConnection();
+	
+	if (db.transactionInProgress)
+	{
+		this._transactionNestingLevel++;
+		this._debug('Transaction in progress -- increasing level to '
+			+ this._transactionNestingLevel, 5);
+	}
+	else
+	{
+		this._debug('Beginning DB transaction', 5);
+		db.beginTransaction();
+		
+		// Run callbacks
+		for (var i=0; i<this._callbacks.begin.length; i++)
+		{
+			if (this._callbacks.begin[i])
+				this._callbacks.begin[i]();
+		}
+	}
+},
+
+
+commitTransaction: function ()
+{
+	var db = this._getDBConnection();
+	
+	if (this._transactionNestingLevel)
+	{
+		this._transactionNestingLevel--;
+		this._debug('Decreasing transaction level to ' + this._transactionNestingLevel, 5);
+	}
+	else if (this._transactionRollback)
+	{
+		this._debug('Rolling back previously flagged transaction', 5);
+		this.rollbackTransaction();
+	}
+	else
+	{
+		this._debug('Committing transaction',5);
+		try {
+			db.commitTransaction();
+			
+			// Run callbacks
+			for (var i=0; i<this._callbacks.commit.length; i++)
+			{
+				if (this._callbacks.commit[i])
+					this._callbacks.commit[i]();
+			}
+		}
+		catch(e) {
+			var dberr = (db.lastErrorString!='not an error')
+				? ' [ERROR: ' + db.lastErrorString + ']' : '';
+			throw(e + dberr);
+		}
+	}
+},
+
+
+rollbackTransaction: function ()
+{
+	var db = this._getDBConnection();
+	
+	if (!db.transactionInProgress)
+	{
+		this._debug("Transaction is not in progress in rollbackTransaction()", 2);
+		return;
+	}
+	
+	if (this._transactionNestingLevel)
+	{
+		this._transactionNestingLevel--;
+		this._transactionRollback = true;
+		this._debug('Flagging nested transaction for rollback', 5);
+	}
+	else
+	{
+		this._debug('Rolling back transaction', 5);
+		this._transactionRollback = false;
+		try {
+			db.rollbackTransaction();
+			
+			// Run callbacks
+			for (var i=0; i<this._callbacks.rollback.length; i++)
+			{
+				if (this._callbacks.rollback[i])
+					this._callbacks.rollback[i]();
+			}
+		}
+		catch(e) {
+			var dberr = (db.lastErrorString!='not an error')
+				? ' [ERROR: ' + db.lastErrorString + ']' : '';
+			throw(e + dberr);
+		}
+	}
+},
+
+
+addCallback: function (type, cb)
+{
+	switch (type)
+	{
+		case 'begin':
+		case 'commit':
+		case 'rollback':
+			break;
+			
+		default:
+			throw ("Invalid callback type '" + type + "' in DB.addCallback()");
+	}
+	
+	var id = this._callbacks[type].length;
+	this._callbacks[type][id] = cb;
+	return id;
+},
+
+
+removeCallback: function (type, id)
+{
+	switch (type)
+	{
+		case 'begin':
+		case 'commit':
+		case 'rollback':
+			break;
+			
+		default:
+			throw ("Invalid callback type '" + type + "' in DB.removeCallback()");
+	}
+	
+	delete this._callbacks[type][id];
+},
+
+
+transactionInProgress: function ()
+{
+	var db = this._getDBConnection();
+	return db.transactionInProgress;
+},
+
+
+/**
+ * Safety function used on shutdown to make sure we're not stuck in the
+ * middle of a transaction
+ *
+ * NOTE: No longer used
+ */
+commitAllTransactions: function ()
+{
+	if (this.transactionInProgress())
+	{
+		var level = this._transactionNestingLevel;
+		this._transactionNestingLevel = 0;
+		try {
+			this.commitTransaction();
+		}
+		catch (e) {}
+		return level ? level : true;
+	}
+	return false;
+},
+
+
+/*
+ * Used on shutdown to rollback all open transactions
+ */
+rollbackAllTransactions: function ()
+{
+	if (this.transactionInProgress())
+	{
+		var level = this._transactionNestingLevel;
+		this._transactionNestingLevel = 0;
+		try {
+			this.rollbackTransaction();
+		}
+		catch (e) {}
+		return level ? level : true;
+	}
+	return false;
+},
+
+
+tableExists: function (table)
+{
+	return this._getDBConnection().tableExists(table);
+},
+
+
+getColumns: function (table)
+{
+	var db = this._getDBConnection();
+	
+	try {
+		var sql = "SELECT * FROM " + table + " LIMIT 1";
+		var statement = this.getStatement(sql);
+		var cols = new Array();
+		for (var i=0,len=statement.columnCount; i<len; i++)
+			cols.push(statement.getColumnName(i));
+		statement.reset();
+		return cols;
+	}
+	catch (e) {
+		this._debug(e,1);
+		return false;
+	}
+},
+
+
+getColumnHash: function (table)
+{
+	var cols = this.getColumns(table);
+	var hash = {};
+	if (cols.length)
+	{
+		for (var i=0; i<cols.length; i++)
+			hash[cols[i]] = true;
+	}
+	return hash;
+},
+
+
+/**
+* Find the lowest unused integer >0 in a table column
+*
+* Note: This retrieves all the rows of the column, so it's not really
+*	meant for particularly large tables.
+**/
+getNextID: function (table, column)
+{
+	var sql = 'SELECT ' + column + ' FROM ' + table + ' ORDER BY ' + column;
+	var vals = this.columnQuery(sql);
+	
+	if (!vals)
+		return 1;
+	
+	if (vals[0] === '0')
+		vals.shift();
+	
+	for (var i=0, len=vals.length; i<len; i++)
+	{
+		if (vals[i] != i+1)
+			break;
+	}
+	
+	return i+1;
+},
+
+
+/**
+* Find the next lowest numeric suffix for a value in table column
+*
+* For example, if "Untitled" and "Untitled 2" and "Untitled 4",
+* returns "Untitled 3"
+*
+* DEBUG: doesn't work once there's an "Untitled 10"
+*
+* If _name_ alone is available, returns that
+**/
+getNextName: function (table, field, name)
+{
+	var sql = "SELECT " + field + " FROM " + table + " WHERE " + field
+		+ " LIKE ? ORDER BY " + field + " COLLATE NOCASE";
+	var untitleds = this.columnQuery(sql, name + '%');
+	
+	if (!untitleds || untitleds[0]!=name)
+		return name;
+	
+	var i = 1;
+	var num = 2;
+	while (untitleds[i] && untitleds[i]==(name + ' ' + num))
+	{
+		while (untitleds[i+1] && untitleds[i]==untitleds[i+1])
+		{
+			this._debug('Next ' + i + ' is ' + untitleds[i]);
+			i++;
+		}
+		
+		i++;
+		num++;
+	}
+	
+	return name + ' ' + num;
+},
+
+
+/*
+ * Shutdown observer -- implements nsIObserver
+ */
+observe: function(subject, topic, data)
+{
+	switch (topic)
+	{
+		case 'xpcom-shutdown':
+			this.destroy();
+			
+			break;
+	}
+},
+
+destroy: function ()
+{
+	if (this._shutdown)
+	{
+		this._debug('returning');
+		return;
+	}
+	
+	// NOTE: disabled
+	//var level = this.commitAllTransactions();
+	var level = this.rollbackAllTransactions();
+	if (level)
+	{
+		level = level === true ? '0' : level;
+		this._debug("A transaction in DB '" + this._dbName + "' was still open! (level " + level + ")", 2);
+	}
+	
+	this._shutdown = true;
+	
+	this.skipBackup = (this.skipBackup || (! this._modified) || (! this._parent.getValue("@enable_db_backup"))); 
+	
+	this.backupDatabase();
+	
+	this._parent = null;
+},
+
+integrityCheck: function ()
+{
+	var ok = this.valueQuery("PRAGMA integrity_check");
+	return ok == 'ok';
+},
+
+
+checkException: function (e)
+{
+	if (e.name && e.name == 'NS_ERROR_FILE_CORRUPTED')
+	{
+		// Write corrupt marker to data directory
+		var file = this.getDBFile(this._dbName, 'is.corrupt');
+		var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
+						 .createInstance(Components.interfaces.nsIFileOutputStream);
+		foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate
+		foStream.write('', 0);
+		foStream.close();
+		
+		this._dbIsCorrupt = true;
+		
+//		var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
+//								.getService(Components.interfaces.nsIPromptService);
+//		
+//		var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
+//			+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_IS_STRING);
+//		
+//		var index = ps.confirmEx(null,
+//			Zotero.getString('general.error'),
+//			Zotero.getString('db.dbCorrupted', this._dbName) + '\n\n' + Zotero.getString('db.dbCorrupted.restart'),
+//			buttonFlags,
+//			Zotero.getString('general.restartNow'),
+//			Zotero.getString('general.restartLater'),
+//			null, null, {});
+//		
+//		if (index == 0)
+//		{
+//			var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
+//					.getService(Components.interfaces.nsIAppStartup);
+//			appStartup.quit(Components.interfaces.nsIAppStartup.eRestart);
+//			appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit);
+//		}
+//		
+//		Zotero.skipLoading = true;
+//		return false;
+	}
+	return true;
+},
+
+
+backupDatabase: function (suffix)
+{
+	if (this.transactionInProgress())
+	{
+		this._debug("Transaction in progress--skipping backup of DB '" + this._dbName + "'", 2);
+		return false;
+	}
+	
+	var corruptMarker = this.getDBFile(this._dbName, 'is.corrupt').exists();
+	
+	if (this.skipBackup)
+	{
+		this._debug("Skipping backup of database '" + this._dbName + "'", 1);
+		return false;
+	}
+	else if (this._dbIsCorrupt || corruptMarker)
+	{
+		this._debug("Database '" + this._dbName + "' is marked as corrupt--skipping backup", 1);
+		return false;
+	}
+	
+	this._debug("Backing up database '" + this._dbName + "'");
+	
+	var file = this.getDBFile(this._dbName);
+	var backupFile = this.getDBFile(this._dbName,
+		(suffix ? suffix + '.' : '') + 'bak');
+	
+	// Copy via a temporary file so we don't run into disk space issues
+	// after deleting the old backup file
+	var tmpFile = this.getDBFile(this._dbName, 'tmp');
+	if (tmpFile.exists())
+		tmpFile.remove(null);
+	
+	try {
+		file.copyTo(file.parent, tmpFile.leafName);
+	}
+	catch (e){
+		// TODO: deal with low disk space
+		throw (e);
+	}
+	
+	// Opened database files can't be moved on Windows, so we have to skip
+	// the extra integrity check (unless we wanted to write two copies of
+	// the database, but that doesn't seem like a great idea)
+	if (!this._hostIsWindows())
+	{
+		try {
+			var store = Components.classes["@mozilla.org/storage/service;1"].
+				getService(Components.interfaces.mozIStorageService);
+				
+			var connection = store.openDatabase(tmpFile);
+		}
+		catch (e){
+			this._debug("Database file '" + tmpFile.leafName + "' is corrupt--skipping backup");
+			if (tmpFile.exists())
+				tmpFile.remove(null);
+			return false;
+		}
+	}
+	
+	// Remove old backup file
+	if (backupFile.exists())
+		backupFile.remove(null);
+	
+	tmpFile.moveTo(tmpFile.parent, backupFile.leafName);
+	
+	return true;
+},
+
+_hostIsWindows: function ()
+{
+	var outval = true;
+	try {
+		var appinfo = Components.classes["@mozilla.org/xre/app-info;1"]
+				.getService(Components.interfaces.nsIXULAppInfo);
+		appinfo = appinfo.QueryInterface(Components.interfaces.nsIXULRuntime);
+
+//		spec.id = appinfo.ID;
+//		spec.version = appinfo.version;
+		outval = (appinfo.OS.toLowerCase().indexOf("win") != -1);
+	} catch (e) {}
+	
+	return outval;
+},
+
+/*
+ * Keep the SQLite shared cache live between transactions with a dummy statement,
+ * which speeds up DB access dramatically (at least on Windows and Linux--OS X
+ * seems to be much faster already, perhaps due to its own disk cache)
+ *
+ * This is the same technique used by Mozilla code. The one downside is that it
+ * prevents schema changes, so this is called after schema updating. If the
+ * schema really needs to be updated at another point, use stopDummyStatement().
+ *
+ * See http://developer.mozilla.org/en/docs/Storage:Performance for more info.
+ */
+startDummyStatement: function ()
+{
+//	try {
+		if (!this._dummyConnection)
+		{
+			this._debug("Opening database '" + this._dbName + " for dummy statement");
+			// Get the storage service
+			var store = Components.classes["@mozilla.org/storage/service;1"].
+				getService(Components.interfaces.mozIStorageService);
+			var file = this.getDBFile(this._dbName);
+			this._dummyConnection = store.openDatabase(file);
+		}
+		
+		if (this._dummyStatement)
+		{
+			this._debug("Dummy statement is already open");
+			return;
+		}
+		
+		this._debug("Initializing dummy statement for '" + this._dbName + "'");
+		
+		var sql = "CREATE TABLE IF NOT EXISTS dummyTable (id INTEGER PRIMARY KEY)";
+		this._dummyConnection.executeSimpleSQL(sql);
+		
+		sql = "INSERT OR IGNORE INTO dummyTable VALUES (1)";
+		this._dummyConnection.executeSimpleSQL(sql);
+		
+		sql = "SELECT id FROM dummyTable LIMIT 1";
+		this._dummyStatement = this._dummyConnection.createStatement(sql);
+		this._dummyStatement.executeStep();
+	
+//	}
+//	catch (e) {
+//		Components.utils.reportError(e);
+//		this._debug(e);
+//	}
+},
+
+
+/*
+ * Stop the dummy statement temporarily to allow for schema changess
+ *
+ * The statement needs to be started again or performance will suffer.
+ */
+stopDummyStatement: function ()
+{
+	if (!this._dummyStatement)
+		return;
+	
+	this._debug("Stopping dummy statement for '" + this._dbName + "'");
+	this._dummyStatement.reset();
+	this._dummyStatement = null;
+},
+
+
+getDBFile: function (name, ext)
+{
+	var str;
+	
+	if (name)
+		str = name;
+	else if (this._dbName)
+		str = this._dbName;
+	else
+		str = 'stumbleupon';
+	
+	str += '.sqlite';
+	
+	str += (ext) ? ('.' + ext) : '';
+	
+	var file = this._getStorageDirectory();
+	
+	file.append(str);
+	
+	return file;
+},
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Private methods
+//
+/////////////////////////////////////////////////////////////////
+
+_getStorageDirectory: function ()
+{
+	var file = Components.classes["@mozilla.org/file/directory_service;1"]
+				.getService(Components.interfaces.nsIProperties)
+				.get("ProfD", Components.interfaces.nsIFile);
+
+	file.append("StumbleUpon");
+	if (! file.exists())
+		file.create(file.DIRECTORY_TYPE, 0700);
+	
+	return file;	
+},
+
+_moveToUniqueFile: function (file, newFile)
+{
+	newFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0644);
+	var newName = newFile.leafName;
+	newFile.remove(null);
+	
+	// Move file to unique name
+	file.moveTo(newFile.parent, newName);
+	return file;
+},
+
+/*
+ * Retrieve a link to the data store
+ */
+_getDBConnection: function ()
+{
+	if (this._connection)
+		return this._connection;
+	
+	this._debug("Opening database '" + this._dbName + "'");
+	
+	// Get the storage service
+	var store = Components.classes["@mozilla.org/storage/service;1"].
+		getService(Components.interfaces.mozIStorageService);
+	
+	var file = this.getDBFile(this._dbName);
+	var backupFile = this.getDBFile(this._dbName, 'bak');
+	
+	var fileName = this._dbName + '.sqlite';
+	
+//	if (this._dbName == 'zotero' && ZOTERO_CONFIG['DB_REBUILD'])
+//	{
+//		if (confirm('Erase all user data and recreate database from schema?'))
+//		{
+//			// Delete existing Zotero database
+//			if (file.exists())
+//				file.remove(null);
+//			
+//			// Delete existing storage folder
+//			var dir = Zotero.getStorageDirectory();
+//			if (dir.exists())
+//				dir.remove(true);
+//		}
+//	}
+	
+	catchBlock: try {
+		var corruptMarker = this.getDBFile(this._dbName, 'is.corrupt');
+		if (corruptMarker.exists())
+			throw({ name: 'NS_ERROR_FILE_CORRUPTED' })
+		this._connection = store.openDatabase(file);
+	}
+	catch (e) {
+		if (e.name=='NS_ERROR_FILE_CORRUPTED')
+		{
+			this._debug("Database file '" + file.leafName + "' corrupted", 1);
+			
+			// No backup file! Eek!
+			if (!backupFile.exists())
+			{
+				this._debug("No backup file for DB '" + this._dbName + "' exists", 1);
+				
+				// Save damaged filed
+				this._debug('Saving damaged DB file with .damaged extension', 1);
+				var damagedFile = this.getDBFile(this._dbName, 'damaged');
+				this._moveToUniqueFile(file, damagedFile);
+				
+				// Create new main database
+				var file = this.getDBFile(this._dbName);
+				this._connection = store.openDatabase(file);
+				
+				if (corruptMarker.exists())
+					corruptMarker.remove(null);
+				
+//				alert(Zotero.getString('db.dbCorruptedNoBackup', fileName));
+				break catchBlock;
+			}
+			
+			// Save damaged file
+			this._debug('Saving damaged DB file with .damaged extension', 1);
+			var damagedFile = this.getDBFile(this._dbName, 'damaged');
+			this._moveToUniqueFile(file, damagedFile);
+			
+			// Test the backup file
+			try {
+				this._connection = store.openDatabase(backupFile);
+			}
+			// Can't open backup either
+			catch (e) {
+				// Create new main database
+				var file = this.getDBFile(this._dbName);
+				this._connection = store.openDatabase(file);
+				
+//				alert(Zotero.getString('db.dbRestoreFailed', fileName));
+				
+				if (corruptMarker.exists())
+					corruptMarker.remove(null);
+				
+				break catchBlock;
+			}
+			
+			this._connection = undefined;
+			
+			// Copy backup file to main DB file
+			this._debug("Restoring database '" + this._dbName + "' from backup file", 1);
+			try {
+				backupFile.copyTo(backupFile.parent, fileName);
+			}
+			catch (e) {
+				// TODO: deal with low disk space
+				throw (e);
+			}
+			
+			// Open restored database
+			var file = this._getStorageDirectory();
+			file.append(fileName);
+			this._connection = store.openDatabase(file);
+			this._debug('Database restored', 1);
+//			var msg = Zotero.getString('db.dbRestored', [
+//				fileName,
+//				Zotero.Date.getFileDateString(backupFile),
+//				Zotero.Date.getFileTimeString(backupFile)
+//			]);
+//			alert(msg);
+			
+			if (corruptMarker.exists())
+				corruptMarker.remove(null);
+			
+			break catchBlock;
+		}
+		
+		// Some other error that we don't yet know how to deal with
+		throw (e);
+	}
+	
+	// Register shutdown handler to call this.onShutdown() for DB backup
+	var observerService = Components.classes["@mozilla.org/observer-service;1"]
+		.getService(Components.interfaces.nsIObserverService);
+	observerService.addObserver(this, "xpcom-shutdown", false);
+	observerService = null;
+	
+	return this._connection;
+},
+
+
+_debug: function (str, level)
+{
+	//this._parent._logError(false, {}, "DB ", str);
+},
+
+
+_getTypedValue: function (statement, i)
+{
+	var type = statement.getTypeOfIndex(i);
+	switch (type)
+	{
+		case statement.VALUE_TYPE_INTEGER:
+			return statement.getInt64(i);
+		case statement.VALUE_TYPE_TEXT:
+			return statement.getUTF8String(i);
+		case statement.VALUE_TYPE_NULL:
+			return null;
+		case statement.VALUE_TYPE_FLOAT:
+			return statement.getDouble(i);
+		case statement.VALUE_TYPE_BLOB:
+			return statement.getBlob(i);
+		default:
+			return null;
+	}
+}
+
+} // END prototype
diff --git a/chrome/stumbleupon.jar!/content/contents.rdf b/content/contents.rdf
similarity index 100%
rename from chrome/stumbleupon.jar!/content/contents.rdf
rename to content/contents.rdf
diff --git a/chrome/stumbleupon.jar!/content/datastore.js b/content/datastore.js
similarity index 94%
rename from chrome/stumbleupon.jar!/content/datastore.js
rename to content/datastore.js
index 12a0479..f67ffbc 100644
--- a/chrome/stumbleupon.jar!/content/datastore.js
+++ b/content/datastore.js
@@ -3,7 +3,8 @@
 	* 
 	* handles persistent data and lookup tables
 	*/
-var su_Datastore = function (parent, enabledb)
+	
+StumbleGlobals.Datastore = function (parent, enabledb)
 {
 	this._components = Components;
 	this._parent = parent;
@@ -83,7 +84,7 @@ var su_Datastore = function (parent, enabledb)
 			"nsIWindowMediator");
 	mediator.addListener(this);
 }
-su_Datastore.prototype =
+StumbleGlobals.Datastore.prototype =
 { // BEGIN prototype
 
 // called by parent upon xpcom shutdown
@@ -158,7 +159,7 @@ _openUserDB: function ()
 		return;
 	}
 
-	this._userdb = new su_DatabaseConnection(
+	this._userdb = new StumbleGlobals.DatabaseConnection(
 			this,
 			"user" + this._userid);
 	
@@ -263,19 +264,21 @@ deserialize: function (str)
 	try {
 		if (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.
 					test(str))
-			return eval('(' + str + ')');
-	} catch (e) {}
+		return StumbleGlobals.JSON.parse(str);
+	}
+	catch (e)
+	{
+	}
 	return null;
 },
 
 // creates a json string from an object
 serialize: function (obj, include_linefeeds)
 {
-//	su_dump_object(obj);
-	
 	return this._JSONRecurse(obj, include_linefeeds).join('');
 },
 
+
 _JSONRecurse: function (arg, lf, out)
 {
 	// [IP:] [kudos:] This method is derived from the TrimPath
@@ -312,7 +315,8 @@ SOFTWARE.
 		case 'object':
 			if (! arg)
 			{
-				out.push('"');
+				out.push("null");
+//  why did it have this:	out.push('"');
 			}
 			else if (arg.constructor == Array)
 			{
@@ -529,7 +533,7 @@ getPrefValue: function (id, optionalOverrideDefault)
 		
 		var attemptCount = 0;
 		var success = false;
-		var error = new Object();
+		var error = {};
 		while ((! success) && (attemptCount < this.prefRetries))
 		{
 			attemptCount++;
@@ -537,7 +541,18 @@ getPrefValue: function (id, optionalOverrideDefault)
 			this._verifyPrefAccess();
 		
 			try {
-				eval("value = this._prefBranch.get" + type + "Pref(key)");
+				switch(type) {
+					case "JSON":
+					case "Char":
+						value = this._prefBranch.getCharPref(key);
+						break;
+					case "Bool":
+						value = this._prefBranch.getBoolPref(key);
+						break;
+					case "Int":
+						value = this._prefBranch.getIntPref(key);
+						break;
+				}
 				success = true;
 			}
 			catch (e) {
@@ -585,6 +600,16 @@ getUserPrefValue: function (tmpUserid, id)
 	return retval;
 },
 
+setUserPrefValue: function (tmpUserid, id, value)
+{
+	if (id.charAt(0) != "$")
+		return;
+	var savedUserid = this._userid;
+	this._userid = tmpUserid;
+	this.setPrefValue(id, value);
+	this._userid = savedUserid;
+},
+
 getPrefType: function (id)
 {
 	if ((id.charAt(0) == "$") || (id.charAt(0) == "@"))
@@ -598,7 +623,7 @@ getPrefType: function (id)
 	{
 		var attemptCount = 0;
 		var success = false;
-		var error = new Object();
+		var error = {};
 		var type = null;
 		while ((! success) && (attemptCount < this.prefRetries))
 		{
@@ -701,9 +726,9 @@ getTaggingService: function ()
 /*
 getRating: function ()
 {
-	if (su_host.places)
+	if (StumbleGlobals.host.places)
 	{
-		var db = su_ds.getDatabase();
+		var db = StumbleGlobals.ds.getDatabase();
 		
 		db.a("SELECT rating FROM url_map JOIN url ON url_map.urlid=url.urlid WHERE url=" + db.q(url));
 		var result = db.query();
@@ -1075,7 +1100,7 @@ setPrefValue: function (id, value)
 	
 	var attemptCount = 0;
 	var success = false;
-	var error = new Object();
+	var error = {};
 	while ((! success) && (attemptCount < this.prefRetries))
 	{
 		attemptCount++;
@@ -1083,7 +1108,18 @@ setPrefValue: function (id, value)
 		this._verifyPrefAccess();
 	
 		try {
-			eval("this._prefBranch.set" + type + "Pref(key, value)");
+			switch(type) {
+				case "JSON":
+				case "Char":
+					value = this._prefBranch.setCharPref(key, value);
+					break;
+				case "Bool":
+					value = this._prefBranch.setBoolPref(key, value);
+					break;
+				case "Int":
+					value = this._prefBranch.setIntPref(key, value);
+					break;
+			}
 			success = true;
 		}
 		catch (e) {
@@ -1109,7 +1145,7 @@ isPrefDefined: function (id)
 	
 	var attemptCount = 0;
 	var success = false;
-	var error = new Object();
+	var error = {};
 	var defined = null;
 	while ((! success) && (attemptCount < this.prefRetries))
 	{
@@ -1162,8 +1198,8 @@ getPrefNames: function (prefix)
 {
 	var attemptCount = 0;
 	var success = false;
-	var error = new Object();
-	var list = new Array();
+	var error = {};
+	var list = [];
 	while ((! success) && (attemptCount < this.prefRetries))
 	{
 		attemptCount++;
@@ -1193,7 +1229,7 @@ flushPrefs: function (force)
 	this._prefsDirty = false;
 	var attemptCount = 0;
 	var success = false;
-	var error = new Object();
+	var error = {};
 	while ((! success) && (attemptCount < 1000))
 	{
 		attemptCount++;
@@ -1483,7 +1519,12 @@ _processInstallResourceQueue: function ()
 
 _processInstallResourceQueue2: function ()
 {
-	var maxConnections = Math.round(this.getValue("network.http.max-connections-per-server") / 2);
+	// We build this string dynamically because otherwise the AMO fires off a bogus warning about
+	// reading that network value
+	var key = "net" + 'work.ht';
+	key += "tp.max-conn";
+	key += "ections-per-server";
+	var maxConnections = Math.round(this.getValue(key) / 2);
 	
 	if (maxConnections < 2)
 		maxConnections = 2;
@@ -1520,7 +1561,7 @@ _processInstallResourceQueue2: function ()
 	this._installResourcePendingCount++;
 	
 	if (this._parent._logCommunicationEnabled && this._parent._logResourceCFD)
-		su_log("persist resource", spec.sourceURL, spec.type + "/" + spec.filename);
+		StumbleGlobals.log("persist resource", spec.sourceURL, spec.type + "/" + spec.filename);
 	
 	var persister = this._saveURLResourceToFile(spec.sourceURL, file); 
 	
@@ -1643,11 +1684,11 @@ migrateToContacts: function ()
 	if ((friendsStr != "") && (friendsStr != "FRIEND"))
 		this.updateLegacyFriend(friendsStr);
 	
-	var emails;
+	var emails = [];
 	if (this.isPrefDefined("$emails"))
 		emails = this.getValue("$emails").split("\t");
 	else
-		emails = new Array();
+		emails = [];
 	
 	var i;
 	
@@ -1667,13 +1708,13 @@ migrateToContacts: function ()
 	}
 	
 	
-	var sends;
+	var sends = [];
 	if (this.isPrefDefined("$sendto_stats"))
 		sends = this.getValue("$sendto_stats").split("\n");
 	else if (this.isPrefDefined("$sendtos"))
 		sends = this.getValue("$sendtos").split("\n");
 	else
-		sends = new Array();
+		sends = [];
 	
 	var artificialTimestamp = 1;
 	for (i = sends.length - 1; i >= 0; i--)
@@ -1923,11 +1964,10 @@ getBMTagFromCatid: function (cat)
 		{
 			num = this._catnums[i];
 			bmtag = this._tagnames[num];
-			
 			tmp = this.lookup("topic_tag:bookmark_topic_tag", bmtag);
 			if (tmp)
 				bmtag = tmp;
-			
+
 			this._bmcattags[num] = bmtag.replace(/\-/g, " ");
 		}
 	}
@@ -1957,6 +1997,9 @@ _loadTopicTree: function ()
 	// Parse it into an array
 	var folder = '';
 	var folders = new Array();
+	// Do Windows->Unix line endings
+	catdata = catdata.replace(/\r\n/g, "\n");
+	
 	var splitseen = catdata.split("\n");
 	for (var i = 0; i < splitseen.length; i++)
 	{
@@ -2039,7 +2082,7 @@ getEncodedPassword: function (password, user_salt)
 },
 
 // used by getStoredPassword, by signinDialog, by 
-// handle_change_password and by su_init_new_user to save the password
+// handle_change_password and by StumbleGlobals.init_new_user to save the password
 storePassword: function (password, unhashedPassword)
 {
 	var passwordManager = this._createInstance(
@@ -2088,7 +2131,7 @@ storePassword: function (password, unhashedPassword)
 	}
 	else
 	{
-		if (unhashedPassword != null)
+		if (unhashedPassword)
 			this.setValue("$password", unhashedPassword);
 		this.flushPrefs();
 	}
@@ -2138,7 +2181,7 @@ getStoredPassword: function ()
 	return password;
 },
 
-// used by su_logout to delete the stored password
+// used by StumbleGlobals.logout to delete the stored password
 deleteStoredPassword: function ()
 {
 	if (this.isPrefDefined("$token"))
@@ -2165,7 +2208,7 @@ QueryInterface: function (iid)
 			iid.equals(this._components.interfaces.nsIWindowMediatorListener))
 		return this;
 	else
-		throw this._components.errors.NS_ERROR_NO_INTERFACE;
+		throw this._components.results.NS_ERROR_NO_INTERFACE;
 
 },
 
@@ -2191,7 +2234,7 @@ onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus)
 		}
 		
 		if (this._parent._logCommunicationEnabled && this._parent._logResourceCFD)
-			su_log("resourceinstalled", event.URL);
+			StumbleGlobals.log("resourceinstalled", event.URL);
 		
 		this._dispatchEvent("resourceinstalled", event);
 	}
@@ -2227,7 +2270,7 @@ onWindowTitleChange: function (win) {},
 
 //Code to upgrade database from 1 version to another one
 //When modifying schema for an upgrade :
-//1/ Increment "su_current_schema_version" number
+//1/ Increment "stumbleglobals_current_schema_version" number
 //2/ Add an entry in the switch (dbVersion) with the previous db version
 // and add all your sql statements into the upgradeQuery array.
 //Then the upgrade will be done automatically by running all the needed queries
@@ -2281,24 +2324,24 @@ _upgradeProfileDB: function()
 
 _initConstants: function ()
 {
-	this._dicts["lang_code:language"] = su_const_a;
-	this._dicts["nickname:bad_nick_flag"] = su_const_b;
-	this._dicts["userid:uc_logger_flag"] = su_const_c;
-	this._dicts["toolbarid:bad_target_flag"] = su_const_d;
-	this._dicts["domain:info_message"] = su_const_e;
-	this._dicts["domain:info_message_simple"] = su_const_f;
-	this._dicts["domain:tomore_favicon_list"] = su_const_g;
-	this._dicts["state:poll_interval_s"] = su_const_h;
-	this._dicts["topic_tag:bookmark_topic_tag"] = su_const_i;
-	this._dicts["featureid:bitmask"] = su_const_feature_bits;
-	this._dicts["stumblereportretrycount:timeout"] = su_const_stumble_report_timeouts_s;
+	this._dicts["lang_code:language"] = StumbleGlobals.const_a;
+	this._dicts["nickname:bad_nick_flag"] = StumbleGlobals.const_b;
+	this._dicts["userid:uc_logger_flag"] = StumbleGlobals.const_c;
+	this._dicts["toolbarid:bad_target_flag"] = StumbleGlobals.const_d;
+	this._dicts["domain:info_message"] = StumbleGlobals.const_e;
+	this._dicts["domain:info_message_simple"] = StumbleGlobals.const_f;
+	this._dicts["domain:tomore_favicon_list"] = StumbleGlobals.const_g;
+	this._dicts["state:poll_interval_s"] = StumbleGlobals.const_h;
+	this._dicts["topic_tag:bookmark_topic_tag"] = StumbleGlobals.const_i;
+	this._dicts["featureid:bitmask"] = StumbleGlobals.const_feature_bits;
+	this._dicts["stumblereportretrycount:timeout"] = StumbleGlobals.const_stumble_report_timeouts_s;
  	
-	this._TABLE_IDS_BY_NAME = su_const_tables;
+	this._TABLE_IDS_BY_NAME = StumbleGlobals.const_tables;
 	
 	// Note that we don't support using lookup() to acquire default
 	// values.  Clients who need a default value should use
 	// getDefaultValue().
-	this._DEFAULTS_BY_ID = su_const_defaults;
+	this._DEFAULTS_BY_ID = StumbleGlobals.const_defaults;
 }
 
 
@@ -2306,7 +2349,7 @@ _initConstants: function ()
 } // END prototype
 
 // "lang_code:language" dictionary
-const su_const_a = {
+StumbleGlobals.const_a = {
 "AR":"Arabic",
 "EU":"Basque",
 "BN":"Bengali",
@@ -2351,7 +2394,7 @@ const su_const_a = {
 "VI":"Vietnamese"};
 
 // "nickname:bad_nick_flag" dictionary
-const su_const_b = {
+StumbleGlobals.const_b = {
 "about":1,
 "backup":1,
 "blog":1,
@@ -2425,7 +2468,7 @@ const su_const_b = {
 "wwww":1};
 
 // "userid:uc_logger_flag" dictionary
-const su_const_c = {
+StumbleGlobals.const_c = {
 "1":1,
 "2":1,
 "3":1,
@@ -2456,7 +2499,7 @@ const su_const_c = {
 "5805687":1};
 
 // "toolbarid:bad_target_flag" dictionary
-const su_const_d = {
+StumbleGlobals.const_d = {
 "FindToolbar":1,
 "linktoolbar":1,
 "main-menubar":1,
@@ -2468,7 +2511,7 @@ const su_const_d = {
 "webpedia":1};
 
 // "domain:info_message" dictionary
-const su_const_e = {
+StumbleGlobals.const_e = {
 "wikipedia.org":"Explore a world of knowledge and oddities in the Wikipedia channel.",
 "flickr.com":"See the best of the best pics in the Flickr channel.",
 "myspace.com":"Stumble through music, peeps and more with the Myspace channel.",
@@ -2487,7 +2530,7 @@ const su_const_e = {
 "wired.com":"Catch the latest tech trends in the Wired channel."};
 
 // "domain:info_message_simple" dictionary
-const su_const_f = {
+StumbleGlobals.const_f = {
 "flickr.com":"Click here to Stumble thru Flickr pages.",
 "blogspot.com":"Click here to Stumble thru Blogspot blogs.",
 "wordpress.com":"Click here to Stumble thru Wordpress blogs.",
@@ -2496,7 +2539,7 @@ const su_const_f = {
 ".edu":"Click here to Stumble thru university sites."};
 
 // "domain:tomore_favicon_list" dictionary
-const su_const_g = {
+StumbleGlobals.const_g = {
 "wikipedia.org":"cnn.com,pbs.org,youtube.com",
 "flickr.com":"youtube.com,myspace.com,theonion.com",
 "myspace.com":"youtube.com,flickr.com,theonion.com",
@@ -2512,7 +2555,7 @@ const su_const_g = {
 ".edu":"wikipedia.org,cnn.com,youtube.com"};
 
 // "state:poll_interval_s" dictionary
-const su_const_h = {
+StumbleGlobals.const_h = {
 "a":28800,  // 8h   never sent or received a stumble
 "b":10,     // 10s  sent a referral
 "c":20,     // 20s  from 'b' upon check
@@ -2527,7 +2570,7 @@ const su_const_h = {
 "l":14400}; // 4h   contingency; set via server command
 
 // "topic_tag:bookmark_topic_tag" dictionary
-const su_const_i = {
+StumbleGlobals.const_i = {
 "c-a-d":"cad",
 "children-s-books":"childrens-books",
 "dj-s-mixing":"djs-mixing",
@@ -2536,7 +2579,7 @@ const su_const_i = {
 "women-s-issues":"womens-issues"};
 
 // "featureid:bitmask" dictionary
-const su_const_feature_bits = {
+StumbleGlobals.const_feature_bits = {
 "$sociallinks":             0x00000001,
 "$tagger":                  0x00000002, // reclaimable (was freereporting)
 "$mediareporting":          0x00000004, // reclaimable
@@ -2553,14 +2596,14 @@ const su_const_feature_bits = {
 "$has_subscriptions":		0x00002000};
 
 // _TABLE_IDS_BY_NAME dictionary
-const su_const_tables = {
+StumbleGlobals.const_tables = {
 "contact":"c",
 "dyn_channel":"d",
 "slclick":"s",
 "stumble_visited_urls":"v"};
 
 // The amount of time to wait between submission of failed stumble reports
-const su_const_stumble_report_timeouts_s = {
+StumbleGlobals.const_stumble_report_timeouts_s = {
 	0: 0,
 	1: 60,
 	2: 120,
@@ -2578,7 +2621,7 @@ const su_const_stumble_report_timeouts_s = {
 };
 
 // _DEFAULTS_BY_ID dictionary
-const su_const_defaults = {
+StumbleGlobals.const_defaults = {
 
 // browser session global variable defaults
 "~batched_error_log":          "",    // overridden
@@ -2614,19 +2657,23 @@ const su_const_defaults = {
 "#slprocessed":                false,
 
 // client preference defaults
+"@ab_bits":						0,
 "@auto_cookie_exceptions":		true,
 "@category_reset_timeout":     1 * 60 * 60 * 1000,
 "@clear_favicons":             false,
 "@click_throttle_ms":          1500,
+"@clientid":					"",
 "@client_form":                0,
 "@client_migration_state":     0,     // overridden
 "@client_version":             "",    // overridden
+"@comscore_enabled":			true,
 "@current_user":               "",
 "@db_visitedurls_fail":        false,
 "@dd_display_message":         false,
 "@dd_links_m":                 "",
 "@dd_uc":                      false,
 "@dd_uc_server":               "",
+"@did_force_toggle":			false,
 "@dist_id_list":               "",
 "@dist_reg":                   "0",   // read via getIntValue()
 "@dist_regid":                 "",
@@ -2645,17 +2692,23 @@ const su_const_defaults = {
 "@fbcontacts":                 {},    // stored in prefs table
 "@first_run_time":				"0",  // First time seen in seconds (read via getIntValue())
 "@first_version":				"",
+"@google_is_timeout_ms":		1000,  // The timeout for Google Instant Search pages
 "@id_list":                    "",
 "@installed":                  "0",   // read via getIntValue()
 "@json_db":                    {},    // obsolete v3.05
 "@latch-to-sidebar":           false,
+"@log_communication":			false,
 "@log_prefetch_progress":      false,
+"@min_links_separation_ms":		0,    // Minimum time gap required between requests to links.php
 "@min_noscript_for_prefetch":  "1.9.8.4",
 "@position-group":             "first",
 "@position_history":           "stumbleupon",
 "@recommend_timeout_ms":       60000,
+"@ref_description_style":		"margin: 0px 6px;padding:0px;",
+"@referred_mouseout_timeout_ms":5000,
 "@report_error_count":         0,
 "@report_error_count_max":     3,     // overridden
+"@report_phishing":				true,
 "@right-justify-width":        0,     // overridden
 "@search-width":               156,
 "@server_time_float_s":        3,
@@ -2736,6 +2789,7 @@ const su_const_defaults = {
 "$prefetcher_pass_3_timeout_ms": 120000,
 "$prefetcher_pass_max":        3,
 "$prefetcher_skip_resources":  false,
+"$prev_stumble_stats":			"",
 "$process_rarely_timestamp":   "0",   // read via getIntValue()
 "$query_history_depth":        100,
 "$rate_new_window":            false,
@@ -2754,6 +2808,7 @@ const su_const_defaults = {
 "$sendtos":                    "",    // obsolete v2.7
 "$sendtos_menu_depth":         16,
 "$sendto_stats":               "",    // obsolete v3.0
+"$shortcut_referrals":			"",		// No default value
 "$shortcut_reviews":           "",    // platform-specific
 "$shortcut_stumble":           "",    // platform-specific
 "$shortcut_tag":               "",    // Alt+VK_SLASH
@@ -2768,6 +2823,7 @@ const su_const_defaults = {
 "$shortcuts_enabled":          false,
 "$show_aboutme":               false,
 "$show_editinfo":              false, // obsolete v3.0
+"$show_fbshare":				true,
 "$show_field":                 false,
 "$show_filter":                false,
 "$show_firstrater_label_always": false,
@@ -2780,8 +2836,8 @@ const su_const_defaults = {
 "$show_home_user_changed":     false,
 "$show_info":                  false,
 "$show_info_user_changed":     false,
-"$show_legacy_forums":         false,
-"$show_legacy_network":        false,
+"$show_legacy_forums":         false, // obsolete v3.63
+"$show_legacy_network":        false, // obsolete v3.38?
 "$show_matches":               false,
 "$show_messages":              false,
 "$show_mode":                  false,
@@ -2809,6 +2865,7 @@ const su_const_defaults = {
 "$show_searchlinks_score":     false,
 "$show_separators":            true,
 "$show_tag":                   false,
+"$show_toggle_refcount":		true,
 "$show_topics":                true,
 "$show_tutorial_info":         false,
 "$shown_find_friends":         false,
@@ -2845,7 +2902,7 @@ const su_const_defaults = {
 "$stumbletimes":               "",
 "$stumbletypes":               "",
 "$sync_bm_adult":              false,
-"$sync_bm_meta":               true,
+"$sync_bm_meta":               false,
 "$sync_bm_delete_autotags":    true,
 "$sync_cur_q":                 0,
 "$sync_cur_t":                 "",
diff --git a/chrome/stumbleupon.jar!/content/discoveryDialog.xul b/content/discoveryDialog.xul
similarity index 73%
rename from chrome/stumbleupon.jar!/content/discoveryDialog.xul
rename to content/discoveryDialog.xul
index 863ffbf..84d5867 100644
--- a/chrome/stumbleupon.jar!/content/discoveryDialog.xul
+++ b/content/discoveryDialog.xul
@@ -1,84 +1,86 @@
-<?xml version="1.0"?>
-
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-
-<window id="stumble_discovery_dialog" title="Discovery - StumbleUpon"
-  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-  onload="init();"
-  style="background-color:white;">
-
-<script type="application/x-javascript">
-<![CDATA[
-
-var detail;
-var browser;
-
-function init()
-{
-	detail = window.arguments[0];
-	// Old, Straightforward technique is commented out for now.
-	// We use XMLHttpRequest instead to work around a NoScript problem.  NoScript by default will
-	// block cross-domain POST requests, even if they are from a Chrome URL.  We are hoping Giorgio
-	// will fix this, but until then we need to use the XmlHttpRequest workaround.
-	browser = document.getElementById("browser");
-	var url = opener.su_base_url + detail.uri_suffix;
-	
-	browser.webNavigation.loadURI(
-				url,
-				Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE,
-				opener.su_get_nsiuri(opener.getBrowser().contentDocument.referrer),
-				opener.su_get_mime_input_stream(detail.postdata, "application/x-www-form-urlencoded"),
-				null); // headers
-	browser.addEventListener("click", handle_content_click, false);
-
-}
-
-function handle_content_click(event)
-{
-	if (event.originalTarget.hasAttribute("ondblclick"))
-		ondblclick = event.originalTarget.getAttribute("ondblclick");
-	
-	var current_page = opener.su_get_browser_url(event.target.ownerDocument, true);
-	
-	if(ondblclick == "whitelist_stumbleupon_with_noscript")
-	{
-		var tld = opener.su_get_tld(current_page);
-		if (tld == opener.su_servername)
-		{
-			opener.su_update_noscript_whitelists();
-			var ps = opener.su_get_service(
-						"@mozilla.org/embedcomp/prompt-service;1",
-						"nsIPromptService");
-			
-			ps.alert(window, "StumbleUpon", "NoScript configuration updated.  Please try the operation again.");
-			window.close();
-		}
-	}
-
-	return true;
-}
-
-function handle_submit_command()
-{
-	try {
-		var el = browser.contentDocument.getElementById("tagtext");
-		if (el)
-			detail.tagtext = decodeURIComponent(el.getAttribute("value"));
-	} catch (e) {}
-	detail.submitted = true;
-	window.close();
-}
-
-function handle_cancel_command()
-{
-	window.close();
-}
-
-document.addEventListener("RATING_CANCELLED", handle_cancel_command, false, true);
-document.addEventListener("RATING_SUBMITTED", handle_submit_command, false, true);
-
-]]>
-</script>
-<browser id="browser" 
-flex="1"/>
-</window>
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window id="stumble_discovery_dialog" title="Discovery - StumbleUpon"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+  onload="init();"
+  style="background-color:white;">
+
+<script type="application/x-javascript">
+<![CDATA[
+
+var detail;
+var browser;
+
+function init()
+{
+	detail = window.arguments[0];
+	// Old, Straightforward technique is commented out for now.
+	// We use XMLHttpRequest instead to work around a NoScript problem.  NoScript by default will
+	// block cross-domain POST requests, even if they are from a Chrome URL.  We are hoping Giorgio
+	// will fix this, but until then we need to use the XmlHttpRequest workaround.
+	browser = document.getElementById("browser");
+	var url = opener.StumbleGlobals.base_url + detail.uri_suffix;
+	
+	browser.webNavigation.loadURI(
+				url,
+				Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE,
+				opener.StumbleGlobals.get_nsiuri(opener.getBrowser().contentDocument.referrer),
+				opener.StumbleGlobals.get_mime_input_stream(detail.postdata, "application/x-www-form-urlencoded"),
+				null); // headers
+	browser.addEventListener("click", handle_content_click, false);
+
+}
+
+function handle_content_click(event)
+{
+	var ondblclick = null;	
+	if (event.originalTarget.hasAttribute("ondblclick"))
+		ondblclick = event.originalTarget.getAttribute("ondblclick");
+	
+	var current_page = opener.StumbleGlobals.get_browser_url(event.target.ownerDocument, true);
+	
+	if(ondblclick == "whitelist_stumbleupon_with_noscript")
+	{
+		var tld = opener.StumbleGlobals.get_tld(current_page);
+		if (tld == opener.StumbleGlobals.servername)
+		{
+			opener.StumbleGlobals.update_noscript_whitelists();
+			var ps = opener.StumbleGlobals.get_service(
+						"@mozilla.org/embedcomp/prompt-service;1",
+						"nsIPromptService");
+			
+			ps.alert(window, "StumbleUpon", "NoScript configuration updated.  Please try the operation again.");
+			window.close();
+		}
+	}
+
+	return true;
+}
+
+function handle_submit_command()
+{
+	try {
+		var el = browser.contentDocument.getElementById("tagtext");
+		if (el)
+			detail.tagtext = decodeURIComponent(el.getAttribute("value"));
+	} catch (e) {}
+	detail.submitted = true;
+	window.close();
+}
+
+function handle_cancel_command()
+{
+	window.close();
+}
+
+document.addEventListener("RATING_CANCELLED", handle_cancel_command, false, true);
+document.addEventListener("RATING_SUBMITTED", handle_submit_command, false, true);
+
+]]>
+</script>
+<browser id="browser"
+type="content"
+flex="1"/>
+</window>
diff --git a/chrome/stumbleupon.jar!/content/downloadFavsDialog.xul b/content/downloadFavsDialog.xul
similarity index 88%
rename from chrome/stumbleupon.jar!/content/downloadFavsDialog.xul
rename to content/downloadFavsDialog.xul
index 399c6f0..b874dd1 100644
--- a/chrome/stumbleupon.jar!/content/downloadFavsDialog.xul
+++ b/content/downloadFavsDialog.xul
@@ -46,10 +46,10 @@ function start()
 		setCursor("wait");
 	} catch (e) {}
 	
-	opener.setTimeout(function (parent) { parent.su_download_favs(true); }, 0, opener);
+	opener.setTimeout(function (parent) { parent.StumbleGlobals.download_favs(true); }, 0, opener);
 	
-	if (! opener.su_ds.getValue("#migrating_places"))
-		opener.su_backup_places("DOWNLOADFAVS BACKUP");
+	if (! opener.StumbleGlobals.ds.getValue("#migrating_places"))
+		opener.StumbleGlobals.backup_places("DOWNLOADFAVS BACKUP");
 	
 	var interval = ((new Date()).getTime()) - start_time;
 	
diff --git a/content/extensionApi.js b/content/extensionApi.js
new file mode 100644
index 0000000..192b60c
--- /dev/null
+++ b/content/extensionApi.js
@@ -0,0 +1,199 @@
+//
+// extensionApi.js
+//
+// This code provides the suExtensionApi implementation to the 
+// stumbleupon.com web pages.
+//
+StumbleGlobals.extension_api = function(window) {
+	this.id = null;
+	this._siteWindow = window;
+
+	// -------------------------------------------------------------------
+	// Message support
+	// -------------------------------------------------------------------
+	// Note that this doesn't exist in the prototype because it has its own properties
+	// that we don't want to share amongst other objects.
+	this.message = {
+		_api: this,
+		_listeners: [],
+		
+		_handleIncoming: function(msg) {
+			if(msg.target && (msg.target.id != this._api.id))
+				return;
+			// Send the message to the listeners.
+			for(var i=0; i<this._listeners.length; i++)
+			{
+				this._listeners[i](msg.messageId, msg.data, msg.sender);
+			}
+		},
+		
+		addListener: function(fnListener) {
+			this.removeListener(fnListener);
+			this._listeners.push(fnListener);
+		},
+		
+		removeListener: function(fnListener) {
+			for(var i=0; i<this._listeners.length; i++)
+			{
+				if(this._listeners[i] === fnListener)
+				{
+					this._listeners.splice(i, 1);
+					return;
+				}
+			}
+		},
+		
+		broadcastMessage: function(messageId, data) {
+			var sender = { id: this._api.id };
+			var msg = { sender: sender, messageId: messageId, data: data };
+			var obsService = Components.classes["@mozilla.org/observer-service;1"]
+								.getService(Components.interfaces.nsIObserverService);
+			obsService.notifyObservers(null, "stumbleglobals_extensionapi_message", StumbleGlobals.ds.serialize(msg));
+		},
+		
+		postMessage: function(target, messageId, data) {
+			var sender = { id: this._api.id };
+			var msg = { sender: sender, target: target, messageId: messageId, data: data };
+			var obsService = Components.classes["@mozilla.org/observer-service;1"]
+								.getService(Components.interfaces.nsIObserverService);
+			obsService.notifyObservers(null, "stumbleglobals_extensionapi_message", StumbleGlobals.ds.serialize(msg));
+		}
+	
+	};
+	
+	this._init();
+}
+
+// -------------------------------------------------------------------
+// Top-level StumbleGlobals.extension_api methods
+// -------------------------------------------------------------------
+StumbleGlobals.extension_api.prototype = {
+	
+	// -------------------------------------------------------------------
+	// Core functionality
+	// -------------------------------------------------------------------
+	getProviderInfo: function(callback) {
+		var info = {
+			apiVersion: "1.0",
+			provider: "mozbar"
+		}
+		info.providerVersion = StumbleGlobals.mozbar_version + "." + StumbleGlobals.private_label;
+		callback(info);
+	},
+	
+	getDomain: function(callback) {
+		callback(StumbleGlobals.servername);
+	},
+
+	oldbar: {
+		processCommands: function(commands) {
+			StumbleGlobals.process_commands(commands);
+		}
+	},
+	
+	// -------------------------------------------------------------------
+	// Data functionality
+	// -------------------------------------------------------------------
+	data: {
+		_normalizeKey: function(key) {
+			if(key.indexOf("@@") == 0)
+			{
+				key = key.slice(2);
+			}
+			else
+			{
+				key = "@extapi." + key;
+			}
+			return key;
+		},
+		
+		getValue: function(key, callback) {
+			var value = null;
+			key = this._normalizeKey(key);
+			if(StumbleGlobals.ds.isPrefDefined(key))
+				value = StumbleGlobals.ds.getPrefValue(key, "JSON");
+			callback(StumbleGlobals.ds.deserialize(value));
+		},
+		
+		setValue: function(key, value, callback) {
+			key = this._normalizeKey(key);
+			if(value == null)
+			{
+				StumbleGlobals.ds.clearPref(key);
+			}
+			else
+			{
+				StumbleGlobals.ds.setValue(key, value);
+			}
+			if(typeof(callback) != "undefined")
+				callback();
+		}
+	},
+	
+	isReady: function() {
+		return this._initialized;
+	},
+
+	// -------------------------------------------------------------------
+	// Private implementation methods
+	// -------------------------------------------------------------------
+	
+	// observer service callback.
+	observe: function(subject, topic, data) 
+	{
+		if(topic == "stumbleglobals_extensionapi_message") 
+		{
+			msg = StumbleGlobals.ds.deserialize(data);
+			this.message._handleIncoming(msg);
+		}
+	},
+	
+	_generateEndpointId: function() {
+		return Math.floor(Math.random() * 100000000);
+	},
+	
+	// -------------------------------------------------------------------
+	// Private initialization
+	// -------------------------------------------------------------------
+	_init: function() {
+		if(this._initialized)
+			return;
+		
+		// Generate a new endpoint id
+		this.id = this._generateEndpointId();
+		
+		// Listen for messages using the observer service
+		var obsService = Components.classes["@mozilla.org/observer-service;1"]
+							.getService(Components.interfaces.nsIObserverService);
+		obsService.addObserver(this, "stumbleglobals_extensionapi_message", false);
+		
+		// Listen for the window to unload so we can clean up
+		var me = this;
+		this._siteWindow.addEventListener("unload", function() {
+			me._uninit();
+		}, false);
+		
+		this._initialized = true;
+
+		// Notify anyone who has been waiting for us to be ready.
+		window.setTimeout(function() {
+			var scriptReadyEvent = me._siteWindow.document.createEvent("Event");
+			scriptReadyEvent.initEvent("suScriptReadyExtensionApi", false, false);
+			me._siteWindow.dispatchEvent(scriptReadyEvent);
+		}, 0);
+	},
+	
+	_uninit: function() {
+		// Remove any reference to ourselves
+		this._siteWindow.suExtensionApi = null;
+
+		// Remove our references to client listeners
+		this.message._listeners = [];
+
+		// Remove ourselves as an observer service listener
+		var obsService = Components.classes["@mozilla.org/observer-service;1"]
+							.getService(Components.interfaces.nsIObserverService);
+		obsService.removeObserver(this, "stumbleglobals_extensionapi_message");
+	}
+}
+
diff --git a/content/initOverlay.js b/content/initOverlay.js
new file mode 100644
index 0000000..9a03f5f
--- /dev/null
+++ b/content/initOverlay.js
@@ -0,0 +1,234 @@
+/***
+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 StumbleUpon code.
+The Initial Developer of the Original Code is StumbleUpon.
+
+Portions created by StumbleUpon are
+Copyright (C) 2002-2007 StumbleUpon.  All
+Rights Reserved.
+
+Original Author: Geoff Smith <geoff at stumbleupon.com>
+Contributor(s): Garrett Camp <gmc at stumbleupon.com>
+		Joe Walp <joewalp at yahoo.com>
+		Manpreet Singh (loonyone.stumbleupon.com)
+		Don Schmitt <don at stumbleupon.com>
+
+Questions/Comments?  Please send them here:
+
+http://www.stumbleupon.com/feedback.php
+
+Copyright notes:
+1. No code contributed by Manpreet Singh remains in the codebase.
+2. Regardless of intellectual property claims, Manpreet Singh supports
+   changing the license from MPL to MPL/GPL/LGPL tri-license if other
+	 contributors so choose.  For reference:
+	 http://www.mozilla.org/MPL/boilerplate-1.1/mpl-tri-license-txt
+3. For additional intellectual property considerations, search for 
+   [IP:] and [kudos:] in the code.
+
+***/
+
+
+/***
+
+    INITOVERLAY
+
+The purpose of this file is to do the minimum amount of work necessary to initialize
+the main overlay file.  It runs at start-up, does what is necessary, then loads the
+main overlay file later, thus avoiding delays in the browser's initialization so the
+user can get their initial pages loaded as fast as possible.
+
+***/
+
+if(!StumbleGlobals)
+	StumbleGlobals = {};
+
+/***
+  Global variables and utility functions that are also needed to perform the
+  bootstrap operations.
+***/
+StumbleGlobals.mozbar_version = "3.91";
+StumbleGlobals.useragent = "mozbar " + StumbleGlobals.mozbar_version + " xpi";
+StumbleGlobals.servername = 'stumbleupon.com';
+StumbleGlobals.serverhttp = 'http://www.' + StumbleGlobals.servername + '/';
+StumbleGlobals.serverhttps = 'https://www.' + StumbleGlobals.servername + '/';
+StumbleGlobals.serviceshttp = 'http://services.' + StumbleGlobals.servername + '/' + '1.02/';
+
+
+StumbleGlobals.include = function(uri)
+{
+	try {
+		var loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
+					.getService(Components.interfaces["mozIJSSubScriptLoader"]);
+		loader.loadSubScript(uri);
+	} catch(ex) {
+	}
+}
+
+StumbleGlobals.get_service = function(nsclass, nsinterface)
+{
+	try {
+		return Components.classes[nsclass].getService(Components.interfaces[nsinterface]);
+	}
+	catch (e) {
+		return null;
+	}
+}
+
+/***
+ A minimal datastore provider.  It will be replaced by the true datastore when full initilaization
+ happens in initOverlay.js.
+
+ We use a minimal store to avoid writing, flushing, default value initialization, all the work
+ that is done in the normal datastore.
+ 
+***/
+StumbleGlobals.ds = {
+	init: function() {
+		this._prefService =
+					Components.classes["@mozilla.org/preferences-service;1"]
+					.getService(Components.interfaces.nsIPrefService);
+	
+		this._prefBranch = this._prefService.getBranch("");
+		if(!this.isPrefDefined("@current_user"))
+			this._userid = 0;
+		else
+			this._userid = this.getCharPref("@current_user");
+		return this;
+	},
+	
+	getCurrentUser: function() {
+		return this._userid;
+	},
+
+	isPrefDefined: function(key) {
+		var key = this._expandKey(key);
+		return this._prefBranch.prefHasUserValue(key);
+	},
+	
+	getStoredPassword: function() {
+		var password = null;
+		
+		if (this._userid == "")
+			return null;
+		
+		if (this.isPrefDefined("$token"))
+			return this.getCharPref("$token");
+		
+		return null;
+	},
+	
+	getCharPref: function(key) {
+		return this._prefBranch.getCharPref(this._expandKey(key));
+	},
+	
+	_expandKey: function (key)
+	{
+		if (key.charAt(0) == "$")
+			return "stumble." + this._userid + "." + key.substr(1);
+		else if (key.charAt(0) == "@")
+			return "stumble." + key.substr(1);
+		else
+			return key;
+	}
+}.init();
+
+
+StumbleGlobals.is_server_page = function(url, path)
+{
+	return ((url.indexOf(StumbleGlobals.serverhttp + path) == 0) ||
+			(url.indexOf(StumbleGlobals.serverhttps + path) == 0) ||
+			(url.indexOf(StumbleGlobals.serviceshttp + path) == 0));
+}
+
+/***
+  We need the initial http_observer because we may need to provide credentials to pages
+  that are loaded at start-up before the overlay is initialized.
+  
+  Note that the main overlay file will replace this with a more complete implementation that
+  does more work.
+
+***/
+StumbleGlobals.init_http_observer = 
+{
+	// This is the observerService's observe listener method.
+	observe: function(aSubject, aTopic, aData) 
+	{
+		if (aTopic == 'http-on-modify-request') 
+		{
+			if (typeof(Components) != "undefined")
+			{
+				aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
+				this.onModifyRequest(aSubject);
+			}
+		} 
+	},
+
+	// Modify stumbleupon.com requests by adding version and authentication headers
+	onModifyRequest : function (oHttp)
+	{
+		if (!StumbleGlobals.is_server_page(oHttp.URI.asciiSpec, ""))
+			return;
+		
+		var userid = StumbleGlobals.ds.getCurrentUser();
+		var password = StumbleGlobals.ds.getStoredPassword();
+		oHttp.setRequestHeader("X-SU-Version", StumbleGlobals.useragent, 0);
+		
+		if(userid == 0)
+		{
+			var clientid = StumbleGlobals.ds.getCharPref("@clientid");
+			if(clientid)
+			{
+				oHttp.setRequestHeader("X-SU-ClientID", clientid, 0);
+			}
+			
+			// No userid, so we're done
+			return;
+		}
+
+		// send authentication headers
+		// 0 = do not merge header with old headers, replace them
+		oHttp.setRequestHeader('X-SU-Username', userid, 0);
+		oHttp.setRequestHeader('X-SU-Password', password, 0);
+		oHttp.setRequestHeader("X-SU-Version", StumbleGlobals.useragent, 0);
+	}
+}
+
+StumbleGlobals.bootstrap = function() {
+	// We delay our initialization until the window is loaded plus 1 second just so we don't
+	// impact start-up performance which is something Mozilla is really focused on.
+	window.addEventListener("load",  function() {
+			// Set a timeout to load and initialize the rest of the overlay
+			window.setTimeout(function() {
+				// Remove our temporary observer
+				observer_service.removeObserver(StumbleGlobals.init_http_observer, "http-on-modify-request");
+				if(!StumbleGlobals.handle_window_load)
+				{
+					// If it's not loaded already, then load it.
+					StumbleGlobals.include("chrome://stumbleupon/content/stumbleuponOverlay.js");
+				}
+				// And call the load initialization routine.
+				StumbleGlobals.handle_window_load();
+			}, 1000);
+	}, false);
+
+	// We do early observation of HTTP requests before everything else is loaded just to be sure
+	// we can authenticate pre-loaded tabs.  This observer is removed and replaced by observers established
+	// in stumbleUponOverlay.js.
+	var observer_service = StumbleGlobals.get_service(
+				"@mozilla.org/observer-service;1",
+				"nsIObserverService");
+	observer_service.addObserver(StumbleGlobals.init_http_observer, "http-on-modify-request", false);
+}
+
+
+StumbleGlobals.bootstrap();
diff --git a/content/json_sans_eval.js b/content/json_sans_eval.js
new file mode 100644
index 0000000..27c5829
--- /dev/null
+++ b/content/json_sans_eval.js
@@ -0,0 +1,250 @@
+// This source code is free for use in the public domain.
+// NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+// http://code.google.com/p/json-sans-eval/
+
+/**
+ * Parses a string of well-formed JSON text.
+ *
+ * If the input is not well-formed, then behavior is undefined, but it is
+ * deterministic and is guaranteed not to modify any object other than its
+ * return value.
+ *
+ * This does not use `eval` so is less likely to have obscure security bugs than
+ * json2.js.
+ * It is optimized for speed, so is much faster than json_parse.js.
+ *
+ * This library should be used whenever security is a concern (when JSON may
+ * come from an untrusted source), speed is a concern, and erroring on malformed
+ * JSON is *not* a concern.
+ *
+ *                      Pros                   Cons
+ *                    +-----------------------+-----------------------+
+ * json_sans_eval.js  | Fast, secure          | Not validating        |
+ *                    +-----------------------+-----------------------+
+ * json_parse.js      | Validating, secure    | Slow                  |
+ *                    +-----------------------+-----------------------+
+ * json2.js           | Fast, some validation | Potentially insecure  |
+ *                    +-----------------------+-----------------------+
+ *
+ * json2.js is very fast, but potentially insecure since it calls `eval` to
+ * parse JSON data, so an attacker might be able to supply strange JS that
+ * looks like JSON, but that executes arbitrary javascript.
+ * If you do have to use json2.js with untrusted data, make sure you keep
+ * your version of json2.js up to date so that you get patches as they're
+ * released.
+ *
+ * @param {string} json per RFC 4627
+ * @param {function (this:Object, string, *):*} opt_reviver optional function
+ *     that reworks JSON objects post-parse per Chapter 15.12 of EcmaScript3.1.
+ *     If supplied, the function is called with a string key, and a value.
+ *     The value is the property of 'this'.  The reviver should return
+ *     the value to use in its place.  So if dates were serialized as
+ *     {@code { "type": "Date", "time": 1234 }}, then a reviver might look like
+ *     {@code
+ *     function (key, value) {
+ *       if (value && typeof value === 'object' && 'Date' === value.type) {
+ *         return new Date(value.time);
+ *       } else {
+ *         return value;
+ *       }
+ *     }}.
+ *     If the reviver returns {@code undefined} then the property named by key
+ *     will be deleted from its container.
+ *     {@code this} is bound to the object containing the specified property.
+ * @return {Object|Array}
+ * @author Mike Samuel <mikesamuel at gmail.com>
+ *
+ * UPDATES
+ *
+ * 2/14/11 - Don Schmitt
+ *           Adapted to not use the stumbleupon name prefix "StumbleGlobals"
+ *
+ */
+
+if(typeof(StumbleGlobals) == "undefined")
+	var StumbleGlobals = {};
+
+StumbleGlobals.JSON = {};
+
+StumbleGlobals.JSON.parse = (function () {
+  var number
+      = '(?:-?\\b(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b)';
+  var oneChar = '(?:[^\\0-\\x08\\x0a-\\x1f\"\\\\]'
+      + '|\\\\(?:[\"/\\\\bfnrt]|u[0-9A-Fa-f]{4}))';
+  var string = '(?:\"' + oneChar + '*\")';
+
+  // Will match a value in a well-formed JSON file.
+  // If the input is not well-formed, may match strangely, but not in an unsafe
+  // way.
+  // Since this only matches value tokens, it does not match whitespace, colons,
+  // or commas.
+  var jsonToken = new RegExp(
+      '(?:false|true|null|[\\{\\}\\[\\]]'
+      + '|' + number
+      + '|' + string
+      + ')', 'g');
+
+  // Matches escape sequences in a string literal
+  var escapeSequence = new RegExp('\\\\(?:([^u])|u(.{4}))', 'g');
+
+  // Decodes escape sequences in object literals
+  var escapes = {
+    '"': '"',
+    '/': '/',
+    '\\': '\\',
+    'b': '\b',
+    'f': '\f',
+    'n': '\n',
+    'r': '\r',
+    't': '\t'
+  };
+  function unescapeOne(_, ch, hex) {
+    return ch ? escapes[ch] : String.fromCharCode(parseInt(hex, 16));
+  }
+
+  // A non-falsy value that coerces to the empty string when used as a key.
+  var EMPTY_STRING = new String('');
+  var SLASH = '\\';
+
+  // Constructor to use based on an open token.
+  var firstTokenCtors = { '{': Object, '[': Array };
+
+  var hop = Object.hasOwnProperty;
+
+  return function (json, opt_reviver) {
+    // Split into tokens
+    var toks = json.match(jsonToken);
+    // Construct the object to return
+    var result;
+    var tok = toks[0];
+    var topLevelPrimitive = false;
+    if ('{' === tok) {
+      result = {};
+    } else if ('[' === tok) {
+      result = [];
+    } else {
+      // The RFC only allows arrays or objects at the top level, but the JSON.parse
+      // defined by the EcmaScript 5 draft does allow strings, booleans, numbers, and null
+      // at the top level.
+      result = [];
+      topLevelPrimitive = true;
+    }
+
+    // If undefined, the key in an object key/value record to use for the next
+    // value parsed.
+    var key;
+    // Loop over remaining tokens maintaining a stack of uncompleted objects and
+    // arrays.
+    var stack = [result];
+    for (var i = 1 - topLevelPrimitive, n = toks.length; i < n; ++i) {
+      tok = toks[i];
+
+      var cont;
+      switch (tok.charCodeAt(0)) {
+        default:  // sign or digit
+          cont = stack[0];
+          cont[key || cont.length] = +(tok);
+          key = void 0;
+          break;
+        case 0x22:  // '"'
+          tok = tok.substring(1, tok.length - 1);
+          if (tok.indexOf(SLASH) !== -1) {
+            tok = tok.replace(escapeSequence, unescapeOne);
+          }
+          cont = stack[0];
+          if (!key) {
+            if (cont instanceof Array) {
+              key = cont.length;
+            } else {
+              key = tok || EMPTY_STRING;  // Use as key for next value seen.
+              break;
+            }
+          }
+          cont[key] = tok;
+          key = void 0;
+          break;
+        case 0x5b:  // '['
+          cont = stack[0];
+          stack.unshift(cont[key || cont.length] = []);
+          key = void 0;
+          break;
+        case 0x5d:  // ']'
+          stack.shift();
+          break;
+        case 0x66:  // 'f'
+          cont = stack[0];
+          cont[key || cont.length] = false;
+          key = void 0;
+          break;
+        case 0x6e:  // 'n'
+          cont = stack[0];
+          cont[key || cont.length] = null;
+          key = void 0;
+          break;
+        case 0x74:  // 't'
+          cont = stack[0];
+          cont[key || cont.length] = true;
+          key = void 0;
+          break;
+        case 0x7b:  // '{'
+          cont = stack[0];
+          stack.unshift(cont[key || cont.length] = {});
+          key = void 0;
+          break;
+        case 0x7d:  // '}'
+          stack.shift();
+          break;
+      }
+    }
+    // Fail if we've got an uncompleted object.
+    if (topLevelPrimitive) {
+      if (stack.length !== 1) { throw new Error(); }
+      result = result[0];
+    } else {
+      if (stack.length) { throw new Error(); }
+    }
+
+    if (opt_reviver) {
+      // Based on walk as implemented in http://www.json.org/json2.js
+      var walk = function (holder, key) {
+        var value = holder[key];
+        if (value && typeof value === 'object') {
+          var toDelete = null;
+          for (var k in value) {
+            if (hop.call(value, k) && value !== holder) {
+              // Recurse to properties first.  This has the effect of causing
+              // the reviver to be called on the object graph depth-first.
+
+              // Since 'this' is bound to the holder of the property, the
+              // reviver can access sibling properties of k including ones
+              // that have not yet been revived.
+
+              // The value returned by the reviver is used in place of the
+              // current value of property k.
+              // If it returns undefined then the property is deleted.
+              var v = walk(value, k);
+              if (v !== void 0) {
+                value[k] = v;
+              } else {
+                // Deleting properties inside the loop has vaguely defined
+                // semantics in ES3 and ES3.1.
+                if (!toDelete) { toDelete = []; }
+                toDelete.push(k);
+              }
+            }
+          }
+          if (toDelete) {
+            for (var i = toDelete.length; --i >= 0;) {
+              delete value[toDelete[i]];
+            }
+          }
+        }
+        return opt_reviver.call(holder, key, value);
+      };
+      result = walk({ '': result }, '');
+    }
+
+    return result;
+  };
+})();
diff --git a/content/migrate.js b/content/migrate.js
new file mode 100644
index 0000000..cd3e94c
--- /dev/null
+++ b/content/migrate.js
@@ -0,0 +1,934 @@
+
+StumbleGlobals.migrate_version = function()
+{
+	var had_version = StumbleGlobals.ds.isPrefDefined("@client_version");
+	var prev_version = StumbleGlobals.ds.getPrefValue("@client_version", StumbleGlobals.useragent);
+	if (had_version && (prev_version == StumbleGlobals.useragent))
+		return;
+	StumbleGlobals.ds.setValue("@client_version", StumbleGlobals.useragent);
+	
+	// After upgrading, this routine gets run once.  For a new migration
+	// routine:
+	// 1: Create a M_[identifier] constant using the next sequential bit
+	// 2: OR that bit with the others in the 'if (StumbleGlobals.new_install)' block
+	// 3: Add the migration routine near the bottom, as indicated by the
+	//    comment there.
+	// 4: Gate the migration routine using the bit.
+	// 5: Be sure to OR the bit at the end of the migration routine.
+
+	const M_PASSWORDS = 0x1;
+	const M_IDS = 0x2;
+	const M_POSITION = 0x4;
+	const M_PREFS_DB = 0x8;
+	const M_V3_27 = 0x10;
+	
+	if (StumbleGlobals.new_install)
+	{
+		StumbleGlobals.ds.setValue("@client_migration_state", M_PASSWORDS | 
+					M_IDS | M_POSITION | M_PREFS_DB | M_V3_27);
+		StumbleGlobals.ds.flushPrefs();
+		return;
+	}
+
+	StumbleGlobals.new_upgrade = true;
+	StumbleGlobals.prev_version = prev_version;
+	StumbleGlobals.ds.setValue("@report_error_count", 0);
+	StumbleGlobals.ds.setValue("@report_error_count_max", 3);
+	if (! StumbleGlobals.ds.isPrefDefined("@dd_display_message"))
+		StumbleGlobals.ds.setValue("@dd_display_message", false);
+	
+	var migration_bitfield = StumbleGlobals.ds.getValue("@client_migration_state");
+
+	try {  // migration can be tricky, so we do a try
+
+	
+	if (! (migration_bitfield & M_PASSWORDS))
+	{
+		// Clear passwords left by old versions.
+		StumbleGlobals.migrate_clear_old_passwords();
+		migration_bitfield |= M_PASSWORDS;
+	}
+
+	if (! (migration_bitfield & M_IDS))
+	{
+		// Fix a bug in version 2.81.
+		if ((StumbleGlobals.ds.getPrefType("stumble.ids") == "Bool") && (StumbleGlobals.stumbleid != 0))
+			StumbleGlobals.ds.setValue("@id_list", StumbleGlobals.stumbleid + ":");
+		else if (StumbleGlobals.ds.getPrefType("stumble.ids") == "Char")
+			StumbleGlobals.ds.setValue("@id_list", StumbleGlobals.ds.getValue("stumble.ids"));
+
+		StumbleGlobals.ds.clearPref("stumble.ids");
+		migration_bitfield |= M_IDS;
+	}
+
+	if (! (migration_bitfield & M_POSITION))
+	{
+		// Clear passwords left by old versions.
+		StumbleGlobals.migrate_toolbar_position_scheduled = true;
+		migration_bitfield |= M_POSITION;
+	}
+
+	if (! (migration_bitfield & M_PREFS_DB))
+	{
+		// version 3.05
+		try {
+			StumbleGlobals.migrate_contacts_to_prefs();
+		}
+		catch (e) {
+			setTimeout(function() {
+				StumbleGlobals.migrate_contacts_to_prefs_delayed();
+			}, 8000);
+		}
+		migration_bitfield |= M_PREFS_DB;
+	}
+	
+	if (! (migration_bitfield & M_V3_27))
+	{
+		StumbleGlobals.ds.setValue("@enable_db_backup", false);
+		
+		migration_bitfield |= M_V3_27;
+	}
+	
+	// Add each new version migration routine immediately above.
+
+	} catch (e) { try { StumbleGlobals.log_error("MIGRATE VERSION", e); } catch (ee) {} }
+
+	StumbleGlobals.ds.setValue("@client_migration_state", migration_bitfield)
+	StumbleGlobals.ds.flushPrefs();
+}
+
+// used during init to handle version-specific migration
+StumbleGlobals.migrate_profile = function(new_profile)
+{
+	setTimeout(function() {
+		StumbleGlobals.migrate_places();
+	}, 0);
+	
+	var had_version = StumbleGlobals.ds.isPrefDefined("$version");
+	var prev_version = StumbleGlobals.ds.getPrefValue("$version", StumbleGlobals.useragent);
+	if (had_version && (prev_version == StumbleGlobals.useragent))
+		return;
+	StumbleGlobals.ds.setValue("$version", StumbleGlobals.useragent);
+
+	// After upgrading, this routine gets run once for each profile,
+	// upon the first use of that profile.  For a new migration routine:
+	// 1: Create a M_[identifier] constant using the next sequential bit
+	// 2: OR that bit with the others in the 'if (StumbleGlobals.new_install)' block
+	// 3: Add the migration routine near the bottom, as indicated by the
+	//    comment there.
+	// 4: Gate the migration routine using the bit.
+	// 5: Be sure to OR the bit at the end of the migration routine.
+
+	// note: maximum positive bit for pref storage is 0x40000000
+	const M_USERAGENT = 0x1;
+	const M_SHORTCUTS = 0x2;
+	const M_MENU_DEPTH_25 = 0x4;
+	const M_INTRO_COUNT = 0x8;
+	const M_JSON_CONTACTS_AND_MENU_DEPTH_16 = 0x10;
+	const M_HIDE_TAG = 0x20;
+	const M_FIX_JSON_CONTACTS = 0x40;
+	const M_REFRESH_AVATARS = 0x80;
+	const M_INIT_AND_MERGE_BUTTONS = 0x100;
+	const M_V3_11 = 0x200;
+	const M_V3_15 = 0x400; // 0x400:1024 0x7FF:2047
+	const M_V3_16 = 0x800;
+	const M_V3_17 = 0x1000;
+	const M_V3_22 = 0x2000;
+	const M_V3_27 = 0x4000;
+	const M_V3_27A = 0x8000;
+	const M_V3_27B = 0x10000;
+	const M_V3_41  = 0x20000;
+	const M_V3_41B = 0x40000;
+	const M_V3_51  = 0x80000;
+	const M_V3_51B = 0x100000;
+	const M_V3_63  = 0x200000;
+	const M_V3_77  = 0x400000;
+	const M_V3_772 = 0x800000;
+	const M_V3_778 = 0x1000000;
+	const M_V3_87  = 0x2000000; 
+	
+	if (StumbleGlobals.new_install || new_profile)
+	{
+		StumbleGlobals.ds.setValue("$migration_state", M_USERAGENT | M_SHORTCUTS | 
+					M_MENU_DEPTH_25 | M_INTRO_COUNT | 
+					M_JSON_CONTACTS_AND_MENU_DEPTH_16 | M_HIDE_TAG |
+					M_FIX_JSON_CONTACTS | M_REFRESH_AVATARS | 
+					M_INIT_AND_MERGE_BUTTONS | M_V3_11 | M_V3_15 | M_V3_16 |
+					M_V3_17 | M_V3_22 | M_V3_27 | M_V3_27A | M_V3_27B |
+					M_V3_41 | M_V3_41B | M_V3_51 | M_V3_51B | M_V3_63 | M_V3_77 |
+					M_V3_772 | M_V3_778 | M_V3_87 );
+		StumbleGlobals.ds.flushPrefs();
+		return;
+	}
+
+	var migration_bitfield = StumbleGlobals.ds.getValue("$migration_state");
+	
+	try {  // migration can be tricky, so we do a try
+
+	
+	if (! (migration_bitfield & M_USERAGENT))
+	{
+		// Note:  We used to have code (before 2/14) that would remove even older code
+		//        from 2002 that would actually remove our useragent that we used to set.
+		//        But AMO got confused and they thought we were setting the useragent, so that
+		//        code has been removed to stop scaring them.
+		migration_bitfield |= M_USERAGENT;
+	}
+	
+	if (! (migration_bitfield & M_SHORTCUTS))
+	{
+		// version <=2.7
+		if (StumbleGlobals.host.win)
+			StumbleGlobals.migrate_shortcuts();
+		migration_bitfield |= M_SHORTCUTS;
+	}
+
+	if (! (migration_bitfield & M_MENU_DEPTH_25))
+	{
+		// version 2.84
+		StumbleGlobals.ds.setValue("$sendtos_menu_depth", 25);
+		migration_bitfield |= M_MENU_DEPTH_25;
+	}
+
+	if (! (migration_bitfield & M_INTRO_COUNT))
+	{
+		// version 2.87
+		StumbleGlobals.ds.setValue("$intro_count", 15);
+		migration_bitfield |= M_INTRO_COUNT;
+	}
+	
+	if (! (migration_bitfield & M_JSON_CONTACTS_AND_MENU_DEPTH_16))
+	{
+		// version 2.90
+		StumbleGlobals.ds.migrateToContacts();
+		StumbleGlobals.ds.setValue("$sendtos_menu_depth", 16);
+		StumbleGlobals.ds.flushPrefs();
+		migration_bitfield |= M_JSON_CONTACTS_AND_MENU_DEPTH_16;
+	}
+
+	if (! (migration_bitfield & M_HIDE_TAG))
+	{
+		StumbleGlobals.ds.setValue("$show_tag", false);
+		migration_bitfield |= M_HIDE_TAG;
+	}
+	
+	if (! (migration_bitfield & M_FIX_JSON_CONTACTS))
+	{
+//		StumbleGlobals.ds.fixJSONContacts(false);
+		migration_bitfield |= M_FIX_JSON_CONTACTS;
+	}
+
+	if (! (migration_bitfield & M_REFRESH_AVATARS))
+	{
+		StumbleGlobals.ds.setValue("$has_avatars", false);
+		migration_bitfield |= M_REFRESH_AVATARS;
+	}
+	
+	if (! (migration_bitfield & M_INIT_AND_MERGE_BUTTONS))
+	{
+		// version 3.07 / 3.08
+		StumbleGlobals.ds.setValue("$show_groups", StumbleGlobals.ds.getValue("$show_groups") || 
+					StumbleGlobals.ds.getValue("$show_forums"));
+		StumbleGlobals.ds.setValue("$show_aboutme", StumbleGlobals.ds.getValue("$show_aboutme") ||
+					StumbleGlobals.ds.getValue("$show_mystumblers"));
+
+		StumbleGlobals.ds.setValue("$shown_find_friends", true);
+		
+		migration_bitfield |= M_INIT_AND_MERGE_BUTTONS;
+	}
+	
+	if (! (migration_bitfield & M_V3_11))
+	{
+		// version 3.11
+		if (StumbleGlobals.host.dist)
+			StumbleGlobals.ds.setValue("$show_mode_wiki", true);
+		
+		var show_searchlinks = StumbleGlobals.ds.getValue("$show_searchlinks"); 
+		StumbleGlobals.ds.setValue("$show_searchlinks_score", show_searchlinks);
+		StumbleGlobals.ds.setValue("$show_searchlinks_friends", show_searchlinks);
+		StumbleGlobals.ds.setValue("$show_searchlinks_topic", show_searchlinks);
+		StumbleGlobals.ds.setValue("$shown_searchlinks", show_searchlinks);
+		StumbleGlobals.ds.setValue("$show_searchlinks_logo", StumbleGlobals.ds.getValue("$searchlink_logos"));
+		// pitch social searchlinks to people who have searchlinks disabled
+		
+		StumbleGlobals.ds.setValue("$autocomplete_type", "tag,query");
+		
+		StumbleGlobals.ds.setValue("$show_flag", StumbleGlobals.ds.getValue("$show_tag"));
+		
+		StumbleGlobals.get_state(true);
+		
+		if (StumbleGlobals.ds.isPrefDefined("$stumblestats") &&
+					(StumbleGlobals.ds.getValue("$stumblestats") != ""))
+		{
+			var stumblestats = StumbleGlobals.ds.getValue("$stumblestats");
+	
+			var stumbletypes = "";
+			var stumblereferrals = "";
+			var first = 0;
+			var splitseen = stumblestats.split(".");
+			var i;
+			for (i = 0; i < splitseen.length; i++)
+			{
+				if (first == 0)
+				{
+					first = 1;
+				}
+				else
+				{
+					stumbletypes += ".";
+					stumblereferrals += ".";
+				}
+				stumbletypes += "0";
+			}
+			
+			// most profiles were migrated when this was in load_data1()
+			if (! StumbleGlobals.ds.isPrefDefined("$stumbletypes"))
+				StumbleGlobals.ds.setValue("$stumbletypes", stumbletypes);
+			
+			StumbleGlobals.ds.setValue("$stumblereferrals", stumblereferrals);
+		}
+		
+		StumbleGlobals.check_dyn_channels();
+		
+		migration_bitfield |= M_V3_11;
+	}
+
+	if (! (migration_bitfield & M_V3_15))
+	{
+		// version 3.15
+		
+		StumbleGlobals.ds.enableFeature("$sociallinks");
+		
+		// remove ancient legacy contacts
+		var contacts = StumbleGlobals.ds.getValue("$contacts");
+		var i;
+		for (i = 0; i < contacts.length; i++)
+		{
+			var contact = contacts[i];
+			if (contact.nickname && (! contact.contactid) &&
+						(typeof(contact.fbid) == "undefined"))
+				StumbleGlobals.ds.deleteRow(contact);
+		}
+		
+		migration_bitfield |= M_V3_15;
+	}
+		
+	if (! (migration_bitfield & M_V3_16))
+	{
+		var tmpstr = StumbleGlobals.ds.getValue("$process_rarely_timestamp");
+		if (tmpstr == "")
+			StumbleGlobals.ds.setValue("$process_rarely_timestamp", "0");
+		
+		StumbleGlobals.check_dyn_channels();
+		
+		migration_bitfield |= M_V3_16;
+	}
+
+	if (! (migration_bitfield & M_V3_17))
+	{
+//		if (StumbleGlobals.ds.getValue("$shown_find_friends_time_s") == 0)
+//			StumbleGlobals.ds.setValue("$shown_find_friends_time_s", 2);
+		StumbleGlobals.ds.setValue("$show_tag", false);
+		StumbleGlobals.ds.setValue("$show_flag", false);
+		StumbleGlobals.get_state(true);
+		StumbleGlobals.clear_stumbles();
+		migration_bitfield |= M_V3_17;
+	}
+
+	if (! (migration_bitfield & M_V3_22))
+	{
+		StumbleGlobals.migrate_check_shared();
+		if (StumbleGlobals.ds.isPrefDefined("$referral_count"))
+		{
+			StumbleGlobals.ds.setValue("$undelivered_count", parseInt(StumbleGlobals.ds.getValue("$referral_count")));
+			StumbleGlobals.ds.clearPref("$referral_count");
+		}
+		
+		StumbleGlobals.get_state(true);
+
+		migration_bitfield |= M_V3_22;
+	}
+	
+	if ((! (migration_bitfield & M_V3_27A))
+			|| (! (migration_bitfield & M_V3_27B)))
+	{
+		StumbleGlobals.ds.setValue("$show_legacy_network", false);	
+		
+		StumbleGlobals.ds.setValue("$migrate_places_state", "a");
+		
+		migration_bitfield |= M_V3_27A;
+		migration_bitfield |= M_V3_27B;
+	}
+	
+	if (! (migration_bitfield & M_V3_41))
+	{
+		// Turn the comment icon off by default.
+		StumbleGlobals.ds.setValue("$show_searchlinks_comment_icon", false);
+		migration_bitfield |= M_V3_41;
+	}
+	
+	if (! (migration_bitfield & M_V3_41B))
+	{
+		// No longer add ourselves to the noscript whitelist and XSS 
+		// exception list by default.
+		StumbleGlobals.ds.setValue("@whitelist_upon_load", false);
+		migration_bitfield |= M_V3_41B;
+		
+		// For existing users we treat the "user_changed" values as true
+		// so we don't change preferences that they may have set explicitly.
+		StumbleGlobals.ds.setValue("$show_info_user_changed", true);
+		StumbleGlobals.ds.setValue("$show_referral_user_changed", true);
+		StumbleGlobals.ds.setValue("$show_home_user_changed", true);
+		StumbleGlobals.ds.setValue("$show_friends_user_changed", true);
+	}
+
+	if (! (migration_bitfield & M_V3_51))
+	{
+		// Turn the search links topic off by default, even for existing users.
+		StumbleGlobals.ds.setValue("$show_searchlinks_topic", false);
+		migration_bitfield |= M_V3_51;
+	}
+	
+	if (! (migration_bitfield & M_V3_51B))
+	{
+		// If they haven't changed the old default channel button configuration
+		// then remove the channel buttons
+		var modesChanged = false;
+
+		var oldDefaultModes = [ 
+			[ "$show_mode_friends", true ],
+			[ "$show_mode_more", true ],
+			[ "$show_mode_news", true ],
+			[ "$show_mode_photo", true ],
+			[ "$show_mode_search", false ],
+			[ "$show_mode_stumblers", false ],
+			[ "$show_mode_video", true ],
+			[ "$show_mode_wiki", false ]
+		];
+		
+		for(var i=0; i<oldDefaultModes.length; i++)
+		{
+			var entry = oldDefaultModes[i]
+			if(StumbleGlobals.ds.getValue(entry[0]) != entry[1])
+			{
+				modesChanged = true;
+				break;
+			}
+		}
+
+		if(!modesChanged)
+		{
+			// Check whether they have added any "thru" domain buttons
+			var thruChannels = StumbleGlobals.ds.getThruDomainChannels();
+			if(thruChannels)
+			{
+				for(var i=0; i<thruChannels.length; i++)
+				{
+					if(thruChannels[i].show)
+					{
+						modesChanged = true;
+						break;
+					}
+				}
+			}
+		}
+		
+		// If they haven't changed the old default settings, then remove the
+		// channels button section
+		if(!modesChanged)
+		{
+			StumbleGlobals.ds.setValue("$show_mode", false);
+			// But make sure the channels selector menu is visible
+			StumbleGlobals.ds.setValue("$show_topics", true);
+			
+		}
+		migration_bitfield |= M_V3_51B;
+	}
+	
+	if (! (migration_bitfield & M_V3_63))
+	{
+		
+		if (StumbleGlobals.ds.getValue("$show_legacy_forums")
+				&& (! StumbleGlobals.ds.getValue("$show_groups")))
+		{
+			StumbleGlobals.ds.setValue("$show_groups", true);
+		}
+		
+		migration_bitfield |= M_V3_63;
+	}
+	
+	if (! (migration_bitfield & M_V3_772))
+	{
+		// We were dropping the share list to 12 entries, but we got too many complaints, so
+		// that change has been reverted.
+
+		// Yet another update to sendtos_max
+		// StumbleGlobals.ds.setValue("$sendtos_menu_depth", 12);
+		migration_bitfield |= M_V3_772;
+	}
+
+	if (! (migration_bitfield & M_V3_778))
+	{
+		if(StumbleGlobals.ds.isPrefDefined("@ab_bits"))
+		{
+			// Normalize this to just have the single bit that was
+			// used previously.
+			var old_value = StumbleGlobals.ds.getValue("@ab_bits");
+			old_value &= 1;
+			StumbleGlobals.ds.setValue("@ab_bits");
+			StumbleGlobals.ds.setValue("@ab_bits", old_value);
+			migration_bitfield |= M_V3_778;
+		}
+	}
+	
+	if (! (migration_bitfield & M_V3_87))
+	{
+		// Turn on phishing reporting by default
+		StumbleGlobals.ds.setValue("@report_phishing", true);
+		migration_bitfield |= M_V3_87;
+	}
+
+	// Add each new profile migration routine immediately above.
+
+	} catch (e) { try { StumbleGlobals.log_error("MIGRATE PROFILE", e); } catch (ee) {}}
+	
+	StumbleGlobals.ds.setValue("$migration_state", migration_bitfield)
+	StumbleGlobals.ds.flushPrefs();
+}
+
+StumbleGlobals.migrate_places = function()
+{
+	if (! StumbleGlobals.host.places)
+		return;
+	
+	var state = StumbleGlobals.ds.getValue("$migrate_places_state");
+	
+	if (state == "d")
+		return;
+	
+	if (StumbleGlobals.ds.getValue("#migrating_places"))
+		return;
+	
+	StumbleGlobals.ds.setValue("#migrating_places", true);
+	
+	var context = new Object();
+	context.ratings_str = null;
+	context.processed_key = null;
+	context.processed_idx = null;
+	context.state = state;
+	context.unrated_rows = null;
+	setTimeout(function (win, context) { win.StumbleGlobals.migrate_places2(context) }, 0, window, context);
+}
+
+StumbleGlobals.migrate_places2 = function(context)
+{
+	var new_state = context.state;
+	var migrate_file;
+	var db;
+	var result;	
+	var row;
+	var url;
+	var urlid;
+	var rating;
+	var legacy_rating;
+	var has_bookmark;
+	var has_thumbup_tag;
+	var bookmarked;
+	var sql;
+	var ts;
+	var parts;
+	var lines;
+	var urls;
+	var i;
+	var j;
+	switch (context.state)
+	{
+		case "a":
+			// 1. load ratings and backup places
+			context.ratings_str = StumbleGlobals.read_file_user("stumblerating");
+			StumbleGlobals.backup_places("MIGRATEPLACES BACKUP");
+			new_state = "b";
+			break;
+		case "b":
+			// 2. backup ratings
+			if (! context.ratings_str)
+				context.ratings_str = StumbleGlobals.read_file_user("stumblerating");
+			migrate_file = StumbleGlobals.ds.getResourceNSIFile("temp", "migraterating" + StumbleGlobals.ds.userid);
+			StumbleGlobals.ds.writeFile(migrate_file, context.ratings_str);
+			StumbleGlobals.ratings = null;
+			new_state = "c";
+			break;
+		case "c":
+			// 3. initialize ratings and processed_idx if necessary
+			if (! StumbleGlobals.ratings)
+				StumbleGlobals.load_ratings();
+			
+			db = StumbleGlobals.ds.getDatabase();
+			if (! context.processed_key)
+				context.processed_key = StumbleGlobals.ds.getValue("$migrate_places_key");
+			
+			if (! context.url_rows)
+			{
+				sql = "SELECT urlid,rating FROM url WHERE urlid>" + db.q(context.processed_key) + " ORDER BY urlid LIMIT 1000";
+				context.url_rows = db.query(sql);
+				context.processed_idx = 0;
+			}
+			
+			// 4. check whether we're done
+			if (context.url_rows.length == 0)
+			{
+				context.processed_key = "";
+				context.processed_idx = 0;
+				StumbleGlobals.ds.setValue("$migrate_places_key", "");				
+				StumbleGlobals.ds.setValue("$migrate_places_idx", 0);
+				StumbleGlobals.ds.setValue("#migrating_places", false)
+				new_state = "d";
+				setTimeout(function() {
+					StumbleGlobals.download_favs(false);
+				}, 0);
+				setTimeout(function() {
+					StumbleGlobals.process_command_queue();
+				}, 0);
+				break;
+			}
+			
+			rating = context.url_rows[context.processed_idx].rating;
+			urlid = context.url_rows[context.processed_idx].urlid;
+			
+			context.processed_key = urlid;
+			
+			// 5. save progress periodically
+			if ((context.processed_idx % 100) == 0)
+			{
+				StumbleGlobals.ds.setValue("$migrate_places_key", urlid);
+				StumbleGlobals.ds.flushPrefs();
+			}
+			
+			context.processed_idx++;
+
+			if (context.url_rows.length == context.processed_idx)
+			{
+				context.url_rows = null;
+				context.processed_idx = 0;
+			}
+			
+			// 6. get urls and legacy rating for this urlid
+			sql = "SELECT url FROM url_map WHERE urlid=" + db.q(urlid);
+			rows = db.query(sql);
+			if (rows.length == 0)
+				break; // shouldn't happen
+			
+			legacy_rating = null;
+			urls = new Array();
+			while (row = rows.shift())
+			{
+				urls.push(row.url);
+				if (((typeof StumbleGlobals.ratings[row.url]) != "undefined")
+						&& (legacy_rating != 1)) // prefer thumbup over thumbdown
+					legacy_rating = StumbleGlobals.ratings[row.url];
+			}
+			
+			ts = StumbleGlobals.ds.getTaggingService();
+			
+			// 7. check existing bookmarks and tags
+			has_bookmark = false; 
+			has_thumbup_tag = false;
+			for (i = 0; i < urls.length; i++)
+			{
+				url = urls[i];
+				nsiuri = StumbleGlobals.get_nsiuri(url);
+				tags = ts.getTagsForURI(nsiuri, []);
+				bookmarked = StumbleGlobals.is_bookmarked(nsiuri);
+				
+				has_bookmark = has_bookmark || bookmarked;
+				for (j = 0; j < tags.length; j++)
+				{
+					if (tags[j] == "SU")
+					{
+						has_thumbup_tag = true;
+						break;
+					}
+				}
+				
+				// 7a. if the url isn't bookmarked, nuke spurious tags
+				if (tags.length && (! bookmarked))
+					ts.untagURI(nsiuri, tags);
+			}
+			
+			// 8. update ratings
+			if (has_bookmark && has_thumbup_tag && (rating != 1))
+			{
+				// bookmarked with SU tag gets thumbup
+				sql = "UPDATE url SET rating=1 WHERE urlid=" + db.q(urlid); 
+				db.query(sql);
+			}
+			else if ((legacy_rating != null) && (legacy_rating != rating))
+			{
+				// legacy rating overrides db rating
+				sql = "UPDATE url SET rating=" + db.v(legacy_rating) + " WHERE urlid=" + db.q(urlid);
+				db.query(sql);
+			}
+			else if ((legacy_rating == null) && (rating == 0))
+			{
+				// unrate thumbdowns that don't have a legacy_rating
+				sql = "UPDATE url SET rating=-1 WHERE urlid=" + db.q(urlid);
+				db.query(sql);
+			}
+			
+			break;
+	}
+	
+	if (context.state != new_state)
+	{
+		context.state = new_state;
+		StumbleGlobals.ds.setValue("$migrate_places_state", new_state);
+		StumbleGlobals.ds.flushPrefs();
+	}
+	
+	if (new_state != "d")
+		setTimeout(function (win, context) { win.StumbleGlobals.migrate_places2(context) }, 0, window, context);
+}
+
+StumbleGlobals.migrate_check_shared = function()
+{
+	var contacts = StumbleGlobals.ds.getValue("$contacts");
+	var share_count = 0;
+	var i;
+	for (i = 0; i < contacts.length; i++)
+	{
+		if (contacts[i].referral_count)
+			share_count += contacts[i].referral_count;
+		
+		if (share_count >= 2)
+			break;
+	}
+	
+	if (share_count >= 1)
+		StumbleGlobals.ds.setValue("$poll_state", "f");
+	
+	if (share_count >= 2)	
+		StumbleGlobals.ds.setValue("$shown_referral_info", true);
+}
+
+StumbleGlobals.migrate_contacts_to_prefs_delayed = function()
+{
+	try {
+		StumbleGlobals.migrate_contacts_to_prefs();
+	}
+	catch (e) {
+		StumbleGlobals.log_error("MIGRATE CONTACT_DELAYED", e);
+		return;
+	}
+	
+	if (StumbleGlobals.stumbleid == 0);
+		return;
+	
+	StumbleGlobals.invoke_global_event("refresh-referral-menu", null);
+}
+
+StumbleGlobals.migrate_contacts_to_prefs = function()
+{
+	var file = StumbleGlobals.ds.getResourceNSIFile(null, "json_db")
+	if (! file.exists())
+		return;
+	
+	var db = StumbleGlobals.ds.deserialize(StumbleGlobals.ds.readFile(file));
+	if (! db)
+		return;
+	
+	var ids = StumbleGlobals.ds.getValue("@id_list").split(":");
+	var i;
+	for (i = 0; i < ids.length; i++)
+	{
+		if (ids[i] == "")
+			continue;
+		
+		if (! db[ids[i]])
+			continue;
+		
+		if (! db[ids[i]]["contact"])
+			continue;
+
+
+		var names = StumbleGlobals.ds.getPrefNames("stumble." + ids[i] + ".c.");
+		if (! names)
+			return;
+		
+		var pref_contacts = new Array();
+		var k;
+		for (k = 0; k < names.length; k++)
+			pref_contacts.push(StumbleGlobals.ds.deserialize(StumbleGlobals.ds.getValue(names[k])));
+
+		
+		var contacts = db[ids[i]]["contact"];
+		if (! contacts.constructor != Array)
+		{
+			// convert to array
+			var a = new Array();
+			var p;
+			for (p in contacts)
+			{
+				if ((typeof (contacts[p])) == "function")
+					continue;
+				
+				if ((typeof (contacts[p])) == "undefined")				
+					continue;
+				
+				if (contacts[p].constructor == Object)
+					a.push(contacts[p]);
+			}
+			contacts = a;
+		}
+		
+		var j;
+		var contact;
+		for (j = 0; j < contacts.length; j++)
+		{
+			var pref_contact = null;
+			if (contacts[j].nickname)
+			{
+				pref_contact = StumbleGlobals.get_row(
+							pref_contacts,
+							"nickname",
+							contacts[j].nickname);
+			}
+			else if (contacts[j].email)
+			{
+				pref_contact = StumbleGlobals.get_row(
+							pref_contacts,
+							"email",
+							contacts[j].email);
+			}
+			else
+			{
+				continue;
+			}
+			
+			if (pref_contact)
+			{
+				contacts[j]._r = pref_contact._r;
+			}
+			else
+			{
+				var autoinc_name = "stumble." + ids[i] + ".c_ai";
+				contacts[j]._r = StumbleGlobals.ds.getPrefValue(autoinc_name, 0);
+				StumbleGlobals.ds.setValue(autoinc_name, (contacts[j]._r + 1));
+			}
+			contacts[j]._t = "c";
+			var name = "stumble." + ids[i] + ".c." + contacts[j]._r;
+			StumbleGlobals.ds.setValue(name, StumbleGlobals.ds.serialize(contacts[j]));
+		}
+	}
+}
+
+StumbleGlobals.get_row = function(rows, col_name, value)
+{
+	var i;
+	for (i = 0; i < rows.length; i++)
+	{
+		if (rows[i][col_name] && (rows[i][col_name] == value))
+			return rows[i];
+	}
+	return null;
+}
+
+StumbleGlobals.migrate_clear_old_passwords = function()
+{
+	var names = 	StumbleGlobals.ds.getPrefNames("stumble.");
+	var current_id_pref = "stumble." + 
+				StumbleGlobals.ds.getValue("@current_user") +
+				".password";
+	var i;
+	for (i = 0; i < names.length; i++)
+	{
+		if (names[i].indexOf("$password") == -1) continue;
+		if (names[i] == current_id_pref) continue;
+		StumbleGlobals.ds.clearPref(names[i]);
+	}
+}
+
+StumbleGlobals.migrate_shortcuts = function()
+{
+	// If we're on Windows, and if all of the key bindings match the 
+	// old defaults, change the bindings to the new defaults. -- JW
+	var details = new Array();
+	var obj = {};
+	
+	obj.oldpref = "$shortcut-stumble";
+	obj.newpref = "$shortcut_stumble";
+	obj.oldval = "Alt+VK_F1";
+	obj.newval = "Alt+VK_BACK_QUOTE";
+	details.push(obj);
+	
+	obj = {};
+	obj.oldpref = "$shortcut-thumbup";
+	obj.newpref = "$shortcut_thumbup";
+	obj.oldval = "Alt+VK_F2";
+	obj.newval = "Alt+VK_1";
+	details.push(obj);		
+	
+	obj = {};
+	obj.oldpref = "$shortcut-thumbdown";
+	obj.newpref = "$shortcut_thumbdown";
+	obj.oldval = "Alt+VK_F3";
+	obj.newval = "Alt+VK_2";
+	details.push(obj);		
+	
+	obj = {};
+	obj.oldpref = "$shortcut-reviews";
+	obj.newpref = "$shortcut_reviews";
+	obj.oldval = "Alt+VK_F5";
+	obj.newval = "Alt+VK_3";
+	details.push(obj);		
+	
+	obj = {};
+	obj.oldpref = "$shortcut-toolbar";
+	obj.newpref = "$shortcut_toolbar";
+	obj.oldval = "Alt+VK_11";
+	obj.newval = "Alt+VK_11";
+	details.push(obj);		
+	
+	var keybindings_edited = false;
+	var i;
+	for (i = 0; i < details.length; i++)
+	{
+		if (StumbleGlobals.ds.isPrefDefined(details[i].oldpref))
+		{
+			keybindings_edited = (StumbleGlobals.ds.getValue(details[i].oldpref) != details[i].oldval);
+			if (keybindings_edited)
+			{
+				break;
+			}
+		}
+	}
+	
+	if (keybindings_edited)
+	{
+		StumbleGlobals.init_key_const_dictionaries();
+
+		for (i = 0; i < details.length; i++)
+		{
+			// This tranlates keyids like " " and "A" to "VK_SPACE" and 
+			// "VK_A". -- JW
+			var keyspec = StumbleGlobals.ds.getValue(details[i].oldpref);
+			var parts = keyspec.split("+");
+			var old_keyid;
+			if (parts[parts.length - 1] == "")
+				old_keyid = "+";
+			else
+				old_keyid = parts[parts.length - 1];
+
+			if (old_keyid.length == 1)
+			{
+				var new_keyid = StumbleGlobals.keyids_by_char[old_keyid];
+				if (new_keyid)
+				{
+					var regexp = new RegExp(StumbleGlobals.escape_regexp_chars(old_keyid) + "$");
+					keyspec = keyspec.replace(regexp, new_keyid);
+				}
+			}
+			StumbleGlobals.ds.setValue(details[i].newpref, keyspec);
+		}
+	}
+}
+
diff --git a/chrome/stumbleupon.jar!/content/moreChannelsDialog.js b/content/moreChannelsDialog.js
similarity index 61%
rename from chrome/stumbleupon.jar!/content/moreChannelsDialog.js
rename to content/moreChannelsDialog.js
index 472d90b..5f6ff77 100644
--- a/chrome/stumbleupon.jar!/content/moreChannelsDialog.js
+++ b/content/moreChannelsDialog.js
@@ -1,79 +1,82 @@
-var su_ds;
-var channels;
-var channel_count;
-
-function su_get_element(id)
-{
-	return document.getElementById(id);
-}
-
-function init()
-{
-	su_ds = opener.su_ds;
-	var su_host = opener.parent_window.su_host;
-	channels = su_ds.getThruDomainChannels(true);
-	if (! channels)
-		channels = new Array();
-	
-	channel_count = channels.length;
-	var col_count = 1;
-	if (channel_count > 8)
-		col_count = 2;
-	else if (channel_count > 32)
-		col_count = 3;
-	
-	var row_count = Math.round(channel_count / col_count);
-	
-	var columns = su_get_element("columns");
-	var rows = su_get_element("rows");
-
-	var el;
-	
-	for (i = 0; i < col_count; i++)
-	{
-		el = document.createElement("column");
-		columns.appendChild(el);
-	}
-	
-	for (i = 0; i < row_count; i++)
-	{
-		el = document.createElement("row");
-		el.setAttribute("id", "row_" + i);
-		rows.appendChild(el);
-	}
-	
-	for (i = 0; i < channel_count; i++)
-	{
-		el = document.createElement("checkbox");
-		el.setAttribute("id", "item_" + i);
-		el.setAttribute("label", channels[i].name);
-		var filename = channels[i].domain.replace(/\./g, "_") + ".ico";
-		el.setAttribute("src", 
-					su_ds.getResourceURLFromName("favicons", filename));
-		if (su_host.mac || su_host.win)
-			el.setAttribute("class", "su-iconic-favicon");
-		else
-			el.setAttribute("class", "su-iconic-favicon-alt");
-		var row_el = su_get_element("row_" + (i % row_count));
-		row_el.appendChild(el);
-		el.checked = channels[i].show;
-	}
-}
-
-function handle_accept()
-{
-	var i;
-	var el;
-	for (i = 0; i < channel_count; i++)
-	{
-		el = su_get_element("item_" + i);
-		channels[i].show = el.checked;
-		su_ds.updateRow(channels[i]);
-	}
-}
-
-function handle_cancel()
-{
-	return true;
-}
-
+
+var channels;
+var channel_count;
+
+if(typeof(StumbleGlobals) == "undefined")
+	var StumbleGlobals = {};
+
+StumbleGlobals.get_element = function(id)
+{
+	return document.getElementById(id);
+}
+
+function init()
+{
+	StumbleGlobals.ds = opener.StumbleGlobals.ds;
+	StumbleGlobals.host = opener.parent_window.StumbleGlobals.host;
+	channels = StumbleGlobals.ds.getThruDomainChannels(true);
+	if (! channels)
+		channels = new Array();
+	
+	channel_count = channels.length;
+	var col_count = 1;
+	if (channel_count > 8)
+		col_count = 2;
+	else if (channel_count > 32)
+		col_count = 3;
+	
+	var row_count = Math.round(channel_count / col_count);
+	
+	var columns = StumbleGlobals.get_element("columns");
+	var rows = StumbleGlobals.get_element("rows");
+
+	var el;
+	
+	for (i = 0; i < col_count; i++)
+	{
+		el = document.createElement("column");
+		columns.appendChild(el);
+	}
+	
+	for (i = 0; i < row_count; i++)
+	{
+		el = document.createElement("row");
+		el.setAttribute("id", "row_" + i);
+		rows.appendChild(el);
+	}
+	
+	for (i = 0; i < channel_count; i++)
+	{
+		el = document.createElement("checkbox");
+		el.setAttribute("id", "item_" + i);
+		el.setAttribute("label", channels[i].name);
+		var filename = channels[i].domain.replace(/\./g, "_") + ".ico";
+		el.setAttribute("src", 
+					StumbleGlobals.ds.getResourceURLFromName("favicons", filename));
+		if (StumbleGlobals.host.mac || StumbleGlobals.host.win)
+			el.setAttribute("class", "su-iconic-favicon");
+		else
+			el.setAttribute("class", "su-iconic-favicon-alt");
+		var row_el = StumbleGlobals.get_element("row_" + (i % row_count));
+		row_el.appendChild(el);
+		el.checked = channels[i].show;
+	}
+}
+
+function handle_accept()
+{
+	var i;
+	var el;
+	for (i = 0; i < channel_count; i++)
+	{
+		el = StumbleGlobals.get_element("item_" + i);
+		channels[i].show = el.checked;
+		StumbleGlobals.ds.updateRow(channels[i]);
+	}
+}
+
+function handle_cancel()
+{
+	return true;
+}
+
diff --git a/chrome/stumbleupon.jar!/content/moreChannelsDialog.xul b/content/moreChannelsDialog.xul
similarity index 96%
rename from chrome/stumbleupon.jar!/content/moreChannelsDialog.xul
rename to content/moreChannelsDialog.xul
index d6f217a..ee52ce3 100644
--- a/chrome/stumbleupon.jar!/content/moreChannelsDialog.xul
+++ b/content/moreChannelsDialog.xul
@@ -1,30 +1,29 @@
-<?xml version="1.0"?>
-
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-<?xml-stylesheet href="chrome://stumbleupon/content/skin/stumbleuponOverlay.css" type="text/css"?>
-
-<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
-
-<dialog id="stumble_more_channels"
-	xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-	title="More Channels"
-	buttons="accept,cancel"
-	ondialogaccept="return handle_accept();"
-  ondialogcancel="return handle_cancel();"
-	onload="init()">
-
-<stringbundleset id="stringbundleset">
-	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
-</stringbundleset>
-
-<script type="application/x-javascript" src="moreChannelsDialog.js"/>
-
-<groupbox>
-	<caption label="Website Channels"/>
-	<grid>
-		<columns id="columns"/>
-		<rows id="rows"/>
-	</grid>
-</groupbox>
-
-</dialog>
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://stumbleupon/content/skin/stumbleuponOverlay.css" type="text/css"?>
+
+<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
+
+<dialog id="stumble_more_channels"
+	xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+	title="More Channels"
+	buttons="accept,cancel"
+	ondialogaccept="return handle_accept();"
+  ondialogcancel="return handle_cancel();"
+	onload="init()">
+
+<stringbundleset id="stringbundleset">
+	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
+</stringbundleset>
+
+<script type="application/x-javascript" src="moreChannelsDialog.js"/>
+
+<groupbox>
+	<caption label="Website Channels"/>
+	<grid>
+		<columns id="columns"/>
+		<rows id="rows"/>
+	</grid>
+</groupbox>
+</dialog>
diff --git a/content/namespace.js b/content/namespace.js
new file mode 100644
index 0000000..2e5e2b6
--- /dev/null
+++ b/content/namespace.js
@@ -0,0 +1,9 @@
+//
+// The namespace for globals
+//
+
+if(typeof(StumbleGlobals) == "undefined")
+{
+	var StumbleGlobals = {};
+}
+
diff --git a/chrome/stumbleupon.jar!/content/passwordDialog.xul b/content/passwordDialog.xul
similarity index 88%
rename from chrome/stumbleupon.jar!/content/passwordDialog.xul
rename to content/passwordDialog.xul
index 3b111b1..b9b92c7 100644
--- a/chrome/stumbleupon.jar!/content/passwordDialog.xul
+++ b/content/passwordDialog.xul
@@ -1,194 +1,194 @@
-<?xml version="1.0"?>
-
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-
-<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
-
-<dialog id="stumble_password_dialog" title="Change StumbleUpon Password"
-  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-  buttons="accept,cancel"
-  ondialogaccept="return handle_accept();"
-  onload="init()">
-
-<script type="application/x-javascript">
-<![CDATA[
-
-var detail;
-function init()
-{
-	detail = window.arguments[0];
-}
-
-function handle_accept()
-{
-	var password0 = document.getElementById("password0").value;
-	var password1 = document.getElementById("password1").value;
-	var password2 = document.getElementById("password2").value;
-	var password = password1;
-	if (password1 != password2)
-	{
-		alert("The passwords don't match");
-		return false;
-	}
-	
-	if (password.length == 0)
-	{
-		alert("You cannot have a blank password");
-		return false;
-	}
-	
-	var res = opener.su_post_url_server_secure(
-				"change_password.php",
-				"username=" + detail.id +
-				"&password=" + encodeURIComponent(password0) +
-				"&newpassword=" + encodeURIComponent(password));
-
-	if (res.status == 1)
-	{
-		alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to http://www.stumbleupon.com/feedback.php to report the problem\nError : " + res.error + "\nStatus : " + res.status);
-		return false;
-	}
-
-	if (res.status != 200)
-	{
-		alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to http://www.stumbleupon.com/feedback.php to report the problem\nError : " + res.error + "\nStatus : " + res.status);
-		return false;
-	}
-
-	var s = res.response;
-	
-	try {
-		if (opener.su_log_communication)
-			opener.su_log("response change_password.php", s);
-	} catch (e) {}
-
-	// Split the response it username and pass
-	var ss;
-	if (s)
-	{
-		ss = s.split("\n")[0].split(" ");
-	}
-	else if (s != "")
-	{
-		alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to http://www.stumbleupon.com/feedback.php to report the problem\nError : incomplete response");
-		return false;
-	}
-	else
-	{
-		ss = new Array();
-		ss[0] = "";
-	}
-
-	if (ss[0] == "ERROR")
-	{
-		var ps = window.opener.su_get_service(
-					"@mozilla.org/embedcomp/prompt-service;1",
-					"nsIPromptService");
-		var msg = "An unknown error occurred trying to change your password.\r\n\r\nPlease try a different password.";
-
-		if(ss[1])
-		{
-			if(ss[1] == "INCORRECT_PASSWORD")    
-		    {
-				var out = ps.confirmEx(
-							window,
-							"StumbleUpon Password Recovery",
-							"The password you supplied was incorrect.\r\n\r\nWould you like to recover your username/password?",
-							ps.STD_YES_NO_BUTTONS,
-							null,
-							null,
-							null,
-							null,
-							{});
-				if(out == 0)
-				{
-					var doc = opener.getBrowser().contentDocument;
-					close();
-					doc.location = opener.su_base_url + "recover_password.php";
-				}
-				// No additional messaging
-				msg = "";
-            }
-            else if(ss[1] == "PASSWORD_IS_NICKNAME")
-            {
-                msg = "You cannot use your nickname as your password.\r\n\r\nPlease try a different password.";
-            }
-            else if(ss[1] == "PASSWORD_TOO_WEAK")
-            {
-                msg = "That password is too weak.\r\n\r\nPlease try a different password.";
-            }
-            else
-            {
-                msg = "An unknown error occurred trying to change your password.\r\n\r\nPlease try a different password.";
-            }
-		}
-		if(msg != "")
-			ps.alert(window, "StumbleUpon", msg);
-		return false;
-	}
-		
-	detail.password = password;
-
-	opener.setTimeout(function (parent, detail) { parent.su_handle_password_dialog_accept(detail); }, 0, opener, detail);
-	
-	return true;
-}
-
-
- ]]>
-</script>
-<spacer height="10px"/>
-<hbox>
-	<spacer width="10px"/>
-	<image
-		width="32px"
-		height="32px"
-		src="chrome://stumbleupon/content/skin/ChangePassword.png"/>
-	<spacer width="5px"/>
-	<vbox>
-		<label value="Please enter a new password for your StumbleUpon"/>
-		<label value="account:"/>
-	</vbox>
-</hbox>
-
-<grid flex="1" style="margin:10px">
-  <columns>
-    <column flex="2"/>
-    <column flex="1"/>
-  </columns>
-
-  <rows>
-    <row>
-    <vbox align="right">
-    	<spacer flex="1"/>
-    	<label control="password0" value="Old Password:"/>
-    	<spacer flex="1"/>
-    </vbox>
-    <textbox id="password0"
-			type="password"
-			maxlength="16"/>
-    </row>
-    <row>
-    <vbox align="right">
-    	<spacer flex="1"/>
-    	<label control="password1" value="New Password:"/>
-    	<spacer flex="1"/>
-    </vbox>
-    <textbox id="password1"
-			type="password"
-			maxlength="16"/>
-    </row>
-    <row>
-    <vbox align="right">
-   		<spacer flex="1"/>
-	  	<label control="password2" value="Retype New Password:"/>
-	  	<spacer flex="1"/>
-	  </vbox>
-    <textbox id="password2"
-			type="password"
-			maxlength="16"/>
-    </row>
-  </rows>
-</grid>
-
-</dialog>
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
+
+<dialog id="stumble_password_dialog" title="Change StumbleUpon Password"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+  buttons="accept,cancel"
+  ondialogaccept="return handle_accept();"
+  onload="init()">
+
+<script type="application/x-javascript">
+<![CDATA[
+
+var detail;
+function init()
+{
+	detail = window.arguments[0];
+}
+
+function handle_accept()
+{
+	var password0 = document.getElementById("password0").value;
+	var password1 = document.getElementById("password1").value;
+	var password2 = document.getElementById("password2").value;
+	var password = password1;
+	if (password1 != password2)
+	{
+		alert("The passwords don't match");
+		return false;
+	}
+	
+	if (password.length == 0)
+	{
+		alert("You cannot have a blank password");
+		return false;
+	}
+	
+	var res = opener.StumbleGlobals.post_url_server_secure(
+				"change_password.php",
+				"username=" + detail.id +
+				"&password=" + encodeURIComponent(password0) +
+				"&newpassword=" + encodeURIComponent(password));
+
+	if (res.status == 1)
+	{
+		alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to http://www.stumbleupon.com/feedback.php to report the problem\nError : " + res.error + "\nStatus : " + res.status);
+		return false;
+	}
+
+	if (res.status != 200)
+	{
+		alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to http://www.stumbleupon.com/feedback.php to report the problem\nError : " + res.error + "\nStatus : " + res.status);
+		return false;
+	}
+
+	var s = res.response;
+	
+	try {
+		if (opener.StumbleGlobals.log_communication)
+			opener.StumbleGlobals.log("response change_password.php", s);
+	} catch (e) {}
+
+	// Split the response it username and pass
+	var ss;
+	if (s)
+	{
+		ss = s.split("\n")[0].split(" ");
+	}
+	else if (s != "")
+	{
+		alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to http://www.stumbleupon.com/feedback.php to report the problem\nError : incomplete response");
+		return false;
+	}
+	else
+	{
+		ss = new Array();
+		ss[0] = "";
+	}
+
+	if (ss[0] == "ERROR")
+	{
+		var ps = window.opener.StumbleGlobals.get_service(
+					"@mozilla.org/embedcomp/prompt-service;1",
+					"nsIPromptService");
+		var msg = "An unknown error occurred trying to change your password.\r\n\r\nPlease try a different password.";
+
+		if(ss[1])
+		{
+			if(ss[1] == "INCORRECT_PASSWORD")    
+		    {
+				var out = ps.confirmEx(
+							window,
+							"StumbleUpon Password Recovery",
+							"The password you supplied was incorrect.\r\n\r\nWould you like to recover your username/password?",
+							ps.STD_YES_NO_BUTTONS,
+							null,
+							null,
+							null,
+							null,
+							{});
+				if(out == 0)
+				{
+					var doc = opener.getBrowser().contentDocument;
+					close();
+					doc.location = opener.StumbleGlobals.base_url + "recover_password.php";
+				}
+				// No additional messaging
+				msg = "";
+            }
+            else if(ss[1] == "PASSWORD_IS_NICKNAME")
+            {
+                msg = "You cannot use your nickname as your password.\r\n\r\nPlease try a different password.";
+            }
+            else if(ss[1] == "PASSWORD_TOO_WEAK")
+            {
+                msg = "That password is too weak.\r\n\r\nPlease try a different password.";
+            }
+            else
+            {
+                msg = "An unknown error occurred trying to change your password.\r\n\r\nPlease try a different password.";
+            }
+		}
+		if(msg != "")
+			ps.alert(window, "StumbleUpon", msg);
+		return false;
+	}
+		
+	detail.password = password;
+
+	opener.setTimeout(function (parent, detail) { parent.StumbleGlobals.handle_password_dialog_accept(detail); }, 0, opener, detail);
+	
+	return true;
+}
+
+
+ ]]>
+</script>
+<spacer height="10px"/>
+<hbox>
+	<spacer width="10px"/>
+	<image
+		width="32px"
+		height="32px"
+		src="chrome://stumbleupon/content/skin/ChangePassword.png"/>
+	<spacer width="5px"/>
+	<vbox>
+		<label value="Please enter a new password for your StumbleUpon"/>
+		<label value="account:"/>
+	</vbox>
+</hbox>
+
+<grid flex="1" style="margin:10px">
+  <columns>
+    <column flex="2"/>
+    <column flex="1"/>
+  </columns>
+
+  <rows>
+    <row>
+    <vbox align="right">
+    	<spacer flex="1"/>
+    	<label control="password0" value="Old Password:"/>
+    	<spacer flex="1"/>
+    </vbox>
+    <textbox id="password0"
+			type="password"
+			maxlength="16"/>
+    </row>
+    <row>
+    <vbox align="right">
+    	<spacer flex="1"/>
+    	<label control="password1" value="New Password:"/>
+    	<spacer flex="1"/>
+    </vbox>
+    <textbox id="password1"
+			type="password"
+			maxlength="16"/>
+    </row>
+    <row>
+    <vbox align="right">
+   		<spacer flex="1"/>
+	  	<label control="password2" value="Retype New Password:"/>
+	  	<spacer flex="1"/>
+	  </vbox>
+    <textbox id="password2"
+			type="password"
+			maxlength="16"/>
+    </row>
+  </rows>
+</grid>
+
+</dialog>
diff --git a/chrome/stumbleupon.jar!/content/positionDialog.xul b/content/positionDialog.xul
similarity index 87%
rename from chrome/stumbleupon.jar!/content/positionDialog.xul
rename to content/positionDialog.xul
index 877ace3..7a245aa 100644
--- a/chrome/stumbleupon.jar!/content/positionDialog.xul
+++ b/content/positionDialog.xul
@@ -35,7 +35,7 @@ function handle_button_click(value)
 
 function handle_window_unload()
 {
-	opener.setTimeout(function (parent, detail) { parent.su_handle_position_dialog_close(detail); }, 0, opener, detail);
+	opener.setTimeout(function (parent, detail) { parent.StumbleGlobals.handle_position_dialog_close(detail); }, 0, opener, detail);
 }
 
 ]]>
diff --git a/content/preferenceDialog.js b/content/preferenceDialog.js
new file mode 100644
index 0000000..8b3cc15
--- /dev/null
+++ b/content/preferenceDialog.js
@@ -0,0 +1,1390 @@
+
+if(typeof(StumbleGlobals) == "undefined")
+	var StumbleGlobals = {};
+
+StumbleGlobals.include = function(uri)
+{
+	try {
+		StumbleGlobals.get_service(
+					"@mozilla.org/moz/jssubscript-loader;1",
+					"mozIJSSubScriptLoader")
+					.loadSubScript(uri);
+	}
+	catch (e) {
+		if ((uri != "chrome://stumbleupon/content/extra.js") || 
+					StumbleGlobals.test_extra_init)
+			StumbleGlobals.log_error("INCLUDE", e, uri);
+	}
+}
+
+StumbleGlobals.create_instance = function(nsclass, nsinterface)
+{
+	try {
+		return Components.classes[nsclass]
+					.createInstance(Components.interfaces[nsinterface]);
+	} catch (e) {
+		return null;
+	}
+}
+
+StumbleGlobals.get_service = function(nsclass, nsinterface)
+{
+	try {
+		return Components.classes[nsclass]
+					.getService(Components.interfaces[nsinterface]);
+	} catch (e) {
+		return null;
+	}
+}
+
+StumbleGlobals.get_element = function(id)
+{
+	return document.getElementById(id);
+}
+
+StumbleGlobals.service;
+try {
+	StumbleGlobals.service = Components.classes["@stumbleupon.com/stumbleupon-service;1"].getService().wrappedJSObject;
+}
+catch (e) {
+	// seamonkey kludge
+	StumbleGlobals.include("chrome://stumbleupon/content/stumbleuponService.js");
+	StumbleGlobals.service = new StumbleGlobals.Service();
+}
+
+StumbleGlobals.ds = StumbleGlobals.service.getDatastore();
+var icons_only;
+var bad_stumble;
+var great_stumble;
+var parent_window = null;
+var search_plugin;
+//var autocomplete_source;
+var keyspec;
+var shortcut_item;
+var recent_keypress_modifiers;
+var preferred_position_group;
+var preferred_show_firstrater_label_always;
+var stumbleupon_toolbar_menuitem = null;
+var download_favs_context = null;
+var bookmarks_backup_dir = null;
+var TOGGLE_TOOLBAR_LISTITEM_INDEX = 4;
+var enable_ids = [
+			"shortcut_stumble",
+			"shortcut_referrals",
+			"shortcut_thumbup",
+			"shortcut_thumbdown",
+			"shortcut_tag",
+			"shortcut_reviews"];
+//			"shortcut_details"
+var mode_ids = [
+//			"show_mode_all",
+			"show_mode_friends",
+			"show_mode_news",
+			"show_mode_photo",
+			"show_mode_search",
+			"show_mode_stumblers",
+			"show_mode_video",
+			"show_mode_wiki",
+			"show_mode_more"];
+	
+//
+// setUserChangedValue
+//
+// We want to track whether the user changes certain values.  This function
+// takes care of this by adding a new boolean key when the value is changed by
+// the user.
+//
+function setUserChangedValue(key, newValue)
+{
+	var oldValue = StumbleGlobals.ds.getValue(key);
+	if(oldValue != newValue)
+	{
+		StumbleGlobals.ds.setValue(key + "_user_changed", true);
+		StumbleGlobals.ds.setValue(key, newValue);
+	}
+}
+
+function doOK()
+{
+	//!!! Update all open windows for this application. -- JW
+
+	// now save new prefs...
+
+	if (is_parent_window_destroyed())
+	{
+		StumbleGlobals.get_element("stumble_pref_dialog").cancelDialog();
+		return true;
+	}
+	
+	StumbleGlobals.ds.setValue("$show_mode", StumbleGlobals.get_element("show_mode").checked);
+	for (i = 0; i < mode_ids.length; i++)
+	{
+		StumbleGlobals.ds.setValue("$" + mode_ids[i], StumbleGlobals.get_element(mode_ids[i]).checked);
+	}
+	
+	StumbleGlobals.ds.setValue("$show_field", StumbleGlobals.get_element("show_field").checked);
+
+	// see if they have changed...
+	var thebutton = StumbleGlobals.get_element("bad-stumble");
+	bad_stumble = thebutton.checked;
+	StumbleGlobals.ds.setValue("$bad_stumble", bad_stumble);
+
+	thebutton = StumbleGlobals.get_element("great-stumble");
+	great_stumble = thebutton.checked;
+	StumbleGlobals.ds.setValue("$great_stumble", great_stumble);
+
+	StumbleGlobals.ds.setValue("$prefetch", StumbleGlobals.get_element("prefetch").checked);
+
+//	StumbleGlobals.ds.setValue("$comment_firstrating", StumbleGlobals.get_element("comment_firstrating").checked);
+
+	StumbleGlobals.ds.setValue("$review_new_window", StumbleGlobals.get_element("review_new_window").checked);
+	StumbleGlobals.ds.setValue("$rate_new_window", StumbleGlobals.get_element("rate_new_window").checked);
+//	StumbleGlobals.ds.setValue("$search_new_window", StumbleGlobals.get_element("search_new_window").checked);
+
+	var new_show_topics = StumbleGlobals.get_element("show_topics").checked;
+	StumbleGlobals.ds.setValue("$show_topics", new_show_topics);
+
+    var new_stumble_topics = StumbleGlobals.get_element("stumble_topics").checked;
+	StumbleGlobals.ds.setValue("$stumble_topics", new_stumble_topics);
+
+	var new_show_topics_style = StumbleGlobals.get_element("stumble_topics2_style_menu").selectedItem;
+	if (new_show_topics_style)
+		StumbleGlobals.ds.setValue("$stumble_topics_style", new_show_topics_style.value);
+	else
+		StumbleGlobals.ds.setValue("$stumble_topics_style", 0);
+
+	var new_show_info = StumbleGlobals.get_element("show_info").checked;
+	setUserChangedValue("$show_info", new_show_info);
+	
+	var new_show_tag = StumbleGlobals.get_element("show_tag").checked;
+	StumbleGlobals.ds.setValue("$show_tag", new_show_tag);
+	if (new_show_tag)
+		StumbleGlobals.ds.setValue("$shown_tag", true);
+
+//	var new_show_flag = StumbleGlobals.get_element("show_flag").checked;
+//	StumbleGlobals.ds.setValue("$show_flag", new_show_flag);
+
+//	var new_show_search = StumbleGlobals.get_element("show_search").checked;
+//	StumbleGlobals.ds.setValue("$show_search", new_show_search);
+
+//	StumbleGlobals.ds.setValue("$show_legacy_network",  
+//				StumbleGlobals.get_element("show_legacy_network").checked);
+
+	var new_show_home = StumbleGlobals.get_element("show_home").checked;
+	setUserChangedValue("$show_home", new_show_home);
+
+//	var new_show_editinfo = StumbleGlobals.get_element("show_editinfo").checked;
+//	StumbleGlobals.ds.setValue("$show_editinfo", new_show_editinfo);
+
+//	StumbleGlobals.ds.setValue("$show_legacy_forums", 
+//				StumbleGlobals.get_element("show_legacy_forums").checked);
+
+	var new_show_friends = StumbleGlobals.get_element("show_friends").checked;
+	setUserChangedValue("$show_friends", new_show_friends);
+
+	var new_sync_bm_meta = StumbleGlobals.get_element("sync_bm_meta").checked;
+	StumbleGlobals.ds.setValue("$sync_bm_meta", new_sync_bm_meta);
+
+	var new_sync_bm_adult = ! StumbleGlobals.get_element("sync_bm_exclude_adult").checked;
+	StumbleGlobals.ds.setValue("$sync_bm_adult", new_sync_bm_adult);
+
+	var new_show_matches = StumbleGlobals.get_element("show_matches").checked;
+	StumbleGlobals.ds.setValue("$show_matches", new_show_matches);
+
+	var new_show_aboutme = StumbleGlobals.get_element("show_aboutme").checked;
+	StumbleGlobals.ds.setValue("$show_aboutme", new_show_aboutme);
+
+	var new_show_groups = StumbleGlobals.get_element("show_groups").checked;
+	StumbleGlobals.ds.setValue("$show_groups", new_show_groups);
+
+	var new_show_messages = StumbleGlobals.get_element("show_messages").checked;
+	StumbleGlobals.ds.setValue("$show_messages", new_show_messages);
+
+	var new_show_fbshare = StumbleGlobals.get_element("show_fbshare").checked;
+	setUserChangedValue("$show_fbshare", new_show_fbshare);
+
+	var new_show_referral = StumbleGlobals.get_element("show_referral").checked;
+	setUserChangedValue("$show_referral", new_show_referral);
+
+	var new_search_clear_queries = StumbleGlobals.get_element("search_clear_queries").checked;
+	StumbleGlobals.ds.setValue("$search_clear_queries", new_search_clear_queries);
+
+	var new_show_searchlinks_score = StumbleGlobals.get_element("show_searchlinks_score").checked;
+	StumbleGlobals.ds.setValue("$show_searchlinks_score", new_show_searchlinks_score);
+
+	var new_show_searchlinks_friends = StumbleGlobals.get_element("show_searchlinks_friends").checked;
+	StumbleGlobals.ds.setValue("$show_searchlinks_friends", new_show_searchlinks_friends);
+
+	var new_show_searchlinks_topic = StumbleGlobals.get_element("show_searchlinks_topic").checked;
+	StumbleGlobals.ds.setValue("$show_searchlinks_topic", new_show_searchlinks_topic);
+
+	var new_show_searchlinks_logo = StumbleGlobals.get_element("show_searchlinks_logo").checked;
+	StumbleGlobals.ds.setValue("$show_searchlinks_logo", new_show_searchlinks_logo);
+
+	var new_stumble_upon_change = StumbleGlobals.get_element("stumble_upon_change").checked;
+	StumbleGlobals.ds.setValue("$stumble_upon_change", new_stumble_upon_change);
+	
+	var new_show_toggle_refcount = StumbleGlobals.get_element("show_toggle_refcount").checked;
+	StumbleGlobals.ds.setValue("$show_toggle_refcount", new_show_toggle_refcount);
+
+//	var new_autocomplete_type = StumbleGlobals.get_element("search_group").selectedItem.value;
+//	StumbleGlobals.ds.setValue("$autocomplete_type", new_autocomplete_type);
+
+	// now see if icons thingies have changed...
+	var new_icons_only;
+	if (StumbleGlobals.get_element("icons-only").selected)
+	{
+		new_icons_only = "icons-only";
+		StumbleGlobals.ds.setValue("$show_firstrater_label_always", StumbleGlobals.get_element("show_firstrater_label_always").checked);
+	}
+	else if (StumbleGlobals.get_element("text-icons").selected)
+	{
+		new_icons_only = "text-icons";
+		StumbleGlobals.ds.setValue("$show_firstrater_label_always", preferred_show_firstrater_label_always);
+	}
+	StumbleGlobals.ds.setValue("$icons", new_icons_only);
+
+//	else if (StumbleGlobals.get_element("extra-text").selected)
+//		new_icons_only = "extra-text";
+
+/*
+	if ((navigator.userAgent.indexOf("Win") != -1) &&
+				(navigator.userAgent.indexOf("Firefox") != -1))
+	{
+		// The plugin only works on Firefox under XP for now....
+		// See also the relevant section in stumbleuponOverlay.js.
+
+		var new_search_plugin = StumbleGlobals.get_element("search_plugin").checked;
+
+		if (new_search_plugin != search_plugin)
+		{
+			StumbleGlobals.ds.setValue("$search_plugin", new_search_plugin);
+			if (parent_window)
+			{
+				if (new_search_plugin)
+				{
+					parent_window.StumbleGlobals.add_search_plugin(1);
+					alert("The search engine plugin will be added when you restart your browser.");
+				}
+				else
+				{
+					parent_window.StumbleGlobals.remove_search_plugin();
+					alert("The search engine plugin will be removed when you restart your browser.");
+				}
+			}
+		}
+	}
+*/
+	var toolbar_toggle_visible = StumbleGlobals.get_element("toggle").checked;
+	StumbleGlobals.ds.setValue("@toolbar_toggle_visible", toolbar_toggle_visible)
+	var old_toolbar_position = StumbleGlobals.ds.getValue("@toolbar-position");
+	var toolbar_position = StumbleGlobals.get_element("toolbar-position").selectedItem.id;
+	StumbleGlobals.ds.setValue("@toolbar-position", toolbar_position);
+	if (StumbleGlobals.get_element("position-group").selectedItem)
+	{
+		var toolbar = parent_window.StumbleGlobals.get_element(toolbar_position);
+		var customizable = (toolbar.hasAttribute("customizable") && 
+					(toolbar.getAttribute("customizable") == "true"))
+
+		var position_group = StumbleGlobals.get_element("position-group").selectedItem.id;
+		
+		if ((position_group == "drop") && ((! customizable) ||
+					(toolbar_position != old_toolbar_position)))
+			position_group = "first";
+			
+		StumbleGlobals.ds.setValue("@position-group", position_group);
+	}
+
+	var shortcuts_enabled = StumbleGlobals.get_element("shortcuts-enable").checked;
+	StumbleGlobals.ds.setValue("$shortcuts_enabled", shortcuts_enabled);
+	
+	var shortcut_stumble = StumbleGlobals.get_element("shortcut_stumble").getAttribute("keyspec");
+	StumbleGlobals.ds.setValue("$shortcut_stumble", shortcut_stumble);
+
+	var shortcut_referrals = StumbleGlobals.get_element("shortcut_referrals").getAttribute("keyspec");
+	StumbleGlobals.ds.setValue("$shortcut_referrals", shortcut_referrals);
+	
+	var shortcut_reviews = StumbleGlobals.get_element("shortcut_reviews").getAttribute("keyspec");
+	StumbleGlobals.ds.setValue("$shortcut_reviews", shortcut_reviews);
+
+	var shortcut_thumbup = StumbleGlobals.get_element("shortcut_thumbup").getAttribute("keyspec");
+	StumbleGlobals.ds.setValue("$shortcut_thumbup", shortcut_thumbup);
+
+	var shortcut_thumbdown = StumbleGlobals.get_element("shortcut_thumbdown").getAttribute("keyspec");
+	StumbleGlobals.ds.setValue("$shortcut_thumbdown", shortcut_thumbdown);
+
+	var shortcut_tag = StumbleGlobals.get_element("shortcut_tag").getAttribute("keyspec");
+	StumbleGlobals.ds.setValue("$shortcut_tag", shortcut_tag);
+
+//	var shortcut_details = StumbleGlobals.get_element("shortcut_details").getAttribute("keyspec");
+//	StumbleGlobals.ds.setValue("$shortcut_details", shortcut_details);
+
+	var shortcut_toolbar = StumbleGlobals.get_element("shortcut_toolbar").getAttribute("keyspec");
+	StumbleGlobals.ds.setValue("$shortcut_toolbar", shortcut_toolbar);
+	
+	StumbleGlobals.ds.flushPrefs();
+
+	parent_window.setTimeout(function (parent) { parent.StumbleGlobals.handle_preference_dialog_accept(); }, 0, parent_window);
+	
+	return true;
+}
+
+function doCancel(event)
+{
+	if (! is_parent_window_destroyed())
+	{
+		parent_window.StumbleGlobals.preference_dialog = null;
+	}
+	
+	return true;
+}
+
+function is_parent_window_destroyed()
+{
+	// Verify that the window is undestroyed. -- JW
+	try { var str = parent_window.location + " "; }
+	catch (e)
+	{
+		return true;
+	}
+	return false;
+}
+
+function init()
+{
+	var i;
+	if (opener && opener.location.href.indexOf("extensions.xul") != -1)
+	{
+		if (opener.opener && (opener.opener.location.href.indexOf("browser.xul") != -1))
+		{
+			// opened from the extensions window
+			parent_window = opener.opener;
+		}
+	}
+	else
+	{
+		// opened via the toolbar Menu
+		parent_window = opener;
+	}
+	
+	if(!parent_window || !parent_window.StumbleGlobals)
+	{
+		// Try the last top-level browser window.
+		// This will work when the opener is either Fx4 or the all-in-one-sidebar
+		//  (I think the latter might be deprecated)
+		// possibly opened from the all-in-one sidebar
+		var window_service = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+					.getService(Components.interfaces.nsIWindowMediator);
+		parent_window = window_service.getMostRecentWindow("navigator:browser");
+	}
+
+	if (is_parent_window_destroyed())
+	{
+		StumbleGlobals.get_element("stumble_pref_dialog").cancelDialog();
+		return;
+	}
+	
+	
+	parent_window.StumbleGlobals.preference_dialog = StumbleGlobals.get_element("stumble_pref_dialog");
+	
+	var deck = StumbleGlobals.get_element("prefs_deck");
+	
+	var accept_button = document.getElementById("stumble_pref_dialog").getButton("accept");
+	
+	if (StumbleGlobals.ds.getValue("@current_user") == 0)
+	{
+		var id_list = StumbleGlobals.ds.getValue("@id_list");
+		
+		var ids = id_list.split(":");
+		
+		var found_an_id = false;
+		
+		for (i = 0; i < ids.length; i++)
+		{
+			if (ids[i] == "")
+				continue;
+			
+			found_an_id = true;
+			break;
+		}
+		
+		deck.selectedPanel = StumbleGlobals.get_element("prefs_signin");
+		accept_button.collapsed = true;
+//		if (found_an_id)
+//		{
+//			alert("You can edit preferences after you sign-in.\n\n" +
+//						'Click the "Start Stumbling..." button on the toolbar to sign-in.');
+//		}
+//		else
+//		{
+//			alert("You can edit toolbar preferences after you create a StumbleUpon profile.\n\n" +
+//						'Click the "Start Stumbling..." button on the toolbar to create a profile.');
+//		}
+//		window.close();
+		return;
+	}
+	else
+	{
+		deck.selectedPanel = StumbleGlobals.get_element("prefs_tabbox");
+		accept_button.collapsed = false;
+	}
+	
+	var detail;
+	if (window.arguments && window.arguments.length)
+		detail = window.arguments[0];
+	else
+		detail = null;
+	
+	StumbleGlobals.get_element("sync_bm_meta").checked = StumbleGlobals.ds.getValue("$sync_bm_meta");
+	StumbleGlobals.get_element("sync_bm_exclude_adult").checked = (! StumbleGlobals.ds.getValue("$sync_bm_adult"));
+	update_download_favs_enabled_state();
+	
+	if (StumbleGlobals.ds.hasFeature("$sociallinks"))
+		StumbleGlobals.get_element("show_searchlinks_friends_box").hidden = false;
+	
+//	if (StumbleGlobals.ds.hasFeature("$reportoption"))
+//		StumbleGlobals.get_element("show_flag_box").hidden = false;
+	
+	if (parent_window.StumbleGlobals.host.places && (! StumbleGlobals.ds.getValue("#migrating_places")))
+		StumbleGlobals.get_element("favs_box").hidden = false;
+	
+	var show_searchlinks_score = StumbleGlobals.ds.getValue("$show_searchlinks_score");
+	StumbleGlobals.get_element("show_searchlinks_score").checked = show_searchlinks_score;
+	
+	var show_searchlinks_friends = StumbleGlobals.ds.getValue("$show_searchlinks_friends");
+	StumbleGlobals.get_element("show_searchlinks_friends").checked = show_searchlinks_friends;
+	
+	var show_searchlinks_topic = StumbleGlobals.ds.getValue("$show_searchlinks_topic");
+	StumbleGlobals.get_element("show_searchlinks_topic").checked = show_searchlinks_topic;
+	
+	var show_searchlinks_logo = StumbleGlobals.ds.getValue("$show_searchlinks_logo");
+	StumbleGlobals.get_element("show_searchlinks_logo").checked = show_searchlinks_logo;
+	
+	var stumble_upon_change = StumbleGlobals.ds.getValue("$stumble_upon_change");
+	StumbleGlobals.get_element("stumble_upon_change").checked = stumble_upon_change;
+	
+	var show_toggle_refcount = StumbleGlobals.ds.getValue("$show_toggle_refcount");
+	StumbleGlobals.get_element("show_toggle_refcount").checked = show_toggle_refcount;
+	
+	StumbleGlobals.update_searchlinks_logo_enabled_state();
+//	}
+	
+	bad_stumble = StumbleGlobals.ds.getValue("$bad_stumble");
+	great_stumble = StumbleGlobals.ds.getValue("$great_stumble");
+	
+	StumbleGlobals.get_element("show_field").checked = StumbleGlobals.ds.getValue("$show_field");
+//	update_field_enabled_state();	
+/*
+	if ((navigator.userAgent.indexOf("Win") != -1) &&
+				(navigator.userAgent.indexOf("Firefox") != -1))
+	{
+		search_plugin = StumbleGlobals.ds.getValue("$search_plugin");
+	}
+	else
+	{
+		// The plugin only works on Firefox under XP for now....
+		// Hide the search plug-in configuration control until we figure out
+		// how to install/uninstall on other platforms.
+		// See also the relevant section in stumbleuponOverlay.js.
+		
+		StumbleGlobals.get_element("search_plugin").hidden = true;
+	}
+*/
+
+	StumbleGlobals.get_element("show_mode").checked = StumbleGlobals.ds.getValue("$show_mode");
+	for (i = 0; i < mode_ids.length; i++)
+	{
+		StumbleGlobals.get_element(mode_ids[i]).checked = StumbleGlobals.ds.getValue("$" + mode_ids[i]);
+	}
+	update_mode_enabled_state();
+	
+	// set inputs...
+	StumbleGlobals.get_element("bad-stumble").checked = bad_stumble;
+	StumbleGlobals.get_element("great-stumble").checked = great_stumble;
+//	StumbleGlobals.get_element("search_plugin").checked = search_plugin;
+	
+	StumbleGlobals.get_element("prefetch").checked = StumbleGlobals.ds.getValue("$prefetch");
+//	StumbleGlobals.get_element("comment_firstrating").checked = StumbleGlobals.ds.getValue("$comment_firstrating");
+	StumbleGlobals.get_element("review_new_window").checked = StumbleGlobals.ds.getValue("$review_new_window");
+	StumbleGlobals.get_element("rate_new_window").checked = StumbleGlobals.ds.getValue("$rate_new_window");
+//	StumbleGlobals.get_element("search_new_window").checked = StumbleGlobals.ds.getValue("$search_new_window");
+	StumbleGlobals.get_element("stumble_topics").checked = StumbleGlobals.ds.getValue("$stumble_topics");
+	StumbleGlobals.get_element("stumble_topics2").checked = StumbleGlobals.ds.getValue("$stumble_topics");
+	StumbleGlobals.get_element("stumble_topics2_style_menu").disabled = !StumbleGlobals.ds.getValue("$stumble_topics");
+	var current_select = StumbleGlobals.ds.getValue("$stumble_topics_style");
+	if (current_select == 1 || current_select == 2)
+		StumbleGlobals.get_element("stumble_topics2_style_menu").selectedIndex = current_select;
+	else
+		StumbleGlobals.get_element("stumble_topics2_style_menu").selectedIndex = 0;
+	StumbleGlobals.get_element("search_clear_queries").checked = StumbleGlobals.ds.getValue("$search_clear_queries");
+	
+	StumbleGlobals.get_element("show_topics").checked = StumbleGlobals.ds.getValue("$show_topics");
+	StumbleGlobals.get_element("show_info").checked = StumbleGlobals.ds.getValue("$show_info");
+//	StumbleGlobals.get_element("show_search").checked = StumbleGlobals.ds.getValue("$show_search");
+	StumbleGlobals.get_element("show_tag").checked = StumbleGlobals.ds.getValue("$show_tag");
+	StumbleGlobals.get_element("show_tag2").checked = StumbleGlobals.ds.getValue("$show_tag");
+//	StumbleGlobals.get_element("show_flag").checked = StumbleGlobals.ds.getValue("$show_flag");
+	StumbleGlobals.get_element("show_fbshare").checked = StumbleGlobals.ds.getValue("$show_fbshare");
+	StumbleGlobals.get_element("show_referral").checked = StumbleGlobals.ds.getValue("$show_referral");
+	StumbleGlobals.get_element("show_aboutme").checked = StumbleGlobals.ds.getValue("$show_aboutme");
+	StumbleGlobals.get_element("show_home").checked = StumbleGlobals.ds.getValue("$show_home");
+	StumbleGlobals.get_element("show_friends").checked = StumbleGlobals.ds.getValue("$show_friends");
+	StumbleGlobals.get_element("show_messages").checked = StumbleGlobals.ds.getValue("$show_messages");
+//	StumbleGlobals.get_element("show_legacy_network").checked = StumbleGlobals.ds.getValue("$show_legacy_network");
+	StumbleGlobals.get_element("show_matches").checked = StumbleGlobals.ds.getValue("$show_matches");
+//	StumbleGlobals.get_element("show_legacy_forums").checked = StumbleGlobals.ds.getValue("$show_legacy_forums");
+	StumbleGlobals.get_element("show_groups").checked = StumbleGlobals.ds.getValue("$show_groups");
+//	StumbleGlobals.get_element("show_editinfo").checked = StumbleGlobals.ds.getValue("$show_editinfo");
+	
+	StumbleGlobals.get_element("toggle").checked = StumbleGlobals.ds.getValue("@toolbar_toggle_visible");
+	
+	icons_only = StumbleGlobals.ds.getValue("$icons");
+	
+	if (icons_only == "extra-text")
+		icons_only = "text-icons";
+	
+	StumbleGlobals.get_element("text-group").selectedItem = StumbleGlobals.get_element(icons_only);
+	
+	preferred_show_firstrater_label_always = StumbleGlobals.ds.getValue("$show_firstrater_label_always");
+	update_firstrater_label_enabled_state();
+	
+//	var autocomplete_type = StumbleGlobals.ds.getValue("$autocomplete_type");
+//	StumbleGlobals.get_element("search_group").selectedItem = StumbleGlobals.get_element("search_group_" + autocomplete_type);
+	
+	var shortcut_stumble_default;
+	var shortcut_reviews_default;
+	var shortcut_thumbup_default;
+	var shortcut_thumbdown_default;
+	var shortcut_tag_default;
+//	var shortcut_details_default;
+	var shortcut_toolbar_default;
+	var shortcut_referrals_default = "";
+	
+	if (parent_window.StumbleGlobals.host.mac)
+	{
+		shortcut_stumble_default = "Alt+VK_ESCAPE";
+		shortcut_thumbup_default = "Alt+VK_F1";
+		shortcut_thumbdown_default = "Alt+VK_F2";
+		shortcut_tag_default     = "Alt+VK_SLASH";
+		shortcut_reviews_default = "Alt+VK_F3";
+//		shortcut_details_default = "Alt+VK_F4";
+		shortcut_toolbar_default = "Command+VK_F11";
+	}
+	else if (parent_window.StumbleGlobals.host.win)
+	{
+ 		shortcut_stumble_default = "Alt+VK_BACK_QUOTE";
+ 		shortcut_thumbup_default = "Alt+VK_1";
+ 		shortcut_thumbdown_default = "Alt+VK_2";
+		shortcut_tag_default     = "Alt+VK_SLASH";
+ 		shortcut_reviews_default = "Alt+VK_3";
+//		shortcut_details_default = "Alt+VK_4";
+		shortcut_toolbar_default = "Ctrl+VK_F11";
+	}
+	else
+	{
+		shortcut_stumble_default = "Alt+VK_ESCAPE";
+		shortcut_thumbup_default = "Alt+VK_F1";
+		shortcut_thumbdown_default = "Alt+VK_F2";
+		shortcut_tag_default     = "Alt+VK_SLASH";
+ 		shortcut_reviews_default = "Alt+VK_F3";
+//		shortcut_details_default = "Alt+VK_F4";
+		shortcut_toolbar_default = "Ctrl+VK_F11";
+	}
+	var shortcut_stumble = StumbleGlobals.ds.getPrefValue("$shortcut_stumble", shortcut_stumble_default);
+	var shortcut_thumbup = StumbleGlobals.ds.getPrefValue("$shortcut_thumbup", shortcut_thumbup_default);
+	var shortcut_thumbdown = StumbleGlobals.ds.getPrefValue("$shortcut_thumbdown", shortcut_thumbdown_default);
+	var shortcut_tag = StumbleGlobals.ds.getPrefValue("$shortcut_tag", shortcut_tag_default);
+	var shortcut_reviews = StumbleGlobals.ds.getPrefValue("$shortcut_reviews", shortcut_reviews_default);
+	var shortcut_referrals = StumbleGlobals.ds.getPrefValue("$shortcut_referrals", shortcut_referrals_default);
+	
+//	var shortcut_details = StumbleGlobals.ds.getPrefValue("$shortcut_details", shortcut_details_default);
+	var shortcut_toolbar = StumbleGlobals.ds.getPrefValue("$shortcut_toolbar", shortcut_toolbar_default);
+	
+	StumbleGlobals.get_element("shortcut_stumble").setAttribute("keyspec", shortcut_stumble);
+	StumbleGlobals.get_element("shortcut_stumble").setAttribute("keyspec-default", shortcut_stumble_default);
+	StumbleGlobals.get_element("shortcut_thumbup").setAttribute("keyspec", shortcut_thumbup);
+	StumbleGlobals.get_element("shortcut_thumbup").setAttribute("keyspec-default", shortcut_thumbup_default);
+	StumbleGlobals.get_element("shortcut_thumbdown").setAttribute("keyspec", shortcut_thumbdown);
+	StumbleGlobals.get_element("shortcut_thumbdown").setAttribute("keyspec-default", shortcut_thumbdown_default);
+	StumbleGlobals.get_element("shortcut_tag").setAttribute("keyspec", shortcut_tag);
+	StumbleGlobals.get_element("shortcut_tag").setAttribute("keyspec-default", shortcut_tag_default);
+	StumbleGlobals.get_element("shortcut_reviews").setAttribute("keyspec", shortcut_reviews);
+	StumbleGlobals.get_element("shortcut_reviews").setAttribute("keyspec-default", shortcut_reviews_default);
+	StumbleGlobals.get_element("shortcut_referrals").setAttribute("keyspec", shortcut_referrals);
+	StumbleGlobals.get_element("shortcut_referrals").setAttribute("keyspec-default", shortcut_referrals_default);
+//	StumbleGlobals.get_element("shortcut_details").setAttribute("keyspec", shortcut_details);
+//	StumbleGlobals.get_element("shortcut_details").setAttribute("keyspec-default", shortcut_details_default);
+	
+	var shortcuts_enabled = StumbleGlobals.ds.getValue("$shortcuts_enabled");
+	StumbleGlobals.get_element("shortcuts-enable").checked = shortcuts_enabled;
+	handle_shortcuts_enable_command(shortcuts_enabled);
+	
+	StumbleGlobals.get_element("shortcut_toolbar").setAttribute("label", "  " + parent_window.StumbleGlobals.get_display_keyspec(shortcut_toolbar));
+	StumbleGlobals.get_element("shortcut_toolbar").setAttribute("keyspec", shortcut_toolbar);
+	StumbleGlobals.get_element("shortcut_toolbar").setAttribute("keyspec-default", shortcut_toolbar_default);
+	
+	
+	if (! parent_window.BrowserCustomizeToolbar)
+	{
+		StumbleGlobals.get_element("placement-toolkit-caption").hidden = true;
+		StumbleGlobals.get_element("placement-caption").hidden = false;
+		StumbleGlobals.get_element("customize-position-box").hidden = true;
+	}
+	init_toolbar_placement();
+	
+	if (detail && detail.initial_tab)
+	{
+		setTimeout(function() {
+			select_tab(detail.initial_tab);	
+		}, 0);
+	}
+}
+
+function select_tab(tabid)
+{
+	StumbleGlobals.get_element("prefs_tabbox").selectedTab = StumbleGlobals.get_element(tabid);
+}
+
+function init_toolbar_placement()
+{
+	// Create list of toolbars for toolbar-position
+	
+	var toolbars = parent_window.document.getElementsByTagName("toolbar");
+	var statusbars = parent_window.document.getElementsByTagName("statusbar");
+	var menubars = parent_window.document.getElementsByTagName("menubar");
+	var popup = StumbleGlobals.get_element("placement-popup");
+	var x, bar, item, val, list;
+	
+	// first remove the toolbars already there...
+	while (popup.hasChildNodes())
+		popup.removeChild(popup.firstChild);
+	
+	toolbars = concat(toolbars, statusbars);
+	toolbars = concat(toolbars, menubars);
+	
+	for (x = 0; x < toolbars.length; x++)
+	{
+		if (! toolbars[x].hasAttribute("id"))
+			continue;
+		
+		var bar_id = toolbars[x].getAttribute("id");
+
+		if (StumbleGlobals.ds.lookup("toolbarid:bad_target_flag", bar_id))
+			continue;
+		
+		// Skip non-customizable toolbars with the exception of the status-bar
+		if (! toolbars[x].hasAttribute("customizable") ||
+			! (toolbars[x].getAttribute("customizable").toLowerCase() == "true"))
+		{
+			if(bar_id != "status-bar")
+				continue;
+		}
+		
+		// weird firefox toolbar
+		if ((bar_id == "toolbar-menubar") &&
+					(navigator.userAgent.indexOf("Mac") != -1))
+			continue;
+
+		// Exclude the All-in-One Sidebar extension toolbars. -- JW
+		if (bar_id.indexOf("aios") == 0)
+			continue;
+		
+		// Exclude the ScrapBook toolbars. -- JW
+		if (bar_id.indexOf("ScrapBook") == 0)
+			continue;
+		
+		// Exclude webdeveloper supplemental toolbars. -- JW
+		if ((bar_id.indexOf("webdeveloper") != -1) && 
+					(bar_id != "webdeveloper-toolbar"))
+			continue;
+		
+		item = document.createElement("menuitem");
+		item.setAttribute("id", bar_id);
+		item.value = bar_id;
+		if (item.value == "status-bar")
+			item.setAttribute("label", "Status Bar");
+		else if (item.value == "toolbar-menubar")
+			item.setAttribute("label", "Menu Bar");
+		else if (item.value == "nav-bar")
+			item.setAttribute("label", "Navigation Toolbar");
+		else if (item.value == "PersonalToolbar")
+			item.setAttribute("label", "Personal Toolbar");
+		else if (item.value == "linktoolbar")
+			item.setAttribute("label", "Link Toolbar");
+		else if (toolbars[x].hasAttribute("toolbarname"))
+			item.setAttribute("label", toolbars[x].getAttribute("toolbarname"));
+		else
+			item.setAttribute("label", bar_id);
+		
+		if (bar_id == "stumbleupon")
+		{
+			stumbleupon_toolbar_menuitem = item;
+		}
+		
+		popup.appendChild(item);
+	}
+
+	var toolbar_position = StumbleGlobals.ds.getValue("@toolbar-position");
+	if ((toolbar_position == "webpedia") || 
+			(toolbar_position == "fbToolbar"))
+	{
+		toolbar_position = "stumbleupon";
+	}
+	StumbleGlobals.get_element("toolbar-position").selectedItem = StumbleGlobals.get_element(toolbar_position);
+
+	var position_group = StumbleGlobals.ds.getValue("@position-group");
+	if ((toolbar_position == "stumbleupon") || 
+			(toolbar_position == "gtbToolbar") || 
+			(toolbar_position == "yahoo-toolbar") ||
+			(toolbar_position == "prefbar") ||
+			(toolbar_position == "MBSTB-Toolbar"))
+	{
+		position_group = "first";
+		StumbleGlobals.ds.setValue("@position-group", "first");
+	}
+	preferred_position_group = position_group;
+	StumbleGlobals.get_element("position-group").selectedItem = StumbleGlobals.get_element(position_group);
+	
+	handle_toolbar_position_command(toolbar_position);
+	handle_position_group_command(position_group);
+}
+	
+function concat(c1, c2)
+{
+	// Concats too collections into an array.
+	var c3 = new Array(c1.length + c2.length);
+	var x,y = 0;
+	
+	for (x = 0; x < c1.length; x++)
+		c3[y++] = c1[x];
+	
+	for (x = 0; x < c2.length; x++)
+		c3[y++] = c2[x];
+	
+	return c3;
+}
+
+/*
+function topWindow()
+{
+	//XXX need app specific
+	var windowManager = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService();
+	var windowManagerInterface = windowManager.QueryInterface(Components.interfaces.nsIWindowMediator);
+	var win = windowManagerInterface.getMostRecentWindow("navigator:browser");
+	if (!win)
+		win = window.openDialog("chrome://browser/content/browser.xul", "_blank", "chrome,all,dialog=no", "about:blank", null, null);
+	return win;
+}
+*/
+
+function handle_show_tag_command()
+{
+	StumbleGlobals.get_element("show_tag2").checked = StumbleGlobals.get_element("show_tag").checked;
+}
+
+function handle_show_tag2_command()
+{
+	StumbleGlobals.get_element("show_tag").checked = StumbleGlobals.get_element("show_tag2").checked;
+}
+
+function handle_stumble_topics_command()
+{
+	StumbleGlobals.get_element("stumble_topics2").checked = StumbleGlobals.get_element("stumble_topics").checked;
+	StumbleGlobals.get_element("stumble_topics2_style_menu").disabled = !StumbleGlobals.get_element("stumble_topics2").checked;
+}
+
+function handle_stumble_topics2_command()
+{
+	StumbleGlobals.get_element("stumble_topics").checked = StumbleGlobals.get_element("stumble_topics2").checked;
+	StumbleGlobals.get_element("stumble_topics2_style_menu").disabled = !StumbleGlobals.get_element("stumble_topics2").checked;
+}
+
+function update_download_favs_enabled_state()
+{
+	var sync = StumbleGlobals.get_element("sync_bm_meta").checked;
+	
+	if (! sync)
+		handle_stop_download_favs_command();
+	
+	var detail = StumbleGlobals.ds.getValue("#download_favs_detail");
+	
+	var enabled = (! detail);
+	
+	StumbleGlobals.get_element("download_start").disabled = (! sync) || (! enabled);
+	StumbleGlobals.get_element("download_stop").disabled = (! sync) || enabled;
+	StumbleGlobals.get_element("sync_bm_exclude_adult").disabled = (! sync);
+}
+
+function update_firstrater_label_enabled_state()
+{
+	if (StumbleGlobals.get_element("icons-only").selected)
+	{
+		StumbleGlobals.get_element("show_firstrater_label_always").checked = preferred_show_firstrater_label_always;
+		StumbleGlobals.get_element("show_firstrater_label_always").disabled = false;
+	}
+	else if (StumbleGlobals.get_element("text-icons").selected)
+	{
+		preferred_show_firstrater_label_always = StumbleGlobals.get_element("show_firstrater_label_always").checked;
+		StumbleGlobals.get_element("show_firstrater_label_always").checked = true;
+		StumbleGlobals.get_element("show_firstrater_label_always").disabled = true;
+	}
+}
+
+StumbleGlobals.update_searchlinks_logo_enabled_state = function()
+{
+	var show_searchlinks_score = StumbleGlobals.get_element("show_searchlinks_score").checked;
+	var show_searchlinks_friends = StumbleGlobals.get_element("show_searchlinks_friends").checked;
+	var show_searchlinks_topic = StumbleGlobals.get_element("show_searchlinks_topic").checked;
+	StumbleGlobals.get_element("show_searchlinks_logo").disabled = 
+			(!(show_searchlinks_score || show_searchlinks_friends || show_searchlinks_topic));
+}
+
+function update_mode_enabled_state()
+{
+	var enabled = StumbleGlobals.get_element("show_mode").checked;
+	var i;
+	for (i = 0; i < mode_ids.length; i++)
+		StumbleGlobals.get_element(mode_ids[i]).disabled = (! enabled);
+	
+	StumbleGlobals.get_element("show_mode_more").disabled = (! enabled);
+	StumbleGlobals.get_element("show_mode_more_button").disabled = (! enabled);
+}
+
+//function update_field_enabled_state()
+//{
+//	var enabled = StumbleGlobals.get_element("show_field").checked;
+//	
+//	StumbleGlobals.get_element("search_group_prompt").disabled = (! enabled);
+//	StumbleGlobals.get_element("search_group_query").disabled = (! enabled);
+//	StumbleGlobals.get_element("search_group_tag").disabled = (! enabled);
+//	
+//}
+
+function handle_download_favs_command()
+{
+	StumbleGlobals.ds.setValue("#download_favs_detail", null);
+	StumbleGlobals.ds.setValue("$download_favs_detail", {});
+	StumbleGlobals.ds.flushPrefs();
+	
+	parent_window.setTimeout(function (win) {
+				win.StumbleGlobals.handle_download_favs_command(); },
+			100,
+			parent_window);
+}
+
+function handle_stop_download_favs_command()
+{
+	setTimeout(function() {
+		handle_stop_download_favs_command2();
+	}, 100);
+}
+
+function handle_stop_download_favs_command2()
+{
+	var db = StumbleGlobals.ds.getDatabase();
+	var sql;
+	var context;
+	StumbleGlobals.ds.setValue("$download_favs_state", "a");
+	StumbleGlobals.ds.setValue("#download_favs_detail", null);
+	StumbleGlobals.ds.setValue("$download_favs_detail", {});
+	StumbleGlobals.ds.flushPrefs();
+	sql = "DELETE FROM command_queue WHERE priority=16000";
+	db.query(sql);
+	context = StumbleGlobals.ds.getValue("#command_queue_context");
+	if (context)
+		context.command_rows = new Array();
+	StumbleGlobals.get_element("download_progress").value = 0;
+	update_download_favs_enabled_state();
+}
+
+function handle_toggle_label_click()
+{
+	StumbleGlobals.get_element("toggle").checked = (! StumbleGlobals.get_element("toggle").checked); 
+}
+
+function handle_signin_command()
+{
+	if (opener && opener.location.href.indexOf("extensions.xul") != -1)
+	{
+		opener.setTimeout(
+				function (win) { win.close(); },
+				0,
+				opener);
+	}
+	
+	parent_window.setTimeout(
+			function (win) { win.StumbleGlobals.show_signin_dialog(); },
+			0,
+			parent_window);
+	
+	window.close();
+}
+
+function handle_create_account_command()
+{
+	if (opener && opener.location.href.indexOf("extensions.xul") != -1)
+	{
+		opener.setTimeout(
+				function (win) { win.close(); },
+				0,
+				opener);
+	}
+	
+	parent_window.setTimeout(
+			function (win) {
+				win.StumbleGlobals.set_server_location_signup(!win.StumbleGlobals.is_about_blank()); },
+			0,
+			parent_window);
+	
+	window.close();
+}
+
+function handle_toolbar_position_command(toolbar_position)
+{
+	if ((toolbar_position == "stumbleupon") || 
+			(toolbar_position == "gtbToolbar") || 
+			(toolbar_position == "yahoo-toolbar") ||
+			(toolbar_position == "prefbar") ||
+			(toolbar_position == "MBSTB-Toolbar"))
+	{
+		StumbleGlobals.get_element("last").disabled = true;
+		StumbleGlobals.get_element("position-group").selectedItem = StumbleGlobals.get_element("first");
+	}
+	else
+	{
+		StumbleGlobals.get_element("last").disabled = false;
+		StumbleGlobals.get_element("position-group").selectedItem = StumbleGlobals.get_element(preferred_position_group);
+	}
+}
+
+function handle_position_group_command(position_group)
+{
+	preferred_position_group = position_group;
+}
+
+function handle_customize_position_command()
+{
+	StumbleGlobals.ds.setValue("@toolbar-position", "stumbleupon");
+	StumbleGlobals.ds.setValue("@position-group", "drop");
+	StumbleGlobals.ds.flushPrefs();
+	parent_window.setTimeout(function (parent) { parent.StumbleGlobals.customize_toolbox(); }, 100, parent_window);
+	window.close();
+}
+
+function handle_more_mode_command()
+{
+	window.openDialog(
+			"chrome://stumbleupon/content/moreChannelsDialog.xul", 
+			"More Channels",
+			"chrome,modal,dialog,centerscreen,dependent");
+}
+
+function handle_shortcuts_enable_command(enabled)
+{
+	var ids = enable_ids;
+	
+	var i;
+	var found = false;
+	for (i = 0; i < ids.length; i++)
+	{
+		var el = StumbleGlobals.get_element(ids[i]);
+		if (el == shortcut_item)
+			found = true;
+		var label = StumbleGlobals.get_element(ids[i] + "_label");
+		if (enabled)
+		{
+			label.disabled = false;
+			el.setAttribute("label", "  " + 
+					parent_window.StumbleGlobals.get_display_keyspec(
+					el.getAttribute("keyspec")));
+		}
+		else
+		{
+			label.disabled = true;
+			el.setAttribute("label", "");
+		}
+	}
+	
+	if (found && (! enabled))
+	{
+		shortcut_item = null;
+		refresh_shortcut_preview();
+	}
+}
+		
+// handles the select event for the shortcuts element
+function handle_shortcuts_select(event)
+{
+	StumbleGlobals.get_element("shortcut_preview").disabled = false;
+	StumbleGlobals.get_element("shortcut_change").disabled = false;
+	
+	shortcut_item = get_shortcut_item_from_index(event.target.selectedIndex);
+	keyspec = shortcut_item.getAttribute("keyspec");
+	
+	if (! StumbleGlobals.get_element("shortcuts-enable").checked)
+	{
+		var ids = enable_ids;
+		var found = false;
+		for (i = 0; i < ids.length; i++)
+		{
+			if (ids[i] == shortcut_item.id)
+			{
+				found = true;
+				break;
+			}
+		}
+		if (found)
+		{
+			StumbleGlobals.get_element("shortcuts-enable").checked = true;
+			handle_shortcuts_enable_command(true);
+		}
+	}
+	
+	refresh_shortcut_preview();
+}
+
+// dereferences a shortcut selected item index to the cell element
+// used to display the shortcut
+function get_shortcut_item_from_index(index)
+{
+	switch (index)
+	{
+		case 0: item_id = "shortcut_stumble";   break;
+		case 1: item_id = "shortcut_thumbup";   break;
+		case 2: item_id = "shortcut_thumbdown"; break;
+		case 3: item_id = "shortcut_referrals"; break;
+		case 4: item_id = "shortcut_tag";       break;
+		case 5: item_id = "shortcut_reviews";   break;
+		case 6: item_id = "shortcut_toolbar";   break;
+//		case 5: item_id = "shortcut_details";   break;
+//		case 6: item_id = "shortcut_toolbar";   break;
+	}
+	return StumbleGlobals.get_element(item_id);
+}
+
+// handles the shortcut disable button command
+function handle_shortcut_disable_command()
+{
+	keyspec = "";
+	shortcut_item.setAttribute("keyspec", keyspec);
+	shortcut_item.setAttribute("label", "");
+	
+	refresh_shortcut_preview();
+
+	if (shortcut_item.id == "shortcut_toolbar")
+	{
+		set_toolbar_position_label("StumbleUpon Toolbar");
+	}
+}
+
+// handles the shortcut revert button command
+function handle_shortcut_revert_command()
+{
+	keyspec = shortcut_item.getAttribute("keyspec-default");
+	shortcut_item.setAttribute("keyspec", keyspec);
+	shortcut_item.setAttribute("label", "  " + parent_window.StumbleGlobals.get_display_keyspec(keyspec));
+	
+	refresh_shortcut_preview();
+	
+	var item_cur;
+	for (var i = 0; i <= 5; i++)
+	{
+		item_cur = get_shortcut_item_from_index(i);
+ 		if ((item_cur != shortcut_item) && (item_cur.getAttribute("keyspec") == keyspec))
+		{
+			item_cur.setAttribute("keyspec", "");
+			item_cur.setAttribute("label", "");
+			if ((i == TOGGLE_TOOLBAR_LISTITEM_INDEX) && (stumbleupon_toolbar_menuitem != null))
+			{
+				set_toolbar_position_label("StumbleUpon Toolbar");
+			}
+		}
+	}
+}
+
+// handles the shortcut change button command
+function handle_shortcut_change_command()
+{
+	shortcut_item.setAttribute("keyspec", keyspec);
+	shortcut_item.setAttribute("label", "  " + parent_window.StumbleGlobals.get_display_keyspec(keyspec));
+
+	refresh_shortcut_preview();	
+	
+	var item_cur;
+	for (var i = 0; i <= 4; i++)
+	{
+		item_cur = get_shortcut_item_from_index(i);
+		if ((item_cur != shortcut_item) && (item_cur.getAttribute("keyspec") == keyspec))
+		{
+			item_cur.setAttribute("keyspec", "");
+			item_cur.setAttribute("label", "");
+			if (i == TOGGLE_TOOLBAR_LISTITEM_INDEX)
+			{
+				set_toolbar_position_label("StumbleUpon Toolbar");
+			}
+		}
+	}
+	
+	if (shortcut_item.id == "shortcut_toolbar")
+	{
+		set_toolbar_position_label("StumbleUpon Toolbar (" +
+				parent_window.StumbleGlobals.get_display_keyspec(keyspec) + ")")
+	}
+}
+
+// used by the shortcut configuration routines to update the 
+// StumbleUpon Toolbar menuitem in the toolbar-position popup
+function set_toolbar_position_label(label)
+{
+	if (stumbleupon_toolbar_menuitem != null)
+	{
+		stumbleupon_toolbar_menuitem.label = label;
+		var toolbar_position = StumbleGlobals.get_element("toolbar-position");
+		if (toolbar_position.selectedItem == stumbleupon_toolbar_menuitem)
+		{
+			if (stumbleupon_toolbar_menuitem.previousSibling)
+			{
+				toolbar_position.selectedItem = stumbleupon_toolbar_menuitem.previousSibling;
+				toolbar_position.selectedItem = stumbleupon_toolbar_menuitem;
+			}
+			else if (stumbleupon_toolbar_menuitem.nextSibling)
+			{
+				toolbar_position.selectedItem = stumbleupon_toolbar_menuitem.nextSibling;
+				toolbar_position.selectedItem = stumbleupon_toolbar_menuitem;
+			}
+		}
+	}
+}
+
+// handles the keyup event for the shortcuts list
+function handle_shortcuts_keyup(event)
+{
+	if ((event.keyCode == KeyEvent.DOM_VK_UP) ||
+			(event.keyCode == KeyEvent.DOM_VK_DOWN))
+	{
+		return true;
+	}
+	else
+	{
+		return handle_shortcut_preview_keyup(event);
+	}
+}
+
+// handles the keypress event for the shortcuts list
+function handle_shortcuts_keypress(event)
+{
+	return handle_shortcut_preview_keypress(event);
+}
+
+// handles the keypress event for the shortcut-preview textbox
+function handle_shortcut_preview_keypress(event)
+{
+  var str = "";
+
+	if (event.altKey)   str += "Alt+";
+	if (event.ctrlKey)  str += "Ctrl+";
+	if (event.metaKey)  str += "Command+";
+	if (event.shiftKey) str += "Shift+";
+
+	recent_keypress_modifiers = str;
+
+	return true;
+}
+
+// handles the keyup event for the shortcut-preview textbox
+function handle_shortcut_preview_keyup(event)
+{
+  if ((event.keyCode == KeyEvent.DOM_VK_TAB) ||
+  			(event.keyCode == KeyEvent.DOM_VK_SHIFT) ||
+  			(event.keyCode == KeyEvent.DOM_VK_CONTROL) ||
+  			(event.keyCode == KeyEvent.DOM_VK_ALT) ||
+  			(event.keyCode == KeyEvent.DOM_VK_META) ||
+  			(event.keyCode == KeyEvent.DOM_VK_NUM_LOCK) ||
+  			(event.keyCode == KeyEvent.DOM_VK_SCROLL_LOCK) ||
+  			(event.keyCode == KeyEvent.DOM_VK_CAPS_LOCK))
+  {
+  	return true;
+  }
+  event.stopPropagation();
+  event.preventDefault();
+	
+	var keyid;
+	if (event.charCode)
+		keyid = parent_window.StumbleGlobals.keyids_by_eventkeycode[event.charCode];
+	else
+		keyid = parent_window.StumbleGlobals.keyids_by_eventkeycode[event.keyCode];
+	
+	keyspec = recent_keypress_modifiers + keyid;
+	refresh_shortcut_preview();
+	
+	return false;
+}
+
+// sets button and label state given keyspec being previewed as a
+// binding for shortcut_item
+function refresh_shortcut_preview()
+{
+	var shortcut_revert = StumbleGlobals.get_element("shortcut_revert");
+	var shortcut_disable = StumbleGlobals.get_element("shortcut_disable");
+	var shortcut_change = StumbleGlobals.get_element("shortcut_change");
+
+	if (! shortcut_item)
+	{
+		if (shortcut_revert.hasAttribute("tooltiptext"))
+			shortcut_revert.removeAttribute("tooltiptext");
+		
+		shortcut_revert.disabled = true;
+		shortcut_disable.disabled = true;
+		shortcut_change.disabled = true;
+		
+		StumbleGlobals.get_element("shortcut_preview").value = "";
+		StumbleGlobals.get_element("shortcut_default_behavior").value = "";
+		return;
+	}
+
+	var keyspec_current = shortcut_item.getAttribute("keyspec");
+	var keyspec_default = shortcut_item.getAttribute("keyspec-default");
+	
+	if (keyspec_current == keyspec_default)
+	{
+		shortcut_revert.removeAttribute("tooltiptext");
+		shortcut_revert.disabled = true;
+	}
+	else
+	{
+		shortcut_revert.setAttribute("tooltiptext", 
+				"Revert to " + parent_window.StumbleGlobals.get_display_keyspec(keyspec_default));
+		shortcut_revert.disabled = false;
+	}
+	
+	shortcut_change.disabled = (keyspec_current == keyspec);
+	
+	shortcut_disable.disabled = (keyspec_current == "");
+
+	StumbleGlobals.get_element("shortcut_preview").value = parent_window.StumbleGlobals.get_display_keyspec(keyspec);
+	StumbleGlobals.get_element("shortcut_default_behavior").value = get_default_binding_desc(keyspec);
+}
+
+// returns description suitable for user consuption for the target
+// of a keybinding
+function get_default_binding_desc(spec)
+{
+	var desc = "";
+
+	if (spec == "")
+	{
+		return desc;
+	}
+
+	if (is_keyspec_accellerated(spec))
+	{
+		if (typeof parent_window.StumbleGlobals.keys_by_keyspec[spec] != "undefined")
+		{
+			var key = parent_window.StumbleGlobals.keys_by_keyspec[spec];
+			desc = get_binding_name_from_key(key);
+			if (desc == "key_StumbleUpon:ToggleToolbar")
+				desc = "";
+		}
+		else if ((spec.indexOf("Alt") != -1) && 
+				(spec.replace(/[\+_]/g, "").search(/\d|\W/) == -1) &&
+				(spec.indexOf("VK_BACK_QUOTE") == -1) &&
+				(spec != "Alt+VK_SLASH"))
+		{
+			desc = "[menu accelerator]";
+		}
+		else if ((! parent_window.StumbleGlobals.host.win) &&
+				(spec.search(/VK_\d/) != -1))
+		{
+			desc = "[mode/navigation]";
+		}
+	}
+	else if (is_keyspec_editing(spec))
+	{
+		desc = "[editing]";
+	}
+	else
+	{
+		desc = "[mode/navigation]"
+	}
+	return desc;
+}
+
+function is_keyspec_accellerated(spec)
+{
+	return (spec.indexOf("Ctrl") != -1) ||
+			(spec.indexOf("Alt") != -1) ||
+			(spec.indexOf("Command") != -1)
+}
+
+function is_keyspec_editing(spec)
+{
+	if ((spec.indexOf("VK_HOME") != -1) ||
+			(spec.indexOf("VK_END") != -1) ||
+			(spec.indexOf("VK_INSERT") != -1) ||
+			(spec.indexOf("VK_DELETE") != -1))
+	{
+		return true;
+	}
+	else if (is_keyspec_accellerated(spec))
+	{
+		return false;
+	}
+	else if (spec.indexOf("VK_NUMPAD") != -1)
+	{
+		return true;
+	}
+	else
+	{
+		var parts = spec.split("+");
+		return parts[parts.length - 1].length <= 4;
+	}
+}
+
+// [IP:] [kudos:] The following two functions are from the public 
+// domain keyconfig extension by Joe Dorando. -- JW
+
+// searches for a description suitable for user consumption for a
+// given key element
+function get_binding_name_from_key(aKey)
+{
+  var val;
+
+  if(aKey.hasAttribute("label")) return aKey.getAttribute("label");
+
+  if(aKey.hasAttribute("command") || aKey.hasAttribute("observes")) {
+    var command = aKey.getAttribute("command") || aKey.getAttribute("observes");
+    var node = parent_window.StumbleGlobals.get_element(command);
+    if(node && node.hasAttribute("label")) return node.getAttribute("label");
+    val = getLabel("command", command);
+    if(!val) val = getLabel("observes", command);
+  }
+
+  if(!val) val = getLabel("key", aKey.id);
+
+  if(val) return val;
+
+  var id = aKey.id.replace(/xxx_key.+?_/,"");
+	var converter = StumbleGlobals.create_instance(
+				"@mozilla.org/intl/scriptableunicodeconverter",
+				"nsIScriptableUnicodeConverter");
+  try {
+		id = converter.ConvertToUnicode(id);
+	} catch(err) {}
+
+  return id;
+}
+function getLabel(attr, value) {
+  var Users = parent_window.document.getElementsByAttribute(attr,value);
+  var User;
+
+  for(var i = 0, l = Users.length; i < l; i++)
+    if(Users[i].hasAttribute("label") && (!User || User.localName == "menuitem")) User = Users[i];
+
+  if(!User) return null;
+
+  if(User.localName == "menuitem" && User.parentNode.parentNode.parentNode.localName == "menupopup") {
+    return User.getAttribute("label") + " [" + User.parentNode.parentNode.getAttribute("label") + "]";
+  } else return User.getAttribute("label");
+}
+
+
diff --git a/chrome/stumbleupon.jar!/content/preferenceDialog.xul b/content/preferenceDialog.xul
similarity index 92%
rename from chrome/stumbleupon.jar!/content/preferenceDialog.xul
rename to content/preferenceDialog.xul
index c3aef8b..c766568 100644
--- a/chrome/stumbleupon.jar!/content/preferenceDialog.xul
+++ b/content/preferenceDialog.xul
@@ -16,8 +16,11 @@
 	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
 </stringbundleset>
 
+<script type="application/x-javascript" src="namespace.js"/>
 <script type="application/x-javascript" src="preferenceDialog.js"/>
 
+<deck id="prefs_deck">
+
 <tabbox id="prefs_tabbox">
 <tabs>
 	<tab id="appearance_tab"
@@ -127,6 +130,11 @@
 								src="chrome://stumbleupon/content/skin/icon_tb_tag_left.png"/>
 						</hbox>
 						<hbox align="start">
+							<checkbox id="show_fbshare"
+								label="Facebook"
+								 src="chrome://stumbleupon/content/skin/favicon_facebook.gif"/>
+						</hbox>
+						<hbox align="start">
 							<checkbox id="show_referral"
 								label="Share"
 								 src="chrome://stumbleupon/content/skin/icon_tb_share.png"/>
@@ -141,13 +149,13 @@
 								label="What's New"
 								 src="chrome://stumbleupon/content/skin/icon_tb_user_comment.png"/>
 						</hbox>
+					</vbox>
+					<vbox align="start">
 						<hbox align="start">
 							<checkbox id="show_home"
 								label="Favorites"
 								src="chrome://stumbleupon/content/skin/icon_tb_favorites_hover.png"/>
 						</hbox>
-					</vbox>
-					<vbox align="start">
 						<hbox align="start">
 							<checkbox id="show_friends"
 								label="Stumblers"
@@ -216,7 +224,7 @@
 -->
 			<hbox align="start">
 				<checkbox id="show_mode_friends"
-					label="Subscriptions"
+					label="Following"
 					src="chrome://stumbleupon/content/skin/icon_tb_people.png"/>
 			</hbox>
 			<hbox align="start">
@@ -285,7 +293,7 @@
 		<hbox align="start">
 			<checkbox id="show_searchlinks_score"
 				label="Highlight recommended search results"
-				oncommand="su_update_searchlinks_logo_enabled_state();"/>
+				oncommand="StumbleGlobals.update_searchlinks_logo_enabled_state();"/>
 		</hbox>
 		<hbox>
 			<spacer width="19px"/>
@@ -299,12 +307,12 @@
 			hidden="true">
 			<checkbox id="show_searchlinks_friends"
 				label="Show names of friends who like search results"
-				oncommand="su_update_searchlinks_logo_enabled_state();"/>
+				oncommand="StumbleGlobals.update_searchlinks_logo_enabled_state();"/>
 		</hbox>
 		<hbox align="start">
 			<checkbox id="show_searchlinks_topic"
 				label="Show topics of search results"
-				oncommand="su_update_searchlinks_logo_enabled_state();"/>
+				oncommand="StumbleGlobals.update_searchlinks_logo_enabled_state();"/>
 		</hbox>
 		<hbox align="start">
 			<checkbox id="show_searchlinks_logo"
@@ -415,6 +423,10 @@
 		<hbox align="start">
 			<checkbox id="prefetch" label="Prefetch stumbles (makes stumbling faster)" />
 		</hbox>
+		<hbox align="start">
+			<checkbox id="show_toggle_refcount" label="Show count of shares on the toggle button" />
+		</hbox>
+		
 <!--
 		<hbox align="start">
 			<checkbox id="stumble_topics" label="Show topic for stumble" />
@@ -447,11 +459,13 @@
 				label="Show classic Network control" />
 		</hbox>
 -->
+<!--
 		<hbox align="start">
 			<checkbox id="show_legacy_forums"
 				src="chrome://stumbleupon/content/skin/legacy_forum.png"
 				label="Show classic Forums control"/>
 		</hbox>
+-->
 		<hbox>
 			<vbox>
 				<spacer flex="1"/>
@@ -544,6 +558,19 @@
 				</listcell>
 				<listcell id="shortcut_thumbdown"/>
 			</listitem>
+			<listitem id="shortcut_referrals_item">
+				<listcell>
+					<spacer width="3px"/>
+					<image id="shortcut_referrals_icon"
+							src="chrome://stumbleupon/content/skin/arrow_ani4.png"/>
+					<spacer width="3px"/>
+				</listcell>
+				<listcell>
+					<label id="shortcut_referrals_label"
+							value=" Shares" align="baseline"/>
+				</listcell>
+				<listcell id="shortcut_referrals"/>
+			</listitem>
 			<listitem id="shortcut_tag_item">
 				<listcell>
 					<spacer width="3px"/>
@@ -650,4 +677,25 @@
 </tabpanel>
 </tabpanels>
 </tabbox>
+<groupbox id="prefs_signin" orient="vertical">
+	<caption label="Sign-in To Set Preferences"/>
+	<spacer flex="1"/>
+	<hbox pack="center">
+		<button label="Sign-in..."
+			width="170"
+			oncommand="handle_signin_command()"/>
+	</hbox>
+	<spacer height="20"/>
+	<hbox pack="center">
+		<label value="or"/>
+	</hbox>
+	<spacer height="20"/>
+	<hbox pack="center">
+		<button label="Create an account..."
+			width="170"
+			oncommand="handle_create_account_command()"/>
+	</hbox>
+	<spacer flex="3"/>
+</groupbox>
+</deck>
 </dialog>
diff --git a/chrome/stumbleupon.jar!/content/prefetcher.js b/content/prefetcher.js
similarity index 93%
rename from chrome/stumbleupon.jar!/content/prefetcher.js
rename to content/prefetcher.js
index 74ffb23..4de4f07 100644
--- a/chrome/stumbleupon.jar!/content/prefetcher.js
+++ b/content/prefetcher.js
@@ -1,4 +1,4 @@
-function su_Prefetcher()
+StumbleGlobals.Prefetcher = function()
 {
 	//!!! We need to get the mouse cursor load clock image to not spin.
 	// background:
@@ -13,7 +13,7 @@ function su_Prefetcher()
 	}
 	catch (e) {
 		// seamonkey kludge
-		service = su_service;
+		service = StumbleGlobals.service;
 	}
 	this.ds = service.getDatastore();
 	this.URIsIndex = -1;
@@ -25,8 +25,8 @@ function su_Prefetcher()
 	this.urlDetailByURI = new Object();
 	this.httpStatusesByURI = new Object();
 	this.target = null;
-	this.id = su_Prefetcher.instanceCount++;
-	this.browserId = "su_prefetcher" + this.id;
+	this.id = StumbleGlobals.Prefetcher.instanceCount++;
+	this.browserId = "stumbleglobals_prefetcher" + this.id;
 	this.passCount = 1;
 	this.URIsTopIndex = 0;
 	this.URIsBottomIndex = -1;
@@ -88,7 +88,7 @@ function su_Prefetcher()
 				this.allTargetsPrefetched = true;
 				this._dispatchEvent("done");
 				if (this.ds.getValue("@log_prefetch_progress"))
-					su_log("prefetching done");
+					StumbleGlobals.log("prefetching done");
 			}
 			else if (! this.allTargetsPrefetched)
 			{
@@ -125,9 +125,9 @@ function su_Prefetcher()
 		browser.addProgressListener(this);
 		
 		try {
-			browser.loadURI(this.target, su_get_nsiuri(this.referrersByURI[this.target]), null);
+			browser.loadURI(this.target, StumbleGlobals.get_nsiuri(this.referrersByURI[this.target]), null);
 		} catch (e) {
-			su_log_error("prefetch load error", e, this.target);
+			StumbleGlobals.log_error("prefetch load error", e, this.target);
 		}
 		
 //		if (browser.contentDocument.contentType != "text/html")
@@ -146,7 +146,7 @@ function su_Prefetcher()
 		}
 		
 		if (this.ds.getValue("@log_prefetch_progress"))
-			su_log("prefetching " + (this.URIsIndex + 1) + " of " + this.URIs.length, this.target, "pass " + this.passCount + " with timeout " + interval + "ms");
+			StumbleGlobals.log("prefetching " + (this.URIsIndex + 1) + " of " + this.URIs.length, this.target, "pass " + this.passCount + " with timeout " + interval + "ms");
 
 		this.timer = setTimeout(function (prefetcher) { prefetcher._finishPrefetch("timeout"); }, interval, this)
 	}
@@ -154,7 +154,7 @@ function su_Prefetcher()
 	this._finishPrefetch = function (from)
 	{
 		if (this.ds.getValue("@log_prefetch_progress"))
-			su_log("finish", from);
+			StumbleGlobals.log("finish", from);
 		var state;
 		switch (from)
 		{
@@ -208,7 +208,7 @@ function su_Prefetcher()
 			return;
 		
 		if (this.ds.getValue("@log_prefetch_progress"))
-			su_log("logging " + (this.URIsIndex + 1) + " of " + this.URIs.length, this.target, "pass " + this.passCount, "state " + this.statesByURI[this.target]);
+			StumbleGlobals.log("logging " + (this.URIsIndex + 1) + " of " + this.URIs.length, this.target, "pass " + this.passCount, "state " + this.statesByURI[this.target]);
 
 		var browser = document.getElementById(this.browserId);
 		if (browser && browser.contentDocument && browser.contentDocument.location)
@@ -429,7 +429,7 @@ function su_Prefetcher()
 			!iid.equals(Components.interfaces.nsISupportsWeakReference) && // not implemented
 			!iid.equals(Components.interfaces.nsISupports))
 		{
-			throw Components.errors.NS_ERROR_NO_INTERFACE;
+			throw Components.results.NS_ERROR_NO_INTERFACE;
 		}
 
 		return this;
@@ -504,5 +504,5 @@ function su_Prefetcher()
 	this.onSecurityChange = function (aWebProgress, aRequest, aState) {}
 }
 //###  static attributes
-su_Prefetcher.instanceCount = 0;
+StumbleGlobals.Prefetcher.instanceCount = 0;
 
diff --git a/chrome/stumbleupon.jar!/content/ratingDialog.js b/content/ratingDialog.js
similarity index 82%
rename from chrome/stumbleupon.jar!/content/ratingDialog.js
rename to content/ratingDialog.js
index 3b8cf1a..3856fb2 100644
--- a/chrome/stumbleupon.jar!/content/ratingDialog.js
+++ b/content/ratingDialog.js
@@ -1,153 +1,155 @@
-var theurl = "";
-var theurlid = 0;
-var tags_was_focused = false;
-var old_tags_value = "";
-var searchbox_value = "";
-
-// handle dialog load event
-function init()
-{
-	// grab the url you are commenting on
-	var args = window.arguments;
-	theurl = args[0];
-	theurlid = args[1];
-	searchbox_value = args[2];
-	quote = args[3];
-	
-	document.getElementById("firstrater-prompt").hidden = (theurlid != 0);
-	
-	document.getElementById("review").value = quote;
-
-	var tags = document.getElementById("tags");
-
-	tags.autocompleteDatasource =
-				{
-					getResults : function ()
-					{
-						var tags = document.getElementById("tags");
-						return opener.su_get_autocomplete_results(
-									"tag",
-									tags.value,
-									tags.maxRows,
-									new Array(searchbox_value));
-					}
-				}
-}
-
-// handle dialog accept event
-function doOK()
-{
-	// blank url
-	if (theurl == "" || theurlid == 0)
-		return true;
-
-	var tags = document.getElementById("tags").value;
-	if (tags == null)
-		return true;
-
-	var review = document.getElementById("review").value;
-	if (review == null)
-		return true;
-
-	var tagerror = opener.su_validate_tagstring(tags);
-	if (tagerror != null)
-	{
-		alert(tagerror);
-		document.getElementById("tags").focus();
-		return false;
-	}	
-	
-	// We create zero delay timeouts in the context of the parent 
-	// window, then destroy this window after two seconds.  The delay
-	// adds the illusion of immediacy.  And the zero delay timeouts 
-	// make sure the submissions occur even if this window is destroyed
-	// while the submissions are in progress. -- JW
-	
-	if (review.search(/^\s*$/) == -1)
-	{
-		// add review
-		opener.setTimeout(function(parent, theurlid, review){ parent.su_add_review(theurlid, review); }, 0, opener, theurlid, review);
-	}
-	if (tags != '')
-	{
-		opener.document.getElementById("su_searchbox").value = tags;
-		opener.setTimeout(function(parent, tags){ parent.su_tagit(tags, false); }, 0, opener, tags);
-	}
-
-	setTimeout("closeWindow();", 2000);
-
-	return false;
-}
-
-// used by doOK() to close this window after a timeout
-function closeWindow()
-{
-	close();
-}
-
-// handle dialog cancel event
-function doCancel()
-{
-	return true;
-}
-
-// handle tags box click event
-function tags_click_kludge(eventId)
-{
-	// This handles value selection in the case where the user is
-	// clicking back and forth between tags and another field
-	// (like review).  Without this kludge, the text is selected only
-	// every second time.  (ref: Firefox 1.5, XP) -- JW
-
-	switch (eventId)
-	{
-		case "click":
-			var tags = document.getElementById('tags');
-			var selected = (tags.value.length != 0)
-						&& ((tags.selectionEnd - tags.selectionStart) == tags.value.length);
-
-			if ((! tags_was_focused) && (! selected))
-			{
-				tags.select();
-			}
-			tags_was_focused = true;
-		break;
-		case "blur":
-			tags_was_focused = false;
-		break;
-	}
-
-	return true;
-}
-
-// handle tags box focus event
-function handle_tags_focus(evt)
-{
-	var tags = document.getElementById('tags');
-
-	if (tags.value != "")
-	{
-		tags.select();
-	}
-}
-
-// handle tags box keyup event
-function handle_tags_keyup(evt)
-{
-	old_tags_value = document.getElementById("tags").value;
-	return true;
-}
-
-// handle tags box textentered event
-function handle_tags_textentered()
-{
-	document.getElementById("stumble_rating_dialog").acceptDialog();
-}
-
-// handle tags box textreverted event
-function handle_tags_textreverted()
-{
-	document.getElementById("tags").value = old_tags_value;
-	document.getElementById("tags").select();
-}
-
+var theurl = "";
+var theurlid = 0;
+var tags_was_focused = false;
+var old_tags_value = "";
+var searchbox_value = "";
+
+// handle dialog load event
+function init()
+{
+	// grab the url you are commenting on
+	var args = window.arguments;
+	theurl = args[0];
+	theurlid = args[1];
+	searchbox_value = args[2];
+	quote = args[3];
+	
+	document.getElementById("firstrater-prompt").hidden = (theurlid != 0);
+	
+	document.getElementById("review").value = quote;
+
+	var tags = document.getElementById("tags");
+
+	tags.autocompleteDatasource =
+				{
+					getResults : function ()
+					{
+						var tags = document.getElementById("tags");
+						return opener.StumbleGlobals.get_autocomplete_results(
+									"tag",
+									tags.value,
+									tags.maxRows,
+									new Array(searchbox_value));
+					}
+				}
+}
+
+// handle dialog accept event
+function doOK()
+{
+	// blank url
+	if (theurl == "" || theurlid == 0)
+		return true;
+
+	var tags = document.getElementById("tags").value;
+	if (tags == null)
+		return true;
+
+	var review = document.getElementById("review").value;
+	if (review == null)
+		return true;
+
+	var tagerror = opener.StumbleGlobals.validate_tagstring(tags);
+	if (tagerror != null)
+	{
+		alert(tagerror);
+		document.getElementById("tags").focus();
+		return false;
+	}	
+	
+	// We create zero delay timeouts in the context of the parent 
+	// window, then destroy this window after two seconds.  The delay
+	// adds the illusion of immediacy.  And the zero delay timeouts 
+	// make sure the submissions occur even if this window is destroyed
+	// while the submissions are in progress. -- JW
+	
+	if (review.search(/^\s*$/) == -1)
+	{
+		// add review
+		opener.setTimeout(function(parent, theurlid, review){ parent.StumbleGlobals.add_review(theurlid, review); }, 0, opener, theurlid, review);
+	}
+	if (tags != '')
+	{
+		opener.document.getElementById("stumbleglobals_searchbox").value = tags;
+		opener.setTimeout(function(parent, tags){ parent.StumbleGlobals.tagit(tags, false); }, 0, opener, tags);
+	}
+
+	setTimeout(function() {
+		closeWindow();
+	}, 2000);
+
+	return false;
+}
+
+// used by doOK() to close this window after a timeout
+function closeWindow()
+{
+	close();
+}
+
+// handle dialog cancel event
+function doCancel()
+{
+	return true;
+}
+
+// handle tags box click event
+function tags_click_kludge(eventId)
+{
+	// This handles value selection in the case where the user is
+	// clicking back and forth between tags and another field
+	// (like review).  Without this kludge, the text is selected only
+	// every second time.  (ref: Firefox 1.5, XP) -- JW
+
+	switch (eventId)
+	{
+		case "click":
+			var tags = document.getElementById('tags');
+			var selected = (tags.value.length != 0)
+						&& ((tags.selectionEnd - tags.selectionStart) == tags.value.length);
+
+			if ((! tags_was_focused) && (! selected))
+			{
+				tags.select();
+			}
+			tags_was_focused = true;
+		break;
+		case "blur":
+			tags_was_focused = false;
+		break;
+	}
+
+	return true;
+}
+
+// handle tags box focus event
+function handle_tags_focus(evt)
+{
+	var tags = document.getElementById('tags');
+
+	if (tags.value != "")
+	{
+		tags.select();
+	}
+}
+
+// handle tags box keyup event
+function handle_tags_keyup(evt)
+{
+	old_tags_value = document.getElementById("tags").value;
+	return true;
+}
+
+// handle tags box textentered event
+function handle_tags_textentered()
+{
+	document.getElementById("stumble_rating_dialog").acceptDialog();
+}
+
+// handle tags box textreverted event
+function handle_tags_textreverted()
+{
+	document.getElementById("tags").value = old_tags_value;
+	document.getElementById("tags").select();
+}
+
diff --git a/chrome/stumbleupon.jar!/content/ratingDialog.xul b/content/ratingDialog.xul
similarity index 96%
rename from chrome/stumbleupon.jar!/content/ratingDialog.xul
rename to content/ratingDialog.xul
index 17d2b37..4f30a97 100644
--- a/chrome/stumbleupon.jar!/content/ratingDialog.xul
+++ b/content/ratingDialog.xul
@@ -1,78 +1,78 @@
-<?xml version="1.0"?>
-
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-<?xml-stylesheet href="chrome://stumbleupon/skin/ratingDialog.css" type="text/css"?>
-
-<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
-
-<dialog id="stumble_rating_dialog" title="StumbleUpon Review"
-  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-  buttons="accept,cancel"
-  ondialogaccept="return doOK();"
-  ondialogcancel="return doCancel();"
-  onload="init()">
-
-<stringbundleset id="stringbundleset">
-	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
-</stringbundleset>
-
-<script type="application/x-javascript" src="ratingDialog.js"/>
-
-<popupset>
-	<popup id="tagspopup"/>
-</popupset>
-
-<vbox style="margin:5px" align="center">
-	<label id="firstrater-prompt"
-		value="You are the first person to suggest this site."/>
-	<label value="Please add some tags and/or a review."/>
-<grid flex="1" style="margin:10px">
-  <columns>
-    <column flex="2"/>
-    <column flex="1"/>
-  </columns>
-
-  <rows>
-    <row>
-    <vbox>
-    	<spacer flex="1"/>
-    	<label control="tags" value="Tags"/>
-    	<spacer flex="1"/>
-    </vbox>
-    <textbox id="tags"
-			maxrows="14"
-			flex="1"
-			autocompletepopup="tagspopup"
-			inputtooltiptext="Enter Tag Terms separated by Commas"
-			ontextentered="handle_tags_textentered()"
-			ontextreverted="handle_tags_textreverted()"
-			onkeyup="handle_tags_keyup(event)"
-			onfocus="handle_tags_focus()"
-			onclick="tags_click_kludge('click')"
-			onblur="tags_click_kludge('blur')"
-			reflectpopuplabel="true"
-			sizetopopup="none"
-			cols="40"
-			maxLength="150"/>	
-    </row>
-    <row>
-    <label value=""/>
-    <label style="font-size:10px" value="spaces allowed in tags, separate with commas"/>
-    </row>
-    
-    <row>
-    <label control="review"  value="Review"/>
-    <textbox cols="40" multiline="true" rows="3" maxlength="1000" id="review"/>
-    </row>
-    
-    <row>
-    <label value=""/>
-    <label style="font-size:10px" value="(You can turn off this dialog in Toolbar Options)"/>    
-    </row>
-    
-  </rows>
-</grid>
-
-</vbox>
-
-</dialog>
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://stumbleupon/skin/ratingDialog.css" type="text/css"?>
+
+<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
+
+<dialog id="stumble_rating_dialog" title="StumbleUpon Review"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+  buttons="accept,cancel"
+  ondialogaccept="return doOK();"
+  ondialogcancel="return doCancel();"
+  onload="init()">
+
+<stringbundleset id="stringbundleset">
+	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
+</stringbundleset>
+
+<script type="application/x-javascript" src="ratingDialog.js"/>
+
+<popupset>
+	<popup id="tagspopup"/>
+</popupset>
+
+<vbox style="margin:5px" align="center">
+	<label id="firstrater-prompt"
+		value="You are the first person to suggest this site."/>
+	<label value="Please add some tags and/or a review."/>
+<grid flex="1" style="margin:10px">
+  <columns>
+    <column flex="2"/>
+    <column flex="1"/>
+  </columns>
+
+  <rows>
+    <row>
+    <vbox>
+    	<spacer flex="1"/>
+    	<label control="tags" value="Tags"/>
+    	<spacer flex="1"/>
+    </vbox>
+    <textbox id="tags"
+			maxrows="14"
+			flex="1"
+			autocompletepopup="tagspopup"
+			inputtooltiptext="Enter Tag Terms separated by Commas"
+			ontextentered="handle_tags_textentered()"
+			ontextreverted="handle_tags_textreverted()"
+			onkeyup="handle_tags_keyup(event)"
+			onfocus="handle_tags_focus()"
+			onclick="tags_click_kludge('click')"
+			onblur="tags_click_kludge('blur')"
+			reflectpopuplabel="true"
+			sizetopopup="none"
+			cols="40"
+			maxLength="150"/>	
+    </row>
+    <row>
+    <label value=""/>
+    <label style="font-size:10px" value="spaces allowed in tags, separate with commas"/>
+    </row>
+    
+    <row>
+    <label control="review"  value="Review"/>
+    <textbox cols="40" multiline="true" rows="3" maxlength="1000" id="review"/>
+    </row>
+    
+    <row>
+    <label value=""/>
+    <label style="font-size:10px" value="(You can turn off this dialog in Toolbar Options)"/>    
+    </row>
+    
+  </rows>
+</grid>
+
+</vbox>
+
+</dialog>
diff --git a/chrome/stumbleupon.jar!/content/reportTopicDialog.js b/content/reportTopicDialog.js
similarity index 82%
rename from chrome/stumbleupon.jar!/content/reportTopicDialog.js
rename to content/reportTopicDialog.js
index c234e6f..ae04d74 100644
--- a/chrome/stumbleupon.jar!/content/reportTopicDialog.js
+++ b/content/reportTopicDialog.js
@@ -1,27 +1,27 @@
-var detail;
-
-function init()
-{
-	detail = window.arguments[0];
-	
-	var el;
-	
-	el = document.getElementById("stumble_report_topic_dialog");
-	el.getButton("accept").label = "  Suggest Topic Change  ";
-	
-	el = document.getElementById("prompt_old_topic");
-	el.value = detail.old_topic_name;
-
-	el = document.getElementById("prompt_new_topic");
-	el.value = detail.new_topic_name;
-}
-
-function doOK()
-{
-	opener.setTimeout(
-		function(parent, detail) {
-			parent.su_handle_report_topic_dialog_accept(detail); },
-		0,
-		opener,
-		detail);
-}
+var detail;
+
+function init()
+{
+	detail = window.arguments[0];
+	
+	var el;
+	
+	el = document.getElementById("stumble_report_topic_dialog");
+	el.getButton("accept").label = "  Suggest Topic Change  ";
+	
+	el = document.getElementById("prompt_old_topic");
+	el.value = detail.old_topic_name;
+
+	el = document.getElementById("prompt_new_topic");
+	el.value = detail.new_topic_name;
+}
+
+function doOK()
+{
+	opener.setTimeout(
+		function(parent, detail) {
+			parent.StumbleGlobals.handle_report_topic_dialog_accept(detail); },
+		0,
+		opener,
+		detail);
+}
diff --git a/chrome/stumbleupon.jar!/content/reportTopicDialog.xul b/content/reportTopicDialog.xul
similarity index 96%
rename from chrome/stumbleupon.jar!/content/reportTopicDialog.xul
rename to content/reportTopicDialog.xul
index e76d97e..e683591 100644
--- a/chrome/stumbleupon.jar!/content/reportTopicDialog.xul
+++ b/content/reportTopicDialog.xul
@@ -1,95 +1,95 @@
-<?xml version="1.0"?>
-
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-
-<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
-
-<dialog id="stumble_report_topic_dialog" title="Report Wrong Topic - StumbleUpon"
-	xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-  buttons="accept,cancel"
-  persist="screenX screenY"
-  ondialogaccept="return doOK();"
-  onload="init()">
-
-<script type="application/x-javascript" src="reportTopicDialog.js"/>
-
-<spacer height="10px"/>
-<hbox>
-	<vbox>
-		<image class="question-icon" />
-	</vbox>
-	<hbox>
-		<vbox>
-			<spacer style="height: 10px;"/>
-			<label style="font-size: 16px; font-weight: bold;" value="  Do you want to move this page?  "/>
-			<spacer style="height: 20px;"/>
-			<grid>
-				<columns>
-					<column flex="1"/>
-					<column flex="20"/>
-					<column flex="80"/>
-				</columns>
-				<rows>
-					<row>
-						<spacer/>
-						<vbox align="right">
-							<spacer flex="3"/>
-							<description>from topic:</description>
-							<spacer flex="1"/>
-						</vbox>
-						<label id="prompt_old_topic" style="font-weight:bold; font-size:15px; color:gray;" value="stub a"/>
-					</row>
-					<row>
-						<spacer height="5px"/>
-						<spacer/>
-						<spacer/>
-					</row>
-					<row>
-						<spacer/>
-						<vbox align="right">
-							<spacer flex="3"/>
-							<description>to topic:</description>
-							<spacer flex="1"/>
-						</vbox>
-						<label id="prompt_new_topic" style="font-weight:bold; font-size:15px;" value="stub a"/>
-					</row>
-				</rows>
-			</grid>
-			<spacer height="10px"/>
-		</vbox>
-	</hbox>
-</hbox>
-<spacer height="10px"/>
-
-<!--
-<grid flex="1" style="margin:10px">
-  <columns>
-    <column flex="1"/>
-  </columns>
-  <rows>
-    <row>
-			<label value="Enter up to 5 tags, separated by commas:"/>
-		</row>
-		<row>
-			<textbox id="tags"
-				maxrows="14"
-				flex="1"
-				autocompletepopup="tagspopup"
-				inputtooltiptext="Enter Tag Terms separated by Commas"
-				ontextentered="handle_tags_textentered()"
-				ontextreverted="handle_tags_textreverted()"
-				onkeyup="handle_tags_keyup(event)"
-				onfocus="handle_tags_focus()"
-				onclick="tags_click_kludge('click')"
-				onblur="tags_click_kludge('blur')"
-				reflectpopuplabel="true"
-				sizetopopup="none"
-				maxLength="150"/>
-		</row>
-		<row>
-			<label value="Spaces are allowed in a tag." style="color:grey;"/>
-		</row>
-	</rows>
-</grid>
--->
-</dialog>
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
+
+<dialog id="stumble_report_topic_dialog" title="Report Wrong Topic - StumbleUpon"
+	xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+  buttons="accept,cancel"
+  persist="screenX screenY"
+  ondialogaccept="return doOK();"
+  onload="init()">
+
+<script type="application/x-javascript" src="reportTopicDialog.js"/>
+
+<spacer height="10px"/>
+<hbox>
+	<vbox>
+		<image class="question-icon" />
+	</vbox>
+	<hbox>
+		<vbox>
+			<spacer style="height: 10px;"/>
+			<label style="font-size: 16px; font-weight: bold;" value="  Do you want to move this page?  "/>
+			<spacer style="height: 20px;"/>
+			<grid>
+				<columns>
+					<column flex="1"/>
+					<column flex="20"/>
+					<column flex="80"/>
+				</columns>
+				<rows>
+					<row>
+						<spacer/>
+						<vbox align="right">
+							<spacer flex="3"/>
+							<description>from topic:</description>
+							<spacer flex="1"/>
+						</vbox>
+						<label id="prompt_old_topic" style="font-weight:bold; font-size:15px; color:gray;" value="stub a"/>
+					</row>
+					<row>
+						<spacer height="5px"/>
+						<spacer/>
+						<spacer/>
+					</row>
+					<row>
+						<spacer/>
+						<vbox align="right">
+							<spacer flex="3"/>
+							<description>to topic:</description>
+							<spacer flex="1"/>
+						</vbox>
+						<label id="prompt_new_topic" style="font-weight:bold; font-size:15px;" value="stub a"/>
+					</row>
+				</rows>
+			</grid>
+			<spacer height="10px"/>
+		</vbox>
+	</hbox>
+</hbox>
+<spacer height="10px"/>
+
+<!--
+<grid flex="1" style="margin:10px">
+  <columns>
+    <column flex="1"/>
+  </columns>
+  <rows>
+    <row>
+			<label value="Enter up to 5 tags, separated by commas:"/>
+		</row>
+		<row>
+			<textbox id="tags"
+				maxrows="14"
+				flex="1"
+				autocompletepopup="tagspopup"
+				inputtooltiptext="Enter Tag Terms separated by Commas"
+				ontextentered="handle_tags_textentered()"
+				ontextreverted="handle_tags_textreverted()"
+				onkeyup="handle_tags_keyup(event)"
+				onfocus="handle_tags_focus()"
+				onclick="tags_click_kludge('click')"
+				onblur="tags_click_kludge('blur')"
+				reflectpopuplabel="true"
+				sizetopopup="none"
+				maxLength="150"/>
+		</row>
+		<row>
+			<label value="Spaces are allowed in a tag." style="color:grey;"/>
+		</row>
+	</rows>
+</grid>
+-->
+</dialog>
diff --git a/content/requestTracker.js b/content/requestTracker.js
new file mode 100644
index 0000000..c929c37
--- /dev/null
+++ b/content/requestTracker.js
@@ -0,0 +1,80 @@
+//
+// StumbleGlobals.requestTracker
+//
+// StumbleGlobals.requestTracker functionality is used to time stumble requests
+// responses, and stumble actions
+//
+StumbleGlobals.requestTracker = {
+	stumbleClicked: function() {
+		// Track the terminating event for the previous stumble
+		StumbleGlobals.requestTracker.trackEvent(StumbleGlobals.get_browser_url(), "nextStumbleClick");
+		
+		// Start timing the request -- note that the complete time
+		// for the "request" may be very close to 0 if we don't actually have to hit
+		// recommend
+		this._stumbleClickedTime = (new Date()).getTime();
+		this._recommendResponseTime = 0; // We don't have a recommend response yet
+	},
+	
+	startNewStumbleUrl: function(url_detail) {
+		this._currentStumbleUrl = url_detail.url;
+		
+		// Record the starting stats.
+		// stumbleRequest is the time from the click
+		// stumbleResponse is the time between the click and when we have a URL
+		// If we didn't actually get a recommend response, then we must have loaded it
+		// from cache, so just say that we got the response right now.
+		if(!this._recommendResponseTime)
+			this._recommendResponseTime = (new Date()).getTime();
+		
+		var stumbleStats = {
+			publicid: url_detail.publicid,
+			stumbleRequest: this._stumbleClickedTime,
+			stumbleResponse: this._recommendResponseTime
+		}
+		
+		StumbleGlobals.ds.setValue("$prev_stumble_stats", StumbleGlobals.ds.serialize(stumbleStats));
+		
+		// Add listeners to track unload events
+		this._initUnloadTrackers();
+	},
+
+	onRecommendDone: function(url, name) {
+		this._recommendResponseTime = (new Date()).getTime(); 
+	},
+	
+	trackEvent: function(url, name) {
+		if(url == this._currentStumbleUrl)
+		{
+			var stats = StumbleGlobals.ds.getValue("$prev_stumble_stats");
+			if(!stats)
+				return;
+			
+			stats = StumbleGlobals.ds.deserialize(stats);
+			if(stats[name])
+				return;
+			stats[name] = (new Date()).getTime();
+			StumbleGlobals.ds.setValue("$prev_stumble_stats", StumbleGlobals.ds.serialize(stats));
+		}
+	},
+
+	_onPageHide: function(aEvent) {
+		var doc = aEvent.originalTarget; // doc is document that triggered "pagehide" event.
+		if(doc && doc.location && doc.location.href)
+			StumbleGlobals.requestTracker.trackEvent(doc.location.href, "pageHide");
+	},
+
+	_initUnloadTrackers: function() {
+		if(!this._pageHideTrackerInitialized)
+		{
+			this._pageHideTrackerInitialized = true;
+		
+			// Track pagehide (i.e. window unload) events
+			var appcontent = document.getElementById("appcontent");   // browser
+			if(appcontent)
+				appcontent.addEventListener("pagehide", this._onPageHide, false);
+		}
+	}
+}
+
+
diff --git a/chrome/stumbleupon.jar!/content/searchDialog.js b/content/searchDialog.js
similarity index 84%
rename from chrome/stumbleupon.jar!/content/searchDialog.js
rename to content/searchDialog.js
index 8b829c6..4301987 100644
--- a/chrome/stumbleupon.jar!/content/searchDialog.js
+++ b/content/searchDialog.js
@@ -1,110 +1,110 @@
-var detail = window.arguments[0];
-var field_was_focused = false;
-var old_tags_value = "";
-
-function init()
-{
-	var field = document.getElementById("field");
-	field.autocompleteDatasource =
-				{
-					getResults : function ()
-					{
-						var field = document.getElementById("field");
-						return opener.su_get_autocomplete_results(
-									"query",
-									field.value,
-									field.maxRows,
-									new Array());
-					}
-				}
-	field.value = detail.query_default;
-}
-
-function doOK()
-{
-	var query = document.getElementById("field").value;
-	if (query == null)
-		return true;
-
-/*
-	var error = opener.su_validate_tagstring(tags);
-	if (error != null)
-	{
-		alert(error);
-		document.getElementById("field").focus();
-		return false;
-	}
-*/
-	
-	if (query != '')
-	{
-		detail.query = query;
-		opener.document.getElementById("su_searchbox").value = query;
-		opener.setTimeout(
-					function(parent_window, detail){
-						parent_window.su_search_dialog_accept(detail);},
-					0,
-					opener,
-					detail);
-	}
-
-	return true;
-}
-
-function field_click_kludge(eventId)
-{
-	// This handles value selection in the case where the user is
-	// clicking back and forth between tags and another field.  Without
-	// this kludge, the text is selected only every second time.  (ref: 
-	// Firefox 1.5, XP)  This may not be necessary on this window since 
-	// the dialog has only one field, but it's here in case we need it 
-	// later. -- JW
-
-	switch (eventId)
-	{
-		case "click":
-			var tags = document.getElementById('field');
-			var selected = (tags.value.length != 0)
-						&& ((tags.selectionEnd - tags.selectionStart) == tags.value.length);
-
-			if ((! field_was_focused) && (! selected))
-			{
-				tags.select();
-			}
-			field_was_focused = true;
-		break;
-		case "blur":
-			field_was_focused = false;
-		break;
-	}
-
-	return true;
-}
-
-function handle_field_focus(evt)
-{
-	var tags = document.getElementById('field');
-
-	if (tags.value != "")
-	{
-		tags.select();
-	}
-}
-
-function handle_field_keyup(evt)
-{
-	old_tags_value = document.getElementById("field").value;
-	return true;
-}
-
-function handle_field_textentered()
-{
-	document.getElementById("stumble_search_dialog").acceptDialog();
-}
-
-function handle_field_textreverted()
-{
-	document.getElementById("field").value = old_tags_value;
-	document.getElementById("field").select();
-}
-
+var detail = window.arguments[0];
+var field_was_focused = false;
+var old_tags_value = "";
+
+function init()
+{
+	var field = document.getElementById("field");
+	field.autocompleteDatasource =
+				{
+					getResults : function ()
+					{
+						var field = document.getElementById("field");
+						return opener.StumbleGlobals.get_autocomplete_results(
+									"query",
+									field.value,
+									field.maxRows,
+									new Array());
+					}
+				}
+	field.value = detail.query_default;
+}
+
+function doOK()
+{
+	var query = document.getElementById("field").value;
+	if (query == null)
+		return true;
+
+/*
+	var error = opener.StumbleGlobals.validate_tagstring(tags);
+	if (error != null)
+	{
+		alert(error);
+		document.getElementById("field").focus();
+		return false;
+	}
+*/
+	
+	if (query != '')
+	{
+		detail.query = query;
+		opener.document.getElementById("stumbleglobals_searchbox").value = query;
+		opener.setTimeout(
+					function(parent_window, detail){
+						parent_window.StumbleGlobals.search_dialog_accept(detail);},
+					0,
+					opener,
+					detail);
+	}
+
+	return true;
+}
+
+function field_click_kludge(eventId)
+{
+	// This handles value selection in the case where the user is
+	// clicking back and forth between tags and another field.  Without
+	// this kludge, the text is selected only every second time.  (ref: 
+	// Firefox 1.5, XP)  This may not be necessary on this window since 
+	// the dialog has only one field, but it's here in case we need it 
+	// later. -- JW
+
+	switch (eventId)
+	{
+		case "click":
+			var tags = document.getElementById('field');
+			var selected = (tags.value.length != 0)
+						&& ((tags.selectionEnd - tags.selectionStart) == tags.value.length);
+
+			if ((! field_was_focused) && (! selected))
+			{
+				tags.select();
+			}
+			field_was_focused = true;
+		break;
+		case "blur":
+			field_was_focused = false;
+		break;
+	}
+
+	return true;
+}
+
+function handle_field_focus(evt)
+{
+	var tags = document.getElementById('field');
+
+	if (tags.value != "")
+	{
+		tags.select();
+	}
+}
+
+function handle_field_keyup(evt)
+{
+	old_tags_value = document.getElementById("field").value;
+	return true;
+}
+
+function handle_field_textentered()
+{
+	document.getElementById("stumble_search_dialog").acceptDialog();
+}
+
+function handle_field_textreverted()
+{
+	document.getElementById("field").value = old_tags_value;
+	document.getElementById("field").select();
+}
+
diff --git a/chrome/stumbleupon.jar!/content/searchDialog.xul b/content/searchDialog.xul
similarity index 96%
rename from chrome/stumbleupon.jar!/content/searchDialog.xul
rename to content/searchDialog.xul
index 0865898..edb2f42 100644
--- a/chrome/stumbleupon.jar!/content/searchDialog.xul
+++ b/content/searchDialog.xul
@@ -1,56 +1,56 @@
-<?xml version="1.0"?>
-
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-<?xml-stylesheet href="chrome://stumbleupon/skin/searchDialog.css" type="text/css"?>
-
-<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
-
-<dialog id="stumble_search_dialog" title="StumbleUpon Search"
-  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-  buttons="accept,cancel"
-  persist="screenX screenY width height"
-  ondialogaccept="return doOK();"
-  onload="init()">
-
-<stringbundleset id="stringbundleset">
-	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
-</stringbundleset>
-
-<script type="application/x-javascript" src="searchDialog.js"/>
-
-<popupset>
-	<popup id="fieldpopup"/>
-</popupset>
-
-<grid flex="1" style="margin:10px">
-  <columns>
-    <column flex="1"/>
-  </columns>
-  <rows>
-    <row>
-			<hbox>
-				<spacer flex="1"/>
-				<label value="Enter search terms:"/>
-				<spacer flex="1"/>
-			</hbox>
-		</row>
-		<row>
-			<textbox id="field"
-				maxrows="14"
-				width="200px"
-				autocompletepopup="fieldpopup"
-				inputtooltiptext="Enter search terms"
-				ontextentered="handle_field_textentered()"
-				ontextreverted="handle_field_textreverted()"
-				onkeyup="handle_field_keyup(event)"
-				onfocus="handle_field_focus()"
-				onclick="field_click_kludge('click')"
-				onblur="field_click_kludge('blur')"
-				reflectpopuplabel="true"
-				sizetopopup="none"
-				maxLength="150"/>
-		</row>
-	</rows>
-</grid>
-
-</dialog>
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://stumbleupon/skin/searchDialog.css" type="text/css"?>
+
+<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
+
+<dialog id="stumble_search_dialog" title="StumbleUpon Search"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+  buttons="accept,cancel"
+  persist="screenX screenY width height"
+  ondialogaccept="return doOK();"
+  onload="init()">
+
+<stringbundleset id="stringbundleset">
+	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
+</stringbundleset>
+
+<script type="application/x-javascript" src="searchDialog.js"/>
+
+<popupset>
+	<popup id="fieldpopup"/>
+</popupset>
+
+<grid flex="1" style="margin:10px">
+  <columns>
+    <column flex="1"/>
+  </columns>
+  <rows>
+    <row>
+			<hbox>
+				<spacer flex="1"/>
+				<label value="Enter search terms:"/>
+				<spacer flex="1"/>
+			</hbox>
+		</row>
+		<row>
+			<textbox id="field"
+				maxrows="14"
+				width="200px"
+				autocompletepopup="fieldpopup"
+				inputtooltiptext="Enter search terms"
+				ontextentered="handle_field_textentered()"
+				ontextreverted="handle_field_textreverted()"
+				onkeyup="handle_field_keyup(event)"
+				onfocus="handle_field_focus()"
+				onclick="field_click_kludge('click')"
+				onblur="field_click_kludge('blur')"
+				reflectpopuplabel="true"
+				sizetopopup="none"
+				maxLength="150"/>
+		</row>
+	</rows>
+</grid>
+
+</dialog>
diff --git a/chrome/stumbleupon.jar!/content/searchlinksDialog.xul b/content/searchlinksDialog.xul
similarity index 87%
rename from chrome/stumbleupon.jar!/content/searchlinksDialog.xul
rename to content/searchlinksDialog.xul
index b33af3d..ffb6eed 100644
--- a/chrome/stumbleupon.jar!/content/searchlinksDialog.xul
+++ b/content/searchlinksDialog.xul
@@ -1,70 +1,70 @@
-<?xml version="1.0"?>
-
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-
-<window id="stumble_searchlinks_dialog" title="StumbleUpon Search Reviews"
-  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-  onload="init();"
-	onunload="handle_window_unload();"
-	style="background-color:white;">
-
-<script type="application/x-javascript">
-<![CDATA[
-
-var detail;
-
-function init()
-{
-	detail = window.arguments[0];
-	
-	detail.result = "cancel-error";
-
-	var prompt = document.getElementById("prompt");
-
-	prompt.setAttribute("src", detail.prompt_src);
-	
-	setTimeout(resize, 10);
-}
-
-function resize()
-{
-	window.sizeToContent();
-}
-
-function handle_button_click(value)
-{
-	detail.result = value;
-	setTimeout(close, 0);
-}
-
-function handle_window_unload()
-{
-	opener.setTimeout(function (parent, detail) { parent.su_handle_searchlinks_dialog_close(detail); }, 0, opener, detail);
-}
-
-]]>
-</script>
-<spacer height="10px" style="background-color: white;"/>
-<image id="prompt"/>
-<spacer height="10px" style="background-color: white;"/>
-<hbox style="background-color: white;">
-	<spacer width="255px"/>
-	<image id="button-yes"
-		style="cursor:pointer;"
-		src="chrome://stumbleupon/content/skin/btn_turniton.gif"
-		onclick="handle_button_click('yes');"/>
-	<spacer flex="1"/>
-	<vbox>
-		<spacer flex="1"/>
-		<label id="button-no"
-			value="No thanks"
-			style="color:rgb(84,164,222);cursor:pointer;"
-			onclick="handle_button_click('no');"/>
-		<spacer flex="1"/>
-	</vbox>
-	<spacer width="15px"/>
-</hbox>
-<spacer 
-	style="background-color:white;"
-	height="20px"/>
-</window>
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window id="stumble_searchlinks_dialog" title="StumbleUpon Search Reviews"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+  onload="init();"
+	onunload="handle_window_unload();"
+	style="background-color:white;">
+
+<script type="application/x-javascript">
+<![CDATA[
+
+var detail;
+
+function init()
+{
+	detail = window.arguments[0];
+	
+	detail.result = "cancel-error";
+
+	var prompt = document.getElementById("prompt");
+
+	prompt.setAttribute("src", detail.prompt_src);
+	
+	setTimeout(resize, 10);
+}
+
+function resize()
+{
+	window.sizeToContent();
+}
+
+function handle_button_click(value)
+{
+	detail.result = value;
+	setTimeout(close, 0);
+}
+
+function handle_window_unload()
+{
+	opener.setTimeout(function (parent, detail) { parent.StumbleGlobals.handle_searchlinks_dialog_close(detail); }, 0, opener, detail);
+}
+
+]]>
+</script>
+<spacer height="10px" style="background-color: white;"/>
+<image id="prompt"/>
+<spacer height="10px" style="background-color: white;"/>
+<hbox style="background-color: white;">
+	<spacer width="255px"/>
+	<image id="button-yes"
+		style="cursor:pointer;"
+		src="chrome://stumbleupon/content/skin/btn_turniton.gif"
+		onclick="handle_button_click('yes');"/>
+	<spacer flex="1"/>
+	<vbox>
+		<spacer flex="1"/>
+		<label id="button-no"
+			value="No thanks"
+			style="color:rgb(84,164,222);cursor:pointer;"
+			onclick="handle_button_click('no');"/>
+		<spacer flex="1"/>
+	</vbox>
+	<spacer width="15px"/>
+</hbox>
+<spacer 
+	style="background-color:white;"
+	height="20px"/>
+</window>
diff --git a/chrome/stumbleupon.jar!/content/sendDialog.xul b/content/sendDialog.xul
similarity index 61%
rename from chrome/stumbleupon.jar!/content/sendDialog.xul
rename to content/sendDialog.xul
index ff396a3..3ba3d02 100644
--- a/chrome/stumbleupon.jar!/content/sendDialog.xul
+++ b/content/sendDialog.xul
@@ -1,97 +1,137 @@
-<?xml version="1.0"?>
-
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-
-<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
-
-<dialog id="stumble_send_dialog"
-	xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-	title="StumbleUpon Send"
-	buttons="accept,cancel"
-	ondialogaccept="return handle_accept();"
-  ondialogcancel="return handle_cancel();"
-	onload="init()">
-
-<stringbundleset id="stringbundleset">
-	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
-</stringbundleset>
-
-<script type="application/x-javascript">
-<![CDATA[
-
-var detail;
-var textbox;
-
-detail = window.arguments[0];
-document.getElementById("stumble_send_dialog").setAttribute("title", detail.dialog_title);
-
-function init()
-{
-	// Creating elements programatically works around a Firefox bug
-	// related to setting the title attribute (ref: Firefox 1.5, XP).
-	// -- JW
-
-	var dialog = document.getElementById("stumble_send_dialog");
-	dialog.getButton("accept").label = "Send";
-	
-	var grid = document.createElement("grid");
-	dialog.appendChild(grid);
-	var columns = document.createElement("columns");
-	grid.appendChild(columns);
-	var el;
-	el = document.createElement("column");
-	columns.appendChild(el);
-	el = document.createElement("column");
-	columns.appendChild(el);
-	var rows = document.createElement("rows");
-	grid.appendChild(rows);
-	var row;
-	if (detail.show_target)
-	{
-		row = document.createElement("row");
-		rows.appendChild(row);
-		el = document.createElement("label");
-		el.setAttribute("value", "To:");
-		el.setAttribute("style", "font-weight: bold; text-align: right;");
-		row.appendChild(el);
-		el = document.createElement("label");
-		el.setAttribute("value", detail.target);
-		row.appendChild(el);
-	}
-	row = document.createElement("row");
-	rows.appendChild(row);
-	el = document.createElement("label");
-	el.setAttribute("value", "Subject:");
-	el.setAttribute("style", "font-weight: bold;");
-	row.appendChild(el);
-	var display_url = detail.display_url;
-	if (display_url.length > 50)
-	{
-		display_url = display_url.substr(0, 50) + "...";
-	}
-	el = document.createElement("label");
-	el.setAttribute("value", display_url);
-	row.appendChild(el);
-
-	textbox = document.createElement("textbox");
-	textbox.setAttribute("id", "message");
-	textbox.setAttribute("multiline", "false");
-	textbox.setAttribute("style", "width: 300px;");
-	
-	dialog.appendChild(textbox);
-}
-
-function handle_accept()
-{
-	detail.message = textbox.value;
-	opener.setTimeout(function (parent, detail) { parent.su_handle_send_dialog_accept(detail); }, 0, opener, detail);
-}
-
-function handle_cancel()
-{
-	opener.setTimeout(function (parent) { parent.su_invoke_global_event("refresh-referral-menu", null); }, 0, opener);
-}
-
- ]]>
-</script>
-</dialog>
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
+
+<dialog id="stumble_send_dialog"
+	xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+	title="StumbleUpon Send"
+	buttons="accept,cancel"
+	ondialogaccept="return handle_accept();"
+  ondialogcancel="return handle_cancel();"
+	onload="init()">
+
+<stringbundleset id="stringbundleset">
+	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
+</stringbundleset>
+
+<script type="application/x-javascript">
+<![CDATA[
+
+var detail;
+var textbox;
+
+detail = window.arguments[0];
+document.getElementById("stumble_send_dialog").setAttribute("title", detail.dialog_title);
+
+function init()
+{
+	// Creating elements programatically works around a Firefox bug
+	// related to setting the title attribute (ref: Firefox 1.5, XP).
+	// -- JW
+
+	var dialog = document.getElementById("stumble_send_dialog");
+	dialog.getButton("accept").label = "Send";
+	
+	var grid = document.createElement("grid");
+	dialog.appendChild(grid);
+	var columns = document.createElement("columns");
+	grid.appendChild(columns);
+	var el;
+	el = document.createElement("column");
+	columns.appendChild(el);
+	el = document.createElement("column");
+	columns.appendChild(el);
+	var rows = document.createElement("rows");
+	grid.appendChild(rows);
+	var row;
+	if (detail.show_target)
+	{
+		row = document.createElement("row");
+		rows.appendChild(row);
+		el = document.createElement("label");
+		el.setAttribute("value", "To:");
+		el.setAttribute("style", "font-weight: bold; text-align: right;");
+		row.appendChild(el);
+
+		var targets = [];
+		for(var i=0; i<detail.recipients.length; i++)
+			targets.push(detail.recipients[i].target);
+		
+		// Only show 5 recipients and a "more..." option for the others
+		var show_all = (targets.length > 5); 
+		var label = (targets.slice(0,5)).join(", ");
+		
+		// If the label text is still too long, then truncate it
+		if(label.length > 125)
+		{
+			show_all = true;
+			label = label.substr(0, 122);
+		}
+		
+		if(show_all)
+			label += "...";
+			
+		var short_list = document.createElement("label");
+		short_list.setAttribute("value", label);
+		row.appendChild(short_list);
+
+		if(show_all)
+		{
+			var all_targets = targets.join(", ");
+			var more = document.createElement("label");
+			more.setAttribute("value", "see all");
+			more.setAttribute("class", "text-link");
+			more.setAttribute("tabindex", "2");
+			more.setAttribute("onclick", "show_all('" + all_targets + "')");
+			row.appendChild(more);
+		}
+	}
+	
+	row = document.createElement("row");
+	rows.appendChild(row);
+	el = document.createElement("label");
+	el.setAttribute("value", "Subject:");
+	el.setAttribute("style", "font-weight: bold;");
+	row.appendChild(el);
+	var display_url = detail.display_url;
+	if (display_url.length > 50)
+	{
+		display_url = display_url.substr(0, 50) + "...";
+	}
+	el = document.createElement("label");
+	el.setAttribute("value", display_url);
+	row.appendChild(el);
+
+	textbox = document.createElement("textbox");
+	textbox.setAttribute("id", "message");
+	textbox.setAttribute("multiline", "false");
+	textbox.setAttribute("style", "width: 300px;");
+	
+	dialog.appendChild(textbox);
+	textbox.focus();
+}
+
+function show_all(targets)
+{
+	var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
+						.getService(Components.interfaces.nsIPromptService);
+		
+	ps.alert(window, "StumbleUpon", "Send to:  " + targets);
+}
+
+function handle_accept()
+{
+	detail.message = textbox.value;
+	opener.setTimeout(function (parent, detail) { parent.StumbleGlobals.handle_send_dialog_accept(detail); }, 0, opener, detail);
+}
+
+function handle_cancel()
+{
+	opener.setTimeout(function (parent) { parent.StumbleGlobals.invoke_global_event("refresh-referral-menu", null); }, 0, opener);
+}
+
+ ]]>
+</script>
+</dialog>
diff --git a/chrome/stumbleupon.jar!/content/sidebar.js b/content/sidebar.js
similarity index 100%
rename from chrome/stumbleupon.jar!/content/sidebar.js
rename to content/sidebar.js
diff --git a/chrome/stumbleupon.jar!/content/sidebar.xul b/content/sidebar.xul
similarity index 100%
rename from chrome/stumbleupon.jar!/content/sidebar.xul
rename to content/sidebar.xul
diff --git a/chrome/stumbleupon.jar!/content/sidebarOverlay.xul b/content/sidebarOverlay.xul
similarity index 100%
rename from chrome/stumbleupon.jar!/content/sidebarOverlay.xul
rename to content/sidebarOverlay.xul
diff --git a/chrome/stumbleupon.jar!/content/signinDialog.js b/content/signinDialog.js
similarity index 76%
rename from chrome/stumbleupon.jar!/content/signinDialog.js
rename to content/signinDialog.js
index aff19e9..2fb51ea 100644
--- a/chrome/stumbleupon.jar!/content/signinDialog.js
+++ b/content/signinDialog.js
@@ -19,7 +19,7 @@ function init()
 	{
 		// We're not logged in.  See whether we have a previous id.
 
-		id_list = opener.su_ds.getValue("@id_list");
+		id_list = opener.StumbleGlobals.ds.getValue("@id_list");
 		splitids = id_list.split(":");
 
 		for (i = 0; i < splitids.length; i++)
@@ -36,7 +36,7 @@ function init()
 		// We're logged in, so we assume that the user wants to
 		// switch accounts.  See whether we have a previous id.
 		
-		id_list = opener.su_ds.getValue("@id_list", "");
+		id_list = opener.StumbleGlobals.ds.getValue("@id_list", "");
 		splitids = id_list.split(":");
 		var id_count = 0;
 		
@@ -58,7 +58,7 @@ function init()
 		// they already have an account
 
 		// see if we can get nickname
-		var nick = opener.su_ds.getValue("stumble." + id + ".nick", "");
+		var nick = opener.StumbleGlobals.ds.getValue("stumble." + id + ".nick", "");
 
 		if (nick != "")
 			document.getElementById("username").value = nick;
@@ -66,7 +66,7 @@ function init()
 			document.getElementById("username").value = id;
 		document.getElementById("password").focus();
 	}
-	var autologout = opener.su_get_autologout_for_user(document.getElementById("username").value);
+	var autologout = opener.StumbleGlobals.get_autologout_for_user(document.getElementById("username").value);
 	document.getElementById("autologout").checked = autologout;
 }
 
@@ -74,7 +74,7 @@ function forgotPassword()
 {
 	var doc = opener.getBrowser().contentDocument;
 	close();
-	doc.location = opener.su_base_url + "recover_password.php";
+	doc.location = opener.StumbleGlobals.base_url + "recover_password.php";
 }
 
 function doOK()
@@ -84,7 +84,7 @@ function doOK()
 	if (username == null)
 		return true;
 
-	username = opener.su_trim(username).toLowerCase();
+	username = opener.StumbleGlobals.trim(username).toLowerCase();
 	
 	if (username == "")
 	{
@@ -104,19 +104,19 @@ function doOK()
 
 	var res;
 	
-	if (opener.su_enable_hashed_password)
+	if (opener.StumbleGlobals.enable_hashed_password)
 	{
-		res = opener.su_post_url_server_secure(
+		res = opener.StumbleGlobals.post_url_server_secure(
 					"userexists.php",
-					"version=" + opener.su_verstring + 
+					"version=" + opener.StumbleGlobals.verstring + 
 						"&username=" + escape(username) + 
-						"&password=" + opener.su_ds.getEncodedPassword(password, username.toLowerCase()));
+						"&password=" + opener.StumbleGlobals.ds.getEncodedPassword(password, username.toLowerCase()));
 	}
 	else
 	{
-		res = opener.su_post_url_server_secure(
+		res = opener.StumbleGlobals.post_url_server_secure(
 					"userexists.php",
-					"version=" + opener.su_verstring + "&username=" + escape(username) + "&password=" + encodeURIComponent(password));
+					"version=" + opener.StumbleGlobals.verstring + "&username=" + escape(username) + "&password=" + encodeURIComponent(password));
 	}
 	
 	if (res.status == 1)
@@ -135,8 +135,8 @@ function doOK()
 	if (typeof(res.response) != "undefined")
 		s = res.response;
 
-	if (opener.su_log_communication)
-		opener.su_log("response userexists.php", s);
+	if (opener.StumbleGlobals.log_communication)
+		opener.StumbleGlobals.log("response userexists.php", s);
 	
 	var commands = s.split("\n");
 	// Iterate through commands
@@ -164,7 +164,7 @@ function doOK()
 					msg = "An account was not found for '" + username + "'.\n";
 		
 					// we need to clear out that username from the list of usernames
-					var id_list = opener.su_ds.getValue("@id_list");
+					var id_list = opener.StumbleGlobals.ds.getValue("@id_list");
 					var splitids = id_list.split(":");
 					var foundit = 0;
 					var newarray = new Array();
@@ -192,8 +192,8 @@ function doOK()
 							line = newarray[i];
 							id_list += line + ":";	
 						}
-						opener.su_ds.setValue("@id_list", id_list);
-						opener.su_ds.flushPrefs();
+						opener.StumbleGlobals.ds.setValue("@id_list", id_list);
+						opener.StumbleGlobals.ds.flushPrefs();
 					}			
 				}
 				else if (parts[1] == "INCORRECT_PASSWORD")
@@ -227,11 +227,11 @@ function doOK()
 				detail.disableg = parseInt(parts[1]);
 				break;
 			case "SFC":
-				if(opener.su_ds.getValue("@enable_server_counts"))
+				if(opener.StumbleGlobals.ds.getValue("@enable_server_counts"))
 					detail.thumbup_count = parseInt(parts[1]);
 				break;
 			case "SSC":
-				if(opener.su_ds.getValue("@enable_server_counts"))
+				if(opener.StumbleGlobals.ds.getValue("@enable_server_counts"))
 					detail.stumble_count = parseInt(parts[1]);
 				break;
 		}
@@ -241,7 +241,7 @@ function doOK()
 	{
 		detail.password = password;
 		detail.autologout = document.getElementById("autologout").checked;
-		opener.setTimeout(function (parent, detail) { parent.su_handle_signin_dialog_accept(detail); }, 0, opener, detail);
+		opener.setTimeout(function (parent, detail) { parent.StumbleGlobals.handle_signin_dialog_accept(detail); }, 0, opener, detail);
 	}
 	
 	// Other responses fail silently?
@@ -255,7 +255,7 @@ function doCancel()
 
 function handle_username_command(element)
 {
-	var autologout = opener.su_get_autologout_for_user(element.value);
+	var autologout = opener.StumbleGlobals.get_autologout_for_user(element.value);
 	
 	document.getElementById("autologout").checked = autologout;
 }
diff --git a/chrome/stumbleupon.jar!/content/signinDialog.xul b/content/signinDialog.xul
similarity index 96%
rename from chrome/stumbleupon.jar!/content/signinDialog.xul
rename to content/signinDialog.xul
index de81de6..2576a69 100644
--- a/chrome/stumbleupon.jar!/content/signinDialog.xul
+++ b/content/signinDialog.xul
@@ -1,60 +1,60 @@
-<?xml version="1.0"?>
-
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-
-<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
-
-<dialog id="stumble_signin_dialog" title="StumbleUpon Sign-in"
-  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-  buttons="accept,cancel,extra1"
-  ondialogaccept="return doOK();"
-  ondialogcancel="return doCancel();"
-  onload="init()">
-
-<stringbundleset id="stringbundleset">
-	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
-</stringbundleset>
-
-<script type="application/x-javascript" src="signinDialog.js"/>
-
-<spacer height="10px"/>
-<grid flex="1">
-  <columns>
-    <column flex="2"/>
-    <column flex="1"/>
-  </columns>
-
-  <rows>
-    <row>
-    <vbox align="right">
-    		<spacer flex="1"/>
-			<label control="username" value="Nickname, E-mail or ID:"/>
-			<spacer flex="1"/>
-    </vbox>
-    <textbox id="username"
-			type="timed"
-			timeout="20"
-			maxlength="64"
-			oncommand="handle_username_command(this)"/>
-    </row>
-    <row>
-    <vbox align="right">
-   		<spacer flex="1"/>
-	  		<label control="password" value="Password:"/>
-				<spacer flex="1"/>
-	  </vbox>
-    <textbox id="password"
-			type="password"
-			maxlength="16"/>
-    </row>
-  </rows>
-</grid>
-<spacer height="5px"/>
-<hbox>
-	<spacer flex="1"/>
-	<checkbox id="autologout"
-		label="Sign-out when I close the browser"
-		checked="false"/>
-</hbox>
-<spacer height="10px"/>
-</dialog>
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
+
+<dialog id="stumble_signin_dialog" title="StumbleUpon Sign-in"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+  buttons="accept,cancel,extra1"
+  ondialogaccept="return doOK();"
+  ondialogcancel="return doCancel();"
+  onload="init()">
+
+<stringbundleset id="stringbundleset">
+	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
+</stringbundleset>
+
+<script type="application/x-javascript" src="signinDialog.js"/>
+
+<spacer height="10px"/>
+<grid flex="1">
+  <columns>
+    <column flex="2"/>
+    <column flex="1"/>
+  </columns>
+
+  <rows>
+    <row>
+    <vbox align="right">
+    		<spacer flex="1"/>
+			<label control="username" value="Nickname, E-mail or ID:"/>
+			<spacer flex="1"/>
+    </vbox>
+    <textbox id="username"
+			type="timed"
+			timeout="20"
+			maxlength="64"
+			oncommand="handle_username_command(this)"/>
+    </row>
+    <row>
+    <vbox align="right">
+   		<spacer flex="1"/>
+	  		<label control="password" value="Password:"/>
+				<spacer flex="1"/>
+	  </vbox>
+    <textbox id="password"
+			type="password"
+			maxlength="16"/>
+    </row>
+  </rows>
+</grid>
+<spacer height="5px"/>
+<hbox>
+	<spacer flex="1"/>
+	<checkbox id="autologout"
+		label="Sign-out when I close the browser"
+		checked="false"/>
+</hbox>
+<spacer height="10px"/>
+</dialog>
diff --git a/chrome/stumbleupon.jar!/content/signoutDialog.js b/content/signoutDialog.js
similarity index 84%
rename from chrome/stumbleupon.jar!/content/signoutDialog.js
rename to content/signoutDialog.js
index fadbc40..182b782 100644
--- a/chrome/stumbleupon.jar!/content/signoutDialog.js
+++ b/content/signoutDialog.js
@@ -1,33 +1,33 @@
-var detail; 
-
-function init()
-{
-	// get object from parent window
-	detail = window.arguments[0];
-	detail.response = 0;
-	
-	var forgot_button = document.getElementById("stumble_signout_dialog").getButton("extra1");
-	
-	forgot_button.label = "Forgot Password";
-	forgot_button.setAttribute("oncommand", "forgotPassword();");
-}
-
-function forgotPassword()
-{
-	var doc = opener.getBrowser().contentDocument;
-	close();
-	doc.location = opener.su_base_url + "recover_password.php";
-}
-
-function doOK()
-{
-	// Other responses fail silently?
-	detail.response = 1;
-	return true;
-}
-
-function doCancel()
-{
-	detail.response = 0;
-	return true;
-}
+var detail; 
+
+function init()
+{
+	// get object from parent window
+	detail = window.arguments[0];
+	detail.response = 0;
+	
+	var forgot_button = document.getElementById("stumble_signout_dialog").getButton("extra1");
+	
+	forgot_button.label = "Forgot Password";
+	forgot_button.setAttribute("oncommand", "forgotPassword();");
+}
+
+function forgotPassword()
+{
+	var doc = opener.getBrowser().contentDocument;
+	close();
+	doc.location = opener.StumbleGlobals.base_url + "recover_password.php";
+}
+
+function doOK()
+{
+	// Other responses fail silently?
+	detail.response = 1;
+	return true;
+}
+
+function doCancel()
+{
+	detail.response = 0;
+	return true;
+}
diff --git a/chrome/stumbleupon.jar!/content/signoutDialog.xul b/content/signoutDialog.xul
similarity index 100%
rename from chrome/stumbleupon.jar!/content/signoutDialog.xul
rename to content/signoutDialog.xul
diff --git a/chrome/stumbleupon.jar!/content/skin/ChangePassword.png b/content/skin/ChangePassword.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/ChangePassword.png
rename to content/skin/ChangePassword.png
diff --git a/chrome/stumbleupon.jar!/content/skin/Throbber-small.gif b/content/skin/Throbber-small.gif
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/Throbber-small.gif
rename to content/skin/Throbber-small.gif
diff --git a/chrome/stumbleupon.jar!/content/skin/Throbber-small.png b/content/skin/Throbber-small.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/Throbber-small.png
rename to content/skin/Throbber-small.png
diff --git a/content/skin/aaaa.gif b/content/skin/aaaa.gif
new file mode 100644
index 0000000..9510c3a
Binary files /dev/null and b/content/skin/aaaa.gif differ
diff --git a/chrome/stumbleupon.jar!/content/skin/all.png b/content/skin/all.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/all.png
rename to content/skin/all.png
diff --git a/chrome/stumbleupon.jar!/content/skin/arrow.png b/content/skin/arrow.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/arrow.png
rename to content/skin/arrow.png
diff --git a/chrome/stumbleupon.jar!/content/skin/arrow_ani4-a.png b/content/skin/arrow_ani4-a.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/arrow_ani4-a.png
rename to content/skin/arrow_ani4-a.png
diff --git a/content/skin/arrow_ani4.png b/content/skin/arrow_ani4.png
new file mode 100644
index 0000000..a4d1d5c
Binary files /dev/null and b/content/skin/arrow_ani4.png differ
diff --git a/chrome/stumbleupon.jar!/content/skin/arrow_green-b.png b/content/skin/arrow_green-b.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/arrow_green-b.png
rename to content/skin/arrow_green-b.png
diff --git a/chrome/stumbleupon.jar!/content/skin/arrow_green-c.png b/content/skin/arrow_green-c.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/arrow_green-c.png
rename to content/skin/arrow_green-c.png
diff --git a/chrome/stumbleupon.jar!/content/skin/btn_turniton.gif b/content/skin/btn_turniton.gif
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/btn_turniton.gif
rename to content/skin/btn_turniton.gif
diff --git a/chrome/stumbleupon.jar!/content/skin/bubble.png b/content/skin/bubble.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/bubble.png
rename to content/skin/bubble.png
diff --git a/chrome/stumbleupon.jar!/content/skin/bubble1.png b/content/skin/bubble1.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/bubble1.png
rename to content/skin/bubble1.png
diff --git a/chrome/stumbleupon.jar!/content/skin/bubble2.png b/content/skin/bubble2.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/bubble2.png
rename to content/skin/bubble2.png
diff --git a/chrome/stumbleupon.jar!/content/skin/bubble3.png b/content/skin/bubble3.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/bubble3.png
rename to content/skin/bubble3.png
diff --git a/chrome/stumbleupon.jar!/content/skin/bubblex.png b/content/skin/bubblex.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/bubblex.png
rename to content/skin/bubblex.png
diff --git a/chrome/stumbleupon.jar!/content/skin/bug.png b/content/skin/bug.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/bug.png
rename to content/skin/bug.png
diff --git a/chrome/stumbleupon.jar!/content/skin/chevron.png b/content/skin/chevron.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/chevron.png
rename to content/skin/chevron.png
diff --git a/chrome/stumbleupon.jar!/content/skin/close-c.png b/content/skin/close-c.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/close-c.png
rename to content/skin/close-c.png
diff --git a/chrome/stumbleupon.jar!/content/skin/close-d.png b/content/skin/close-d.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/close-d.png
rename to content/skin/close-d.png
diff --git a/chrome/stumbleupon.jar!/content/skin/close.png b/content/skin/close.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/close.png
rename to content/skin/close.png
diff --git a/chrome/stumbleupon.jar!/content/skin/closetab-active.png b/content/skin/closetab-active.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/closetab-active.png
rename to content/skin/closetab-active.png
diff --git a/chrome/stumbleupon.jar!/content/skin/closetab-hover.png b/content/skin/closetab-hover.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/closetab-hover.png
rename to content/skin/closetab-hover.png
diff --git a/chrome/stumbleupon.jar!/content/skin/closetab.png b/content/skin/closetab.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/closetab.png
rename to content/skin/closetab.png
diff --git a/chrome/stumbleupon.jar!/content/skin/comment.png b/content/skin/comment.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/comment.png
rename to content/skin/comment.png
diff --git a/chrome/stumbleupon.jar!/content/skin/contents.rdf b/content/skin/contents.rdf
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/contents.rdf
rename to content/skin/contents.rdf
diff --git a/chrome/stumbleupon.jar!/content/skin/domain.png b/content/skin/domain.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/domain.png
rename to content/skin/domain.png
diff --git a/chrome/stumbleupon.jar!/content/skin/editinfo.png b/content/skin/editinfo.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/editinfo.png
rename to content/skin/editinfo.png
diff --git a/chrome/stumbleupon.jar!/content/skin/facebook_share_icon.gif b/content/skin/facebook_share_icon.gif
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/facebook_share_icon.gif
rename to content/skin/facebook_share_icon.gif
diff --git a/chrome/stumbleupon.jar!/content/skin/favicon_aol.png b/content/skin/favicon_aol.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/favicon_aol.png
rename to content/skin/favicon_aol.png
diff --git a/chrome/stumbleupon.jar!/content/skin/favicon_ask.png b/content/skin/favicon_ask.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/favicon_ask.png
rename to content/skin/favicon_ask.png
diff --git a/content/skin/favicon_facebook.gif b/content/skin/favicon_facebook.gif
new file mode 100644
index 0000000..29869a9
Binary files /dev/null and b/content/skin/favicon_facebook.gif differ
diff --git a/chrome/stumbleupon.jar!/content/skin/favicon_flickr.png b/content/skin/favicon_flickr.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/favicon_flickr.png
rename to content/skin/favicon_flickr.png
diff --git a/chrome/stumbleupon.jar!/content/skin/favicon_google.png b/content/skin/favicon_google.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/favicon_google.png
rename to content/skin/favicon_google.png
diff --git a/chrome/stumbleupon.jar!/content/skin/favicon_mslive.png b/content/skin/favicon_mslive.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/favicon_mslive.png
rename to content/skin/favicon_mslive.png
diff --git a/chrome/stumbleupon.jar!/content/skin/favicon_twitter.gif b/content/skin/favicon_twitter.gif
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/favicon_twitter.gif
rename to content/skin/favicon_twitter.gif
diff --git a/chrome/stumbleupon.jar!/content/skin/favicon_yahoo.png b/content/skin/favicon_yahoo.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/favicon_yahoo.png
rename to content/skin/favicon_yahoo.png
diff --git a/chrome/stumbleupon.jar!/content/skin/favicon_youtube.png b/content/skin/favicon_youtube.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/favicon_youtube.png
rename to content/skin/favicon_youtube.png
diff --git a/chrome/stumbleupon.jar!/content/skin/firstrater.png b/content/skin/firstrater.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/firstrater.png
rename to content/skin/firstrater.png
diff --git a/chrome/stumbleupon.jar!/content/skin/forum.png b/content/skin/forum.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/forum.png
rename to content/skin/forum.png
diff --git a/chrome/stumbleupon.jar!/content/skin/friend.png b/content/skin/friend.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/friend.png
rename to content/skin/friend.png
diff --git a/chrome/stumbleupon.jar!/content/skin/g.png b/content/skin/g.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/g.png
rename to content/skin/g.png
diff --git a/chrome/stumbleupon.jar!/content/skin/greenthumbdown.png b/content/skin/greenthumbdown.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/greenthumbdown.png
rename to content/skin/greenthumbdown.png
diff --git a/chrome/stumbleupon.jar!/content/skin/greenthumbup.png b/content/skin/greenthumbup.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/greenthumbup.png
rename to content/skin/greenthumbup.png
diff --git a/chrome/stumbleupon.jar!/content/skin/greyman.png b/content/skin/greyman.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/greyman.png
rename to content/skin/greyman.png
diff --git a/chrome/stumbleupon.jar!/content/skin/groups.png b/content/skin/groups.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/groups.png
rename to content/skin/groups.png
diff --git a/chrome/stumbleupon.jar!/content/skin/icon_signin.png b/content/skin/icon_signin.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/icon_signin.png
rename to content/skin/icon_signin.png
diff --git a/chrome/stumbleupon.jar!/content/skin/icon_tb_favorites_hover.png b/content/skin/icon_tb_favorites_hover.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/icon_tb_favorites_hover.png
rename to content/skin/icon_tb_favorites_hover.png
diff --git a/chrome/stumbleupon.jar!/content/skin/icon_tb_flag_blue.png b/content/skin/icon_tb_flag_blue.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/icon_tb_flag_blue.png
rename to content/skin/icon_tb_flag_blue.png
diff --git a/chrome/stumbleupon.jar!/content/skin/icon_tb_news.png b/content/skin/icon_tb_news.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/icon_tb_news.png
rename to content/skin/icon_tb_news.png
diff --git a/chrome/stumbleupon.jar!/content/skin/icon_tb_people.png b/content/skin/icon_tb_people.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/icon_tb_people.png
rename to content/skin/icon_tb_people.png
diff --git a/chrome/stumbleupon.jar!/content/skin/icon_tb_photo_hover.png b/content/skin/icon_tb_photo_hover.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/icon_tb_photo_hover.png
rename to content/skin/icon_tb_photo_hover.png
diff --git a/chrome/stumbleupon.jar!/content/skin/icon_tb_search_user.png b/content/skin/icon_tb_search_user.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/icon_tb_search_user.png
rename to content/skin/icon_tb_search_user.png
diff --git a/content/skin/icon_tb_share.png b/content/skin/icon_tb_share.png
new file mode 100644
index 0000000..33e22dd
Binary files /dev/null and b/content/skin/icon_tb_share.png differ
diff --git a/chrome/stumbleupon.jar!/content/skin/icon_tb_share2.png b/content/skin/icon_tb_share2.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/icon_tb_share2.png
rename to content/skin/icon_tb_share2.png
diff --git a/chrome/stumbleupon.jar!/content/skin/icon_tb_tag_left.png b/content/skin/icon_tb_tag_left.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/icon_tb_tag_left.png
rename to content/skin/icon_tb_tag_left.png
diff --git a/chrome/stumbleupon.jar!/content/skin/icon_tb_user_comment.png b/content/skin/icon_tb_user_comment.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/icon_tb_user_comment.png
rename to content/skin/icon_tb_user_comment.png
diff --git a/content/skin/logo24.png b/content/skin/logo24.png
new file mode 100644
index 0000000..c08c247
Binary files /dev/null and b/content/skin/logo24.png differ
diff --git a/chrome/stumbleupon.jar!/content/skin/logo32.png b/content/skin/logo32.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/logo32.png
rename to content/skin/logo32.png
diff --git a/chrome/stumbleupon.jar!/content/skin/mail.png b/content/skin/mail.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/mail.png
rename to content/skin/mail.png
diff --git a/chrome/stumbleupon.jar!/content/skin/mail2.png b/content/skin/mail2.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/mail2.png
rename to content/skin/mail2.png
diff --git a/chrome/stumbleupon.jar!/content/skin/mutual_favorites.png b/content/skin/mutual_favorites.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/mutual_favorites.png
rename to content/skin/mutual_favorites.png
diff --git a/chrome/stumbleupon.jar!/content/skin/point3.gif b/content/skin/point3.gif
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/point3.gif
rename to content/skin/point3.gif
diff --git a/chrome/stumbleupon.jar!/content/skin/preferenceDialog.css b/content/skin/preferenceDialog.css
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/preferenceDialog.css
rename to content/skin/preferenceDialog.css
diff --git a/chrome/stumbleupon.jar!/content/skin/profile.png b/content/skin/profile.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/profile.png
rename to content/skin/profile.png
diff --git a/chrome/stumbleupon.jar!/content/skin/r.png b/content/skin/r.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/r.png
rename to content/skin/r.png
diff --git a/chrome/stumbleupon.jar!/content/skin/ratingDialog.css b/content/skin/ratingDialog.css
similarity index 63%
rename from chrome/stumbleupon.jar!/content/skin/ratingDialog.css
rename to content/skin/ratingDialog.css
index 4b8ee97..6f2d0ed 100644
--- a/chrome/stumbleupon.jar!/content/skin/ratingDialog.css
+++ b/content/skin/ratingDialog.css
@@ -1,21 +1,21 @@
-#tags {
-	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#su_autocomplete');
-	background-color: transparent;
-	margin: 2px 3px;
-}
-
-#tagspopup {
-	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#su_autocompletepopup');
-	background-color: -moz-field !important;
-}
-
-/* Apparently, more complicated selectors aren't necessarily evaluated
-   when a DOM node is added to the tree. (ref: Firefox 1.5) -- JW */
-.su_macpopup {
-	font-size: 11px;
-	min-height: 17px;
-}
-
-#tags .textbox-input-box {
-	-moz-binding: url('chrome://global/content/bindings/textbox.xml#input-box');
+#tags {
+	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#stumbleglobals_autocomplete');
+	background-color: transparent;
+	margin: 2px 3px;
+}
+
+#tagspopup {
+	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#stumbleglobals_autocompletepopup');
+	background-color: -moz-field !important;
+}
+
+/* Apparently, more complicated selectors aren't necessarily evaluated
+   when a DOM node is added to the tree. (ref: Firefox 1.5) -- JW */
+.stumbleglobals_macpopup {
+	font-size: 11px;
+	min-height: 17px;
+}
+
+#tags .textbox-input-box {
+	-moz-binding: url('chrome://global/content/bindings/textbox.xml#input-box');
 }
\ No newline at end of file
diff --git a/chrome/stumbleupon.jar!/content/skin/redman.png b/content/skin/redman.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/redman.png
rename to content/skin/redman.png
diff --git a/chrome/stumbleupon.jar!/content/skin/search.png b/content/skin/search.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/search.png
rename to content/skin/search.png
diff --git a/chrome/stumbleupon.jar!/content/skin/searchDialog.css b/content/skin/searchDialog.css
similarity index 63%
rename from chrome/stumbleupon.jar!/content/skin/searchDialog.css
rename to content/skin/searchDialog.css
index a667651..edcd563 100644
--- a/chrome/stumbleupon.jar!/content/skin/searchDialog.css
+++ b/content/skin/searchDialog.css
@@ -1,21 +1,21 @@
-#field {
-	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#su_autocomplete');
-	background-color: transparent;
-	margin: 2px 3px;
-}
-
-#fieldpopup {
-	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#su_autocompletepopup');
-	background-color: -moz-field !important;
-}
-
-/* Apparently, more complicated selectors aren't necessarily evaluated
-   when a DOM node is added to the tree. (ref: Firefox 1.5) -- JW */
-.su_macpopup {
-	font-size: 11px;
-	min-height: 17px;
-}
-
-#field .textbox-input-box {
-	-moz-binding: url('chrome://global/content/bindings/textbox.xml#input-box');
+#field {
+	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#stumbleglobals_autocomplete');
+	background-color: transparent;
+	margin: 2px 3px;
+}
+
+#fieldpopup {
+	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#stumbleglobals_autocompletepopup');
+	background-color: -moz-field !important;
+}
+
+/* Apparently, more complicated selectors aren't necessarily evaluated
+   when a DOM node is added to the tree. (ref: Firefox 1.5) -- JW */
+.stumbleglobals_macpopup {
+	font-size: 11px;
+	min-height: 17px;
+}
+
+#field .textbox-input-box {
+	-moz-binding: url('chrome://global/content/bindings/textbox.xml#input-box');
 }
\ No newline at end of file
diff --git a/chrome/stumbleupon.jar!/content/skin/smallbubble1.png b/content/skin/smallbubble1.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/smallbubble1.png
rename to content/skin/smallbubble1.png
diff --git a/chrome/stumbleupon.jar!/content/skin/smallbubble2.png b/content/skin/smallbubble2.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/smallbubble2.png
rename to content/skin/smallbubble2.png
diff --git a/chrome/stumbleupon.jar!/content/skin/smallbubble3.png b/content/skin/smallbubble3.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/smallbubble3.png
rename to content/skin/smallbubble3.png
diff --git a/chrome/stumbleupon.jar!/content/skin/smallgreenthumbup.png b/content/skin/smallgreenthumbup.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/smallgreenthumbup.png
rename to content/skin/smallgreenthumbup.png
diff --git a/chrome/stumbleupon.jar!/content/skin/smallgreythumbup.png b/content/skin/smallgreythumbup.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/smallgreythumbup.png
rename to content/skin/smallgreythumbup.png
diff --git a/chrome/stumbleupon.jar!/content/skin/smallredman.png b/content/skin/smallredman.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/smallredman.png
rename to content/skin/smallredman.png
diff --git a/chrome/stumbleupon.jar!/content/skin/smallstumble.png b/content/skin/smallstumble.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/smallstumble.png
rename to content/skin/smallstumble.png
diff --git a/chrome/stumbleupon.jar!/content/skin/splitter.png b/content/skin/splitter.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/splitter.png
rename to content/skin/splitter.png
diff --git a/content/skin/sponsor.png b/content/skin/sponsor.png
new file mode 100644
index 0000000..fcf095b
Binary files /dev/null and b/content/skin/sponsor.png differ
diff --git a/content/skin/sponsor_mac.png b/content/skin/sponsor_mac.png
new file mode 100644
index 0000000..c7c4eaf
Binary files /dev/null and b/content/skin/sponsor_mac.png differ
diff --git a/chrome/stumbleupon.jar!/content/skin/star.png b/content/skin/star.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/star.png
rename to content/skin/star.png
diff --git a/chrome/stumbleupon.jar!/content/skin/stopa.png b/content/skin/stopa.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/stopa.png
rename to content/skin/stopa.png
diff --git a/chrome/stumbleupon.jar!/content/skin/stumble.png b/content/skin/stumble.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/stumble.png
rename to content/skin/stumble.png
diff --git a/chrome/stumbleupon.jar!/content/skin/stumble2.png b/content/skin/stumble2.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/stumble2.png
rename to content/skin/stumble2.png
diff --git a/chrome/stumbleupon.jar!/content/skin/stumbler_favorites.png b/content/skin/stumbler_favorites.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/stumbler_favorites.png
rename to content/skin/stumbler_favorites.png
diff --git a/chrome/stumbleupon.jar!/content/skin/stumblers.png b/content/skin/stumblers.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/stumblers.png
rename to content/skin/stumblers.png
diff --git a/chrome/stumbleupon.jar!/content/skin/stumbleuponOverlay.css b/content/skin/stumbleuponOverlay.css
similarity index 55%
rename from chrome/stumbleupon.jar!/content/skin/stumbleuponOverlay.css
rename to content/skin/stumbleuponOverlay.css
index 82d4079..4b096e1 100644
--- a/chrome/stumbleupon.jar!/content/skin/stumbleuponOverlay.css
+++ b/content/skin/stumbleuponOverlay.css
@@ -3,30 +3,30 @@
 .topic-selector {
 }
 
-.su_toolbar-customize {
+.stumbleglobals_toolbar-customize {
 	display: none;
 	max-width: 15em !important;
 }
 
-.su_toolbar-palette {
+.stumbleglobals_toolbar-palette {
 	display: none;
 	max-width: 15em !important;
 }
 
-toolbarpaletteitem[place="palette"] .su_toolbar-palette {
+toolbarpaletteitem[place="palette"] .stumbleglobals_toolbar-palette {
 	display: -moz-box;
 	-moz-box-orient: vertical;
 }
 
-toolbarpaletteitem[place="toolbar"] .su_toolbar-customize {
+toolbarpaletteitem[place="toolbar"] .stumbleglobals_toolbar-customize {
 	display: -moz-box;
 }
 
-toolbarpaletteitem[place="toolbar"] .su_toolbar-container {
+toolbarpaletteitem[place="toolbar"] .stumbleglobals_toolbar-container {
 	visibility: hidden;
 }
 
-toolbarpaletteitem[place="toolbar"] .su_toolbar-palette {
+toolbarpaletteitem[place="toolbar"] .stumbleglobals_toolbar-palette {
 	display: none;
 }
 
@@ -58,6 +58,13 @@ toolbarpaletteitem[place="toolbar"] .su_toolbar-palette {
   text-align: left;
 }
 
+.su-selected-category {
+	-moz-appearance: none !important;
+	font-weight:bold;
+	color:White;
+	background-color:#5A5A5A;
+}
+
 .su-showtext-menuified > .toolbarbutton-text {
   display: -moz-box !important;
   padding-left: 3px;
@@ -74,7 +81,73 @@ toolbarpaletteitem[place="toolbar"] .su_toolbar-palette {
 }
 
 .su-iconic-referral {
-	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#su_menuitem-iconic');
+	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#stumbleglobals_menuitem-iconic');
+}
+
+.su-toggle-button {
+	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#su-toggle-button');
+}
+
+.su-toggle-button spring {
+	width:21px;
+}
+
+.su-toggle-button[badge] hbox vbox {
+	width:14px;
+	height:14px;
+}
+
+.su-toggle-button[badge] hbox vbox label {
+	padding:1px;
+}
+
+.su-toggle-badge {
+	font-size:11px;
+	color:white;
+	background-color:#FC6d25;
+	-moz-border-radius:1em;
+	margin:0px 0px 0px 0px;
+	padding:0px;
+	text-align:center;
+}
+
+.su-referral-popup {
+	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#stumbleglobals_referral-popup');
+}
+
+.su-referral-popup-topdeck {
+	margin-top:10px;
+}
+
+.su-referral-menuitem {
+	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#stumbleglobals_referral-menuitem') !important;
+	margin-bottom:3px;
+}
+
+.su-referral-menuitem label {
+	font:-moz-pull-down-menu;
+}
+
+/* We remove the border because it createds a distracting little box when there is no label
+   The default style that causes the problem:
+	border:1px dotted ThreeDDarkShadow;
+*/ 
+
+.su-referral-menuitem checkbox .checkbox-label-box {
+	display:none;
+}
+
+.su-referral-menuitem checkbox:focus .checkbox-label-box {
+	border-style:none !important;
+}
+
+#stumbleglobals_referral_send_container {
+	font-size:16px;
+	margin-bottom:12px;
+}
+
+#stumbleglobals_referral_send_button {
+	width:170px;
 }
 
 .su-iconic-referral > .menu-iconic-left {
@@ -106,39 +179,39 @@ toolbarpaletteitem[place="toolbar"] .su_toolbar-palette {
 	height: 100%;
 }
 
-#su_stumble {
-	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#su_toolbarbutton');
+#stumbleglobals_stumble {
+	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#stumbleglobals_toolbarbutton');
 	margin-left: 2px;
 	margin-right: 2px;
 }
 
-#su_thumbup {
+#stumbleglobals_thumbup {
 	list-style-image:url("chrome://stumbleupon/content/skin/thumbup.png");
 }
 
-#su_thumbup[mode="thumbup"] {
+#stumbleglobals_thumbup[mode="thumbup"] {
 	list-style-image:url("chrome://stumbleupon/content/skin/greenthumbup.png");
 }
 
-#su_thumbup[mode="thumbdown"] {
+#stumbleglobals_thumbup[mode="thumbdown"] {
 }
 
-#su_thumbdown {
+#stumbleglobals_thumbdown {
 	padding-top:3px;
 	padding-bottom:0;
 	list-style-image:url("chrome://stumbleupon/content/skin/thumbdown.png");
 }
 
-#su_thumbdown[mode="thumbdown"] {
+#stumbleglobals_thumbdown[mode="thumbdown"] {
 	list-style-image:url("chrome://stumbleupon/content/skin/greenthumbdown.png");
 }
 
-#su_thumbdown[mac="true"] > .toolbarbutton-menubutton-button {
+#stumbleglobals_thumbdown[mac="true"] > .toolbarbutton-menubutton-button {
 	padding-top:0;
 	padding-bottom:0;
 }
 
-#su_referred {
+#stumbleglobals_referred {
   background-color: transparent;
 	font-weight: bold;
 	color: Crimson;
@@ -146,27 +219,27 @@ toolbarpaletteitem[place="toolbar"] .su_toolbar-palette {
   list-style-image: url("chrome://stumbleupon/content/skin/arrow_ani4-a.png");
 }
 
-#su_referred[disabled="true"] {
+#stumbleglobals_referred[disabled="true"] {
 	-moz-image-region: rect(0 32px 16px 16px);
 	color: gray;
   list-style-image: url("chrome://stumbleupon/content/skin/arrow_ani4-a.png");
 }
 
-#su_referred[busy="true"] {
+#stumbleglobals_referred[busy="true"] {
   list-style-image: url("chrome://stumbleupon/content/skin/aaaa.gif");
 }
 
-#su_toggle {
+#stumbleglobals_toggle {
 	-moz-image-region: rect(0 24px 24px 0);
   list-style-image: url("chrome://stumbleupon/skin/logo24.png");
 }
 
-toolbar[iconsize="small"] #su_toggle {
+toolbar[iconsize="small"] #stumbleglobals_toggle {
 	-moz-image-region: rect(0 16px 16px 0);
   list-style-image: url("chrome://stumbleupon/skin/stumble.png");
 }
 
-#su_description {
+#stumbleglobals_description {
   background: white;
   font-size:13px;
   font-family: arial;
@@ -175,7 +248,7 @@ toolbar[iconsize="small"] #su_toggle {
   -moz-box-flex:1;
 }
 
-#su_description2 {
+#stumbleglobals_description2 {
   background: white;
   font-size: 15px;
   font-weight: bold;
@@ -186,32 +259,37 @@ toolbar[iconsize="small"] #su_toggle {
   -moz-box-flex:1;
 }
 
-#su_welcome_box {
+#stumbleglobals_welcome_box {
   background: white;
 }
 
-#su_searchbox {
-	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#su_autocomplete');
+#stumbleglobals_searchbox {
+	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#stumbleglobals_autocomplete');
 	background-color: transparent;
 	margin: 2px 3px;
 }
 
-#su_searchbox[mode="tag"] .textbox-input-box {
+#stumbleglobals_searchbox[mode="tag"] .textbox-input-box {
 	color: #ff3300;
 	background-color: #f3f3f3;
 }
 
-#su_searchbox[mode="prompt"] .textbox-input-box {
+#stumbleglobals_searchbox[mode="prompt"] .textbox-input-box {
 	color: #bbbbbb;
 	background-color: #ffffff;
 }
 
-#su_searchpopup {
-	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#su_autocompletepopup');
+#stumbleglobals_searchpopup {
+	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#stumbleglobals_autocompletepopup');
 	background-color: -moz-field !important;
 }
 
-.su_splitter {
+.stumbleglobals_referral_textbox * {
+	overflow:hidden; /* Make _sure_ we don't get scrollbars */
+	padding: 0px;
+}
+
+.stumbleglobals_splitter {
 	padding: 0;
 	border: none;
 	width: 6px;
@@ -220,17 +298,17 @@ toolbar[iconsize="small"] #su_toggle {
 	background: no-repeat center;
 }
 
-#su_overflow_menu > .toolbarbutton-menu-dropmarker {
+#stumbleglobals_overflow_menu > .toolbarbutton-menu-dropmarker {
 	display: none;
 }
 
 /*  This probably isn't compatible with non-default themes.  I'll 
     add it and test next time I'm having to debug several themes.
 		-- JW
-#su_referral-menu > .toolbarbutton-menu-dropmarker {
+stumbleglobals_referral-menu > .toolbarbutton-menu-dropmarker {
 	margin-left: 3px;
 }
-#su_category > .toolbarbutton-menu-dropmarker {
+stumbleglobals_category > .toolbarbutton-menu-dropmarker {
 	margin-left: 3px;
 }
 #stumble-menu > .toolbarbutton-menu-dropmarker {
@@ -240,76 +318,73 @@ toolbar[iconsize="small"] #su_toggle {
 
 /* Apparently, more complicated selectors aren't necessarily evaluated
    when a DOM node is added to the tree. (ref: Firefox 1.5) -- JW */
-.su_macpopup {
+.stumbleglobals_macpopup {
 	font-size: 11px;
 	min-height: 17px;
 }
 
-.su_winstripe_bannerBox {
+.stumbleglobals_winstripe_bannerBox {
   color: InfoText;
   background-color: InfoBackground;
 }
 
-.su_pinstripe_bannerBox {
+.stumbleglobals_pinstripe_bannerBox {
   color: #0f2c65;
   background-color: #e0e7f9;
   border: 1px solid #a8b8de;
 }
 
-.su_pinstripe_bannerInnerBox {
+.stumbleglobals_pinstripe_bannerInnerBox {
   border: 0 !important;
 }
 
 
-.su_winstripe_bannerMessage {
+.stumbleglobals_winstripe_bannerMessage {
   background-color: InfoBackground;
   color: InfoText;
   -moz-appearance: none;
   border: 0;
 }
 
-.su_pinstripe_bannerMessage {
+.stumbleglobals_pinstripe_bannerMessage {
   color: #0f2c65;
   background-color: #e0e7f9;
   -moz-appearance: none;
   border: 0;
 }
 
-.su_bannerMessageMeasurer {
-	overflow: hidden;
-}
 /*
-.su_bannerText {
+.stumbleglobals_bannerText {
   -moz-margin-start: 5px;
 }
 */
 
-.su_bannerImage {
+.stumbleglobals_bannerImage {
   width: auto;
   height: auto;
   margin: 0px 1px 0px 6px;
 }
 
-.su_pinstripe_messageCloseButton {
+.stumbleglobals_pinstripe_messageCloseButton {
   -moz-appearance: none;
   padding-right: 4px;
   list-style-image: url("chrome://stumbleupon/skin/closetab.png") !important;
   border: none;
 }
 
-.su_pinstripe_messageCloseButton > .toolbarbutton-text {
+.stumbleglobals_pinstripe_messageCloseButton > .toolbarbutton-text {
   display: none;
 }
 
-.su_pinstripe_messageCloseButton:hover {
+.stumbleglobals_pinstripe_messageCloseButton:hover {
   list-style-image: url("chrome://stumbleupon/skin/closetab-hover.png") !important;
 }
 
-.su_pinstripe_messageCloseButton:hover:active {
+.stumbleglobals_pinstripe_messageCloseButton:hover:active {
   list-style-image: url("chrome://stumbleupon/skin/closetab-active.png") !important;
 }
 
-.su_winstripe_messageCloseButton {
+.stumbleglobals_winstripe_messageCloseButton {
   list-style-image: url("chrome://stumbleupon/skin/close.png");
   -moz-appearance: none;
   -moz-image-region: rect(0px, 16px, 16px, 0px);
@@ -317,24 +392,22 @@ toolbar[iconsize="small"] #su_toggle {
   border: none !important;
 }
 
-.su_winstripe_messageCloseButton:hover {
+.stumbleglobals_winstripe_messageCloseButton:hover {
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
-.su_winstripe_messageCloseButton:hover:active {
+.stumbleglobals_winstripe_messageCloseButton:hover:active {
   -moz-image-region: rect(0px, 48px, 16px, 32px);
 }
 
-.su_winstripe_infoMessage {
+.stumbleglobals_winstripe_infoMessage {
   background-color: InfoBackground;
   color: InfoText;
 }
 
-.su_pinstripe_infoMessage {
+.stumbleglobals_pinstripe_infoMessage {
   color: #0f2c65;
   background-color: #e0e7f9;
 }
 
 
-
-
diff --git a/chrome/stumbleupon.jar!/content/skin/tag.png b/content/skin/tag.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/tag.png
rename to content/skin/tag.png
diff --git a/chrome/stumbleupon.jar!/content/skin/tag2.png b/content/skin/tag2.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/tag2.png
rename to content/skin/tag2.png
diff --git a/chrome/stumbleupon.jar!/content/skin/taggingDialog.css b/content/skin/taggingDialog.css
similarity index 63%
rename from chrome/stumbleupon.jar!/content/skin/taggingDialog.css
rename to content/skin/taggingDialog.css
index 4b8ee97..6f2d0ed 100644
--- a/chrome/stumbleupon.jar!/content/skin/taggingDialog.css
+++ b/content/skin/taggingDialog.css
@@ -1,21 +1,21 @@
-#tags {
-	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#su_autocomplete');
-	background-color: transparent;
-	margin: 2px 3px;
-}
-
-#tagspopup {
-	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#su_autocompletepopup');
-	background-color: -moz-field !important;
-}
-
-/* Apparently, more complicated selectors aren't necessarily evaluated
-   when a DOM node is added to the tree. (ref: Firefox 1.5) -- JW */
-.su_macpopup {
-	font-size: 11px;
-	min-height: 17px;
-}
-
-#tags .textbox-input-box {
-	-moz-binding: url('chrome://global/content/bindings/textbox.xml#input-box');
+#tags {
+	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#stumbleglobals_autocomplete');
+	background-color: transparent;
+	margin: 2px 3px;
+}
+
+#tagspopup {
+	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#stumbleglobals_autocompletepopup');
+	background-color: -moz-field !important;
+}
+
+/* Apparently, more complicated selectors aren't necessarily evaluated
+   when a DOM node is added to the tree. (ref: Firefox 1.5) -- JW */
+.stumbleglobals_macpopup {
+	font-size: 11px;
+	min-height: 17px;
+}
+
+#tags .textbox-input-box {
+	-moz-binding: url('chrome://global/content/bindings/textbox.xml#input-box');
 }
\ No newline at end of file
diff --git a/chrome/stumbleupon.jar!/content/skin/tbgrip-texture-12px.png b/content/skin/tbgrip-texture-12px.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/tbgrip-texture-12px.png
rename to content/skin/tbgrip-texture-12px.png
diff --git a/chrome/stumbleupon.jar!/content/skin/thumbdown.png b/content/skin/thumbdown.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/thumbdown.png
rename to content/skin/thumbdown.png
diff --git a/chrome/stumbleupon.jar!/content/skin/thumbup.png b/content/skin/thumbup.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/thumbup.png
rename to content/skin/thumbup.png
diff --git a/chrome/stumbleupon.jar!/content/skin/thumbupcomment.png b/content/skin/thumbupcomment.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/thumbupcomment.png
rename to content/skin/thumbupcomment.png
diff --git a/chrome/stumbleupon.jar!/content/skin/toggle_preview.png b/content/skin/toggle_preview.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/toggle_preview.png
rename to content/skin/toggle_preview.png
diff --git a/chrome/stumbleupon.jar!/content/skin/topic.png b/content/skin/topic.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/topic.png
rename to content/skin/topic.png
diff --git a/chrome/stumbleupon.jar!/content/skin/upgrade.png b/content/skin/upgrade.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/upgrade.png
rename to content/skin/upgrade.png
diff --git a/chrome/stumbleupon.jar!/content/skin/video.png b/content/skin/video.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/video.png
rename to content/skin/video.png
diff --git a/chrome/stumbleupon.jar!/content/skin/widgets.css b/content/skin/widgets.css
similarity index 52%
rename from chrome/stumbleupon.jar!/content/skin/widgets.css
rename to content/skin/widgets.css
index e95f4f4..2e360e8 100644
--- a/chrome/stumbleupon.jar!/content/skin/widgets.css
+++ b/content/skin/widgets.css
@@ -1,14 +1,14 @@
-
- at namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
- at namespace html url("http://www.w3.org/1999/xhtml");
-
-
-hbox.textbox-input-box {
-	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#su_autocompletecontext');
-}
-
-dropmarker.autocomplete-history-dropmarker {
-	display: -moz-box;
-	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#su_autocompletedropmarker');
-}
-
+
+ at namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+ at namespace html url("http://www.w3.org/1999/xhtml");
+
+
+hbox.textbox-input-box {
+	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#stumbleglobals_autocompletecontext');
+}
+
+dropmarker.autocomplete-history-dropmarker {
+	display: -moz-box;
+	-moz-binding: url('chrome://stumbleupon/content/widgets.xml#stumbleglobals_autocompletedropmarker');
+}
+
diff --git a/chrome/stumbleupon.jar!/content/skin/wiki.png b/content/skin/wiki.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/wiki.png
rename to content/skin/wiki.png
diff --git a/chrome/stumbleupon.jar!/content/skin/x.png b/content/skin/x.png
similarity index 100%
rename from chrome/stumbleupon.jar!/content/skin/x.png
rename to content/skin/x.png
diff --git a/chrome/stumbleupon.jar!/content/stumbleReporter.js b/content/stumbleReporter.js
similarity index 85%
rename from chrome/stumbleupon.jar!/content/stumbleReporter.js
rename to content/stumbleReporter.js
index 5f58723..14b7474 100644
--- a/chrome/stumbleupon.jar!/content/stumbleReporter.js
+++ b/content/stumbleReporter.js
@@ -1,10 +1,10 @@
 //
-// su_StumbleReporter
+// StumbleGlobals.StumbleReporter
 //
 // This class encapsulates all of the stumble reporting logic, including storage of stumbled urls and report
 // submission retry logic.
 //
-function su_StumbleReporter(parent)
+StumbleGlobals.StumbleReporter = function(parent)
 {
 	this._parent = parent;
 	this._ds = this._parent.getDatastore();
@@ -15,7 +15,7 @@ function su_StumbleReporter(parent)
 	this._retryCount = 0;
 }
 
-su_StumbleReporter.prototype =
+StumbleGlobals.StumbleReporter.prototype =
 {
 	FAIL_NO_SEENCONF: -1,
 	FAIL_NORMAL_TIMEOUT: -2,
@@ -52,9 +52,8 @@ su_StumbleReporter.prototype =
 	{
 		if (!url.publicid)
 			return;
-
+		
 		// First, see if we have to remove one.
-
 		if (this._enabledb)
 		{
 			var db = this._ds.getDatabase();
@@ -69,7 +68,7 @@ su_StumbleReporter.prototype =
 			db = this._ds.getDatabase();
 			db.a("INSERT INTO stumble_visited_urls (publicid, stumbletime, referralid, retrycount) VALUES (");
 			db.as(url.publicid);
-			db.av(this._parent.callWindow("su_get_time_s"));
+			db.av(this._parent.callWindow("StumbleGlobals.get_time_s"));
 			var referralId = '';
 			if (url.referralid)
 				referralId = url.referralid;
@@ -93,7 +92,7 @@ su_StumbleReporter.prototype =
 			// Insert this visited url into the database.
 			var row = new Object();
 			row.publicid = url.publicid;
-			row.stumbletime = this._parent.callWindow("su_get_time_s");
+			row.stumbletime = this._parent.callWindow("StumbleGlobals.get_time_s");
 			row.referralid = (url.referralid) ? url.referralid : '';
 			row.retrycount = this._retryCount;
 			
@@ -200,7 +199,7 @@ su_StumbleReporter.prototype =
 		{
 			this._ds.setValue("@db_visitedurls_fail", true);
 			this._updateEnableDb();
-			this._parent.callWindow("su_log_error", "DB_VISITEDURLS_FAIL: " + ex);
+			this._parent.callWindow("StumbleGlobals.log_error", "DB_VISITEDURLS_FAIL: " + ex);
 			throw ex;
 		}
 	},
@@ -255,6 +254,40 @@ su_StumbleReporter.prototype =
 			return result[0];
 		}
 	},
+	
+	_getPreviousStumbleInfo: function()
+	{
+		var prev_info = this._ds.getValue("$prev_stumble_stats");
+		
+		if(!prev_info)
+			return null;
+		
+		prev_info = this._ds.deserialize(prev_info);
+		
+		// Translate it from our eventname->timestamp format
+		// into the format expected by the backend.
+		var new_info = {
+			events: []
+		};
+		
+		for(var k in prev_info)
+		{
+			// Public id stays at the top level
+			if(k == "publicid")
+			{
+				new_info.publicid = prev_info[k];
+				continue;
+			}
+			
+			// Otherwise, add a new value to the event array
+			new_info.events.push({
+					event: k,
+					timestamp: prev_info[k]
+			});
+		}
+		
+		return this._ds.serialize(new_info);
+	},
 
 	_reportStumbles: function(active)
 	{
@@ -266,8 +299,8 @@ su_StumbleReporter.prototype =
 			// nothing to do.
 			return;
 		}
+
 		// See if a report is already in progress.
-		
 		if (this._isReportInProgress())
 		{
 			// Someone is still trying to submit, so we won't.
@@ -296,6 +329,12 @@ su_StumbleReporter.prototype =
 		this._ds.setValue("$stumble_report_started", now);
 		this._ds.flushPrefs();
         
+		// Get the previous stumble stats
+		var prev_stumble = this._getPreviousStumbleInfo();
+		
+		// And clear the previous stumble stats
+		this._ds.setValue("$prev_stumble_stats", "");
+		
 		// Now submit the report.
 		var lastFailure = this._ds.getValue("$stumble_report_lastfail");
 		var params = "";
@@ -303,14 +342,21 @@ su_StumbleReporter.prototype =
 		params = this._arp(params, "stumble_time", url.stumbletime);
 		params = this._arp(params, "retry", url.retrycount);
 		params = this._arp(params, "lastfailure", lastFailure);
-		params = this._arp(params, "clienttime", this._parent.callWindow("su_get_time_s"));
+		params = this._arp(params, "clienttime", this._parent.callWindow("StumbleGlobals.get_time_s"));
 		params = this._arp(params, "houroffset", Math.floor((new Date()).getTimezoneOffset() / 60));
 		if (url.referralid && (url.referralId != ''))
 			params = this._arp(params, "stumble_rid", url.referralid);
+
+		if (prev_stumble)
+		{
+			//StumbleGlobals.dd("Stumble stats report:\r\n" + prev_stumble);
+			params = this._arp(params, "stumbleinfo", prev_stumble);
+		}
 		
 		var me = this;
+	
 		this._parent.callWindow(
-				"su_post_url_server_async",
+				"StumbleGlobals.post_url_server_async",
 				"report_stumble.php",
 				params,
 				15000,
@@ -350,11 +396,11 @@ su_StumbleReporter.prototype =
 			strResponse = res.responseText;
 		
 		if (this._parent._logCommunicationEnabled)
-			su_log("response report_stumble.php", strResponse);
+			StumbleGlobals.log("response report_stumble.php", strResponse);
 		
 		// Parse the response, on success it will have the SEENCONF command.
 		this._parent.callWindow(
-				"su_process_commands",
+				"StumbleGlobals.process_commands",
 				strResponse,
 				context);
 		
diff --git a/content/stumbleuponOverlay.js b/content/stumbleuponOverlay.js
new file mode 100644
index 0000000..ccbba93
--- /dev/null
+++ b/content/stumbleuponOverlay.js
@@ -0,0 +1,22398 @@
+/***
+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 StumbleUpon code.
+The Initial Developer of the Original Code is StumbleUpon.
+
+Portions created by StumbleUpon are
+Copyright (C) 2002-2007 StumbleUpon.  All
+Rights Reserved.
+
+Original Author: Geoff Smith <geoff at stumbleupon.com>
+Contributor(s): Garrett Camp <gmc at stumbleupon.com>
+		Joe Walp <joewalp at yahoo.com>
+		Manpreet Singh (loonyone.stumbleupon.com)
+		Don Schmitt <don at stumbleupon.com>
+
+Questions/Comments?  Please send them here:
+
+http://www.stumbleupon.com/feedback.php
+
+Copyright notes:
+1. No code contributed by Manpreet Singh remains in the codebase.
+2. Regardless of intellectual property claims, Manpreet Singh supports
+   changing the license from MPL to MPL/GPL/LGPL tri-license if other
+	 contributors so choose.  For reference:
+	 http://www.mozilla.org/MPL/boilerplate-1.1/mpl-tri-license-txt
+3. For additional intellectual property considerations, search for 
+   [IP:] and [kudos:] in the code.
+
+***/
+
+//************** GLOBALS ****************/
+StumbleGlobals.private_label = "2011051703";
+StumbleGlobals.source_label = "AM";
+StumbleGlobals.log_communication = false;
+StumbleGlobals.log_sync = false;
+StumbleGlobals.log_polling = false;
+StumbleGlobals.log_resource_cfd = false;
+StumbleGlobals.log_mimetype = false;
+StumbleGlobals.force_migrate_prerelease = ((StumbleGlobals.private_label.indexOf("ALPHA") == 0) || (StumbleGlobals.private_label.indexOf("BETA") == 0));
+StumbleGlobals.test_stumblethru_update = false;
+StumbleGlobals.test_info = false;
+StumbleGlobals.test_extra_init = false;
+StumbleGlobals.test_campus_dist = false;
+StumbleGlobals.test_facebookhome_prompt = false;
+StumbleGlobals.test_searchpage_prompt = false;
+StumbleGlobals.test_mimetype = false;
+StumbleGlobals.disable_sync = false;
+StumbleGlobals.enable_freereporting = true;
+StumbleGlobals.enable_message_log = (StumbleGlobals.private_label.indexOf("ALPHA") == 0);
+
+StumbleGlobals.base_url = StumbleGlobals.serverhttp;
+StumbleGlobals.ds = null;
+StumbleGlobals.host = null;
+StumbleGlobals.stumbleReporter = null;
+StumbleGlobals.window_time_ms = (new Date()).getTime();
+StumbleGlobals.stumbleid = 0;
+StumbleGlobals.stumblepass = "";
+StumbleGlobals.visited_login_page = false;
+StumbleGlobals.promo_mode = false;
+StumbleGlobals.login_initialized = false;
+StumbleGlobals.stumble_throttled = false;
+StumbleGlobals.info_spec = null;
+StumbleGlobals.tag_instructions = "Search or Tag here";
+StumbleGlobals.tagged_folder_name = "Unfiled/Tagged";
+StumbleGlobals.video_tagid = 1196;
+StumbleGlobals.window_load_called = false;
+StumbleGlobals.enable_hashed_password;
+StumbleGlobals.prev_nick = null;
+StumbleGlobals.random_delay = 0;
+StumbleGlobals.prefetcher;
+StumbleGlobals.last_typed_tag = 0;  // timestamp of the last time you typed a new tag
+StumbleGlobals.old_search = ""; // the search you had before we change due to tagging
+StumbleGlobals.url_has_tag = false;
+StumbleGlobals.search_service_id = null;
+StumbleGlobals.drawer_timers = new Object();
+
+StumbleGlobals.visited_searchbox = 0;
+StumbleGlobals.toggling_toolbar = false;
+StumbleGlobals.moving_toolbar = false;
+//StumbleGlobals.check_referral_flag = 0;
+StumbleGlobals.check_referral_timer = null;
+StumbleGlobals.process_rarely_timer = null;
+StumbleGlobals.dist_time_timer = null;
+StumbleGlobals.toolbar_disabled = false;
+
+StumbleGlobals.quote = "";
+StumbleGlobals.photoblogimage = null;
+
+StumbleGlobals.ratings = new Object(); // array of url->StumbleGlobals.ratings 
+StumbleGlobals.tag_lists_by_url = new Object(); // object url->tag_list
+StumbleGlobals.tags = new Array(); // array of objects with properties 'url' and 'tag_list'
+
+StumbleGlobals.selected_category = "0";
+StumbleGlobals.stumble_async_context = null;
+StumbleGlobals.stumblevideo_toolbar_rate = false;
+StumbleGlobals.pending_stumblevideo_stumble = false;
+StumbleGlobals.pending_stumblevideo_rate_context = null;
+StumbleGlobals.stumbled_url = ""; // your last stumble
+StumbleGlobals.redirect_url = "";
+StumbleGlobals.stumbled_redirect; // the url your last stumble got redirected to
+StumbleGlobals.previous_query_category = "";
+StumbleGlobals.stumble_action_count = 0;
+StumbleGlobals.stumbles = new Array(); // queue of urls to be stumbled upon in the future
+StumbleGlobals.user_interests = new Array(); // array of intersts the user is signed up for
+StumbleGlobals.catnames = new Array(); // array of catid -> catname (topics.csv)
+StumbleGlobals.catids = new Object(); // array of catid -> catname (topics.csv)
+StumbleGlobals.foldernames = new Array(); // folder names
+StumbleGlobals.topicfolders = new Array(); // maps topic id's to StumbleGlobals.foldernames
+StumbleGlobals.queries; // list of last 100 queries
+
+StumbleGlobals.notifier_dialog = null;
+StumbleGlobals.preference_dialog = null;
+StumbleGlobals.customize_invoked_from_preference_dialog = false;
+StumbleGlobals.uninstall_scheduled = false;
+StumbleGlobals.remove_data_scheduled = false;
+
+// The following are used by the keybinding routines, and some are
+// accessed by the preferenceDialog and by the keybinding migration
+// routine.
+StumbleGlobals.keys_by_keyspec = new Object();
+StumbleGlobals.commands_by_keyspec;
+StumbleGlobals.removed_keybindings_by_keyspec = new Object();
+StumbleGlobals.keyids_by_eventkeycode = new Object();
+StumbleGlobals.chars_by_keyid = new Object();
+StumbleGlobals.keyids_by_char = new Object();
+StumbleGlobals.recent_keypress_modifiers;
+StumbleGlobals.load_image_count = 0;
+StumbleGlobals.has_searchbox = false; // for efficiency
+StumbleGlobals.keep_searchbox_focus = false;
+StumbleGlobals.searchbox_was_focused = false; // used by the searchbox click kludge
+StumbleGlobals.gui_initialized = false;
+
+StumbleGlobals.searchlinks_dialog_detail = null;
+
+// The following are used by the toolbar location and overflow routines.
+StumbleGlobals.sidebar_was_hidden;
+StumbleGlobals.old_toolbar_x;
+StumbleGlobals.old_toolbar_position = null;
+StumbleGlobals.old_toolbar_position_group = null;
+StumbleGlobals.reflow_delayed = false;
+StumbleGlobals.overflow_popup_open = false;
+StumbleGlobals.referred_popup_open = false;
+StumbleGlobals.moving_splitter = false;
+StumbleGlobals.toolbar_justification;
+StumbleGlobals.bookmarks_sibling_loc = null;
+StumbleGlobals.persist_queue = new Array();
+
+StumbleGlobals.resize_window_width = 0;
+StumbleGlobals.resize_window_dirty = false;
+
+StumbleGlobals.referral_menu_dirty = true;
+StumbleGlobals.referral_popup_open = false;
+StumbleGlobals.refreshing_referral_menu = false;
+
+StumbleGlobals.dyn_channels_dirty = true;
+StumbleGlobals.mode_more_popup_open = false;
+StumbleGlobals.refreshing_dyn_channels = false;
+
+StumbleGlobals.pagemeta_dirty = true;
+StumbleGlobals.refreshing_pagemeta = false;
+
+StumbleGlobals.refreshing_category_selector = false;
+StumbleGlobals.blocked_category_selector_refresh_pending = false;
+
+StumbleGlobals.new_install = false; // true for first run after install
+StumbleGlobals.new_upgrade = false; // true for first run after upgrade
+StumbleGlobals.new_user = false;    // true between getid.php and interests_after.php
+StumbleGlobals.prev_version;        // set when StumbleGlobals.new_upgrade is true
+StumbleGlobals.migrate_toolbar_position_scheduled = false;
+
+StumbleGlobals.gecko19orlater = !!(navigator.oscpu && document.getElementsByClassName);
+
+StumbleGlobals.d_rec_rating = false;
+
+// Handle StumbleUpon sidebar (conversation bar)
+StumbleGlobals.sidebar_enabled = false; // Disabled by default
+
+StumbleGlobals.last_links_query = 0;
+
+//************** END GLOBALS ****************/
+
+StumbleGlobals.log_error = function()
+{
+	if (! StumbleGlobals.DEBUG_ENABLED)
+		return;
+
+	StumbleGlobals.service.logError.apply(StumbleGlobals.service, arguments);
+}
+
+//****************** SERVICE CREATION *******************************/
+
+try {
+	StumbleGlobals.service = Components.classes["@stumbleupon.com/stumbleupon-service;1"].getService().wrappedJSObject;
+}
+catch (e) {
+	// seamonkey kludge
+	StumbleGlobals.include("chrome://stumbleupon/content/stumbleuponService.js");
+	StumbleGlobals.service = new StumbleGlobals.Service();
+}
+
+StumbleGlobals.toolbar_api = {
+	processCommands: function(commands) {
+		StumbleGlobals.process_commands(commands);
+	}
+}
+
+//********* INCLUDES *****************//
+
+StumbleGlobals.include("chrome://stumbleupon/content/migrate.js");
+StumbleGlobals.include("chrome://stumbleupon/content/requestTracker.js");
+StumbleGlobals.include("chrome://stumbleupon/content/prefetcher.js");
+StumbleGlobals.include("chrome://stumbleupon/content/extensionApi.js");
+
+//********* END INCLUDES *****************//
+
+
+//********* INITIALIZATION *****************//
+// See also the bottom of the file for additional initialization.
+
+StumbleGlobals.load_categories = function()
+{
+	StumbleGlobals.catnames = StumbleGlobals.ds.getDictionary("catid:topic_name");
+	StumbleGlobals.catids = StumbleGlobals.ds.getDictionary("topic_name:catid");
+	StumbleGlobals.topicfolders = StumbleGlobals.ds.getDictionary("catid:folder_name");
+	StumbleGlobals.foldernames = StumbleGlobals.ds.getAlphaSupertopicNames();
+	
+	// Load topics.csv
+
+	// okay, let's try topics.csv that came with the xpi
+//!!! bah, let's not bother updating topics.csv over the net
+// it changes so infrequently
+
+/*
+	alert(catdat);
+
+//!!! 	var catdat = StumbleGlobals.read_file_global("topics.csv");
+
+	var da = new Date();
+	var timenow = da.getTime();
+	var oneweek = 24 * 60 * 60 * 7 * 1000; // javascript stores time in milliseconds
+
+	var last_categories = StumbleGlobals.ds.getValue("$categories_dat");
+	if (catdat == "" || timenow - last_categories > oneweek)
+	{
+		// We need to hit the server and grab topics.csv
+		//!!! mozilla's caching is on crack (it doesn't even check server to see if there's a new vesrion unless we create a salt!)
+		var res = StumbleGlobals.post_url_server("topics.csv", null);
+	
+		// If we got it, make it catdat and write it to disk
+		if (res.status == 200)
+		{
+ 			catdat = res.response;
+//!!!			StumbleGlobals.write_file_global("topics.csv", catdat);
+		}
+
+		// Write last_categories
+		last_categories = timenow;
+		StumbleGlobals.ds.setValue("$categories_dat", timenow);
+		StumbleGlobals.ds.flushPrefs();
+	}
+
+*/
+}
+
+StumbleGlobals.process_slclicks = function(force)
+{
+	if (StumbleGlobals.ds.getValue("#slprocessed") && (! force))
+		return;
+	StumbleGlobals.ds.setValue("#slprocessed", true);
+	var slclicks = StumbleGlobals.ds.selectAllRows("slclick");
+	var slstats = StumbleGlobals.ds.getValue("$slstats").split(":");
+	var profile = new Object();
+	var url_page1 = new Object();
+	var url_page2 = new Object();
+	var tag_page = new Object();
+	var result = new Object();
+	var result_dt = new Object();
+	var result_dc = new Object();
+	var result_ds = new Object();
+	var result_dl = new Object();
+	var result_df = new Object();
+	var result_dm = new Object();
+	var result_dz = new Object();
+	var index_clicked = new Array();
+	var index_friend_clicked = new Array();
+	var i;
+	for (i = 0; i < 10; i++)
+	{
+		index_clicked[i] = 0;
+		index_friend_clicked[i] = 0;
+	}
+	
+// fields
+// ---------------
+// userid
+// timestamp
+// session query num
+// query term count
+// result count
+// decorated count
+// friend decorated count
+// first decorated num
+// url_page1        clicked count
+// comment          clicked count
+// url_page2        clicked count
+// topic            clicked count
+// result           clicked count
+// thumbed result           clicked count (dt)
+// nickname result          clicked count (df)
+// multinickname result     clicked count (dm)
+// comment result           clicked count (dc)
+// comment level > 0 result clicked count (dl)
+// starred > 1 result       clicked count (ds)
+// topic result             clicked count (dz)
+	
+	var slq;
+	for (i = 0; i < slclicks.length; i++)
+	{
+		var row = slclicks[i];
+		
+		slq = row.q;
+		
+		if (row.i < 10)
+		{
+			if (row.r && row.df)
+				index_friend_clicked[row.i]++;
+			else if (row.r)
+				index_clicked[row.i]++;
+		}
+		
+		if (row.u)
+			url_page1[slq] = (url_page1[slq]) ? (url_page1[slq] + 1) : 1;
+
+		if (row.p)
+			profile[slq] = (profile[slq]) ? (profile[slq] + 1) : 1;
+		
+		if (row.n)
+			url_page2[slq] = (url_page2[slq]) ? (url_page2[slq] + 1) : 1;
+		
+		if (row.z)
+			tag_page[slq] = (tag_page[slq]) ? (tag_page[slq] + 1) : 1;
+		
+		if (row.r)
+			result[slq] = (result[slq]) ? (result[slq] + 1) : 1;
+		
+		if (row.r && row.dt)
+			result_dt[slq] = (result_dt[slq]) ? (result_dt[slq] + 1) : 1;
+		
+		if (row.r && row.dc)
+			result_dc[slq] = (result_dc[slq]) ? (result_dc[slq] + 1) : 1;
+
+		if (row.r && (row.ds > 1))
+			result_ds[slq] = (result_ds[slq]) ? (result_ds[slq] + 1) : 1;
+
+		if (row.r && row.dl)
+			result_dl[slq] = (result_dl[slq]) ? (result_dl[slq] + 1) : 1;
+
+		if (row.r && row.df)
+			result_df[slq] = (result_df[slq]) ? (result_df[slq] + 1) : 1;
+
+		if (row.r && (row.df > 1))
+			result_dm[slq] = (result_dm[slq]) ? (result_dm[slq] + 1) : 1;
+
+		if (row.r && row.dz)
+			result_dz[slq] = (result_dz[slq]) ? (result_dz[slq] + 1) : 1;
+	}
+	
+	var stats = "";
+	for (i = 0; i < slstats.length; i++)
+	{
+		if (slstats[i] == "")
+			continue;
+		
+		slq = slstats[i].split("\t")[1];
+
+		if (! url_page1[slq])
+			url_page1[slq] = 0;
+		
+		if (! profile[slq])
+			profile[slq] = 0;
+		
+		if (! url_page2[slq])
+			url_page2[slq] = 0;
+		
+		if (! tag_page[slq])
+			tag_page[slq] = 0;
+		
+		if (! result[slq])
+			result[slq] = 0;
+		
+		if (! result_dt[slq])
+			result_dt[slq] = 0;
+		
+		if (! result_dc[slq])
+			result_dc[slq] = 0;
+
+		if (! result_ds[slq])
+			result_ds[slq] = 0;
+
+		if (! result_dl[slq])
+			result_dl[slq] = 0;
+
+		if (! result_df[slq])
+			result_df[slq] = 0;
+
+		if (! result_dm[slq])
+			result_dm[slq] = 0;
+
+		if (! result_dz[slq])
+			result_dz[slq] = 0;
+
+		stats +=StumbleGlobals.stumbleid + "\t" + slstats[i] + "\t" + 
+					url_page1[slq] + "\t" + profile[slq] + "\t" + 
+					url_page2[slq] + "\t" + tag_page[slq] + "\t" + 
+					result[slq] + "\t" + result_dt[slq] + "\t" + 
+					result_df[slq] + "\t" + result_dm[slq] + "\t" + 
+					result_dc[slq] + "\t" + result_dl[slq] + "\t" + 
+					result_ds[slq] + "\t" + result_dz[slq] + "\n";
+					
+	}
+	
+	var istats = "";
+	var slistats = StumbleGlobals.ds.getValue("$slistats").split(":");
+	var slidfstats = StumbleGlobals.ds.getValue("$slidfstats").split(":");
+	for (i = 0; i < 10; i++)
+	{
+		istats += (i + 1) + "\t" + slistats[i] + "\t" + 
+					slidfstats[i] + "\t" + index_clicked[i] + "\t" +
+					index_friend_clicked[i] + "\n"
+	}
+	
+	if (stats == "")
+		return;
+	
+	StumbleGlobals.ds.globals.sls = new Array();
+	StumbleGlobals.ds.globals.sluqh = new Object();
+	StumbleGlobals.ds.globals.sltih = new Object();
+	StumbleGlobals.ds.setValue("$slstats", "");
+	StumbleGlobals.ds.setValue("$slistats", "0:0:0:0:0:0:0:0:0:0");
+	StumbleGlobals.ds.setValue("$slidfstats", "0:0:0:0:0:0:0:0:0:0");
+	StumbleGlobals.ds.deleteAllRows("slclick");
+	StumbleGlobals.ds.flushPrefs();
+	
+	var params = "";
+	params = StumbleGlobals.arp(params, "slstats", stats);
+	params = StumbleGlobals.arp(params, "slindexstats", istats);
+	params = StumbleGlobals.arp(params, "f", StumbleGlobals.ds.getValue("$form"));
+	
+	var context = new Object();
+	context.quiet = true;
+	StumbleGlobals.post_url_server_async(
+				"slstats.php",
+				params,
+				15000,
+				StumbleGlobals.generic_done,
+				context);
+}
+
+StumbleGlobals.get_random_int = function(min, max)
+{
+	return Math.floor(Math.random() * (max - min + 1)) + min;
+}
+
+// initializes user-specific configuration that doesn't involve gui
+// elements
+StumbleGlobals.load_data1 = function(new_profile)
+{
+	//!!! We can migrate from flat files to mozStorage after that
+	// feature is mature.  We ought to be able to get rid of the
+	// length limits on these data stores for clients that include
+	// the embedded database.  -- JW
+
+	StumbleGlobals.stumbled_url = "";
+	StumbleGlobals.redirect_url = "";
+	StumbleGlobals.stumbled_redirect = "";
+//	StumbleGlobals.dd("reset", 2);
+	StumbleGlobals.stumbles = new Array();
+	StumbleGlobals.ratings = new Object();
+	
+	StumbleGlobals.migrate_profile(new_profile);
+	
+	// make random delay...
+	// this is to avoid a race condition in hitting StumbleGlobals.stumbles.php
+	// and hitting recommend.php to check_referral
+	// after X+StumbleGlobals.random_delay seconds ... ( up to 5 minutes)
+	StumbleGlobals.random_delay = Math.floor(Math.random()*300);
+
+	StumbleGlobals.stumble_action_count = 0;
+	try {
+		StumbleGlobals.prefetcher.stop();
+		StumbleGlobals.prefetcher.clearTargets();
+		StumbleGlobals.prefetcher.passMax = StumbleGlobals.ds.getValue("$prefetcher_pass_max");
+		StumbleGlobals.prefetcher.pass1TimeoutInterval = StumbleGlobals.ds.getValue("$prefetcher_pass_1_timeout_ms");
+		StumbleGlobals.prefetcher.pass2TimeoutInterval = StumbleGlobals.ds.getValue("$prefetcher_pass_2_timeout_ms");
+		StumbleGlobals.prefetcher.pass3TimeoutInterval = StumbleGlobals.ds.getValue("$prefetcher_pass_3_timeout_ms");
+		if (StumbleGlobals.ds.getValue("$prefetcher_skip_resources"))
+			StumbleGlobals.prefetcher.mode = "DOM";
+		else
+			StumbleGlobals.prefetcher.mode = "complete";
+		StumbleGlobals.prefetcher.addEventListener("progress-start", StumbleGlobals.handle_prefetch_load_start);
+		
+		// If the Authentication Manager is installed, then disable prefetch.  See
+		// the following bugs for reference:
+		//		https://trac.stumble.net/ticket/6049
+		//		https://bugzilla.mozilla.org/show_bug.cgi?id=564295
+		//
+		if(	StumbleGlobals.ds.isPrefDefined("extensions.weave.id.authenticator.enabled") &&
+			StumbleGlobals.ds.getValue("extensions.weave.id.authenticator.enabled"))
+		{
+			StumbleGlobals.prefetcher.setQueueLock(true);
+		}
+		else
+		{
+			// If noscript is installed and the version is less than 1.9.8.4, then disable
+			// the prefetcher.  We do this because those versions have a bug which will cause
+			// the prefetcher to open up a bunch of extra tabs.  So we disable the
+			// prefetcher if one of those versions of noscript is installed.  Technically,
+			// the problematic versions are < 1.9.7.9, but then there was a regression around
+			// 1.9.8.1 that caused the problem again, but it was fixed again in 1.9.8.4, so we just
+			// disable prefetcher on anything earlier than 1.9.8.4.
+			
+			// Update:  The FF4-compatible versions of noscript re-introduce this bug.  So we go back
+			// to disabling the prefetcher whenever noscript is installed until we can find a reasonable
+			// solution.
+			if((typeof noscriptUtil) == "object")
+			{
+				StumbleGlobals.prefetcher.setQueueLock(true);
+			}
+		}
+	} catch (e) { StumbleGlobals.log_error("INIT PREFETCHER: " + e); }
+
+	StumbleGlobals.stumbleReporter.start();
+	
+	setTimeout(function (win) { win.StumbleGlobals.load_ratings(); }, 0, window);
+
+	try {
+		StumbleGlobals.load_stumbles(null);
+	} catch (e) { StumbleGlobals.log_error("LOAD STUMBLES", e); }
+	try {
+		StumbleGlobals.load_categories();
+	} catch (e) { StumbleGlobals.log_error("LOAD CATEGORIES", e); }
+	try {
+		StumbleGlobals.load_user_interests();
+	} catch (e) { StumbleGlobals.log_error("LOAD INTERESTS", e); }
+	StumbleGlobals.tags = new Array();
+	StumbleGlobals.tag_lists_by_url = new Object();
+	setTimeout(function (win) { win.StumbleGlobals.load_tags(null); }, 0, window);
+
+	StumbleGlobals.queries = new Array();
+	setTimeout(function (win) { win.StumbleGlobals.load_queries(); }, 0, window);
+	
+	if (StumbleGlobals.ds.getValue("@whitelist_upon_load"))
+	{
+		try {
+			StumbleGlobals.update_noscript_whitelists();
+		} catch (e) { StumbleGlobals.log_error("INIT WHITELIST", e); }
+	}
+	
+	StumbleGlobals.ds.flushPrefs();
+}
+
+StumbleGlobals.update_noscript_whitelists = function()
+{
+	if (! StumbleGlobals.ds.isPrefDefined("noscript.filterXExceptions"))
+		return;
+	
+	var str = StumbleGlobals.ds.getValue("noscript.filterXExceptions");
+	var exceptions = str.split("\n");
+	var regsafeServer = StumbleGlobals.servername.replace(/\./g, "\\.");
+	var filter_str = "^(http|https)://[a-z0-9\\-]+\\." + regsafeServer + "/";
+	var i;
+	var found = false;
+	for (i = 0; i < exceptions.length; i++)
+	{
+		if (exceptions[i] == filter_str)
+		{
+			found = true;
+			break;
+		}
+	}
+	
+	if (! found)
+	{
+		exceptions.push(filter_str);
+		str = exceptions.join("\n");
+		StumbleGlobals.ds.setValue("noscript.filterXExceptions", str);
+	}
+	
+	if ((typeof noscriptUtil) != "object")
+		return;
+	
+	if (noscriptUtil.service &&
+			noscriptUtil.service.setJSEnabled &&
+			((typeof noscriptUtil.service.setJSEnabled) == "function"))
+	{
+		noscriptUtil.service.setJSEnabled(StumbleGlobals.servername, true);
+		noscriptUtil.service.setJSEnabled("recaptcha.net", true);
+	}
+	
+	StumbleGlobals.ds.flushPrefs();
+}
+
+// populates the stumbles array using content from file 'stumbleurls'
+StumbleGlobals.load_stumbles = function(url_to_exclude)
+{
+	StumbleGlobals.stumbles = new Array();
+	// Load stumbleurls (queue of urls to be stumbled upon)
+	var unseen = StumbleGlobals.read_file_user("stumbleurls");
+	
+	var commands = unseen.split("\n");
+
+	try {
+		if (StumbleGlobals.ds.getValue("$last_incat") == StumbleGlobals.previous_query_category)
+			StumbleGlobals.prefetcher.fetchAheadDepth = StumbleGlobals.ds.getValue("$prefetcher_fetch_depth_in_query");
+		else
+			StumbleGlobals.prefetcher.fetchAheadDepth = StumbleGlobals.ds.getValue("$prefetcher_fetch_depth_in_topic");
+	} catch (e) {}
+	
+	var found_url_to_exclude = false;
+	var i;
+	var url_detail;
+	var target;
+	for (i = 0; i < commands.length; i++)
+	{
+		url_detail = StumbleGlobals.deserialize_url_command_params(commands[i], true);
+
+        // Skip any old stumbles that don't have a public id
+        if(!url_detail || !url_detail.publicid)
+            continue;
+		
+		target = url_detail.actual_url ? url_detail.actual_url : url_detail.url;
+		
+		if ((target == url_to_exclude) && (! found_url_to_exclude))
+		{
+			// exclude only the first instance of url_to_exclude
+			found_url_to_exclude = true;
+			continue;
+		}
+		
+		try {
+			if (StumbleGlobals.is_404_status(StumbleGlobals.prefetcher.getHttpResponseStatus(target)))
+			{
+				StumbleGlobals.report_404(target, StumbleGlobals.prefetcher.getHttpResponseStatus(target));
+				continue;
+			}
+		} catch (e) {}
+				
+		
+		StumbleGlobals.stumbles.push(commands[i]);
+		
+		// Don't prefetch against stumbleupon.com.
+		if (target.indexOf(StumbleGlobals.base_url) == 0)
+			continue;
+		
+		// Don't prefetch profiles.
+		if (StumbleGlobals.get_profile_nickname(target))
+			continue;
+		
+		// Don't prefetch 'is_sound' urls.
+		if (StumbleGlobals.is_sound(target))
+			continue;	
+		
+		// Don't prefetch sponsored stumbles.
+		if (url_detail.cluster_type == 3)
+			continue;
+		
+		// Don't prefetch referrals.
+		if (url_detail.cluster_type == 4)
+			continue;
+		
+		if (! url_detail.referrer)
+		{
+			if (StumbleGlobals.is_adult_category(url_detail.catid))
+				url_detail.referrer = target;
+			else if (StumbleGlobals.ds.getValue("@enable_refer"))
+				url_detail.referrer = "http://www.stumbleupon.com/refer.php?url=" + encodeURIComponent(target);
+			else
+				url_detail.referrer = "about:blank";
+		}
+		
+		try {
+			StumbleGlobals.prefetcher.addTarget(url_detail);
+		} catch (e) { StumbleGlobals.log_error("PREFETCHER 1", e); }
+	}
+}
+
+// populates StumbleGlobals.ratings using content from file 'stumblerating'
+StumbleGlobals.load_ratings = function()
+{
+	StumbleGlobals.ratings = new Object();
+	// load ratings
+	var stumblecat = StumbleGlobals.read_file_user("stumblerating");
+	var splitcat = stumblecat.split("\n");
+	for (var i = 0; i < splitcat.length; i++)
+	{
+		if (splitcat[i] == "")
+			continue;
+		var split2 = splitcat[i].split(" ");
+		StumbleGlobals.ratings[split2[0]] = split2[1];
+	}
+}	
+
+// populates StumbleGlobals.user_interests using content from pref 'interests'
+StumbleGlobals.load_user_interests = function()
+{
+	StumbleGlobals.user_interests = new Array();
+	
+	// Load StumbleGlobals.user_interests
+	var stumbleseen = StumbleGlobals.ds.getValue("$interests");
+	var splitseen = stumbleseen.split(" ");
+	var i;
+	for (i = 0; i < splitseen.length; i++)
+	{
+		if (splitseen[i] == "")
+			continue;
+		if (splitseen[i] == "toXMLRPCParam")
+			continue;
+		StumbleGlobals.user_interests[splitseen[i]] = 1;
+	}
+}	
+
+// populates StumbleGlobals.tags and StumbleGlobals.tag_lists_by_url using content of the
+// stumbletags file
+StumbleGlobals.load_tags = function(url_to_exclude)
+{
+	StumbleGlobals.tags = new Array();
+	StumbleGlobals.tag_lists_by_url = new Object();
+	
+	var stumblecat = StumbleGlobals.read_file_user("stumbletags");
+	var splitcat = stumblecat.split("\n");
+	
+	for (var i = 0; i < splitcat.length; i++)
+	{
+		if (splitcat[i] == "")
+			continue;
+		var split2 = splitcat[i].split("\t");
+		var o = new Object();
+		o.url = split2[0];
+		o.tag_list = split2[1];
+		if ((o.url != url_to_exclude) && (o.url.indexOf("about:") != 0))
+		{
+			StumbleGlobals.tag_lists_by_url[o.url] = o.tag_list;
+			StumbleGlobals.tags.push(o);
+		}
+	}
+}
+
+// stores content of StumbleGlobals.tags into the stumbletags file
+StumbleGlobals.store_tags = function()
+{
+	var towrite = "";
+	for (var i = 0; (i < StumbleGlobals.tags.length) && (i < StumbleGlobals.ds.getValue("$tag_history_depth")); i++)
+		towrite += StumbleGlobals.tags[i].url + "\t" + StumbleGlobals.tags[i].tag_list + "\n";
+
+	StumbleGlobals.write_file_user("stumbletags", towrite);
+}
+
+// populates StumbleGlobals.queries using content of the stumblequeries file
+StumbleGlobals.load_queries = function()
+{
+	StumbleGlobals.queries = new Array();
+	
+	var stumblequeries = StumbleGlobals.read_file_user("stumblequeries");
+
+	if (stumblequeries != "")
+		StumbleGlobals.queries = stumblequeries.split("\n");
+	
+	// !! This is an inefficient method to get rid of the empty last 
+	// element due to the trailing linefeed in the file, but we'll 
+	// leave it this way for now, as it contributes robustness. -- JW
+	for (var i = 0; i < StumbleGlobals.queries.length; i++)
+	{
+		if (StumbleGlobals.queries[i] == "")
+			StumbleGlobals.queries.splice(i, 1);
+	}
+}
+
+// stores content of StumbleGlobals.queries in the stumblequeries file
+StumbleGlobals.store_queries = function()
+{
+	var towrite = "";
+	for (var i = 0; (i < StumbleGlobals.queries.length) && (i < StumbleGlobals.ds.getValue("$query_history_depth")); i++)
+		towrite += StumbleGlobals.queries[i] + "\n";
+
+	StumbleGlobals.write_file_user("stumblequeries", towrite);
+}
+
+// initializes user-specific configuration that involves gui elements
+StumbleGlobals.load_data2 = function(force_update)
+{
+	StumbleGlobals.get_element("stumbleglobals_searchbox").autocompleteDatasource = 
+	{ 
+		getResults : function ()
+		{
+			var searchbox = StumbleGlobals.get_element("stumbleglobals_searchbox");
+			return StumbleGlobals.get_autocomplete_results(
+						StumbleGlobals.ds.getValue("$autocomplete_type"),
+						searchbox.value,
+						searchbox.maxRows,
+						new Array());
+		}
+	};
+	
+//	StumbleGlobals.update_verified_reporting(false);
+	StumbleGlobals.update_referred(false);
+	
+	StumbleGlobals.check_referral(force_update);
+	StumbleGlobals.process_rarely(force_update, false);
+
+	if (force_update)
+	{
+		//!!! 1. Move contacts into getstate.php
+		//!!! 2. Sync tag & following?
+		StumbleGlobals.import_contacts();
+		StumbleGlobals.get_state(false);
+	}
+	
+	// Store this stumbleid in the ids list.  The list is ordered from 
+	// most recently used to least recently used. -- JW
+	var id_list = StumbleGlobals.ds.getValue("@id_list");
+	
+	var splitids = id_list.split(":");
+	var id_list_new = StumbleGlobals.stumbleid + ":";
+	var i;
+	for (i = 0; i < splitids.length; i++)
+	{
+		if (splitids[i] == "")
+			continue;
+		
+		var line = splitids[i];
+		if (line != StumbleGlobals.stumbleid)
+			id_list_new += splitids[i] + ":";
+	}
+	StumbleGlobals.ds.setValue("@id_list", id_list_new);
+
+	StumbleGlobals.ds.flushPrefs();
+
+	StumbleGlobals.init_keybinding_globals();	
+
+	StumbleGlobals.configure_toolbar(false);
+	
+	StumbleGlobals.close_all_messages();
+
+	// Check to see when the url changes
+	StumbleGlobals.add_progress_listener();
+
+	// Upload any pending old stumbles
+	StumbleGlobals.upload_stumbles();
+	
+	window.addEventListener("keyup", StumbleGlobals.handle_window_keyup, false);
+	window.addEventListener("keypress", StumbleGlobals.handle_window_keypress, false);
+	window.addEventListener("mousedown", StumbleGlobals.handle_window_mousedown, true);
+	StumbleGlobals.ds.addEventListener("resourceinstalled", StumbleGlobals.handle_resource_installed, false);
+	
+	StumbleGlobals.download_favs(false);	
+	StumbleGlobals.process_command_queue();
+}
+
+StumbleGlobals.process_command_queue = function()
+{
+	if (! StumbleGlobals.host.places)
+		return;
+	
+	// wait for places migration to finish
+	if (StumbleGlobals.ds.getValue("#migrating_places"))
+		return;
+	
+	var context;
+	
+	if (StumbleGlobals.ds.getValue("#command_queue_context"))
+		return;
+	
+	var db = StumbleGlobals.ds.getDatabase();
+	var sql;
+	var result;
+	sql = "SELECT seqid FROM command_queue WHERE priority>0 ORDER BY priority DESC, seqid LIMIT 1";
+	result = db.query(sql);
+	if (result.length == 0)
+	{
+		StumbleGlobals.ds.setValue("#download_favs_detail", null);
+//		StumbleGlobals.ds.setValue("#command_queue_context", null);
+		return;
+	}
+	
+	context = new Object();
+
+	StumbleGlobals.ds.setValue("#command_queue_context", context);
+	
+	context.priority == null;
+	context.command_rows = null;
+	context.processed_idx = 0;
+	context.download_favs_detail = null;
+//	context.abort = false;
+	setTimeout(function() {
+		StumbleGlobals.process_command_queue2(context);
+	}, 200);
+}
+
+StumbleGlobals.process_command_queue2 = function(context)
+{
+	var db = StumbleGlobals.ds.getDatabase();
+	var sql;
+	var seqid;
+	var command;
+	var row;
+	var detail;
+	var val;
+	
+	// 1. grab a set of commands
+	if (! context.command_rows)
+	{
+		sql = "SELECT priority,seqid,command FROM command_queue WHERE priority>0 ORDER BY priority DESC, seqid LIMIT 1000";
+		context.command_rows = db.query(sql);
+		context.processed_idx = 0;
+	}
+	
+	// 2. check whether we're done.
+//	if ((context.command_rows.length == 0) || context.abort)
+	if (context.command_rows.length == 0) 
+	{
+		StumbleGlobals.ds.setValue("#command_queue_context", null);
+		// moving out of favs
+		if (context.download_favs_detail)
+		{
+			StumbleGlobals.set_download_favs_enabled(true);
+			context.download_favs_detail = null;
+		}
+		setTimeout(function() {
+			StumbleGlobals.process_command_queue();
+		}, 0);
+		return;
+	}
+	
+	row = context.command_rows[context.processed_idx];
+	
+	if (context.download_favs_detail && (row.priority != 16000))
+	{
+		// moving out of favs
+		StumbleGlobals.set_download_favs_enabled(true);
+		
+		context.download_favs_detail = null;
+	}
+	else if ((context.priority != 16000) && (row.priority == 16000))
+	{
+		// moving into favs
+		StumbleGlobals.set_download_favs_enabled(false);
+		
+		detail = StumbleGlobals.ds.getValue("#download_favs_detail");
+		if (! detail)
+		{
+			detail = StumbleGlobals.ds.getValue("$download_favs_detail");
+			StumbleGlobals.ds.setValue("#download_favs_detail", detail);
+		}
+		context.download_favs_detail = detail;
+	}
+	
+	context.priority = row.priority;
+	
+	if (context.download_favs_detail)
+	{
+		detail = context.download_favs_detail;
+		detail.apply_count++;
+		if ((detail.applied_count % 1000) == 0)
+		{
+			StumbleGlobals.ds.setValue("$download_favs_detail", detail);
+			StumbleGlobals.ds.flushPrefs();
+		}
+		
+		if (StumbleGlobals.preference_dialog)
+		{
+			val = 5 + Math.round((45 * (detail.download_count / detail.download_target_count)) + (45 * (detail.apply_count / detail.apply_target_count)));
+			
+			el = StumbleGlobals.preference_dialog.ownerDocument.getElementById("download_progress");
+			if (el && (val != el.value))
+				el.setAttribute("value", val);
+		}
+	}
+	
+	// 3. process the command
+	StumbleGlobals.process_command(row.command, context);
+	
+	// 4. remove it from the queue
+	sql = "DELETE FROM command_queue WHERE seqid=" + db.v(row.seqid);
+	db.query(sql);
+	context.processed_idx++;
+	
+	if (context.command_rows.length == context.processed_idx)
+		context.command_rows = null;
+	
+	setTimeout(function() {
+		StumbleGlobals.process_command_queue2(context);
+	}, 50);
+}
+
+StumbleGlobals.set_download_favs_enabled = function(enabled)
+{
+	var el;
+	var doc;
+	var sync;
+	
+	if (! StumbleGlobals.preference_dialog)
+		return;
+	
+	doc = StumbleGlobals.preference_dialog.ownerDocument; 
+	
+	sync = doc.getElementById("sync_bm_meta").checked;
+	
+	if (enabled)
+		doc.getElementById("download_progress").value = 0;
+
+	doc.getElementById("download_start").disabled = (! sync) || (! enabled);
+	
+	doc.getElementById("download_stop").disabled = (! sync) || enabled;
+}
+
+// used during init to set hidden states for top-level toolbar
+// element
+StumbleGlobals.init_toolbar_element_visibility = function()
+{
+	if ((StumbleGlobals.stumbleid == 0) && StumbleGlobals.promo_mode)
+	{
+		StumbleGlobals.set_visible("stumbleglobals_start",         true);
+		StumbleGlobals.set_visible("stumbleglobals_login",         true);
+		StumbleGlobals.set_visible("stumbleglobals_stumble",       false);
+		StumbleGlobals.set_visible("stumbleglobals_sites_promo",   true);
+		StumbleGlobals.set_visible("stumbleglobals_friends",       true);
+		StumbleGlobals.set_visible("stumbleglobals_thumbup",       true);
+		StumbleGlobals.set_visible("stumbleglobals_thumbdown",     false);
+		StumbleGlobals.get_element("stumbleglobals_thumbdown").type = "";
+		StumbleGlobals.set_visible("stumbleglobals_separator2",    true);
+		StumbleGlobals.set_visible("stumbleglobals_website_info_promo", true);
+		StumbleGlobals.set_visible("stumbleglobals_separator_promo", true);
+		StumbleGlobals.set_visible("stumbleglobals_referral_promo", true);
+		StumbleGlobals.set_visible("stumbleglobals_separator_category", true);
+		StumbleGlobals.set_visible("stumbleglobals_separator4",    true);
+		StumbleGlobals.set_visible("stumbleglobals_video_promo",   true);
+		StumbleGlobals.set_visible("stumbleglobals_separator6",    true);
+		StumbleGlobals.set_visible("stumbleglobals_profile",       true);
+		StumbleGlobals.set_visible("stumbleglobals_separator7",    false);
+		StumbleGlobals.set_visible("stumbleglobals_mode",          false);	
+		StumbleGlobals.set_visible("stumbleglobals_stumble_menu",  false);
+		StumbleGlobals.set_visible("stumbleglobals_category",      false);
+		StumbleGlobals.set_visible("stumbleglobals_website_info",  false);
+		StumbleGlobals.set_visible("stumbleglobals_network",       false); // legacy network
+		StumbleGlobals.set_visible("stumbleglobals_messages",      false);	
+		StumbleGlobals.set_visible("stumbleglobals_field",         false);
+		StumbleGlobals.has_searchbox = false;
+	
+		StumbleGlobals.set_visible("stumbleglobals_filter",        false);
+		StumbleGlobals.set_visible("stumbleglobals_aboutme",       false);
+		StumbleGlobals.set_visible("stumbleglobals_matches",       false);
+		StumbleGlobals.set_visible("stumbleglobals_groups",        false);
+		StumbleGlobals.set_visible("stumbleglobals_myinfo",        false);
+//		StumbleGlobals.set_visible("stumbleglobals_forum",         false);   // legacy forums
+		StumbleGlobals.set_visible("stumbleglobals_referral_menu", false);
+//		StumbleGlobals.set_visible("stumbleglobals_inbox-count",   false);
+		StumbleGlobals.set_visible("stumbleglobals_referred", false);
+	
+		StumbleGlobals.set_visible("stumbleglobals_page_feature_prompt", false);
+		StumbleGlobals.set_visible("firstrater",       false);
+		StumbleGlobals.set_visible("stumbleglobals_stumble_topic", false);
+		StumbleGlobals.set_visible("stumbleglobals_stumble_topic_menu_left", false);
+		StumbleGlobals.set_visible("stumbleglobals_stumble_topic_menu_right", false);
+		StumbleGlobals.set_visible("stumbleglobals_sponsor",       false);
+		StumbleGlobals.set_visible("stumbleglobals_tag",           false);
+		StumbleGlobals.set_visible("stumbleglobals_tag2",          false);
+		StumbleGlobals.set_visible("stumbleglobals_fbshare",		false);
+		StumbleGlobals.set_visible("stumbleglobals_splitter_search_right", false);
+	}
+	else if (StumbleGlobals.stumbleid == 0)
+	{
+		StumbleGlobals.set_visible("stumbleglobals_start",         true);
+		StumbleGlobals.set_visible("stumbleglobals_login",         (! StumbleGlobals.has_logged_in()));
+		StumbleGlobals.set_visible("stumbleglobals_stumble",       false);
+		StumbleGlobals.set_visible("stumbleglobals_sites_promo",   false);
+		StumbleGlobals.set_visible("stumbleglobals_friends",       false);
+		StumbleGlobals.set_visible("stumbleglobals_thumbup",       false);
+		StumbleGlobals.set_visible("stumbleglobals_thumbdown",     false);
+		StumbleGlobals.get_element("stumbleglobals_thumbdown").type = "";
+		StumbleGlobals.set_visible("stumbleglobals_separator2",    false);
+		StumbleGlobals.set_visible("stumbleglobals_website_info_promo", false);
+		StumbleGlobals.set_visible("stumbleglobals_separator_promo", false);
+		StumbleGlobals.set_visible("stumbleglobals_referral_promo", false);
+		StumbleGlobals.set_visible("stumbleglobals_separator4",    false);
+		StumbleGlobals.set_visible("stumbleglobals_separator_category", false);
+		StumbleGlobals.set_visible("stumbleglobals_video_promo",   false);
+		StumbleGlobals.set_visible("stumbleglobals_separator6",    false);
+		StumbleGlobals.set_visible("stumbleglobals_separator7",    false);
+		StumbleGlobals.set_visible("stumbleglobals_profile",       false);
+		StumbleGlobals.set_visible("stumbleglobals_mode",          false);
+		StumbleGlobals.set_visible("stumbleglobals_stumble_menu",  false);
+		StumbleGlobals.set_visible("stumbleglobals_category",      false);
+		StumbleGlobals.set_visible("stumbleglobals_website_info",  false);	
+		StumbleGlobals.set_visible("stumbleglobals_network",       false); // legacy network
+		StumbleGlobals.set_visible("stumbleglobals_messages",      false);	
+		StumbleGlobals.set_visible("stumbleglobals_field",         false);
+		StumbleGlobals.has_searchbox = false;
+		StumbleGlobals.set_visible("stumbleglobals_filter",        false);
+		StumbleGlobals.set_visible("stumbleglobals_aboutme",       false);	
+		StumbleGlobals.set_visible("stumbleglobals_matches",       false);	
+		StumbleGlobals.set_visible("stumbleglobals_groups",        false);	
+		StumbleGlobals.set_visible("stumbleglobals_myinfo",        false);
+//		StumbleGlobals.set_visible("stumbleglobals_forum",         false);   // legacy forums
+		StumbleGlobals.set_visible("stumbleglobals_referral_menu", false);
+//		StumbleGlobals.set_visible("stumbleglobals_inbox-count",   false);
+		StumbleGlobals.set_visible("stumbleglobals_referred", false);
+		StumbleGlobals.set_visible("stumbleglobals_page_feature_prompt", false);
+		StumbleGlobals.set_visible("firstrater",       false);
+		StumbleGlobals.set_visible("stumbleglobals_stumble_topic", false);
+		StumbleGlobals.set_visible("stumbleglobals_stumble_topic_menu_left", false);
+		StumbleGlobals.set_visible("stumbleglobals_stumble_topic_menu_right", false);
+		StumbleGlobals.set_visible("stumbleglobals_sponsor",       false);
+		StumbleGlobals.set_visible("stumbleglobals_tag",           false);
+		StumbleGlobals.set_visible("stumbleglobals_tag2",          false);
+		StumbleGlobals.set_visible("stumbleglobals_fbshare",		false);
+		StumbleGlobals.set_visible("stumbleglobals_splitter_search_right", false);
+	}
+	else
+	{
+		// show rating buttons, menu, etc...
+		StumbleGlobals.set_visible("stumbleglobals_start",         false);
+		StumbleGlobals.set_visible("stumbleglobals_login",         false);
+		StumbleGlobals.set_visible("stumbleglobals_stumble",       true);
+		StumbleGlobals.set_visible("stumbleglobals_separator4",    (
+			                                   (StumbleGlobals.ds.getValue("$show_mode")  &&
+											   StumbleGlobals.ds.getValue("$show_separators"))
+										   )
+			          );
+		StumbleGlobals.set_visible("stumbleglobals_separator_category", !StumbleGlobals.get_element("stumbleglobals_stumble_topic_menu_left").collapsed);
+		StumbleGlobals.set_visible("stumbleglobals_thumbup",       true);
+		StumbleGlobals.set_visible("stumbleglobals_thumbdown",     true);
+		StumbleGlobals.get_element("stumbleglobals_thumbdown").type = "menu-button";
+		StumbleGlobals.set_visible("stumbleglobals_separator2",    StumbleGlobals.ds.getValue("$show_separators"));
+		StumbleGlobals.set_visible("stumbleglobals_referral_promo", false);
+		StumbleGlobals.set_visible("stumbleglobals_separator_promo",  false);
+		StumbleGlobals.set_visible("stumbleglobals_website_info_promo", false);
+		StumbleGlobals.set_visible("stumbleglobals_stumble_menu",  true);
+		StumbleGlobals.set_visible("stumbleglobals_category",      StumbleGlobals.ds.getValue("$show_topics"));
+		StumbleGlobals.set_visible("stumbleglobals_website_info",  StumbleGlobals.ds.getValue("$show_info"));
+		StumbleGlobals.set_visible("stumbleglobals_field",         StumbleGlobals.ds.getValue("$show_field"));
+		StumbleGlobals.has_searchbox = StumbleGlobals.ds.getValue("$show_field");
+		StumbleGlobals.set_visible("stumbleglobals_splitter_search_right", StumbleGlobals.ds.getValue("$show_field"));
+		StumbleGlobals.set_visible("stumbleglobals_tag",           (StumbleGlobals.ds.getValue("$show_tag") && StumbleGlobals.ds.getValue("$show_field")) );
+		StumbleGlobals.set_visible("stumbleglobals_tag2",  (StumbleGlobals.ds.getValue("$show_tag") && (! StumbleGlobals.ds.getValue("$show_field"))) );
+		StumbleGlobals.set_visible("stumbleglobals_fbshare", StumbleGlobals.ds.getValue("$show_fbshare"));
+		StumbleGlobals.set_visible("stumbleglobals_referral_menu", StumbleGlobals.ds.getValue("$show_referral"));
+		StumbleGlobals.set_visible("stumbleglobals_separator6",    (! (
+												(
+													(! StumbleGlobals.ds.getValue("$show_field")) &&
+													(! StumbleGlobals.ds.getValue("$show_info")) &&
+													(! StumbleGlobals.ds.getValue("$show_referral")) &&
+													(! StumbleGlobals.ds.getValue("$show_tag"))
+												) ||
+												(
+													StumbleGlobals.ds.getValue("$show_field") &&
+													(!StumbleGlobals.ds.getValue("$show_tag"))
+												) ||
+												(! StumbleGlobals.ds.getValue("$show_separators"))
+											   )
+											)
+					  );
+		StumbleGlobals.set_visible("stumbleglobals_aboutme",       StumbleGlobals.ds.getValue("$show_aboutme"));
+		StumbleGlobals.set_visible("stumbleglobals_sites_promo",   false);
+		StumbleGlobals.set_visible("stumbleglobals_video_promo",   false);
+		StumbleGlobals.set_visible("stumbleglobals_page_feature_prompt", false);
+		StumbleGlobals.set_visible("stumbleglobals_filter",        StumbleGlobals.ds.getValue("$show_filter"));
+		StumbleGlobals.set_visible("firstrater",       false);
+		StumbleGlobals.set_visible("stumbleglobals_separator7",    false);
+		StumbleGlobals.set_visible("stumbleglobals_stumble_topic", false);
+		StumbleGlobals.set_visible("stumbleglobals_stumble_topic_menu_left", false);
+		StumbleGlobals.set_visible("stumbleglobals_stumble_topic_menu_right", false);
+		StumbleGlobals.set_visible("stumbleglobals_sponsor",       false);
+		StumbleGlobals.set_visible("stumbleglobals_profile",       StumbleGlobals.ds.getValue("$show_home"));
+		StumbleGlobals.set_visible("stumbleglobals_friends",       StumbleGlobals.ds.getValue("$show_friends"));
+		StumbleGlobals.set_inbox_status((StumbleGlobals.ds.getValue("$newmessage")) ? '2' : '');
+//		StumbleGlobals.set_visible("stumbleglobals_messages",      StumbleGlobals.ds.getValue("$show_messages"));
+		StumbleGlobals.set_visible("stumbleglobals_network",       StumbleGlobals.ds.getValue("$show_legacy_network"));
+		StumbleGlobals.set_visible("stumbleglobals_matches",       StumbleGlobals.ds.getValue("$show_matches"));
+//		StumbleGlobals.set_visible("stumbleglobals_forum",         StumbleGlobals.ds.getValue("$show_legacy_forums"));
+		StumbleGlobals.set_visible("stumbleglobals_groups",        StumbleGlobals.ds.getValue("$show_groups"));
+		StumbleGlobals.set_visible("stumbleglobals_myinfo",        StumbleGlobals.ds.getValue("$show_myinfo"));
+	
+		var mode_ids = [
+					"mode",
+	//				"mode_all",
+					"mode_friends",
+					"mode_news",
+					"mode_photo",
+					"mode_search",
+					"mode_stumblers",
+					"mode_video",
+					"mode_wiki",
+					"mode_more"];
+		var i;
+		for (i = 0; i < mode_ids.length; i++)
+			StumbleGlobals.set_visible("stumbleglobals_" + mode_ids[i], StumbleGlobals.ds.getValue("$show_" + mode_ids[i]));
+		StumbleGlobals.set_visible("stumbleglobals_mode_all", true);
+
+		StumbleGlobals.set_visible("stumbleglobals_recthumbup", StumbleGlobals.ds.getValue("$dd_rec_rating") != 0);
+	}
+}
+
+StumbleGlobals.refresh_dyn_channels = function()
+{
+	StumbleGlobals.invoke_global_event("dyn-channels-dirty", null);
+	
+	if (StumbleGlobals.refreshing_dyn_channels)
+		return;
+	
+	StumbleGlobals.refreshing_dyn_channels = true;
+	
+	setTimeout(
+				function (win) {
+					win.StumbleGlobals.invoke_global_event("update-dyn-channels", null); },
+				500,
+				window);
+}
+
+StumbleGlobals.update_dyn_channels = function()
+{
+	StumbleGlobals.refreshing_dyn_channels = false;
+
+	if (! StumbleGlobals.dyn_channels_dirty)
+		return;
+	
+	if (StumbleGlobals.mode_more_popup_open)
+		return;
+	
+	StumbleGlobals.dyn_channels_dirty = false;
+	
+	var channels = StumbleGlobals.ds.getThruDomainChannels(true);
+	
+	if (! channels)
+	{
+		if (! StumbleGlobals.ds.getValue("#checked_dyn_channels"))
+			StumbleGlobals.check_dyn_channels();
+		return;
+	}
+	
+	var parent = StumbleGlobals.get_element("stumbleglobals_mode");
+	var brother_el = StumbleGlobals.get_element("stumbleglobals_mode_all");
+	var id;
+	var channel_id;
+	var el;
+	var i;
+	for (i = 0; i < channels.length; i++)
+	{
+		channel_id = StumbleGlobals.get_channel_id(channels[i].domain); 
+		id = "stumbleglobals_mode_dyn_" + channel_id;
+		el = StumbleGlobals.get_element(id);
+		if (el)
+			el.parentNode.removeChild(el);
+
+		id = "stumbleglobals_mode_more_" + channel_id;
+		el = StumbleGlobals.get_element(id);
+		if (el)
+			el.parentNode.removeChild(el);
+	}
+	
+	var more_popup = StumbleGlobals.get_element("stumbleglobals_mode_more_popup");
+	while (more_popup.lastChild)
+		more_popup.removeChild(more_popup.lastChild);
+	
+	for (i = 0; i < channels.length; i++)
+	{
+		channel_id = StumbleGlobals.get_channel_id(channels[i].domain); 
+		var icon_url = StumbleGlobals.ds.getResourceURLFromName("favicons", 
+					channel_id + ".ico")
+		
+		id = "stumbleglobals_mode_more_" + channel_id;
+		el = document.createElement("menuitem");
+		el.setAttribute("id", id);
+		el.setAttribute("label", " " + channels[i].name);
+		el.setAttribute("onclick", "StumbleGlobals.handle_domain_mode_click(event, '" + channels[i].domain + "');");
+		el.setAttribute("tooltiptext", "StumbleThru " + channels[i].name);
+		el.setAttribute("class", "menuitem-iconic");
+		el.setAttribute("image", icon_url);
+		more_popup.appendChild(el);
+		
+		if (channels[i].show)
+		{
+			// If they've added a dyn channel button, we don't need to
+			// educate via the info bubble. -- Jw
+			StumbleGlobals.ds.setValue("$shown_thru_domain_info_count", StumbleGlobals.ds.getValue("~shown_thru_domain_info_count_max"));
+			
+			id = "stumbleglobals_mode_dyn_" + channel_id;
+			el = document.createElement("toolbarbutton");
+			el.setAttribute("id", id);
+			el.setAttribute("class", "su-hidetext");
+			el.setAttribute("stumbleglobals_ismode", "1");
+			el.setAttribute("onclick", "StumbleGlobals.handle_domain_mode_click(event, '" + channels[i].domain + "');");
+			el.setAttribute("tooltiptext", "StumbleThru " + channels[i].name);
+			el.setAttribute("image", icon_url);
+			parent.insertBefore(el, brother_el);
+			StumbleGlobals.set_image(id, icon_url);
+		}
+	}
+	StumbleGlobals.refreshing_dyn_channels = false;
+	StumbleGlobals.update_thru_domain(StumbleGlobals.get_browser_url(), null, null, null, true);
+	StumbleGlobals.reflow_toolbar(14);
+}
+
+// used by move_toolbar() to initialize splitters
+StumbleGlobals.init_splitters = function()
+{
+	try {
+	var sidebar_splitter = StumbleGlobals.get_element("sidebar-splitter");
+	
+	if (sidebar_splitter)
+	{
+		sidebar_splitter.addEventListener("DOMAttrModified", StumbleGlobals.handle_sidebar_attr_modified, false);
+		sidebar_splitter.addEventListener("mouseup", StumbleGlobals.handle_sidebar_mouseup, false);
+	}
+	
+	var width = StumbleGlobals.ds.getValue("@search-width");
+	if (width == 0)
+	{
+		width = 156;
+		StumbleGlobals.ds.setValue("@search-width", width);
+	}
+	if (width > 400)
+	{
+		width = 400;
+		StumbleGlobals.ds.setValue("@search-width", width);
+	}
+	StumbleGlobals.get_element("stumbleglobals_field").setAttribute("width", width + "px");
+
+	StumbleGlobals.get_element("stumbleglobals_splitter_first_flexbox").collapsed = false;
+
+	setTimeout(function (win) { win.StumbleGlobals.refresh_splitters(true); }, 0, window);
+	} catch (e) { StumbleGlobals.log_error("INIT SPLITTERS", e, StumbleGlobals.ds.getValue("@toolbar-position"), StumbleGlobals.ds.getValue("@position-group")); }
+}	
+
+// used during init to initialize globals and to survey existing 
+// keybindings
+StumbleGlobals.init_keybinding_globals = function()
+{
+	StumbleGlobals.init_key_const_dictionaries();
+
+	var keys = document.getElementsByTagName("key");
+	
+	for (var i = 0; i < keys.length; i++)
+		StumbleGlobals.keys_by_keyspec[StumbleGlobals.get_keyspec_from_key(keys[i])] = keys[i];
+}
+
+// used by init_keybinding_globals to populate
+// StumbleGlobals.keyids_by_eventkeycode, StumbleGlobals.chars_by_keyid and StumbleGlobals.keyids_by_char
+StumbleGlobals.init_key_const_dictionaries = function()
+{
+	var keyid;
+	var property;
+	for (property in KeyEvent)
+	{
+		if (StumbleGlobals.is_property_garbage(KeyEvent, property))
+			continue;
+		
+		keyid = property.replace("DOM_","");
+		StumbleGlobals.keyids_by_eventkeycode[KeyEvent[property]] = keyid;
+		if (keyid.length == 4)
+			StumbleGlobals.chars_by_keyid[keyid] = String.fromCharCode(KeyEvent[property]);
+	}
+	StumbleGlobals.keyids_by_eventkeycode[8] = "VK_BACK";
+	
+	var o = StumbleGlobals.chars_by_keyid;	
+	o["VK_SEMICOLON"] = ";";
+	o["VK_EQUALS]"] = "=";
+	o["VK_MULTIPLY"] = "*";
+	o["VK_ADD"] = "+";
+	o["VK_SUBTRACT"] = "-";
+	o["VK_DECIMAL"] = ".";
+	o["VK_DIVIDE"] = "/";
+	o["VK_COMMA"] = ",";
+	o["VK_PERIOD"] = ".";
+	o["VK_SLASH"] = "/"; // overwrites VK_DIVIDE in StumbleGlobals.keyids_by_char
+	o["VK_BACK_QUOTE"] = "`";
+	o["VK_OPEN_BRACKET"] = "[";
+	o["VK_BACK_SLASH"] = "\\";
+	o["VK_CLOSE_BRACKET"] = "]";
+	o["VK_QUOTE"] = '"';
+
+	StumbleGlobals.keyids_by_char = StumbleGlobals.invert_dictionary(StumbleGlobals.chars_by_keyid);
+}
+
+// used by init_keybinding_globals to get the keyspec from a key 
+// element
+StumbleGlobals.get_keyspec_from_key = function(key)
+{
+  var str = "";
+
+	var modifiers = key.getAttribute("modifiers").toLowerCase();
+
+	if (modifiers.indexOf("alt") != -1)     str += "Alt+";
+	if (modifiers.indexOf("control") != -1) str += "Ctrl+";
+	if (modifiers.indexOf("meta") != -1)    str += "Command+";
+	if (modifiers.indexOf("accel") != -1)
+	{
+		if (StumbleGlobals.host.mac)
+			str += "Command+";
+		else
+			str += "Ctrl+"
+	}
+	if (modifiers.indexOf("shift") != -1)   str += "Shift+";
+
+	var keyid;
+	if (key.hasAttribute("key") && (key.getAttribute("key").length == 1))
+	{
+		keyid = key.getAttribute("key").toUpperCase();
+		var keyid_tmp = StumbleGlobals.keyids_by_char[keyid];
+		if (keyid_tmp)
+			keyid = keyid_tmp;
+	}
+	else if (key.hasAttribute("keycode"))
+	{
+		keyid = key.getAttribute("keycode");
+	}
+	
+	if (! keyid)
+		keyid = "";
+	
+	str += keyid;
+
+	return str;
+}
+
+// called by the global configure-toolbar event and during init
+// to update the key bindings
+StumbleGlobals.refresh_keybindings = function()
+{
+	// It would be more friendly to other extensions if we'd add key
+	// elements rather than attach a keyup listener to the window.
+	// But we have to use a keyup listener in order to distinguish
+	// between 'numeral keys on the number row' and 'numeral keys on 
+	// the numeric keypad w/ numlock turned on'.  This is necessary to
+	// avoid a conflict between binding Alt+VK_1 and typing a special
+	// character via Alt+[keycode] using the numeric keypad on XP.
+	// We're supposed to be able to distinguish between the number row
+	// and the keypad keys using different keycodes (i.e. VK_1 vs 
+	// VK_NUMPAD1) [1], but if one of those keycodes is specified on a 
+	// key element, its command is never invoked (ref Firefox 1.5, XP).
+	// -- JW
+	// [1]
+	// http://www.xulplanet.com/tutorials/xultu/keyshort.html
+	
+	var stumble_default;
+	var reviews_default;
+	var thumbup_default;
+	var thumbdown_default;
+	var tag_default;
+	var toolbar_default;
+	var referrals_default = "";
+	
+	if (StumbleGlobals.host.mac)
+	{
+		stumble_default = "Alt+VK_ESCAPE";
+		thumbup_default = "Alt+VK_F1";
+		thumbdown_default = "Alt+VK_F2";
+		tag_default =     "ALT+VK_SLASH";
+		reviews_default = "Alt+VK_F3";
+//		details_default = "Alt+VK_F4";
+		toolbar_default = "Command+VK_F11";
+	}
+	else if (StumbleGlobals.host.win)
+	{
+		stumble_default = "Alt+VK_BACK_QUOTE";
+		thumbup_default = "Alt+VK_1";
+		thumbdown_default = "Alt+VK_2";
+		tag_default =     "ALT+VK_SLASH";
+		reviews_default = "Alt+VK_3";
+		//		details_default = "Alt+VK_4";
+		toolbar_default = "Ctrl+VK_F11";
+	}
+	else
+	{
+		stumble_default = "Alt+VK_ESCAPE";
+		thumbup_default = "Alt+VK_F1";
+		thumbdown_default = "Alt+VK_F2";
+		tag_default =     "ALT+VK_SLASH";
+		reviews_default = "Alt+VK_F3";
+//		details_default = "Alt+VK_F4";
+		toolbar_default = "Ctrl+VK_F11";
+	}
+	var keyspecs = new Array();
+	StumbleGlobals.commands_by_keyspec = new Object();
+	var keyspec;
+	
+	var rating_enabled = StumbleGlobals.ds.getValue("$shortcuts_enabled");
+	
+	keyspec = StumbleGlobals.ds.getPrefValue("$shortcut_stumble", stumble_default);
+	if (rating_enabled && (keyspec != ""))
+	{
+		keyspecs.push(keyspec);
+		StumbleGlobals.commands_by_keyspec[keyspec] = StumbleGlobals.get_element("StumbleUpon:Stumble");
+	}
+
+	keyspec = StumbleGlobals.ds.getPrefValue("$shortcut_thumbup", thumbup_default);
+	if (rating_enabled && (keyspec != ""))
+	{
+		keyspecs.push(keyspec);
+		StumbleGlobals.commands_by_keyspec[keyspec] = StumbleGlobals.get_element("StumbleUpon:RateThumbup");
+	}
+
+	keyspec = StumbleGlobals.ds.getPrefValue("$shortcut_thumbdown", thumbdown_default);
+	if (rating_enabled && (keyspec != ""))
+	{
+		keyspecs.push(keyspec);
+		StumbleGlobals.commands_by_keyspec[keyspec] = StumbleGlobals.get_element("StumbleUpon:RateThumbdown");
+	}
+
+	keyspec = StumbleGlobals.ds.getPrefValue("$shortcut_tag", tag_default);
+	if (rating_enabled && (keyspec != ""))
+	{
+		keyspecs.push(keyspec);
+		StumbleGlobals.commands_by_keyspec[keyspec] = StumbleGlobals.get_element("StumbleUpon:Tag");
+	}
+
+	keyspec = StumbleGlobals.ds.getPrefValue("$shortcut_reviews", reviews_default);
+	if (rating_enabled && (keyspec != ""))
+	{
+		keyspecs.push(keyspec);
+		StumbleGlobals.commands_by_keyspec[keyspec] = StumbleGlobals.get_element("StumbleUpon:ViewReviews");
+	}
+	
+	keyspec = StumbleGlobals.ds.getPrefValue("$shortcut_referrals", referrals_default);
+	if (rating_enabled && (keyspec != ""))
+	{
+		keyspecs.push(keyspec);
+		StumbleGlobals.commands_by_keyspec[keyspec] = StumbleGlobals.get_element("StumbleUpon:ViewReferrals");
+	}
+
+//	keyspec = StumbleGlobals.ds.getPrefValue("$shortcut_details", details_default);
+//	if (rating_enabled && (keyspec != ""))
+//	{
+//		keyspecs.push(keyspec);
+//		StumbleGlobals.commands_by_keyspec[keyspec] = StumbleGlobals.get_element("StumbleUpon:RateThumbupDetailed");
+//	}
+
+	keyspec = StumbleGlobals.ds.getPrefValue("$shortcut_toolbar", toolbar_default);
+	if (keyspec != "")
+	{
+		keyspecs.push(keyspec);
+		StumbleGlobals.commands_by_keyspec[keyspec] = StumbleGlobals.get_element("StumbleUpon:ToggleToolbar");
+	}
+
+	if (StumbleGlobals.ds.getValue("$shortcut_toolbar") != toolbar_default)
+	{
+		var toggle_key = StumbleGlobals.get_element("key_StumbleUpon:ToggleToolbar");
+		
+		if (toggle_key.hasAttribute("command"))
+		{
+			toggle_key.setAttribute("savedcommand", toggle_key.getAttribute("command"));
+			toggle_key.removeAttribute("command");
+		}
+	}
+
+	if (StumbleGlobals.get_element("stumbleupon"))
+	{
+		var toolbar_keyspec = StumbleGlobals.ds.getValue("$shortcut_toolbar");
+		if (toolbar_keyspec == "")
+		{
+			StumbleGlobals.get_element("stumbleupon").setAttribute("toolbarname", "StumbleUpon Toolbar");
+		}
+		else
+		{
+			StumbleGlobals.get_element("stumbleupon").setAttribute("toolbarname", "StumbleUpon Toolbar (" + 
+						StumbleGlobals.get_display_keyspec(StumbleGlobals.ds.getValue("$shortcut_toolbar")) + 
+						")");
+		}
+	}
+
+	for (keyspec in StumbleGlobals.removed_keybindings_by_keyspec)
+	{
+		if (StumbleGlobals.is_property_garbage(StumbleGlobals.removed_keybindings_by_keyspec, keyspec))
+			continue;
+		
+		if (StumbleGlobals.removed_keybindings_by_keyspec[keyspec])
+		{
+			StumbleGlobals.removed_keybindings_by_keyspec[keyspec].alive = false;
+		}
+	}
+	
+	for (var i = 0; i < keyspecs.length; i++)
+	{
+		var key;
+		var binding;
+		if (StumbleGlobals.keys_by_keyspec[keyspecs[i]])
+		{
+			key = StumbleGlobals.keys_by_keyspec[keyspecs[i]];
+			binding = new Object();
+			binding.alive = true;
+			binding.key = key;
+
+			if (key.hasAttribute("command"))
+			{
+				binding.command = key.getAttribute("command");
+				key.removeAttribute("command");
+			}
+
+			if (key.hasAttribute("oncommand"))
+			{
+				binding.oncommand = key.getAttribute("oncommand");
+				key.removeAttribute("oncommand");
+			}
+
+			if (key.hasAttribute("onkeypress"))
+			{
+				binding.onkeypress = key.getAttribute("onkeypress");
+				key.removeAttribute("onkeypress");
+			}
+
+			StumbleGlobals.removed_keybindings_by_keyspec[keyspecs[i]] = binding;
+		}
+	}
+	
+	for (keyspec in StumbleGlobals.removed_keybindings_by_keyspec)
+	{
+		if (StumbleGlobals.is_property_garbage(StumbleGlobals.removed_keybindings_by_keyspec, keyspec))
+			continue;
+		
+		if (StumbleGlobals.removed_keybindings_by_keyspec[keyspec])
+		{
+			var binding = StumbleGlobals.removed_keybindings_by_keyspec[keyspec];
+			
+			if (! binding.alive)
+			{
+				if (binding.command)
+					binding.key.setAttribute("command", binding.command);
+
+				if (binding.oncommand)
+					binding.key.setAttribute("oncommand", binding.oncommand);
+
+				if (binding.onkeypress)
+					binding.key.setAttribute("onkeypress", binding.onkeypress);
+
+				delete StumbleGlobals.removed_keybindings_by_keyspec[keyspec];
+			}
+		}
+	}
+}
+
+// used by refresh_keybindings and the preferenceDialog to convert a
+// keyspec into its readable form
+StumbleGlobals.get_display_keyspec = function(keyspec)
+{
+	var keyid = StumbleGlobals.get_keyid_from_keyspec(keyspec);
+	if (StumbleGlobals.chars_by_keyid[keyid])
+	{
+		var regexp = new RegExp(StumbleGlobals.escape_regexp_chars(keyid) + "$");
+		keyspec = keyspec.replace(regexp, StumbleGlobals.chars_by_keyid[keyid]);
+	}
+	return keyspec.replace("VK_", "").replace(/BACK$/, "BACKSPACE");
+}
+
+// given a keyspec, returns a string that specifies the corresponding
+// modifiers for a key object
+StumbleGlobals.get_modifiers_from_keyspec = function(keyspec)
+{
+	var parts = keyspec.split("+")
+
+	var str = "";
+	for (var i = 0; i < parts.length; i++)
+	{
+		switch (parts[i])
+		{
+			case "Alt":     str += "alt ";     break;
+			case "Ctrl":    str += "control "; break;
+			case "Command": str += "meta ";    break;
+			case "Shift":   str += "shift ";   break;
+		}
+	}
+
+	if (str != "")
+	{
+		str = str.substring(0, str.length);
+	}
+	return str;
+}
+
+// given a keyspec, returns the keyid portion
+StumbleGlobals.get_keyid_from_keyspec = function(keyspec)
+{
+	var parts = keyspec.split("+");
+	if (parts[parts.length - 1] == "")
+		return "+";  // probably cruft -- JW
+	else
+		return parts[parts.length - 1];
+}
+
+StumbleGlobals.handle_content_click = function(event)
+{
+	if (StumbleGlobals.stumbleid == 0)
+		return true;
+	
+	try {
+		if (StumbleGlobals.is_server_page(event.target.href, "login.php?logout=1"))
+		{
+			setTimeout(function() {
+				StumbleGlobals.handle_page_logout_click();
+			}, 0);
+			return StumbleGlobals.cancel_event(event);
+		}
+	} catch (e) {}
+
+	var ondblclick = "";
+	
+	if (event.originalTarget.hasAttribute("ondblclick"))
+		ondblclick = event.originalTarget.getAttribute("ondblclick");
+	
+	var current_page = StumbleGlobals.get_browser_url(event.target.ownerDocument, true);
+	
+	var slq = StumbleGlobals.ds.globals.sluqh[current_page];
+	
+	if (slq && (ondblclick == ""))
+		ondblclick = "slr";
+	
+	if (ondblclick == "")
+		return true;
+	
+	var cancel_click = false;
+
+	if (ondblclick == "stumble_thru")
+		cancel_click = StumbleGlobals.process_stumblethru_click(event);
+	else if(ondblclick == "whitelist_stumbleupon_with_noscript")
+	{
+		var tld = StumbleGlobals.get_tld(current_page);
+		if (tld == StumbleGlobals.servername)
+		{
+			StumbleGlobals.update_noscript_whitelists();
+			cancel_click = true;
+			
+			var ps = StumbleGlobals.get_service(
+						"@mozilla.org/embedcomp/prompt-service;1",
+						"nsIPromptService");
+			
+			ps.alert(window, "StumbleUpon", "NoScript configuration updated.  You may need to refresh the page or try the operation again.");
+		}
+	}
+	else
+		StumbleGlobals.process_slstats_click(event, current_page, ondblclick, ((slq) ? slq : null));
+	
+	if (cancel_click)
+		return StumbleGlobals.cancel_event(event);
+	
+	return true;
+}
+
+StumbleGlobals.process_stumblethru_click = function(event)
+{
+	var target_anchor = StumbleGlobals.get_target_anchor(event.originalTarget, 5);
+	
+	if (! target_anchor)
+		return false;
+	
+	var target = target_anchor.getAttribute("href").toLowerCase();
+	
+	if (target.indexOf("http://www." + StumbleGlobals.servername + "/through.php?") != 0)
+		return false;
+	//!!! add stumblevideo case
+
+	var through_match = target.match(/^http:\/\/[^\/]*\/through.php\?(.+)/);
+	
+	if (! through_match)
+		return false;
+	
+	if (! through_match.length >= 2)
+		return false;
+	
+	if (! StumbleGlobals.ds.getValue("@toolbar-visible"))
+		StumbleGlobals.toggle_toolbar();
+	
+	// parse out arguments			
+	var spliturl = through_match[1].split("&");
+	
+	return StumbleGlobals.process_stumble_now(spliturl)
+}
+
+StumbleGlobals.process_stumble_now = function(args)
+{
+	var topic_function = "";
+	var topic_displayed = "";
+
+	var mode = "";
+	var tag = "";
+	var user = "";
+	var topic = "";
+	
+	for (var i = 0; i < args.length; i++)
+	{
+		var thearg = args[i];
+		var argsplit = thearg.split("=");
+		if (argsplit.length > 1)
+		{
+			var key = decodeURIComponent(argsplit[0]);
+			var value = decodeURIComponent(argsplit[1]);
+	
+			if (key == "mode")
+				mode = value;
+			else if (key == "tag")
+				tag = value;
+			else if (key == "user")
+				user = value;								 		
+			else if (key == "topic")
+				topic = value;
+		}
+	}
+	
+	if (mode == "")
+		return false;
+	
+//						alert("MODE " + mode + " TAG " + tag + " USER " + user + " TOPIC " + topic);	
+	// we have something	
+	// news, all, tag, video, wiki, photo, language, incat	
+
+	StumbleGlobals.unfocus_searchbox(); 
+	
+	// put it in the box
+	StumbleGlobals.get_element("stumbleglobals_searchbox").value=tag;
+	StumbleGlobals.get_element("stumbleglobals_searchbox").removeAttribute("mode");
+	StumbleGlobals.old_search = tag;
+	StumbleGlobals.last_typed_tag = 0;
+	StumbleGlobals.visited_searchbox = 1;
+
+	var category;
+	var label;
+	// select and do it
+	if (mode == "all")
+	{
+		category = 0;
+		label = "All";
+	}
+	else if (mode == "news")
+	{
+		//!!! tagged news?
+		category = "news";
+		label = "News";
+	}
+	else if (mode == "tag" && tag != "")
+	{
+		category = "TAG_" + tag;
+		label = tag;
+	}
+	else if (mode == "user" && user != "" && tag == "")
+	{
+		category = user;
+		label = user;
+	}
+	else if (mode == "user" && user != "" && tag != "")
+	{
+			//!!!!!????
+		category = "USERTAG_" + user + "_" + tag;
+		label = user;
+	}
+	else if (mode == "subscriptions" || mode == "following")
+	{
+		category = 'friends';
+		label = 'Stumblers';
+	}
+	else if (mode == "incat" && topic != "")
+	{
+		category = topic;
+		label = StumbleGlobals.catnames[topic];
+		if(!label)
+		{
+			// Check for a tag as a backup when the topic id does not exist.
+			if(tag)
+			{
+				category = "TAG_" + tag;
+				label = tag;
+			}
+			else
+			{
+				StumbleGlobals.set_location("http://www." + StumbleGlobals.servername + "/tag/");
+				return true;
+			}
+		}
+	}
+	
+	setTimeout(function() {
+		StumbleGlobals.select_topic(category, label, false);
+	}, 0);
+
+	return true;
+}
+
+StumbleGlobals.process_slstats_click = function(event, current_page, ondblclick, slq)
+{
+	var target_anchor = StumbleGlobals.get_target_anchor(event.originalTarget, 5);
+	if (! target_anchor)
+		return;
+
+	if ((! StumbleGlobals.host.sha1) || (! StumbleGlobals.ds.getValue("@enable_slstats")))
+		return;
+	
+	var sldetail = StumbleGlobals.get_search_query_detail(null, current_page);
+	StumbleGlobals.ds.setValue("#sldetail", sldetail); 
+	sldetail.target = target_anchor.getAttribute("href");
+	var slt;
+	if (target_anchor.hasAttribute("slt"))
+		slt = target_anchor.getAttribute("slt");
+	else if (slq)
+		slt = "" + slq + StumbleGlobals.service.getSha1(target_anchor.getAttribute("href"));
+	
+	if (! slt)
+		return;
+	
+	if (typeof(StumbleGlobals.ds.globals.sltih[slt]) == "undefined")
+		return;
+
+	var row = [];
+	var new_row = [];
+	var sli = StumbleGlobals.ds.globals.sltih[slt];
+
+	if (typeof(sli.rowid) != "undefined")
+	{
+		new_row = false;
+		row = StumbleGlobals.ds.selectRow("slclick", "_r", sli.rowid);
+	}
+	else if (sli.detail)
+	{
+		new_row = true;
+		row = sli.detail;
+	}
+	else
+	{
+		new_row = true;
+		row = {};
+		row.q = slq;
+		row.i = sli.i;
+	}
+	
+	switch (ondblclick)
+	{
+		case "slp":
+			row.p = 1;
+			break;
+		case "sln":
+			row.n = 1;
+			break;
+		case "slu":
+			row.u = 1;
+			break;
+		case "slz":
+			row.z = 1;
+			break;
+		case "slr":
+			row.r = 1;
+			break;
+	}
+	
+	if (new_row)
+		sli.rowid = StumbleGlobals.ds.insertRow("slclick", row);
+	else
+		StumbleGlobals.ds.updateRow(row);
+	
+	return;
+}
+
+StumbleGlobals.check_progress_listener = function()
+{
+	// Check whether the datastore object has buffered any errors.
+	setTimeout(function (win) { win.StumbleGlobals.log_error(); }, 0, window);
+	
+	//!!! we have to keep doing this contantly because firefox likes to randomly
+	// drop our addprogresslisteners.  sad but true.
+	
+	// I think the progresslistener gets added to whichever browser
+	// currently has focus in the tabbrowser.  When a browser goes away,
+	// our listener disappears. -- JW 
+	
+	getBrowser().removeProgressListener(StumbleGlobals.downloadProgressListener);
+	getBrowser().addProgressListener(StumbleGlobals.downloadProgressListener);
+
+	// for instances where we still need a load listener ( such as interests_after.php )
+	// we can keep call this without removing it, that is part of the DOM spec
+	window.addEventListener("DOMContentLoaded", StumbleGlobals.on_load_page, true);
+}
+
+StumbleGlobals.add_progress_listener = function()
+{
+	// We need this listener if we have tabs open
+	getBrowser().addProgressListener(StumbleGlobals.downloadProgressListener);
+}
+
+//************** END INITIALIZATION ****************/
+
+//************** MODEL FUNCTIONS *******************/
+
+StumbleGlobals.set_legacy_user_interests = function(str)
+{
+	var blah3 = str.split("|");
+	var blah4 = blah3[1];
+	var blah5 = blah4.split(" ");
+	StumbleGlobals.user_interests = new Array();
+	for (var i = 0; i < blah5.length; i++)
+	{
+		if (blah5[i] != "")
+			StumbleGlobals.user_interests[blah5[i]] = 1;
+	}
+}
+
+StumbleGlobals.set_user_interests = function(str)
+{
+	var parts = str.split(" ");
+	var i;
+	StumbleGlobals.user_interests = new Array();
+	for (i = 0; i < parts.length; i++)
+	{
+		if (parts[i] == "")
+			continue;
+		
+		if (! parseInt(parts[i]))
+			continue;
+		
+		StumbleGlobals.user_interests[parts[i]] = 1;
+	}
+}
+
+StumbleGlobals.store_user_interests = function()
+{
+	var towrite = "";
+	var first = 0;
+	for (var ii in StumbleGlobals.user_interests)
+	{
+		if (StumbleGlobals.is_property_garbage(StumbleGlobals.user_interests, ii))
+			continue;
+		
+		if (first == 0)
+			first = 1;
+		else
+			towrite += " ";
+		towrite += ii + " ";
+	}
+	StumbleGlobals.ds.setValue("$interests", towrite);
+	StumbleGlobals.ds.flushPrefs();
+}
+
+StumbleGlobals.legacy_interests_after_page = function(doc)
+{
+	var el = doc.getElementById("interests");
+	if (! el)
+		return;
+	
+	StumbleGlobals.set_legacy_user_interests(el.innerHTML);
+	StumbleGlobals.store_user_interests();
+	
+	StumbleGlobals.refresh_category_selector_batched();
+	
+	StumbleGlobals.clear_stumbles();
+}
+
+StumbleGlobals.interests_page = function(doc)
+{
+	var el = doc.getElementById("topic_list");
+
+	if (! el)
+		return;
+	
+	StumbleGlobals.process_topic_list(el.innerHTML);
+}
+
+StumbleGlobals.prefs_page = function(doc)
+{
+	var el;
+	
+	el = doc.getElementById("changePassword");
+	
+	if (! el)
+		return;
+	
+	try {
+		el.wrappedJSObject.addEventListener(
+				"click",
+				StumbleGlobals.handle_change_password,
+				false);
+	} catch (e) {}
+}
+
+StumbleGlobals.tag_page = function(doc)
+{
+	var el;
+	
+	el = doc.getElementById("thumbup");
+	if (el)
+	{
+		try {
+			el.wrappedJSObject.addEventListener(
+					"click",
+					StumbleGlobals.handle_interests_change_click,
+					false);
+		} catch (e) {}
+	}
+	
+	el = doc.getElementById("thumbdown");
+	if (el)
+	{
+		try {
+			el.wrappedJSObject.addEventListener(
+					"click",
+					StumbleGlobals.handle_interests_change_click,
+					false);
+		} catch (e) {}
+	}
+}
+
+StumbleGlobals.handle_interests_change_click = function()
+{
+	setTimeout(function() {
+		StumbleGlobals.get_interests();
+	}, 1000);
+	
+	setTimeout(function() {
+		StumbleGlobals.get_interests();
+	}, 8000);
+}
+
+StumbleGlobals.portal_http_page = function(doc)
+{
+	var el = doc.getElementById("topic_list");
+	
+	if (! el)
+		return;
+	
+	StumbleGlobals.process_topic_list(el.innerHTML);
+}
+
+StumbleGlobals.process_topic_list = function(str)
+{
+	if (str == StumbleGlobals.ds.getValue("#prev_topic_list"))
+		return;
+		
+	StumbleGlobals.ds.setValue("#prev_topic_list", str);
+
+	StumbleGlobals.set_user_interests(str);
+	StumbleGlobals.store_user_interests();
+	
+	StumbleGlobals.refresh_category_selector_batched();
+	StumbleGlobals.clear_stumbles();
+}
+
+//
+// StumbleGlobals.update_topic_list
+//
+// This is the same as StumbleGlobals.process_topic_list, except it isn't restricted
+// to only running once per session with #prev_topic_list.  To be honest,
+// I'm not sure why that is required, so I've created a new command so
+// topic updates can be driven by the web page via. the suLitebarApi.
+//
+StumbleGlobals.update_topic_list = function(str)
+{
+	StumbleGlobals.set_user_interests(str);
+	StumbleGlobals.store_user_interests();
+	
+	StumbleGlobals.refresh_category_selector_batched();
+	StumbleGlobals.clear_stumbles();
+}
+
+StumbleGlobals.process_friends_command = function(command_str)
+{
+	if (command_str == StumbleGlobals.ds.getValue("#prev_friends"))
+		return;
+	
+	if (StumbleGlobals.ds.getValue("#installing_all_avatars"))
+		return;
+
+	StumbleGlobals.ds.setValue("#prev_friends", command_str);
+	
+	var friends = command_str.split(" ");
+	friends.shift();
+	
+	if(friends.length)
+	{
+		// If they have friends, then show the friends menu.
+		if(!StumbleGlobals.ds.getValue("$show_friends_user_changed"))
+		{
+			StumbleGlobals.ds.setValue("$show_friends", true);
+			StumbleGlobals.set_visible("stumbleglobals_friends", true);
+		}
+	}
+	
+	var i;
+	var contact;
+	var mutuals = new Object();
+	var changed = false;
+	var has_avatars = StumbleGlobals.ds.getValue("$has_avatars");
+	if (! has_avatars)
+		StumbleGlobals.ds.setValue("#installing_all_avatars", true);
+	var contacts = StumbleGlobals.ds.selectAllRows("contact");
+	var new_contacts = new Array();
+	var contacts_by_id = new Object();
+	for (i = 0; i < contacts.length; i++)
+	{
+		if (contacts[i].contactid)
+			contacts_by_id[contacts[i].contactid] = contacts[i];
+	}
+	
+	for (i = 0; i < friends.length; i++)
+	{
+		var nickname = friends[i].split(".")[0];
+		var contactid = friends[i].split(".")[1];
+		mutuals[contactid] = true;
+		
+		contact = null;
+		
+		if (contacts_by_id[contactid])
+			contact = contacts_by_id[contactid];
+			
+		if (contact)
+		{
+			contacts_by_id[contact.contactid] = null;
+			if (contact.contactid != contactid)
+			{
+				changed = true;
+				contact.contactid = contactid;
+			}
+			if (contact.nickname != nickname)
+			{
+				changed = true;
+				contact.nickname = nickname;
+			}
+			if (! contact.mutual)
+			{
+				changed = true;
+				contact.mutual = 1;
+			}
+			if (changed)
+				StumbleGlobals.ds.updateRow(contact);
+			if (! has_avatars)
+				StumbleGlobals.ds.refreshAvatar(contactid);
+			contacts_by_id[contactid] = contact;
+		}
+		else
+		{
+			changed = true;
+			contact = new Object();
+			contact.contactid = contactid;
+			contact.nickname = nickname;
+			contact.mutual = 1;
+			StumbleGlobals.ds.refreshAvatar(contactid);
+			StumbleGlobals.ds.insertRow("contact", contact);
+			contacts_by_id[contactid] = contact;
+		}
+	}
+
+	for (i = 0; i < contacts.length; i++)
+	{
+		if ((typeof (contacts[i])) == "undefined")
+		{
+			StumbleGlobals.log_error("LEGACY FRIENDS");
+			contacts.splice(i, 1);
+			i--;
+			continue;
+		}
+		
+		if ((typeof (contacts[i].contactid)) != "undefined")
+		{
+			if (! mutuals[contacts[i].contactid])
+			{
+				if (contacts[i].mutual)
+				{
+					changed = true;
+					contacts[i].mutual = 0;
+					StumbleGlobals.ds.updateRow(contacts[i]);
+				}
+			}
+		}
+	}
+	
+	if (changed)
+		StumbleGlobals.refresh_referral_menu(1);
+}
+
+/*
+StumbleGlobals.process_fbfriends_command = function(command_str)
+{
+	var friends = command_str.split(" ");
+	friends.shift();
+	
+	var i;
+	var contact;
+	var contacts = StumbleGlobals.ds.selectAllRows("contact");
+	var contacts_by_id = new Object();
+	var fbfriends = new Object();
+	for (i = 0; i < contacts.length; i++)
+	{
+		if (contacts[i].contactid)
+			contacts_by_id[contacts[i].contactid] = contacts[i];
+	}
+	
+	for (i = 0; i < friends.length; i++)
+	{
+		var contactid = friends[i].split(".")[0];
+		var nickname = friends[i].split(".")[1];
+		var facebookid = friends[i].split(".")[2];
+		
+		fbfriends[contactid] = true;
+
+		contact = null;
+		
+		if (contacts_by_id[contactid])
+			contact = contacts_by_id[contactid];
+		
+		if (contact)
+		{
+			contact.nickname = nickname;
+			contact.fbid = facebookid;
+			StumbleGlobals.ds.updateRow(contact);
+		}
+		else
+		{
+			contact = new Object();
+			contact.contactid = contactid;
+			contact.nickname = nickname;
+			contact.fbid = facebookid;
+			StumbleGlobals.ds.insertRow("contact", contact);
+			contacts_by_id[contactid] = contact;
+		}
+	}
+
+	for (i = 0; i < contacts.length; i++)
+	{
+		if ((typeof (contacts[i].contactid)) != "undefined")
+		{
+			if (contacts[i].fbid && (! fbfriends[contacts[i].contactid]))
+				contacts[i].fbid = 0;
+			
+			StumbleGlobals.ds.updateRow(contacts[i]);
+		}
+	}
+}
+*/
+
+//************** END MODEL FUNCTIONS ***************/
+
+
+
+//************** UTILITY FUNCTIONS *****************/
+
+// See global.js for additional utility functions.
+
+StumbleGlobals.is_matching_domain = function(uri, domain, opt_parts_length_offset)
+{
+	var splituri = uri.split("/");
+	
+	if (splituri.length < 3)
+		return false;
+
+	var uri_domains = splituri[2].split(".");
+	var ref_domains = domain.split(".");
+	
+	if ((typeof(opt_parts_length_offset) != "undefined") &&
+				(uri_domains.length - ref_domains.length) != opt_parts_length_offset)
+		return false;
+		
+	else if (uri_domains.length < ref_domains.length)
+		return false;
+
+	var i = ref_domains.length-1;
+	var j = uri_domains.length-1;
+	while (i >= 0)
+	{
+		if (uri_domains[j] != ref_domains[i])
+			return false;
+		i--;
+		j--;
+	}
+	return true;
+}
+
+StumbleGlobals.get_domain = function(opt_url)
+{
+	var url;
+	if (opt_url)
+		url = opt_url;
+	else
+		url = StumbleGlobals.get_browser_url();
+	
+	var url_parts = url.split("/");
+	
+	if (url_parts.length < 3)
+		return "";
+	
+	return url_parts[2];
+}
+
+StumbleGlobals.normalize_tag = function(str)
+{
+	str = str.replace(/\s+/g, " ");
+	str = str.replace(/\s*,+\s*/g, ", ");
+	str = str.replace(/^,/, "");
+	str = str.replace(/,\s$/, "");
+	return str;
+}
+
+StumbleGlobals.is_sound = function(url)
+{
+	// checks to see if url produces sound
+	var last3 = url.substr(url.length-3).toLowerCase();
+	var last4 = url.substr(url.length-4).toLowerCase();
+	var last5 = url.substr(url.length-5).toLowerCase();
+	if (    last3 == ".qt" || last3 == ".ra" || last3 == ".rm" 
+		|| last3 == ".rv" || last3 == ".au" || last3 == ".ul"
+  		|| last4 == ".avi" || last4 == ".asf" || last4 == ".mpg"
+   		|| last4 == ".wmf" || last4 == ".wmv" || last4 == ".wma"
+		|| last4 == ".wav" || last4 == ".mov" || last4 == ".mp3"
+		|| last4 == ".ram" || last4 == ".swf" || last4 == ".mp4"
+		|| last4 == ".mpe" || last4 == ".mpv" || last4 == ".mp2"
+		|| last4 == ".aac" || last4 == ".aif" || last4 == ".mid" 
+		|| last4 == ".ogg" || last4 == ".ogm" || last4 == ".ac3" 
+		|| last4 == ".fla" || last4 == ".awm" || last4 == ".ftk"
+		|| last4 == ".mod" || last4 == ".sid" || last4 == ".nap"
+		|| last4 == ".mmm"
+		|| last5 == ".aiff"
+		|| last5 == ".midi"
+		|| last5 == ".mpeg")
+	{
+		return 1;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+StumbleGlobals.is_url_rateable = function(url, tld)
+{
+	// Not enabled for about:, mailto:, etc.
+	if (!url.match(/^(http|https|ftp):/i))
+		return false;
+
+	// Not enabled for url pages
+	
+	if (url.indexOf(StumbleGlobals.base_url + "url/") == 0 || url.indexOf(StumbleGlobals.base_url + "url.php") == 0)
+		return false;
+	
+	if (url == "http://video." + StumbleGlobals.servername + "/")
+		return false;
+	
+	if (tld)
+		return true;
+	
+	return false;
+}
+
+StumbleGlobals.is_adult_category = function(cat)
+{
+	if (cat == null)
+		return false;
+	
+	cat += "";
+	
+	switch (cat)
+	{
+		case "6":    //  Pornography
+		case "159":  //  Fetish Sexuality
+		case "193":  //  Hentai Anime
+		case "510":  //  Gay Sex
+		case "513":  //  Lesbian Sex
+		case "521":  //  BDSM
+		case "522":  //  Bisexual Sex
+		case "531":  //  Transexual Sex
+			return true;
+			break;
+	}
+	return false;
+}
+
+StumbleGlobals.get_media_specs = function()
+{
+	var specs = new Array();
+	var collection;
+	var i;
+	var doc = getBrowser().contentDocument;
+	
+	collection = doc.getElementsByTagName("EMBED");
+	for (i = 0; i < collection.length; i++)
+		specs.push(StumbleGlobals.get_media_spec(collection[i]));
+	
+	collection = doc.getElementsByTagName("OBJECT");
+	for (i = 0; i < collection.length; i++)
+		specs.push(StumbleGlobals.get_media_spec(collection[i]));
+	
+	collection = doc.getElementsByTagName("APPLET");
+	for (i = 0; i < collection.length; i++)
+		specs.push(StumbleGlobals.get_media_spec(collection[i]));
+	
+	collection = doc.getElementsByTagName("img");
+	for (i = 0; i < collection.length; i++)
+	{
+		var spec = StumbleGlobals.get_media_spec(collection[i]);
+		if (spec)
+			specs.push(spec);
+	}
+
+	return specs;
+}
+
+StumbleGlobals.get_media_spec = function(el)
+{
+	var spec = StumbleGlobals.get_property_map(el);
+	
+	spec.tagName = el.tagName.toLowerCase();
+
+	if (el.boxObject)
+	{
+		spec.width = el.boxObject.width;
+		spec.height = el.boxObject.height;
+		spec.top = el.boxObject.top;
+	}
+	else
+	{
+		spec.width = 0;
+		spec.height = 0;
+		spec.top = 0;
+	}
+
+	if (spec.tagName == "img")
+	{
+		var area = spec.width * spec.height;
+		if (area > 70000)
+			return spec;
+		else
+			return null;
+	}
+
+	if (spec.type)
+		return spec;
+	
+	if ((spec.tagName == "applet") || 
+				(spec.code && (spec.code.indexOf(".class") != -1)))
+		spec.type = "application/x-java-applet";
+
+	else if ((spec.src && (spec.src.indexOf(".swf") != -1)) || 
+				(spec.movie && (spec.movie.indexOf(".swf") != -1)))
+		spec.type = "application/x-shockwave-flash";
+
+	return spec;
+}
+
+StumbleGlobals.get_property_map = function(el)
+{
+	var map = new Object();
+	var i;
+	for (i = 0; i < el.attributes.length; i++)
+	{
+		// Add properties representing attributes. -- JW
+		map[el.attributes.item(i).nodeName.toLowerCase()] = el.attributes.item(i).nodeValue;
+	}
+	
+	var children = el.childNodes;
+	for (i = 0; i < children.length; i++)
+	{
+		// Add properties representing param entities. -- JW
+		if (children[i].tagName != "PARAM")
+			continue;
+		
+		if (children[i].hasAttribute("name") && children[i].hasAttribute("value"))
+			map[children[i].getAttribute("name").toLowerCase()] = children[i].getAttribute("value");
+	}
+	return map;
+}
+
+StumbleGlobals.get_target_anchor = function(el, search_depth)
+{
+	var found_el = null;
+	var i;
+	for (i = 0; i < search_depth; i++)
+	{
+		if (el.tagName && (el.tagName == "A"))
+		{
+			found_el = el;
+			break;
+		}
+		if (el.parentNode)
+			el = el.parentNode;
+		else
+			break;
+	}
+	return found_el;
+}
+
+StumbleGlobals.get_ancestor_by_prop_value = function(el, prop_name, prop_value, search_depth)
+{
+	var found_el = null;
+	var i;
+	for (i = 0; i < search_depth; i++)
+	{
+		if (el.parentNode)
+			el = el.parentNode;
+		else
+			break;
+		
+		if (el[prop_name] == prop_value)
+		{
+			found_el = el;
+			break;
+		}
+	}
+	return found_el;
+}
+
+StumbleGlobals.is_mutual_friend = function(nickname)
+{
+	if (! nickname)
+		return false;
+	
+	nickname += "";
+	
+	if (nickname == "")
+		return false;
+	
+	var query = nickname.toLowerCase();
+	
+	var contacts = StumbleGlobals.ds.selectAllRows("contact");
+	var found = false;
+	var i;
+	for (i = 0; i < contacts.length; i++)
+	{
+		if ((contacts[i].nickname) && 
+					(contacts[i].mutual) &&
+					(contacts[i].nickname.toLowerCase() == query))
+		{
+			found = true;
+			break;
+		}
+	}
+	
+	return found;
+}
+
+StumbleGlobals.prefix_article = function(str)
+{
+	if (! str)
+		return "";
+	
+	if (str == "")
+		return "";
+	
+	var chr = str.charAt(0).toLowerCase();
+	
+	var article;
+	switch (chr)
+	{
+		case "a":
+		case "e":
+		case "i":
+		case "o":
+		case "u":
+			article = "an";
+			break;
+		default:
+			article = "a";
+			break;
+	}
+	
+	return article + " " + str;
+}
+
+StumbleGlobals.new_tab = function(event)
+{
+	if (! event)
+		return false;
+	
+	var platform_ctrl_key = (StumbleGlobals.host.mac) ? event.metaKey : event.ctrlKey;
+	var new_tab = false;
+	if (event.button == 1 || (event.button == 0 && platform_ctrl_key))
+		new_tab = true;
+	return new_tab;
+}
+
+StumbleGlobals.is_about_blank = function()
+{
+	var doc = getBrowser().contentDocument;
+	if(doc && (doc.location.toString() == "about:blank"))
+		return true;
+	else
+		return false;
+}	
+		
+StumbleGlobals.cancel_event = function(event)
+{
+	event.stopPropagation();
+	if (event.cancelable)
+		event.preventDefault();			
+	event.cancelBubble = true;
+	return false;
+}
+
+// returns the number of browser windows
+StumbleGlobals.get_browser_window_count = function()
+{
+	var enumerator = StumbleGlobals.get_service(
+				"@mozilla.org/appshell/window-mediator;1",
+				"nsIWindowMediator")
+				.getEnumerator("navigator:browser");
+	
+	var count = 0;
+	while (enumerator.hasMoreElements())
+	{
+		count++;
+		enumerator.getNext();
+	}
+	return count;
+}
+
+StumbleGlobals.get_rdf_resource = function(resource_id)
+{
+	return StumbleGlobals.get_service(
+				"@mozilla.org/rdf/rdf-service;1",
+				"nsIRDFService")
+				.GetResource(resource_id)
+				.QueryInterface(Components.interfaces.nsIRDFResource)
+}
+
+StumbleGlobals.get_rdf_arc_literal = function(datasource, element, arc_id)
+{
+	try {
+		var arc = StumbleGlobals.get_rdf_resource(arc_id);
+					
+		element.QueryInterface(Components.interfaces.nsIRDFResource);
+		
+		var target = datasource.GetTarget(element, arc ,true);
+		if (target)
+			return target.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
+	} catch (e) {}
+	return null;
+}
+
+StumbleGlobals.get_rdf_arc_int = function(datasource, element, arc_id)
+{
+	try {
+		var arc = StumbleGlobals.get_rdf_resource(arc_id);
+					
+		element.QueryInterface(Components.interfaces.nsIRDFResource);
+		
+		var target = datasource.GetTarget(element, arc ,true);
+		if (target)
+			return target.QueryInterface(Components.interfaces.nsIRDFInt).Value;
+	} catch (e) {}
+	return null;
+}
+
+// returns a mime input stream, used primarily for wrapping POST data
+StumbleGlobals.get_mime_input_stream = function(str, content_type)
+{
+  var data_stream = StumbleGlobals.create_instance(
+				"@mozilla.org/io/string-input-stream;1",
+				"nsIStringInputStream");
+  data_stream.setData(str, str.length);
+
+  var mime_stream = StumbleGlobals.create_instance(
+				"@mozilla.org/network/mime-input-stream;1",
+				"nsIMIMEInputStream");
+  mime_stream.addHeader("Content-Type", content_type);
+  mime_stream.addContentLength = true;
+  mime_stream.setData(data_stream);
+  return mime_stream.QueryInterface(Components.interfaces.nsIInputStream);
+}
+
+StumbleGlobals.get_browser_url = function(opt_doc, opt_raw)
+{
+	var doc = (opt_doc) ? opt_doc : getBrowser().contentDocument;
+	var url = doc.location.toString();
+	if (url.indexOf("chrome://ietab/content/reloaded.html?url=") == 0)
+		url = url.substr(41);
+	
+	if (opt_raw)
+		return url;
+	
+	if (StumbleGlobals.is_matching_domain(url, "video." + StumbleGlobals.servername))
+	{
+		var detail = StumbleGlobals.get_stumblevideo_detail(doc);
+		if (detail)
+			url = detail.url;
+	}
+	
+	return url;
+}
+
+StumbleGlobals.get_browser_referrer_url = function(opt_doc, opt_raw)
+{
+	var doc = (opt_doc) ? opt_doc : getBrowser().contentDocument;
+	var url = doc.referrer.toString();
+	if (url.indexOf("chrome://ietab/content/reloaded.html?url=") == 0)
+		url = url.substr(41);
+	
+	if (opt_raw)
+		return url;
+	
+//	if (StumbleGlobals.is_matching_domain(url, "video." + StumbleGlobals.servername))
+//	{
+//		var detail = StumbleGlobals.get_stumblevideo_detail(doc);
+//		if (detail)
+//			url = detail.url;
+//	}
+	
+	return url;
+}
+
+StumbleGlobals.dispatch_click = function(doc, id)
+{
+	var el = doc.getElementById(id);
+	if (! el)
+		return;
+
+	var evt = doc.createEvent("MouseEvent");
+	evt.initMouseEvent(
+				"click",
+				true,
+				true,
+				doc.defaultView,
+				1,
+				0, // screenX
+				0, // screenY
+				0, // clientX
+				0, // clientY
+				false,
+				false,
+				false,
+				false,
+				0,
+				null);
+	el.dispatchEvent(evt);
+}
+
+/*
+StumbleGlobals.dispatch_mouseover = function(doc, id)
+{
+	var el = doc.getElementById(id);
+	if (! el)
+		return;
+
+	var evt = doc.createEvent("MouseEvent");
+	evt.initMouseEvent(
+				"mouseover",
+				true,
+				true,
+				doc.defaultView,
+				1,
+				0, // screenX
+				0, // screenY
+				0, // clientX
+				0, // clientY
+				false,
+				false,
+				false,
+				false,
+				0,
+				null);
+	el.dispatchEvent(evt);
+}
+*/
+
+StumbleGlobals.DEBUG_ENABLED = true;
+
+/*
+StumbleGlobals.insert_before = function(parent, new_el, after_el)
+{
+	if (parent && after_el && after_el.parentNode && (after_el.parentNode == parent))
+		after_el.insertBefore(new_el, after_el.nextSibling);
+	else if (parent)
+		parent.appendChild(new_el);
+}
+*/
+
+StumbleGlobals.get_element = function(id)
+{
+	return document.getElementById(id);
+}
+
+// When doing a 'for ([prop] in [obj])', use this to verify that the
+// property isn't pollution from another extension.
+StumbleGlobals.is_property_garbage = function(obj, prop)
+{
+	return ((typeof (obj[prop])) == "function");
+}
+
+StumbleGlobals.invert_dictionary = function(dict)
+{
+	var out = new Object();
+
+	var key;
+	for (key in dict)
+	{
+		if (StumbleGlobals.is_property_garbage(dict, key))
+			continue;
+		
+		out[dict[key]] = key; 
+	}
+
+	return out;
+}
+
+StumbleGlobals.log_dd_uc = function(unseen)
+{
+	if (	StumbleGlobals.ds.lookup("userid:uc_logger_flag", StumbleGlobals.stumbleid) ||
+				StumbleGlobals.ds.getValue("@dd_uc"))
+	{
+		var str = " " + StumbleGlobals.ds.getValue("@dd_uc_server") + " " + unseen + "\n";
+		StumbleGlobals.ds.writeFile(
+					StumbleGlobals.ds.getLegacyNSIFile("stumbledd"),
+					(StumbleGlobals.ds.getTimestampStr(0) + str),
+					true);
+		StumbleGlobals.ds.writeFile(
+					StumbleGlobals.ds.getLegacyNSIFile("stumbleddw"),
+					(StumbleGlobals.ds.getTimestampStr(1) + str),
+					true);
+	}
+}
+
+StumbleGlobals.get_time_s = function()
+{
+	return Math.floor((new Date()).getTime() / 1000);
+}
+
+StumbleGlobals.trim = function(str)
+{
+	return str.replace(/^\s*|\s*$/g,"");
+}
+
+StumbleGlobals.escape_regexp_chars = function(str)
+{
+	return str.replace(/([\\\^\*\+\?\.\(\)\|\{\}\[\]])/g, "\\$1");
+}
+
+StumbleGlobals.clone = function(obj)
+{
+	return StumbleGlobals.ds.deserialize(StumbleGlobals.ds.serialize(obj, false));
+}
+
+// append request param
+StumbleGlobals.arp = function(param_str, name, value, opt_get_flag)
+{
+	var delimiter;
+	if (opt_get_flag && (param_str.indexOf("&") == -1) &&
+				(param_str.indexOf("?") == -1))
+		delimiter = "?";
+	else
+		delimiter = "&";
+	
+	return param_str + ((param_str == "") ? "" : delimiter) + name + "=" + 
+				encodeURIComponent(value);
+}
+
+StumbleGlobals.build_request_param_string = function(spec)
+{
+	var str = "";
+	var name;
+	for (name in spec)
+	{
+		if (StumbleGlobals.is_property_garbage(spec, name))
+			continue;
+		
+		str += ((str == "") ? "" : "&") + name + "=" + 
+				encodeURIComponent(spec[name]);
+	}
+	return str;
+}
+
+StumbleGlobals.create_instance = function(nsclass, nsinterface)
+{
+	try {
+		return Components.classes[nsclass]
+					.createInstance(Components.interfaces[nsinterface]);
+	}
+	catch (e) {
+		return null;
+	}
+}
+
+// returns an nsIURI object for the specified uri
+StumbleGlobals.get_nsiuri = function(uri_str)
+{
+	var uri = StumbleGlobals.create_instance(
+				"@mozilla.org/network/standard-url;1",
+				"nsIURI");
+	uri.spec = uri_str;
+	return uri;
+}
+
+// writes all arguments to a console message
+StumbleGlobals.dd = function()
+{
+	if (! StumbleGlobals.DEBUG_ENABLED)
+		return;
+
+	StumbleGlobals.service.dd.apply(StumbleGlobals.service, arguments);
+}
+
+StumbleGlobals.ddf = function()
+{
+	StumbleGlobals.service.ddf.apply(StumbleGlobals.service, arguments);
+}
+
+window.StumbleGlobals.log = StumbleGlobals.dd;
+
+window.StumbleGlobals.logf = StumbleGlobals.ddf;
+
+// writes all properties of an object to a console message
+StumbleGlobals.dump_object = function(o)
+{
+	var str = "";
+	var p;
+	
+	for (p in o)
+	{
+		try {
+			str += "[" + p + "]\n" + o[p] + "\n\n";
+		}
+		catch (e) {
+			str += "[" + p + "] ERROR\n" + e + "\n\n";
+		}
+	}
+	StumbleGlobals.log(str);
+}
+
+// send a notification to the event_observer for each window
+StumbleGlobals.invoke_global_event = function(event_id, detail, from)
+{
+	if (event_id == "update-referral-menu")
+	{
+		StumbleGlobals.ds.flushPrefs();
+	}
+	else if ((event_id == "login") && detail && (! detail.skip_cookies)
+			&& detail.ignore_cookies)
+	{
+		StumbleGlobals.process_cookies(true);
+		detail.skip_cookies = true;
+	}
+	
+	StumbleGlobals.get_service(
+				"@mozilla.org/observer-service;1",
+				"nsIObserverService")
+				.notifyObservers(null, "stumbleglobals_" + event_id, StumbleGlobals.ds.serialize(detail));
+}
+
+//************** END UTILITY FUNCTIONS ***************/
+
+
+//******** FILE FUNCTIONS **********//
+
+//
+// Note:  This code includes the ability to fallback to user prefs for file storage.
+//        But since prefs are written frequently, useFailsafe should NOT be used except
+//        when reading / writing very small files.
+//
+StumbleGlobals._read_file_user = function(fname, useFailsafe)
+{
+	// We fall back to using prefs if they have asked for it for this specific
+	// operation, _and_ a previous file write operation failed _and_ the failsafe
+	// option is enabled.
+	//
+	if(useFailsafe &&
+	   StumbleGlobals.ds.getValue("@userfile_write_failed") &&
+	   StumbleGlobals.ds.getValue("@enable_userfile_failsafe"))
+	{
+		// A previous write failed, so we are using prefs.
+		var result = StumbleGlobals.ds.getPrefValue("$file_" + fname + "_failsafe", "");
+		return result;
+	}
+	else
+	{
+		return StumbleGlobals.ds.readFile(StumbleGlobals.ds.getLegacyNSIFile(fname));
+	}
+}
+
+StumbleGlobals._write_file_user = function(fname, data, useFailsafe)
+{
+	if(useFailsafe &&
+	   StumbleGlobals.ds.getValue("@userfile_write_failed") &&
+	   StumbleGlobals.ds.getValue("@enable_userfile_failsafe"))
+	{
+		// If we have failed writing to the filesystem, then we failover
+		// to using prefs for our user data storage.
+		StumbleGlobals.ds.setValue("$file_" + fname + "_failsafe", data);
+		StumbleGlobals.ds.flushPrefs();
+	}
+	else
+	{
+		try
+		{
+			// Try the normal file operation.
+			var file = StumbleGlobals.ds.getLegacyNSIFile(fname);
+			StumbleGlobals.ds.writeFile(file, data);
+			var result = StumbleGlobals.ds.readFile(file);
+			if(result != data)
+			{
+				// This is a ZoneAlarm ForceField hack.  ForceField causes file writes to fail
+				// silently, so we double-check whether the write succeeded and throw our own error
+				// on failure.
+				throw "Data is different";
+			}
+		}
+		catch(ex)
+		{
+			StumbleGlobals.log_error("USERFILE FAILURE: " + ex);
+			StumbleGlobals.ds.setValue("$file_" + fname + "_failsafe", data);
+			StumbleGlobals.ds.setValue("@userfile_write_failed", true);
+			StumbleGlobals.ds.flushPrefs();
+		}
+	}
+}
+
+StumbleGlobals.read_file_user = function(fname)
+{
+	return StumbleGlobals._read_file_user(fname, fname == "stumbleurls");
+}
+
+StumbleGlobals.write_file_user = function(fname, data)
+{
+	StumbleGlobals._write_file_user(fname, data, fname == "stumbleurls");
+}
+		
+//***************** END FILE FUNCTIONS ******************//
+
+
+//***************** GUI HANDLERS ************************//
+
+// deals with interests if you select it from the menu item add more interests...
+StumbleGlobals.interests_pre = function()
+{
+	StumbleGlobals.interests();
+	StumbleGlobals.set_mode_all();
+}
+
+
+//!!! We probably ought to combine StumbleGlobals.handle_mode_click and
+//    StumbleGlobals.select_topic, but to mitigate risk, this change is deferred
+//    until after 3.0. -- JW
+StumbleGlobals.handle_mode_click = function(event, mode)
+{
+	var new_tab = StumbleGlobals.new_tab(event);
+	
+	var tag;
+	switch (mode)
+	{
+		case "All":
+			StumbleGlobals.select_topic(0, mode, new_tab);
+			break;
+		case "Videos":
+			StumbleGlobals.select_topic("video", mode, new_tab);
+			break;
+		case "Photos":
+			StumbleGlobals.select_topic(302, mode, new_tab);
+			break;
+		case "Friends":
+			StumbleGlobals.select_topic("friends", mode, new_tab);
+			break;
+		case "Profiles":
+			StumbleGlobals.select_topic(44, mode, new_tab);
+			break;
+		case "Search":
+			new_tab = new_tab || StumbleGlobals.ds.getValue("$search_new_window");
+			setTimeout(function() {
+				StumbleGlobals.show_search_dialog(new_tab);
+			}, 0);
+			break;
+		case "News":
+			StumbleGlobals.select_topic("news", mode, new_tab);
+			break;
+		case "Wiki":
+			StumbleGlobals.select_topic("wiki", mode, new_tab);
+			break;
+		default:
+			StumbleGlobals.select_topic(mode, mode, new_tab);
+			break;
+	}
+}
+
+StumbleGlobals.handle_domain_mode_click = function(event, domain)
+{
+	StumbleGlobals.select_topic("TAG_" + domain, domain, StumbleGlobals.new_tab(event));
+}
+
+StumbleGlobals.select_topic = function(topic, label, new_tab, opt_force_stumble)
+{
+	topic += "";
+	var lang = false;
+	switch (topic)
+	{
+		case "0":
+			StumbleGlobals.set_mode(topic, label, "", "Stumble!", "Show next page");
+			break;
+		case "44":
+			StumbleGlobals.set_mode(topic, label, 
+						"chrome://stumbleupon/content/skin/stumblers.png",
+						"Stumble! ", "Stumble a profile");
+			break;
+		case "302":
+			StumbleGlobals.set_mode(topic, label, 
+						"chrome://stumbleupon/content/skin/icon_tb_photo_hover.png",
+						"Stumble! ", "Stumble a photo");
+			break;
+		case "friends":
+			StumbleGlobals.set_mode(topic, label, 
+						"chrome://stumbleupon/content/skin/icon_tb_people.png",
+						"Stumble! ", "Stumble a favorite");
+			break;
+		case "video":
+			StumbleGlobals.set_mode(topic, label, 
+						"chrome://stumbleupon/content/skin/video.png",
+						"Stumble! ", "Stumble a video");
+			break;
+		case "news":
+			StumbleGlobals.set_mode(topic, label,
+						"chrome://stumbleupon/content/skin/icon_tb_news.png",
+						"Stumble! ", "Stumble a news item");
+			break;
+		case "wiki":
+			StumbleGlobals.set_mode(topic, label,
+						"chrome://stumbleupon/content/skin/wiki.png",
+						"Stumble! ", "Stumble an article");
+			break;
+		default:
+			if (StumbleGlobals.isInt(topic))
+			{
+				StumbleGlobals.set_mode(topic, label,
+							"chrome://stumbleupon/content/skin/topic.png", 
+							"Stumble! ", "Stumble " + StumbleGlobals.prefix_article(label) + " page");
+			}
+			else if (topic.indexOf("LANG_") == 0)
+			{
+				lang = true;
+				StumbleGlobals.set_mode(topic, label,
+							"chrome://stumbleupon/content/skin/topic.png", 
+							"Stumble! ", "Stumble " + StumbleGlobals.prefix_article(label) + " page");
+			}
+			else if (topic.indexOf("TAG_") == 0)
+			{
+				var tmp_topic = topic.substr(4).toLowerCase();
+				var favicon_url = null;
+				if (StumbleGlobals.ds.isThruDomain(tmp_topic))
+				{
+					// If they've stumbled in a thru domain, we don't need to
+					// educate via an info bubble. -- JW
+//					StumbleGlobals.ds.setValue("$shown_thru_domain_info_count", StumbleGlobals.ds.getValue("~shown_thru_domain_info_count_max"));
+					
+					favicon_url = StumbleGlobals.get_favicon_url(tmp_topic);
+				}
+				
+				if (favicon_url)
+				{
+					StumbleGlobals.set_mode(topic, label, favicon_url,
+								"Stumble! ", "Stumble a page from " + label);
+				}
+				else
+				{
+					StumbleGlobals.set_mode(topic, label,
+								"chrome://stumbleupon/content/skin/search.png",
+								"Stumble! ", "Stumble a '" + label + "' page");
+				}
+			}
+			else if (StumbleGlobals.is_mutual_friend(topic))
+			{
+				StumbleGlobals.set_mode(topic, label,
+							"chrome://stumbleupon/content/skin/mutual_favorites.png",
+							"Stumble! ", "Stumble a favorite from " + label);
+			}
+			else
+			{
+				StumbleGlobals.set_mode(topic, label,
+							"chrome://stumbleupon/content/skin/stumbler_favorites.png",
+							"Stumble! ", "Stumble a favorite from " + label);
+			}
+			break;
+	}
+	
+//	if (! search)
+//	{
+//		StumbleGlobals.get_element("stumbleglobals_searchbox").value = "";
+//		StumbleGlobals.get_element("stumbleglobals_searchbox").removeAttribute("mode");
+//		StumbleGlobals.old_search = "";
+//		StumbleGlobals.last_typed_tag = 0;
+//		StumbleGlobals.visited_searchbox = 1;
+//	}
+
+	if (StumbleGlobals.ds.getValue("$stumble_upon_change") || opt_force_stumble)
+		StumbleGlobals.stumble(new_tab);
+}
+
+StumbleGlobals.backup_places = function(error_label)
+{
+	// Make a snapshot of bookmarks in the standard backup location, but
+	// don't clobber an existing one.
+	try {
+
+	var name; 
+	
+	if(PlacesUtils && PlacesUtils.backups)
+	{
+		// Use the new Fx4 function for getting the name
+		name = PlacesUtils.backups.getFilenameForDate();
+	}
+	else
+	{
+		var datestr = (new Date).toLocaleFormat("%Y-%m-%d");
+		name = PlacesUIUtils.getFormattedString("bookmarksBackupFilenameJSON", [datestr]);
+	}
+		
+	var nsifile = StumbleGlobals.ds.getResourceNSIFile("temp", name);
+	StumbleGlobals.ds.deleteFile(nsifile);
+	
+	nsifile.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0700);
+	
+	PlacesUtils.backupBookmarksToFile(
+			nsifile,
+			[PlacesUIUtils.leftPaneFolderId]);
+	
+	var target_dir = StumbleGlobals.get_service( 
+			"@mozilla.org/file/directory_service;1",
+			"nsIProperties")
+			.get("ProfD", Components.interfaces.nsIFile);
+	target_dir.append("bookmarkbackups");
+	if (! target_dir.exists())
+		target_dir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0700);
+	
+	var target_file;
+	target_file = StumbleGlobals.get_service(
+			"@mozilla.org/file/directory_service;1",
+			"nsIProperties")
+			.get("ProfD", Components.interfaces.nsIFile);
+	target_file.append("bookmarkbackups");
+	target_file.append(name);
+	if (target_file.exists())
+	{
+		var target_file2;
+		target_file2 = StumbleGlobals.get_service(
+				"@mozilla.org/file/directory_service;1",
+				"nsIProperties")
+				.get("ProfD", Components.interfaces.nsIFile);
+		target_file2.append("bookmarkbackups");
+		target_file2.append(name + ".su.saved.json");
+		if (! target_file2.exists())
+			target_file.copyTo(target_dir, name + ".su.saved.json");
+		StumbleGlobals.ds.deleteFile(target_file);
+	}
+	
+	if (! target_file.exists())
+		nsifile.copyTo(target_dir, name);
+	
+	} catch (e) { StumbleGlobals.log_error(error_label, e); }
+}
+
+StumbleGlobals.handle_download_favs_command = function()
+{
+	var detail = new Object();
+	detail.browser_label = StumbleGlobals.host.label;
+	
+	window.openDialog(
+			"chrome://stumbleupon/content/downloadFavsDialog.xul",
+			"stumbleglobals_downloadFavsDialog",
+			"chrome,dialog,centerscreen,dependent",
+			detail);
+}
+
+StumbleGlobals.download_favs = function(start_download)
+{
+	if (start_download)
+		StumbleGlobals.ds.setValue("$sync_bm_meta", true);
+	
+	var state = StumbleGlobals.ds.getValue("$download_favs_state");
+	var context;
+	var val;
+	if (((state == "a") || (state == "c")) && (! start_download))
+		return;
+	
+	context = StumbleGlobals.ds.getValue("$download_favs_detail");
+	
+	if ((state == "a") || (state == "c") || (! context.mode))
+	{
+		context = new Object();
+		context.begin_s = StumbleGlobals.get_time_s();
+		context.end_s = 0;
+		context.prekey = 0;
+		context.prekey2 = 0;
+		context.mode = 1;
+		context.first = 1;
+		context.download_target_count = 200;
+		context.download_count = 0;
+		context.apply_target_count = 200;
+		context.apply_count = 0;
+		context.count = 0;
+		context.done = false;
+		context.stopped = false;
+		StumbleGlobals.ds.setValue("$download_favs_detail", context);
+		StumbleGlobals.ds.setValue("#download_favs_detail", context);
+		StumbleGlobals.ds.setValue("$download_favs_state", "b");
+		StumbleGlobals.ds.flushPrefs();
+	}
+	else
+	{
+		StumbleGlobals.ds.setValue("#download_favs_detail", context);
+	}
+	
+	if (StumbleGlobals.preference_dialog)
+	{
+		val = 5;
+		
+		el = StumbleGlobals.preference_dialog.ownerDocument.getElementById("download_progress");
+		if (val != el.value)
+			el.value = val;
+	}
+
+	StumbleGlobals.set_download_favs_enabled(false);
+	
+	if (StumbleGlobals.ds.getValue("#migrating_places"))
+		return;
+	
+	setTimeout(function (win, context) { win.StumbleGlobals.download_favs_getmetafavs(context) }, 0, window, context);
+}
+
+StumbleGlobals.download_favs_getmetafavs = function(context)
+{
+	var params = "";
+	params = StumbleGlobals.arp(params, "prekey", context.prekey);
+	params = StumbleGlobals.arp(params, "prekey2", context.prekey2);
+	params = StumbleGlobals.arp(params, "first", context.first);
+	params = StumbleGlobals.arp(params, "mode", context.mode);
+	params = StumbleGlobals.arp(params, "a", (StumbleGlobals.ds.getValue("$sync_bm_adult") ? 1 : 0))
+	context.quiet = true;
+	StumbleGlobals.post_url_server_async(
+				"getmetafavs.php",
+				params,
+				15000,
+				StumbleGlobals.download_favs_getmetafavs_done,
+				context);
+}
+
+StumbleGlobals.download_favs_getmetafavs_done = function(res)
+{
+	try {
+		if (res.status != 200)
+			return;
+	} catch (e) { return; } 
+	
+	var context = res.detail;
+	
+	context.first = 0;
+	
+	StumbleGlobals.ds.setValue("$download_favs_detail", context);
+	StumbleGlobals.ds.flushPrefs();
+	
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+	
+	setTimeout(function (win, context, s) {
+				win.StumbleGlobals.download_favs_getmetafavs_done2(context, s); },	
+			0,
+			window,
+			context,
+			s);		
+}
+
+StumbleGlobals.download_favs_getmetafavs_done2 = function(context, s)
+{
+	if (context.stopped)
+		return;
+	
+//	if (context.paused)
+//	{
+//		setTimeout(function (win, context, s) {
+//				win.StumbleGlobals.download_favs_getmetafavs_done2(context, s); },
+//				1000,
+//				window,
+//				context,
+//				s);
+//		return;
+//	}
+	
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response getmetafavs.php", s);
+	
+	var commands = s.split("\n");
+	
+	window.setTimeout(function (win, context, commands) {
+			win.StumbleGlobals.download_favs2(context, commands); },
+			0,
+			window,
+			context,
+			commands);
+}
+
+StumbleGlobals.download_favs2 = function(context, commands)
+{
+	var command;
+	var command_parts; 
+	
+	if (StumbleGlobals.ds.getValue("$download_favs_state") != "b")
+	{
+		// Download is done or stopped.
+		StumbleGlobals.process_command_queue();
+	}
+	else if (commands.length)
+	{
+		command = commands.shift();
+		
+		if (command.indexOf("META ") == 0)
+		{	
+			context.download_count++;
+			StumbleGlobals.enqueue_command(16000, command);
+		}
+		else if (command.indexOf("BATCH ") == 0)
+		{
+			command_parts = command.split(" ");
+			context.download_target_count = parseInt(command_parts[3]);
+			context.apply_target_count = parseInt(command_parts[3]);
+			StumbleGlobals.ds.setValue("$download_favs_detail", context);
+			StumbleGlobals.ds.flushPrefs();
+		}
+		else
+		{
+			StumbleGlobals.process_command(command, context);
+		}
+		
+		setTimeout(function (win, context, commands) {
+					win.StumbleGlobals.download_favs2(context, commands); },
+				10,
+				window,
+				context,
+				commands);
+	}
+	else if (! context.done)
+	{
+		setTimeout(function (win, context) {
+					win.StumbleGlobals.download_favs_getmetafavs(context); },
+				0,
+				window,
+				context);
+		
+		StumbleGlobals.process_command_queue();
+	}
+	else if (context.done && (context.mode == 1))
+	{
+		context.mode = 2;
+		context.prekey = 0;
+		context.done = false;
+		
+		setTimeout(function (win, context) {
+					win.StumbleGlobals.download_favs_getmetafavs(context); },
+				0,
+				window,
+				context);
+
+		StumbleGlobals.process_command_queue();
+	}
+	else if (context.done && (context.mode == 2))
+	{
+		context.apply_target_count = context.download_count;
+		context.apply_count = context.download_count - StumbleGlobals.count_enqueued_commands(16000);
+		StumbleGlobals.ds.setValue("$download_favs_detail", context);
+		StumbleGlobals.ds.setValue("$download_favs_state", "c");
+		StumbleGlobals.ds.flushPrefs();
+		StumbleGlobals.ds.logEvent("dfth");
+		StumbleGlobals.ds.setValue("#command_queue_context", null);
+		
+		StumbleGlobals.process_command_queue();
+	}
+	else
+	{
+		StumbleGlobals.log_error("DOWNLOADFAVS TERMINATION", context, commands.length);
+	}
+}
+
+StumbleGlobals.add_query_folder_bm = function(parent_folderid, target_folderids, tag, title, index)
+{
+	var hs = StumbleGlobals.ds.getHistoryService();
+	var query = hs.getNewQuery();
+	var bms = StumbleGlobals.ds.getBookmarksService();
+	query.setFolders(target_folderids, target_folderids.length);
+	query.searchTerms = tag;
+	var opt = hs.getNewQueryOptions();
+	opt.sortingMode = opt.SORT_BY_LASTMODIFIED_DESCENDING;
+	opt.resultType = opt.RESULTS_AS_URI;
+	opt.queryType = 1;
+	var query_str = hs.queriesToQueryString([query], 1, opt);
+	var ios = StumbleGlobals.get_service(
+			"@mozilla.org/network/io-service;1",
+			"nsIIOService");
+	var nsiuri = ios.newURI(query_str, null, null);
+	
+	return bms.insertBookmark(
+			parent_folderid,
+			nsiuri,
+			index,
+			title);
+}
+
+StumbleGlobals.get_favicon_url = function(domain)
+{
+	if (! domain)
+		return null;
+	
+	filename = StumbleGlobals.get_channel_id(domain) + ".ico";
+	
+	if (! StumbleGlobals.ds.isResourceInstalled("favicons", filename))
+		return null;
+	
+	return StumbleGlobals.ds.getResourceURLFromName("favicons", filename);
+}
+
+StumbleGlobals.get_channel_id = function(domain)
+{
+	return domain.replace(/\./g, "_");
+}
+
+StumbleGlobals.set_mode_all = function()
+{
+	StumbleGlobals.set_mode("0", "All", "", "Stumble!", "Show next page");
+}
+
+StumbleGlobals.remove_class = function(el, class_name)
+{
+	var theClass = el.getAttribute("class");
+	if(theClass)
+	{
+		theClass = StumbleGlobals.trim(theClass.replace(class_name, ""));
+		el.setAttribute("class", theClass);
+	}
+}
+
+StumbleGlobals.add_class = function(el, class_name)
+{
+	var theClass = el.getAttribute("class");
+	if(!theClass)
+		el.setAttribute("class", class_name);
+	else if(theClass.indexOf(class_name) == -1)
+		el.setAttribute("class", theClass + " " + class_name);
+}
+
+StumbleGlobals.update_category_selection = function(cat, label)
+{
+	var mp = document.getElementById("stumbleglobals_category_menupopup");
+	var selectedId = "";
+
+	// Nothing to update until the menu popup has been created (the creation function will call
+	// this update routine at that time).
+	if(!mp)
+		return;
+	
+	// First, see if it is one of our special-case ones that get highlighted
+	switch(cat)
+	{
+	case "0":
+		selectedId = "stumbleglobals_cat_0";
+		break;
+	case "friends":
+		selectedId = "stumbleglobals_cat_friends";
+		break;
+	case "302":
+		selectedId = "stumbleglobals_cat_photos";
+		break;
+	case "video":
+		selectedId = "stumbleglobals_cat_video";
+		break;
+	case "news":
+		selectedId = "stumbleglobals_cat_news";
+		break;
+	}
+
+	var el = null;
+	if(selectedId)
+		el = StumbleGlobals.get_element(selectedId);
+	var oldSelected = StumbleGlobals.get_element("stumbleglobals_category").selectedItem;
+	
+	// If the element exists and it is already the selected element, then we're done
+	if(el && (el == oldSelected))
+		return;
+
+	// Deselect (or remove) the previously selected item
+	if(oldSelected)
+	{
+		if(oldSelected.selectionIndicator)
+		{
+			oldSelected.parentNode.removeChild(oldSelected);
+		}
+		else
+		{
+			StumbleGlobals.remove_class(oldSelected, "su-selected-category");
+		}
+		StumbleGlobals.get_element("stumbleglobals_category").selectedItem = null;
+	}
+	
+	// If we don't have an item to select, create one at the top
+	if(!el)
+	{
+		var el = document.createElement("menuitem");
+		el.setAttribute("class", "menuitem-iconic");
+		el.setAttribute("label", label);
+		el.setAttribute("tooltiptext", "The currently selected category");
+		el.setAttribute("onclick", "StumbleGlobals.clickstumble(event)");
+		mp.insertBefore(el, mp.firstChild);
+		el.selectionIndicator = true;
+	}
+	
+	// Mark it as selected and keep track of it.
+	StumbleGlobals.get_element("stumbleglobals_category").selectedItem = el;
+	StumbleGlobals.get_element("stumbleglobals_category").setAttribute("tooltiptext", "Choose your stumble mode.  Currently stumbling '" + label + "'");
+	StumbleGlobals.add_class(el, "su-selected-category");
+}
+
+StumbleGlobals.set_mode = function(cat, cat_label, src, label, tooltip)
+{
+	cat += "";
+	var el;
+	el = StumbleGlobals.get_element("stumbleglobals_cat_langall");
+	if (el)
+		el.hidden = (cat.indexOf("LANG_") != 0);
+	
+	StumbleGlobals.selected_category = cat + "";
+
+	var tweakedCat = '';
+	if(cat_label)
+	{
+		tweakedCat = cat_label.replace(/\.com$/igm, "");
+		if(tweakedCat.length > 30)
+			tweakedCat = tweakedCat.slice(0, 27) + "...";
+	}
+
+	StumbleGlobals.update_category_selection(cat, tweakedCat);
+
+	// We only show the category text for the "All" category	
+	if(tweakedCat != "All")
+		tweakedCat = "";
+	
+	StumbleGlobals.set_label("stumbleglobals_category", tweakedCat);
+
+	if (! ((StumbleGlobals.stumbleid == 0) && (! StumbleGlobals.promo_mode)))
+	{
+		StumbleGlobals.get_element("stumbleglobals_category").setAttribute("image", src);
+		StumbleGlobals.get_element("stumbleglobals_stumble").setAttribute("tooltiptext", tooltip);
+	}
+}
+
+StumbleGlobals.refresh_category_selector_batched = function()
+{
+	// By delaying for 500 ms, we batch sets of closely spaced menu 
+	// updates.
+	if (! StumbleGlobals.refreshing_category_selector)
+	{
+		StumbleGlobals.refreshing_category_selector = true;
+		StumbleGlobals.blocked_category_selector_refresh_pending = false;
+		setTimeout(
+					function (win) {
+						win.StumbleGlobals.invoke_global_event("refresh-category-selector", null); },
+					500,
+					window);
+	}
+	else if (StumbleGlobals.refreshing_category_selector && 
+				(! StumbleGlobals.blocked_category_selector_refresh_pending))
+	{
+		// If refresh is blocked, push back the refresh event.
+		StumbleGlobals.blocked_category_selector_refresh_pending = true;
+		setTimeout(
+					function (win) {
+						win.StumbleGlobals.refresh_category_selector_batched(); },
+					500,
+					window);
+	}
+}
+
+// This is the javascript way of creating an object and it's constructor:
+StumbleGlobals.CatObj = function(id, name)
+{
+	this.id = id;
+  this.name = name;
+}
+
+// Updates interest list in the in-cat stumble dialog, and saves current interests to disk (StumbleGlobals.user_interests)
+StumbleGlobals.refresh_category_selector = function()
+{
+	// we need to completely *remove* the menupopup and re-add it
+	// if we don't, the menupopup will be corrupt and it willl eventually 
+	// stop working.  this is a firefox specific problem	
+	var incat = StumbleGlobals.get_element("stumbleglobals_category");
+
+	// delete the menupopup and regenerate it
+	var thechild;
+	thechild = incat.childNodes[0];
+	if (typeof(thechild.hidePopup) == "function")
+	{
+		thechild.hidePopup();
+		StumbleGlobals.unfocus();
+	}
+	incat.removeChild(thechild);
+	
+	var ja = document.createElement("menupopup");
+	ja.setAttribute("id", "stumbleglobals_category_menupopup");
+	incat.appendChild(ja);
+
+	StumbleGlobals.load_categories();
+
+	// Now add new children
+	var ints = new Array();
+	if (StumbleGlobals.user_interests.length)
+	{
+		var cat2;
+		for (cat2 in StumbleGlobals.user_interests)
+		{
+			if (StumbleGlobals.is_property_garbage(StumbleGlobals.user_interests, cat2))
+				continue;
+			
+			if (StumbleGlobals.is_property_garbage(StumbleGlobals.catnames, cat2))
+				continue;
+	
+			if ((typeof(StumbleGlobals.catnames[cat2])) == "undefined")
+				continue;
+
+			ints.push(new StumbleGlobals.CatObj(cat2, StumbleGlobals.catnames[cat2]));
+		}
+	}
+	
+	ints.sort(function (a, b) 
+				{
+					if ( a.name < b.name ) return -1;
+					if ( a.name > b.name ) return 1;
+					return 0;
+				});
+
+	// ** An individual stumbler
+	ja = document.createElement("menuitem");
+	ja.setAttribute("class", "menuitem-iconic");
+	ja.setAttribute("label", "Pages from...");
+	ja.setAttribute("id", "stumbleglobals_cat_favorites_of2");
+	ja.setAttribute("tooltiptext", "Stumble someone's favorites");
+	ja.setAttribute("onclick", "StumbleGlobals.favorites_of(event);");
+	ja.setAttribute("image", "chrome://stumbleupon/content/skin/stumbler_favorites.png");
+	ja.setAttribute("hidden", "true");
+	incat.childNodes[0].appendChild(ja);
+
+	// ** stumble in "all"
+
+	ja = document.createElement("menuitem");
+	ja.setAttribute("class", "menuitem-iconic");
+//	ja.setAttribute("label", StumbleGlobals.ds.getValue("%menu.anytopic"));
+	ja.setAttribute("label", "All");
+	ja.setAttribute("id", "stumbleglobals_cat_0");
+	ja.setAttribute("tooltiptext", "Stumble all");
+	ja.setAttribute("oncommand", "StumbleGlobals.select_topic(0, 'All', false);");
+	ja.setAttribute("image", "chrome://stumbleupon/content/skin/all.png");
+	incat.childNodes[0].appendChild(ja);
+
+	// ** Following
+	
+	ja = document.createElement("menuitem");
+	ja.setAttribute("class", "menuitem-iconic");
+//	ja.setAttribute("label", StumbleGlobals.ds.getValue("%menu.anytopic"));
+	ja.setAttribute("label", "Following");
+	ja.setAttribute("id", "stumbleglobals_cat_friends");
+	ja.setAttribute("tooltiptext", "Sites from people you are following");
+	ja.setAttribute("oncommand", "StumbleGlobals.select_topic('friends', 'Following', false);");
+	ja.setAttribute("image", "chrome://stumbleupon/content/skin/icon_tb_people.png");
+	incat.childNodes[0].appendChild(ja);
+
+	// ** StumbeThru
+	
+	ja = document.createElement("menuitem");
+	ja.setAttribute("class", "menuitem-iconic");
+	ja.setAttribute("label", "StumbleThru");
+	ja.setAttribute("id", "stumbleglobals_cat_stumblethru");
+	ja.setAttribute("tooltiptext", "StumbleThru a website");
+	ja.setAttribute("oncommand", 'StumbleGlobals.set_server_location("stumblethru.php");');
+	ja.setAttribute("image", "chrome://stumbleupon/content/skin/domain.png");
+	incat.childNodes[0].appendChild(ja);
+
+	// ** Search
+	
+	ja = document.createElement("menuitem");
+	ja.setAttribute("class", "menuitem-iconic");
+	ja.setAttribute("label", "Search");
+	ja.setAttribute("id", "stumbleglobals_cat_stumble_tags");
+	ja.setAttribute("tooltiptext", "Stumble within a query");
+	ja.setAttribute("oncommand", 'StumbleGlobals.handle_mode_click(event, "Search");');
+	ja.setAttribute("image", "chrome://stumbleupon/content/skin/search.png");
+	incat.childNodes[0].appendChild(ja);
+
+	// ** Photos
+	
+	ja = document.createElement("menuitem");
+	ja.setAttribute("class", "menuitem-iconic");
+//	ja.setAttribute("label", StumbleGlobals.ds.getValue("%menu.anytopic"));
+	ja.setAttribute("label", "Photos");
+	ja.setAttribute("id", "stumbleglobals_cat_photos");
+	ja.setAttribute("tooltiptext", "Stumble an image");
+	ja.setAttribute("oncommand", "StumbleGlobals.select_topic(302, 'Photos', false);");
+	ja.setAttribute("image", "chrome://stumbleupon/content/skin/icon_tb_photo_hover.png");
+	incat.childNodes[0].appendChild(ja);
+
+	// ** Videos
+	
+	ja = document.createElement("menuitem");
+	ja.setAttribute("class", "menuitem-iconic");
+//	ja.setAttribute("label", StumbleGlobals.ds.getValue("@menu.anytopic"));
+	ja.setAttribute("label", "Videos");
+	ja.setAttribute("id", "stumbleglobals_cat_video");
+	ja.setAttribute("tooltiptext", "Stumble a video");
+	ja.setAttribute("oncommand", "StumbleGlobals.select_topic('video', 'Videos', false);");
+	ja.setAttribute("image", "chrome://stumbleupon/content/skin/video.png");
+	incat.childNodes[0].appendChild(ja);
+
+	// ** News
+
+	ja = document.createElement("menuitem");
+	ja.setAttribute("class", "menuitem-iconic");
+//	ja.setAttribute("label", StumbleGlobals.ds.getValue("%menu.anytopic"));
+	ja.setAttribute("label", "News");
+	ja.setAttribute("id", "stumbleglobals_cat_news");
+	ja.setAttribute("tooltiptext", "Stumble news");
+	ja.setAttribute("oncommand", "StumbleGlobals.select_topic('news', 'News', false);");
+	ja.setAttribute("image", "chrome://stumbleupon/content/skin/icon_tb_news.png");
+	incat.childNodes[0].appendChild(ja);
+	
+	// ** contextual...
+	
+	// Create favorites of menu
+	var random_topic_id = 499;
+	var random_topic_name = 'StumbleUpon';
+		
+	ja = document.createElement("menuitem");
+	ja.setAttribute("class", "menuitem-iconic");	
+	ja.setAttribute("label", "More from " + random_topic_name);
+	ja.setAttribute("tooltiptext", "More from " + random_topic_name);
+	ja.setAttribute("id", "stumbleglobals_cat_morefrom");
+	ja.setAttribute("hidden", "true");
+	ja.setAttribute("oncommand", "StumbleGlobals.select_topic(" + random_topic_id + ", '" + random_topic_name + "', false);");
+	ja.setAttribute("image", "chrome://stumbleupon/content/skin/topic.png");
+	incat.childNodes[0].appendChild(ja);
+
+	var preTopicsItem = ja;
+
+	var i;
+	if (ints.length < 21)
+	{
+		for (i = 0; i < ints.length; i++)
+		{
+			var newname
+			try {
+				newname = ints[i].name.replace(/'/g, "\\\'");
+			}
+			catch (e) {
+				StumbleGlobals.log_error("CAT NEWNAME", ints[i], i);
+				continue;
+			}
+			ja = document.createElement("menuitem");
+			ja.setAttribute("label", ints[i].name);
+			ja.setAttribute("id", "stumbleglobals_cat_" + ints[i].id);
+			ja.setAttribute("tooltiptext", "Stumble " + ints[i].name);
+			ja.setAttribute("oncommand", "StumbleGlobals.select_topic(" + ints[i].id + ",'" + newname + "', false);");
+			incat.childNodes[0].appendChild(ja);
+		}
+	}
+	else
+	{
+		var folders = new Array();
+		for (var cat in StumbleGlobals.user_interests)
+		{
+			if (StumbleGlobals.is_property_garbage(StumbleGlobals.user_interests, cat))
+				continue;
+			
+			if (StumbleGlobals.is_property_garbage(StumbleGlobals.topicfolders, cat))
+				continue;
+			
+			if (StumbleGlobals.is_property_garbage(StumbleGlobals.catnames, cat))
+				continue;
+			
+			var folder = StumbleGlobals.topicfolders[cat];
+			var name = StumbleGlobals.catnames[cat];
+			if (typeof(folders[folder]) == "undefined")
+				folders[folder] = new Array();
+		
+			folders[folder][name]=cat;
+		}
+	
+		for (i = 0; i < StumbleGlobals.foldernames.length; i++)
+		{
+			var key = StumbleGlobals.foldernames[i];
+			if (typeof(folders[key]) == "undefined")
+					continue;
+			// topics = folders[key];
+
+			ja = document.createElement("menu");
+			ja.setAttribute("label", key);
+			ja.setAttribute("tooltiptext", "Stumble...");
+			var child = incat.childNodes[0].appendChild(ja);
+	
+			ja = document.createElement("menupopup");
+			var child2 = child.appendChild(ja);
+
+			var newtopics = new Array();
+			var counter = 0;
+			for (var catname in folders[key])
+			{
+				if (StumbleGlobals.is_property_garbage(folders[key], catname))
+					continue;
+				
+				newtopics[counter] = catname;
+				counter++;	
+
+			}
+			newtopics.sort();
+			for (var j = 0; j < newtopics.length; j++)
+			{
+				name = newtopics[j];
+				var catid = StumbleGlobals.catids[name];
+
+				ja = document.createElement("menuitem");
+				ja.setAttribute("class", "topic-selector");
+				ja.setAttribute("label", name);
+				ja.setAttribute("id", "stumbleglobals_cat_" + catid);
+				ja.setAttribute("tooltiptext", "Stumble " + name);
+				newname = name.replace(/'/g, "\\\'");
+				ja.setAttribute("oncommand", "StumbleGlobals.select_topic(" + catid + ",'" + newname + "', false);");
+				child2.appendChild(ja);
+			}
+		}
+	}
+
+	if(preTopicsItem !== incat.childNodes[0].lastChild)
+	{
+		// If we have favorite topics, then include a separator before them
+		ja = document.createElement("menuseparator");
+		incat.childNodes[0].insertBefore(ja, preTopicsItem.nextSibling);
+	}
+
+	ja = document.createElement("menuseparator");
+	incat.childNodes[0].appendChild(ja);
+
+	ja = document.createElement("menuitem");
+//	ja.setAttribute("class", "topic-selector");
+//	ja.setAttribute("label", StumbleGlobals.ds.getValue("%menu.addmoretopics"));
+	ja.setAttribute("label", "Update Topics");
+	ja.setAttribute("tooltiptext", "Select different topics");
+	ja.setAttribute("id", "stumbleglobals_cat_addmore");
+	ja.setAttribute("oncommand", "StumbleGlobals.interests_pre();");
+	incat.childNodes[0].appendChild(ja);
+
+
+	// Create languages
+	ja = document.createElement("menu");
+//	ja.setAttribute("class", "topic-selector");
+	ja.setAttribute("label", "Languages");
+	ja.setAttribute("tooltiptext", "Stumble pages in a specific language");
+	ja.setAttribute("id", "stumbleglobals_languages");
+	var langs2 = incat.childNodes[0].appendChild(ja);
+
+	ja = document.createElement("menupopup");
+//	ja.setAttribute("class", "topic-selector");
+	ja.setAttribute("id", "stumbleglobals_languages-popup");
+	langs2.appendChild(ja);
+
+	// first check to see if favorites of is already there
+	var langs = StumbleGlobals.get_element("stumbleglobals_languages-popup");
+
+	ja = document.createElement("menuitem");
+	ja.setAttribute("label", "All");
+//		ja.setAttribute("class", "topic-selector");
+	ja.setAttribute("id", "stumbleglobals_cat_langall");
+	ja.setAttribute("tooltiptext", "Stumble all");
+	ja.setAttribute("oncommand", "StumbleGlobals.select_topic(0, 'All', false);");
+	langs.appendChild(ja);
+
+	var languages = new Array();
+
+	languages['ZH'] = "Chinese";
+	languages['DA'] = "Danish";
+	languages['NL'] = "Dutch";
+	languages['FI'] = "Finnish";
+	languages['FR'] = "French";
+	languages['DE'] = "German";
+	languages['EL'] = "Greek";
+	languages['IT'] = "Italian";
+	languages['JA'] = "Japanese";
+	languages['PT'] = "Portuguese";
+	languages['ES'] = "Spanish";
+	languages['SV'] = "Swedish";
+	languages['TR'] = "Turkish";
+
+	for (var langid in languages)
+	{
+		if (StumbleGlobals.is_property_garbage(languages, langid))
+			continue;
+		
+		var langname = languages[langid];
+
+		ja = document.createElement("menuitem");
+		ja.setAttribute("label", langname);
+//		ja.setAttribute("class", "topic-selector");
+		ja.setAttribute("id", 'stumbleglobals_cat_LANG_' + langid);
+		ja.setAttribute("tooltiptext", "Stumble " + langname + " pages");
+		ja.setAttribute("oncommand", "StumbleGlobals.select_topic('" + 'LANG_' + langid + "', '" + langname + "', false);");
+		langs.appendChild(ja);
+	}
+
+	StumbleGlobals.set_mode_all();
+
+	StumbleGlobals.refreshing_category_selector = false;
+}
+
+StumbleGlobals.favorites_of = function(event)
+{
+	StumbleGlobals.unfocus_searchbox(); 
+	var stumbler = getBrowser().contentWindow.prompt("Enter the nickname of a stumbler:","");
+
+	// they clicked cancel
+	if (stumbler && (stumbler != ""))
+	{
+		// select and do it
+		StumbleGlobals.select_topic(stumbler, stumbler, StumbleGlobals.new_tab(event));
+	}
+	else
+	{
+		StumbleGlobals.set_mode_all();
+	}
+	return true;
+}
+
+StumbleGlobals.unfocus_searchbox = function()
+{ 	 
+	// unfocus search box so we don't end up searching when they hit enter   	 
+	if (StumbleGlobals.get_element("stumbleglobals_searchbox").getAttribute("focused") == "true")
+		StumbleGlobals.unfocus();
+}
+
+StumbleGlobals.unfocus = function()
+{
+	if (! StumbleGlobals.gui_initialized) return;
+	
+	if (document.commandDispatcher.focusedElement)
+	{
+		if ((document.commandDispatcher.focusedElement instanceof NSHTMLElement) || 
+					(document.commandDispatcher.focusedElement instanceof XULElement))
+		{
+			document.commandDispatcher.focusedElement.blur();
+		}
+		else
+		{
+			// non-HTML/XUL elements have no blur method; see bug 323805
+			document.commandDispatcher.focusedElement = null;
+		}
+	}
+}
+
+/*
+StumbleGlobals.tag_stumble = function()
+{
+	StumbleGlobals.unfocus_searchbox(); 
+	var tag = getBrowser().contentWindow.prompt("Please enter a tag","");
+
+	// they clicked cancel
+	if (typeof(tag) == "undefined" || tag == "" || tag.length <= 0)
+	{
+		StumbleGlobals.set_mode_all();
+		return false;
+	}
+
+	// put it in the box
+	StumbleGlobals.get_element("stumbleglobals_searchbox").value=tag;
+	StumbleGlobals.get_element("stumbleglobals_searchbox").removeAttribute("mode");
+	StumbleGlobals.old_search = tag;
+	StumbleGlobals.last_typed_tag = 0;
+	StumbleGlobals.visited_searchbox = 1;
+
+	// select and do it
+	StumbleGlobals.select_topic('TAG_' + tag, tag, false);
+	return true;
+}
+*/
+
+StumbleGlobals.update_check_referred_disabled = function()
+{
+	var el = StumbleGlobals.get_element("stumbleglobals_referred");
+	var now = (new Date()).getTime();
+	var click_throttle = StumbleGlobals.ds.getValue("@click_throttle_ms");
+	
+	// Check whether it is currently disabled
+	var wasDisabled = el.disabled;
+	
+	// Disable it and set a timer to update the button later
+	el.disabled = true;
+	setTimeout(function() {
+		StumbleGlobals.update_referred();
+	}, click_throttle);
+	
+	if(!wasDisabled)
+		el.last_click = now;
+
+	return !!wasDisabled;
+}
+	
+StumbleGlobals.handle_referral_throbber_click = function(event)
+{
+	StumbleGlobals.stop_referred_throbber();
+	
+	if(StumbleGlobals.update_check_referred_disabled())
+		return;
+	
+	StumbleGlobals.stumble(StumbleGlobals.new_tab(event), true, true);
+}
+
+
+/*
+StumbleGlobals.handle_report_dupe_command = function(url)
+{
+	if (StumbleGlobals.enable_freereporting)
+	{
+		var media = StumbleGlobals.ds.serialize(StumbleGlobals.get_media_specs());
+	
+		var params = "";
+		params = StumbleGlobals.arp(params, "url", StumbleGlobals.stumbled_url);
+		params = StumbleGlobals.arp(params, "redirect", StumbleGlobals.redirect_url);
+		params = StumbleGlobals.arp(params, "current", StumbleGlobals.get_browser_url());
+		params = StumbleGlobals.arp(params, "current_media", media);
+	
+		StumbleGlobals.post_url_server_async(
+					"dupe.php",
+					params,
+					15000,
+					StumbleGlobals.generic_done);
+	
+		var ps = StumbleGlobals.get_service(
+					"@mozilla.org/embedcomp/prompt-service;1",
+					"nsIPromptService");
+		
+		ps.alert(window, "StumbleUpon", "Thanks for reporting this duplicate.\n\nIt will be reviewed by our support team.");
+	}
+	else
+	{
+		if (StumbleGlobals.stumbled_url == "")
+		{
+			alert("You can't report pages that you haven't Stumbled upon."); 
+		}
+	
+		if (StumbleGlobals.stumbleid == 0)
+			return;
+	
+		var params = "";
+		params = StumbleGlobals.arp(params, "url", StumbleGlobals.stumbled_url);
+		params = StumbleGlobals.arp(params, "redirect", StumbleGlobals.redirect_url);
+		params = StumbleGlobals.arp(params, "current", StumbleGlobals.get_browser_url());
+		params = StumbleGlobals.arp(params, "verified", 1);
+
+		if (window.confirm("Are you sure that the following URL contains duplicate content?\n\n" + StumbleGlobals.stumbled_url))
+		{
+			StumbleGlobals.post_url_server_async(
+						"dupe.php",
+						params,
+						15000,
+						StumbleGlobals.generic_done);
+		}
+	}
+}
+*/
+
+
+// Handler for menuitem "Report Miscat"
+StumbleGlobals.handle_report_miscat_command = function(tab_url)
+{
+	if (StumbleGlobals.enable_freereporting)
+	{
+		var url_detail = StumbleGlobals.ds.lookup("url:url_detail", tab_url);
+		
+		var loc = "misclassified.php";
+		if (url_detail)
+		{
+			loc = StumbleGlobals.arp(loc, "url", url_detail.url, true);
+			loc = StumbleGlobals.arp(loc, "redirect", url_detail.redirect_url, true);
+		}
+		else
+		{
+			loc = StumbleGlobals.arp(loc, "url", tab_url, true);
+			loc = StumbleGlobals.arp(loc, "redirect", tab_url, true);
+		}
+		loc = StumbleGlobals.arp(loc, "current", StumbleGlobals.get_browser_url(), true);
+		
+		StumbleGlobals.set_server_location(loc, null, true);
+	}
+	else
+	{
+		if (StumbleGlobals.stumbled_url == "")
+		{
+			alert("You can't report pages that you haven't Stumbled upon."); 
+			return;
+		}
+	
+		if (StumbleGlobals.stumbleid == 0)
+			return;
+	
+		var loc = "misclassified.php";
+		loc = StumbleGlobals.arp(loc, "url", StumbleGlobals.stumbled_url, true);
+		loc = StumbleGlobals.arp(loc, "redirect", StumbleGlobals.redirect_url, true);
+		loc = StumbleGlobals.arp(loc, "current", StumbleGlobals.get_browser_url(), true);
+		loc = StumbleGlobals.arp(loc, "verified", 1, true);
+		if (window.confirm("Are you sure that the following URL is in the wrong topic?\n\n" + StumbleGlobals.stumbled_url))
+			StumbleGlobals.set_server_location(loc, null, true);
+	}
+}
+
+
+// Handler for menuitem "Report Adult"
+StumbleGlobals.handle_report_adult_profile_command = function(tab_url)
+{
+	if (StumbleGlobals.enable_freereporting)
+	{
+		var nickname = StumbleGlobals.get_profile_nickname(tab_url);
+		
+		var loc = "adult.php";
+		loc = StumbleGlobals.arp(loc, "stumbler", nickname);
+		
+		StumbleGlobals.set_server_location(loc, null, true);
+	}
+	else
+	{
+		if (StumbleGlobals.stumbled_url == "")
+		{
+			alert("You can't report pages that you haven't Stumbled upon."); 
+			return;
+		}
+	
+		if (StumbleGlobals.stumbleid == 0)
+			return;
+	
+		var url = StumbleGlobals.get_browser_url();
+		var nickname = StumbleGlobals.get_profile_nickname(url);
+		
+		var loc;
+		if (nickname)
+		{
+			loc = "adult.php";
+			loc = StumbleGlobals.arp(loc, "stumbler", nickname, true);
+			loc = StumbleGlobals.arp(loc, "verified", 1, true);
+		}
+		else
+		{
+			loc = "misclassified.php";
+			loc = StumbleGlobals.arp(loc, "adult_content", 1, true); 
+			loc = StumbleGlobals.arp(loc, "url", StumbleGlobals.stumbled_url, true);
+			loc = StumbleGlobals.arp(loc, "redirect", StumbleGlobals.redirect_url, true);
+			loc = StumbleGlobals.arp(loc, "current", url, true);
+			loc = StumbleGlobals.arp(loc, "verified", 1, true);
+		}
+
+		if (window.confirm("Are you sure that the following URL contains adult content?\n\n" + StumbleGlobals.stumbled_url))
+			StumbleGlobals.set_server_location(loc, null, true);
+	}
+}
+
+
+StumbleGlobals.handle_report_wrong_language_command = function(tab_url)
+{
+	if (StumbleGlobals.enable_freereporting)
+	{
+		var url_detail = StumbleGlobals.ds.lookup("url:url_detail", tab_url);
+		
+		var loc = "wrong_language.php";
+		if (url_detail)
+		{
+			loc = StumbleGlobals.arp(loc, "url", url_detail.url, true);
+			loc = StumbleGlobals.arp(loc, "redirect", url_detail.redirect_url, true);
+		}
+		else
+		{
+			loc = StumbleGlobals.arp(loc, "url", tab_url, true);
+			loc = StumbleGlobals.arp(loc, "redirect", tab_url, true);
+		}
+		
+		loc = StumbleGlobals.arp(loc, "current", StumbleGlobals.get_browser_url(), true);
+		
+		StumbleGlobals.set_server_location(loc, null, true);
+	}
+	else
+	{
+		if (StumbleGlobals.stumbled_url == "")
+		{
+			alert("You can't report pages that you haven't Stumbled upon."); 
+			return;
+		}
+	
+		if (StumbleGlobals.stumbleid == 0)
+			return;
+	
+		var loc = "wrong_language.php";
+		loc = StumbleGlobals.arp(loc, "url", StumbleGlobals.stumbled_url, true);
+		loc = StumbleGlobals.arp(loc, "redirect", StumbleGlobals.redirect_url, true);
+		loc = StumbleGlobals.arp(loc, "current", StumbleGlobals.get_browser_url(), true);
+		loc = StumbleGlobals.arp(loc, "verified", 1, true);
+		
+		if (window.confirm("Are you sure that the following URL is in the wrong language?\n\n" + StumbleGlobals.stumbled_url))
+			StumbleGlobals.set_server_location(loc, null, true);
+	}
+}
+
+// Handler for menuitem "Report Spam"
+StumbleGlobals.handle_report_spam_command = function(tab_url)
+{
+	if (StumbleGlobals.enable_freereporting)
+	{
+		var url_detail = StumbleGlobals.ds.lookup("url:url_detail", tab_url);
+		
+		var loc = "spam.php";
+		if (url_detail)
+		{
+			loc = StumbleGlobals.arp(loc, "url", url_detail.url, true);
+			loc = StumbleGlobals.arp(loc, "redirect", url_detail.redirect_url, true);
+		}
+		else
+		{
+			loc = StumbleGlobals.arp(loc, "url", tab_url, true);
+			loc = StumbleGlobals.arp(loc, "redirect", tab_url, true);
+		}
+		loc = StumbleGlobals.arp(loc, "current", StumbleGlobals.get_browser_url(), true);
+		
+		StumbleGlobals.set_server_location(loc, null, true);
+
+//		ps.alert(window, "StumbleUpon", "Thanks for helping improve stumble selection.");
+	}
+	else
+	{
+		if (StumbleGlobals.stumbled_url == "")
+		{
+			alert("You can't report pages that you haven't Stumbled upon."); 
+			return;
+		}
+	
+		if (StumbleGlobals.stumbleid == 0)
+			return;
+	
+		var loc = "spam.php";
+		loc = StumbleGlobals.arp(loc, "url", StumbleGlobals.stumbled_url, true);
+		loc = StumbleGlobals.arp(loc, "redirect", StumbleGlobals.redirect_url, true);
+		loc = StumbleGlobals.arp(loc, "current", StumbleGlobals.get_browser_url(), true);
+		loc = StumbleGlobals.arp(loc, "verified", 1, true);
+		
+		if (window.confirm("Are you sure that the following URL is spam?\n\n" + StumbleGlobals.stumbled_url))
+			StumbleGlobals.set_server_location(loc, null, true);
+	}
+}
+
+StumbleGlobals.handle_report_badware_command = function(tab_url)
+{
+	if (StumbleGlobals.enable_freereporting)
+	{
+		var url_detail = StumbleGlobals.ds.lookup("url:url_detail", tab_url);
+		
+		var params = "";
+		if (url_detail)
+		{
+			loc = StumbleGlobals.arp(loc, "url", url_detail.url, true);
+			loc = StumbleGlobals.arp(loc, "redirect", url_detail.redirect_url, true);
+		}
+		else
+		{
+			loc = StumbleGlobals.arp(loc, "url", tab_url, true);
+			loc = StumbleGlobals.arp(loc, "redirect", tab_url, true);
+		}
+		params = StumbleGlobals.arp(params, "current", StumbleGlobals.get_browser_url());
+		
+		StumbleGlobals.post_url_server_async(
+				"badware.php",
+				params,
+				15000,
+				function (){});
+
+		var ps = StumbleGlobals.get_service(
+					"@mozilla.org/embedcomp/prompt-service;1",
+					"nsIPromptService");
+		
+		ps.alert(window, "StumbleUpon", "Thanks for reporting this stumble.\n\nIt will be reviewed by our support team.");
+	}
+	else
+	{
+		if (StumbleGlobals.stumbled_url == "")
+		{
+			alert("You can't report pages that you haven't Stumbled upon."); 
+		}
+	
+		if (StumbleGlobals.stumbleid == 0)
+			return;
+	
+		var params = "";
+		params = StumbleGlobals.arp(params, "url", StumbleGlobals.stumbled_url);
+		params = StumbleGlobals.arp(params, "redirect", StumbleGlobals.redirect_url);
+		params = StumbleGlobals.arp(params, "current", StumbleGlobals.get_browser_url());
+		params = StumbleGlobals.arp(params, "verified", 1);
+
+		if (window.confirm("Are you sure that the following URL contains hostile content?\n\n" + StumbleGlobals.stumbled_url))
+		{
+			StumbleGlobals.post_url_server_async(
+					"badware.php",
+					params,
+					15000,
+					StumbleGlobals.generic_done);
+		}
+	}
+}
+
+// Handler for menuitem "Report 404"
+StumbleGlobals.handle_report_404_command = function(tab_url)
+{
+	//!!! we shouldn't really report 404, it should be something else (user 404?)
+	if (StumbleGlobals.enable_freereporting)
+	{
+		var url_detail = StumbleGlobals.ds.lookup("url:url_detail", tab_url);
+		
+		var params = "";
+		if (url_detail)
+		{
+			params = StumbleGlobals.arp(params, "url", url_detail.url);
+			params = StumbleGlobals.arp(params, "redirect", url_detail.redirect_url);
+		}
+		else
+		{
+			params = StumbleGlobals.arp(params, "url", tab_url);
+			params = StumbleGlobals.arp(params, "redirect", tab_url);
+		}
+		params = StumbleGlobals.arp(params, "current", StumbleGlobals.get_browser_url());
+		params = StumbleGlobals.arp(params, "status", 404);
+	
+		StumbleGlobals.post_url_server_async(
+				"404.php",
+				params,
+				15000,
+				StumbleGlobals.generic_done);
+		
+		var ps = StumbleGlobals.get_service(
+					"@mozilla.org/embedcomp/prompt-service;1",
+					"nsIPromptService");
+		
+		ps.alert(window, "StumbleUpon", "Thanks for reporting this broken page.\n\nIt will be reviewed by our support team.");
+	}
+	else
+	{
+		if (StumbleGlobals.stumbled_url == "")
+		{
+			alert("You can't report pages that you haven't Stumbled upon."); 
+		}
+	
+		if (StumbleGlobals.stumbleid == 0)
+			return;
+	
+		var params = "";
+		params = StumbleGlobals.arp(params, "url", StumbleGlobals.stumbled_url);
+		params = StumbleGlobals.arp(params, "redirect", StumbleGlobals.redirect_url);
+		params = StumbleGlobals.arp(params, "current", StumbleGlobals.get_browser_url());
+		params = StumbleGlobals.arp(params, "status", 404);
+		params = StumbleGlobals.arp(params, "verified", 1);
+
+		if (window.confirm("Are you sure that the following URL is 404 or broken?\n\n" + StumbleGlobals.stumbled_url))
+		{
+			StumbleGlobals.post_url_server_async(
+					"404.php",
+					params,
+					15000,
+					StumbleGlobals.generic_done);
+			//alert("404 reported for page:\n\n" + StumbleGlobals.stumbled_url);
+		}
+	}
+}
+
+StumbleGlobals.handle_report_inaccurate_command = function(tab_url)
+{
+	if (StumbleGlobals.enable_freereporting)
+	{
+		var url_detail = StumbleGlobals.ds.lookup("url:url_detail", tab_url);
+		
+		var params = "";
+		if (url_detail)
+		{
+			params = StumbleGlobals.arp(params, "url", url_detail.url);
+			params = StumbleGlobals.arp(params, "redirect", url_detail.redirect_url);
+		}
+		else
+		{
+			params = StumbleGlobals.arp(params, "url", tab_url);
+			params = StumbleGlobals.arp(params, "redirect", tab_url);
+		}
+		params = StumbleGlobals.arp(params, "current", StumbleGlobals.get_browser_url());
+		
+		StumbleGlobals.post_url_server_async(
+					"inaccurate.php",
+					params,
+					15000,
+					StumbleGlobals.generic_done);
+		
+		var ps = StumbleGlobals.get_service(
+					"@mozilla.org/embedcomp/prompt-service;1",
+					"nsIPromptService");
+		
+		ps.alert(window, "StumbleUpon", "Thanks for helping improve stumble selection.");
+	}
+	else
+	{
+		if (StumbleGlobals.stumbled_url == "")
+		{
+			alert("You can't report pages that you haven't Stumbled upon."); 
+		}
+	
+		if (StumbleGlobals.stumbleid == 0)
+			return;
+	
+		var params = "";
+		params = StumbleGlobals.arp(params, "url", StumbleGlobals.stumbled_url);
+		params = StumbleGlobals.arp(params, "redirect", StumbleGlobals.redirect_url);
+		params = StumbleGlobals.arp(params, "current", StumbleGlobals.get_browser_url());
+		params = StumbleGlobals.arp(params, "verified", 1);
+
+		if (window.confirm("Are you sure that the following URL contains inaccurate information?\n\n" + StumbleGlobals.stumbled_url))
+		{
+			StumbleGlobals.post_url_server_async(
+						"inaccurate.php",
+						params,
+						15000,
+						StumbleGlobals.generic_done);
+		}
+	}
+}
+
+StumbleGlobals.handle_filter_command = function(tmp_adult)
+{
+	var params = "";
+	params = StumbleGlobals.arp(params, "sadult", tmp_adult);
+	StumbleGlobals.post_url_server_async(
+			"setoption.php",
+			params,
+			15000,
+			StumbleGlobals.generic_done);
+}
+
+// Handler for menuitem "Change Current User" and used by newuserWindow
+StumbleGlobals.show_signin_dialog = function()
+{
+	StumbleGlobals.unfocus_searchbox(); 
+	
+	var detail = new Object();
+	
+	detail.userid = "";
+	detail.password = "";
+	detail.nickname = "";
+	detail.enableg = 0;
+	detail.enableu = 0;
+	detail.disableu = 0;
+	detail.disableg = 0;
+	detail.autologout = false;
+	
+	window.openDialog(
+				"chrome://stumbleupon/content/signinDialog.xul", 
+				"stumbleglobals_sign_in",
+				"chrome,modal,dialog,centerscreen,dependent",
+				detail);
+}
+
+StumbleGlobals.get_autologout_for_user = function(str)
+{
+	var pref = "stumble." + str + ".autologout";
+	if (StumbleGlobals.ds.isPrefDefined(pref))
+	{
+		// easy, uncommon case where str is the userid
+		return StumbleGlobals.ds.getValue(pref);
+	}
+	
+	// more common case where str is the nickname
+	var ids = StumbleGlobals.ds.getValue("@id_list").split(":");
+	
+	var i;
+	for (i = 0; i < ids.length; i++)
+	{
+		if (ids[i] == "") continue;
+		if (StumbleGlobals.ds.isPrefDefined("stumble." + ids[i] + ".nick") &&
+					(str == StumbleGlobals.ds.getValue("stumble." + ids[i] + ".nick")))
+		{
+			return StumbleGlobals.ds.getPrefValue("stumble." + ids[i] + ".autologout", false);
+		}
+	}
+	return false;
+}
+
+//
+// StumbleGlobals.handle_new_login_credentials
+//
+// Pass a detail object that has username, userid, and password.
+//
+// The web site will end up invoking this when it notifies us of a new user
+// with new credentials. The login dialog also uses this method, but sets updateUI = false
+// because it does more work before logging in (because it got more information directly from
+// userexists.php).
+//
+StumbleGlobals.handle_new_login_credentials = function(detail, updateUI)
+{
+	if (StumbleGlobals.stumbleid != 0)
+	{
+		StumbleGlobals.ds.deleteStoredPassword();
+		// New stumbleid, check whether we need to clear stumble history
+		StumbleGlobals.check_clear_history();
+	}
+	
+	StumbleGlobals.stumbleid = detail.userid;
+
+	StumbleGlobals.ds.setValue("@current_user", detail.userid);
+	var new_profile = (! StumbleGlobals.ds.isPrefDefined("$nick"));
+
+	var password = null;
+	if(detail.hashedPassword)
+		password = detail.hashedPassword;
+	else
+	{
+		if (StumbleGlobals.enable_hashed_password)
+			password = StumbleGlobals.ds.getEncodedPassword(detail.password, detail.userid);
+	}
+	
+	StumbleGlobals.ds.storePassword(password, detail.password);
+	if(detail.username)
+		StumbleGlobals.ds.setValue("$nick", detail.username);
+	else if(detail.nickname)
+		StumbleGlobals.ds.setValue("$nick", detail.nickname);
+
+	StumbleGlobals.ds.flushPrefs();
+	
+	if(updateUI)
+	{
+		var login_detail = new Object();
+		login_detail.skip_cookies = false;
+		login_detail.ignore_cookies = true;
+		login_detail.new_profile = new_profile;
+		login_detail.new_user_prompt = false;
+		StumbleGlobals.invoke_global_event("login", login_detail);
+	}
+}
+	
+StumbleGlobals.handle_signin_dialog_accept = function(detail)
+{
+	var new_profile = (! StumbleGlobals.ds.isPrefDefined("$nick"));
+	
+	// Do the default new login handling
+	StumbleGlobals.handle_new_login_credentials(detail, false);
+	
+	StumbleGlobals.ds.setValue("$autologout", detail.autologout);
+	if(detail.thumbup_count)
+	{
+		StumbleGlobals.ds.setValue("$thumbup_count", detail.thumbup_count);
+		StumbleGlobals.thumbup_count_changed();
+	}
+	if(detail.stumble_count)
+	{
+		StumbleGlobals.ds.setValue("$stumble_count", detail.stumble_count);
+		StumbleGlobals.stumble_count_changed();
+	}
+	
+	StumbleGlobals.enable_client_features(detail.enableg);
+	StumbleGlobals.enable_user_features(detail.enableu);
+	StumbleGlobals.disable_client_features(detail.disableg);
+	StumbleGlobals.disable_user_features(detail.disableu);
+	
+	// Sync the settings before updating
+	StumbleGlobals.ds.flushPrefs();
+
+	var login_detail = new Object();
+	login_detail.skip_cookies = false;
+	login_detail.ignore_cookies = true;
+	login_detail.new_profile = new_profile;
+	login_detail.new_user_prompt = false;
+	StumbleGlobals.invoke_global_event("login", login_detail);
+	
+	var loc = "home/?mozbarlogin=1";
+	var isSuPage = StumbleGlobals.is_server_page(StumbleGlobals.get_browser_url(), "");
+	StumbleGlobals.set_server_location(loc, null, !isSuPage && !StumbleGlobals.is_about_blank());
+}
+
+// Handler for menuitem "Change Password"
+StumbleGlobals.handle_change_password = function()
+{
+	StumbleGlobals.unfocus_searchbox(); 
+	
+	var detail = new Object();
+	
+	detail.password = "";	
+	detail.id = StumbleGlobals.stumbleid;
+	
+	window.openDialog(
+				"chrome://stumbleupon/content/passwordDialog.xul",
+				"stumbleglobals_password",
+				"chrome,modal,dialog,centerscreen,dependent",
+				detail);
+}
+
+StumbleGlobals.handle_password_dialog_accept = function(detail)
+{
+	// change local password
+	var unhashed_password = detail.password;
+	var password = null;
+	
+	if (StumbleGlobals.enable_hashed_password)
+		password = StumbleGlobals.ds.getEncodedPassword(unhashed_password, StumbleGlobals.stumbleid);
+	
+	StumbleGlobals.ds.storePassword(password, unhashed_password);
+	
+	var cookieManager = StumbleGlobals.get_service(
+				"@mozilla.org/cookiemanager;1",
+				"nsICookieManager");
+	cookieManager.remove("." + StumbleGlobals.servername, "PHPSESSID", "/", 0);
+	
+	StumbleGlobals.invoke_global_event("change-password", null);
+	alert("Password changed");
+}
+
+// Handler for menuitem "Feedback"
+StumbleGlobals.feedback = function()
+ {
+	if (StumbleGlobals.stumbleid == 0)
+		return false;
+
+	// Redirect to the feedback page
+	getBrowser().contentDocument.location = StumbleGlobals.base_url + "feedback.php";
+
+	return true;
+}
+
+// Handler for menuitem "Sign-out"
+StumbleGlobals.handle_logout = function(logout_from_website)
+{
+	var doc = getBrowser().contentDocument;
+
+	if (StumbleGlobals.stumbleid == 0)
+		return false;
+
+	var detail = new Object();
+	detail.response = 0;
+	
+	window.openDialog(
+			"chrome://stumbleupon/content/signoutDialog.xul", 
+			"stumbleglobals_sign_out",
+			"chrome,modal,dialog,centerscreen,dependent",
+			detail);
+	if (detail.response == 1)
+	//if (window.confirm("Are you *sure* you would like to Sign-out?\n\n(Click CANCEL if you do not know your password,\nor you will LOSE THIS ACCOUNT)"))
+	{
+		StumbleGlobals.invoke_global_event("logout", null)
+		if (logout_from_website)
+			StumbleGlobals.set_location("http://www." + StumbleGlobals.servername + "/login.php?logout=1", null, null, null);
+		else
+		{
+			var url = doc.location.toString();
+			if (StumbleGlobals.is_matching_domain(url, StumbleGlobals.servername))
+			{
+				// If they were on an SU page, then take them to the logged out page
+				StumbleGlobals.set_location("http://www." + StumbleGlobals.servername + "/login.php?logout=1", null, null, null);
+			}
+		}
+	}
+
+	return true;
+}
+
+// handles the global login event
+StumbleGlobals.login = function(skip_cookies, ignore_cookies, new_profile, new_user_prompt)
+{
+	if (StumbleGlobals.stumble_async_context && StumbleGlobals.stumble_async_context._request)
+	{
+		// kill the pending action
+		StumbleGlobals.service.abortPostAsync(StumbleGlobals.stumble_async_context._request);
+	}
+	
+	StumbleGlobals.init_login(skip_cookies, ignore_cookies); // clears user session globals
+
+	StumbleGlobals.load_data1(new_profile);
+	
+	if (! new_user_prompt)
+		StumbleGlobals.ds.setValue("$intro_count", 15);
+	
+	if (! StumbleGlobals.ds.getValue("~visited_signup"))
+		StumbleGlobals.show_searchlinks_dialog(new_user_prompt, false, false);
+
+	StumbleGlobals.load_data2(true);  // calls StumbleGlobals.configure_toolbar()
+	
+	StumbleGlobals.ds.setValue("~visited_signup", false);
+}
+
+// handles the global change-password event
+StumbleGlobals.change_password = function()
+{
+	StumbleGlobals.stumblepass = StumbleGlobals.ds.getStoredPassword();
+}
+
+StumbleGlobals.has_logged_in = function()
+{
+	var ids = StumbleGlobals.ds.getValue("@id_list").split(":");
+
+	var found = false;
+	var i;
+	for (i = 0; i < ids.length; i++)
+	{
+		if (ids[i] == "")
+			continue;
+		
+		found = true;
+		break;
+	}
+	return found;
+}
+
+// handles the global configure-toolbar event and is used by
+// load_data2()
+StumbleGlobals.configure_toolbar = function(from_preference_dialog)
+{
+	if (! from_preference_dialog)
+	{
+		try {
+			StumbleGlobals.close_info();
+		} catch (e) { StumbleGlobals.log_error("CONFIGURE CLOSEINFO", e, from_preference_dialog); } 
+		
+		try {
+			StumbleGlobals.move_toolbar(true, 1);
+		} catch (e) { StumbleGlobals.log_error("CONFIGURE MOVE", e, from_preference_dialog, StumbleGlobals.ds.getValue("@toolbar-position"), StumbleGlobals.ds.getValue("@position-group")); } 
+	
+		try {
+			StumbleGlobals.refresh_toggle_button(true);
+		} catch (e) { StumbleGlobals.log_error("CONFIGURE TOGGLE", e, from_preference_dialog); } 
+	}
+		
+	try {
+		StumbleGlobals.set_mode_all();
+	} catch (e) { StumbleGlobals.log_error("CONFIGURE SET MODE", e, from_preference_dialog); } 
+
+	try {
+		StumbleGlobals.init_labels();
+	} catch (e) { StumbleGlobals.log_error("CONFIGURE LABELS", e, from_preference_dialog); } 
+
+	try {	
+		if (StumbleGlobals.host.mac)
+			StumbleGlobals.set_attribute("stumbleglobals_thumbdown", "mac", "true");
+	} catch (e) { StumbleGlobals.log_error("CONFIGURE THUMBDOWN", e, from_preference_dialog); }
+	
+	try {
+		StumbleGlobals.init_toolbar_element_visibility();
+	} catch (e) { StumbleGlobals.log_error("CONFIGURE HIDDEN STATES", e, from_preference_dialog); } 
+
+	try {
+		if (StumbleGlobals.host.mac)
+			StumbleGlobals.set_attribute("stumbleglobals_sponsor", "image", "chrome://stumbleupon/content/skin/sponsor_mac.png");
+	} catch (e) { StumbleGlobals.log_error("SET SPONSOR IMAGE", e, from_preference_dialog); }
+	
+	if (StumbleGlobals.stumbleid != 0)
+	{
+		try {
+			StumbleGlobals.set_autocomplete_type(StumbleGlobals.ds.getValue("$autocomplete_type"));
+		} catch (e) { StumbleGlobals.log_error("CONFIGURE AUTOCOMPLETE", e, from_preference_dialog); } 
+
+		try {
+			StumbleGlobals.dyn_channels_dirty = true;
+			StumbleGlobals.update_dyn_channels();
+		} catch (e) { StumbleGlobals.log_error("CONFIGURE DYN CHANNEL BUTTONS", e, from_preference_dialog); } 
+
+		try {
+			StumbleGlobals.refresh_category_selector();
+		} catch (e) { StumbleGlobals.log_error("CONFIGURE CATEGORY SELECTOR", e, from_preference_dialog); } 
+	
+		try {
+			StumbleGlobals.referral_menu_dirty = true;
+			StumbleGlobals.update_referral_menu();
+		} catch (e) { StumbleGlobals.log_error("CONFIGURE REFERRAL MENU", e, from_preference_dialog); } 
+
+		try {
+			StumbleGlobals.refresh_keybindings();
+		} catch (e) { StumbleGlobals.log_error("CONFIGURE KEYBINDINGS", e, from_preference_dialog); }
+
+	}
+	
+	StumbleGlobals.reflow_toolbar("CONFIGURE");
+
+	setTimeout(function (win, url) { win.StumbleGlobals.refresh_pagemeta(false, 2); }, 0, window);
+	setTimeout(function (win) { win.StumbleGlobals.reflow_toolbar("CONFIGURE2"); }, 500, window);
+	setTimeout(function (win) { win.StumbleGlobals.reflow_toolbar("CONFIGURE3"); }, 2000, window);
+}
+
+StumbleGlobals.verify_bookmarks_folder = function()
+{
+	if (! StumbleGlobals.host.places)
+		return;
+	
+	var bms = StumbleGlobals.ds.getBookmarksService();
+	
+	var folderid = StumbleGlobals.ds.getValue("$bm_folderid");
+	var tmpidx;
+	if (folderid != 0)
+	{
+		tmpidx = -1;
+		try {
+			tmpidx = bms.getItemIndex(folderid);
+		} catch (e) {}
+		if (tmpidx != -1)
+			return;
+	}
+	
+	var children = Application.bookmarks.menu.children;
+	var i;
+	var folders_by_label = new Object();
+	var nonfolders_by_label = new Object();
+	var item;
+	for (i = 0; i < children.length; i++)
+	{
+		item = children[i];
+
+		if ((typeof item.title) != "string")
+			continue;
+		
+		if (item.title.indexOf("StumbleUpon") == 0)
+		{
+			if (item.type == "folder")
+				folders_by_label[item.title] = item;
+			else
+				nonfolders_by_label[item.title] = item;
+		}
+	}
+	
+	item = null;
+
+	if ((! folders_by_label["StumbleUpon"])
+			&& (! nonfolders_by_label["StumbleUpon"]))
+	{
+		item = Application.bookmarks.menu.addFolder("StumbleUpon");
+	}
+	
+	var basename = "StumbleUpon - " + StumbleGlobals.ds.getValue("$nick");
+	var i = 1;
+	var candidate_name;
+	while (! item)
+	{
+		if (i == 1)
+			candidate_name = basename;
+		else
+			candidate_name = basename + " (" + i + ")";
+			
+		if (folders_by_label[candidate_name])
+			item = folders_by_label[candidate_name];
+		else if (! nonfolders_by_label[candidate_name])
+			item = Application.bookmarks.menu.addFolder(candidate_name);
+		
+		i++;
+	}
+	
+	StumbleGlobals.ds.setValue("$bm_folderid", item.id);
+	
+	StumbleGlobals.ds.flushPrefs();
+}
+
+StumbleGlobals.check_clear_history = function()
+{
+	var ids = StumbleGlobals.ds.getValue("@id_list").split(":");
+
+	var startid = StumbleGlobals.stumbleid;
+	
+	for (i = 0; i < ids.length; i++)
+	{
+		var id = ids[i];
+		if(!id)
+			continue;
+		
+		StumbleGlobals.stumbleid = id;
+		
+		if (StumbleGlobals.ds.getUserPrefValue(id, "$search_clear_queries"))
+		{
+			// If it's the current user, clear the search box
+			if(id == startid)
+			{
+				if(StumbleGlobals.get_element("stumbleglobals_searchbox"))
+					StumbleGlobals.get_element("stumbleglobals_searchbox").value = "";
+				StumbleGlobals.old_search = "";
+			}
+			
+			// Remove their query history
+			StumbleGlobals.queries = new Array();
+			StumbleGlobals.store_queries();
+
+			// And clear the last category if it was a search category.
+			var last_cat = StumbleGlobals.ds.getUserPrefValue(id, "$last_incat");
+			if( last_cat && ((last_cat.indexOf("TAG_") == 0) || (last_cat.indexOf("USERTAG_") == 0)))
+				StumbleGlobals.ds.setUserPrefValue(id, "$last_incat", "0");
+		}
+	}
+	
+	StumbleGlobals.stumbleid = startid;
+}
+
+// handles the global logout event
+StumbleGlobals.logout = function()
+{
+	// 0. If we don't hide the popup, the menu get munged
+	var stumble_popup = StumbleGlobals.get_element("stumbleglobals_stumble_popup");
+	if (typeof(stumble_popup.hidePopup) == "function")
+	{
+		stumble_popup.hidePopup();
+		StumbleGlobals.unfocus();
+	}
+	
+	if (StumbleGlobals.stumble_async_context && StumbleGlobals.stumble_async_context._request)
+	{
+		// kill the pending action
+		StumbleGlobals.service.abortPostAsync(StumbleGlobals.stumble_async_context._request);
+	}
+	
+	StumbleGlobals.stumbleReporter.stop();
+	
+	try {	
+		StumbleGlobals.prefetcher.stop();
+		StumbleGlobals.prefetcher.clearTargets();
+	} catch (e) { StumbleGlobals.log_error("PREFETCHER 4", e); }
+	
+	try {
+		StumbleGlobals.close_all_messages();
+	} catch (e) { StumbleGlobals.log_error("LOGOUT CLOSEALLMSGS", e); }
+	
+	// Clear search history if they want us to
+	StumbleGlobals.check_clear_history();
+	
+	StumbleGlobals.logout_auth(); // clears user session globals
+
+	StumbleGlobals.init_labels();
+	
+	StumbleGlobals.init_toolbar_element_visibility();
+	
+	StumbleGlobals.refresh_pagemeta(false, 5);
+
+	StumbleGlobals.get_element("stumbleglobals_stumble").setAttribute("image2", "");
+	
+	setTimeout(function() {
+		StumbleGlobals.reflow_toolbar(2);
+	}, 0);
+
+	StumbleGlobals.commands_by_keyspec = new Object();
+
+	window.removeEventListener("keyup", StumbleGlobals.handle_window_keyup, false);
+	window.removeEventListener("keypress", StumbleGlobals.handle_window_keypress, false);
+
+	var toggle_key = StumbleGlobals.get_element("key_StumbleUpon:ToggleToolbar");
+	if (toggle_key)
+		toggle_key.setAttribute("command", toggle_key.getAttribute("savedcommand"));
+
+	var toolbar_el = StumbleGlobals.get_element("stumbleupon");
+	if (toolbar_el)
+		toolbar_el.setAttribute("toolbarname", toolbar_el.getAttribute("savedtoolbarname"));
+	
+}
+
+StumbleGlobals.report_uninstall = function()
+{
+	// TODO:  "method" is redundant, but apparently the services API isn't picking up
+	// the method from the command-line when you use POST.  Fix this server-side.
+	var params = "";
+	params = StumbleGlobals.arp(params, "method", "uninstall");
+	params = StumbleGlobals.arp(params, "client_type", "mozbar");
+	params = StumbleGlobals.arp(params, "version", StumbleGlobals.useragent);
+	
+	// Add the current client id if it exists
+	var clientid = StumbleGlobals.ds.getValue("@clientid");
+	if(clientid)
+	{
+		params = StumbleGlobals.arp(params, "clientid", clientid);
+	}
+
+	var context = {};
+	context.quiet = true;
+	
+	StumbleGlobals.post_url_async(
+		StumbleGlobals.serviceshttp + "client.uninstall",
+		params,
+		15000,
+		null,
+		context);
+}
+
+// handles the Extension Manager uninstall event in Firefox 1.5+; 
+// prompts for uninstallation options
+StumbleGlobals.handle_em_uninstall = function()
+{
+	StumbleGlobals.uninstall_scheduled = true;
+
+	var recent_window = StumbleGlobals.get_service(
+				"@mozilla.org/appshell/window-mediator;1",
+				"nsIWindowMediator")
+				.getMostRecentWindow("navigator:browser");
+
+	if (window != recent_window)
+		return;
+	
+	// Send an uninstall notification
+	StumbleGlobals.report_uninstall();
+	
+	// Build the details for the uninstall dialog
+	var detail = new Object();
+	detail.logout = false;
+	detail.remove_data = false;
+
+	StumbleGlobals.unfocus_searchbox(); 
+
+	window.openDialog(
+				"chrome://stumbleupon/content/uninstallDialog.xul",
+				"stumbleglobals_uninstall_options",
+				"chrome,modal,dialog,centerscreen,dependent", 
+				detail);
+				
+	if (detail.logout)
+		StumbleGlobals.invoke_global_event("logout", null);
+	
+	if (detail.remove_data)
+		StumbleGlobals.invoke_global_event("schedule-remove-data", null);
+}
+
+
+// handles the global schedule-remove-data event
+StumbleGlobals.schedule_remove_data = function()
+{
+	// We remove the data now for good measure, then we remove it again
+	// when each window is closed and when the app quits. -- JW
+	StumbleGlobals.remove_data_scheduled = true;
+	StumbleGlobals.remove_data();
+}
+
+// removes all stumbleupon files and preferences
+StumbleGlobals.remove_data = function()
+{
+	var ids = [];
+	try {
+		ids = StumbleGlobals.ds.getValue("@id_list").split(":");
+	} catch (e) {
+	}
+	var i;
+	for (i = 0; i < ids.length; i++)
+	{
+		if (ids[i] == "")
+			continue;
+		
+		StumbleGlobals.ds.deleteFile(StumbleGlobals.ds.getLegacyNSIFile("stumbleurls", ids[i]));
+		StumbleGlobals.ds.deleteFile(StumbleGlobals.ds.getLegacyNSIFile("stumblerating", ids[i]));
+		StumbleGlobals.ds.deleteFile(StumbleGlobals.ds.getLegacyNSIFile("stumbletags", ids[i]));
+		StumbleGlobals.ds.deleteFile(StumbleGlobals.ds.getLegacyNSIFile("stumblequeries", ids[i]));
+	}
+
+	var file = StumbleGlobals.get_service(
+				"@mozilla.org/file/directory_service;1",
+				"nsIProperties")
+				.get("ProfD", Components.interfaces.nsIFile);
+	file.append("StumbleUpon");
+	StumbleGlobals.ds.deleteDirectory(file);
+	
+	var pref_names = StumbleGlobals.ds.getPrefNames("stumble.");
+	for (i = 0; i < pref_names.length; i++)
+	{
+		try {
+			StumbleGlobals.ds.clearPref(pref_names[i]);
+		} catch (e) {}
+	}
+
+	var cookieManager = StumbleGlobals.get_service(
+			"@mozilla.org/cookiemanager;1",
+			"nsICookieManager");
+	cookieManager.remove("." + StumbleGlobals.servername, "PHPSESSID", "/", 0);
+	cookieManager.remove("." + StumbleGlobals.servername, "stumble_user", "/", 0);
+	cookieManager.remove("." + StumbleGlobals.servername, "stumble_pass", "/", 0);
+	cookieManager.remove("." + StumbleGlobals.servername, "tsuu", "/", 0);
+	cookieManager.remove("." + StumbleGlobals.servername, "tsut", "/", 0);
+	cookieManager.remove("." + StumbleGlobals.servername, "nickname", "/", 0);
+	cookieManager.remove("." + StumbleGlobals.servername, "searchlinks", "/", 0);
+	cookieManager.remove("." + StumbleGlobals.servername, "thru_domains", "/", 0);
+	cookieManager.remove("." + StumbleGlobals.servername, "enableu", "/", 0);
+	cookieManager.remove("." + StumbleGlobals.servername, "enableg", "/", 0);
+	cookieManager.remove("." + StumbleGlobals.servername, "stumbleglobals_REMEMBER", "/", 0);
+	
+	StumbleGlobals.logout_server();
+}
+
+// Handler for menuitem "Chatroom"
+StumbleGlobals.chat = function()
+{
+	var doc = getBrowser().contentDocument;
+
+	if (StumbleGlobals.stumbleid == 0)
+		return;
+
+	// Redirect to the chat page
+	getBrowser().contentDocument.location = StumbleGlobals.base_url + "chat.php";
+}
+
+// Handler for button "FirstRater" (the happy face)
+StumbleGlobals.firstrater_func = function(event)
+{
+	var doc = getBrowser().contentDocument;
+
+	if (StumbleGlobals.stumbleid == 0)
+		return;
+
+	var frater = StumbleGlobals.get_element("firstrater");
+	var firstrater = frater.firstrater;
+
+	StumbleGlobals.set_location(
+				"http://" + firstrater + "." + StumbleGlobals.servername + "/",
+				null,
+				StumbleGlobals.new_tab(event));
+}
+
+// sets the tabbrowser location, to one of the user's profile tabs
+StumbleGlobals.set_profile_location = function(profile_tab, new_tab)
+{
+	var nick = StumbleGlobals.ds.getValue("$nick");
+
+	var go_url = '';
+	if (nick == '')
+		go_url = "http://" + StumbleGlobals.stumbleid + "." + StumbleGlobals.servername + "/";
+	else
+		go_url = "http://" + nick + "." + StumbleGlobals.servername + "/";		
+
+	if (profile_tab != '')
+		go_url += profile_tab + "/";
+
+	StumbleGlobals.set_location(go_url, null, new_tab);
+}
+
+// sets the tabbrowser location, when the location is beneath the 
+// www stumbleupon domain
+StumbleGlobals.set_server_location = function(url_suffix, postdata, new_tab)
+{
+	StumbleGlobals.set_location(StumbleGlobals.base_url + url_suffix, postdata, new_tab, null)
+}
+
+StumbleGlobals.set_server_location_signup = function(new_tab)
+{
+	var params = "";
+	var loc = "signup.php";
+	if (StumbleGlobals.host.dist)
+		loc = "sign_up.php";
+	
+	params = StumbleGlobals.arp(params, "version", StumbleGlobals.useragent);
+	
+	if (StumbleGlobals.host.dist)
+		loc = StumbleGlobals.arp(loc, "dist", StumbleGlobals.host.dist, true);
+	
+	if (StumbleGlobals.ds.getValue("@facebook_user"))
+		loc = StumbleGlobals.arp(loc, "pre", "facebook", true);
+	
+	StumbleGlobals.set_server_location(
+				loc,
+				params,
+				new_tab);		
+}
+
+// sets the tabbrowser location
+StumbleGlobals.set_location = function(uri, postdata, new_tab, opt_detail)
+{
+	if ((typeof opt_detail) == "undefined")
+		opt_detail = null;
+	
+	var browser = getBrowser();
+	if (new_tab)
+	{
+		var tab = browser.addTab(
+					uri,
+					StumbleGlobals.get_nsiuri(browser.contentDocument.referrer),
+					null, // charset
+					(postdata == null) ? null : StumbleGlobals.get_mime_input_stream(postdata, "application/x-www-form-urlencoded"));
+		browser.selectedTab = tab;
+		
+		tab.stumbleglobals_detail = opt_detail;
+	}
+	else
+	{
+		browser.selectedTab.stumbleglobals_detail = opt_detail;
+		
+		browser.webNavigation.loadURI(
+					uri,
+					Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE,
+					StumbleGlobals.get_nsiuri(browser.contentDocument.referrer),
+					(postdata == null) ? null : StumbleGlobals.get_mime_input_stream(postdata, "application/x-www-form-urlencoded"),
+					null); // headers
+	}
+}
+
+// Handler for button "Website Info"
+StumbleGlobals.website_info = function(new_tab, theurl, firstrate)
+{
+	
+	if (StumbleGlobals.ds.getValue("$review_new_window"))
+		new_tab = true;
+
+	if (StumbleGlobals.stumbleid == 0)
+		return;
+
+	var current_page = theurl;
+	
+	if (theurl == "")
+	{
+		current_page = StumbleGlobals.get_browser_url();		
+		if (StumbleGlobals.stumbled_redirect != '' && current_page == StumbleGlobals.stumbled_redirect)
+		{
+			// we have a redirect, rate the original url we stumbled on
+			current_page = StumbleGlobals.stumbled_url;
+		}		
+	}
+	
+	var cmp_url = current_page.toLowerCase();
+	
+	if (cmp_url.indexOf("http://video." + StumbleGlobals.servername + "/#p") == 0)
+		return;
+				
+	if (cmp_url.indexOf("http://video." + StumbleGlobals.servername + "/?p") == 0)
+		return;
+	
+	var stumblevideo = (StumbleGlobals.get_stumblevideo_detail() != null);
+	
+	if (current_page.indexOf("about:") == 0)
+		return;
+	
+	if ((StumbleGlobals.quote == "") && getBrowser().contentWindow.getSelection)
+	{
+		quote = getBrowser().contentWindow.getSelection().toString();
+	}
+	else
+	{
+		quote = StumbleGlobals.quote;
+		StumbleGlobals.quote = "";
+	}
+	
+	var searchbox_value = StumbleGlobals.get_element("stumbleglobals_searchbox").value;
+	if ((! StumbleGlobals.ds.getValue("$show_field")) || 
+				(searchbox_value == StumbleGlobals.tag_instructions) ||
+				StumbleGlobals.validate_tagstring(searchbox_value))
+	{
+		searchbox_value = "";
+	}
+	
+	var current_page2 = current_page;
+	if (current_page2.length > 300)
+		current_page2 = current_page2.substr(0, 300);
+
+	if ((! stumblevideo) && StumbleGlobals.photoblogimage)
+	{
+		StumbleGlobals.set_server_location(
+					"url.php?url=" + encodeURIComponent(current_page2) + 
+						"&image=" + encodeURIComponent(StumbleGlobals.photoblogimage.src) + 
+						"&width=" + StumbleGlobals.photoblogimage.width + 
+						"&height=" + StumbleGlobals.photoblogimage.height + 
+						"&firstrate=" + firstrate + 
+						"&tag=" + escape(searchbox_value),
+					null,
+					new_tab);
+		StumbleGlobals.photoblogimage = null;
+	}
+	else if ((! stumblevideo) && (quote != ""))
+	{
+		StumbleGlobals.set_server_location(
+					"url.php?url=" + encodeURIComponent(current_page2) + 
+						"&quote=" + encodeURIComponent(quote) + 
+						"&firstrate=" + firstrate + 
+						"&tag=" + escape(searchbox_value), 
+					null,
+					new_tab);
+	}
+	else
+	{
+		StumbleGlobals.set_server_location(
+					"url/" + StumbleGlobals.review_url(current_page),
+					null,
+					new_tab);
+//		setTimeout(
+//					StumbleGlobals.set_server_location,
+//					3000,
+//					"url/" + StumbleGlobals.review_url(current_page, true),
+//					null,
+//					new_tab);
+	}
+}
+
+StumbleGlobals.review_url = function(url, new_impl)
+{
+	// strip off the http://
+	if (url.match(/^http:\/\//i))
+		url = url.substr(7);
+	
+	url = encodeURIComponent(url);
+	
+	url = encodeURIComponent(url);
+
+	url = url.replace(/%252F/g, "/");
+
+	return url;
+}
+
+// Check to see if an email is valid
+StumbleGlobals.validate_email = function(str)
+{
+	// var filter=/^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
+	var filter  = /^([a-zA-Z0-9_\.\-+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
+	if (filter.test(str))
+		return(true);
+	else
+		return(false);
+}
+
+StumbleGlobals.remove_email = function(email)
+{
+	if (!(window.confirm("Are you sure that you want to delete the email address '" + email + "'")))
+		return;
+
+	var contact = StumbleGlobals.ds.selectRow("contact", "email", email);
+	
+	if (! contact)
+		return;
+	
+	contact.hidden = true;
+	StumbleGlobals.ds.updateRow(contact);
+	StumbleGlobals.ds.flushPrefs();
+	
+	StumbleGlobals.refresh_referral_menu(2);
+}
+
+StumbleGlobals.sendto = function(recipients)
+{
+	if (StumbleGlobals.stumbleid == 0)
+		return;
+	
+	var current_page = StumbleGlobals.get_browser_url();
+
+	StumbleGlobals.unfocus_searchbox(); 
+
+	for(var i=0; i<recipients.length; i++)
+	{
+		var to = recipients[i];
+		if(to.send_type == "mail")
+		{
+			// Save the email
+			var contact = StumbleGlobals.ds.selectRow("contact", "email", to.target);
+			
+			if (contact && contact.hidden)
+			{
+				contact.hidden = false;
+				StumbleGlobals.ds.updateRow(contact);
+			}
+			else if (! contact)
+			{
+				contact = new Object();
+				contact.email = to.target;
+				StumbleGlobals.ds.insertRow("contact", contact);
+			}
+		
+			StumbleGlobals.ds.flushPrefs();	
+		}
+	}
+
+	var detail = new Object();
+	detail.mode = "send";
+	detail.recipients = recipients;
+	detail.url = current_page;
+	detail.display_url = StumbleGlobals.get_browser_url(null, true);
+	detail.stumblevideo = (StumbleGlobals.get_stumblevideo_detail() != null);
+	
+	if(recipients.length == 1)
+		detail.dialog_title = "Send to " + recipients[0].target;
+	else
+		detail.dialog_title = "Send to " + recipients.length + " contacts";
+	
+	//detail.show_target = StumbleGlobals.host.mac;
+	detail.show_target = true;
+	detail.referrer_url = StumbleGlobals.get_browser_referrer_url();
+
+	window.openDialog(
+				"chrome://stumbleupon/content/sendDialog.xul",
+				"",
+				"chrome,dialog,centerscreen,dependent", 
+				detail);
+}
+
+StumbleGlobals.generic_done = function(res)
+{
+	var context = res.detail;
+	
+	try {
+		if (res.status != 200)
+			return;
+	} catch (e) { return; } 
+	
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+	
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response " + context.request_target, s);
+	
+	StumbleGlobals.process_commands(s, context);
+}
+
+StumbleGlobals.serverdown_message = function(operation, aborted, error, status)
+{
+	var msg = "";
+	
+	if(!operation)
+		operation = "Operation";
+	
+	msg = operation + " failed.\n\n";
+	
+	msg +=	"The stumbleupon.com server appears to be down.\nPlease try again, and if you are still having difficulties,\n" +
+			"go to " + StumbleGlobals.base_url + "feedback.php to report the problem details:\n\n";
+	if(aborted)
+		msg += "Cause: Aborted\n";
+	if(error)
+		msg += "Error: " + error;
+	
+	if(status)
+		msg += "Status: " + status;
+	
+	alert(msg);
+}
+
+//
+// Processes a toolbar JSON-response-format request.  This is a new format
+// that is used for the other toolbars.
+//
+// An example is shareservices.php
+//
+// These responses are JSON-formatted
+//
+StumbleGlobals.newjson_request_done = function(res)
+{
+	var context = res.detail;
+	if(context && context.enable_element)
+		context.enable_element.setAttribute("disabled", "false");
+	
+	try {
+		if (res.aborted)
+		{
+			StumbleGlobals.serverdown_message(context.operation, res.aborted, null, null);
+			return;
+		}
+		else if(res.status != 200)
+		{
+			StumbleGlobals.serverdown_message(context.operation, null, null, res.status);
+			return;
+		}
+	} catch (e) {	return; } 
+	
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+	
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response " + context.request_target, s);
+
+	if(s)
+	{
+		// If there was an error, try to find an error message to display
+		var obj = StumbleGlobals.ds.deserialize(s);
+		if(obj && (obj.status == "error"))
+		{
+			var operation = "Operation";
+			if(context.operation)
+				operation = context.operation;
+				
+			var msg = operation + " failed, please try again later.  If the problem persists, please go to " + StumbleGlobals.base_url + "feedback.php " +
+						"to report the problem.";
+			
+			if(obj.errors && obj.errors.length)
+			{
+				for(var i=0; i<obj.errors.length; i++)
+				{
+					if(obj.errors[i].msg)
+					{
+						// Display the error message
+						msg = operation + " error: " + obj.errors[i].msg;
+						break;
+					}
+				}
+			}
+			alert(msg);
+		}
+		
+		if(obj && obj.commands)
+		{
+			StumbleGlobals.process_commands(obj.commands, context);
+		}
+	}
+}
+
+// TODO:  I suspect this completion method should be used in more places, but we are 
+//        too close to a release right now to touch too many code paths.  Note that this
+//        is the same code in stumble done, so at least those two should be combined. 
+//
+StumbleGlobals.verbose_generic_done = function(res)
+{
+	var context = res.detail;
+	res.done = true;
+	
+	try {
+		if (res.status != 200)
+		{
+			// Maintenance mode returns 503 with "ERROR xxx" set.
+			// In that case, let the "ERROR" command be handled.
+			var isMaintenanceMode = false;
+			if(res.status == 503)
+			{
+				var commands = res.responseText.split(" ");
+				if(commands.length && (commands[0] == "ERROR"))
+				{
+					// Let it fall through 
+					isMaintenanceMode = true;
+				}
+			}
+			if(!isMaintenanceMode)
+			{
+				if (! context.quiet)
+					alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to "
+						+ StumbleGlobals.base_url + "feedback.php to report the problem\nError : " + res.error + "\nStatus : " + res.status);
+				if (callback)
+					callback("connection error", ancestor_callback, context);
+				return;
+			}
+		}
+	} catch (e) { return; } 
+	
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+	
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response " + context.request_target, s);
+	
+	StumbleGlobals.process_commands(s, context);
+}
+
+
+// Handler for menuitem "About"
+StumbleGlobals.about = function()
+{
+	// Redirect to about page
+	getBrowser().contentDocument.location = StumbleGlobals.serverhttp + 'about.php?version=' + StumbleGlobals.verstring;
+}
+
+StumbleGlobals.get_friends = function()
+{
+	var params = "";
+	params = StumbleGlobals.arp(params, "now", StumbleGlobals.get_time_s());
+	params = StumbleGlobals.arp(params, "configured", StumbleGlobals.ds.getValue("$friends_synced"));
+	
+	StumbleGlobals.post_url_server_async(
+				"getfriends.php",
+				params,
+				null,
+				StumbleGlobals.get_friends_done,
+				null);
+}
+
+StumbleGlobals.get_friends_done = function(res)
+{
+	try {
+		if (res.status != 200)
+			return;
+	} catch (e) { return; } 
+	
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+	
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response getfriends.php", s);
+	
+	var context = new Object();
+	context.quiet = true;
+	StumbleGlobals.process_commands(s, context);
+	
+	StumbleGlobals.ds.setValue("$friends_synced", "" + StumbleGlobals.get_time_s());
+}
+
+StumbleGlobals.get_facebook_userid = function()
+{
+	var fbuserid = StumbleGlobals.ds.getValue("#facebook_userid"); 
+	if (fbuserid)
+		return fbuserid;
+	
+	var manager = StumbleGlobals.get_service(
+				"@mozilla.org/cookiemanager;1",
+				"nsICookieManager");
+	var cookies = manager.enumerator;
+	var cookie;
+	
+	while (cookies.hasMoreElements())
+	{
+		cookie = cookies.getNext().QueryInterface(
+					Components.interfaces.nsICookie);
+					
+		if (cookie.host == ".facebook.com")
+		{
+			if (cookie.name == "c_user")
+			{
+				fbuserid = parseInt(cookie.value);
+				break;
+			}
+		}
+	}
+	StumbleGlobals.ds.setValue("#facebook_userid", fbuserid);
+	return fbuserid;
+}
+
+StumbleGlobals.get_facebook = function(doc)
+{
+	if (StumbleGlobals.stumbleid == 0)
+		return;
+	
+	if (StumbleGlobals.ds.getValue("#checking_facebook"))
+		return;
+	
+	StumbleGlobals.ds.setValue("#checking_facebook", true);
+	
+	var detail = new Object();
+	detail.doc = doc;
+	detail.stumbleid = StumbleGlobals.stumbleid;
+	
+	var fbuserid = StumbleGlobals.get_facebook_userid();
+	
+	if (! fbuserid)
+	{
+		StumbleGlobals.ds.setValue("#checking_facebook", false);
+		return;
+	}
+	
+	StumbleGlobals.post_url_server_async(
+				"getfacebook.php",
+				StumbleGlobals.arp("", "id", fbuserid),
+				15000,
+				StumbleGlobals.get_facebook_done,
+				detail);
+}
+
+StumbleGlobals.get_facebook_done = function(res)
+{
+	try {
+		if (res.status != 200)
+			return;
+	} catch (e) { return; } 
+	
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+	
+	var detail = res.detail;
+	
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response getfacebook.php", s);
+	
+	if (detail.stumbleid != StumbleGlobals.stumbleid)
+		return;
+	
+	StumbleGlobals.ds.setValue("#checking_facebook", false);	
+	
+	if (! res.aborted)
+		StumbleGlobals.ds.setValue("#checked_facebook", true);
+	
+	var context = new Object();
+	context.quiet = true;
+	StumbleGlobals.process_commands(s, context);
+	
+	StumbleGlobals.refresh_pagemeta(false, 6);
+	
+	if (detail.doc)
+		StumbleGlobals.facebookhome_page(detail.doc);
+}
+
+StumbleGlobals.get_state = function(migrating)
+{
+	StumbleGlobals.post_url_server_async(
+				"getstate.php",
+				StumbleGlobals.arp("", "migrating", ((migrating) ? 1 : 0)),
+				null,
+				StumbleGlobals.get_state_done,
+				null);
+}
+
+StumbleGlobals.get_state_done = function(res)
+{
+	try {
+		if (res.status != 200)
+			return;
+	} catch (e) { return; } 
+	
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+	
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response getstate.php", s);
+	
+	var context = new Object();
+	context.quiet = true;
+	StumbleGlobals.process_commands(s, context, true, 0);
+}
+
+StumbleGlobals.import_contacts = function()
+{
+	// hit getcontacts.php, parse, and add non-dupes to menu	
+	StumbleGlobals.post_url_server_async(
+				"getcontacts.php",
+				null,
+				null,
+				StumbleGlobals.import_contacts_done,
+				null);
+}
+
+StumbleGlobals.import_contacts_done = function(res)
+{
+	try {
+		if (res.status == 1)
+			return;
+	} catch (e) { return; }
+
+	if (res.status != 200)
+		return;
+	
+	var s = res.responseText;
+
+	if (typeof(s) != "object" && typeof(s) != "undefined" && s != "")
+	{
+		var newlines = s.split("\n");
+		for (var i = 0; i < newlines.length; i++)
+		{
+			if (newlines[i] == "")
+				continue;
+			
+			var lines = newlines[i].split(",");
+			if (lines.length>0)
+			{
+				var email = lines[0];
+
+				//invalid email address
+				if (!StumbleGlobals.validate_email(email))
+					continue;
+				
+				var contact = StumbleGlobals.ds.selectRow("contact", "email", email);
+				if (! contact)
+				{
+					contact = new Object();
+					contact.email = email;
+					StumbleGlobals.ds.insertRow("contact", contact);
+				}
+			}
+		}
+		StumbleGlobals.ds.flushPrefs();
+		StumbleGlobals.refresh_referral_menu(4);	
+	}
+}
+
+StumbleGlobals.get_interests = function()
+{
+	StumbleGlobals.post_url_server_async(
+				"getinterests.php",
+				null,
+				null,
+				StumbleGlobals.get_interests_done,
+				null);
+}
+
+StumbleGlobals.get_interests_done = function(res)
+{
+	try {
+		if (res.status != 200)
+			return;
+	} catch (e) { return; } 
+	
+	var s = "";
+	
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+	
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response getinterests.php", s);
+	
+	if (typeof(s) != "string")
+		return;
+		
+	StumbleGlobals.process_topic_list(s);
+}
+
+StumbleGlobals.dist_time = function()
+{
+	var now = StumbleGlobals.get_time_s();
+	var installed = StumbleGlobals.ds.getIntValue("@installed");
+	if (installed == 0)
+	{
+		installed = now;
+		StumbleGlobals.ds.setValue("@installed", "" + now);
+	}
+	
+	if (! StumbleGlobals.host.dist)
+		return;
+	
+	if (StumbleGlobals.dist_time_timer)
+	{
+		// if the user changes, this clears the timeout set for the
+		// previously logged in user
+		clearTimeout(StumbleGlobals.dist_time_timer);
+	}
+	
+	var reg_prev = StumbleGlobals.ds.getIntValue("@dist_reg");
+	var interval = 7 * 24 * 60 * 60 * 1000;
+	var id_list_prev = StumbleGlobals.ds.getValue("@dist_id_list");  
+	var id_list = StumbleGlobals.ds.getValue("@id_list");
+	if ((reg_prev < (now - interval)) && ((id_list_prev == "") || 
+				(id_list_prev != id_list)))
+	{
+		StumbleGlobals.ds.setValue("@dist_reg", "" + now);
+		
+		var params = "";
+		params = StumbleGlobals.arp(params, "dist", StumbleGlobals.host.dist);
+		params = StumbleGlobals.arp(params, "regid", StumbleGlobals.ds.getValue("@dist_regid")); 
+		params = StumbleGlobals.arp(params, "idlist", id_list); 
+		params = StumbleGlobals.arp(params, "preidlist", id_list_prev);
+		params = StumbleGlobals.arp(params, "age", (now - installed));
+		params = StumbleGlobals.arp(params, "visible", 
+					(StumbleGlobals.ds.getValue("@toolbar-visible")) ? 1 : 0);
+		StumbleGlobals.post_url_server_async(
+					"disttime.php",
+					params,
+					null,
+					StumbleGlobals.dist_time_done,
+					null);
+	}
+
+	StumbleGlobals.dist_time_timer = setTimeout(function () {
+		StumbleGlobals.dist_time();
+	},  interval - (StumbleGlobals.random_delay * 1000));
+}
+
+StumbleGlobals.dist_time_done = function(res)
+{
+	try {
+		if (res.status != 200)
+			return;
+	} catch (e) { return; } 
+	
+	StumbleGlobals.ds.setValue("@dist_id_list", StumbleGlobals.ds.getValue("@id_list"));
+	
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+	
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response disttime.php", s);
+
+	var context = new Object();
+	context.quiet = true;
+	StumbleGlobals.process_commands(s, context);
+}
+
+//
+// After a certain period of idle stumble activity, we want to reset
+// the stumble category back to "All".  This takes care of preventing users from
+// unknowingly being stuck in a category.
+//
+StumbleGlobals.test_category_reset = function()
+{
+	var last_stumbled = StumbleGlobals.ds.getIntValue("$last_stumble");
+	if(StumbleGlobals.selected_category == "0")
+	{
+		// We are already in "all"
+		return;
+	}
+	
+	var last_stumbled = StumbleGlobals.ds.getIntValue("$last_stumble");
+	var category_reset_timeout = StumbleGlobals.ds.getValue("@category_reset_timeout");
+	var timenow = (new Date()).getTime();
+	
+	var diff = timenow - last_stumbled;
+	if(diff >= category_reset_timeout)
+	{
+		StumbleGlobals.set_mode_all();
+	}
+}
+
+StumbleGlobals.process_quarter_hourly = function()
+{
+	StumbleGlobals.test_category_reset();
+}
+
+StumbleGlobals.process_rarely = function(force_dyn_channels, timeout)
+{
+	if (StumbleGlobals.process_rarely_timer)
+	{
+		// if the user changes, this clears the timeout set for the
+		// previously logged in user
+		clearTimeout(StumbleGlobals.process_rarely_timer);
+	}
+	var old_timestamp = StumbleGlobals.ds.getIntValue("$process_rarely_timestamp");
+	var last_stumbled = StumbleGlobals.ds.getIntValue("$last_stumble");
+	
+	var timenow = (new Date()).getTime();
+	
+	var interval = 48 * 60 * 60 * 1000; // two days
+	var oneweek = 7 * 24 * 60 * 60 * 1000;
+	
+	StumbleGlobals.process_slclicks(timeout);
+	
+	if (force_dyn_channels)
+	{
+		StumbleGlobals.ds.setValue("$process_rarely_timestamp", timenow);
+		StumbleGlobals.check_dyn_channels();
+	}
+	else if ( ((timenow - old_timestamp) > interval) && 
+				((timenow - last_stumbled) < (8 * oneweek)) )
+	{
+		StumbleGlobals.ds.setValue("$process_rarely_timestamp", timenow);
+		// Routines here run every second day unless the user hasn't 
+		// stumbled for two months. -- JW
+		StumbleGlobals.check_dyn_channels();
+	}
+	StumbleGlobals.process_rarely_timer = setTimeout(StumbleGlobals.process_rarely, interval - (StumbleGlobals.random_delay * 1000), false, true);
+}
+
+StumbleGlobals.check_dyn_channels = function()
+{
+	var url = "http://cdn.stumble-upon.com/stumblethru.csv";
+	
+	if (StumbleGlobals.test_stumblethru_update)
+		url = StumbleGlobals.serverhttp + "stumblethru.csv";
+	
+	StumbleGlobals.ds.setValue("#checked_dyn_channels", true);
+	StumbleGlobals.post_url_async(
+				url,
+				null,
+				null,
+				StumbleGlobals.check_dyn_channels_done,
+				null);
+}
+
+StumbleGlobals.check_dyn_channels_done = function(res)
+{
+	try {
+		if (res.status != 200)
+			return;
+	} catch (e) { return; } 
+	
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response stumblethru.csv", s);
+
+	if (StumbleGlobals.ds.getValue("#installing_favicons"))
+		return;
+	
+	StumbleGlobals.ds.setValue("#installing_favicons", true);
+	
+	// Parse response text
+	var items = s.split("\n");
+
+	var default_domain_list = StumbleGlobals.ds.getValue("$default_thru_domain_list");
+	var default_domain_flags = new Object();
+	if (default_domain_list != "")
+	{
+		var domains = default_domain_list.split(" ");
+		for (i = 0; i < domains.length; i++)
+			default_domain_flags[domains[i]] = 1;
+	}
+	
+	var i;
+
+	var j;
+	var channel;
+	var good_channels = new Object(); 
+	var has_favicons = StumbleGlobals.ds.getValue("$has_favicons");
+	
+	var checked_sanity = false;
+	
+	for (i = 0; i < items.length; i++)
+	{
+		if (items[i] == "")
+			continue;
+		
+		// do a sanity check on the first nonempty row
+		if (! checked_sanity)
+		{
+			checked_sanity = true;
+			if (! items[i].match(/^.*\..*,\d+,/))
+				return;
+		}
+		
+		var domain = items[i].split(",")[0];
+		var name = items[i].split(",")[2];
+		good_channels[domain] = 1;
+		
+		channel = StumbleGlobals.ds.getThruDomainChannel(domain);
+		
+		var filename = StumbleGlobals.get_channel_id(domain) + ".ico";
+		var url = "http://cdn.stumble-upon.com/images/stumblethru/" + filename;
+		if (StumbleGlobals.test_stumblethru_update)
+			url = StumbleGlobals.serverhttp + "images/stumblethru/" + filename;
+		if (channel)
+		{
+			channel.name = name;
+			StumbleGlobals.ds.updateRow(channel);
+			if ((! has_favicons) || (! StumbleGlobals.ds.isResourceInstalled("favicons", filename)))
+			{
+				StumbleGlobals.ds.installResource(
+						url,
+						"favicons",
+						filename);
+			}
+		}
+		else
+		{
+			channel = new Object();
+			channel.domain = domain;
+			channel.name = name;
+			if (default_domain_flags[domain])
+				channel.show = 1;
+			StumbleGlobals.ds.installResource(
+					url,
+					"favicons",
+					filename);
+			StumbleGlobals.ds.insertRow("dyn_channel", channel);
+		}
+	}
+	
+	var channels = StumbleGlobals.ds.getThruDomainChannels(false);
+	for (i = 0; i < channels.length; i++)
+	{
+		if (! good_channels[channels[i].domain])
+			StumbleGlobals.ds.deleteRow(channels[i]);
+	}
+}
+
+StumbleGlobals.sync = function(context)
+{
+	if (StumbleGlobals.get_time_s() < StumbleGlobals.ds.getIntValue("$sync_retry_time_s"))
+		return;
+	
+	var params = "";
+	
+	params = StumbleGlobals.append_sync_params(params);
+	
+	var context = new Object();
+	context.quiet = true;
+	context.from_sync = true;
+	
+	StumbleGlobals.post_url_server_async(
+				"sync.php",
+				params,
+				15000,
+				StumbleGlobals.sync_done,
+				context);
+}
+
+StumbleGlobals.getGeckoVersion = function()
+{
+  if (navigator.product != 'Gecko')
+  {
+    return -1;
+  }
+  var rvValue = 0;
+  var ua      = navigator.userAgent.toLowerCase();
+  var rvStart = ua.indexOf('rv:');
+  var rvEnd   = ua.indexOf(')', rvStart);
+  var rv      = ua.substring(rvStart+3, rvEnd);
+
+  return rv;
+}
+
+StumbleGlobals.append_sync_params = function(params)
+{
+	params = StumbleGlobals.arp(params, "ycur_q", StumbleGlobals.ds.getValue("$sync_cur_q"));
+	params = StumbleGlobals.arp(params, "ycur_t", StumbleGlobals.ds.getValue("$sync_cur_t"));
+	params = StumbleGlobals.arp(params, "ycur_s", StumbleGlobals.ds.getValue("$sync_cur_s"));
+	params = StumbleGlobals.arp(params, "ypre_q", StumbleGlobals.ds.getValue("$sync_pre_q"));
+	params = StumbleGlobals.arp(params, "ypre_t", StumbleGlobals.ds.getValue("$sync_pre_t"));
+	params = StumbleGlobals.arp(params, "ypre_s", StumbleGlobals.ds.getValue("$sync_pre_s"));
+	params = StumbleGlobals.arp(params, "yr", StumbleGlobals.ds.getValue("$sync_retry"));
+	params = StumbleGlobals.arp(params, "yts", StumbleGlobals.ds.getValue("$sync_time_s"));
+	return params;
+}
+
+
+//!!! Would be better to store in a command buffer.
+StumbleGlobals.sync_done = function(res)
+{
+	var context = res.detail;
+	
+//	if (context.stopped)
+//		return;
+	
+	try {
+		if (res.status != 200)
+			return;
+	} catch (e) { return; } 
+	
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+	
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response sync.php", s);
+	
+	StumbleGlobals.process_commands(s, context, true, 10); 
+}
+
+StumbleGlobals.process_commands = function(str, opt_context, opt_async, opt_async_interval)
+{
+	var commands = str.split("\n");
+	var i;
+	var interval;
+	var context = (opt_context) ?  opt_context : new Object();
+	
+	if (opt_async)
+	{
+		context.async_commands = commands;
+		context.async_interval = (opt_async_interval) ? opt_async_interval : 0;
+		setTimeout(StumbleGlobals.process_commands2, 0, context);
+	}		
+	else
+	{
+		for (i = 0; i < commands.length; i++)
+		{
+			if (commands[i] == "")
+				continue;
+			StumbleGlobals.process_command(commands[i], context);
+		}
+		setTimeout(function () { StumbleGlobals.ds.flushPrefs(); }, 100);
+	}
+}
+
+StumbleGlobals.process_commands2 = function(context)
+{
+	var command = context.async_commands.shift();
+	
+	if (command != "")
+		StumbleGlobals.process_command(command, context);
+	
+	if (context.async_commands.length)
+	{
+		setTimeout(StumbleGlobals.process_commands2, context.async_interval, context);
+	}
+	else
+	{
+		StumbleGlobals.ds.flushPrefs();
+		StumbleGlobals.refresh_pagemeta(false, 10);
+	}
+}
+
+StumbleGlobals.process_command = function(command_str, context, opt_command_parts)
+{
+	try {
+	
+	var val;
+	var el;
+	var detail;
+	
+	var command_parts;
+	if (opt_command_parts)
+		command_parts = opt_command_parts;
+	else
+		command_parts = command_str.split(" ");
+	
+	switch (command_parts[0])
+	{
+		case "SYNC":
+			if (StumbleGlobals.stumbleid == 0)
+				break;
+			if (StumbleGlobals.disable_sync)
+				return;
+			if (command_parts.length >= 2)
+				StumbleGlobals.ds.setValue("$sync_time_s", parseInt(command_parts[1]));
+			if (command_parts.length >= 3)
+				StumbleGlobals.ds.setValue("$sync_retry", parseInt(command_parts[2]));
+			if (command_parts.length >= 4)
+			{
+				var retry_interval_s = parseInt(command_parts[3]);
+				var retry_time_s = StumbleGlobals.get_time_s() + retry_interval_s;
+				StumbleGlobals.ds.setValue("$sync_retry_time_s", retry_time_s);
+				setTimeout(StumbleGlobals.sync, retry_interval_s * 1000);
+			}
+			break;
+		case "NICK":
+			if (StumbleGlobals.stumbleid == 0)
+				break;
+			if (StumbleGlobals.prev_nick != command_parts[1])
+			{
+				StumbleGlobals.prev_nick = command_parts[1];
+				StumbleGlobals.ds.setValue("$nick", command_parts[1]);
+			}
+			break;
+		case "MESSAGE":
+			if (StumbleGlobals.stumbleid == 0)
+				break;
+			StumbleGlobals.set_inbox_status('2');
+			StumbleGlobals.register_activity("message-notify");
+			break;
+		case "FRIENDS":
+			setTimeout(StumbleGlobals.process_friends_command, 0, command_str);
+			break;
+		case "SEENCONF":
+			StumbleGlobals.process_seenconf_command(command_parts[1], context);
+			break;
+		case "DONE":
+			context.done = true;
+			break;
+		case "KEY":
+			if (context.mode == 1)
+			{
+				context.prekey = command_parts[1];
+			}
+			else if (context.mode == 2)
+			{
+				context.prekey = command_parts[1];
+				context.prekey2 = command_parts[2];
+			}
+			break;
+		case "SQCS":
+			if (StumbleGlobals.stumbleid == 0)
+				break;
+			StumbleGlobals.clear_stumbles();
+			break;
+		case "SQCF":
+			if (StumbleGlobals.stumbleid == 0)
+				break;
+			StumbleGlobals.clear_stumbles();
+			break;
+		case "META":
+			try {
+				StumbleGlobals.process_meta_command(command_parts, context);
+				if (StumbleGlobals.log_sync)
+					StumbleGlobals.logf(command_str);
+			} catch (e) { StumbleGlobals.log_error("META COMMAND", e); }
+			break;
+		case "MEDR":
+			try {
+				StumbleGlobals.process_medr_command(command_parts, context);
+				if (StumbleGlobals.log_sync)
+					StumbleGlobals.logf(command_str);
+			} catch (e) { StumbleGlobals.log_error("MEDR COMMAND", e); }
+			break;
+		case "MEDT":
+			try {
+				StumbleGlobals.process_medt_command(command_parts, context);
+				if (StumbleGlobals.log_sync)
+					StumbleGlobals.logf(command_str);
+			} catch (e) { StumbleGlobals.log_error("MEDT COMMAND", e); }
+			break;
+		case "BKDA":
+			try {
+				StumbleGlobals.process_bkda_command(command_parts, context);
+				if (StumbleGlobals.log_sync)
+					StumbleGlobals.logf(command_str);
+			} catch (e) { StumbleGlobals.log_error("BKDA COMMAND", e); }
+			break;
+		case "BKDR":
+			try {
+				StumbleGlobals.process_bkdr_command(command_parts, context);
+				if (StumbleGlobals.log_sync)
+					StumbleGlobals.logf(command_str);
+			} catch (e) { StumbleGlobals.log_error("BKDR COMMAND", e); }
+			break;
+		case "BKDC":
+			try {
+				StumbleGlobals.process_bkdc_command();
+				if (StumbleGlobals.log_sync)
+					StumbleGlobals.logf(command_str);
+			} catch (e) { StumbleGlobals.log_error("BKDC COMMAND", e); }
+			break;
+		case "TOPICS":
+			try {
+				StumbleGlobals.process_topics_command(command_parts);
+			} catch (e) { StumbleGlobals.log_error("TOPICS COMMAND", e); }
+			break;
+		case "UPDATETOPICS":
+			try {
+				StumbleGlobals.update_topics_command(command_parts);
+			} catch(e) { StumbleGlobals.log_error("UPDATETOPICS COMMAND", e); }
+			break;
+		case "OK":
+			if (StumbleGlobals.stumbleid == 0)
+				break;
+			if (command_parts.length >= 2)
+				StumbleGlobals.ds.setCC(command_parts[1]);
+			break;
+		case "SACK":
+			if (StumbleGlobals.stumbleid == 0)
+				break;
+			context.sack = true;
+			if (command_parts.length >= 2)
+				StumbleGlobals.ds.setValue("$sync_time_s", command_parts[1]);
+			if (command_parts.length >= 3)
+				StumbleGlobals.ds.setValue("$sync_cur_q", command_parts[2]);
+			if (command_parts.length >= 4)
+				StumbleGlobals.ds.setValue("$sync_cur_t", command_parts[3]);
+			if (command_parts.length >= 5)
+				StumbleGlobals.ds.setValue("$sync_cur_s", command_parts[4]);
+			if (command_parts.length >= 6)
+				StumbleGlobals.ds.setValue("$sync_pre_q", command_parts[5]);
+			if (command_parts.length >= 7)
+				StumbleGlobals.ds.setValue("$sync_pre_t", command_parts[6]);
+			if (command_parts.length >= 8)
+				StumbleGlobals.ds.setValue("$sync_pre_s", command_parts[7]);
+			break;
+		case "ENABLEG":
+			StumbleGlobals.enable_client_features(parseInt(command_parts[1]));
+			break;
+		case "DISABLEG":
+			StumbleGlobals.disable_client_features(parseInt(command_parts[1]));
+			break;
+		case "ENABLEU":
+			StumbleGlobals.enable_user_features(parseInt(command_parts[1]));
+			break;
+		case "DISABLEU":
+			StumbleGlobals.disable_user_features(parseInt(command_parts[1]));
+			break;
+		case "ALLAVATARS":
+			if (StumbleGlobals.stumbleid == 0)
+				break;
+			StumbleGlobals.ds.setValue("$has_avatars", false);
+			break;
+		case "TAGGER":
+			if (StumbleGlobals.stumbleid == 0)
+				break;
+			StumbleGlobals.enable_user_features(0x2);
+			break;
+		case "FACEBOOK":
+			if (StumbleGlobals.stumbleid == 0)
+				break;
+			switch (command_parts[1])
+			{
+				case "1":
+					StumbleGlobals.ds.setValue("$facebook_added", true);
+					StumbleGlobals.ds.setValue("$facebook_linked", false);
+					break;
+				case "2":
+					StumbleGlobals.ds.setValue("$facebook_added", true);
+					StumbleGlobals.ds.setValue("$facebook_linked", true);
+					break;
+			}
+			break;
+		case "UPGRADE":
+			if (StumbleGlobals.stumbleid == 0)
+				break;
+			StumbleGlobals.set_visible("stumbleglobals_upgrade", true);
+			break;
+		case "FIRSTFRIEND": 
+			if (StumbleGlobals.stumbleid == 0)
+				break;
+			StumbleGlobals.ds.setValue("$firstfriends", command_str);
+			break;
+//		case "SPONSOR":
+//			StumbleGlobals.ds.setValue("$sponsor", true);
+//			break;
+//		case "NOSPONSOR":
+//			StumbleGlobals.ds.setValue("$sponsor", false);
+//			break;
+		case "REGID":
+			StumbleGlobals.ds.setValue("@dist_regid", command_parts[1]);
+			break;
+		case "SETU":
+			if (StumbleGlobals.stumbleid == 0)
+				break;
+			StumbleGlobals.process_set_pref_command("$" + command_parts[1], command_parts[2]);
+			break;
+		case "SETG":
+			StumbleGlobals.process_set_pref_command("@" + command_parts[1], command_parts[2]);
+			break;
+		case "STUMBLENOW":
+			StumbleGlobals.process_stumble_now_command(command_str);
+			break;
+		case "SUPR_TWITTER_LINK":
+			if(StumbleGlobals.stumbleid == 0)
+				break;
+			StumbleGlobals.ds.setValue("$twitter_supr_linked", (command_parts[1] == "1") ? true : false);
+			StumbleGlobals.refresh_referral_menu(10);
+			break;
+		case "SUPR_FACEBOOK_LINK":
+			if(StumbleGlobals.stumbleid == 0)
+				break;
+			StumbleGlobals.ds.setValue("$facebook_supr_linked", (command_parts[1] == "1") ? true : false);
+			StumbleGlobals.refresh_referral_menu(11);
+			break;
+		case "SFC":
+			StumbleGlobals.process_sync_favorites_count_command(parseInt(command_parts[1]));
+			break;
+		case "SSC":
+			StumbleGlobals.process_sync_stumble_count_command(parseInt(command_parts[1]));
+			break;
+		case "SHOWURL":
+			if(context.share)
+			{
+				StumbleGlobals.process_showurl_command(command_parts, context);
+			}
+			break;
+		// Note:  SHOWPOPUP was implemented incorrectly in an old client, so we now send
+		//        SHOWPOPUP2 so it doesn't try to invoke old clients.
+		case "SHOWPOPUP2":
+			// SHOWPOPUP is only supported on Fx 3.6.16+ because it appears that some controls
+			// aren't working in pre-3.6.16 (like radio buttons).
+			var geckoVer = StumbleGlobals.getGeckoVersion();
+			if(StumbleGlobals.dotversion_compare(geckoVer, '1.9.2.16') >= 0)
+			{
+				StumbleGlobals.process_showpopup_command(command_parts, context);
+			}
+			break;
+			
+		case "NUM_REFERRALS":
+			{
+				var num_referrals = parseInt(command_parts[1]);
+				var old_count = StumbleGlobals.ds.getValue("$undelivered_count");
+				if(old_count != num_referrals)
+				{
+					StumbleGlobals.ds.setValue("$undelivered_count", num_referrals);
+					StumbleGlobals.update_referred(false);
+				}
+			}
+			break;
+		case "ERROR":
+			StumbleGlobals.process_error_command(command_parts, context);
+			break;
+	}
+	
+	} catch (e) { StumbleGlobals.log_error("PROCESS " + command_parts[0], e, command_str); }  
+}
+
+StumbleGlobals.get_browser_centered_window_pos = function(width, height)
+{
+	var topWin = window.top;
+	var pos = {};
+	pos.left = (topWin.outerWidth - width) / 2 + topWin.screenX;
+	pos.top = (topWin.outerHeight - height) / 2 + topWin.screenY;
+	
+	return pos;
+}
+
+StumbleGlobals.process_showurl_command = function(command_parts, context)
+{
+	var targetUrl = command_parts[1];
+	var width = parseInt(command_parts[2]);
+	var height = parseInt(command_parts[3]);
+	var options = "dialog=1,toolbar=0,status=0,resizable=1,scrollbars=1";
+	if((command_parts.length > 4) && (command_parts[4] != ''))
+	{
+		options = command_parts[4];
+	}
+	var name = "_blank";
+	if(context.target)
+		name = "stumbleglobals_" + context.target;
+	
+	var pos = StumbleGlobals.get_browser_centered_window_pos(width, height);
+	options += ',left=' + pos.left;
+	options += ',top=' + pos.top;
+	options += ',width=' + width;
+	options += ',height=' + height;
+	
+	window.open(targetUrl, name, options);
+
+}
+
+StumbleGlobals.process_stumble_now_command = function(command_str)
+{
+	var parts = command_str.split(" ");
+	
+	if (parts.length < 2)
+		return;
+	
+	// Treat it just like we treat the through.php command
+	var args = parts[1].split("&");
+	StumbleGlobals.process_stumble_now(args);
+}
+
+StumbleGlobals.process_sync_favorites_count_command = function(count)
+{
+	if(StumbleGlobals.ds.getValue("@enable_server_counts") && (count != StumbleGlobals.ds.getValue("$thumbup_count")))
+	{
+		StumbleGlobals.ds.setValue("$thumbup_count", count);
+		StumbleGlobals.thumbup_count_changed();
+	}
+}
+
+StumbleGlobals.process_sync_stumble_count_command = function(count)
+{
+	if(StumbleGlobals.ds.getValue("@enable_server_counts") && (count != StumbleGlobals.ds.getValue("$stumble_count")))
+	{
+		StumbleGlobals.ds.setValue("$stumble_count", count);
+		StumbleGlobals.stumble_count_changed();
+	}
+}
+
+StumbleGlobals.thumbup_count_changed = function()
+{
+	var count = StumbleGlobals.ds.getValue("$thumbup_count");
+	if( (count >= 1) && !StumbleGlobals.ds.getValue("$show_info") && !StumbleGlobals.ds.getValue("$show_info_user_changed") )
+	{
+		// Show the info button after the first thumbup.
+		StumbleGlobals.ds.setValue("$show_info", true);
+		StumbleGlobals.set_visible("stumbleglobals_website_info", true);
+	}
+	
+	if( (count >= 3) && !StumbleGlobals.ds.getValue("$show_home") && !StumbleGlobals.ds.getValue("$show_home_user_changed") )
+	{
+		// Show the favorites button after the third thumbup.
+		StumbleGlobals.ds.setValue("$show_home", true);
+		StumbleGlobals.set_visible("stumbleglobals_profile", true);
+	}
+}
+
+StumbleGlobals.stumble_count_changed = function()
+{
+	var count = StumbleGlobals.ds.getValue("$stumble_count");
+	if( (count > 99) && !StumbleGlobals.ds.getValue("$show_friends") && !StumbleGlobals.ds.getValue("$show_friends_user_changed") )
+	{
+		// After 100 stumbles, show the "Stumblers" button.
+		StumbleGlobals.ds.setValue("$show_friends", true);
+		StumbleGlobals.set_visible("stumbleglobals_friends", true);
+	}
+}
+
+StumbleGlobals.process_seenconf_command = function(ids, context)
+{
+	if(context && context.oldStumbleReport)
+	{
+	    StumbleGlobals.process_old_seenconf_command(ids);
+		return;
+	}
+	
+	// It's not an old format stumble request so we expect this to just be a single
+	// publicid.
+	context.confirmed = ids;
+}
+
+StumbleGlobals.process_old_seenconf_command = function(conf_urlids_str)
+{
+	var conf_urlids;
+	var seen_urlids;
+	var stumbletimes;
+	var stumbletypes;
+	var stumblereferrals;
+	var str;
+	var i;
+	var j;
+	
+	if (conf_urlids_str == "")
+		return;
+	
+	if (StumbleGlobals.ds.getValue("$stumblestats") == conf_urlids_str ||
+			conf_urlids_str == "[clear]")
+	{
+		seen_urlids = [];
+		stumbletimes = [];
+		stumbletypes = [];
+		stumblereferrals = [];
+	}
+	else
+	{
+		str = StumbleGlobals.ds.getValue("$stumblestats");
+		seen_urlids = str.split(".");
+		str = StumbleGlobals.ds.getValue("$stumbletimes");
+		stumbletimes = str.split(".");
+		str = StumbleGlobals.ds.getValue("$stumbletypes");
+		stumbletypes = str.split(".");
+		str = StumbleGlobals.ds.getValue("$stumblereferrals");
+		stumblereferrals = str.split(".");
+		
+		conf_urlids = conf_urlids_str.split(".");
+		
+		for (i = 0; i < conf_urlids.length; i++)
+		{
+			for (j = 0; j < seen_urlids.length; j++)
+			{
+				if (conf_urlids[i] == seen_urlids[j])
+				{
+					seen_urlids.splice(j, 1);
+					stumbletimes.splice(j, 1);
+					stumbletypes.splice(j, 1);
+					stumblereferrals.splice(j, 1);
+					break;
+				}
+			}
+		}
+	}
+
+	StumbleGlobals.ds.setValue("$stumblestats", seen_urlids.join("."));
+	StumbleGlobals.ds.setValue("$stumbletimes", stumbletimes.join("."));
+	StumbleGlobals.ds.setValue("$stumbletypes", stumbletypes.join("."));
+	StumbleGlobals.ds.setValue("$stumblereferrals", stumblereferrals.join("."));
+	StumbleGlobals.ds.setValue("$last_uploaded", (new Date()).getTime());
+	StumbleGlobals.ds.flushPrefs();
+}
+
+StumbleGlobals.enqueue_command = function(priority, command)
+{
+	if (! StumbleGlobals.host.places)
+		return;
+	
+	var db = StumbleGlobals.ds.getDatabase();
+	db.a("INSERT INTO command_queue (priority, command) VALUES (");
+	db.av(priority);
+	db.als(command);
+	db.query();
+}
+
+StumbleGlobals.count_enqueued_commands = function(priority)
+{
+	if (! StumbleGlobals.host.places)
+		return;
+	
+	var db = StumbleGlobals.ds.getDatabase();
+	var sql = "SELECT count(*) as count FROM command_queue WHERE priority=" + db.v(priority);
+	var result = db.query(sql);
+	var row;
+	if (row = result.shift())
+		return row.count;
+	else
+		return 0;
+}
+
+StumbleGlobals.process_topics_command = function(parts)
+{
+	if (parts.length < 2)
+		return;
+	
+	parts.shift();
+	
+	StumbleGlobals.process_topic_list(parts.join(" "));
+}
+
+StumbleGlobals.update_topics_command = function(parts)
+{
+	if (parts.length < 2)
+		return;
+	
+	parts.shift();
+	
+	StumbleGlobals.update_topic_list(parts.join(" "));
+}
+
+StumbleGlobals.process_error_command = function(parts, context)
+{
+	if (! context)
+	{
+		StumbleGlobals.log("warning: missing context for error");
+		return;
+	}
+	
+	context.error = true;
+	
+	if (context.quiet)
+		return;
+	
+	StumbleGlobals.handle_error(parts[1]);
+}
+
+StumbleGlobals.process_bkda_command = function(parts, context)
+{
+	if (! StumbleGlobals.host.places)
+		return;
+	
+	if (parts.length < 3)
+		return;
+	
+	var spec = new Object();
+	spec.domain = parts[1];
+	spec.timestamp = parseInt(parts[2]);
+
+	var db = StumbleGlobals.ds.getDatabase();
+	var row;
+	var result;
+	var sql;
+	
+	if (context.from_sync)
+	{
+		sql = "SELECT modified FROM blocked_domain WHERE domain=" + db.q(spec.domain);
+		result = db.query(sql);
+		if (row = result.shift())
+		{
+			// Ignore obsolete sync commands
+			var offset = spec.timestamp - row.modified;
+			if (offset < (- StumbleGlobals.ds.getValue("@server_time_float_s")))
+				return;
+		}
+	}
+	
+	db.a("INSERT INTO blocked_domain (domain, modified, active) VALUES (");
+	db.as(spec.domain);
+	db.av(spec.timestamp);
+	db.alv(1);
+	db.query();
+}
+
+StumbleGlobals.process_bkdr_command = function(parts, context)
+{
+	if (! StumbleGlobals.host.places)
+		return;
+	
+	if (parts.length < 3)
+		return;
+	
+	var spec = new Object();
+	spec.domain = parts[1];
+	spec.timestamp = parseInt(parts[2]);
+	
+	var db = StumbleGlobals.ds.getDatabase();
+	var row;
+	var result;
+	var sql;
+	
+	if (context.from_sync)
+	{
+		sql = "SELECT modified FROM blocked_domain WHERE domain=" + db.q(spec.domain);
+		result = db.query(sql);
+		if (row = result.shift())
+		{
+			// Ignore obsolete sync commands
+			var offset = spec.timestamp - row.modified;
+			if (offset < (- StumbleGlobals.ds.getValue("@server_time_float_s")))
+				return;
+		}
+	}
+	
+	db.a("INSERT INTO blocked_domain (domain, modified, active) VALUES (");
+	db.as(spec.domain);
+	db.av(spec.timestamp);
+	db.alv(0);
+	db.query();
+}
+
+StumbleGlobals.process_bkdc_command = function()
+{
+	if (! StumbleGlobals.host.places)
+		return;
+	
+	var db = StumbleGlobals.ds.getDatabase();
+	var sql;
+	
+	sql = "UPDATE blocked_domain SET active=0";
+	db.query(sql);
+}
+
+StumbleGlobals.process_medt_command = function(parts, context)
+{
+	if (! StumbleGlobals.host.places)
+		return;
+	
+	var field_names = new Array(
+		"urlid",                  //  1
+		"tagid",                  //  2
+		"timestamp");             //  3
+
+	parts.shift();
+	
+	var spec = new Object();
+	var i;
+	for (i = 0; i < field_names.length; i++)
+	{
+		if (parts.length > 0)
+			spec[field_names[i]] = parts.shift();
+		else
+			spec[field_names[i]] = null;
+		
+		if (spec[field_names[i]] == "")
+			spec[field_names[i]] = null;
+	}
+	
+	spec.tagid = parseInt(spec.tagid);
+	
+	var result;
+	var row;
+	var result2;
+	var row2;
+	var id;
+	var ids;
+	var nsiuri;
+	var tags = new Array();
+	var db = StumbleGlobals.ds.getDatabase();
+	var sql;
+	
+	if (context.from_sync)
+	{
+		sql = "SELECT tag_applied FROM url_tag WHERE urlid=" + db.q(spec.urlid) + " AND tagid=" + db.v(spec.tagid);
+		result = db.query(sql);
+		if (row = result.shift())
+		{
+			// Ignore obsolete sync commands
+			var offset = spec.timestamp - row.tag_applied;
+			if (offset < (- StumbleGlobals.ds.getValue("@server_time_float_s")))
+				return;
+		}
+	}
+	
+	// if this tag has been applied to another url, keep the tag record
+	sql = "SELECT urlid FROM url_tag WHERE tagid=" + db.v(spec.tagid) + " AND urlid!=" + db.q(spec.urlid) + " LIMIT 1";
+	result = db.query(sql);
+	var keep_tag = false;
+	if (result.length)
+		keep_tag = true;
+	
+	// if this url has been rated, keep the url record  
+	sql = "SELECT rating FROM url WHERE urlid=" + db.q(spec.urlid) + " AND rating!=-1";
+	result = db.query(sql);
+	var keep_url = false;
+	if (result.length)
+		keep_url = true;
+	
+	if (! keep_url)
+	{
+		// if this url has a non-autotag other than the tag to be nuked, keep the url record  
+		sql = "SELECT tagid FROM url_tag WHERE urlid=" + db.q(spec.urlid) + " AND tagid!=" + db.v(spec.tagid) + " AND tagid>1000 AND tagid!=" + db.v(StumbleGlobals.video_tagid) + " LIMIT 1";
+		result = db.query(sql);
+		if (result.length)
+			keep_url = true;
+	}
+	
+	if (StumbleGlobals.ds.getValue("$sync_bm_meta"))
+	{
+		var ts = StumbleGlobals.ds.getTaggingService();
+		
+		if (keep_url)
+		{
+			sql = "SELECT tag FROM tag_map WHERE tagid=" + db.v(spec.tagid);
+			result = db.query(sql);
+			while (row = result.shift())
+				tags.push(row.tag);
+		}
+		else
+		{
+			sql = "SELECT tag FROM url_tag NATURAL JOIN tag_map WHERE url_tag.urlid=" + db.q(spec.urlid);
+			result = db.query(sql);
+			while (row = result.shift())
+				tags.push(row.tag);
+			tags.push("SU"); // for good measure
+			
+			sql = "SELECT catid FROM url WHERE urlid=" + db.q(spec.urlid);
+			result = db.query(sql);
+			if (row = result.shift())
+			{
+				if (StumbleGlobals.ds.getBMTagFromCatid(row.catid))
+					tags.push(StumbleGlobals.ds.getBMTagFromCatid(row.catid));
+			}
+		}
+		
+		if (tags.length)
+		{
+			sql = "SELECT url FROM url_tag NATURAL JOIN url_map WHERE url_tag.urlid=" + db.q(spec.urlid) + " AND url_tag.tagid=" + db.v(spec.tagid);
+			result = db.query(sql);
+			for (j = 0; row = result[j]; j++)
+			{
+				nsiuri = StumbleGlobals.get_nsiuri(row.url);
+				
+				ts.untagURI(nsiuri, tags);
+				
+				if (! keep_url)
+					StumbleGlobals.remove_managed_bookmark(nsiuri);
+			}
+		}
+	}
+	
+	if (! keep_url)
+	{
+		sql = "DELETE FROM url_map WHERE urlid=" + db.q(spec.urlid);
+		db.query(sql);
+		sql = "DELETE FROM url WHERE urlid=" + db.q(spec.urlid);
+		db.query(sql);
+	}
+	
+	if (! keep_tag)
+	{
+		sql = "DELETE FROM tag_map WHERE tagid=" + db.v(spec.tagid);
+		db.query(sql);
+	}
+	
+	sql = "DELETE FROM url_tag WHERE urlid=" + db.q(spec.urlid) + " AND tagid=" + db.v(spec.tagid);
+	db.query(sql);
+}
+
+StumbleGlobals.process_medr_command = function(parts, context)
+{
+	if (! StumbleGlobals.host.places)
+		return;
+
+	var field_names = new Array(
+		"urlid",                  //  1
+		"timestamp");             //  2
+
+	parts.shift();
+	
+	var spec = new Object();
+	var i;
+	var j;
+	for (i = 0; i < field_names.length; i++)
+	{
+		if (parts.length > 0)
+			spec[field_names[i]] = parts.shift();
+		else
+			spec[field_names[i]] = null;
+		
+		if (spec[field_names[i]] == "")
+			spec[field_names[i]] = null;
+	}
+	
+	var result;
+	var row;
+	var db = StumbleGlobals.ds.getDatabase();
+	var sql;
+	
+	if (context.from_sync)
+	{
+		sql = "SELECT rating_applied FROM url WHERE urlid=" + db.q(spec.urlid);
+		result = db.query(sql);
+		if (row = result.shift())
+		{
+			// Ignore obsolete sync commands
+			var offset = spec.timestamp - row.rating_applied;
+			if (offset < (- StumbleGlobals.ds.getValue("@server_time_float_s")))
+				return;
+		}
+	}
+	
+	if (context.ref_url)
+		StumbleGlobals.delete_rating(context.ref_url);
+	
+	var usertags = StumbleGlobals.get_db_tags(spec.urlid, false, true, true);
+	
+	if (StumbleGlobals.ds.getValue("$sync_bm_meta"))
+		StumbleGlobals.remove_thumbup_bookmark(spec.urlid, null, usertags);
+	
+	if (usertags)
+	{
+		sql = "UPDATE url SET rating=-1 WHERE urlid=" + db.q(spec.urlid);
+		db.query(sql);
+	}
+	else
+	{
+		sql = "DELETE FROM url WHERE urlid=" + db.q(spec.urlid);
+		db.query(sql);
+		sql = "DELETE FROM url_map WHERE urlid=" + db.q(spec.urlid);
+		db.query(sql);
+	}
+}
+
+StumbleGlobals.process_meta_command = function(parts, context)
+{
+	if (! StumbleGlobals.host.places)
+		return;
+	
+//	if ((context.mode == 1) || (context.mode == 2))
+//		context.count++;
+	
+	var field_names = new Array(
+		"urlid",                  //  1
+		"ref_url",                //  2
+		"title",                  //  3
+		"catid",                  //  4
+		"comment_level",          //  5
+		"score",                  //  6
+		"rating",                 //  7
+		"rating_applied",         //  8
+		"tagid",                  //  9
+		"tag",                    // 10
+		"tag_applied");           // 11
+	
+	parts.shift();
+	
+	var spec = new Object();
+	var i;
+	for (i = 0; i < field_names.length; i++)
+	{
+		if (parts.length > 0)
+			spec[field_names[i]] = parts.shift();
+		else
+			spec[field_names[i]] = null;
+		
+		if (spec[field_names[i]] == "")
+			spec[field_names[i]] = null;
+	}
+	
+	if (context.ref_url)
+		spec.ref_url = context.ref_url;
+	
+	if (context.title)
+	{
+		spec.title = context.title;
+	}
+	else if (spec.title)
+	{
+		try {
+			spec.title = decodeURIComponent(spec.title);
+		} catch (e) { StumbleGlobals.log_error("DECODE TITLE", e); }
+	}
+	
+	if (! spec.title)
+		spec.title = spec.ref_url;
+	
+	if (! spec.title)
+	{
+		StumbleGlobals.log("missing title");
+		return;
+	}
+	
+	var db = StumbleGlobals.ds.getDatabase();
+	var sql;
+	var result;
+	var row;
+	var tags = new Array();
+	var old_catid = null;
+	
+	sql = "SELECT catid FROM url WHERE urlid=" + db.q(spec.urlid);
+	result = db.query(sql);
+	
+	if (row = result.shift())
+		old_catid = row.catid;
+	
+	var local_catid = StumbleGlobals.ds.lookup("url:local_catid", spec.ref_url);
+	
+	if (local_catid)
+		spec.catid = local_catid;
+	else if (spec.catid)
+		spec.catid = parseInt(spec.catid);
+	else if (old_catid)
+		spec.catid = old_catid;
+	else
+		spec.catid = 0;
+
+	if ((typeof context.rating) != "undefined")
+		spec.rating = context.rating;
+	
+	var tag;
+	if (spec.tag)
+	{
+		spec.tagid = parseInt(spec.tagid);
+		spec.tag_applied = parseInt(spec.tag_applied);
+		if (! spec.tagid)
+		{
+			StumbleGlobals.log("missing tagid");
+			return;
+		}
+		
+		if (! spec.tag_applied)
+		{
+			StumbleGlobals.log("missing tag_applied");
+			return;
+		}
+		
+		if (spec.tagid == StumbleGlobals.video_tagid)
+			tag = "video";
+		else if (context.ref_tag)
+			tag = StumbleGlobals.ds.getBMTagFromTag(context.ref_tag);
+		else if (spec.tagid < 1000)
+			tag = StumbleGlobals.ds.getBMTagFromCatid(spec.tagid);
+		else
+			tag = StumbleGlobals.ds.getBMTagFromTag(spec.tag);
+		
+		if (tag)
+			tags.push(tag);
+		
+		sql = "SELECT rating,rating_applied FROM url WHERE urlid=" + db.q(spec.urlid);
+		result = db.query(sql);
+		if (row = result.shift())
+		{
+			spec.rating = row.rating;
+			spec.rating_applied = row.rating_applied;
+			if ((spec.rating == 1) && (spec.tagid == StumbleGlobals.video_tagid))
+				context.has_video_favs = true;
+		}
+		else
+		{
+			spec.rating = -1;
+			spec.rating_applied = 0;
+		}
+		
+	}
+	
+	if (spec.rating == null)
+	{
+		sql = "SELECT rating FROM url WHERE urlid=" + db.q(spec.urlid);
+		result = db.query(sql);
+		if (row = result.shift())
+			spec.rating = row.rating;
+		else
+			spec.rating = -1;
+	}
+	else
+	{
+		spec.rating = parseInt(spec.rating);
+	}
+	
+	if ((spec.rating == -1) && (! spec.tagid))
+		return; // equivalent to medr plus autotag info
+	
+	var bms = StumbleGlobals.ds.getBookmarksService();
+	var timestamp_us;
+	var itemid;
+	var i;
+	var ts;
+	var nsiuri;
+	var urls;
+	var url;
+	var folderid;	
+
+/*	
+	if ((context.mode == 1) || (context.mode == 2))
+	{
+		// Mode 1 is the favs batch download
+		// Mode 2 is the custom tags batch download
+		
+		nsiuri = StumbleGlobals.get_nsiuri(spec.ref_url);
+	
+		// Only create a bookmark if they don't have this url bookmarked
+		// already.  If they already have it somewhere, we'll just apply
+		// tags.
+		
+		if (! StumbleGlobals.is_bookmarked(nsiuri))
+		{
+			//!!! Checking folderid every time is a bit expensive but
+			//    probably necessary since we allow interaction during
+			//    download.
+			
+			folderid = StumbleGlobals.get_supertopic_folderid(spec.catid, true);
+			
+			if (folderid)
+			{
+				itemid = bms.insertBookmark(
+						folderid,
+						nsiuri,
+						bms.DEFAULT_INDEX,
+						spec.title);
+		
+				timestamp_us = spec.rating_applied * 1000000;
+				bms.setItemDateAdded(itemid, timestamp_us);
+				bms.setItemLastModified(itemid, timestamp_us);
+			}
+		}
+		
+		
+		// build the tag set
+		
+		var skip = (StumbleGlobals.is_adult_category(spec.catid) && (! StumbleGlobals.ds.getValue("$sync_bm_adult")));
+		
+		tag = StumbleGlobals.ds.getBMTagFromCatid(spec.catid); 
+		if (tag && (! skip))
+			tags.push(tag);
+		
+		if ((spec.rating == 1) && (! skip))
+			tags.push("SU");
+		
+		// apply tags
+		
+		if (tags.length)
+		{
+			ts = StumbleGlobals.ds.getTaggingService();
+			try {
+				ts.tagURI(nsiuri, tags);
+			} catch (e) { StumbleGlobals.log_error("DOWNLOAD TAG", e); }
+		}
+	}
+*/
+	
+	if (StumbleGlobals.ds.getValue("$sync_bm_meta"))
+	{
+		if (context.from_sync)
+		{
+			//!!! need to handle tag.modified when from_sync
+			sql = "SELECT rating,rating_applied FROM url WHERE urlid=" + db.q(spec.urlid);
+			result = db.query(sql);
+			if (row = result.shift())
+			{
+				var offset = spec.rating_applied - row.rating_applied;
+				if (offset < (- StumbleGlobals.ds.getValue("@server_time_float_s")))
+				{
+					if (spec.tagid)
+					{
+						spec.rating = row.rating;
+						spec.rating_applied = row.rating_applied;
+					}
+					else
+					{
+						return;
+					}
+				}
+			}
+		}
+	}
+		
+	db.a("INSERT OR REPLACE INTO url (urlid,title,catid,rating,rating_applied,comment_level,score) VALUES (");
+	db.as(spec.urlid);
+	db.as(spec.title);
+	db.av(spec.catid);
+	db.av(spec.rating);
+	db.av(spec.rating_applied);
+	db.av(spec.comment_level);
+	db.alv(spec.score);
+	db.query();
+	
+	db.a("INSERT OR REPLACE INTO url_map (url,urlid) VALUES (");
+	db.as(spec.ref_url);
+	db.als(spec.urlid);
+	db.query();
+
+	if (spec.tagid && spec.tag && spec.tag_applied)
+	{
+		db.a("INSERT OR REPLACE INTO tag_map (tag,tagid) VALUES (");
+		db.as(spec.tag);
+		db.alv(spec.tagid);
+		db.query();
+		
+		db.a("INSERT OR REPLACE INTO url_tag (urlid,tagid,tag_applied) VALUES (");
+		db.as(spec.urlid);
+		db.av(spec.tagid);
+		db.alv(spec.tag_applied);
+		db.query();
+	}
+	
+	if ((context.mode == 1) || (context.mode == 2)
+			|| (! StumbleGlobals.ds.getValue("$sync_bm_meta")))
+		return;
+	
+	if (old_catid && (spec.catid != old_catid))
+		StumbleGlobals.remove_autotag(spec.urlid, old_catid);
+	
+	if ((spec.rating >= 1)
+			&& ((! StumbleGlobals.is_adult_category(spec.catid))
+			|| StumbleGlobals.ds.getValue("$sync_bm_adult")))
+	{
+		StumbleGlobals.add_thumbup_bookmark(spec.urlid, spec.title, spec.catid);
+	}
+	else
+	{
+		var usertags = StumbleGlobals.get_db_tags(spec.urlid, false, true, true);
+		StumbleGlobals.remove_thumbup_bookmark(spec.urlid, spec.title, usertags);
+	}
+}
+
+StumbleGlobals.remove_autotag = function(urlid, catid)
+{
+	if (! StumbleGlobals.host.places)
+		return;
+
+	var db = StumbleGlobals.ds.getDatabase();
+	var tag = StumbleGlobals.ds.getBMTagFromCatid(catid);
+	var tags = new Array();
+	tags.push(tag);
+	var ts = StumbleGlobals.ds.getTaggingService();
+	var row;
+	var sql = "SELECT url FROM url_map WHERE urlid=" + db.q(urlid);
+	var result = db.query(sql);
+	while (row = result.shift())
+	{
+		nsiuri = StumbleGlobals.get_nsiuri(row.url);
+		ts.untagURI(nsiuri, tags);
+	}
+}
+
+StumbleGlobals.change_local_catid = function(url, new_catid)
+{
+	if (! StumbleGlobals.host.places)
+		return;
+	
+	var urlid = StumbleGlobals.ds.getUrlid(url);
+	if (! urlid)
+	{
+		StumbleGlobals.ds.define("url:local_catid", url, new_catid);
+		return;
+	}
+	
+	var db = StumbleGlobals.ds.getDatabase();
+	var row;
+	var sql;
+	var result;
+	var old_catid;
+	sql = "SELECT catid FROM url WHERE urlid=" + db.q(urlid);
+	result = db.query(sql);
+	if (row = result.shift())
+		old_catid = row.catid;
+	else
+		return;
+	
+	if (new_catid == old_catid)
+		return;
+	
+	sql = "UPDATE url SET catid=" + db.v(new_catid) + " WHERE urlid=" + db.q(urlid);
+	db.query(sql);
+	
+	if (! StumbleGlobals.ds.getValue("$sync_bm_meta"))
+		return;
+	
+	var old_tag = StumbleGlobals.ds.getBMTagFromCatid(old_catid);
+	var old_tags = new Array();
+	old_tags.push(old_tag);
+	var new_tag = StumbleGlobals.ds.getBMTagFromCatid(new_catid);
+	var new_tags = new Array();
+	new_tags.push(new_tag);
+	var ts = StumbleGlobals.ds.getTaggingService();
+	var adult = StumbleGlobals.is_adult_category(new_catid);
+	
+	sql = "SELECT url FROM url_map WHERE urlid=" + db.q(urlid);
+	result = db.query(sql);
+	while (row = result.shift())
+	{
+		nsiuri = StumbleGlobals.get_nsiuri(row.url);
+		ts.untagURI(nsiuri, old_tags);
+		if ((! adult) || (adult && StumbleGlobals.ds.getValue("$sync_bm_adult")))
+			ts.tagURI(nsiuri, new_tags);
+	}
+}
+
+StumbleGlobals.get_db_tags = function(urlid, include_autotags, include_usertags, include_adult_tags)
+{
+	var tags = new Array();
+	var db = StumbleGlobals.ds.getDatabase();
+	var sql;
+	var result;
+	var row;
+	
+	if (include_autotags && (! include_usertags))
+		sql = "SELECT tag,tag_map.tagid FROM url_tag NATURAL JOIN tag_map WHERE url_tag.urlid=" + db.q(urlid) + " AND (url_tag.tagid<1000 OR url_tag.tagid=" + db.v(StumbleGlobals.video_tagid) + ")";
+	else if ((! include_autotags) && include_usertags)
+		sql = "SELECT tag,tag_map.tagid FROM url_tag NATURAL JOIN tag_map WHERE url_tag.urlid=" + db.q(urlid) + " AND url_tag.tagid>=1000 AND url_tag.tagid!=" + db.v(StumbleGlobals.video_tagid);
+	else
+		sql = "SELECT tag,tag_map.tagid FROM url_tag NATURAL JOIN tag_map WHERE url_tag.urlid=" + db.q(urlid);
+	
+	
+	result = db.query(sql);
+	while (row = result.shift())
+	{
+		if ((! include_adult_tags) && StumbleGlobals.is_adult_category(row.tagid))
+			continue;
+		
+		tags.push(StumbleGlobals.ds.getBMTagFromTag(row.tag));
+	}
+	
+	if (include_autotags)
+	{
+		tags.push("SU");
+		sql = "SELECT catid FROM url WHERE urlid=" + db.q(urlid);
+		result = db.query(sql);
+		if (row = result.shift())
+		{
+			if ((include_adult_tags || (! StumbleGlobals.is_adult_category(row.catid)))
+					&& StumbleGlobals.ds.getBMTagFromCatid(row.catid))
+				tags.push(StumbleGlobals.ds.getBMTagFromCatid(row.catid));
+		}
+	}
+	
+	return (tags.length) ? tags : null;
+}
+
+StumbleGlobals.add_thumbup_bookmark = function(urlid, title, catid)
+{
+	var db = StumbleGlobals.ds.getDatabase();
+	var bms = StumbleGlobals.ds.getBookmarksService();
+	var ts = StumbleGlobals.ds.getTaggingService();
+	var tags = StumbleGlobals.get_db_tags(urlid, true, true, StumbleGlobals.ds.getValue("$sync_bm_adult"));
+	var sql;
+	var result;
+	var row;
+	var result2;
+	var row2;
+	var folderid;
+	var bookmarked;
+	var itemid;
+	var ids;
+	var id;
+	
+	if (! tags)
+		tags = new Array();
+	
+	// get all urls mapped to this urlid
+	sql = "SELECT url FROM url_map WHERE urlid=" + db.q(urlid);
+	result = db.query(sql);
+	while (row = result.shift())
+	{
+		nsiuri = StumbleGlobals.get_nsiuri(row.url);
+		
+		ids = bms.getBookmarkIdsForURI(nsiuri, []);
+		
+		bookmarked = false;
+		
+		while (id = ids.shift())
+		{
+			folderid = bms.getFolderIdForItem(id);
+			
+			// if the bookmark is in one of our managed bookmark folders,
+			// remove it
+			sql = "SELECT label FROM supertopic WHERE bm_folderid=" + db.v(folderid);
+			result2 = db.query(sql);
+			if (row2 = result2.shift())
+			{
+				if (row2.label == StumbleGlobals.tagged_folder_name)
+				{
+					bms.removeItem(id);
+					StumbleGlobals.check_managed_folder_emptiness(folderid);
+				}
+				else
+					bookmarked = true;
+			}
+		}
+		
+		if (! bookmarked)
+		{
+			folderid = StumbleGlobals.get_supertopic_folderid(catid, true);
+			if(folderid)
+			{
+				itemid = bms.insertBookmark(
+						folderid,
+						nsiuri,
+						bms.DEFAULT_INDEX,
+						title);
+			}
+		}
+		
+		ts.tagURI(nsiuri, tags);
+	}
+}
+
+StumbleGlobals.remove_thumbup_bookmark = function(urlid, title, usertags)
+{
+	var db = StumbleGlobals.ds.getDatabase();
+	var bms = StumbleGlobals.ds.getBookmarksService();
+	var ts = StumbleGlobals.ds.getTaggingService();
+	var autotags = StumbleGlobals.get_db_tags(urlid, true, false, true);
+	var sql;
+	var result;
+	var row;
+	
+	// get all urls mapped to this urlid
+	sql = "SELECT url FROM url_map WHERE urlid=" + db.q(urlid);
+	result = db.query(sql);
+	while (row = result.shift())
+	{
+		nsiuri = StumbleGlobals.get_nsiuri(row.url);
+		
+		var removed_spec = StumbleGlobals.remove_managed_bookmark(nsiuri, autotags);
+		
+		// If the url still has tags and isn't bookmarked
+		// elsewhere, add it to the Unfiled/Tagged folder.
+		
+		if (usertags && (! StumbleGlobals.is_bookmarked(nsiuri)))
+		{
+			var timestamp_us;
+			if (removed_spec)
+			{
+				title = removed_spec.title;
+				timestamp_us = removed_spec.timestamp_us;
+			}
+			else
+			{
+				title = (title) ? title : row.url;
+				timestamp_us = StumbleGlobals.get_time_s() + 1000000;
+			}
+			// get all bookmark items mapped to the urlid
+		
+			folderid = StumbleGlobals.get_supertopic_folderid(-1, true);
+			if(folderid)
+			{
+				itemid = bms.insertBookmark(
+						folderid,
+						nsiuri,
+						bms.DEFAULT_INDEX,
+						title);
+				bms.setItemDateAdded(itemid, timestamp_us);
+				bms.setItemLastModified(itemid, timestamp_us);
+			}
+		}
+		
+		if (usertags)
+			ts.tagURI(nsiuri, usertags);
+		else if (autotags)
+			ts.untagURI(nsiuri, autotags);
+	}
+}
+
+StumbleGlobals.remove_managed_bookmark = function(nsiuri, autotags)
+{
+	var db = StumbleGlobals.ds.getDatabase();
+	var bms = StumbleGlobals.ds.getBookmarksService();
+	var hs = StumbleGlobals.ds.getHistoryService();
+	var ts = StumbleGlobals.ds.getTaggingService();
+	var folderid;
+	var sql;
+	var result;
+	var query;
+	var ids;
+	var id;
+	var removed_spec = null;
+	
+	ts.untagURI(nsiuri, ["SU"]);
+	if (autotags)
+		ts.untagURI(nsiuri, autotags);
+	
+	ids = bms.getBookmarkIdsForURI(nsiuri, []);
+	
+	while (id = ids.shift())
+	{
+		folderid = bms.getFolderIdForItem(id);
+		// if the bookmark is in one of our managed bookmark folders,
+		// remove it
+		sql = "SELECT label FROM supertopic WHERE bm_folderid=" + db.v(folderid);
+		result = db.query(sql);
+		if (result.length)
+		{
+			removed_spec = new Object();			
+			removed_spec.title = bms.getItemTitle(id);
+			removed_spec.timestamp_us = bms.getItemLastModified(id);
+			bms.removeItem(id);
+			
+			StumbleGlobals.check_managed_folder_emptiness(folderid);
+		}
+	}
+	return removed_spec;
+}
+
+StumbleGlobals.check_managed_folder_emptiness = function(folderid)
+{
+	var hs = StumbleGlobals.ds.getHistoryService();
+	var query;
+	var result;
+	var bms;
+	var db;
+	var sql;
+	// if the managed folder is now empty, remove it.
+	query = hs.getNewQuery();
+	query.setFolders([folderid], 1);
+	result = hs.executeQuery(query, hs.getNewQueryOptions());
+	result.root.containerOpen = true;
+	if (result.root.childCount == 0)
+	{
+		bms = StumbleGlobals.ds.getBookmarksService();
+		bms.removeItem(folderid);
+		db = StumbleGlobals.ds.getDatabase();
+		sql = "DELETE FROM supertopic WHERE bm_folderid=" + db.v(folderid);
+		db.query(sql);
+	}
+}
+
+StumbleGlobals.get_rating = function(url, stumblevideo, opt_url_detail)
+{
+	if (opt_url_detail)
+		return opt_url_detail.rating;
+	
+	if (StumbleGlobals.host.places && ! stumblevideo)
+	{
+		var db = StumbleGlobals.ds.getDatabase();
+		var result;
+		var row;
+		var sql;
+		sql = "SELECT rating FROM url_map NATURAL JOIN url WHERE url=" + db.q(url);
+		result = db.query(sql);
+		if (row = result.shift())
+		{
+			return (row.rating == -1) ? null : row.rating;
+		}
+		else if ((typeof StumbleGlobals.ratings[url]) != "undefined")
+		{
+			// We're generating too many hits.
+			if (! StumbleGlobals.ds.lookup("url:rating_getmeta_flag", url))
+			{
+				StumbleGlobals.ds.define("url:rating_getmeta_flag", url, 1);
+				StumbleGlobals.rate_getmeta(url, false);
+			}
+			
+			return StumbleGlobals.ratings[url];
+		}
+		else
+		{
+			return null;
+		}
+	}
+	else
+	{
+		if ((typeof StumbleGlobals.ratings[url]) == "undefined")
+			return null;
+		else
+			return StumbleGlobals.ratings[url];
+	}
+}
+
+StumbleGlobals.get_tag_list = function(url)
+{
+	var retval = null;
+	if (((typeof (StumbleGlobals.tag_lists_by_url[url])) != "undefined") &&
+			(StumbleGlobals.tag_lists_by_url[url] != ""))
+	{
+		retval = StumbleGlobals.tag_lists_by_url[url];
+	}
+	else if (StumbleGlobals.host.places)
+	{
+		var db = StumbleGlobals.ds.getDatabase();
+		var result;
+		var row;
+		var sql;
+		var tags = new Array();
+		sql = "SELECT tag FROM url_map NATURAL JOIN url_tag NATURAL JOIN tag_map WHERE url=" + db.q(url) + " AND url_tag.tagid>1000 AND url_tag.tagid!=" + db.v(StumbleGlobals.video_tagid);
+		result = db.query(sql);
+		if (result.length)
+		{
+			while (row = result.shift())
+				tags.push(row.tag);
+			
+			retval = tags.join(", ");
+			StumbleGlobals.tag_lists_by_url[url] = retval;
+		}
+	}
+	return retval;
+}
+
+// returns true/false is domain is blocked or not
+StumbleGlobals.is_domain_blocked = function(domain)
+{
+	if (! StumbleGlobals.host.places)
+		return false;
+	
+	var out = false;
+	try {
+		var db = StumbleGlobals.ds.getDatabase();
+		var sql;
+		var result;
+		sql = "SELECT active FROM blocked_domain WHERE domain=" + db.q(domain) + " AND active=1";
+		result = db.query(sql);
+		out = (result.length) ? true : false;
+	} catch (e) {} // be safe since this is within the stumbling path
+	return out;
+}	
+
+StumbleGlobals.is_bookmarked = function(nsiuri)
+{
+	return (PlacesUtils.getMostRecentBookmarkForURI(nsiuri) != -1)
+}
+
+// FF4 removed the getChildFolder function, so we have to implement it ourselves.
+StumbleGlobals.bm_get_child_folder = function(aFolder, aSubFolder)
+{
+ var htService = Components.classes["@mozilla.org/browser/nav-history-service;1"].
+    getService(Components.interfaces.nsINavHistoryService);
+  var query = htService.getNewQuery();
+  var options = htService.getNewQueryOptions();
+  query.setFolders([aFolder], 1);
+  var result = htService.executeQuery(query, options);
+  var rootNode = result.root;
+  var childFolder = 0;
+  rootNode.containerOpen = true;
+  for (var i = 0; i < rootNode.childCount; i++) {
+    var node = rootNode.getChild(i);
+    if (node.type == node.RESULT_TYPE_FOLDER && node.title == aSubFolder) {
+      childFolder = node.itemId;
+      break;
+    }
+  }
+  rootNode.containerOpen = false;
+
+  return childFolder;
+}
+
+StumbleGlobals.get_supertopic_folderid = function(catid, create)
+{
+	var folder_name;
+	if (catid == 0)
+		catid = -1;
+	else if (StumbleGlobals.is_adult_category(catid)
+			&& (! StumbleGlobals.ds.getValue("$sync_bm_adult")))
+		catid = -1;
+	
+	if (catid == -1)
+	{
+		folder_name = StumbleGlobals.tagged_folder_name; 
+	}
+	else
+	{
+		folder_name = StumbleGlobals.ds.lookup("catid:folder_name", catid);
+		if (! folder_name)
+			return null;
+	}
+			
+	StumbleGlobals.verify_bookmarks_folder();
+	
+	var bms = StumbleGlobals.ds.getBookmarksService();
+	
+	// If a folder with this name exists in their su bookmarks folder,
+	// use it.
+	
+	var folderid;
+	var parentid = StumbleGlobals.ds.getValue("$bm_folderid");
+	if(!bms.getChildFolder)
+	{
+		folderid = StumbleGlobals.bm_get_child_folder(parentid, folder_name);
+	}
+	else
+	{
+		folderid = bms.getChildFolder(
+				parentid,
+				folder_name);
+	}
+	
+	if (folderid != 0)
+		return folderid;
+	
+	// Otherwise, try to use the most recent one that we created, even
+	// if they moved or renamed it.
+	
+	var db = StumbleGlobals.ds.getDatabase();
+	var result;
+	var index;
+	var row;
+	var sql;
+	sql = "SELECT bm_folderid FROM supertopic WHERE label=" + db.q(folder_name);
+	result = db.query(sql);
+	index = -1;
+	if (row = result.shift())
+	{
+		folderid = row.bm_folderid;
+		index = bms.getItemIndex(folderid);
+	}
+	
+	if (index != -1)
+		return folderid;
+	
+	else if (! create)
+		return null;
+	
+	// Do a sanity check to make sure we're allowed to create it.
+	
+	if ((folder_name == "Adult") && (! StumbleGlobals.ds.getValue("$sync_bm_adult")))
+		return null;
+	
+	
+	// Create a new one in alphabetical order with our other
+	// automatically generated supertopic folders; make the
+	// 'Other Tagged' folder always last.  
+	
+	index = -1;
+	if (catid != -1)
+	{
+		sql = "SELECT label,bm_folderid FROM supertopic WHERE label>" + db.q(folder_name) + " AND label!="  + db.q(StumbleGlobals.tagged_folder_name) + " ORDER BY label LIMIT 1";
+		result = db.query(sql);
+		if (row = result.shift())
+		{
+			try {
+				index = bms.getItemIndex(row.bm_folderid);
+			} catch (e) {}
+		}
+	}
+	
+	folderid = null;
+	try {
+		
+		folderid = bms.createFolder(
+				StumbleGlobals.ds.getValue("$bm_folderid"),
+				folder_name,
+				index);
+		var index2 = bms.getItemIndex(folderid);
+		db.a("INSERT OR REPLACE INTO supertopic (label,bm_folderid) VALUES (");
+		db.as(folder_name);
+		db.alv(folderid);
+		db.query();
+	} catch (e) { StumbleGlobals.log_error("CREATE FOLDER", e); }
+	
+	
+	// Update the video query to include this new folder.
+
+	if (folderid)
+		StumbleGlobals.refresh_video_folder_bm();
+	
+	return folderid;
+}
+
+
+StumbleGlobals.refresh_video_folder_bm = function()
+{
+	var db = StumbleGlobals.ds.getDatabase();
+	var sql;
+	var result;
+	var row;
+	sql = "SELECT bm_folderid FROM supertopic ORDER BY label";
+	result = db.query(sql);
+	var i;
+	var folderids = new Array();
+	for (i = 0; row = result[i]; i++)
+		folderids.push(row.bm_folderid);
+	
+	var bms = StumbleGlobals.ds.getBookmarksService();
+	
+	var itemid = StumbleGlobals.ds.getValue("$bm_suvid_itemid");
+	var tmpidx;
+	if (itemid != 0)
+	{
+		tmpidx = -1;
+		try {
+		tmpidx = bms.getItemIndex(itemid);
+		} catch (e) {}
+		if (tmpidx != -1)
+			bms.removeItem(itemid);
+	}
+	
+	itemid = StumbleGlobals.add_query_folder_bm(
+			StumbleGlobals.ds.getValue("$bm_folderid"),
+			folderids,
+			"video",
+			"Video Favorites",
+			0);
+	
+	StumbleGlobals.ds.setValue("$bm_suvid_itemid", itemid);
+	
+	StumbleGlobals.ds.flushPrefs();
+}
+
+StumbleGlobals.get_error_object_dump = function(o)
+{
+	if (! o)
+		return "\n" + (typeof o);
+	
+	var str = "\n===== dump ===\n"; 
+	var p;
+	for (p in o)
+	{
+		if (p.match(/.*_ERR$/))
+			continue;
+		
+		try {
+			str += "[" + p + "]\n" + o[p] + "\n";
+		}
+		catch (e) {
+			str += "[" + p + "] ERROR\n" + e + "\n";
+		}
+	}
+	str += "========";
+	return str;
+}
+
+StumbleGlobals.enable_client_features = function(enable_mask)
+{
+	var old_bits = StumbleGlobals.ds.getValue("@client_form");
+	
+	// add new enable routines immediately above
+	
+	StumbleGlobals.ds.setValue("@client_form", (old_bits | enable_mask));
+}
+
+StumbleGlobals.disable_client_features = function(disable_mask)
+{
+	var old_bits = StumbleGlobals.ds.getValue("@client_form");
+
+	// add new disable routines immediately above
+	
+	StumbleGlobals.ds.setValue("@client_form", (old_bits & (~ disable_mask)));
+}
+
+StumbleGlobals.enable_user_features = function(enable_mask)
+{
+	var old_bits = StumbleGlobals.ds.getValue("$form");
+	
+	if (StumbleGlobals.ds.hasFeature("$sociallinks", enable_mask) &&
+			(! StumbleGlobals.ds.hasFeature("$sociallinks", old_bits)))
+	{
+		var searchlinks_enabled = 
+				(StumbleGlobals.ds.getValue("$show_searchlinks_score") ||
+				StumbleGlobals.ds.getValue("$show_searchlinks_friends") ||
+				StumbleGlobals.ds.getValue("$show_searchlinks_topic"));
+
+		StumbleGlobals.ds.setValue("$shown_searchlinks_dialog", searchlinks_enabled);
+		if (! searchlinks_enabled)
+			StumbleGlobals.ds.setValue("$intro_count", 0);
+	}
+	
+	if (StumbleGlobals.ds.hasFeature("$adultrrecat", enable_mask) &&
+			(! StumbleGlobals.ds.hasFeature("$adultrrecat", old_bits)))
+	{
+		StumbleGlobals.ds.setValue("$recat_adult", 1);
+	}
+	
+	if (StumbleGlobals.ds.hasFeature("$adultxrecat", enable_mask) &&
+			(! StumbleGlobals.ds.hasFeature("$adultxrecat", old_bits)))
+	{
+		StumbleGlobals.ds.setValue("$recat_adult", 2);
+	}
+	
+	if (StumbleGlobals.ds.hasFeature("$tagger", enable_mask) &&
+			(! StumbleGlobals.ds.hasFeature("$tagger", old_bits)))
+	{
+		StumbleGlobals.ds.setValue("$show_tag", true);
+		StumbleGlobals.ds.setValue("$show_flag", true);
+		StumbleGlobals.ds.setValue("$shown_tag", true);
+		StumbleGlobals.init_toolbar_element_visibility();
+	}
+	
+	if (StumbleGlobals.ds.hasFeature("$has_subscriptions", enable_mask) &&
+			(! StumbleGlobals.ds.hasFeature("$has_subscriptions", old_bits)))
+	{
+		// If they have followers, then turn on the stumblers menu.
+		if(!StumbleGlobals.ds.getValue("$show_friends_user_changed"))
+		{
+			StumbleGlobals.ds.setValue("$show_friends", true);
+			StumbleGlobals.set_visible("stumbleglobals_friends", true);
+		}
+	}
+
+	// add new enable routines immediately above
+	StumbleGlobals.ds.setValue("$form", (old_bits | enable_mask));
+}
+
+StumbleGlobals.disable_user_features = function(disable_mask)
+{
+	var old_bits = StumbleGlobals.ds.getValue("$form");
+
+	// add new disable routines immediately above
+	
+	StumbleGlobals.ds.setValue("$form", (old_bits & (~ disable_mask)));
+}
+
+StumbleGlobals.process_set_pref_command = function(name, val_str)
+{
+	switch (StumbleGlobals.ds.getPrefType(name))
+	{
+		case "Int":
+			StumbleGlobals.ds.setValue(name, parseInt(val_str));
+			break;
+		case "Bool":
+			StumbleGlobals.ds.setValue(name, ((val_str == "1") || (val_str == "true")));
+			break;
+		case "Char":
+			StumbleGlobals.ds.setValue(name, val_str);
+			break;
+		case "JSON":
+			StumbleGlobals.ds.setValue(name, StumbleGlobals.ds.deserialize(val_str));
+			break;
+	}
+}
+
+StumbleGlobals.http_error = function(error, status)
+{
+	alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to "
+		+ StumbleGlobals.base_url + "feedback.php to report the problem\nError : " 
+		+ error + "\nStatus : " + status);
+}
+
+// initializes stumbleid and stumblepass; also sets the use_token
+// preference during migration
+StumbleGlobals.init_login = function(skip_cookies, ignore_cookies)
+{
+	try {
+		if (StumbleGlobals.ds.isPrefDefined("@current_user"))
+		{
+			var tmp_id = StumbleGlobals.ds.getValue("@current_user");
+			if (tmp_id == "")
+			{
+				StumbleGlobals.stumbleid = 0;
+				StumbleGlobals.stumblepass = "";
+			}
+			else
+			{
+				StumbleGlobals.stumbleid = tmp_id;
+				StumbleGlobals.stumblepass = StumbleGlobals.ds.getStoredPassword();
+				if ((StumbleGlobals.stumblepass == null) || (StumbleGlobals.stumblepass == ""))
+				{
+					try {
+						StumbleGlobals.log_error("NULL PASSWORD");
+					} catch (e) {}
+					StumbleGlobals.ds.setValue("@current_user", "");
+					StumbleGlobals.stumbleid = 0;
+					StumbleGlobals.stumblepass = "";
+					return false;
+				}
+			}
+		}
+		else
+		{
+			StumbleGlobals.stumbleid = 0;
+			StumbleGlobals.stumblepass = "";
+		}
+	
+		if (! skip_cookies)
+		{
+			try {
+				StumbleGlobals.process_cookies(ignore_cookies);
+			} catch (e) { StumbleGlobals.log_error("INIT COOKIES", e); }
+		}
+		
+	} catch (e) { StumbleGlobals.log_error("INIT LOGIN", e);
+		StumbleGlobals.stumbleid = 0;
+		StumbleGlobals.stumblepass = "";
+	}
+	StumbleGlobals.ds.getValue("@current_user");
+	StumbleGlobals.ds.flushPrefs();
+	return true;
+}
+
+StumbleGlobals.process_cookies = function(clear_only)
+{
+var manager = StumbleGlobals.get_service(
+				"@mozilla.org/cookiemanager;1",
+				"nsICookieManager");
+	var cookies = manager.enumerator;
+	var cookie;
+	var userid1 = null;
+	var password1 = null;
+	var userid2 = null;
+	var password2 = null;
+	var now = (new Date()).getTime();
+	var searchlinks = null;
+	var nickname = null;
+	var enableg = null;
+	var enableu = null;
+	var disableg = null;
+	var disableu = null;
+	var thru_domains = null;
+	
+	while (cookies.hasMoreElements())
+	{
+		cookie = cookies.getNext().QueryInterface(
+					Components.interfaces.nsICookie);
+					
+		if ((cookie.host == ("." + StumbleGlobals.servername)) &&
+					((cookie.expires * 1000) > now))
+		{
+			if (cookie.name == "tsuu")
+			{
+				userid1 = cookie.value;
+				manager.remove("." + StumbleGlobals.servername, "tsuu", "/", 0);
+			}
+			else if (cookie.name == "tsut")
+			{
+				// As of 2008-04-15, this is always salted, hashed and
+				// not encoded.
+				password1 = cookie.value;
+				manager.remove("." + StumbleGlobals.servername, "tsut", "/", 0);
+			}
+			else if (cookie.name == "stumble_user")
+			{
+				userid2 = cookie.value;
+				manager.remove("." + StumbleGlobals.servername, "stumble_user", "/", 0);
+			}
+			else if (cookie.name == "stumble_pass")
+			{
+				// As of 2008-04-15, this is always salted, hashed and
+				// not encoded.
+				password2 = cookie.value;
+				manager.remove("." + StumbleGlobals.servername, "stumble_pass", "/", 0);
+			}
+			else if (cookie.name == "nickname")
+			{
+				nickname = cookie.value;
+				manager.remove("." + StumbleGlobals.servername, "nickname", "/", 0);
+			}
+			else if (cookie.name == "searchlinks")
+			{
+				searchlinks = true;
+				manager.remove("." + StumbleGlobals.servername, "searchlinks", "/", 0);
+			}
+			else if (cookie.name == "thru_domains")
+			{
+				thru_domains = cookie.value;
+				manager.remove("." + StumbleGlobals.servername, "thru_domains", "/", 0);
+			}
+			else if (cookie.name == "enableu")
+			{
+				enableu = parseInt(cookie.value);
+				manager.remove("." + StumbleGlobals.servername, "enableu", "/", 0);
+			}
+			else if (cookie.name == "enableg")
+			{
+				enableg = parseInt(cookie.value);
+				manager.remove("." + StumbleGlobals.servername, "enableg", "/", 0);
+			}
+			else if (cookie.name == "disableu")
+			{
+				disableu = parseInt(cookie.value);
+				manager.remove("." + StumbleGlobals.servername, "disableu", "/", 0);
+			}
+			else if (cookie.name == "disableg")
+			{
+				disableg = parseInt(cookie.value);
+				manager.remove("." + StumbleGlobals.servername, "disableg", "/", 0);
+			}
+			else if (clear_only && ((typeof cookie.name) == "string") &&
+					(cookie.name.indexOf("NSC_") == 0))
+			{
+				manager.remove("." + StumbleGlobals.servername, cookie.name, "/", 0);
+			}
+		}
+	}
+
+	if (clear_only)
+		return null;
+
+	var profile_change = null;
+
+	if ((userid1 != null) && (password1 != null) &&
+				(userid1 != "") && (password1 != ""))
+	{
+		var login = true;
+		if ((StumbleGlobals.stumbleid != 0) && (StumbleGlobals.stumblepass != ""))
+		{
+			var name = StumbleGlobals.ds.getValue("$nick");
+			if (name == "")
+				name += StumbleGlobals.stumbleid;
+			
+			if (StumbleGlobals.ds.getValue("~visited_signup"))
+			{
+				login = true;
+			}
+			else
+			{
+				login = window.confirm("Do you want to sign-in to this new account?\n\n")
+			}
+		}
+
+		if (login)
+		{
+			profile_change = new Object();
+			StumbleGlobals.stumbleid = userid1;
+			StumbleGlobals.ds.setValue("@current_user", StumbleGlobals.stumbleid);
+			profile_change.new_profile = (! StumbleGlobals.ds.isPrefDefined("$nick"));
+			StumbleGlobals.stumblepass = password1;
+			StumbleGlobals.ds.storePassword(StumbleGlobals.stumblepass, null);
+		}
+	}
+	else if ((userid2 != null) && (password2 != null) &&
+				(userid2 != "") && (password2 != ""))
+	{
+		profile_change = new Object();
+		StumbleGlobals.stumbleid = userid2;
+		StumbleGlobals.ds.setValue("@current_user", StumbleGlobals.stumbleid);
+		profile_change.new_profile = (! StumbleGlobals.ds.isPrefDefined("$nick"));
+		if (password2.length < 28)
+		{
+			if (StumbleGlobals.enable_hashed_password)
+			{
+				StumbleGlobals.stumblepass = StumbleGlobals.ds.getEncodedPassword(password2, StumbleGlobals.stumbleid);
+				StumbleGlobals.ds.storePassword(StumbleGlobals.stumblepass, null);
+			}
+			else
+			{
+				StumbleGlobals.stumblepass = password2;
+				StumbleGlobals.ds.storePassword(null, StumbleGlobals.stumblepass);
+			}
+		}
+		else
+		{
+			StumbleGlobals.stumblepass = password2;
+			StumbleGlobals.ds.storePassword(StumbleGlobals.stumblepass, null);
+		}
+	}
+	
+	if (StumbleGlobals.stumbleid != 0)
+	{
+		if (searchlinks)
+		{
+			StumbleGlobals.ds.setValue("$show_searchlinks_friends", true);
+			StumbleGlobals.ds.setValue("$show_searchlinks_score", true);
+			StumbleGlobals.ds.setValue("$shown_searchlinks", true);
+		}
+		
+		if (nickname)
+			StumbleGlobals.ds.setValue("$nick", nickname);
+		
+		if (enableg)
+			StumbleGlobals.enable_client_features(enableg);
+		
+		if (enableu)
+			StumbleGlobals.enable_user_features(enableu);
+		
+		if (disableg)
+			StumbleGlobals.disable_client_features(disableg);
+		
+		if (disableu)
+			StumbleGlobals.disable_user_features(disableu);
+		
+		if (thru_domains)
+			StumbleGlobals.ds.setValue("$default_thru_domain_list", thru_domains);
+		
+		manager.remove("." + StumbleGlobals.servername, "stumbleglobals_REMEMBER", "/", 0);
+	}
+	
+	if (profile_change)
+		StumbleGlobals.visited_login_page = false;
+	
+	return profile_change;
+}
+
+// used by logout and handle_window_load to clear authentication
+StumbleGlobals.logout_auth = function()
+{
+	// 1. remove username and password
+	StumbleGlobals.ds.setValue("@current_user", "");
+	StumbleGlobals.ds.deleteStoredPassword();
+
+	// now sync this stuff before we crash
+	StumbleGlobals.ds.flushPrefs();
+
+	// 2. change current user to 0
+	StumbleGlobals.stumbleid = 0;
+	StumbleGlobals.stumblepass = '';
+
+	// 3. remove cookies stumble_user, stumble_pass, and PHPSESSID
+	// ??? or maybe just all cookies from stumbleupon.com?
+
+	var cookieManager = StumbleGlobals.get_service(
+				"@mozilla.org/cookiemanager;1",
+				"nsICookieManager");
+	cookieManager.remove("." + StumbleGlobals.servername, "PHPSESSID", "/", 0);
+	cookieManager.remove("." + StumbleGlobals.servername, "stumble_user", "/", 0);
+	cookieManager.remove("." + StumbleGlobals.servername, "stumble_pass", "/", 0);
+	cookieManager.remove("." + StumbleGlobals.servername, "stumbleglobals_REMEMBER", "/", 0);
+	
+	StumbleGlobals.logout_server();
+}
+
+
+StumbleGlobals.logout_server = function()
+{
+	StumbleGlobals.post_url_server_async(
+				"session.php",
+				StumbleGlobals.arp("", "logout", 1),
+				15000,
+				StumbleGlobals.generic_done);
+}
+
+
+// used by signup_page() to grab a new StumbleGlobals.stumbleid from the server
+// and to initialize StumbleGlobals.stumbleid, stumblepass and nick
+StumbleGlobals.init_new_user = function(challenge, init_toolbar)
+{
+	var detail = new Object();
+	detail.init_toolbar = init_toolbar;
+	// We have no ID yet, hit getid.php
+	StumbleGlobals.post_url_server_async(
+				"init_user.php",
+				"challenge=" + challenge + 
+					((StumbleGlobals.enable_hashed_password) ? "&hashed=1" : ""), 
+				null,
+				StumbleGlobals.init_new_user_done,
+				detail);
+}
+
+StumbleGlobals.init_new_user_done = function(res)
+{
+	var msg = "StumbleUpon was unable to create an account for you.  Please try again later.";
+	
+	try {
+		if (res.status == 1)
+		{
+			alert(msg);
+			return;
+		}
+	} catch (e) {
+		alert(msg);
+		return;
+	}
+
+	if (res.status != 200)
+	{
+		StumbleGlobals.http_error(res.error, res.status);
+		return;
+	}
+	
+	var detail = res.detail;
+	
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+	
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response init_user.php", s);
+	
+	var parsed = s.split("\n");
+	// Iterate through commands
+	
+	for (var i = 0; i < parsed.length; i++)
+	{
+		if (parsed[i] == "")
+			continue;
+
+		// Parse command structure
+		var command = parsed[i].split(" ");
+		switch(command[0])
+		{
+			case "USER":
+				StumbleGlobals.stumbleid = command[1];
+				StumbleGlobals.ds.setValue("@current_user", StumbleGlobals.stumbleid);
+				break;
+			case "PASS":
+				StumbleGlobals.stumblepass = command[1];
+				break;
+			default:
+				var context = new Object();
+				StumbleGlobals.process_command(parsed[i], context, command);
+				if (context.error)
+					return;
+				break;
+		}
+	}
+	
+	if (StumbleGlobals.isInt(StumbleGlobals.stumbleid) && StumbleGlobals.stumbleid != 0 && StumbleGlobals.stumblepass != 0 && StumbleGlobals.stumbleid != false && StumbleGlobals.stumblepass != false && StumbleGlobals.stumblepass.length>0)
+	{
+		StumbleGlobals.ds.storePassword(StumbleGlobals.stumblepass, null);
+		
+		StumbleGlobals.store_user_interests();
+		
+		// sync prefs.js in case we crash
+		StumbleGlobals.ds.flushPrefs();
+		
+		if (detail.init_toolbar)
+		{
+			var login_detail = new Object();
+			login_detail.skip_cookies = false;
+			login_detail.ignore_cookies = true;
+			login_detail.new_user_prompt = true;
+			login_detail.new_profile = true;
+			StumbleGlobals.invoke_global_event("login", login_detail);
+		}
+	}
+	else
+	{
+		// spit out an error
+		alert("StumbleUpon was unable to create an account for you.  Please try again later.");
+	}
+}
+
+//!!! sometimes fails  0 = notint ???
+StumbleGlobals.isInt = function(elm) 
+{
+	elm = elm.toString();
+	var pattern = /[^0-9]/;
+	if (pattern.test(elm))
+		return false;
+	else
+		return true;
+}
+
+
+// user_cat = incat stumble category ID
+// Gets an url the users hasn't seen yet from stumbleurls
+StumbleGlobals.get_unseen_url = function(user_cat, hit_server, callback, context)
+{
+	// load stumbles...
+	try {
+		StumbleGlobals.load_stumbles(null);
+	} catch (e) { StumbleGlobals.log_error("UNSEEN LOAD", e); }
+	
+	if (StumbleGlobals.stumbles.length == 0)
+	{
+		if (hit_server)
+		{
+			// We need to hit the server to get urls
+			if (! context)
+				context = new StumbleGlobals.AsyncContext();
+
+			context.callbacks.push(callback);
+			
+			StumbleGlobals.hit_recommend(
+						user_cat,
+						false,
+						StumbleGlobals.get_unseen_url_done,
+						context);
+
+			// Did we get any urls from server?
+			if (StumbleGlobals.stumbles.length == 0)
+				return false;
+		}
+		else
+		{
+			// we're out of stumbles and we're not hitting the server, so bail
+			return false;
+		}
+	}
+	else
+	{
+		// we have stumbles in our queue, carry on
+		StumbleGlobals.get_unseen_url_done('', callback, context);
+	}
+	return true;
+}
+
+StumbleGlobals.get_unseen_url_done = function(error, callback, context)
+{
+	if (error == "error")
+	{
+		if (callback)
+			callback("error", context);
+		return;
+	}
+	StumbleGlobals.load_stumbles(null);
+	
+	var i;
+	for (i = 0; i < StumbleGlobals.stumbles.length; i++)
+	{
+		// Go through each seen url to see if there's one we haven't seen already
+		if (StumbleGlobals.stumbles[i] == "")
+			continue;
+		
+		if (callback)
+			callback(StumbleGlobals.stumbles[i], context);
+		return;
+	}
+
+	if (callback)
+		callback("", context);
+}
+
+StumbleGlobals.clickstumble = function(event)
+{
+	if (StumbleGlobals.promo_mode && (StumbleGlobals.stumbleid == 0))
+	{
+//		var user_cat = StumbleGlobals.selected_category;
+//		user_cat += "";
+//		
+//		if (! user_cat)
+//			user_cat = "0";
+//		
+//		var new_cat_flag = (user_cat != StumbleGlobals.ds.getValue("$last_incat"));
+//		StumbleGlobals.ds.setValue("$last_incat", user_cat);
+//	
+//		var norm_cat = StumbleGlobals.trim(user_cat.toLowerCase());
+//		if (((norm_cat == "video") || (norm_cat == "videos") || 
+//					(norm_cat == "tag_video") || (norm_cat == "tag_videos")) &&
+//					(StumbleGlobals.host.version != "0.0"))
+//		{
+//			StumbleGlobals.stumble_video(StumbleGlobals.new_tab(event));
+//		}
+//		else
+//		{
+			StumbleGlobals.handle_promo_click(event, "stumble");
+//		}
+		return;
+	}
+	
+	StumbleGlobals.stumble(StumbleGlobals.new_tab(event));
+}
+
+StumbleGlobals.AsyncContext = function()
+{
+	this.callbacks = new Array();
+}
+
+StumbleGlobals.cancel_stumble_throttle = function()
+{
+	StumbleGlobals.stumble_throttled = false;
+}
+
+StumbleGlobals.check_and_update_throttle = function()
+{
+	if (StumbleGlobals.stumble_throttled)
+	{
+		return true;
+	}
+	else
+	{
+		StumbleGlobals.stumble_throttled = true;
+		setTimeout(
+			StumbleGlobals.cancel_stumble_throttle,
+			StumbleGlobals.ds.getValue("@click_throttle_ms"));
+		return false;
+	}
+}
+
+// Before stumbling, check whether we have a current user, and return true if we do.
+// If we do not, then either show the sign in dialog or the sign up page, depending
+// on whether they have logged in before
+StumbleGlobals.stumble_check_user = function()
+{
+	var getit = StumbleGlobals.ds.getValue("@current_user");
+	if(getit)
+	{
+		// We have a user, but we still can't stumble if we don't have a stumbleid
+		return (StumbleGlobals.stumbleid != 0);
+	}
+	
+	// They are not logged in		
+
+	// see if they've already created/used an account with this toolbar
+	if (StumbleGlobals.has_logged_in())
+	{
+		StumbleGlobals.show_signin_dialog();
+	}
+	else
+	{
+		StumbleGlobals.verify_cookie_perms(false);
+		
+		StumbleGlobals.set_server_location_signup(false);
+	}
+	StumbleGlobals.check_progress_listener();
+	return false;
+}
+
+StumbleGlobals.stumble_check_show_searchlinks = function(stumble_new_tab, skip_searchlinks_dialog)
+{
+	if (! skip_searchlinks_dialog)
+	{
+		if (StumbleGlobals.show_searchlinks_dialog(true, stumble_new_tab, true))
+			return true;
+	}
+	
+	if (! StumbleGlobals.ds.getValue("$shown_searchlinks_dialog"))
+		StumbleGlobals.ds.incrementValue("$intro_count");
+
+	return false;
+}
+
+StumbleGlobals.ping_comscore = function()
+{
+	var xhr = new XMLHttpRequest;
+	var url = "http://b.scorecardresearch.com/p?c1=7&c2=7677660&c3=655321&c4=&c5=&c6=&c15=&cj=1";
+	xhr.open("GET", url, true);
+	xhr.send(null);
+}
+
+// Handler for button "Stumble"
+StumbleGlobals.stumble = function(stumble_new_tab, skip_searchlinks_dialog, stumble_referral) 
+{
+try {
+	var newDate = new Date();
+	var newTime = newDate.getTime();
+	var oldTime = StumbleGlobals.ds.getIntValue("$last_stumble");
+	
+	// avoid double-click
+	if (!stumble_new_tab && StumbleGlobals.check_and_update_throttle())
+		return;
+
+	// Make sure progress listener is installed
+	StumbleGlobals.check_progress_listener();
+
+	// Check whether we have a user or should show sign in or sign up pages
+	if (!StumbleGlobals.stumble_check_user())
+		return;
+	
+	// Check whether we should just show the searchlinks dialog
+	if(StumbleGlobals.stumble_check_show_searchlinks(stumble_new_tab, skip_searchlinks_dialog))
+		return;
+	
+	var new_cat_flag = false;
+	var user_cat = "0";
+	
+	StumbleGlobals.ds.setValue("$last_stumble", newTime);
+	
+	if(StumbleGlobals.ds.getValue("@comscore_enabled"))
+		StumbleGlobals.ping_comscore();
+	
+	// Let the stats tracker know about the click
+	StumbleGlobals.requestTracker.stumbleClicked();
+	
+	if(!stumble_referral)
+	{
+		user_cat = StumbleGlobals.selected_category;
+		
+		if (! user_cat)
+			user_cat = "0";
+		
+		new_cat_flag = (user_cat != StumbleGlobals.ds.getValue("$last_incat"));
+		StumbleGlobals.ds.setValue("$last_incat", user_cat);
+	
+		if (user_cat == "0")
+			StumbleGlobals.ds.setValue("$poll_time_s", StumbleGlobals.get_time_s());
+		
+		StumbleGlobals.ds.flushPrefs();
+		
+		// change icon...
+		StumbleGlobals.get_element("stumbleglobals_stumble").image="chrome://stumbleupon/content/skin/stumble2.png";
+		StumbleGlobals.stumble_action_count++;
+		setTimeout(
+					StumbleGlobals.reset_stumble_action_indicator,
+					StumbleGlobals.ds.getValue("@stumble_action_timeout_ms"),
+					StumbleGlobals.stumble_action_count);
+		
+		var norm_cat = StumbleGlobals.trim(user_cat.toLowerCase());
+		if (((norm_cat == "video") || (norm_cat == "videos") || 
+					(norm_cat == "tag_video") || (norm_cat == "tag_videos")) &&
+					(StumbleGlobals.host.version != "0.0"))
+		{
+			StumbleGlobals.stumble_video(stumble_new_tab);
+			return;
+		}
+	}
+	
+	if (StumbleGlobals.stumble_async_context && ((newTime - oldTime) <= 
+				StumbleGlobals.ds.getValue("@recommend_timeout_ms")) &&
+				(! new_cat_flag))
+	{
+		// If a stumble action is in progress and the category hasn't 
+		// changed, we only simulate stumbling.  Ideally, the time 
+		// comparison above shouldn't be necessary, but we include it as a
+		// failsafe to avoid disabling stumbling if 
+		// StumbleGlobals.stumble_async_context somehow doesn't get set to null. 
+		// -- JW
+
+		//!!! It would be better to queue stumble actions if they're in
+		// the same topic and if they're to be opened in new tabs.  But
+		// this would increase likelihood that a referral (and, more 
+		// importantly, a note attached to a referral) may not be seen.
+		// Here are a couple related options:
+		// o Don't consider a referral to have been seen unless the
+		//   person lingers on the relevant tab.
+		// o Highlight tabs featuring referrals that haven't been lingered
+		//   upon.
+		// o If a pending action not targeting a new tab exists, 
+		//   implicitly cancel the non-new-tab action, perhaps by 
+		//   converting it into a new-tab action.
+		// -- JW
+		
+		return;
+	}
+	else if (StumbleGlobals.stumble_async_context)
+	{
+		try {
+			// Try shouldn't be necessary, but this eliminates possibility 
+			// of an error in the callback execution path breaking 
+			// stumbling. -- JW
+			if (StumbleGlobals.stumble_async_context && StumbleGlobals.stumble_async_context._request)
+				StumbleGlobals.service.abortPostAsync(StumbleGlobals.stumble_async_context._request);
+		} catch (e) { StumbleGlobals.log_error("RECOMMEND ABORT ERROR", e); }
+	}
+
+	// see if new day is the same as today
+	var oldDate = new Date();
+	oldDate.setTime(oldTime);
+	var newDay = newDate.getDate();
+	var oldDay = oldDate.getDate();
+	var newMonth = newDate.getMonth();
+	var oldMonth = oldDate.getMonth();
+	var newYear = newDate.getYear();
+	var oldYear = oldDate.getYear();
+
+	if (new_cat_flag)
+	{
+		StumbleGlobals.clear_stumbles();
+	}
+	
+	var first_of_day = false;
+	if (oldTime != 0)
+	{
+		if (oldDay != newDay || oldMonth != newMonth || oldYear != newYear)
+		{
+			first_of_day = true;
+			// clear stumbles
+			StumbleGlobals.clear_stumbles();
+		}
+		else if (newTime - oldTime > 1000 * 60 * 60 * 2)
+		{
+			// clear stumbles if you haven't stumbled in the last 2 hours
+			// so our stumbles are "fresh"
+			StumbleGlobals.clear_stumbles();
+		}
+	}
+	
+	var target_browser = null;
+	if (! stumble_new_tab)
+		target_browser = getBrowser().selectedBrowser;
+
+	if(!stumble_referral)
+	{
+		if (typeof(user_cat) == "number" || typeof(user_cat) == "undefined" || user_cat == null || user_cat.indexOf("TAG") == -1)
+		{
+			// clear search/tag box
+			StumbleGlobals.old_search = '';
+			StumbleGlobals.get_element("stumbleglobals_searchbox").value = '';
+			StumbleGlobals.last_typed_tag = 0;
+		}
+		else
+		{
+			// put it in the box
+			if (user_cat.indexOf("TAG_") == 0)
+			{
+				var tmp_cat = user_cat.substr(4);
+	
+				// Don't tag with thru domains.
+				tag = StumbleGlobals.ds.isThruDomain(tmp_cat) ? "" : tmp_cat;
+			}
+			else if (user_cat.indexOf("USERTAG_") == 0)
+			{
+				var chunk = user_cat.substr(8);
+				chunks = chunk.split('_');
+				var tag = chunks[1];
+				var profile = chunks[0];
+			}
+			else
+			{
+				tag = '';	
+			}
+			StumbleGlobals.get_element("stumbleglobals_searchbox").value=tag;
+			StumbleGlobals.get_element("stumbleglobals_searchbox").removeAttribute("mode");
+			StumbleGlobals.old_search = tag;
+			StumbleGlobals.last_typed_tag = 0;
+			StumbleGlobals.visited_searchbox = 1;
+		}
+	}
+
+	var unseen = "";
+
+	var context = new StumbleGlobals.AsyncContext();
+	context.user_cat = user_cat;
+	context.timestamp = newTime;
+	context.new_tab = stumble_new_tab;
+	context.target_browser = target_browser;
+	context.quiet = false;
+	context.stumblevideo = false;
+	context.first_of_day = first_of_day;
+	context.skip_count = 0;
+	context.stumble_referral = stumble_referral;
+
+	StumbleGlobals.stumble_async_context = context;
+	
+	if(stumble_referral)
+	{
+		StumbleGlobals.hit_recommend(
+					0,
+					true,
+					function(error, callback, context) {
+						if(error == "error")
+							window.stumble_done("error", context);
+						else
+							window.stumble_done(context.referral_url, context);
+					},
+					context);
+	}
+	else
+	{
+		StumbleGlobals.get_unseen_url(
+					user_cat,
+					1,
+					function(unseen, context) { window.stumble_done(unseen, context); },
+					context);
+	}
+	
+	
+	} catch (e) {
+		if (StumbleGlobals.stumbleid == 0)
+			StumbleGlobals.log_error("STUMBLE LOGGED-OUT", e);
+		else
+			StumbleGlobals.log_error("STUMBLE LOGGED-IN", e, StumbleGlobals.ds.getValue("$last_incat"), StumbleGlobals.service.getErrorObjectDump(StumbleGlobals.stumble_async_context));
+		StumbleGlobals.stumble_async_context = null;
+	}
+}
+
+StumbleGlobals.stumble_video = function(new_tab)
+{
+	var label;
+	if (!(StumbleGlobals.promo_mode && (StumbleGlobals.stumbleid == 0)))
+	{
+		StumbleGlobals.set_mode("video", "Video",
+					"chrome://stumbleupon/content/skin/video.png",
+					"Stumble! ", "Stumble a video");
+	}
+	
+	if (new_tab)
+	{
+		StumbleGlobals.pending_stumblevideo_stumble = true;
+		var params = StumbleGlobals.arp("", "stumblefrom", StumbleGlobals.useragent);
+		StumbleGlobals.set_location(
+					"http://video." + StumbleGlobals.servername + "/",
+					params,
+					true);
+	}
+	else if (StumbleGlobals.is_matching_domain(StumbleGlobals.get_browser_url(null, true), 
+				"video." + StumbleGlobals.servername))
+	{
+		StumbleGlobals.dispatch_click(getBrowser().contentDocument, "stumbleButton");
+	}
+	else
+	{
+		StumbleGlobals.pending_stumblevideo_stumble = true;
+		var params = StumbleGlobals.arp("", "stumblefrom", StumbleGlobals.useragent);
+		StumbleGlobals.set_location(
+					"http://video." + StumbleGlobals.servername + "/",
+					params,
+					false);
+	}
+}
+
+StumbleGlobals.update_message = function(tab_url_detail, url_detail, url, tld, stumblevideo)
+{
+	if (! tab_url_detail)
+		return;
+	
+	if (! tab_url_detail.messageid)
+		return;
+	
+	var id = "stumbleglobals_messageOuterBox" + tab_url_detail.messageid;
+	
+	if (StumbleGlobals.drawer_timers[id])
+		return;
+	
+	var el;
+	if (url_detail == tab_url_detail)
+	{
+		el = StumbleGlobals.get_element("stumbleglobals_bannerReloadButton" + tab_url_detail.messageid);
+		if (el)
+			el.disabled = true;
+	}
+	else if (stumblevideo && (url != tab_url_detail.url))
+	{
+		StumbleGlobals.close_message(tab_url_detail.messageid, true);
+	}
+	else if ((! stumblevideo) && (tab_url_detail.tld != tld))
+	{
+		StumbleGlobals.close_message(tab_url_detail.messageid, true);
+	}
+	else
+	{
+		el = StumbleGlobals.get_element("stumbleglobals_bannerReloadButton" + tab_url_detail.messageid);
+		if (el)
+			el.disabled = false;
+	}
+}
+
+/*
+StumbleGlobals.update_verified_reporting = function(enable_reporting)
+{
+	if (StumbleGlobals.enable_freereporting)
+		return;
+	
+	// people can't report a stumble as 404/spam until they actually stumble
+	var disabled = (enable_reporting) ? "false" : "true";
+	
+	StumbleGlobals.get_element("stumbleglobals_report-menu").setAttribute("disabled", disabled);
+	StumbleGlobals.get_element("stumbleglobals_flag_adult").setAttribute("disabled", disabled);
+	StumbleGlobals.get_element("stumbleglobals_flag_wrongtopic").setAttribute("disabled", disabled);
+	StumbleGlobals.get_element("stumbleglobals_flag_duplicate").setAttribute("disabled", disabled);
+	StumbleGlobals.get_element("stumbleglobals_flag_inaccurate").setAttribute("disabled", disabled);
+	StumbleGlobals.get_element("stumbleglobals_flag_spam").setAttribute("disabled", disabled);
+	StumbleGlobals.get_element("stumbleglobals_flag_broken").setAttribute("disabled", disabled);
+	StumbleGlobals.get_element("stumbleglobals_flag_wronglanguage").setAttribute("disabled", disabled);
+}
+*/
+
+StumbleGlobals.update_comment_level = function(url_detail, rateable)
+{
+	if (url_detail && url_detail.comment_level)
+		StumbleGlobals.set_image("stumbleglobals_website_info", "chrome://stumbleupon/content/skin/bubble" + url_detail.comment_level + ".png");
+	
+	else if (rateable)
+		StumbleGlobals.set_image("stumbleglobals_website_info", "chrome://stumbleupon/content/skin/bubble.png");
+	
+	else
+		StumbleGlobals.set_image("stumbleglobals_website_info", "chrome://stumbleupon/content/skin/bubblex.png");
+}
+
+StumbleGlobals.update_referral_menu_tooltip = function(url_detail, stumblevideo)
+{
+	var el = StumbleGlobals.get_element("stumbleglobals_referral_menu");
+	
+	if (! url_detail)
+	{
+		el.setAttribute("tooltiptext", "Share this page");
+		return;
+	}
+	
+	if (stumblevideo)
+		el.setAttribute("tooltiptext", "Share this video");
+	
+	else if (url_detail.catid == 302)
+		el.setAttribute("tooltiptext", "Share this picture");
+	
+	else
+		el.setAttribute("tooltiptext", "Share this page");
+}
+
+StumbleGlobals.update_firstrater = function(url_detail)
+{
+	if (! url_detail)
+	{
+		StumbleGlobals.set_visible("firstrater", false);
+		StumbleGlobals.set_visible("stumbleglobals_sponsor", false);
+		StumbleGlobals.set_image("stumbleglobals_website_info",
+					"chrome://stumbleupon/content/skin/bubble.png");
+		StumbleGlobals.set_image("stumbleglobals_referral_menu", 
+					"chrome://stumbleupon/content/skin/icon_tb_share.png");
+		return;
+	}
+
+	if ((url_detail.relationship == "sponsored") || 
+				(url_detail.relationship == "friend-sponsored"))
+	{
+		// sponsor
+	
+		// Set and show sponsor button
+		StumbleGlobals.set_visible("stumbleglobals_sponsor", true);
+		frater = StumbleGlobals.get_element("stumbleglobals_sponsor");
+		frater.setAttribute("tooltiptext", "This site is sponsored");
+	}
+	else
+	{
+		// nonsponsor
+	
+		// Hide sponsor button
+		StumbleGlobals.set_visible("stumbleglobals_sponsor", false);
+	}
+
+	if (! url_detail.firstrater_nick)
+	{
+		// Hide firstrater button
+		StumbleGlobals.set_visible("firstrater", false);
+		return;
+	}
+	
+	// Set and show firstrater button
+	frater = StumbleGlobals.get_element("firstrater");
+	
+	StumbleGlobals.set_visible("firstrater", true);
+	
+	var tooltip = url_detail.firstrater_nick;
+	
+	StumbleGlobals.set_label("firstrater", url_detail.firstrater_nick);
+	
+	switch (url_detail.relationship)
+	{
+		case "referral":
+			// this site was sent directly to you by a friend	
+			frater.image = "chrome://stumbleupon/content/skin/redman.png";
+			tooltip += " who sent you: ";
+			break;
+			
+		case "friend":
+			// your friend rate this site	
+			frater.image = "chrome://stumbleupon/content/skin/redman.png";
+			tooltip += " who recommends: ";
+			break;
+		
+		case "friend-sponsored":
+			frater.image = "chrome://stumbleupon/content/skin/redman.png";
+			tooltip += " who suggested: ";
+			break;
+			
+		case "sponsored":
+			// a non friend rated this site	
+			frater.image = "chrome://stumbleupon/content/skin/firstrater.png";
+			tooltip += " who recommends: ";
+			break;
+	
+		case "firstrater":
+			// a non friend rated this site	
+			frater.image = "chrome://stumbleupon/skin/firstrater.png";
+			tooltip += " who suggested: ";
+			break;
+	}
+
+	tooltip += url_detail.url;
+
+	frater.firstrater = url_detail.firstrater_nick;
+	frater.setAttribute("tooltiptext", tooltip);
+}
+
+StumbleGlobals.update_thru_domain = function(url, tld, url_detail, stumblevideo, from_resource_installed)
+{
+	if (! url)
+		return;
+
+	if (! tld)
+		tld = StumbleGlobals.get_tld(url);
+	
+	if ((! tld) || (url_detail && stumblevideo)) 
+	{
+		StumbleGlobals.set_visible("stumbleglobals_mode_domain", false);
+		StumbleGlobals.set_image("stumbleglobals_mode_domain",
+					"chrome://stumbleupon/content/skin/topic.png");
+		return;
+	}
+	
+	var tld_parts = tld.split(".");
+	
+	var i = 0;
+	var domain = null;
+	var cmp = "";
+	while (tld_parts.length)
+	{
+		var part = tld_parts.pop();
+		if (part == "")
+			return;
+		
+		if (i == 0)
+			cmp = "." + part;
+		else if (i == 1)
+			cmp = part + cmp;
+		else
+			cmp = part + "." + cmp;
+		
+		if (StumbleGlobals.ds.isThruDomain(cmp))
+			domain = cmp;
+		
+		i++;
+	}
+
+	if (domain)
+	{
+		if (StumbleGlobals.get_element("stumbleglobals_mode_dyn_" + StumbleGlobals.get_channel_id(domain)))
+			domain = null;
+	}
+	
+	if ((domain == "wikipedia.org") && 
+				StumbleGlobals.ds.getValue("$show_mode_wiki"))
+		domain = null;
+	
+	if (! domain)
+	{
+		StumbleGlobals.set_visible("stumbleglobals_mode_domain", false);
+		StumbleGlobals.set_image("stumbleglobals_mode_domain",
+					"chrome://stumbleupon/content/skin/topic.png");
+		
+		if (StumbleGlobals.info_spec && StumbleGlobals.info_spec.domain)
+			StumbleGlobals.hide_info();
+		
+		return;
+	}
+	
+	var favicon_url = StumbleGlobals.get_favicon_url(domain);
+	
+	if (favicon_url)
+	{
+		StumbleGlobals.set_image("stumbleglobals_mode_domain", favicon_url);
+	}
+	else
+	{
+		StumbleGlobals.set_image("stumbleglobals_mode_domain",
+					"chrome://stumbleupon/content/skin/domain.png");
+	}
+	StumbleGlobals.set_visible("stumbleglobals_mode_domain", true);
+	var el = StumbleGlobals.get_element("stumbleglobals_mode_domain");
+	el.setAttribute("onclick", "StumbleGlobals.handle_domain_mode_click(event, '" + domain + "');");
+	el.setAttribute("tooltiptext", "Stumble a page from " + domain);
+	
+	if (stumblevideo)
+		return;
+	
+	if (from_resource_installed)
+		return;
+	
+	if (StumbleGlobals.ds.getValue("$shown_thru_domain_info_count") >= StumbleGlobals.ds.getValue("~shown_thru_domain_info_count_max"))
+		return;
+	
+	var domains = StumbleGlobals.ds.getValue("$shown_thru_domain_info_list").split(":");
+	for (i = 0; i < domains.length; i++)
+	{
+		if (domains[i] == "")
+			continue;
+		
+		if (domains[i] == domain)
+			return;
+	}
+	
+	StumbleGlobals.display_info("thru_domain", domain);
+}
+
+StumbleGlobals.update_topic_and_reporting = function(tab_url_detail, url_detail, tld, from_stumbled, rec_url)
+{
+	
+	var el = StumbleGlobals.get_element("stumbleglobals_morefrom");
+
+	if (el && url_detail && url_detail.topic_name)
+	{
+		el.setAttribute("label", "More from " + url_detail.topic_name);
+		el.setAttribute("tooltiptext", "More from " + url_detail.topic_name);
+		el.setAttribute("hidden", "false");
+		el.setAttribute("oncommand", "StumbleGlobals.select_topic(" + 
+					url_detail.catid + ",'" + url_detail.topic_name + "', false);");
+	}	
+	else if (el)
+	{
+		el.setAttribute("hidden", "true");
+	}
+
+	// Define the topic button used for display
+
+	var topics_style = StumbleGlobals.ds.getValue("$stumble_topics_style");
+	
+	var menu_style = (topics_style != 2);
+	
+	// Set the information to the topic button
+	
+	var report_menu = StumbleGlobals.get_element("stumbleglobals_stumble_report_menu"); 
+	
+	if (menu_style && StumbleGlobals.ds.getValue("$stumble_topics"))
+	{
+		StumbleGlobals.set_visible("stumbleglobals_stumble_topic", false);
+		
+		var widget_id;
+		
+		switch (topics_style)
+		{
+			case 0: widget_id = "stumbleglobals_stumble_topic_menu_left";  break;
+			case 1: widget_id = "stumbleglobals_stumble_topic_menu_right"; break;
+		}
+		
+		if ((url_detail && url_detail.cur_topic_name) ||
+				(tab_url_detail && (tab_url_detail.tld == tld) &&
+				tab_url_detail.cur_topic_name))
+		{
+			var url = (url_detail) ? url_detail.url : tab_url_detail.url;
+			var topic_name = (url_detail) ? url_detail.cur_topic_name : tab_url_detail.cur_topic_name;
+			StumbleGlobals.get_element(widget_id + "_popup").removeAttribute("onpopupshowing");
+			StumbleGlobals.get_element(widget_id + "_popup").setAttribute("onpopupshowing",
+					'StumbleGlobals.prepare_stumble_topic_menu(event, "' + url + '");');
+			
+			if (tab_url_detail && (tab_url_detail == url_detail))
+				StumbleGlobals.remove_attribute(widget_id, "style");
+			else
+				StumbleGlobals.set_attribute(widget_id, "style", "color: #707070;");
+			
+			if (topics_style == 1)
+				StumbleGlobals.set_visible("stumbleglobals_separator7", true);
+			
+			StumbleGlobals.set_label(widget_id, topic_name);
+			StumbleGlobals.set_visible(widget_id, true);
+		}
+		else
+		{
+			StumbleGlobals.set_visible(widget_id, false);
+			StumbleGlobals.set_visible("stumbleglobals_separator7", false);
+		}
+	}
+	else
+	{
+		StumbleGlobals.set_visible("stumbleglobals_stumble_topic_menu_left", false);
+		StumbleGlobals.set_visible("stumbleglobals_stumble_topic_menu_right", false);
+		
+		if (url_detail && url_detail.cur_topic_name && StumbleGlobals.ds.getValue("$stumble_topics"))
+		{
+			StumbleGlobals.set_label("stumbleglobals_stumble_topic", url_detail.cur_topic_name);
+			StumbleGlobals.get_element("stumbleglobals_stumble_topic").removeAttribute("onclick");
+			StumbleGlobals.get_element("stumbleglobals_stumble_topic").setAttribute("onclick", 
+					'StumbleGlobals.handle_stumble_topic_click(event, "' + url_detail.url + '");');
+			StumbleGlobals.set_visible("stumbleglobals_stumble_topic", true);
+			StumbleGlobals.set_visible("stumbleglobals_separator7", true);
+		}
+		else
+		{
+			StumbleGlobals.set_visible("stumbleglobals_stumble_topic", false);
+			StumbleGlobals.set_visible("stumbleglobals_separator7", false);
+		}
+	}
+	
+		
+	if ((url_detail && url_detail.cur_topic_name) ||
+			(tab_url_detail && (tab_url_detail.tld == tld)) ||
+			rec_url)
+	{
+		var url;
+		if (url_detail)
+			url = url_detail.url;
+		else if (rec_url)
+			url = rec_url;
+		else
+			url = tab_url_detail.url;
+		
+		StumbleGlobals.get_element("stumbleglobals_stumble_report_popup").removeAttribute("onpopupshowing");
+		StumbleGlobals.get_element("stumbleglobals_stumble_report_popup").setAttribute("onpopupshowing",
+				'StumbleGlobals.prepare_stumble_report_menu(event, "' + url + '");');
+		report_menu.disabled = false;
+		
+		if (tab_url_detail && (tab_url_detail == url_detail))
+			report_menu.removeAttribute("style");
+		else
+			report_menu.setAttribute("style", "color: #707070;");
+	}
+	else
+	{
+		report_menu.disabled = true;
+	}
+
+	// Update the separator that may be affected by whether the topic menu is visible.
+	StumbleGlobals.set_visible("stumbleglobals_separator_category", !StumbleGlobals.get_element("stumbleglobals_stumble_topic_menu_left").collapsed);
+}
+
+/*
+StumbleGlobals.update_language = function(url_detail, from_stumbled)
+{
+	if ((! from_stumbled) && (! StumbleGlobals.enable_freereporting))
+		return;
+	
+	// Update language UI elements.
+	if (url_detail && url_detail.language)
+	{
+		StumbleGlobals.get_element("stumbleglobals_wronglanguage").label='Wrong Language (currently ' + url_detail.language + ')';
+		StumbleGlobals.get_element("stumbleglobals_flag_wronglanguage").label='Flag as Wrong Language (currently ' + url_detail.language + ')';
+	}
+	else
+	{
+		StumbleGlobals.get_element("stumbleglobals_wronglanguage").label='Wrong Language';
+		StumbleGlobals.get_element("stumbleglobals_flag_wronglanguage").label='Flag as Wrong Language';
+	}
+}
+*/
+
+StumbleGlobals.update_page_feature_prompt = function(url)
+{
+	var service_detail = StumbleGlobals.get_service_meta(url, true);
+	
+	if (StumbleGlobals.is_matching_domain("facebook.com"))
+	{
+		if (StumbleGlobals.ds.getValue("#checked_facebook"))
+		{
+			if (StumbleGlobals.ds.getValue("$facebook_linked"))
+			{
+				StumbleGlobals.set_visible("stumbleglobals_page_feature_prompt", false);
+			}
+			else
+			{
+				StumbleGlobals.set_image("stumbleglobals_page_feature_prompt", "chrome://stumbleupon/content/skin/favicon_facebook.gif");
+
+				if (StumbleGlobals.ds.getValue("$facebook_added"))
+					StumbleGlobals.set_label("stumbleglobals_page_feature_prompt", "Link your Facebook account");
+				else
+					StumbleGlobals.set_label("stumbleglobals_page_feature_prompt", "Share using Facebook");
+					
+				StumbleGlobals.get_element("stumbleglobals_page_feature_prompt").setAttribute("tooltiptext", "Share and browse using the StumbleUpon application on Facebook");
+				StumbleGlobals.set_visible("stumbleglobals_page_feature_prompt", true);
+			}
+		}
+		else
+		{
+			StumbleGlobals.get_facebook(null);
+		}
+	}
+	else if (service_detail)
+	{
+		if (0) //StumbleGlobals.ds.hasFeature("$slbuttonprompt") &&
+//				(! StumbleGlobals.ds.getValue("$show_searchlinks_score")) &&
+//				(! StumbleGlobals.ds.getValue("$show_searchlinks_friends")) &&
+//				(! StumbleGlobals.ds.getValue("$show_searchlinks_topic")) &&
+//				((! StumbleGlobals.ds.getValue("$shown_searchlinks")) || 
+//				StumbleGlobals.ds.hasFeature("$slbuttonpermaprompt")))
+		{
+			StumbleGlobals.set_image("stumbleglobals_page_feature_prompt", service_detail.icon);
+			StumbleGlobals.set_label("stumbleglobals_page_feature_prompt", service_detail.prompt_label);
+			StumbleGlobals.get_element("stumbleglobals_page_feature_prompt").setAttribute("tooltiptext",  service_detail.prompt_tooltip);
+			StumbleGlobals.set_visible("stumbleglobals_page_feature_prompt", true);
+		}
+		else
+		{
+			StumbleGlobals.set_visible("stumbleglobals_page_feature_prompt", false);
+		}
+	}
+	else
+	{
+		StumbleGlobals.set_visible("stumbleglobals_page_feature_prompt", false);
+	}
+}
+
+StumbleGlobals.update_website_info_promo = function(url)
+{
+	var service_detail = StumbleGlobals.get_service_meta(url, false);
+	
+	if (url.indexOf(StumbleGlobals.base_url + "url") == 0)
+		StumbleGlobals.get_element("stumbleglobals_website_info_promo").disabled = true;
+	else
+		StumbleGlobals.get_element("stumbleglobals_website_info_promo").disabled = false;
+
+	if (service_detail)
+	{
+		StumbleGlobals.search_service_id = service_detail.id;
+		StumbleGlobals.set_image("stumbleglobals_website_info_promo", service_detail.icon);
+		StumbleGlobals.set_label("stumbleglobals_website_info_promo", service_detail.prompt_label);
+		StumbleGlobals.get_element("stumbleglobals_website_info_promo").setAttribute("tooltiptext",  service_detail.prompt_tooltip);
+	}
+	else
+	{
+		StumbleGlobals.search_service_id = null;
+		StumbleGlobals.set_image("stumbleglobals_website_info_promo", "chrome://stumbleupon/content/skin/bubble.png");
+		StumbleGlobals.set_label("stumbleglobals_website_info_promo", StumbleGlobals.get_element("stumbleglobals_website_info_promo").getAttribute("showlabel"));
+		StumbleGlobals.get_element("stumbleglobals_website_info_promo").setAttribute("tooltiptext",  "People who like this");
+	}
+}
+		
+StumbleGlobals.get_tld = function(url)
+{
+	return StumbleGlobals.service.getEffectiveTLD(url);
+}
+
+StumbleGlobals.get_bad_referral_url = function(url_string)
+{
+	return StumbleGlobals.serverhttp + "bad_referral_sent?referral=" + encodeURIComponent(url_string);
+}
+
+StumbleGlobals.deserialize_url_command_params = function(unseen, for_load)
+{
+	var field_names = new Array(
+				"url",                //  1 .
+				"catid",              //  2
+				"referrer",           //  3 .
+				"actual_url",         //  4 .
+				"firstrater",         //  5
+				"firstrater_nick",    //  6
+				"lang_code",          //  7  not mime_type?
+				"cluster_type",       //  8 .
+				"urlid",              //  9 .
+				"publicid",           // 10
+				"comment_level",      // 11
+				"rec_type",           // 12
+				"referral_note",      // 13
+				"referralid",         // 14 .
+				"catid2",             // 15
+				"catid3"              // 16
+				);
+	
+	var a = unseen.split(" ");
+	var spec = new Object();
+	var i;
+	for (i = 0; i < field_names.length; i++)
+	{
+		if (a.length > 0)
+			spec[field_names[i]] = a.shift();
+		else
+			spec[field_names[i]] = null;
+		
+		if (spec[field_names[i]] == "")
+			spec[field_names[i]] = null;
+	}
+	
+	if (!spec.url || !spec.url.match(/^(http|https|ftp):/i))
+	{
+		if(spec.cluster_type && spec.referralid && (spec.cluster_type == "4"))
+		{
+			// Workaround for server sending malformed or empty URLs.
+			// If it's a referral, we still want to try to show it and report it, or the user
+			// will be stuck.
+			spec.url = StumbleGlobals.get_bad_referral_url(spec.referralid);			
+		}
+		else
+			return null;
+	}
+	
+//	spec.load_dateobj = null;
+	
+	spec.redirect_url = spec.url;
+	
+	if (spec.url && spec.url != "")
+		spec.tld = StumbleGlobals.get_tld(spec.url);
+	
+	if (! spec.tld)
+		spec.tld = "";
+	
+	if (spec.cluster_type)
+		spec.cluster_type = parseInt(spec.cluster_type);
+	
+	if (! spec.urlid)
+		spec.urlid = 0;
+	
+
+	if (for_load)
+		return spec;
+	
+	
+	spec.sender = (spec.firstrater_nick) ? 
+				spec.firstrater_nick : spec.firstrater;
+	
+	spec.is_system_referral = ((spec.cluster_type == 4) &&
+				spec.sender && 
+				(spec.sender.toLowerCase() == "stumbleupon"));
+	
+	spec.is_friend_referral = ((spec.cluster_type == 4) && 
+				(! spec.is_system_referral));
+	
+	if (spec.referral_note)
+	{
+		try {
+			spec.referral_note = decodeURIComponent(spec.referral_note);
+			if (spec.referral_note.length > 5000)
+				spec.referral_note = spec.referral_note.substring(0, 4999);
+		}
+		catch (e) {
+			spec.referral_note = null;
+			StumbleGlobals.log_error("BAD REFERRALNOTE", e);
+		}
+	}
+//		spec.referral_note = spec.referral_note.replace(/\|/g, ' ');
+	
+	if (! spec.rec_type)
+		spec.rec_type = 0;
+
+	if (spec.comment_level)
+		spec.comment_level = parseInt(spec.comment_level);
+	else
+		spec.comment_level = 0;
+	
+	// Augment with category_name, relationship, language
+	spec.display_url = spec.url;
+	
+	spec.stumblevideo = false;
+	
+	spec.cur_catid = spec.catid;
+	
+	spec.topic_name = StumbleGlobals.catnames[spec.catid];
+	if (! spec.topic_name)
+		spec.topic_name = null;
+	
+	spec.cur_topic_name = spec.topic_name;
+	
+	spec.rating = null;
+	
+	var status;
+	// show user's comment (if it's not a referral, and there is a comment) using display_message
+	switch (spec.cluster_type)
+	{
+		case 1:   status = "friend"; break;
+		case 3:   
+			if (spec.firstrater_nick && StumbleGlobals.is_mutual_friend(spec.firstrater_nick)) 
+				status = "friend-sponsored";
+			else
+				status = "sponsored";
+			break;
+		case 4:
+			status = "referral";
+			spec.rating = StumbleGlobals.get_rating(spec.url, false, null);
+			break;
+		default:  status = "firstrater"; break;
+	}
+	spec.relationship = status;
+	
+	spec.language = StumbleGlobals.ds.lookup("lang_code:language", spec.lang_code);
+	
+	if (spec.catid2)
+		spec.catid2 = parseInt(spec.catid2);
+
+	if (spec.catid3)
+		spec.catid3 = parseInt(spec.catid3);
+	
+	spec.eval_interval = 0;
+	
+	spec.shown_dateobj = null;
+	
+	return spec;
+}
+
+function stumble_done(unseen, context)
+{
+	try {
+	
+	StumbleGlobals.stumble_async_context = null;
+	StumbleGlobals.get_element("stumbleglobals_stumble").image="chrome://stumbleupon/content/skin/stumble.png";
+
+	// ignore excessively delayed responses
+	var delay_ms = ((new Date()).getTime()) - context.timestamp;
+	if (delay_ms > StumbleGlobals.ds.getValue("@stumble_action_timeout_ms"))
+		return;
+	
+	if ((unseen == "error") || (unseen == "connection error"))
+		return;
+	
+	if (!unseen)
+	{
+		StumbleGlobals.stumble_done_no_stumbles(context);
+		return;
+	}
+	
+	// Build the url_detail spec.
+	
+	var url_detail = StumbleGlobals.deserialize_url_command_params(unseen, false);
+	
+//	url_detail.url = "http://media.tumblr.com/mlsyKxOF8fzc9kd1zQ37q9b8o1_500.jpg";
+//	url_detail.urlid = "25624734";
+//	url_detail.tld = StumbleGlobals.get_tld(url_detail.url);
+	
+	if (! url_detail)
+	{
+		StumbleGlobals.log_error("STUMBLE DESERIALIZE", unseen);
+		StumbleGlobals.clear_stumbles();
+		StumbleGlobals.stumble_done_no_stumbles(context);
+		return;
+	}
+	
+	// These shouldn't be served, but it doesn't hurt to do a sanity
+	// check.
+	if ((url_detail.cluster_type != 4) && StumbleGlobals.is_domain_blocked(url_detail.tld))
+	{
+		StumbleGlobals.enqueue_stumblestats(url_detail);
+		StumbleGlobals.load_stumbles(url_detail.url);
+		StumbleGlobals.save_stumbles();
+		setTimeout(StumbleGlobals.skip_stumble, 0, context);
+		return;
+	}
+	
+//	StumbleGlobals.dd("setstumbled", 1, url_detail.url);
+	// Set globals.
+	StumbleGlobals.stumbled_url = url_detail.url;
+	StumbleGlobals.redirect_url = url_detail.url;
+//	StumbleGlobals.dd("reset", 1);
+	StumbleGlobals.stumbled_redirect = "";
+
+	// Record url details.
+	StumbleGlobals.ds.define("url:url_detail", StumbleGlobals.stumbled_url, url_detail);
+	
+//		if (url_detail.affiliate_url)
+//		{
+//			StumbleGlobals.prefetch_url(
+//						url_detail.affiliate_url,
+//						StumbleGlobals.base_url + "refer.php?url=" + escape(url_detail.affiliate_url),
+//						0);
+//		}
+
+	// Report the stumble (make sure the stats work happens before the startNewStumble)
+	StumbleGlobals.enqueue_stumblestats(url_detail);
+	
+	// Start tracking the new stumble (it's important that the stats work happen before this)
+	StumbleGlobals.requestTracker.startNewStumbleUrl(url_detail);
+	
+	// Show the stumble!
+	shown = StumbleGlobals.stumble_done_show_stumble(url_detail, context);
+	
+	if (! shown)
+	{
+		StumbleGlobals.check_progress_listener();
+		return;
+	}
+	
+	// Note that we still try to keep the count on the client, and just let the server 
+	// override it with SSC after the submission occurs, if necessary.  We are doing this primarily
+	// for testing purposes because the toolbar might be pointed at a server that doesn't yet 
+	// implement SSC and SFC
+	var stumble_count = StumbleGlobals.ds.incrementValue("$stumble_count");
+	StumbleGlobals.stumble_count_changed();
+	
+	StumbleGlobals.log_dd_uc(unseen);
+	
+	if (context.user_cat.indexOf("TAG_") == 0)
+	{
+		var str = context.user_cat.substr(4).toLowerCase();
+		if (StumbleGlobals.ds.isThruDomain(str))
+		{
+			var spec = StumbleGlobals.ds.getValue("#recent_info_spec");
+			
+			if (spec.domain && spec.domain == str)
+			{
+				if (! StumbleGlobals.ds.getValue("$shown_toall_info"))
+					setTimeout(StumbleGlobals.display_info, 0, "thru_domain_praise_toall", spec.domain);
+				else if (! StumbleGlobals.ds.getValue("$shown_tomore_info")) 
+					setTimeout(StumbleGlobals.display_info, 0, "thru_domain_praise_tomore", spec.domain);
+			}
+			
+			StumbleGlobals.close_info();
+		}
+	}
+	else if (context.user_cat == "302")
+	{
+		StumbleGlobals.ds.setValue("$shown_photo_info", true);
+		
+		var spec = StumbleGlobals.ds.getValue("#recent_info_spec");
+		
+		if ((spec.type == "photo") && (! StumbleGlobals.ds.getValue("$shown_toall_info")))
+			setTimeout(StumbleGlobals.display_info, 0, "photo_praise");
+		
+		StumbleGlobals.close_info();
+	}
+	else if (StumbleGlobals.is_image_url(url_detail.url) && (! StumbleGlobals.ds.getValue("$shown_photo_info")))
+	{
+		setTimeout(StumbleGlobals.display_info, 0, "photo");
+		
+		StumbleGlobals.close_info();
+	}
+	else
+	{
+		StumbleGlobals.close_info();
+	}
+	
+	// Remove the url from our local stumble queue.
+	//!!! We want to do
+	//    - removal from local queue
+	//    - stumbletimes recording
+	//    - referral count decriment
+	//    after both (a) the page loads enough for the user to have
+	//    reviewed content and (b) the user has visited the tab.  But
+	//    detecting those events is a relatively difficult problem. 
+	//    -- JW
+	
+	//!!! Are we removing multiple referrals for the same url? -- JW
+	StumbleGlobals.load_stumbles(url_detail.url);
+	StumbleGlobals.save_stumbles();
+	
+	// Update topic UI elements.
+	StumbleGlobals.update_topic_and_reporting(url_detail, url_detail, url_detail.tld, true, null);
+	StumbleGlobals.update_firstrater(url_detail);
+	
+//	StumbleGlobals.update_language(url_detail, true);
+	
+	// Clear old sponsor or firstrater buttons
+//	StumbleGlobals.set_visible("stumbleglobals_sponsor", false);
+//	StumbleGlobals.set_visible("firstrater", false);
+
+	// If we have a message, display it.
+	if (url_detail.is_friend_referral || url_detail.referral_note)
+	{
+		setTimeout(
+					StumbleGlobals.stumble_done_display_message,
+					0,
+					url_detail,
+					context.target_browser);
+	}
+	else if ((stumble_count >= 5) &&
+			((StumbleGlobals.ds.getValue("$thumbup_count") + StumbleGlobals.ds.getValue("$thumbdown_count")) <= 1) &&
+			(! StumbleGlobals.ds.getValue("$shown_rate_info")))
+	{
+		StumbleGlobals.display_info("rate");
+	}
+	
+	// If this is a referral, decriment referral count.
+	//!!! May get out of sync if we start sending referrals via the SV 
+	//    page. -- JW
+	if (url_detail.cluster_type == 4)
+		StumbleGlobals.decriment_undelivered_count();
+	
+	if ((! context.stumblevideo) && 
+				(StumbleGlobals.stumbled_url.indexOf(StumbleGlobals.serverhttp + "first_stumble.php") != 0))
+	{
+		// get unseen url, but don't hit the server to do it
+		StumbleGlobals.get_unseen_url(
+					context.user_cat,
+					0,
+					null,
+					null);
+	}
+	
+	StumbleGlobals.check_progress_listener();
+	
+	StumbleGlobals.register_activity("stumble");
+	
+	} catch (e) { StumbleGlobals.log_error("STUMBLE DONE", e); }
+}
+
+StumbleGlobals.is_image_url = function(url)
+{
+	//!!! Ideally, we should use the content type logic from the
+	// surveyor. -- JW
+	return (url.match(/\.(jpg|jpeg|png|gif)$/) ? true : false);
+}
+
+StumbleGlobals.stumble_done_show_stumble = function(url_detail, context)
+{
+	try {
+		StumbleGlobals.prefetcher.advancePastTarget(StumbleGlobals.stumbled_url);
+	} catch (e) { StumbleGlobals.log_error("PREFETCHER 5", e); }
+	
+	var detail = StumbleGlobals.get_async_target_browser(
+				context.target_browser,
+				context.new_tab);
+	
+	if (! detail)
+		return false;
+	
+	context.target_browser = detail.target_browser;
+	
+	if (context.target_browser.stumbleglobals_url_detail && context.target_browser.stumbleglobals_url_detail.messageid)
+	{
+		setTimeout(
+				StumbleGlobals.close_message,
+				0,
+				context.target_browser.stumbleglobals_url_detail.messageid,
+				true);
+	}
+	
+	context.target_browser.stumbleglobals_url_detail = url_detail;
+	
+	//var referrer = StumbleGlobals.base_url + "refer.html";
+	var referrer = StumbleGlobals.base_url + "refer.php?url=" + encodeURIComponent(StumbleGlobals.stumbled_url);
+	if (url_detail.referrer)
+		referrer = url_detail.referrer;
+	
+	if (! StumbleGlobals.ds.getValue("@enable_refer"))
+		referrer = "about:blank";
+	
+	if (StumbleGlobals.is_adult_category(url_detail.catid))
+		referrer = url_detail.url;
+	
+	var postdata = "";
+	if (url_detail.url.indexOf(StumbleGlobals.base_url + "signup.php") == 0)
+		postdata = StumbleGlobals.get_client_postdata(url_detail.url);
+	
+	var listener = new StumbleGlobals.StumbleProgressListener(url_detail, context);
+	try {
+		context.target_browser.addProgressListener(listener);
+	} catch (e) {}
+	
+	StumbleGlobals.requestTracker.trackEvent(url_detail.url, "startLoad");
+	
+	//	context.target_browser.stumbleglobals_content_clicked = false;
+	try {
+		context.target_browser.webNavigation.loadURI(
+					url_detail.url,
+					0,
+					StumbleGlobals.get_nsiuri(referrer),
+					(postdata == "") ? null : StumbleGlobals.get_mime_input_stream(postdata, "application/x-www-form-urlencoded"),
+					null);
+	} catch (e) { StumbleGlobals.log_error("LOADURI ERROR4", e, url_detail.url); }
+
+	return true;
+}
+
+StumbleGlobals.enqueue_stumblestats = function(url_detail)
+{
+	if (!url_detail.publicid)
+		return;
+
+	// Old urlids, don't store, just send
+    var recently_seen = StumbleGlobals.ds.getValue("$recently_seen");
+	var seen_urlids;
+	if (recently_seen == "")
+		seen_urlids = new Array();
+	else
+		seen_urlids = recently_seen.split(".");
+    
+    // New format, public ids
+    var recently_seen_publicids = StumbleGlobals.ds.getValue("$recently_seen_publicids");
+    var seen_publicids;
+    if(recently_seen_publicids == "")
+        seen_publicids = new Array();
+    else
+        seen_publicids = recently_seen_publicids.split(".");
+
+    // Add this public id to recentlyseen
+    seen_publicids.push(url_detail.publicid);
+    while (seen_publicids.length > 50)
+		seen_publicids.shift();
+	StumbleGlobals.ds.setValue("$recently_seen_publicids", seen_publicids.join("."));
+	
+	// Recently seen referral ids
+	var recently_seen_referralids = StumbleGlobals.ds.getValue("$recently_seen_referralids");
+	var seen_referralids;
+	if(recently_seen_referralids == "")
+		seen_referralids = new Array();
+	else
+		seen_referralids = recently_seen_referralids.split(".");
+	
+	// Add this referral id to recentlyseen referralids
+	seen_referralids.push(url_detail.referralid);
+	while (seen_referralids.length > 50)
+		seen_referralids.shift();
+	StumbleGlobals.ds.setValue("$recently_seen_referralids", seen_referralids.join("."));
+	
+	StumbleGlobals.ds.flushPrefs();
+
+	// Add the visited URL details to the visited table
+	StumbleGlobals.stumbleReporter.addVisitedUrl(url_detail);
+}
+
+StumbleGlobals.get_async_target_browser = function(target_browser, new_tab)
+{
+	var detail = new Object();
+	
+	var browser = getBrowser();
+	
+	if (new_tab)
+	{
+		var characterSet = browser.contentDocument.characterSet;
+		try {
+			var tab = browser.addTab(
+						"about:blank",
+						StumbleGlobals.stumbled_url,
+						null,
+						characterSet);
+			detail.target_browser = browser.getBrowserForTab(tab);
+			browser.selectedTab = tab;
+		} catch (e) { StumbleGlobals.log_error("ADDTAB ERROR", e, StumbleGlobals.stumbled_url); }
+	}
+	else
+	{
+		var found = false;
+		for (var i = 0; i < browser.browsers.length; i++)
+		{                                                         
+			if (browser.browsers[i] == target_browser)
+			{
+				detail.target_browser = target_browser;
+				found = true;
+				break;
+			}
+		}
+		
+		if (! found)
+		{
+			// Cancel the stumble if, by the time we get here, 
+			// they've closed the tab. -- JW
+			detail = null;
+		}
+	}
+	return detail;
+}
+
+StumbleGlobals.decriment_undelivered_count = function()
+{
+	// decriment referral count
+	var count = StumbleGlobals.ds.getValue("$undelivered_count");
+	count--;
+	StumbleGlobals.ds.setValue("$undelivered_count", count);
+	
+	StumbleGlobals.update_referred(true);
+
+	setTimeout(StumbleGlobals.test, 1000);
+}
+
+StumbleGlobals.test = function()
+{
+}
+
+StumbleGlobals.stumble_done_no_stumbles = function(context)
+{
+	var user_cat = context.user_cat + "";
+
+	var detail = StumbleGlobals.get_async_target_browser(
+				context.target_browser,
+				context.new_tab);
+	
+	if (! detail)
+		return;
+	
+	var target_browser = detail.target_browser;
+	
+	var target_url;
+	// We couldn't find an unseen url...
+	// Check to make sure this isn't an incat stumble
+	if (!context.stumble_referral && (user_cat == "0"))
+	{
+		// If we got here, we're out of urls, and we're in "Any Topic"
+		//!!! first make sure we are not already here....
+		target_url = StumbleGlobals.base_url + "interests.php?out=1"; 
+		
+		target_browser.webNavigation.loadURI(
+					target_url,
+					0,
+					null,
+					StumbleGlobals.get_mime_input_stream(
+						StumbleGlobals.get_client_postdata(target_url),
+						"application/x-www-form-urlencoded"),
+					null);
+
+		// change icon...
+		StumbleGlobals.get_element("stumbleglobals_stumble").image = "chrome://stumbleupon/content/skin/stumble.png";
+
+		return;
+		//!!! eventually we should cycle through "great history" here
+	}
+	
+	var tag = "";
+	var mode = "";
+	var profile = "";
+	if (context.stumble_referral)
+	{
+		mode = "referral";
+
+		// Close any previous message
+		if(context.target_browser &&
+			context.target_browser.stumbleglobals_url_detail &&
+			context.target_browser.stumbleglobals_url_detail.messageid)
+		{
+			setTimeout(
+					StumbleGlobals.close_message,
+					0,
+					context.target_browser.stumbleglobals_url_detail.messageid,
+					true);
+		}
+	}
+	else if (StumbleGlobals.isInt(user_cat))
+	{
+		// mode = incat
+		mode = "incat";
+		StumbleGlobals.load_categories();
+		if (typeof(StumbleGlobals.catnames[user_cat]) != "undefined")
+			tag = StumbleGlobals.catnames[user_cat];
+		else
+			tag = "";
+	}
+	else if (user_cat.indexOf("LANG_") == 0)
+	{
+		mode = "language";
+		tag = StumbleGlobals.ds.lookup("lang_code:language", user_cat.substr(5));
+	} 
+	else if (user_cat.indexOf("TAG_") == 0)
+	{
+		mode = "tag";
+		tag = user_cat.substr(4);
+	}
+	else if (user_cat.indexOf("USERTAG_") == 0)
+	{
+		mode = "showfriendtag";
+		var chunk = user_cat.substr(8);
+		chunks = chunk.split('_');
+		var tag = chunks[1];
+		var profile = chunks[0];
+//				alert("tag " + tag + " profile " + profile);
+	}
+	else
+	{
+		if (user_cat == "news")
+		{
+			mode = "news";	
+			tag = "news";
+		}
+		else if (user_cat == "video")
+		{
+			mode = "video";	
+			tag = "video";
+		}
+		else if (user_cat == "friends")
+		{
+			mode = "friends";	
+			tag = "friends";
+		}
+		else if (user_cat == "wiki")
+		{
+			mode = "wiki";
+			tag = "wiki";
+		}
+		else
+		{
+			mode = "showfriend";	
+			profile = user_cat;
+		}
+	}	
+	
+	target_url = StumbleGlobals.base_url + "explore.php?mode=" + mode;
+	if (tag != "")
+		target_url += "&tag=" + tag.toLowerCase();
+	if (profile != "")
+		target_url += "&showfriend=" + profile.toLowerCase();
+	if (mode == "incat")
+		target_url += "&topic=" + user_cat;
+		
+	// User is doing an incat stumble
+	// Set user_cat to 0
+	if(!context.stumble_referral)
+		StumbleGlobals.set_mode_all();
+
+	// Give them a message explaining they have run out in their particular cat.
+	target_browser.webNavigation.loadURI(
+				target_url,
+				0,
+				null,
+				StumbleGlobals.get_mime_input_stream(
+					StumbleGlobals.get_client_postdata(target_url),
+					"application/x-www-form-urlencoded"),
+				null);
+
+	// change icon...
+	StumbleGlobals.get_element("stumbleglobals_stumble").image = "chrome://stumbleupon/content/skin/stumble.png";
+}
+
+// used by a timeout to ensure that the stumble button icon returns
+// to vertical within 15 seconds
+StumbleGlobals.reset_stumble_action_indicator = function(stumble_action_id)
+{
+	if (stumble_action_id == StumbleGlobals.stumble_action_count)
+		StumbleGlobals.get_element("stumbleglobals_stumble").image="chrome://stumbleupon/content/skin/stumble.png";
+}
+
+// used load_data2
+StumbleGlobals.check_referral = function(force_update)
+{
+	if (StumbleGlobals.stumbleid == 0)
+		return;
+	
+	var check_now = force_update;
+
+	if (StumbleGlobals.check_referral_timer)
+	{
+		// if the user changes, this clears the timeout set for the
+		// previously logged in user
+		clearTimeout(StumbleGlobals.check_referral_timer);
+	}
+	
+	var state = StumbleGlobals.ds.getValue("$poll_state");
+	var interval = StumbleGlobals.ds.lookup("state:poll_interval_s", state);
+
+	var poll_time_s = StumbleGlobals.ds.getIntValue("$poll_time_s");
+	var now_s = StumbleGlobals.get_time_s();
+	var elapsed = now_s - poll_time_s;
+	if (elapsed >= interval)
+		check_now = true;
+
+	if (check_now)
+	{
+		elapsed = 0;
+		// advance state
+		var new_state = null;
+		switch (state)
+		{
+			case "b": new_state = "c"; break;
+			case "c": new_state = "d"; break;
+			case "d": new_state = "e"; break;
+			case "e": new_state = "f"; break;
+			case "a":
+			case "f":
+			case "g":
+				var activity_time_s = StumbleGlobals.ds.getIntValue("$activity_time_s");
+				if (activity_time_s == 0)
+					activity_time_s = now_s;
+				
+				var idle_interval = now_s - activity_time_s;
+				if (idle_interval > (3600 * 24 * 60))
+					new_state = "h";
+				else if (idle_interval > (3600 * 24 * 10))
+					new_state = "g";
+				break;
+		}
+		
+		if (new_state)
+		{
+			StumbleGlobals.ds.setValue("$poll_state", new_state);
+			interval = StumbleGlobals.ds.lookup("state:poll_interval_s", new_state);
+		}
+
+		StumbleGlobals.ds.setValue("$poll_time_s", now_s);
+		
+		var context = new StumbleGlobals.AsyncContext();
+		context.quiet = true;
+		context.user_cat = 0;
+		
+		StumbleGlobals.hit_recommend(
+					0,
+					true, // check_referral
+					StumbleGlobals.check_referral_done,
+					context);
+	}
+	
+	StumbleGlobals.check_referral_timer = setTimeout(StumbleGlobals.check_referral, ((interval - elapsed) * 1000), false);
+}
+
+StumbleGlobals.register_activity = function(type)
+{
+	if (StumbleGlobals.stumbleid == 0)
+		return;
+	
+	StumbleGlobals.ds.setValue("$activity_time_s", StumbleGlobals.get_time_s());
+	
+	var state = StumbleGlobals.ds.getValue("$poll_state");
+	var new_state = state;
+	switch (type)
+	{
+		case "referred":
+			if (state == "a" || state == "g" || state == "h")
+				new_state = "f";
+			break;
+		case "referral":
+			if (state == "a" || state == "d" || state == "e" || state == "g" || state == "h")
+				new_state = "b";
+			break;
+		case "stumble":
+		case "rate":
+		case "message-notify":
+			if (state == "g" || state == "h")
+				new_state = "a";
+			break;
+	}
+	
+	if (new_state != state)
+	{
+		StumbleGlobals.ds.setValue("$poll_state", new_state);
+		StumbleGlobals.check_referral(false);
+	}
+}
+
+StumbleGlobals.check_referral_done = function(error)
+{
+	if (error == "connection error")
+		setTimeout(StumbleGlobals.check_referral_retry, 10000);
+}
+
+StumbleGlobals.check_referral_retry = function()
+{
+	// Retry once.  This mostly caters to DSL users who have to wait
+	// for the modem to reconnect. -- JW
+	var context = new StumbleGlobals.AsyncContext();
+	context.quiet = true;
+	context.user_cat = 0;
+	
+	StumbleGlobals.hit_recommend(
+				0,
+				true, // check_referral
+				null,
+				context);
+}
+
+StumbleGlobals.show_searchlinks_dialog = function(new_user_prompt, new_tab, stumble)
+{
+	var intro_count = StumbleGlobals.ds.getValue("$intro_count");
+	if ((intro_count == 0) || ((intro_count % 15) != 0)) return false;
+	if (StumbleGlobals.ds.getValue("$shown_searchlinks_dialog")) return false;
+	StumbleGlobals.ds.setValue("$shown_searchlinks_dialog", true);
+	if (StumbleGlobals.ds.getValue("$show_searchlinks_score")) return false;
+	if (StumbleGlobals.ds.getValue("$show_searchlinks_friends")) return false;
+	if (StumbleGlobals.ds.getValue("$show_searchlinks_topic")) return false;
+	window.setTimeout(StumbleGlobals.show_searchlinks_dialog_wrapped, 100, new_user_prompt, new_tab, stumble);
+	return true;
+}
+
+StumbleGlobals.show_searchlinks_dialog_wrapped = function(new_user_mode, new_tab, stumble)
+{
+	var detail = new Object();
+	var filename;
+	var social = StumbleGlobals.ds.hasFeature("$sociallinks");
+	if (social && new_user_mode)
+		filename = "social_searchlinks_newuser_prompt.gif";
+	else if (social)
+		filename = "social_searchlinks_prompt.gif";
+	else if (new_user_mode)
+		filename = "searchlinks_newuser_prompt.gif";
+	else
+		filename = "searchlinks_prompt.gif";
+	
+	if (new_user_mode)
+		detail.preview_serp_url = "http://www.google.com/search?q=StumbleUpon";
+	else
+		detail.preview_serp_url = null;
+	detail.new_tab = new_tab;
+	detail.prompt_filename = filename;
+	detail.stumble = stumble;
+	
+	StumbleGlobals.ds.installResource(
+				"http://cdn.stumble-upon.com/images/" + filename,
+				"images",
+				filename);
+	
+	StumbleGlobals.searchlinks_dialog_detail = detail;
+}
+
+StumbleGlobals.handle_searchlinks_dialog_resource_load = function(detail)
+{
+	detail.prompt_src = StumbleGlobals.ds.getResourceURLFromName(
+				"images",
+				detail.prompt_filename);
+
+	window.openDialog(
+				"chrome://stumbleupon/content/searchlinksDialog.xul",
+				"",
+				"chrome,dialog,centerscreen,dependent,close=no",
+				detail);
+}
+
+StumbleGlobals.handle_searchlinks_dialog_close = function(detail)
+{
+	if (detail.result == "cancel-error")
+	{
+		detail.result = "";
+	
+		window.openDialog(
+					"chrome://stumbleupon/content/searchlinksDialog.xul",
+					"",
+					"chrome,dialog,centerscreen,dependent,close=no",
+					detail);
+	}
+	else if (detail.result == "yes")
+	{
+		StumbleGlobals.ds.setValue("$show_searchlinks_score", true);
+		StumbleGlobals.ds.setValue("$show_searchlinks_friends", true);
+		StumbleGlobals.ds.setValue("$shown_searchlinks", true);
+		StumbleGlobals.ds.flushPrefs();
+		
+		if (detail.preview_serp_url)
+		{
+			// The timeout and the StumbleGlobals.ds.flushPrefs() above work around an 
+			// intermittent timing issue where the link behavior isn't
+			// enabled in time for searchlinks to appear in the demo. -- JW
+			setTimeout(
+						StumbleGlobals.set_location,
+						150,
+						detail.preview_serp_url,
+						null, 
+						detail.new_tab);
+		}
+	}
+	else
+	{
+		StumbleGlobals.ds.setValue("$show_searchlinks_score", false);
+		StumbleGlobals.ds.setValue("$show_searchlinks_friends", false);
+		StumbleGlobals.ds.setValue("$show_searchlinks_topic", false);
+	}
+}
+
+StumbleGlobals.check_show_position_dialog = function()
+{
+	if(StumbleGlobals.ds.getValue("$shown_position_dialog")) return false;
+	StumbleGlobals.ds.setValue("$shown_position_dialog", true);
+	if(StumbleGlobals.ds.getValue("@toolbar-position") != StumbleGlobals.ds.getDefaultValue("@toolbar-position")) return false;
+	if(StumbleGlobals.ds.getValue("$stumble_count") < 5) return false;
+
+	var detail = new Object();
+	window.openDialog(
+				"chrome://stumbleupon/content/positionDialog.xul",
+				"",
+				"chrome,dialog,centerscreen,dependent,close=no",
+				detail);
+	return true;
+}
+
+StumbleGlobals.handle_position_dialog_close = function(detail)
+{
+	if (detail.result == "cancel-error")
+	{
+		detail.result = "";
+	
+		window.openDialog(
+					"chrome://stumbleupon/content/positionDialog.xul",
+					"",
+					"chrome,dialog,centerscreen,dependent,close=no",
+					detail);
+	}
+	else if (detail.result == "yes")
+	{
+		StumbleGlobals.move_to_bookmark_bar();
+	}
+}
+
+StumbleGlobals.handle_click_toomany_shares = function(button, block)
+{
+	var params = "";
+	params = StumbleGlobals.arp(params, "act", block ? 'remove_ds' : 'allow_ds');
+	params = StumbleGlobals.arp(params, "referral_id", button.url_detail.referralid);
+	
+	// Change the button to the opposite
+	if(block)
+	{
+		var label = button.text_box.firstChild;
+		label.textContent = "Allow shares from";
+		label = label.nextSibling;
+		label.textContent = "this user again?";
+		button.setAttribute("label", "Allow their shares");
+		button.setAttribute("oncommand", "StumbleGlobals.handle_click_toomany_shares(this, false)");
+	}
+	else
+	{
+		var label = button.text_box.firstChild;
+		label.textContent = "Too many shares";
+		label = label.nextSibling;
+		label.textContent = "from this user?";
+		button.setAttribute("label", "Stop their shares");
+		button.setAttribute("oncommand", "StumbleGlobals.handle_click_toomany_shares(this, true)");
+	}
+	button.setAttribute("disabled", "true");
+	
+	StumbleGlobals.post_url_server_async(
+		"ajax/user/subscribe",
+		params,
+		15000,
+		StumbleGlobals.newjson_request_done,
+		{
+			operation: "Block User",
+			enable_element: button
+		}
+	);
+}
+
+StumbleGlobals.stumble_done_display_message = function(url_detail, target_browser)
+{
+	//!!! test in FF 1.5, Seamonkey, Flock
+	var parent = target_browser.parentNode;
+	var elBefore = target_browser;
+	
+	// On FF 4, this is a stack, move to the parent
+	if(parent.tagName.indexOf("stack") != -1)
+	{
+		elBefore = parent;
+		parent = parent.parentNode;
+	}
+	
+	var messageid = StumbleGlobals.ds.incrementValue("~message_count");
+
+	target_browser.stumbleglobals_url_detail.messageid = messageid;
+	
+	// This stack prevents reflow of the banner content upon show/hide.
+	// We could reuse it, but there's no compelling reason to. -- JW
+	var stack = document.createElement("stack");
+	
+	var outerbox = document.createElement("vbox");
+	var outerbox_id = "stumbleglobals_messageOuterBox" + messageid;
+	outerbox.setAttribute("id", outerbox_id);
+	outerbox.style.position = "fixed";
+	outerbox.style.top = "100%";
+	if (StumbleGlobals.host.mac)
+		outerbox.setAttribute("class", "stumbleglobals_pinstripe_bannerBox outset");
+	else
+		outerbox.setAttribute("class", "stumbleglobals_winstripe_bannerBox outset");
+	
+	stack.appendChild(outerbox);
+	
+	var grid = document.createElement("grid");
+	grid.setAttribute("flex", "1");
+	outerbox.appendChild(grid);
+	var columns = document.createElement("columns");
+	grid.appendChild(columns);
+	var el;
+	el = document.createElement("column");
+	columns.appendChild(el);
+	el = document.createElement("column");
+	el.setAttribute("flex", "1");
+	columns.appendChild(el);
+	el = document.createElement("column");
+	columns.appendChild(el);
+	var rows = document.createElement("rows");
+	rows.setAttribute("flex", "1");
+	grid.appendChild(rows);
+	
+	var firstrow = document.createElement("row");
+	if (StumbleGlobals.host.mac)
+		firstrow.setAttribute("class", "stumbleglobals_pinstripe_bannerInnerBox");
+	rows.appendChild(firstrow);
+	
+	var hboxaa = document.createElement("hbox");
+	hboxaa.setAttribute("align", "center");
+	firstrow.appendChild(hboxaa);
+	
+	el = document.createElement("image");
+	el.setAttribute("src", StumbleGlobals.get_message_icon_src(url_detail));
+	el.setAttribute("class", "stumbleglobals_bannerImage");
+	if (! url_detail.is_system_referral)
+	{
+		el.setAttribute("style", "cursor: pointer;");
+		el.setAttribute("onclick", "StumbleGlobals.handle_message_sender_click(event, " + messageid + ")");
+	}
+	hboxaa.appendChild(el);
+	el = document.createElement("label");
+	el.setAttribute("value", url_detail.sender);
+	if (! url_detail.is_system_referral)
+	{
+		el.setAttribute("style", "color: rgb(0,0,238); text-decoration: underline; margin-right:0; cursor: pointer;");
+		el.setAttribute("onclick", "StumbleGlobals.handle_message_sender_click(event, " + messageid + ")");
+	}
+	hboxaa.appendChild(el);
+	el = document.createElement("label");
+	el.setAttribute("style", "margin-left: 0");
+	el.setAttribute("value", StumbleGlobals.get_message_label(url_detail));
+	hboxaa.appendChild(el);
+
+	var hboxab = document.createElement("hbox");
+	hboxab.setAttribute("flex", "1");
+	hboxab.setAttribute("align", "center");
+	firstrow.appendChild(hboxab);
+
+	// Ah, XUL trickery.  We want a textbox element because it is the only XUL element that users
+	// can highlight and select (complaints were legion when we removed it).
+	// You can make a textbox element multiline to make it wrap, but then it just truncates itself
+	// to the size of the parent and adds scrollbars without expanding the parent vertically.
+	// The visual effect we want is provided by a "description" element.  So...we create a
+	// deck that has both.  The visual element provides the spacing we want in the deck, and the
+	// textbox displays the actual UI.
+	messagedeck = document.createElement("deck");
+	messagedeck.setAttribute("flex", "1");
+	messagedeck.setAttribute("align", "center");
+	hboxab.appendChild(messagedeck);
+
+	el = document.createElement("textbox");
+	el.setAttribute("id", "stumbleglobals_bannerTextDisplay" + messageid);
+	el.setAttribute("flex", "1");
+	el.setAttribute("multiline", "true");
+	el.setAttribute("crop", "end");
+	el.setAttribute("readonly", "true");
+	// Align it vertically in the middle of the box
+	el.setAttribute("style", "width:0px;height:0px;margin:0px 0px; padding:0px;" +
+							"-moz-user-focus:normal;-moz-user-select:text;");
+	if (StumbleGlobals.host.mac)
+		el.setAttribute("class", "stumbleglobals_pinstripe_bannerMessage StumbleGlobals.referral_textbox StumbleGlobals.banner_text_display");
+	else
+		el.setAttribute("class", "stumbleglobals_winstripe_bannerMessage StumbleGlobals.referral_textbox StumbleGlobals.banner_text_display");
+	messagedeck.appendChild(el);
+
+	var description_style = StumbleGlobals.ds.getValue("@ref_description_style");
+	el = document.createElement("description");
+	el.textContent = url_detail.referral_note + "  ";
+	el.setAttribute("flex", "1");
+	el.setAttribute("style", description_style);
+	messagedeck.appendChild(el);
+
+	if (url_detail.is_friend_referral)
+	{
+		el = document.createElement("button");
+		el.setAttribute("id", "stumbleglobals_bannerReplyButton" + messageid);
+		el.setAttribute("label", "Reply Now");
+		el.setAttribute("accesskey", "R");
+		el.setAttribute("oncommand", "StumbleGlobals.handle_message_reply_command(" + messageid + ")");
+		hboxab.appendChild(el);
+	}
+	el = document.createElement("spacer");
+	el.setAttribute("flex", "1000");
+	hboxab.appendChild(el);
+	
+	// Too many shares text.  
+	// Put it in a wrapper vbox to control with width and force it to two lines.
+	// We use two different labels because unfortunately when the label control itself wraps
+	// it keeps all of the left-over space to the right even if no characters are in it.  So we create
+	// to short horizontal lines so we get the minimum width necessary for the vbox.
+	var text_box = document.createElement("vbox");
+	text_box.setAttribute("align", "left");
+	text_box.setAttribute("style", "margin-left:12px");
+	hboxab.appendChild(text_box);
+	var label = document.createElement("label");
+	label.textContent = "Too many shares"; 
+	text_box.appendChild(label);
+	label = document.createElement("label");
+	label.textContent = "from this user?";
+	text_box.appendChild(label);
+	
+	// Stop their shares button
+	el = document.createElement("button");
+	el.setAttribute("id", "stumbleglobals_bannerStopSharesButton" + messageid);
+	el.setAttribute("label", "Stop their shares");
+	el.url_detail = url_detail;
+	el.text_box = text_box;
+	el.setAttribute("oncommand", "StumbleGlobals.handle_click_toomany_shares(this, true)");
+	hboxab.appendChild(el);
+
+	var elac = document.createElement("toolbarbutton");
+	if (StumbleGlobals.host.mac)
+		elac.setAttribute("class", "stumbleglobals_pinstripe_messageCloseButton");
+	else
+		elac.setAttribute("class", "stumbleglobals_winstripe_messageCloseButton");
+	elac.setAttribute("oncommand", "StumbleGlobals.handle_message_close_command(" + messageid + ")");
+	firstrow.appendChild(elac);
+	
+	var secondrow = document.createElement("row");
+	secondrow.setAttribute("id", "stumbleglobals_messageSendRow" + messageid); 
+	secondrow.setAttribute("hidden", "true");
+	rows.appendChild(secondrow);
+	
+	var hboxba = document.createElement("hbox");
+	hboxba.setAttribute("pack", "end");
+	hboxba.setAttribute("align", "center");
+	secondrow.appendChild(hboxba);
+	
+	el = document.createElement("label");
+	el.setAttribute("value", "Reply:");
+	hboxba.appendChild(el);
+	
+	var hboxbb = document.createElement("hbox");
+	hboxbb.setAttribute("flex", "1");
+	secondrow.appendChild(hboxbb);
+	
+	el = document.createElement("textbox");
+	el.setAttribute("flex", "1");
+	el.setAttribute("id", "stumbleglobals_messageTextbox" + messageid);
+	el.setAttribute("class", "stumbleglobals_messageTextbox");
+	el.setAttribute("maxlength", 5000);
+	el.setAttribute("onkeypress", "StumbleGlobals.handle_message_keypress(event, " + messageid + ")");
+	hboxbb.appendChild(el);
+	el = document.createElement("button");
+	el.setAttribute("label", "Send");
+	el.setAttribute("accesskey", "S");
+	el.setAttribute("oncommand", "StumbleGlobals.handle_message_send_command(" + messageid + ")");
+	hboxbb.appendChild(el);
+	el = document.createElement("button");
+	el.setAttribute("label", "Cancel");
+	el.setAttribute("accesskey", "C");
+	el.setAttribute("oncommand", "StumbleGlobals.handle_message_cancel_command(" + messageid + ")");
+	hboxbb.appendChild(el);
+	
+	parent.insertBefore(stack, elBefore);
+	
+	if (url_detail.referral_note)
+	{
+		var el = StumbleGlobals.get_element("stumbleglobals_bannerTextDisplay" + messageid);
+		el.setAttribute("value", url_detail.referral_note + " ");
+
+		StumbleGlobals.set_drawer_open(
+			outerbox_id,
+			true,
+			StumbleGlobals.init_message_textbox,
+			messageid);
+	}
+	else
+	{
+		StumbleGlobals.set_drawer_open(outerbox_id, true, null);
+	}
+}
+
+StumbleGlobals.init_message_textbox = function(messageid)
+{
+	// Firefox bug workaround:  For some reason I cannot get CSS to be selected for the two-level deep 
+	// anonymous textarea element.  We want to make sure that element does _not_ have scrollbars, so we
+	// set that style explicitly.
+	var el = StumbleGlobals.get_element("stumbleglobals_bannerTextDisplay" + messageid);
+	var child = null;
+	if(el)
+		child = document.getAnonymousElementByAttribute(el, "class", "textbox-textarea");
+	if(child)
+		child.style.overflow = "hidden";
+	
+	return;
+
+	// @todo:  If we live with the new message text format for any length of time, then just dump this complex logic, hopefully it was for some legacy
+	//         platform that no longer matters.
+/*
+	var target_browser = null;
+	var browsers = getBrowser().browsers;
+	for (i = 0; i < browsers.length; i++)
+	{
+		if (browsers[i].stumbleglobals_url_detail && browsers[i].stumbleglobals_url_detail.messageid &&
+					(browsers[i].stumbleglobals_url_detail.messageid == messageid))
+		{
+			target_browser = browsers[i];
+			break;
+		}
+	}
+	
+	var measurer = target_browser.ownerDocument.getElementById("stumbleglobals_bannerTextDisplay" + messageid);
+	var height = measurer.boxObject.height; 
+	var line_count = Math.round(height / 17);
+	if (line_count > 1)
+	{
+		target_browser.ownerDocument.getElementById("stumbleglobals_bannerLineTextbox" + messageid).hidden = true;
+		var textbox = target_browser.ownerDocument.getElementById("stumbleglobals_bannerMultilineTextbox" + messageid);
+		textbox.setAttribute("rows", line_count - 1);
+		textbox.setAttribute("height", (height + 5) + "px");
+		textbox.value = target_browser.stumbleglobals_url_detail.referral_note;
+		textbox.hidden = false;
+	}
+	else
+	{
+		var width = measurer.boxObject.width;
+		var textbox = target_browser.ownerDocument.getElementById("stumbleglobals_bannerLineTextbox" + messageid);
+		textbox.setAttribute("width", (width + 10) + "px");
+		textbox.value = target_browser.stumbleglobals_url_detail.referral_note;
+		textbox.hidden = false;
+	}
+*/
+}
+
+StumbleGlobals.get_message_icon_src = function(url_detail)
+{
+	var src;
+	if (url_detail.is_friend_referral)
+	{
+		var contact = StumbleGlobals.ds.selectRow("contact", "nickname", url_detail.sender);
+		if (! contact)
+			contact = StumbleGlobals.ds.selectRow("contact", "contactid", url_detail.sender);
+		
+		if (contact && contact.contactid)
+		{
+			var filename = contact.contactid + ".jpg";
+			
+			if (StumbleGlobals.ds.isResourceInstalled("iconpics", filename))
+				src = StumbleGlobals.ds.getResourceURLFromName("iconpics", filename);
+			else
+				src = "http://cdn.stumble-upon.com/iconpics/" + filename;
+			
+			StumbleGlobals.ds.refreshAvatar(contact.contactid);
+		}
+		else
+		{
+			src = "chrome://stumbleupon/content/skin/arrow.png";
+		}
+	}
+	else if (url_detail.is_system_referral)
+	{
+		src = "chrome://stumbleupon/content/skin/arrow.png";
+	}
+	else
+	{
+		src = "chrome://stumbleupon/content/skin/bubble3.png";
+	}
+	return src;
+}	
+
+StumbleGlobals.get_message_label = function(url_detail)
+{
+	var label = "";
+	if (url_detail.is_friend_referral || url_detail.is_system_referral)
+	{
+		if (url_detail.referral_note)
+			label += " says:"; 
+		else
+			label += " sent you this page";
+	}
+	else if (url_detail.referral_note)
+	{
+		label += " reviewed saying:";
+	}
+	
+	return label;
+}
+
+StumbleGlobals.handle_message_sender_click = function(event, messageid)
+{
+	var url_detail = StumbleGlobals.get_message_url_detail(messageid);
+	var new_tab = true;
+	if (StumbleGlobals.ds.getValue("$sender_click_platform"))
+		new_tab = StumbleGlobals.new_tab(event);
+	StumbleGlobals.set_location(
+				"http://" + url_detail.sender + "." + StumbleGlobals.servername + "/",
+				null,
+				new_tab);
+}
+
+StumbleGlobals.handle_message_keypress = function(event, messageid)
+{
+	if (event.keyCode != KeyEvent.DOM_VK_RETURN)
+		return;
+	
+	StumbleGlobals.send_reply_message(messageid);
+}
+
+StumbleGlobals.handle_message_reply_command = function(messageid)
+{
+	StumbleGlobals.get_element("stumbleglobals_bannerReplyButton" + messageid).disabled = true;	
+	StumbleGlobals.get_element("stumbleglobals_messageSendRow" + messageid).hidden = false;
+	setTimeout(
+				function (messageid) {
+					StumbleGlobals.get_element("stumbleglobals_messageTextbox" + messageid).focus(); },
+				0,
+				messageid);
+}
+
+StumbleGlobals.get_message_browser = function(messageid)
+{
+	var el = StumbleGlobals.get_element("stumbleglobals_messageOuterBox" + messageid).parentNode.nextSibling;
+	
+	// On FF 4, the browser is a child of a stack
+	if(el.tagName.indexOf("stack") != -1)
+		el = el.firstChild;
+	
+	return el;
+}
+
+StumbleGlobals.get_message_url_detail = function(messageid)
+{
+	return StumbleGlobals.get_message_browser(messageid).stumbleglobals_url_detail;
+}
+
+StumbleGlobals.handle_message_cancel_command = function(messageid)
+{
+	StumbleGlobals.get_element("stumbleglobals_bannerReplyButton" + messageid).disabled = false;	
+	StumbleGlobals.get_element("stumbleglobals_messageSendRow" + messageid).hidden = true;
+}
+
+StumbleGlobals.handle_message_send_command = function(messageid)
+{
+	StumbleGlobals.send_reply_message(messageid);
+}
+
+StumbleGlobals.send_reply_message = function(messageid)
+{
+	var url_detail = StumbleGlobals.get_message_url_detail(messageid);
+	var note = StumbleGlobals.get_element("stumbleglobals_messageTextbox" + messageid).value;
+	note = StumbleGlobals.trim(note);
+	if (note == "")
+	{
+		alert("The reply is blank.");
+		return;
+	}
+	
+	var url = StumbleGlobals.get_browser_url();
+	
+	var params = "";
+	
+	params = StumbleGlobals.arp(params, "url", url);
+	params = StumbleGlobals.arp(params, "friend", url_detail.sender);
+	params = StumbleGlobals.arp(params, "note", note);
+	params = StumbleGlobals.arp(params, "referer", StumbleGlobals.get_browser_referrer_url())
+	
+	var cmp_url = StumbleGlobals.get_browser_url(null, true);
+	if ((cmp_url.indexOf("http://video." + StumbleGlobals.servername + "/#p") == 0) ||
+			(cmp_url.indexOf("http://video." + StumbleGlobals.servername + "/?p") == 0))
+		params = StumbleGlobals.arp(params, "videoperma", 1);
+	
+	StumbleGlobals.post_url_server_async(
+			"referral.php",
+			params,
+			15000,
+			StumbleGlobals.generic_done);
+	
+	var contact = StumbleGlobals.ds.selectRow("contact", "nickname", url_detail.sender);
+	if (contact && contact.contactid)
+		StumbleGlobals.ds.refreshAvatar(contact.contactid);
+	
+	StumbleGlobals.close_message(messageid, true);
+
+	StumbleGlobals.increment_sendto("friend", url_detail.sender);
+	StumbleGlobals.register_activity("referral");
+	
+	var contact = StumbleGlobals.ds.selectRow("contact", "nickname", url_detail.sender);
+	if (contact && contact.contactid)
+		StumbleGlobals.ds.refreshAvatar(contact.contactid);
+	StumbleGlobals.refresh_referral_menu(5);
+}
+
+StumbleGlobals.handle_message_close_command = function(messageid)
+{
+	StumbleGlobals.close_message(messageid, true);
+}
+
+StumbleGlobals.close_message = function(messageid, animate)
+{
+	var id = "stumbleglobals_messageOuterBox" + messageid;
+	var el = StumbleGlobals.get_element(id);
+	if (! el)
+		return;
+	
+	if (animate)
+	{
+		StumbleGlobals.set_drawer_open(
+					id,
+					false,
+					function () { el.parentNode.removeChild(el); });
+	}
+	else
+	{
+		el.parentNode.removeChild(el);
+	}
+}
+
+// called upon logout
+StumbleGlobals.close_all_messages = function()
+{
+	var browsers = getBrowser().browsers;
+	var i;
+	var url_detail;
+	for (i = 0; i < browsers.length; i++)
+	{
+		var browser = browsers[i];
+		
+		if (! browser.stumbleglobals_url_detail)
+			continue;
+		
+		url_detail = browser.stumbleglobals_url_detail;
+		
+		delete browser.stumbleglobals_url_detail;
+		
+		if (! url_detail.messageid)
+			continue;
+		
+		var id = "stumbleglobals_messageOuterBox" + url_detail.messageid;
+		var el = StumbleGlobals.get_element(id);
+		if (el)
+			el.parentNode.removeChild(el);
+	}
+}
+
+// [kudos:] This xul-specific sliding code is derived from the
+// _showNotification method of the Firefox notificationbox widget in
+// source file mozilla/toolkit/content/widgets/notification.xml.
+StumbleGlobals.set_drawer_open = function(id, state, callback, messageid)
+{
+	var el = StumbleGlobals.get_element(id);
+	var height = el.boxObject.height;
+	var steps = 4;
+	var delta = height / steps;
+	var opacity_delta = 1 / steps;
+	
+	if (state)
+	{
+		el.style.removeProperty("position");
+		el.style.removeProperty("top");
+		el.style.marginTop = -height + "px";
+		el.style.opacity = 0;
+	}
+	else
+	{
+		delta = -delta;
+		opacity_delta = -opacity_delta;
+	}
+	
+	var slide = function (callback, messageid)
+	{
+		var done = false;
+		var style = window.getComputedStyle(el, null);
+		var margin = style.getPropertyCSSValue("margin-top").
+					getFloatValue(CSSPrimitiveValue.CSS_PX);
+
+		if (delta > 0 && margin + delta >= 0)
+		{
+			el.style.marginTop = "0px";
+			el.style.opacity = 1;
+			done = true;
+		}
+		else if (delta < 0 && margin + delta <= -height)
+		{
+			el.style.marginTop = -height + "px";
+			done = true;
+		}
+		else
+		{
+			el.style.marginTop = (margin + delta).toFixed(4) + "px";
+			el.style.opacity = Number(el.style.opacity) + opacity_delta;
+		}
+
+		if (done)
+		{
+			clearInterval(StumbleGlobals.drawer_timers[id]);
+			delete StumbleGlobals.drawer_timers[id];
+			if (callback)
+				setTimeout(callback, 100, messageid);
+		}
+	}
+	
+	StumbleGlobals.drawer_timers[id] = setInterval(slide, 50, callback, messageid);
+}
+
+StumbleGlobals.display_info = function(info_type, optDomain)
+{
+	if (! StumbleGlobals.host.ff3plus)
+		return;
+	
+	if (! StumbleGlobals.ds.getValue("$show_tutorial_info"))
+		return;
+
+	if ((! StumbleGlobals.ds.hasFeature("$info_tutorial")) && (! StumbleGlobals.test_info))
+		return;
+	
+	// display info only if the toolbar is in default position
+	if (StumbleGlobals.ds.getValue("@toolbar-position") != "stumbleupon")
+		return;
+	
+	if (! StumbleGlobals.ds.getValue("@toolbar-visible"))
+		return;
+	
+	// close the info if we change thru domain
+	if (StumbleGlobals.info_spec && optDomain && StumbleGlobals.info_spec.domain && (StumbleGlobals.info_spec.domain != optDomain))
+	{
+		StumbleGlobals.close_info();
+		return;
+	}
+	
+	// Show only one info bubble per day.
+	var now_s = StumbleGlobals.get_time_s();
+	var min_interval = 4 * 3600; // 4 hours
+	var time_s = StumbleGlobals.ds.getIntValue("$info_time_s"); 
+
+	var spec = new Object();
+	
+	spec.closed = false;
+	spec.type = info_type;
+	spec.shown_interval_s = 0;
+	spec.shown_time_s = null;
+	
+	switch (info_type)
+	{
+		case "rate":			
+			if ((time_s && ((now_s - time_s) < min_interval)) && (! StumbleGlobals.test_info))
+				return;
+			spec.bubble_offset = (StumbleGlobals.host.win) ? 0 : 2;
+			spec.leader_offset = (StumbleGlobals.host.win) ? -2 : 0;
+			spec.target_id = "stumbleglobals_thumbup";
+			spec.shown_pref = "$shown_rate_info";
+			spec.message = "Friendly reminder:  If you rate pages as you go, the toolbar learns what you like and delivers more.";
+			break;
+		case "reviews":
+			if ((time_s && ((now_s - time_s) < min_interval)) && (! StumbleGlobals.test_info))
+				return;
+			spec.bubble_offset = 7;
+			spec.leader_offset = 5;
+			spec.target_id = "stumbleglobals_website_info";
+			spec.shown_pref = "$shown_reviews_info";
+			spec.message = "Tip: The Reviews button lets you see what other Stumblers think of this site.";
+			break;
+		case "referral":
+			if ((time_s && ((now_s - time_s) < min_interval)) && (! StumbleGlobals.test_info))
+				return;
+			spec.bubble_offset = (StumbleGlobals.host.win) ? 0 : 2;
+			spec.leader_offset = (StumbleGlobals.host.win) ? -2 : 0;
+			spec.target_id = "stumbleglobals_referral_menu";
+			spec.shown_pref = "$shown_referral_info";
+			spec.message = "Tidbit: You can share a good website with friends or any email address.";
+			break;
+		case "thru_domain":
+			if ((time_s && ((now_s - time_s) < min_interval)) && (! StumbleGlobals.test_info))
+				return;
+			spec.bubble_offset = (StumbleGlobals.host.win) ? 5 : 7;
+			spec.leader_offset = (StumbleGlobals.host.win) ? 3 : 5;
+			spec.domain = optDomain;
+			spec.target_id = "stumbleglobals_mode_domain";
+			spec.shown_pref = null;
+			if (StumbleGlobals.ds.getValue("$shown_thru_domain_info_count"))
+				spec.message = StumbleGlobals.ds.lookup("domain:info_message", optDomain);
+			else
+				spec.message = StumbleGlobals.ds.lookup("domain:info_message_simple", optDomain);
+			if (! spec.message)
+				spec.message = "Click here to Stumble thru " + StumbleGlobals.ds.getThruDomainChannel(optDomain).name + ".";
+			break;
+		case "photo":
+			if ((time_s && ((now_s - time_s) < min_interval)) && (! StumbleGlobals.test_info))
+				return;
+			spec.bubble_offset = (StumbleGlobals.host.win) ? 5 : 7;
+			spec.leader_offset = (StumbleGlobals.host.win) ? 3 : 5;
+			spec.target_id = "stumbleglobals_mode_photo";
+			spec.shown_pref = "$shown_photo_info";
+			spec.message = "Tip: You can discover more of the web's best images in the Photos channel.";
+			break;
+		case "video":
+			
+			break;
+		case "photo_praise":
+			spec.bubble_offset = (StumbleGlobals.host.win) ? 5 : 7;
+			spec.leader_offset = (StumbleGlobals.host.win) ? 3 : 5;
+			spec.target_id = "stumbleglobals_mode_all";
+			spec.shown_pref = "$shown_toall_info";
+			spec.message = "Enjoy the photos!  The globe button changes back to the 'All' channel.";
+			StumbleGlobals.close_info();
+			setTimeout(StumbleGlobals.refresh_info, 3000);
+			break;
+		case "thru_domain_praise_toall":
+			spec.bubble_offset = (StumbleGlobals.host.win) ? 5 : 7;
+			spec.leader_offset = (StumbleGlobals.host.win) ? 3 : 5;
+			spec.target_id = "stumbleglobals_mode_all";
+			spec.shown_pref = "$shown_toall_info";
+			spec.message = "Have fun with " + StumbleGlobals.ds.getThruDomainChannel(optDomain).name + " pages!  The globe button changes back to the 'All' channel.";
+			StumbleGlobals.close_info();
+			setTimeout(StumbleGlobals.refresh_info, 3000);
+			break;
+		case "thru_domain_praise_tomore":
+			spec.bubble_offset = (StumbleGlobals.host.win) ? 0 : 2;
+			spec.leader_offset = (StumbleGlobals.host.win) ? -2 : 0;
+			spec.domain = optDomain;
+			spec.target_id = "stumbleglobals_mode_more";
+			spec.shown_pref = "$shown_tomore_info";
+			spec.message = null; // overridden
+			StumbleGlobals.close_info();
+			setTimeout(StumbleGlobals.refresh_info, 3000);
+			break;
+		default:
+			return;
+	}
+	
+	StumbleGlobals.info_spec = spec;
+	StumbleGlobals.ds.setValue("#recent_info_spec", spec);
+	
+	try {
+		StumbleGlobals.refresh_info();
+	} catch (e) { StumbleGlobals.log_error("REFRESH INFO", e); } 
+}
+
+StumbleGlobals.refresh_info = function()
+{
+	var toolbar = StumbleGlobals.get_element("stumbleglobals_info_toolbar");
+	if (! StumbleGlobals.info_spec)
+	{
+		toolbar.collapsed = true;
+		return;
+	}
+	
+	var spec = StumbleGlobals.info_spec;
+	var target_el = StumbleGlobals.get_element(spec.target_id);
+	
+	if ((target_el.boxObject.width == 0) || spec.closed)
+	{
+		StumbleGlobals.hide_info();
+		return;
+	}
+	
+	
+	// record the 'shown info' event
+	
+	var i;
+	var found;
+	var first_thru_domain = false;
+	if (spec.shown_pref)
+	{
+		StumbleGlobals.ds.setValue(spec.shown_pref, true);
+	}
+	else if (spec.type == "thru_domain")
+	{
+		var domains = StumbleGlobals.ds.getValue("$shown_thru_domain_info_list").split(":");
+		if (domains.length)
+		{
+			found = false;
+			for (i = 0; i < domains.length; i++)
+			{
+				if (domains[i] == spec.domain)
+					found = true;
+			}
+			
+			if (! found)
+			{
+				var count = StumbleGlobals.ds.incrementValue("$shown_thru_domain_info_count");
+				if (count == 1)
+				{
+					StumbleGlobals.ds.setValue("$shown_thru_domain_info_list", spec.domain);
+				}
+				else
+				{
+					domains.push(spec.domain);
+					StumbleGlobals.ds.setValue("$shown_thru_domain_info_list", domains.join(":"));
+				}	
+			}
+		}	
+		else
+		{
+			StumbleGlobals.ds.incrementValue("$shown_thru_domain_info_count");
+			StumbleGlobals.ds.setValue("$shown_thru_domain_info_list", spec.domain);
+		}
+	}
+
+	var now_s = StumbleGlobals.get_time_s();
+	
+	StumbleGlobals.ds.setValue("$info_time_s", now_s);
+	
+	StumbleGlobals.ds.flushPrefs();
+	
+	spec.shown_time_s = now_s;
+	
+	// If an old container exists, fix the toolbar height to avoid
+	// collapse/reflow upon browser resize.  Then nuke the old
+	// container.  
+	
+	var container = StumbleGlobals.get_element("stumbleglobals_info_container");	
+
+	if (container)
+	{
+		toolbar.style.height = toolbar.boxObject.height + "px";
+		toolbar.removeChild(container);
+	}	
+	
+	
+	// construct the speech bubble
+	
+	var x = target_el.boxObject.screenX - toolbar.boxObject.screenX + Math.round(target_el.boxObject.width / 2);
+	
+	var el;
+	var vbox;
+	var hbox;
+	var text;
+	var style;
+	var vbox;
+	var content_el;
+	
+	container = document.createElement("hbox");
+	container.setAttribute("id", "stumbleglobals_info_container");
+	container.setAttribute("style", "position: absolute; height: 0; width: 0; margin-bottom: 2px;");
+	toolbar.appendChild(container);
+	
+	var bubble_outerbox = document.createElement("hbox");
+	style = "position: absolute; left: " + (x + spec.bubble_offset) + "px; top: 1px;";
+	bubble_outerbox.setAttribute("style", style);
+	container.appendChild(bubble_outerbox);
+	
+	var bubble_midbox = document.createElement("hbox");
+	bubble_outerbox.appendChild(bubble_midbox);
+	
+	var bubble = document.createElement("hbox");
+	style = "border-color: rgb(247,182,0); border-style: solid; border-width: 3px; font-weight: normal; font-size: 12pt; color: black; background-color: rgb(255,255,189); -moz-border-radius-topright: 15px; -moz-border-radius-bottomright: 15px; -moz-border-radius-bottomleft: 15px; -moz-border-radius-topleft: 15px; padding-top: 2px; padding-bottom: 2px; padding-left: 15px; padding-right: 12px;";
+	bubble.setAttribute("id", "stumbleglobals_info_bubble");
+	bubble.setAttribute("style", style);
+	if (StumbleGlobals.host.mac)
+		bubble.setAttribute("class", "stumbleglobals_pinstripe_infoMessage");
+	else
+		bubble.setAttribute("class", "stumbleglobals_winstripe_infoMessage");
+	bubble_midbox.appendChild(bubble);
+	
+	vbox = document.createElement("vbox");
+	bubble_midbox.appendChild(vbox);
+	
+	el = document.createElement("spacer");
+	el.setAttribute("flex", "1");
+	vbox.appendChild(el);
+	
+	var optout = document.createElement("checkbox");
+	optout.setAttribute("label", "Show tips");
+	optout.setAttribute("checked", StumbleGlobals.ds.getValue("$show_tutorial_info"));
+	optout.setAttribute("style", "margin-left: 15px;");
+	optout.setAttribute("hidden", "true");
+	optout.setAttribute("oncommand", "StumbleGlobals.handle_info_optout_command(this)");
+	vbox.appendChild(optout);
+	
+	var bubble_hbox = document.createElement("hbox");
+	bubble.appendChild(bubble_hbox);
+
+	// construct bubble content
+	switch (spec.type)
+	{
+		case "thru_domain_praise_tomore":
+			vbox = document.createElement("vbox");
+			vbox.setAttribute("pack", "top");
+			bubble_hbox.appendChild(vbox);
+			content_el = document.createElement("label");
+			if (StumbleGlobals.host.win)
+				content_el.setAttribute("style", "margin-right: 20px; font-size: 17px;");
+			else
+				content_el.setAttribute("style", "margin-right: 20px; font-size: 15px;");
+			vbox.appendChild(content_el);
+			var seq = StumbleGlobals.ds.lookup("domain:tomore_favicon_list", spec.domain);
+			if (seq)
+			{
+				text = document.createTextNode("Have fun with " + StumbleGlobals.ds.getThruDomainChannel(spec.domain).name + " pages! You can StumbleThru this and other websites ");
+				content_el.appendChild(text);
+				var domains = seq.split(",");
+				for (i = 0; i < domains.length; i++)
+				{
+					hbox = document.createElement("hbox");
+					hbox.setAttribute("style", "padding-right:4px;");
+					content_el.appendChild(hbox);
+					if (i == 0)
+					{
+						text = document.createTextNode("(");
+						hbox.appendChild(text);
+					}
+					vbox = document.createElement("vbox");
+					if (i == 0)
+						vbox.setAttribute("style", "padding-top:2px; padding-left:2px;");
+					else
+						vbox.setAttribute("style", "padding-top:2px;");
+					hbox.appendChild(vbox);
+					el = document.createElement("image");
+					el.setAttribute("width", "16");
+					el.setAttribute("height", "16");
+					el.setAttribute("src", StumbleGlobals.get_favicon_url(domains[i]));
+					el.setAttribute("tooltiptext", StumbleGlobals.ds.getThruDomainChannel(domains[i]).name);
+					vbox.appendChild(el);
+					text = document.createTextNode(",");
+					hbox.appendChild(text);
+				}
+				text = document.createTextNode("etc.) anytime.");
+				content_el.appendChild(text);
+			}
+			else
+			{
+				text = document.createTextNode("You can StumbleThru " + StumbleGlobals.ds.getThruDomainChannel(spec.domain).name + " anytime.");
+				content_el.appendChild(text);
+			}
+			vbox = document.createElement("vbox");
+			vbox.setAttribute("pack", "top");
+			bubble_hbox.appendChild(vbox);
+			break;
+		default:
+			vbox = document.createElement("vbox");
+			vbox.setAttribute("pack", "top");
+			bubble_hbox.appendChild(vbox);
+			content_el = document.createElement("label");
+			if (StumbleGlobals.host.win)
+				content_el.setAttribute("style", "margin-right: 20px; margin-top: 2px; font-size: 17px;");
+			else
+				content_el.setAttribute("style", "margin-right: 20px; margin-top: 4px; font-size: 15px;");
+			vbox.appendChild(content_el);
+			text = document.createTextNode(spec.message);
+			content_el.appendChild(text);
+			vbox = document.createElement("vbox");
+			vbox.setAttribute("pack", "top");
+			bubble_hbox.appendChild(vbox);
+			break;
+	}
+	
+	el = document.createElement("toolbarbutton");
+	if (StumbleGlobals.host.mac)
+		el.setAttribute("class", "stumbleglobals_pinstripe_messageCloseButton");
+	else
+		el.setAttribute("class", "stumbleglobals_winstripe_messageCloseButton");
+	el.setAttribute("style", "margin-top: 4px;");
+	el.setAttribute("oncommand", "StumbleGlobals.handle_close_info_command()");
+	bubble_hbox.appendChild(el);
+	
+	// If the bubble overflows with window.innerWidth, narrow the label.
+	var toolbox = StumbleGlobals.get_element("navigator-toolbox");
+	var right_edge = (bubble_outerbox.boxObject.screenX - toolbox.boxObject.screenX) + bubble_outerbox.boxObject.width;
+	var width = content_el.boxObject.width;
+	bubble_outerbox.hidden = true;
+	var right_margin_width = window.innerWidth - right_edge;
+	if (right_margin_width < 0)
+		content_el.style.width = (width + right_margin_width) + "px";
+	else if (right_margin_width > 110)
+		optout.hidden = false;
+	bubble_outerbox.hidden = false;
+	
+	// Add the arrow leader.
+	el = StumbleGlobals.create_html_element("img");
+	if (StumbleGlobals.host.win)
+		style = "position: absolute; left: " + (x - Math.round(25 / 2) + spec.leader_offset) + "px; top: -5px; width: 18px; height: 34px";
+	else
+		style = "position: absolute; left: " + (x - Math.round(25 / 2) + spec.leader_offset) + "px; top: -10px; width: 18px; height: 34px";
+	el.setAttribute("style", style);
+	if (StumbleGlobals.host.win)
+		el.setAttribute("src", "chrome://stumbleupon/content/skin/arrow_green-c.png");
+	else
+		el.setAttribute("src", "chrome://stumbleupon/content/skin/arrow_green-b.png");
+	el.setAttribute("onclick", "StumbleGlobals.handle_info_leader_click()");
+	container.appendChild(el);
+	
+	if (right_margin_width <= 110)
+	{
+		// Add the optout2 box.
+		el = StumbleGlobals.create_html_element("div");
+		style = "position: absolute; left: " + (x - Math.round(25 / 2) + spec.leader_offset - 100) + "px; top: " + (bubble_outerbox.boxObject.height - 20) + "px;";
+		el.setAttribute("style", style)
+		container.appendChild(el);
+		
+		var optout2 = document.createElement("checkbox");
+		optout2.setAttribute("label", "Show tips");
+		optout2.setAttribute("checked", StumbleGlobals.ds.getValue("$show_tutorial_info"));
+		optout2.setAttribute("oncommand", "StumbleGlobals.handle_info_optout_command(this)");
+		el.appendChild(optout2);
+	}
+	
+	toolbar.style.height = "auto";
+	toolbar.collapsed = false;
+}
+
+StumbleGlobals.handle_info_leader_click = function()
+{
+	StumbleGlobals.dispatch_click(document, StumbleGlobals.info_spec.target_id);
+}
+
+StumbleGlobals.create_html_element = function(lowercase_tag_name)
+{
+	return document.createElementNS("http://www.w3.org/1999/xhtml", "html:" + lowercase_tag_name);
+}
+
+StumbleGlobals.handle_close_info_command = function()
+{
+	StumbleGlobals.close_info();
+}
+
+StumbleGlobals.handle_info_optout_command = function(el)
+{
+	StumbleGlobals.ds.setValue("$show_tutorial_info", el.checked);
+}
+
+StumbleGlobals.hide_info = function()
+{
+	if (! StumbleGlobals.info_spec)
+		return;
+	
+	var spec = StumbleGlobals.info_spec;
+	if (spec.shown_time_s)
+	{
+		spec.shown_interval_s += StumbleGlobals.get_time_s() - spec.shown_time_s;
+		spec.shown_time_s = null;
+	}
+	if (spec.shown_interval_s >= 8)
+		StumbleGlobals.close_info();
+	else
+		toolbar.collapsed = true;
+	return;
+}
+
+StumbleGlobals.close_info = function()
+{
+	var el = StumbleGlobals.get_element("stumbleglobals_info_container");	
+	if (el)
+		el.parentNode.removeChild(el);
+	
+	if (StumbleGlobals.info_spec)
+		StumbleGlobals.info_spec.closed = true;
+	
+	StumbleGlobals.get_element("stumbleglobals_info_toolbar").collapsed = true;
+}
+
+StumbleGlobals.handle_send_dialog_accept = function(detail)
+{
+	// Register this as a referral activity
+	StumbleGlobals.register_activity("referral");
+
+	var params = "";
+	params = StumbleGlobals.arp(params, "action", "send");
+	params = StumbleGlobals.arp(params, "url", detail.url);
+	params = StumbleGlobals.arp(params, "src", "mozbar");
+
+	if(detail.message)
+		params = StumbleGlobals.arp(params, "msg", detail.message);
+	
+	if (detail.stumblevideo)
+		params = StumbleGlobals.arp(params, "videoperma", 1);
+
+	for(var i=0; i<detail.recipients.length; i++)
+	{
+		var to = detail.recipients[i];
+		
+		if(to.send_type == "referral")
+		{
+			params = StumbleGlobals.arp(params, "usernames[]", to.target);
+			StumbleGlobals.increment_sendto("friend", to.target);
+			contact = StumbleGlobals.ds.selectRow("contact", "nickname", to.target);
+			if (contact && contact.contactid)
+				StumbleGlobals.ds.refreshAvatar(contact.contactid);
+		}
+		else
+		{
+			params = StumbleGlobals.arp(params, "emails[]", to.target);
+			StumbleGlobals.increment_sendto("email", to.target);
+		}
+	}
+	
+	StumbleGlobals.post_url_server_async(
+		"toolbar/shareservices.php",
+		params,
+		15000,
+		StumbleGlobals.newjson_request_done,
+		{ operation: "Share" });
+
+	StumbleGlobals.refresh_referral_menu(6);
+}
+
+// Handler for menitem "Suggest New Interests"
+StumbleGlobals.suggest = function()
+{
+	getBrowser().contentDocument.location = StumbleGlobals.serverhttp + "suggest_interests.php";
+}
+
+// Handler for menuitem "Update Interests"
+StumbleGlobals.interests = function()
+{
+	if (StumbleGlobals.stumbleid == 0)
+		return;
+	
+	// Redirect to interests page
+	var loc = StumbleGlobals.serverhttp + "interests.php";
+	
+	//!!! disabled because it screws up history
+	// if (StumbleGlobals.get_browser_url() != loc)
+	
+	getBrowser().contentDocument.location = loc;
+}
+
+// Handler for button "Toolbar Preferences"
+StumbleGlobals.preferences = function(opt_initial_tab)
+{
+	if (StumbleGlobals.stumbleid == 0)
+		return;
+	
+	var detail = new Object();
+	detail.initial_tab = (opt_initial_tab) ? opt_initial_tab : null;
+	
+	StumbleGlobals.unfocus_searchbox(); 
+	window.openDialog(
+				"chrome://stumbleupon/content/preferenceDialog.xul",
+				"stumbleglobals_preferences",
+				"chrome,dialog,centerscreen,dependent",
+				detail);
+}
+
+StumbleGlobals.handle_preference_dialog_accept = function()
+{
+	var toolbar_position = StumbleGlobals.ds.getValue("@toolbar-position");
+	var toolbar = StumbleGlobals.get_element(toolbar_position);
+	if (! toolbar)
+	{
+		StumbleGlobals.log_error(
+					"MOVE FAILSAFE3",
+					new Object(),
+					toolbar_position,
+					StumbleGlobals.ds.getValue("@position-group"));
+		
+		setTimeout(alert, 50, 
+					"The specified toolbar movement cannot be completed.\n\n" +
+					"The default position will be used.\n\n");
+		
+		StumbleGlobals.ds.setValue("@toolbar-position", "stumbleupon");
+		StumbleGlobals.ds.setValue("@position-group", "first");
+	}
+	
+	try {
+		StumbleGlobals.move_toolbar(true, 6);
+	} catch (e) { StumbleGlobals.log_error("PREFERENCE MOVE", e, StumbleGlobals.ds.getValue("@toolbar-position"), StumbleGlobals.ds.getValue("@position-group")); } 
+	
+	try {
+		StumbleGlobals.refresh_toggle_button(true);
+	} catch (e) { StumbleGlobals.log_error("PREFERENCE TOGGLE", e); } 
+
+	var detail = new Object();
+	detail.from_preference_dialog = true;
+	StumbleGlobals.invoke_global_event("configure-toolbar", detail);
+	StumbleGlobals.preference_dialog = null;
+
+	StumbleGlobals.update_referred(false);
+	setTimeout(StumbleGlobals.verify_toolbar_move, 0, 6);
+}
+
+// called during the global configure-toolbar event and during init
+// to set labels for top-level toolbar elements
+StumbleGlobals.init_labels = function()
+{
+	var ids;
+	if (StumbleGlobals.promo_mode && (StumbleGlobals.stumbleid == 0))
+	{
+		ids = new Array(
+			"stumbleglobals_thumbup",
+			"stumbleglobals_referral_promo",
+			"stumbleglobals_website_info_promo",
+			"stumbleglobals_sites_promo",
+			"stumbleglobals_video_promo",
+			"stumbleglobals_profile",
+			"stumbleglobals_friends",
+			"stumbleglobals_referral_menu");
+	}
+	else
+	{
+		ids = new Array(
+			"stumbleglobals_stumble",
+			"stumbleglobals_thumbup",
+			"stumbleglobals_recthumbup",
+			"stumbleglobals_profile",
+			"stumbleglobals_friends",
+			"stumbleglobals_page_feature_prompt",
+			"stumbleglobals_referral_menu",
+			"stumbleglobals_website_info",
+			"stumbleglobals_mode",
+			"stumbleglobals_sponsor",
+			"firstrater",
+			"stumbleglobals_stumble_menu");
+	}
+	
+	for (var i = 0; i < ids.length; i++)
+	{
+		if (ids[i] == "stumbleglobals_thumbup")
+		{
+			var element = StumbleGlobals.get_element("stumbleglobals_thumbup");
+			
+			if (element.label == element.getAttribute("showlabel2"))
+				StumbleGlobals.set_label("stumbleglobals_thumbup", element.getAttribute("showlabel2"));
+			else
+				StumbleGlobals.set_label("stumbleglobals_thumbup", null);
+		}
+		else if (ids[i] == "stumbleglobals_recthumbup")
+		{
+			if (StumbleGlobals.stumbleid)
+				StumbleGlobals.set_label("stumbleglobals_recthumbup", StumbleGlobals.ds.getValue("$dd_rec_label"));
+		}
+		else
+		{
+			StumbleGlobals.set_label(ids[i], null);
+		}
+	}
+}
+
+// Handler for button "Invite Friends"
+StumbleGlobals.invite = function(event)
+{
+	// Redirect to home
+	var loc = "find_friends.php";
+	var params = null;
+	if (StumbleGlobals.ds.getValue("@facebook_user"))
+	{
+		loc = StumbleGlobals.arp(loc, "pre", "facebook", true);
+		var client_count = StumbleGlobals.ds.getValue("@facebook_client_invite_count");
+		client_count++;
+		StumbleGlobals.ds.setValue("@facebook_client_invite_count", client_count);
+		params = StumbleGlobals.arp("", "fbclientcount", client_count);
+		params = StumbleGlobals.arp(params, "fbsessioncount",
+					StumbleGlobals.ds.incrementValue("#find_friends_facebook_count"));
+		
+		if (StumbleGlobals.stumbleid != 0)
+		{
+			var count = StumbleGlobals.ds.getValue("$facebook_invite_count");
+			count++;
+			StumbleGlobals.ds.setValue("$facebook_invite_count", count);
+			params = StumbleGlobals.arp(params, "fbcount", count);
+		}
+	}
+	
+	if (StumbleGlobals.stumbleid != 0)
+		StumbleGlobals.ds.setValue("$shown_find_friends", true);
+	
+	if (StumbleGlobals.host.dist)
+		loc = StumbleGlobals.arp(loc, "dist", StumbleGlobals.host.dist, true);
+	
+	StumbleGlobals.set_server_location(
+				loc,
+				params,
+				StumbleGlobals.new_tab(event));
+}
+
+// Handler for button "Upgrade Now"
+StumbleGlobals.sponsor = function(extra)
+{
+	if (StumbleGlobals.stumbleid == 0)
+		return;
+
+	// Redirect to sponsor page
+	getBrowser().contentDocument.location = StumbleGlobals.serverhttp + "sponsors.php" + extra;
+}
+
+// handler for profile tab buttons
+StumbleGlobals.redir_tab = function(event, tab)
+{
+	try {
+	
+	if (StumbleGlobals.promo_mode && (StumbleGlobals.stumbleid == 0))
+	{
+		if (tab == "")
+			tab = "favorites";
+		StumbleGlobals.handle_promo_click(event, tab);
+		return true;
+	}
+	
+	if (StumbleGlobals.overflow_popup_open)
+	{
+		var popup = StumbleGlobals.get_element("stumbleglobals_overflow_popup");
+		if ((typeof popup.hidePopup) == "function")
+			popup.hidePopup();
+
+		StumbleGlobals.unfocus();
+	}
+	
+	if (StumbleGlobals.stumbleid == 0)
+		return true;
+
+	StumbleGlobals.set_profile_location(tab, StumbleGlobals.new_tab(event));
+	
+	} catch (e) { StumbleGlobals.log_error("HANDLE TAB", e); }
+	
+	return true;
+}
+
+// Sends stumble stats to server (urls and dates you've stumbled upon)
+StumbleGlobals.upload_stumbles = function()
+{
+	if (StumbleGlobals.ds.getValue("$stumblestats") == "")
+	{
+		return;
+	}
+	
+	var context = new StumbleGlobals.AsyncContext();
+	context.oldStumbleReport = true;
+	context.quiet = true;
+	
+	var params = "";
+	params = StumbleGlobals.arp(params, "urlids", StumbleGlobals.ds.getValue("$stumblestats")); 
+	params = StumbleGlobals.arp(params, "timestamps", StumbleGlobals.ds.getValue("$stumbletimes")); 
+	params = StumbleGlobals.arp(params, "types", StumbleGlobals.ds.getValue("$stumbletypes")); 
+	params = StumbleGlobals.arp(params, "referralids", StumbleGlobals.ds.getValue("$stumblereferrals"));
+	params = StumbleGlobals.arp(params, "clienttime", StumbleGlobals.get_time_s());
+	params = StumbleGlobals.arp(params, "houroffset", Math.floor((new Date()).getTimezoneOffset() / 60));
+	StumbleGlobals.post_url_server_async(
+				"stumbles.php",
+				params,
+				15000,
+				StumbleGlobals.upload_stumbles_done,
+				context);
+}
+
+StumbleGlobals.upload_stumbles_done = function(res)
+{
+	var context = res.detail;
+
+	if (res.status != 200)
+		return;
+	
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+	
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response stumbles.php", s);
+	
+	StumbleGlobals.process_commands(s, context);
+}
+
+// Get rid of the stumble queue
+StumbleGlobals.clear_stumbles = function()
+{
+	StumbleGlobals.stumbles = new Array();
+//	StumbleGlobals.fu.remove(StumbleGlobals.prefDir + "stumbleurls");
+	StumbleGlobals.write_file_user("stumbleurls", "");
+	try {
+		StumbleGlobals.prefetcher.clearTargets();
+	} catch (e) { StumbleGlobals.log_error("PREFETCHER 5", e); }
+}
+
+StumbleGlobals.set_inbox_status = function(icon)
+{
+	var message_element = StumbleGlobals.get_element("stumbleglobals_messages");
+	var newimage = "chrome://stumbleupon/content/skin/mail" + icon + ".png";
+	StumbleGlobals.set_image("stumbleglobals_messages", newimage);
+	
+	// right now we don't save between sessions
+	if (icon == 2)
+	{
+		StumbleGlobals.ds.setValue("$newmessage", true);
+		if (StumbleGlobals.ds.getValue("$show_messages") || (!StumbleGlobals.new_user))
+			StumbleGlobals.set_visible("stumbleglobals_messages", true);
+	}
+	else
+	{
+		StumbleGlobals.set_visible("stumbleglobals_messages", StumbleGlobals.ds.getValue("$show_messages"));
+		StumbleGlobals.ds.setValue("$newmessage", false);
+	}
+	StumbleGlobals.ds.flushPrefs();
+}
+
+// called by sendto() and mailit() to increment the sendto count in 
+// sendto_stats
+StumbleGlobals.increment_sendto = function(key_type, key)
+{
+	var contact;
+	var field_name;
+	if (key_type == "friend")
+		field_name = "nickname";
+	else if (key_type == "email")
+		field_name = "email";
+	
+	contact = StumbleGlobals.ds.selectRow("contact", field_name, key);
+	var new_contact = false;
+	if (! contact)
+	{
+		new_contact = true;
+		contact = new Object()
+		contact[field_name] = key;
+	}
+
+	if (contact.referral_count)
+		contact.referral_count++;
+	else
+		contact.referral_count = 1;
+
+	contact.referral_timestamp = (new Date()).getTime();
+
+	if (new_contact)
+		StumbleGlobals.ds.insertRow("contact", contact);
+	else
+		StumbleGlobals.ds.updateRow(contact);
+
+	StumbleGlobals.ds.flushPrefs();
+}
+
+StumbleGlobals.share_facebook = function()
+{
+	StumbleGlobals.get_element("stumbleglobals_referral_popup").hidePopup();
+
+	var params = "";
+	params = StumbleGlobals.arp(params, "url", StumbleGlobals.get_browser_url());
+	params = StumbleGlobals.arp(params, "target", "facebook");
+	var context = { target: "facebook",  share: true };
+	StumbleGlobals.post_url_server_async(
+				"suprshare.php",
+				params,
+				15000,
+				StumbleGlobals.verbose_generic_done,
+				context);
+}
+
+StumbleGlobals.share_twitter = function()
+{
+	StumbleGlobals.get_element("stumbleglobals_referral_popup").hidePopup();
+
+	var params = "";
+	params = StumbleGlobals.arp(params, "url", StumbleGlobals.get_browser_url());
+	params = StumbleGlobals.arp(params, "target", "twitter");
+	var context = { target: "twitter", share: true };
+	StumbleGlobals.post_url_server_async(
+				"suprshare.php",
+				params,
+				15000,
+				StumbleGlobals.verbose_generic_done,
+				context);
+}
+
+StumbleGlobals.refresh_referral_menu = function(from)
+{
+	StumbleGlobals.invoke_global_event("referral-menu-dirty", null, from);
+	
+	if (StumbleGlobals.refreshing_referral_menu)
+		return;
+
+	StumbleGlobals.refreshing_referral_menu = true;
+	
+	setTimeout(
+				function (win, from) {
+					win.StumbleGlobals.invoke_global_event("update-referral-menu", null, from); },
+				1000,
+				window,
+				from);
+}
+
+// utility object for refresh_referral_menu()
+StumbleGlobals.SendObj = function(type, contact)
+{
+	this.type = type;
+	if (type == "friend")
+		this.name = contact.nickname;
+	else if (type == "email")
+		this.name = contact.email;
+	
+	this.count = (contact.referral_count) ? contact.referral_count : 0;
+	this.timestamp = (contact.referral_timestamp) ? contact.referral_timestamp : 0;
+	this.compare_name = this.name.toLowerCase();
+	
+	this.avatar_url = "";
+	
+	if (contact.iconpic)
+	{
+		if (StumbleGlobals.ds.isResourceInstalled("iconpics", contact.contactid + ".jpg"))
+			this.avatar_url = StumbleGlobals.ds.getResourceURLFromName("iconpics", contact.contactid + ".jpg");
+	}
+}
+
+StumbleGlobals.update_referral_menu = function()
+{
+	StumbleGlobals.refreshing_referral_menu = false;
+	if (! StumbleGlobals.referral_menu_dirty)
+		return;
+	
+	if (StumbleGlobals.referral_popup_open)
+		return;
+	
+	setTimeout(StumbleGlobals.update_referral_menu2, 0);
+}
+
+StumbleGlobals.update_referral_menu2 = function()
+{
+	if (StumbleGlobals.referral_popup_open)
+		return;
+
+	StumbleGlobals.refreshing_referral_menu = false;
+	StumbleGlobals.referral_menu_dirty = false;
+	
+	try {
+
+	var i, j, ja, count;
+	
+	// Delete it if it already exists.
+	var el = StumbleGlobals.get_element("stumbleglobals_referral_popup");
+	if (el)
+	{
+		el.parentNode.removeChild(el);
+	}
+	
+	var referral_popup = document.createElement("menupopup");
+	referral_popup.setAttribute("class", "su-referral-popup");
+	referral_popup.setAttribute("position", "after_start");
+	referral_popup.setAttribute("id", "stumbleglobals_referral_popup");
+	referral_popup.setAttribute("onpopupshowing", "StumbleGlobals.handle_popupshowing(event);");
+	referral_popup.setAttribute("onpopuphidden", "StumbleGlobals.handle_popuphidden(event);");
+
+	var menu = StumbleGlobals.get_element("stumbleglobals_referral_menu");
+	menu.appendChild(referral_popup);
+	
+	if (StumbleGlobals.referral_popup_open)
+	{
+		referral_popup.hidePopup();
+		StumbleGlobals.unfocus();
+	}
+	
+	var popup;
+	var has_avatar = false;
+	var has_email = false;
+	var mains = new Array();
+	var mutuals = new Array();
+	var emails = [];
+	var virgin_avatar_mutuals = new Array();
+	var virgin_avatarless_mutuals = new Array();
+	var virgin_gmails = new Array();
+	var virgin_emails = new Array();
+	
+	var contacts = StumbleGlobals.ds.selectAllRows("contact");
+	var i;
+	
+	if (! contacts)
+		return;
+	
+	// Build the list of mutual share people and emails
+	for (i = 0; i < contacts.length; i++)
+	{
+		var send_obj;
+		if (contacts[i].mutual)
+		{
+			send_obj = new StumbleGlobals.SendObj("friend", contacts[i]);
+			mutuals.push(send_obj);
+			
+			if (send_obj.count)
+			{
+				has_avatar = (has_avatar || (send_obj.avatar_url != ""));
+				mains.push(send_obj);
+			}
+			else if (send_obj.avatar_url == "")
+			{
+				virgin_avatarless_mutuals.push(send_obj);
+			}
+			else
+			{
+				virgin_avatar_mutuals.push(send_obj);
+			}
+		}
+		else if (contacts[i].email && (! contacts[i].hidden))
+		{
+			send_obj = new StumbleGlobals.SendObj("email", contacts[i]);
+			emails.push(send_obj);
+			
+			if (send_obj.count)
+			{
+				has_email = true;
+				mains.push(send_obj);
+			}
+			else if (send_obj.compare_name.indexOf("@gmail.com") != -1)
+			{
+				virgin_gmails.push(send_obj);
+			}
+			else
+			{
+				virgin_emails.push(send_obj);
+			}
+		}
+	}
+	
+	emails.sort(function (a, b)
+				{
+					if ( a.compare_name > b.compare_name ) return 1;
+					if ( a.compare_name < b.compare_name ) return -1;
+					return 0;
+				});
+		
+	mutuals.sort(function (a, b)
+				{
+					if ( a.compare_name > b.compare_name ) return 1;
+					if ( a.compare_name < b.compare_name ) return -1;
+					return 0;
+				});
+	
+	var sendtos_count_max = StumbleGlobals.ds.getValue("$sendtos_menu_depth");
+	if (mains.length > sendtos_count_max)
+	{
+		// This is an overflow "Recent" menu if you have more than
+		// sendtos_count_max contacts to put them all at the top level.
+		
+		// Add and populate the Recent submenu. -- JW
+		mains.sort(function (a, b)
+					{
+						if ( a.timestamp < b.timestamp ) return 1;
+						if ( a.timestamp > b.timestamp ) return -1;
+						return 0;
+					});
+		
+		menu = document.createElement("menu");
+		menu.setAttribute("label", "Recent");
+		menu.setAttribute("tooltiptext", "Recent recipients");
+		referral_popup.appendChild(menu);
+		popup = document.createElement("menupopup");
+		menu.appendChild(popup);
+
+		var recent_count_max = StumbleGlobals.ds.getValue("$recent_sendtos_menu_depth");
+		for (i = 0; (i < mains.length) && (i < recent_count_max); i++)
+		{
+			var send_options = {
+				checkbox: true,
+				label: mains[i].name + " (" + mains[i].count + ")",
+				tooltiptext: "Send to " + mains[i].name,
+				target: mains[i].name,
+				send_type: "referral"
+			}
+			var ja = StumbleGlobals.create_send_target(send_options);
+			popup.appendChild(ja);
+		}
+		
+		// separator
+		ja = document.createElement("menuseparator");
+		referral_popup.appendChild(ja);
+	}
+
+	virgin_avatar_mutuals.sort(function (a, b)
+				{
+					return ((Math.random() > 0.5) ? 1 : -1);
+				});
+	
+	virgin_avatarless_mutuals.sort(function (a, b)
+				{
+					return ((Math.random() > 0.5) ? 1 : -1);
+				});
+	
+	virgin_gmails.sort(function (a, b)
+				{
+					return ((Math.random() > 0.5) ? 1 : -1);
+				});
+	
+	virgin_emails.sort(function (a, b)
+				{
+					return ((Math.random() > 0.5) ? 1 : -1);
+				});
+	
+	var gmail_quota = (sendtos_count_max - (mains.length + 
+				virgin_avatar_mutuals.length + 
+				virgin_avatarless_mutuals.length)) * 0.5;
+	
+	var gmail_quota_i = 0;
+	
+	while ((mains.length < sendtos_count_max) && 
+				((virgin_avatar_mutuals.length > 0) ||
+				(virgin_avatarless_mutuals.length > 0) ||
+				(virgin_gmails.length > 0) ||
+				(virgin_emails.length > 0)))
+	{
+		if (virgin_avatar_mutuals.length > 0)
+		{
+			mains.push(virgin_avatar_mutuals.shift());
+			has_avatar = true;
+		}
+		else if (virgin_avatarless_mutuals.length > 0)
+		{
+			mains.push(virgin_avatarless_mutuals.shift());
+		}
+		else if ((gmail_quota_i < gmail_quota) && (virgin_gmails.length > 0))
+		{
+			mains.push(virgin_gmails.shift());
+			gmail_quota_i++;
+			has_email = true;
+		}
+		else if (virgin_emails.length > 0)
+		{
+			mains.push(virgin_emails.shift());
+			has_email = true;
+		}
+		else
+		{
+			mains.push(virgin_gmails.shift());
+			has_email = true;
+		}
+	}
+	
+	// Sort the main Share menu by decreasing count and increasing
+	// name. -- JW
+	mains.sort(function (a, b)
+				{
+					if ( a.count < b.count ) return 1;
+					if ( a.count > b.count ) return -1;
+					if ( a.compare_name > b.compare_name ) return 1;
+					if ( a.compare_name < b.compare_name ) return -1;
+					return 0;
+				});
+
+	var abbr_send_array = new Array();
+	var abbr_work_array = new Array();
+	var max_abbr_idx = 0;
+	for (i = 0; (i < mains.length) && (i < sendtos_count_max); i++)
+	{
+		// Build the abbr_send_array, and begin calcuating e-mail 
+		// abbreviations. -- JW
+		var item = mains[i];
+		var at_idx = item.name.indexOf("@");
+		if (at_idx == -1)
+		{
+			item.abbr_idx = item.name.length - 1;
+			if (item.abbr_idx > max_abbr_idx)
+			{
+				max_abbr_idx = item.abbr_idx;
+			}
+		}
+		else if (at_idx <= 14)
+		{
+			item.abbr_idx = StumbleGlobals.truncate_at(item.name, 14);
+			abbr_work_array.push(item);
+		}
+		else
+		{
+			item.abbr_idx = at_idx;
+			abbr_work_array.push(item);
+		}
+		abbr_send_array.push(item);
+	}		
+	
+	var j;
+	var item_a, item_b;
+	for (i = 0; i < abbr_work_array.length; i++)
+	{
+		// Eliminate duplicate e-mail abbreviations. -- JW
+		item_a = abbr_work_array[i];
+		for (j = i + 1; j < abbr_work_array.length; j++)
+		{
+			item_b = abbr_work_array[j];
+			
+			var common_idx = (item_a.abbr_idx > item_b.abbr_idx) ? item_b.abbr_idx : item_a.abbr_idx;
+
+			if (common_idx > 3)
+				common_idx -= 2;
+			
+			while ((item_a.name.substring(0, common_idx + 1) == item_b.name.substring(0, common_idx + 1)) && (common_idx <= item_a.name.length) && (common_idx <= item_b.name.length))
+				common_idx++;
+			
+			item_a.abbr_idx = (common_idx > item_a.abbr_idx) ? common_idx : item_a.abbr_idx;
+			item_a.abbr_idx = StumbleGlobals.truncate_at(item_a.name, item_a.abbr_idx);
+			item_b.abbr_idx = (common_idx > item_b.abbr_idx) ? common_idx : item_b.abbr_idx;
+			item_b.abbr_idx = StumbleGlobals.truncate_at(item_b.name, item_b.abbr_idx);
+		}
+
+		if (item_a.abbr_idx > max_abbr_idx)
+			max_abbr_idx = item_a.abbr_idx
+	}
+	
+	if (abbr_send_array.length > 0)
+	{
+		// Populate the main Share menu. -- JW
+		
+		var item_count_max = StumbleGlobals.ds.getValue("$sendtos_menu_depth");
+		for (i = 0; i < abbr_send_array.length; i++)
+		{
+			var item = abbr_send_array[i];
+			var label;
+			if (item.abbr_idx == item.name.length - 1)
+				label = item.name;
+			else
+				label = item.name.substring(0, item.abbr_idx + ((item.count == 0) ? 4 : 1)) + "...";
+
+			if (item.count > 0)
+				label += " (" + item.count + ")";
+			
+			var send_options = {
+				checkbox: true,
+				label: label,
+				tooltiptext: "Send to " + item.name,
+				target: item.name,
+				send_type: "referral"
+			}
+			if (item.type == "friend")
+			{
+				send_options.send_type = "referral";
+				if (item.avatar_url == "")
+				{
+					if (has_email)
+					{
+						send_options.image = "chrome://stumbleupon/content/skin/greyman.png";
+					}
+				}
+				else
+				{
+					send_options.image = item.avatar_url;
+				}
+			}
+			else if (item.type == "email")
+			{
+				send_options.send_type = "mail";
+				if (has_avatar)
+				{
+					send_options.image = "chrome://stumbleupon/content/skin/arrow.png";
+				}
+			}
+			var ja = StumbleGlobals.create_send_target(send_options);
+			referral_popup.appendChild(ja);
+		}
+	}
+	
+	ja = document.createElement("menuseparator");
+	referral_popup.appendChild(ja);
+
+	if (mutuals.length > 0)
+	{
+		menu = document.createElement("menu");
+		menu.setAttribute("label", "Stumblers");
+		menu.setAttribute("tooltiptext", "All of the stumblers you can share with");
+		referral_popup.appendChild(menu);
+		
+		popup = document.createElement("menupopup");
+		menu.appendChild(popup);
+		
+		for (i = 0; i < mutuals.length; i++)
+		{
+			if (mutuals[i].count)
+				label = mutuals[i].name + " (" + mutuals[i].count + ")";
+			else
+				label = mutuals[i].name;
+
+			var send_options = {
+				checkbox: true,
+				label: label,
+				target: mutuals[i].name,
+				tooltiptext: "Send to " + mutuals[i].name,
+				send_type: "referral"
+			}
+			
+			var ja = StumbleGlobals.create_send_target(send_options);
+			popup.appendChild(ja);
+		}
+	}
+		
+	if (emails.length > 0)
+	{
+		menu = document.createElement("menu");
+		menu.setAttribute("label", "All Emails");
+		menu.setAttribute("tooltiptext", "All email addresses");
+		referral_popup.appendChild(menu);
+
+		popup = document.createElement("menupopup");
+		menu.appendChild(popup);
+		
+		menu = document.createElement("menu");
+		menu.setAttribute("label", "Remove Email");
+		menu.setAttribute("tooltiptext", "Remove an email address");
+		popup.appendChild(menu);
+		
+		var remove_popup = document.createElement("menupopup");
+		menu.appendChild(remove_popup);
+		
+		ja = document.createElement("menuseparator");
+		popup.appendChild(ja);
+		
+		for (i = 0; i < emails.length; i++)
+		{
+			var name = emails[i].name;
+			var label;
+			
+			if (emails[i].count)
+				label = name + " (" + emails[i].count + ")";
+			else
+				
+				label = name;
+	
+			var send_options = {
+				checkbox: true,
+				label: label,
+				target: name,
+				tooltiptext: "Send to " + name,
+				send_type: "mail"
+			}
+			var ja = StumbleGlobals.create_send_target(send_options);
+			popup.appendChild(ja);
+			
+			ja = document.createElement("menuitem");
+			ja.setAttribute("label", name);
+			ja.setAttribute("oncommand", "StumbleGlobals.remove_email(\"" + name + "\");");
+			ja.setAttribute("tooltiptext", "Remove this address");
+			remove_popup.appendChild(ja);
+		}
+	}
+	
+	ja = document.createElement("menuitem");
+	ja.setAttribute("label", "New Email Address...");
+	ja.setAttribute("image", "chrome://stumbleupon/content/skin/arrow.png");
+	ja.setAttribute("class", "menuitem-iconic");
+	ja.setAttribute("tooltiptext", "Send to a new e-mail address");
+	ja.setAttribute("oncommand", "StumbleGlobals.send_new_mail()");
+	referral_popup.appendChild(ja);
+
+	ja = document.createElement("menuseparator");
+	referral_popup.appendChild(ja);
+
+	ja = document.createElement("menuitem");
+	ja.setAttribute("label", "Find people you know...");
+	ja.setAttribute("class", "menuitem-iconic");
+	ja.setAttribute("image", "chrome://stumbleupon/content/skin/friend.png");
+	ja.setAttribute("tooltiptext", "Import contacts from an address book");
+	ja.setAttribute("onclick", "StumbleGlobals.invite(event);");
+	
+	referral_popup.appendChild(ja);
+	
+	
+	} catch (e) { StumbleGlobals.log_error("REFERRAL MENU", e); }
+}
+
+StumbleGlobals.create_send_target = function(options)
+{
+	var container = document.createElement("menuitem");
+	container.setAttribute("class", "su-referral-menuitem");
+	container.setAttribute("align", "center");
+	container.setAttribute("closemenu", "none");
+	container.setAttribute("oncommand", "StumbleGlobals.referral_menuitem_clicked(event);");
+
+	if(options.checkbox)
+		container.setAttribute("checkbox", "true");		
+
+	if(options.image)
+		container.setAttribute("image", options.image); 
+	
+	if(options.label)
+		container.setAttribute("label", options.label);
+	
+	// Tooltips on the mac seem to really mess up the menu highlighting functionality
+	// and make it freeze.  So we just diable them entirely.
+	if(!StumbleGlobals.host.mac && options.tooltiptext)
+		container.setAttribute("tooltiptext", options.tooltiptext);
+	
+	container.setAttribute("send_type", options.send_type);
+	container.setAttribute("target", options.target);
+
+	return container;
+}
+
+StumbleGlobals.referral_menuitem_checked = function(event)
+{
+	// Get the attributes of the checked item.
+	var checkbox = event.target;
+	var item = checkbox.parentNode;
+	var send_type = item.getAttribute("send_type");
+	var target = item.getAttribute("target");
+	var any_checked = checkbox.checked;
+	
+	// Search for any other menu items with the same target name and type
+	// and update their checked state to match this checked state.
+	var popup = document.getElementById("stumbleglobals_referral_popup");
+	var children = popup.getElementsByClassName("su-referral-menuitem");
+	for (var i=0; i<children.length; i++)
+	{
+		if((children[i].getAttribute("send_type") == send_type) &&
+		    (children[i].getAttribute("target") == target))
+		{
+			children[i].checked = checkbox.checked;
+		}
+		any_checked = (any_checked || children[i].checked);
+	}
+	
+	// Update the Send button display based on whether any targets were checked
+	var deck = document.getElementById("stumbleglobals_referral_deck");
+	
+	if(any_checked)
+		deck.setAttribute("selectedIndex", "1");
+	else
+		deck.setAttribute("selectedIndex", "0");
+}
+
+StumbleGlobals.referral_menuitem_clicked = function(event)
+{
+	StumbleGlobals.get_element("stumbleglobals_referral_popup").hidePopup();
+	
+	// Check this item
+	event.target.checked = true;
+
+	// Normalize and retrieve the current targets
+	var arrTargets = StumbleGlobals.collect_referral_targets();
+		
+	StumbleGlobals.sendto(arrTargets);
+}
+
+StumbleGlobals.referral_sendbutton_clicked = function(event)
+{
+	StumbleGlobals.get_element("stumbleglobals_referral_popup").hidePopup();
+	var arrTargets = StumbleGlobals.collect_referral_targets();
+	StumbleGlobals.sendto(arrTargets);
+}
+
+StumbleGlobals.collect_referral_targets = function()
+{
+	// We want them in order, so we build an array, but we also want to prevent
+	// duplicates, and we use a temporary map for that.
+	var arrTargets = [];
+	var mapTargets = {};
+
+	// Add all of the checked targets to the array
+	var popup = document.getElementById("stumbleglobals_referral_popup");
+	var children = document.getElementsByClassName("su-referral-menuitem");
+	
+	for (var i=0; i<children.length; i++)
+	{
+		if(children[i].checked)
+		{
+			var send_type = children[i].getAttribute("send_type");
+			var target = children[i].getAttribute("target");
+			var key = send_type + "_" + target;
+			
+			if(!mapTargets[key])
+			{
+				arrTargets.push({
+						send_type: send_type,
+						target: target
+				});
+				mapTargets[key] = 1;
+			}
+		}
+	}
+
+	// Sort the array by name
+	arrTargets.sort(function(a, b) {
+		var a = a.target.toLowerCase();
+		var b = b.target.toLowerCase();
+		if(a < b)
+			return -1;
+		else if(a > b)
+			return 1;
+		else
+			return 0;
+	});
+	return arrTargets;
+}
+
+StumbleGlobals.send_new_mail = function()
+{
+	var recipient_email = getBrowser().contentWindow.prompt("Please enter the recipient's email address", "");
+	if (recipient_email == null || recipient_email == "" || typeof(recipient_email) == "undefined")
+		return;
+	
+	// Do an email sanity check
+	if (!StumbleGlobals.validate_email(recipient_email))
+	{
+		alert("Recipient is not a valid email address!");
+		return;
+	}
+	
+	// Send to this one e-mail 
+	StumbleGlobals.sendto([ {
+			send_type: "mail",
+			target: recipient_email
+	} ]);
+}
+
+// utility function for update_referral_menu()
+StumbleGlobals.truncate_at = function(str, idx)
+{
+	if (str.length < idx + 6)
+		idx = str.length - 1;
+	
+	return idx;
+}
+
+// This function grabs urls from recommend.php and stores them in stumbleurls (user_cat is either category id of incat stumble or 0)
+StumbleGlobals.hit_recommend = function(user_cat, check_referral, callback, context)
+{
+	try {
+	
+	var res;
+	var postspec = new Object();
+	var now = StumbleGlobals.get_time_s();
+	
+	if (context.first_of_day)
+		postspec.first_of_day = 1;
+	
+	postspec.houroffset = Math.floor((new Date()).getTimezoneOffset() / 60);
+	
+	if (StumbleGlobals.isInt(user_cat))
+	{
+		postspec.category = user_cat;
+	}
+	else
+	{
+		if (user_cat.indexOf("LANG_") == 0)
+		{
+			postspec.language = user_cat.substr(5);
+		}
+		else if (user_cat.indexOf("TAG_") == 0)
+		{
+			postspec.tag = user_cat.substr(4);
+		}
+		else if (user_cat.indexOf("USERTAG_") == 0)
+		{
+			var chunk = user_cat.substr(8);
+			chunks = chunk.split('_');
+			var tag = chunks[1];
+			var profile = chunks[0];
+			postspec.showfriend = profile;
+			postspec.tag = tag;
+		}
+		else
+		{
+			if (user_cat == "news")
+				postspec.shownews = 1;
+			
+			else if (user_cat == "video")
+				postspec.mode = "video";
+			
+			else if (user_cat == "friends")
+				postspec.mode = "friends";
+			
+			else if (user_cat == "wiki")
+				postspec.mode = "wiki";
+			
+			else	
+				postspec.showfriend = user_cat;
+		}
+	}
+	
+	if (check_referral)
+		postspec.check_referral = 1;
+	else
+		postspec.check_referral = -1;
+	
+	// if we need to upload_stumbles, do it
+	if (StumbleGlobals.ds.getValue("$stumblestats") != "")
+	{
+		postspec.urlids = StumbleGlobals.ds.getValue("$stumblestats");
+		postspec.timestamps = StumbleGlobals.ds.getValue("$stumbletimes");
+		postspec.types = StumbleGlobals.ds.getValue("$stumbletypes");
+		postspec.referralids = StumbleGlobals.ds.getValue("$stumblereferrals");
+		postspec.clienttime = now;
+        context.oldStumbleReport = true;
+	}
+	
+	postspec.recentlyseen = StumbleGlobals.ds.getValue("$recently_seen");
+    postspec.recentlyseen_publicids = StumbleGlobals.ds.getValue("$recently_seen_publicids");
+	postspec.recentlyseen_referralids = StumbleGlobals.ds.getValue("$recently_seen_referralids");
+	
+	var params = StumbleGlobals.build_request_param_string(postspec);
+	
+	params = StumbleGlobals.append_sync_params(params);
+	
+	if (callback)
+		context.callbacks.push(callback);
+	
+	context.dd_uc_server = StumbleGlobals.servername;
+	context.check_referral = check_referral;
+	
+	StumbleGlobals.post_url_server_async(
+				"recommend.php",
+				params,
+				StumbleGlobals.ds.getValue("@recommend_timeout_ms"),
+				StumbleGlobals.hit_recommend_done,
+				context);
+	
+	} catch (e) { StumbleGlobals.log_error("RECOMMEND BEGIN", e); }
+}
+
+StumbleGlobals.hit_recommend_done = function(res)
+{
+	try {
+	
+	var context = res.detail;
+	var callback = null;
+	var ancestor_callback = null;
+	StumbleGlobals.requestTracker.onRecommendDone();
+	if (context)
+	{
+		callback = context.callbacks.pop();
+		ancestor_callback = context.callbacks.pop();
+	}
+
+	if (res.aborted)
+	{
+		if (callback)
+			callback("error", ancestor_callback, context);
+		return;
+	}
+
+	try {
+		if (res.status == 1)
+		{
+			if (callback)
+				callback("error", ancestor_callback, context);
+			return;
+		}
+	} catch (e) {}
+
+	try {
+		if (res.status != 200)
+		{
+			// Maintenance mode returns 503 with "ERROR xxx" set.
+			// In that case, let the "ERROR" command be handled.
+			var isMaintenanceMode = false;
+			if(res.status == 503)
+			{
+				var commands = res.responseText.split(" ");
+				if(commands.length && (commands[0] == "ERROR"))
+				{
+					// Let it fall through 
+					isMaintenanceMode = true;
+				}
+			}
+			if(!isMaintenanceMode)
+			{
+				if (! context.quiet)
+					alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to "
+						+ StumbleGlobals.base_url + "feedback.php to report the problem\nError : " + res.error + "\nStatus : " + res.status);
+				if (callback)
+					callback("connection error", ancestor_callback, context);
+				return;
+			}
+		}
+	}
+	catch (e) {
+		if (! context.quiet)
+			alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to "
+				+ StumbleGlobals.base_url + "feedback.php to report the problem.\nError : connection error");
+		if (callback)
+			callback("connection error", ancestor_callback, context);
+	}
+	
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+	
+	if (StumbleGlobals.log_communication && ((! context.quiet) || StumbleGlobals.log_polling))
+		StumbleGlobals.log("response recommend.php", s);
+	
+	// Parse response text
+	var parsed = s.split("\n");
+	
+	var pre_stumbles = new Array(); // temporary variable for storing stumbles if we are checking referrals
+
+	// Iterate through commands
+	var i;
+	for (i = 0; i < parsed.length; i++)
+	{
+		if (parsed[i] == "")
+			continue;
+
+		// Parse command structure
+		var command = parsed[i].split(" ");
+		if (command[0] == "")
+			continue;
+
+		switch(command[0])
+		{
+			case "ERROR":
+				if (command[1] == "INCORRECT_PASSWORD" && context.quiet)
+				{
+					// auth failed during polling, so poll less frequently
+					
+					// note that iebar signs out when it receives INCORRECT_PASSWORD
+					
+					StumbleGlobals.invoke_global_event("logout", null)
+					return;
+				}
+				else if (command[1] == "NO_INTERESTS")
+				{
+					// Redirect to interests page
+					var loc = StumbleGlobals.serverhttp + "interests.php";
+					//!!! disabled because it screws up history
+					// if (StumbleGlobals.get_browser_url() != loc)
+
+					getBrowser().contentDocument.location = loc;
+
+					if (callback)
+						callback("error", ancestor_callback, context);
+					return;
+				}
+				else if (command[1] == "NO_SITES")
+				{
+					// do nothing
+				}
+				else
+				{
+					if (! context.quiet)
+						StumbleGlobals.handle_error(command[1]);
+					
+					if (callback)
+						callback("error", ancestor_callback, context);
+					return;
+				}
+				break;
+			case "URL":
+				var url = parsed[i].substr(4);
+				pre_stumbles.push(url);
+				// Check to see if we have a referral
+				if (typeof(command[8]) != "undefined" && command[8] == 4)
+					context.referral_url = url;
+				break;
+			default:
+				StumbleGlobals.process_command(parsed[i], context, command);
+				break;
+		}
+	}
+	StumbleGlobals.ds.flushPrefs();
+
+	StumbleGlobals.update_referred(false);
+	
+	if(!context.stumble_referral && !context.check_referral)
+	{
+		// Clear the stumble cache because we have new ones
+		StumbleGlobals.clear_stumbles();
+
+		// populate the stumbles array
+		StumbleGlobals.load_stumbles(null);
+		
+		// push the new stumbles onto the end of stumbles
+		for (i = 0; i < pre_stumbles.length; i++)
+			StumbleGlobals.stumbles.push(pre_stumbles[i]);
+		
+		// Now dump the new stumble queue to disk
+		StumbleGlobals.save_stumbles();
+		
+		if (StumbleGlobals.stumbles.length && (StumbleGlobals.ds.lookup("userid:uc_logger_flag", StumbleGlobals.stumbleid) ||
+					StumbleGlobals.ds.getValue("@dd_uc")))
+			StumbleGlobals.ds.setValue("@dd_uc_server", context.dd_uc_server);
+	}
+	
+	if (callback)
+		callback("", ancestor_callback, context);
+	
+	} catch (e) { StumbleGlobals.log_error("RECOMMEND DONE", e); }
+}
+
+StumbleGlobals.update_referred = function(disable_animation)
+{
+	setTimeout(StumbleGlobals.update_referred2, 0, disable_animation);
+}
+
+StumbleGlobals.add_referred_mousedown_listener = function()
+{
+	var el = StumbleGlobals.get_element("stumbleglobals_category");
+	if(el.mousedown_listener_added)
+		return;
+	el.mousedown_listener_added = true;
+	
+	var fn_mouse_down = function() {
+		StumbleGlobals.get_element("stumbleglobals_referred").show_when_zero = false;
+		StumbleGlobals.update_referred(false);
+	}
+	
+	if(!el.stumbleglobals_mousedown_listener)
+	{
+		el.stumbleglobals_mousedown_listener = true;
+		el.addEventListener("mousedown", fn_mouse_down, false);
+	}
+	
+	el = StumbleGlobals.get_element("stumbleglobals_stumble");
+	if(!el.stumbleglobals_mousedown_listener)
+	{
+		el.stumbleglobals_mousedown_listener = true;
+		el.addEventListener("mousedown", fn_mouse_down, false);
+	}
+}
+
+StumbleGlobals.update_referred2 = function(disable_animation)
+{
+	// Update the disabled and visible state of the referral button.
+	//
+	// It should be visible if:
+	// 1. There are a positive number of referrals.
+	//     - or -
+	// 2. There are 0 referrals, and it went to 0 during this session, and
+	//    the stumble button and topics buttons have not been clicked.
+	//
+	// It should be disabled if:
+	// 1. The requisite time has not passed since the last click.
+	//     - or -
+	// 2. The undelivered count is 0. 
+	//
+	
+	var undelivered_count = StumbleGlobals.ds.getValue("$undelivered_count"); 
+	var el = StumbleGlobals.get_element("stumbleglobals_referred");
+	var previous_count = el.label;
+	var now = (new Date()).getTime();
+	var click_throttle = StumbleGlobals.ds.getValue("@click_throttle_ms");
+
+	// Update the referred button count
+	StumbleGlobals.set_label("stumbleglobals_referred", "" + undelivered_count);
+	
+	// Update the toggle button count
+	var el_toggle = StumbleGlobals.get_element("stumbleglobals_toggle");
+	if(el_toggle)
+	{
+		// If the toolbar is visible, then we do not display the toggle button count, we let
+		// the referral button display the count
+		if(StumbleGlobals.ds.getValue("@toolbar-visible") || (undelivered_count < 1) || !StumbleGlobals.ds.getValue("$show_toggle_refcount"))
+		{
+			el_toggle.removeAttribute("badge");
+		}
+		else
+		{
+			// The toolbar is not visible, go ahead and update the count on the toggle button
+			el_toggle.setAttribute("badge", "" + undelivered_count);
+		}
+	}
+		
+	StumbleGlobals.add_referred_mousedown_listener();
+	
+	if (undelivered_count > 0)
+	{
+		// We are going to continue to show the referral button even when it hits 0.
+		// And hide it when they click on the stumble or category buttons.
+		el.show_when_zero = true;
+		
+		// We have referrals, so make it visible 
+		StumbleGlobals.set_visible("stumbleglobals_referred", true);
+		StumbleGlobals.register_activity("referred");
+		if (! disable_animation)
+			StumbleGlobals.set_attribute("stumbleglobals_referred", "busy", "true");
+		
+		// Disable it if the click timeout has not passed.
+		if(el.last_click & (now - el.last_click < click_throttle))
+		{
+			// Enough time has not passed, keep it disabled and check back later.
+			el.disabled = true;
+			setTimeout(StumbleGlobals.update_referred, click_throttle);
+		}
+		else
+		{
+			el.disabled = false;
+		}
+ 	}
+	else
+	{
+		if(StumbleGlobals.stumbleid == 0)
+		{
+			// If we aren't logged in, then it is simply not visible
+			StumbleGlobals.set_visible("stumbleglobals_referred", false);
+		}
+		else
+		{
+			// 0 referrals, so for sure it is disabled.
+			el.disabled = true;
+			StumbleGlobals.set_attribute("stumbleglobals_referred", "busy", "false");
+	
+			// Visibility depends on whether show_when_zero is on
+			StumbleGlobals.set_visible("stumbleglobals_referred", !!el.show_when_zero);
+		}
+	}
+}
+	
+StumbleGlobals.save_stumbles = function()
+{
+	var towrite = "";
+	for (var ii = 0; ii < StumbleGlobals.stumbles.length; ii++)
+		towrite += StumbleGlobals.stumbles[ii] + "\n";
+	
+	StumbleGlobals.write_file_user("stumbleurls", towrite);
+}
+
+// Saves a rating to the rating history (so we can grey out rating buttons later)
+StumbleGlobals.store_rating = function(u, c)
+{
+	var url_detail = StumbleGlobals.ds.lookup("url:url_detail", u)
+	if (url_detail)
+		url_detail.rating = c;
+	
+	// Load rating history (in case the user has rated something in another window)
+	stumblecat = StumbleGlobals.read_file_user("stumblerating");
+	splitcat = stumblecat.split("\n");
+	for (var i = 0; i < splitcat.length; i++)
+	{
+		if (splitcat[i] == "")
+			continue;
+		split2 = splitcat[i].split(" ");
+		StumbleGlobals.ratings[split2[0]] = split2[1];
+	}
+
+	// Add the new rating
+	StumbleGlobals.ratings[u] = c;
+
+	// Now dump it to disk
+	var towrite = "";
+	for (var ii in StumbleGlobals.ratings)
+	{
+		if (StumbleGlobals.is_property_garbage(StumbleGlobals.ratings, ii))
+			continue;
+		
+		towrite += ii + " " + StumbleGlobals.ratings[ii] + "\n";
+	}
+	StumbleGlobals.write_file_user("stumblerating", towrite); 
+}
+
+StumbleGlobals.delete_rating = function(u)
+{
+	var url_detail = StumbleGlobals.ds.lookup("url:url_detail", u)
+	if (url_detail)
+		url_detail.rating = null;
+
+	// Load rating history (in case the user has rated something in another window)
+	stumblecat = StumbleGlobals.read_file_user("stumblerating");
+	splitcat = stumblecat.split("\n");
+	StumbleGlobals.ratings = new Array();
+	for (var i = 0; i < splitcat.length; i++)
+	{
+		if (splitcat[i] == "")
+			continue;
+		split2 = splitcat[i].split(" ");
+		if (split2[0] != u)
+			StumbleGlobals.ratings[split2[0]] = split2[1];
+	}
+
+	// Now dump it to disk
+	var towrite = "";
+	for (var ii in StumbleGlobals.ratings)
+	{
+		if (StumbleGlobals.is_property_garbage(StumbleGlobals.ratings, ii))
+			continue;
+		
+		towrite += ii + " " + StumbleGlobals.ratings[ii] + "\n";
+	}
+	StumbleGlobals.write_file_user("stumblerating", towrite); 
+}
+
+// performs a synchronous POST, when the interface is beneath the www
+// stumbleupon domain
+StumbleGlobals.post_url_server = function(uri_suffix, postdata)
+{
+	return StumbleGlobals.post_url(
+				StumbleGlobals.serverhttp + uri_suffix + "?username=" + StumbleGlobals.stumbleid,
+				postdata);
+}
+
+StumbleGlobals.post_url_server_secure = function(uri_suffix, postdata)
+{
+	return StumbleGlobals.post_url(
+				StumbleGlobals.serverhttps + uri_suffix + "?username=" + StumbleGlobals.stumbleid,
+				postdata);
+}
+
+// performs a synchronous POST
+StumbleGlobals.post_url = function(uri, postdata)
+{
+	var script_timeout_saved;
+ 	try {
+		if (StumbleGlobals.ds.isPrefDefined("dom.max_chrome_script_run_time"))
+		{
+			script_timeout_saved = StumbleGlobals.ds.getValue("dom.max_chrome_script_run_time");
+			StumbleGlobals.ds.setValue("dom.max_chrome_script_run_time", 120);
+		}
+	} catch (e) {}
+	
+	// This function trys to post 3 times (since there is 
+	// something screwy with xmlhttprequest).
+	var ret2 = new Object();
+	var x;
+	var status;
+	var retries = 3;
+
+	if (! postdata)
+		postdata = "";
+	
+	var client_postdata = StumbleGlobals.get_client_postdata(uri);
+	if (client_postdata != "")
+		postdata += ((postdata == "") ? "" : "&") + client_postdata;
+	
+	for (var i = 1; i <= retries; i++)
+	{
+		x = new XMLHttpRequest();
+		x.open("POST", uri, false);
+		x.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+		try { 
+			if (StumbleGlobals.log_communication && (uri.indexOf("topics.csv") == -1))
+				StumbleGlobals.log("post sync", uri, postdata, "attempt: " + i);
+			x.send(postdata); 
+			status = x.status;
+			break;
+		}
+		catch (e) {
+			if (i == retries) 
+			{
+				// Failed on 3nd try, bail out
+				ret2.error = e;
+				ret2.response = "";
+				ret2.status = 1;
+				try {
+					if (StumbleGlobals.ds.isPrefDefined("dom.max_chrome_script_run_time"))
+					{
+						StumbleGlobals.ds.setValue(
+									"dom.max_chrome_script_run_time",
+									script_timeout_saved);
+					}
+				} catch (e) {}
+				return ret2;
+			}
+		}
+	}
+	ret2.error = "";
+	ret2.response = x.responseText;
+	if (typeof(ret2.response) == "undefined")
+		ret2.response = "";
+	ret2.status = x.status;
+	var mime = '';
+	try {
+		mime = x.getResponseHeader("Content-Type");
+	}
+	catch (e) {
+		mime = '';
+	}
+	
+	if (mime != null && typeof(mime) != "undefined" && mime != '')
+	{
+		var mimes = mime.split(";");
+		ret2.mimetype	= mimes[0];
+	}
+	else
+		ret2.mimetype = '';
+	try {
+		if (StumbleGlobals.ds.isPrefDefined("dom.max_chrome_script_run_time"))
+		{
+			StumbleGlobals.ds.setValue(
+						"dom.max_chrome_script_run_time",
+						script_timeout_saved);
+		}
+	} catch (e) {}
+	return ret2;
+}
+
+// begins an asynchronous POST, when the interface is beneath the www
+// stumbleupon domain
+StumbleGlobals.post_url_server_async = function(uri_suffix, postdata, timeout_interval_ms, callback, detail)
+{
+	if (! detail)
+		detail = new Object();
+	detail.request_target = uri_suffix;
+	
+	StumbleGlobals.post_url_async(
+				StumbleGlobals.serverhttp + uri_suffix + 
+					((StumbleGlobals.stumbleid && (uri_suffix != "stumblethru.csv")) ? 
+					("?username=" + StumbleGlobals.stumbleid) : ""),
+				postdata,
+				timeout_interval_ms,
+				callback,
+				detail);
+}
+
+StumbleGlobals.post_url_server_async_secure = function(uri_suffix, postdata, timeout_interval_ms, callback, detail)
+{
+	if (! detail)
+		detail = new Object();
+	detail.request_target = uri_suffix;
+	
+	StumbleGlobals.post_url_async(
+				StumbleGlobals.serverhttps + uri_suffix + 
+					((StumbleGlobals.stumbleid && (uri_suffix != "stumblethru.csv")) ? 
+					("?username=" + StumbleGlobals.stumbleid) : ""),
+				postdata,
+				timeout_interval_ms,
+				callback,
+				detail);
+}
+
+// begins an asynchronous POST
+StumbleGlobals.post_url_async = function(uri, postdata, timeout_interval_ms, callback, detail)
+{
+	// This ensures that our request objects are created in the context
+	// of this window.  This is necessary for the first stumble after
+	// new account creation. -- JW
+	setTimeout(function (window, uri, postdata, timeout_interval_ms, callback, detail) { window.StumbleGlobals.post_url_async_wrapped(uri, postdata, timeout_interval_ms, callback, detail); }, 0, window, uri, postdata, timeout_interval_ms, callback, detail);
+}
+
+// do not call this; call post_url_async instead
+StumbleGlobals.post_url_async_wrapped = function(uri, postdata, timeout_interval_ms, callback, detail)
+{
+	if (! postdata)
+		postdata = "";
+	
+	postdata += ((postdata == "") ? "" : "&") + StumbleGlobals.get_client_postdata(uri);
+	
+	StumbleGlobals.service.postAsync(StumbleGlobals.useragent, uri, postdata, timeout_interval_ms, callback, detail);
+}
+
+// Used by post_url, post_url_async and stumble_done to
+// construct version and authentication portions of postdata
+StumbleGlobals.get_client_postdata = function(uri)
+{
+	var postdata = "";
+	
+	if (uri.indexOf(StumbleGlobals.serverhttp) == 0)
+		postdata += "version=" + StumbleGlobals.verstring;
+
+	if (StumbleGlobals.is_auth_allowed(uri))
+	{
+		if (StumbleGlobals.enable_hashed_password)
+		{
+			postdata += ((postdata == "") ? "" : "&") + 
+						"username=" + StumbleGlobals.stumbleid + 
+						"&password=" + StumbleGlobals.stumblepass +
+						"&ycc=" + StumbleGlobals.ds.getCC();
+		}
+		else
+		{
+			postdata += ((postdata == "") ? "" : "&") + 
+						"username=" + StumbleGlobals.stumbleid + 
+						"&password=" + encodeURIComponent(StumbleGlobals.stumblepass) +
+						"&ycc=" + StumbleGlobals.ds.getCC();
+		}
+	}
+	return postdata;
+}
+
+// used by the http_observer and get_client_postdata to determine
+// whether we're allowed to send authentication to the page
+StumbleGlobals.is_auth_allowed = function(url)
+{
+	if (! StumbleGlobals.is_matching_domain(url, StumbleGlobals.servername))
+		return false;
+	
+	if ((url.indexOf(StumbleGlobals.serverhttp == 0)) || (url.indexOf(StumbleGlobals.serverhttps == 0)))
+	{
+		// These get special authentication sent in postdata.
+		if ((StumbleGlobals.is_server_page(url, "userexists.php")) ||
+					(StumbleGlobals.is_server_page(url, "delete_account.php")) ||
+					(StumbleGlobals.is_server_page(url, "change_password.php")) ||
+					(StumbleGlobals.is_server_page(url, "sign_up.php")) ||
+					(StumbleGlobals.is_server_page(url, "getid.php")) ||
+					(StumbleGlobals.is_server_page(url, "init_user.php")) ||
+					(StumbleGlobals.is_server_page(url, "signup.php")))
+			return false;
+
+		// Don't bother with obvious non-pages....
+		if ((StumbleGlobals.is_server_page(url, "images/")) ||
+					(StumbleGlobals.is_server_page(url, "pics/")) ||
+					(StumbleGlobals.is_server_page(url, "iconpics/")) ||
+					(StumbleGlobals.is_server_page(url, "superminipics/")) ||
+					(StumbleGlobals.is_server_page(url, "groupsuperminipics/")) ||
+					(StumbleGlobals.is_server_page(url, "topicsuperminipics/")) ||
+					(StumbleGlobals.is_server_page(url, "mediumpics/")) ||
+					(StumbleGlobals.is_server_page(url, "thumb/")) ||
+					(StumbleGlobals.is_server_page(url, "css/")) ||
+					(StumbleGlobals.is_server_page(url, "js/")) ||
+					(StumbleGlobals.is_server_page(url, "favicon.ico")) ||
+					(StumbleGlobals.is_server_page(url, "stumble.js")) ||
+					(StumbleGlobals.is_server_page(url, "post.js")) ||
+					(StumbleGlobals.is_server_page(url, "help.js")))
+			return false;
+	}
+	return true;
+}
+
+StumbleGlobals.handle_page_feature_prompt_click = function(event)
+{
+	var url = StumbleGlobals.get_browser_url();
+	var search_service_id = StumbleGlobals.get_service_id(url, true);
+	
+	if (StumbleGlobals.is_matching_domain(url, "facebook.com"))
+	{
+		if (StumbleGlobals.ds.getValue("$facebook_added"))
+		{
+			StumbleGlobals.ds.setValue("$facebook_linked", true);
+			
+			StumbleGlobals.set_server_location(
+						"facebook/index.php?link",
+						null,
+						StumbleGlobals.new_tab(event));
+		}
+		else
+		{
+			StumbleGlobals.set_location(
+						"http://apps.facebook.com/stumbleupon/",
+						null,
+						StumbleGlobals.new_tab(event));
+		}
+	}
+	else if (search_service_id)
+	{
+		StumbleGlobals.ds.setValue("$show_searchlinks_score", true);
+		StumbleGlobals.ds.setValue("$show_searchlinks_friends", true);
+		StumbleGlobals.ds.setValue("$shown_searchlinks", true);
+		if (StumbleGlobals.new_tab(event))
+		{
+			StumbleGlobals.set_location(url, null, true);
+		}
+		else
+		{
+			StumbleGlobals.search_results_page(
+						getBrowser().contentDocument,
+						search_service_id);
+		}
+	}
+	StumbleGlobals.set_visible("stumbleglobals_page_feature_prompt", false);
+}
+
+// handles the click event for the website_info button
+StumbleGlobals.handle_website_info_click = function(event)
+{	
+	// button is disabled
+	if (StumbleGlobals.get_element("stumbleglobals_website_info").getAttribute("image") == "chrome://stumbleupon/content/skin/bubblex.png")
+		return;
+
+	StumbleGlobals.website_info(StumbleGlobals.new_tab(event), "", 0);
+}
+
+StumbleGlobals.handle_website_info_promo_click = function(event, from_control_id)
+{	
+	if (StumbleGlobals.search_service_id)
+	{
+		StumbleGlobals.handle_promo_click(event, 	"search");
+		return;
+	}
+	
+	// button is disabled
+	if (StumbleGlobals.get_element("stumbleglobals_website_info_promo").disabled)
+		return;
+
+	var url = StumbleGlobals.get_browser_url();		
+	
+	var cmp_url = url.toLowerCase();
+	
+	if (cmp_url.indexOf("http://video." + StumbleGlobals.servername + "/#p") == 0)
+		return;
+				
+	if (cmp_url.indexOf("http://video." + StumbleGlobals.servername + "/?p") == 0)
+		return;
+	
+	var loc;
+	var params = null;
+	
+	if (url.indexOf("about:") == 0)
+	{
+		StumbleGlobals.verify_cookie_perms(false);
+		loc = "sign_up.php";
+		if (StumbleGlobals.ds.getValue("@facebook_user"))
+			loc = StumbleGlobals.arp(loc, "pre", "facebook", true);
+		
+		loc = StumbleGlobals.arp(loc, "pre2", from_control_id, true); 
+		
+		if (StumbleGlobals.host.dist)
+			loc = StumbleGlobals.arp(loc, "dist", StumbleGlobals.host.dist, true);
+	}
+	else
+	{
+		loc = "url/" + StumbleGlobals.review_url(url);
+		params = "";
+		if (StumbleGlobals.ds.getValue("@facebook_user"))
+			params = StumbleGlobals.arp(params, "pre", "facebook");
+		
+		params = StumbleGlobals.arp(params, "pre2", from_control_id); 
+		
+		if (StumbleGlobals.host.dist)
+			params = StumbleGlobals.arp(params, "dist", StumbleGlobals.host.dist);
+		
+		params = StumbleGlobals.arp(params, "retry_url", url);
+	}
+	
+	StumbleGlobals.set_server_location(
+				loc,
+				params,
+				StumbleGlobals.new_tab(event));
+}
+
+StumbleGlobals.handle_promo_click = function(event, from_control_id)
+{	
+	var is_search = false;
+	var url = StumbleGlobals.get_browser_url();
+	var detail = new Object();
+	if (from_control_id == "search")
+	{
+		is_search = true;
+		from_control_id = StumbleGlobals.search_service_id;
+		detail = StumbleGlobals.get_search_query_detail(StumbleGlobals.search_service_id, url); 
+	}
+	
+	StumbleGlobals.verify_cookie_perms(false);
+	var loc = "sign_up.php";
+	var params = null;
+	if (StumbleGlobals.ds.getValue("@facebook_user"))
+		loc = StumbleGlobals.arp(loc, "pre", "facebook", true);
+	
+	loc = StumbleGlobals.arp(loc, "pre2", from_control_id, true); 
+	
+	if (StumbleGlobals.host.dist)
+		loc = StumbleGlobals.arp(loc, "dist", StumbleGlobals.host.dist, true);
+	
+	if (detail.is_short_query_results)
+		params = StumbleGlobals.arp("", "post_url", url);
+	else if (detail.is_query_results)
+		params = StumbleGlobals.arp("", "post_url2", url);
+	else if (from_control_id == "referral")
+		loc = StumbleGlobals.arp(loc, "url", url, true);
+
+	StumbleGlobals.set_server_location(
+				loc,
+				params,
+				StumbleGlobals.new_tab(event));
+}
+
+StumbleGlobals.handle_video_promo_click = function(event)
+{
+
+	StumbleGlobals.get_element("stumbleglobals_stumble").image="chrome://stumbleupon/content/skin/stumble2.png";
+	StumbleGlobals.stumble_action_count++;
+	setTimeout(
+				StumbleGlobals.reset_stumble_action_indicator,
+				StumbleGlobals.ds.getValue("@stumble_action_timeout_ms"),
+				StumbleGlobals.stumble_action_count);
+	
+	StumbleGlobals.stumble_video(StumbleGlobals.new_tab(event));
+}
+
+StumbleGlobals.handle_tag_command = function(force_dialog)
+{
+	var searchbox = StumbleGlobals.get_element("stumbleglobals_searchbox");
+	if (searchbox.open)
+		searchbox.closePopup();
+	
+	setTimeout(StumbleGlobals.handle_tag_command2, 0, force_dialog);	
+}
+
+StumbleGlobals.get_title = function(opt_doc, opt_raw_url)
+{
+	var doc = (opt_doc) ? opt_doc : getBrowser().contentDocument;
+	
+	if (doc.title != "")
+		return doc.title;
+	
+	if (opt_raw_url)
+		return opt_raw_url;
+		
+	return StumbleGlobals.get_browser_url(doc, true)
+}
+
+StumbleGlobals.handle_tag_command2 = function(force_dialog)
+{
+	//!!! canonize tag?
+	var current_url = StumbleGlobals.get_browser_url();
+	
+	if (StumbleGlobals.url_has_tag)
+	{
+		var tag = StumbleGlobals.get_tag_list(current_url);
+		
+		if (tag)
+		{
+			StumbleGlobals.tagit(current_url, tag, true, StumbleGlobals.get_title(), StumbleGlobals.get_browser_url(null, true));
+			return;
+		}
+	}
+	
+	StumbleGlobals.unfocus_searchbox(); 
+	// see if searchbox is hidden
+	var tag = '';
+	if (force_dialog || (StumbleGlobals.get_element("stumbleglobals_field").collapsed == true))
+	{
+		var detail = new Object();
+		detail.url = current_url;
+		detail.tags_default = StumbleGlobals.get_element("stumbleglobals_searchbox").value;
+		if (detail.tags_default == StumbleGlobals.tag_instructions)
+			detail.tags_default = "";
+
+		window.openDialog(
+					"chrome://stumbleupon/content/taggingDialog.xul",
+					"",
+					"chrome,dialog,centerscreen,dependent",
+					detail);
+	}
+	else
+	{	
+		tag = StumbleGlobals.get_element("stumbleglobals_searchbox").value;
+		if (tag == StumbleGlobals.tag_instructions)
+			tag = "";
+		
+		if (tag == "")
+		{
+			// put a little instruction thing up
+			var alerttext = "To tag a page, type some tags into the text box before clicking the tag button.\nTags are descriptive keywords you can use to organize and share useful websites.\nTags may contain spaces, letters, and numbers and must be separated by commas.\nFor example, you might tag page of travel photos as \"photos, traveling, costa rica\".\n\nYou can lookup sites you've tagged using the 'Find pages you liked' button on your Favorites page.";
+			alert(alerttext);
+			
+			// put focus in search box
+			StumbleGlobals.get_element("stumbleglobals_searchbox").focus();
+			return;	
+		}	
+		
+		var tagerror = StumbleGlobals.validate_tagstring(tag);
+		if (tagerror != null)
+		{
+			alert(tagerror);
+			return;
+		}	
+		StumbleGlobals.tagit(current_url, tag, false, StumbleGlobals.get_title(), StumbleGlobals.get_browser_url(null, true));
+	}	
+}
+
+StumbleGlobals.validate_tagstring = function(str)
+{
+	// validate tag...
+	var tags = str.split(',');
+	var tagerror = null;
+	// Itetag through commands
+	var tagcount = 0;
+	for (var i = 0; i < tags.length; i++)
+	{
+		if (tags[i] == "")
+			continue;
+		tagcount++;
+		if (tagcount > 5)
+		{
+			tagerror = 'You cannot apply more than 5 tags to a page.';
+			break;
+		}
+		
+		var thetag = tags[i];
+		
+		if (thetag.indexOf('http://') != -1)
+		{
+			tagerror = 'If you want to search for a site, enter some search terms then click \'enter\'.\nTo tag a page, type in some keywords before clicking this icon.';
+			break;	
+		}
+		
+		if (thetag.length > 32)
+		{
+			tagerror = 'Each tag cannot be longer than 32 characters.\nYour tag \'' + thetag + '\' is ' + thetag.length + ' characters long.';
+			break;
+		}
+		var tagpieces = thetag.split(/[^A-Za-z0-9]/);
+//		alert(tagpieces.length);
+		var tagpiececount = 0;
+		for (var j = 0; j < tagpieces.length; j++)
+		{
+			if (tagpieces[j] == "")
+				continue;
+			//alert(tagpieces[j]);
+			tagpiececount++;
+			if (tagpiececount > 3)
+			{
+				tagerror = 'Each tag cannot have more than 3 words. For example,\n \'costa rica trip\' is a valid tag, but \'costa rica trip photos\' is not.\nYour tag \'' + thetag + '\' has ' + tagpiececount + ' words.';
+				break;	
+			}
+		}
+		if (tagpiececount > 3)
+			break;	
+	}
+	return tagerror;
+}
+
+StumbleGlobals.tagit = function(url, tag, untag, opt_title, opt_raw_url)
+{
+	// when you tag, we know it's not a tag on i-likeit
+	StumbleGlobals.last_typed_tag = 0;
+	
+	if ((url == "") || (url.indexOf("about:") == 0))
+		return;
+
+	var context = new StumbleGlobals.AsyncContext();
+	context.url = url;
+	context.tag = tag;
+	context.ref_url = (opt_raw_url) ? opt_raw_url : StumbleGlobals.get_browser_url(null, true);
+	context.untagging = untag;
+	if (! untag)
+		context.title = (opt_title) ? opt_title : StumbleGlobals.get_title();
+	
+	var params = "tag=" + escape(tag) + "&url=" + encodeURIComponent(url);
+	
+	params = StumbleGlobals.arp(params, "referer", StumbleGlobals.get_browser_referrer_url());
+	
+	params = StumbleGlobals.append_sync_params(params);
+	
+	if (untag)
+	{
+		// we want to undo this tag	
+		StumbleGlobals.post_url_server_async(
+					"untagit.php",
+					params,
+					null,
+					StumbleGlobals.untag_done,
+					context);
+	}
+	else
+	{
+		StumbleGlobals.post_url_server_async(
+					"tagit.php",
+					params,
+					null,
+					StumbleGlobals.tag_done,
+					context);
+	}
+	return;
+}
+
+
+StumbleGlobals.untag_done = function(res)
+{
+	try {
+		if (res.status == 1)
+			return;
+	} catch (e) { return; }
+	
+	if (res.status != 200)
+	{
+		StumbleGlobals.http_error(res.error, res.status);
+		return;
+	}
+	
+	var context = res.detail;
+	
+	// success!
+	// !!! go to info page? (middle click or option?)
+	
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response untagit.php", s);
+	
+	StumbleGlobals.process_commands(s, context);
+	if (context.error)
+		return;
+	
+	StumbleGlobals.load_tags(context.url);
+	StumbleGlobals.store_tags();
+	
+	StumbleGlobals.enable_tag_toolbar();
+	
+	return;
+}
+
+
+StumbleGlobals.tag_done = function(res)
+{
+	try {
+		if (res.status == 1)
+			return;
+	} catch (e) { return; }
+	
+	if (res.status != 200)
+	{
+		StumbleGlobals.http_error(res.error, res.status);
+		return;
+	}
+	
+	var context = res.detail;
+	
+	// success!
+	// !!! go to info page? (middle click or option?)
+
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+	
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response tagit.php", s);
+	
+	StumbleGlobals.process_commands(s, context);
+	if (context.error)
+		return;
+	
+	var tag = StumbleGlobals.normalize_tag(context.tag);
+	
+	StumbleGlobals.load_tags(context.url);
+	
+	// Add the new tag
+	var o = new Object();
+	o.url = context.url;
+	o.tag_list = tag;
+	StumbleGlobals.tag_lists_by_url[context.url] = tag;
+	StumbleGlobals.tags.unshift(o);
+	
+	StumbleGlobals.store_tags();
+	
+	StumbleGlobals.disable_tag_toolbar(tag);
+	StumbleGlobals.old_search = tag;
+	
+	StumbleGlobals.get_element("stumbleglobals_tag").image="chrome://stumbleupon/content/skin/tag2.png";
+	StumbleGlobals.get_element("stumbleglobals_tag2").image="chrome://stumbleupon/content/skin/tag2.png";
+}
+
+
+// Returns the size of the URL in bytes; must be cached and therefore an HTTP or FTP URL
+StumbleGlobals.get_size = function(url) 
+{
+	var cacheService = StumbleGlobals.get_service(
+				"@mozilla.org/network/cache-service;1",
+				"nsICacheService");
+	var httpCacheSession = cacheService.createSession("HTTP", 0, true);
+	httpCacheSession.doomEntriesIfExpired = false;
+	var ftpCacheSession = cacheService.createSession("FTP", 0, true);
+	ftpCacheSession.doomEntriesIfExpired = false;
+	
+	try
+	{
+		var cacheEntryDescriptor = httpCacheSession.openCacheEntry(url, Components.interfaces.nsICache.ACCESS_READ, false);
+		if (cacheEntryDescriptor)
+			return cacheEntryDescriptor.dataSize;
+	}
+	catch(ex) {}
+	try
+	{
+		cacheEntryDescriptor = ftpCacheSession.openCacheEntry(url, Components.interfaces.nsICache.ACCESS_READ, false);
+		if (cacheEntryDescriptor)
+			return cacheEntryDescriptor.dataSize;
+	}
+	catch(ex) {}
+	return -1;
+}
+
+// Handler for photoblog
+StumbleGlobals.blogImage = function(rating)
+{
+	StumbleGlobals.photoblogimage = document.popupNode;
+
+	if (StumbleGlobals.get_size(StumbleGlobals.photoblogimage.src) > 250000)
+	{
+		StumbleGlobals.photoblogimage = null;
+		alert("Image too large (250kb max size)");
+		return;
+	}
+
+	if (StumbleGlobals.photoblogimage.width > 715)
+	{
+		StumbleGlobals.photoblogimage = null;
+		alert("Image too large (715px max width)");
+		return;
+	}
+
+	if (StumbleGlobals.photoblogimage.height > 715)
+	{
+		StumbleGlobals.photoblogimage = null;
+		alert("Image too large (715px max height)");
+		return;
+	}
+
+/*
+	// see if we need to grab the referring page for this image
+	var current_page = StumbleGlobals.get_browser_url();
+	alert("currente page: " + current_page + " StumbleGlobals.photoblogimage: " + StumbleGlobals.photoblogimage.src);
+	if (current_page == StumbleGlobals.photoblogimage.src)
+	{
+		// we want to find the referring page...
+		var referer = getBrowser().contentDocument.referrer;
+		alert("referer " + referer);
+		if (typeof(referer) != "undefined" && referer != null && referer != "" && referer.indexOf('http://') != -1)
+		{
+			// we need to rate the referering page.. 	
+			alert("refering page: " + referer);
+			return;
+		}
+	}
+
+	alert("no referring page");
+	return;
+*/
+
+	// first do rating...
+	StumbleGlobals.rate(rating, false, true, false, 0);	
+}
+
+// pre-Handler for button "rate"
+StumbleGlobals.handle_rate_click = function(event, r)
+{
+	if (StumbleGlobals.promo_mode && (StumbleGlobals.stumbleid == 0) && (! StumbleGlobals.get_stumblevideo_detail()))
+	{
+		if (r > 0)
+			StumbleGlobals.handle_website_info_promo_click(event, "thumbup");
+		else
+			StumbleGlobals.handle_website_info_promo_click(event, "thumbdown");
+			
+		return;
+	}
+	
+	if (r == 2)
+	{
+		r = 1;
+		StumbleGlobals.d_rec_rating = true;
+	}
+	else
+	{
+		StumbleGlobals.d_rec_rating = false;
+	}
+	
+	var url = StumbleGlobals.get_browser_url();
+	var old_rating = StumbleGlobals.get_rating(url, (StumbleGlobals.get_stumblevideo_detail() != null));
+	
+	// see if they are unrating an old rating
+	
+	if ((old_rating != null) && 
+			((old_rating == r) || (r == 0 && (old_rating <= 0))))
+	{
+		setTimeout(StumbleGlobals.unrate, 0);
+		return;
+	}
+	
+	if (StumbleGlobals.get_element("stumbleglobals_thumbup").disabled == true)
+		return;
+	
+	if (typeof(event.button) == "undefined")
+		event.button = 0; // For menu entries, simulate left button
+
+	var platform_ctrl_key = (StumbleGlobals.host.mac) ? event.metaKey : event.ctrlKey;
+	
+	if (((event.button == 0) && (! platform_ctrl_key)) && 
+				(! StumbleGlobals.ds.getValue("$rate_new_window")))
+		StumbleGlobals.rate(r, false, false, false, 0);
+	
+	else if ((event.button == 1) || ((event.button == 0) && 
+				platform_ctrl_key) || StumbleGlobals.ds.getValue("$rate_new_window"))
+		StumbleGlobals.rate(r, true, false, false, 0);
+}
+
+
+// Handler for button "rate"
+StumbleGlobals.unrate = function()
+{
+	StumbleGlobals.check_progress_listener();
+
+	if ((StumbleGlobals.stumbleid == 0) && (! StumbleGlobals.promo_mode))
+		return;
+	
+	var theurl = StumbleGlobals.get_browser_url();
+	if (StumbleGlobals.stumbled_redirect != '' && theurl == StumbleGlobals.stumbled_redirect)
+	{
+		// we have a redirect, rate the original url we stumbled on
+		theurl = StumbleGlobals.stumbled_url;
+	}
+
+	var sv_detail = StumbleGlobals.get_stumblevideo_detail();
+				
+	if (sv_detail)
+	{
+		var doc = getBrowser().contentDocument;
+		
+		StumbleGlobals.stumblevideo_toolbar_rate = true;
+		var thumbup = doc.getElementById("thumbUp");
+		var thumbdown = doc.getElementById("thumbDown");
+		if (thumbup.src.indexOf("_sel") != -1)
+			StumbleGlobals.dispatch_click(doc, "thumbUp");
+		else if (thumbdown.src.indexOf("_sel") != -1)
+			StumbleGlobals.dispatch_click(doc, "thumbDown");
+		return;
+	}
+	
+	// grey out the buttons until the rating goes through
+	StumbleGlobals.get_element("stumbleglobals_thumbup").disabled=true;
+	StumbleGlobals.get_element("stumbleglobals_thumbdown").disabled=true;
+	StumbleGlobals.get_element("stumbleglobals_thumbup").setAttribute("onclick", "");
+
+	var params = "";
+	params = StumbleGlobals.arp(params, "url", theurl); 
+	params = StumbleGlobals.append_sync_params(params);
+	
+	var context = new StumbleGlobals.AsyncContext();
+	context.url = theurl;
+	context.ref_url = context.url;
+	StumbleGlobals.post_url_server_async(
+				"unrate.php",
+				params,
+				null,
+				StumbleGlobals.unrate_done,
+				context);
+
+	StumbleGlobals.check_progress_listener();
+}
+
+StumbleGlobals.unrate_done = function(res)
+{
+	try {
+		if (res.status == 1)
+		{
+			StumbleGlobals.enable_toolbar();
+			return;
+		}
+	} catch (e) { return; }
+	
+	if (res.status != 200)
+	{
+		StumbleGlobals.http_error(res.error, res.status);
+		StumbleGlobals.enable_toolbar();
+		return;
+	}
+	
+	var context = res.detail;
+	context.unrating = true;
+
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response unrate.php", s);
+
+	StumbleGlobals.process_commands(s, context);
+	if (context.error && !context.discoveryCancelled)
+	{
+		StumbleGlobals.enable_toolbar();
+		return;
+	}
+	
+	// Store in list of rated urls
+	StumbleGlobals.delete_rating(context.url);
+
+	StumbleGlobals.refresh_pagemeta(false, 3);
+	
+	StumbleGlobals.check_progress_listener();
+}
+
+// Handler for button "rate"
+StumbleGlobals.block_domain = function()
+{
+	var url = StumbleGlobals.get_browser_url();
+	
+	var rating = StumbleGlobals.get_rating(url, (StumbleGlobals.get_stumblevideo_detail() != null));
+	
+	var domain = StumbleGlobals.get_tld(url);
+	
+	var blk_domain = StumbleGlobals.is_domain_blocked(domain) ? -1 : 1;
+	
+	if (rating == null && blk_domain == 1)
+		rating = -2;
+	
+	if (rating == null && blk_domain == -1)
+	{
+		var context = new StumbleGlobals.AsyncContext();
+		context.url = url;
+		context.ref_url = url;
+		var params = "";
+		params = StumbleGlobals.arp(params, "url", url); 
+		params = StumbleGlobals.arp(params, "blkdomain", -1); 
+		params = StumbleGlobals.append_sync_params(params);
+		StumbleGlobals.post_url_server_async(
+					"unrate.php",
+					params,
+					null,
+					StumbleGlobals.unrate_done,
+					context);
+	}
+	else
+	{
+		StumbleGlobals.rate(rating, false, true, false, blk_domain, url);
+	}
+}
+
+// Handler for button "rate"
+StumbleGlobals.rate = function(r, open_reviews, force_nostumble, force_comment, blk_domain, opt_url) 
+{
+	StumbleGlobals.register_activity("rate");
+	StumbleGlobals.check_progress_listener();
+	try {
+		StumbleGlobals.close_info();
+	} catch (e) {}
+	
+	// If we are opening a comment button in a new tab
+	// we shouldn't be stumbling
+	if (open_reviews)
+		force_nostumble = true;
+
+	if ((StumbleGlobals.stumbleid == 0) && (! StumbleGlobals.promo_mode))
+		return;
+	
+	var rating = r;
+
+	var theurl = (opt_url) ? opt_url : StumbleGlobals.get_browser_url();
+
+//	StumbleGlobals.dd("rate", theurl, StumbleGlobals.stumbled_redirect);
+	
+//	return;
+	
+	
+	if (StumbleGlobals.stumbled_redirect != '' && theurl == StumbleGlobals.stumbled_redirect)
+	{
+		// we have a redirect, rate the original url we stumbled on
+		theurl = StumbleGlobals.stumbled_url;
+	}
+
+	if (rating > 0)
+	{
+		// We try to keep our own local thumbup count but defer to the server when it sends an
+		// SFC command
+		StumbleGlobals.ds.incrementValue("$thumbup_count");
+		StumbleGlobals.thumbup_count_changed();
+	}
+	else
+		StumbleGlobals.ds.incrementValue("$thumbdown_count");
+	
+	var sv_detail = StumbleGlobals.get_stumblevideo_detail();
+				
+	if (sv_detail &&
+				(! ((StumbleGlobals.ds.getValue("$bad_stumble", false) && rating <= 0)
+				|| (StumbleGlobals.ds.getValue("$great_stumble", false) && rating == 1))))
+	{
+		var doc = getBrowser().contentDocument;
+
+		StumbleGlobals.stumblevideo_toolbar_rate = true;
+		if (rating == 1)
+			StumbleGlobals.dispatch_click(doc, "thumbUp");
+		else if (rating <= 0)
+			StumbleGlobals.dispatch_click(doc, "thumbDown");
+
+		return;
+	}
+	else if (sv_detail)
+	{
+		theurl = sv_detail.url;
+	}
+	
+	var cmp_url = theurl.toLowerCase();
+	if (cmp_url.indexOf("http://video." + StumbleGlobals.servername + "/#p") == 0)
+		return;
+				
+	if (cmp_url.indexOf("http://video." + StumbleGlobals.servername + "/?p") == 0)
+		return;
+
+	// grey out the buttons until the rating goes through
+	StumbleGlobals.get_element("stumbleglobals_thumbup").disabled=true;
+	StumbleGlobals.get_element("stumbleglobals_thumbdown").disabled=true;
+	StumbleGlobals.get_element("stumbleglobals_thumbup").setAttribute("onclick", "");
+
+	StumbleGlobals.quote = "";
+	if (getBrowser().contentWindow.getSelection)
+		StumbleGlobals.quote = getBrowser().contentWindow.getSelection().toString();
+
+	var charset = "";
+	var webShell = getBrowser().docShell.QueryInterface(Components.interfaces.nsIDocCharset);
+	if (webShell)
+		charset = webShell.charset;
+	
+	var doc = getBrowser().contentDocument;
+	var context = new StumbleGlobals.AsyncContext();
+	context.rating = rating;
+	context.url = theurl;
+	context.ref_url = StumbleGlobals.get_browser_url(doc, true);
+	context.browser = getBrowser().selectedBrowser;
+	context.title = StumbleGlobals.get_title(doc, context.ref_url);
+	context.force_nostumble = force_nostumble;
+	context.force_comment = force_comment;
+	context.timestamp = (new Date()).getTime();
+	context.open_reviews = open_reviews;
+	context.charset = charset;
+	context.referrer = doc.referrer;
+	context.stumblevideo_mode = null;
+	context.blk_domain = blk_domain;
+	
+	var postdata = "rating=" + rating + 
+					'&url=' + encodeURIComponent(theurl) + 
+					"&charset=" + encodeURIComponent(charset) + 
+					"&referer=" + encodeURIComponent(context.referrer) +
+					"&blkdomain=" + blk_domain;
+	
+	if (sv_detail)
+		postdata += "&videoperma=1";
+	
+	postdata = StumbleGlobals.append_sync_params(postdata);
+	
+	StumbleGlobals.post_url_server_async(
+				"rate.php",
+				postdata,
+				null,
+				StumbleGlobals.rate_done,
+				context);
+	
+	StumbleGlobals.check_progress_listener();
+}
+
+StumbleGlobals.current_url_stumbled = function()
+{
+	var theurl = StumbleGlobals.get_browser_url();
+	return theurl && ((theurl == StumbleGlobals.stumbled_url) || (theurl == StumbleGlobals.stumbled_redirect));
+}
+
+StumbleGlobals.process_showpopup_command = function(command_parts, context)
+{
+	// This functionality is only supported in Gecko 1.9 or later (i.e. Firefox 3+)
+	if(!StumbleGlobals.gecko19orlater)
+		return;
+	
+	// Options are formatted like a querystring
+	var options = command_parts[1];
+	var parts = options.split("&");
+	var parsed_options = {};
+	for(var i=0; i<parts.length; i++)
+	{
+		var pieces = parts[i].split("=");
+		parsed_options[decodeURIComponent(pieces[0])] = decodeURIComponent(pieces[1]);
+	}
+
+	// Get target URL, width, height
+	var targetUrl = parsed_options['url'];
+	var width = parseInt(parsed_options['width']);
+	var height = parseInt(parsed_options['height']);
+	
+	// Get the anchor element
+	var anchor = document.getElementById(parsed_options['anchor']);
+	if(!anchor)
+		return;
+	
+	// Create the panel element
+	var apanel = document.createElement("panel");
+	document.getElementById('main-window').appendChild(apanel);
+
+	// Create the frame
+	var frame = document.createElement("iframe");
+	frame.setAttribute("type", "content");
+	frame.setAttribute("style", "margin:0px;padding:0px");
+	frame.id = "theFrame";
+	frame.width = width;
+	frame.height = height;
+	apanel.appendChild(frame);
+	
+	// Listen for the load event so we can add the custom event listeners	
+	frame.addEventListener("load", function()
+	{
+		frame.contentDocument.addEventListener("hidePopup", function() {
+			apanel.hidePopup();
+		}, false);
+		frame.contentDocument.addEventListener("closePopup", function() {
+			// Hide it before removing it, or it will leave an artifact on OSX/Fx 3.6
+			apanel.hidePopup();
+			apanel.parentNode.removeChild(apanel);
+		}, false);
+		frame.contentDocument.addEventListener("showPopup", function() {
+			apanel.openPopup(anchor, 'after_start', 0, 0, true, false);
+		}, false);
+	}, true);
+	frame.setAttribute("src", targetUrl);
+	
+	// Display the panel
+	apanel.openPopup(anchor, 'after_start', 0, 0, true, false);
+}
+
+StumbleGlobals.rate_done = function(res)
+{
+	try {
+		if (res.status == 1)
+		{
+			StumbleGlobals.enable_toolbar();
+			return;
+		}
+	} catch (e) { return; }
+	
+	if (res.status != 200)
+	{
+		StumbleGlobals.http_error(res.error, res.status);
+		StumbleGlobals.enable_toolbar();
+		return;
+	}
+	
+	var context = res.detail;
+	
+	if (context.browser == getBrowser().selectedBrowser)
+	{
+		if ((context.stumblevideo_mode == "page") || 
+					(! StumbleGlobals.ds.getValue("$bad_stumble") && 
+						(context.rating <= 0)) || 
+					(! StumbleGlobals.ds.getValue("$great_stumble") && 
+						(context.rating == 1))) 
+			StumbleGlobals.disable_toolbar(context.rating);
+	}
+	
+	
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+	
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response rate.php", s);
+	
+	// Parse response text
+	var parsed = s.split("\n");
+	var prepend = "";
+	var discovery = false;
+	var firstrate = 0;
+	var canceled = false;
+	
+	// Iterate through commands
+	for (var i = 0; i < parsed.length; i++)
+	{
+		if (parsed[i] == "")
+			continue;
+
+		// Parse command structure
+		var command = parsed[i].split(" ");
+		switch(command[0])
+		{
+			case "URL": prepend += command[1] + "\n"; break;
+			case "FIRSTRATER": firstrate = command[1]; break;
+			case "NEWURL" : 
+				// do 800x600+
+				if (context.rating == 1)
+				{
+					discovery = true;
+					StumbleGlobals.disable_toolbar(context.rating);
+					var detail = new Object();
+					detail.finalized = false;
+					detail.submitted = false;
+					detail.url = context.url;
+					detail.uri_suffix = "newurl.php";
+					detail.tagtext = "";
+					detail.postdata = "url=" + encodeURIComponent(context.url) + 
+								"&title=" + encodeURIComponent(context.title) + 
+								"&charset=" + encodeURIComponent(context.charset) + 
+								"&rating=" + context.rating + 
+								"&quote=" + encodeURIComponent(StumbleGlobals.quote) + 
+								"&referer=" + encodeURIComponent(context.referrer) +
+								"&catidlist=" + encodeURIComponent('');
+	
+					if (StumbleGlobals.photoblogimage)
+					{
+						detail.postdata += "&image=" + encodeURIComponent(StumbleGlobals.photoblogimage.src) + 
+									"&width=" + StumbleGlobals.photoblogimage.width + 
+									"&height=" + StumbleGlobals.photoblogimage.height;
+						StumbleGlobals.photoblogimage = null;
+					}
+		
+					var width = (command.length >= 2) ? parseInt(command[1]) : 700;
+					var height = (command.length >= 3) ? parseInt(command[2]) : 450;
+					
+					var dialog_url = "chrome://stumbleupon/content/discoveryDialog.xul";
+					dialog_url += "#d" + StumbleGlobals.ds.incrementValue("~discovery_count");
+					
+					StumbleGlobals.ds.define("disc_dialog_url:disc_detail", dialog_url, detail);
+					StumbleGlobals.ds.addEventListener(
+							"discdlgclose",
+							function (event) {
+								window.StumbleGlobals.handle_discovery_dialog_close(event); });
+					
+					window.openDialog(
+								dialog_url,
+								"",
+								"chrome,dialog,centerscreen,width=" + width + 
+									",height=" + height + 
+									",resizable=1",
+								detail);
+					
+					// calculate this before we get the add comment
+					var da = new Date();
+					var now = da.getTime();
+					// Store in list of rated urls
+					
+					StumbleGlobals.store_rating(context.url, (StumbleGlobals.d_rec_rating) ? 2 : context.rating);
+				}
+				else if ((context.rating <= 0) && 
+							(context.browser == getBrowser().selectedBrowser))
+				{
+					var tmpres = new Object();
+					tmpres.detail = new StumbleGlobals.AsyncContext();
+					tmpres.detail.url = context.url;
+					tmpres.status = 200;
+					tmpres.responseText = "";
+					StumbleGlobals.unrate_done(tmpres);
+					canceled = true;
+					if (context.blk_domain == 0)
+						setTimeout(StumbleGlobals.show_thumbdown_discovery_alert, 0);
+				}
+				
+				var time_between_tagging = now - StumbleGlobals.last_typed_tag;
+				var i_just_stumbled = false;
+								
+				return;
+			default:
+				StumbleGlobals.process_command(parsed[i], context, command);
+				if (context.error)
+				{
+					StumbleGlobals.enable_toolbar();
+					return;
+				}
+				break;
+		}
+	}
+	
+	setTimeout(StumbleGlobals.refresh_pagemeta, 0, false, 9);
+	
+	if (canceled)
+		return;
+	
+	if ((context.rating == 1) && (! discovery))
+	{
+		if (! StumbleGlobals.ds.getValue("$shown_reviews_info"))
+			StumbleGlobals.display_info("reviews");
+		else if (! StumbleGlobals.ds.getValue("$shown_referral_info"))
+			StumbleGlobals.display_info("referral");
+	}
+	
+	// Store in list of rated urls
+	StumbleGlobals.store_rating(context.url, (StumbleGlobals.d_rec_rating) ? 2 : context.rating);
+
+	// Prepend URLs if we got any
+	if (prepend != "")
+	{
+		prior = StumbleGlobals.read_file_user("stumbleurls");
+		StumbleGlobals.write_file_user("stumbleurls", prepend + prior);
+	}
+
+	var searchbox_value = StumbleGlobals.get_element("stumbleglobals_searchbox").value;
+	if ((! StumbleGlobals.ds.getValue("$show_field")) || (searchbox_value == StumbleGlobals.tag_instructions))
+		searchbox_value = "";
+		
+	// calculate this before we get the add comment
+	var now = (new Date()).getTime();
+	var time_between_tagging = now - StumbleGlobals.last_typed_tag;
+	var opened_website_info = false;
+	if (StumbleGlobals.photoblogimage)
+	{
+		opened_website_info = true;
+		StumbleGlobals.website_info(false, context.url, firstrate);
+	}
+//	else if (context.force_comment || ((! context.open_reviews) && 
+//				StumbleGlobals.ds.getValue("$comment_firstrating") && firstrate != 0))
+//	{
+//		StumbleGlobals.unfocus_searchbox();
+//
+//		window.openDialog(
+//					"chrome://stumbleupon/content/ratingDialog.xul",
+//					"StumbleUpon Review",
+//					"chrome,modal,dialog,centerscreen,dependent", 
+//					context.url, 
+//					firstrate, 
+//					searchbox_value,
+//					StumbleGlobals.quote);
+//	}
+	
+	var tag_term = StumbleGlobals.get_element('stumbleglobals_searchbox').value;
+	
+	// if they've typed a tag in within the last 10 seconds, tag it
+	if (context.rating == 1 && tag_term != '' && StumbleGlobals.last_typed_tag != 0 && time_between_tagging < 1000 * 6)
+	{
+		StumbleGlobals.tagit(context.url, tag_term, false, context.title, context.ref_url);
+		
+		// clear it once we are done..
+		StumbleGlobals.last_typed_tag = 0;
+		StumbleGlobals.old_search = '';
+		//StumbleGlobals.get_element('stumbleglobals_searchbox').value = '';
+	}
+		
+	var i_just_stumbled = false;
+	
+	// Stumble-On-Rate
+	if ( (! context.force_nostumble) &&
+		StumbleGlobals.current_url_stumbled() &&
+		((StumbleGlobals.ds.getValue("$bad_stumble") && context.rating <= 0)
+		|| (StumbleGlobals.ds.getValue("$great_stumble") && context.rating == 1)) ) 
+	{
+		StumbleGlobals.stumble(0);	
+		i_just_stumbled = true;
+	}
+	
+	if ((! opened_website_info) && (! i_just_stumbled) && 
+				context.open_reviews && (context.rating == 1) && 
+				(context.stumblevideo_mode != "page"))
+	{
+		StumbleGlobals.website_info(0, context.url, 0);
+	}
+	
+	StumbleGlobals.check_progress_listener();
+}
+
+StumbleGlobals.prepare_thumbdown_menu = function()
+{
+	var url = StumbleGlobals.get_browser_url();
+	
+	var rating = StumbleGlobals.get_rating(url, (StumbleGlobals.get_stumblevideo_detail() != null));
+		
+	// Handle checks
+	StumbleGlobals.get_element('stumbleglobals_thumbdown_menu_notforme').setAttribute("checked", ((rating == -2) || (rating == 0))); 
+	StumbleGlobals.get_element('stumbleglobals_thumbdown_menu_spam').setAttribute("checked", (rating == -5));
+	StumbleGlobals.get_element('stumbleglobals_thumbdown_menu_dupe').setAttribute("checked", (rating == -3));
+//	StumbleGlobals.get_element('stumbleglobals_thumbdown_menu_saturation').setAttribute("checked", (rating == -4));
+
+	if (! StumbleGlobals.host.places)
+	{
+		StumbleGlobals.get_element('stumbleglobals_thumbdown_menu_blockdomain').hidden = true;
+		StumbleGlobals.get_element("stumbleglobals_thumbdown_menu_separator").hidden = true;
+		return;
+	}
+	StumbleGlobals.get_element("stumbleglobals_thumbdown_menu_separator").hidden = false;
+	
+	var el = StumbleGlobals.get_element('stumbleglobals_thumbdown_menu_blockdomain');
+	el.hidden = false; // for good measure
+
+	// Handle block domain label
+	
+	var domain = StumbleGlobals.get_tld(url);
+
+	if (domain == null)
+	{
+		el.disabled = true;
+		el.label = "Website: ''";
+		el.setAttribute("checked", "false");
+	}
+	else if (domain == StumbleGlobals.servername)
+	{
+		el.disabled = true;
+		el.label = "Website: '" + domain + "'";
+		el.setAttribute("checked", "false");
+	}
+	else if (StumbleGlobals.is_domain_blocked(domain))
+	{
+		el.disabled = false
+		el.label = "Unblock website: '" + domain + "'";
+		el.setAttribute("checked", "true");
+	}
+	else
+	{
+		el.disabled = false
+		el.label = "Block website: '" + domain + "'";
+		el.setAttribute("checked", "false");
+	}
+}
+
+StumbleGlobals.show_thumbdown_discovery_alert = function()
+{
+
+	var promptService = StumbleGlobals.get_service(
+				"@mozilla.org/embedcomp/prompt-service;1",
+				"nsIPromptService");
+	
+	promptService.alert(
+			window,
+			"Rating Canceled",
+			"You can't rate this page because it's not part of StumbleUpon's directory. You can add a page to StumbleUpon by thumbing it up. But if you don't like the page, don't add it!");
+}
+
+StumbleGlobals.handle_discovery_dialog_close = function(event)
+{
+	var detail = StumbleGlobals.ds.lookup("disc_dialog_url:disc_detail", event.URL);
+	
+	if (detail.finalized)
+		return;
+	
+	detail.finalized = true;
+	
+	if (detail.submitted)
+	{
+		StumbleGlobals.rate_getmeta(detail.url, true);
+		
+		if (detail.tagtext != "")
+		{
+			var count = StumbleGlobals.ds.getValue("$tagged_discovery_count");
+			count ++;
+			StumbleGlobals.ds.setValue("$tagged_discovery_count", count);
+			if (count == 3)
+			{
+				StumbleGlobals.ds.setValue("$show_tag", true);
+				StumbleGlobals.ds.setValue("$shown_tag", true);
+				StumbleGlobals.ds.setValue("$show_flag", true);
+				StumbleGlobals.set_visible("stumbleglobals_tag",  StumbleGlobals.ds.getValue("$show_field"));
+				StumbleGlobals.set_visible("stumbleglobals_tag2", (! StumbleGlobals.ds.getValue("$show_field")));
+	//			setTimeout(
+	//						alert,
+	//						500,
+	//						"For convenience, the Tag control has been added to the toolbar.\nIf this is unwelcome, you can remove it via:\ntoolbar->Tools->Toolbar Options.");
+			}
+			
+			var tag = StumbleGlobals.normalize_tag(detail.tagtext);
+		
+			StumbleGlobals.load_tags(detail.url);
+			
+			// Add the new tag
+			var o = new Object();
+			o.url = detail.url;
+			o.tag_list = tag;
+			StumbleGlobals.tag_lists_by_url[detail.url] = tag;
+			StumbleGlobals.tags.unshift(o);
+			
+			StumbleGlobals.store_tags();
+		
+			StumbleGlobals.disable_tag_toolbar(tag);
+			StumbleGlobals.old_search = tag;
+		}
+	}
+	else
+	{
+		var context = new StumbleGlobals.AsyncContext();
+		context.url = detail.url;
+		context.ref_url = context.url;
+		context.quiet = true;
+		context.discoveryCancelled = true;
+		var params = "url=" + encodeURIComponent(context.url); 
+	
+		params = StumbleGlobals.append_sync_params(params);
+	
+		StumbleGlobals.post_url_server_async(
+					"unrate.php",
+					params,
+					null,
+					StumbleGlobals.unrate_done,
+					context);
+	}
+	StumbleGlobals.check_progress_listener();
+}
+
+StumbleGlobals.prepare_reporting_menu = function(submenu, url_detail, tools_menu, url)
+{
+	var stumbler_name = StumbleGlobals.get_profile_nickname(url);
+	
+	var item;
+	if (! tools_menu)
+	{
+		item = document.createElement("menuitem");
+		item.setAttribute("label", "This stumble is:");
+		item.setAttribute("style", "font-weight: bold; color: #404040;");
+		item.setAttribute("disabled", "true");
+		submenu.appendChild(item);
+	}
+	
+	if (! stumbler_name)
+	{
+		item = document.createElement("menuitem");
+		item.setAttribute("label", " Broken or 404");
+		item.setAttribute("tooltiptext", "Report that this page is broken");
+		item.setAttribute("oncommand", "StumbleGlobals.handle_report_404_command('" + url + "');");
+		submenu.appendChild(item);
+	}
+
+	item = document.createElement("menuitem");
+	item.setAttribute("label", " Factually incorrect");
+	item.setAttribute("tooltiptext", "Report that this page contains bogus info");
+	item.setAttribute("oncommand", "StumbleGlobals.handle_report_inaccurate_command('" + url + "');");
+	submenu.appendChild(item);
+	
+	if (tools_menu)
+	{
+		if (stumbler_name)
+		{
+			item = document.createElement("menuitem");
+			item.setAttribute("label", " Adult content...");
+			item.setAttribute("tooltiptext", "Report that the " + stumbler_name + " profile contains adult content");
+			item.setAttribute("oncommand", "StumbleGlobals.handle_report_adult_profile_command('" + url + "');");
+			submenu.appendChild(item);
+		}
+		else
+		{
+			item = document.createElement("menuitem");
+			if (url_detail)
+				item.setAttribute("label", " Not about " + url_detail.cur_topic_name + "...");
+			else
+				item.setAttribute("label", " Suggest topic change...");
+			item.setAttribute("tooltiptext", "Choose a different topic for this page");
+			item.setAttribute("oncommand", "StumbleGlobals.handle_report_miscat_command('" + url + "');");
+			submenu.appendChild(item);
+		}
+	}
+	
+	if (url_detail && url_detail.language)
+	{
+		item = document.createElement("menuitem");
+		item.setAttribute("label", " Not in " + url_detail.language + "...");
+		item.setAttribute("tooltiptext", "Choose a different language for this page");
+		item.setAttribute("oncommand", "StumbleGlobals.handle_report_wrong_language_command('" + url + "');");
+		submenu.appendChild(item);
+	}
+
+	item = document.createElement("menuitem");
+	item.setAttribute("label", " Spam...");
+	item.setAttribute("tooltiptext", "Report this as bad solicitation");
+	item.setAttribute("oncommand", "StumbleGlobals.handle_report_spam_command('" + url + "');");
+	submenu.appendChild(item);
+
+	item = document.createElement("menuitem");
+	item.setAttribute("label", " Unsafe");
+	item.setAttribute("tooltiptext", "Report that this page is a security risk");
+	item.setAttribute("oncommand", "StumbleGlobals.handle_report_badware_command('" + url + "');");
+	submenu.appendChild(item);
+}
+
+StumbleGlobals.prepare_stumble_report_menu = function(event, url)
+{
+	if (event.originalTarget.id != "stumbleglobals_stumble_report_popup")
+		return;
+	
+	var submenu = StumbleGlobals.get_element("stumbleglobals_stumble_report_popup");
+
+	if (submenu.getAttribute("data-url") == url)
+		return;
+	
+	submenu.removeAttribute("data-url");
+	submenu.setAttribute("data-url", url);
+
+	// Check if a menu already exists -> If so, we need to remove it
+	var url_detail = StumbleGlobals.ds.lookup("url:url_detail", url);
+	
+	while(submenu.childNodes.length)
+		submenu.removeChild(submenu.firstChild);
+	
+	StumbleGlobals.prepare_reporting_menu(submenu, url_detail, true, url);
+}
+
+/*
+// handles discovery dialog accept
+StumbleGlobals.handle_discovery_dialog_accept = function(detail)
+{
+	if (detail.tagtext != "")
+	{
+		var count = StumbleGlobals.ds.getValue("$tagged_discovery_count");
+		count ++;
+		StumbleGlobals.ds.setValue("$tagged_discovery_count", count);
+		if (count == 3)
+		{
+			StumbleGlobals.ds.setValue("$show_tag", true);
+			StumbleGlobals.ds.setValeu("$shown_tag", true);
+			StumbleGlobals.ds.setValue("$show_flag", true);
+			StumbleGlobals.set_visible("stumbleglobals_tag",  StumbleGlobals.ds.getValue("$show_field"));
+			StumbleGlobals.set_visible("stumbleglobals_tag2", (! StumbleGlobals.ds.getValue("$show_field")));
+//			setTimeout(
+//						alert,
+//						500,
+//						"For convenience, the Tag control has been added to the toolbar.\nIf this is unwelcome, you can remove it via:\ntoolbar->Tools->Toolbar Options.");
+		}
+	}
+}
+
+// handles discovery dialog cancel
+StumbleGlobals.handle_discovery_dialog_cancel = function(detail, state)
+{
+	var context = new StumbleGlobals.AsyncContext();
+	context.url = detail.rated_uri;
+	context.ref_url = context.url;
+	var params = "url=" + encodeURIComponent(context.url); 
+
+	params = StumbleGlobals.append_sync_params(params);
+
+	StumbleGlobals.post_url_server_async(
+				"unrate.php",
+				params,
+				null,
+				StumbleGlobals.unrate_done,
+				context);
+
+	StumbleGlobals.check_progress_listener();
+}
+*/
+
+// used by ratingDialog to add a comment
+//StumbleGlobals.add_review = function(urlid, review)
+//{
+//	StumbleGlobals.post_url_server_async(
+//				"addcomment.php",
+//				"urlid=" + urlid + 
+//					"&comment=" + encodeURIComponent(review),
+//				null,
+//				null,
+//				null);
+//}
+
+StumbleGlobals.handle_error = function(error)
+{
+	StumbleGlobals.set_server_location('error.php?error=' + error, null, false);
+}
+
+StumbleGlobals.disabled_button_color = null;
+
+//
+// Get the color used by the current theme for disabled buttons because we want to
+// use that same color for an active thumbup button (but without disabling it)
+//
+StumbleGlobals.get_disabled_button_color = function()
+{
+	if(!StumbleGlobals.disabled_button_color)
+	{
+		try
+		{
+			// Get the current thumbup state 
+			var elThumbup = StumbleGlobals.get_element("stumbleglobals_thumbup");
+			var oldMode = elThumbup.getAttribute("mode");
+			var oldDisabled = elThumbup.disabled;
+			
+			// Disable the button and remove the mode so we can compute the disabled style
+			StumbleGlobals.remove_attribute("stumbleglobals_thumbup", "mode");
+			elThumbup.disabled = true;
+			var disabledStyle = document.defaultView.getComputedStyle(elThumbup, "");
+			
+			// Restore the thumbup button to its original state
+			if(oldMode)
+				elThumbup.setAttribute("mode", oldMode);
+			elThumbup.disabled = oldDisabled;
+			
+			// And grab the disabled button color from the computed stylesheet
+			if(disabledStyle.color)
+			{
+				StumbleGlobals.disabled_button_color = disabledStyle.color;
+			}
+		}
+		catch(ex)
+		{
+			// We are being defensive here because this code is being added late in a release cycle and I'm nervous
+			// about support for getComputedStyle
+		}
+		
+		if(!StumbleGlobals.disabled_button_color)
+		{
+			StumbleGlobals.disabled_button_color = "GrayText";
+		}
+	}
+	return StumbleGlobals.disabled_button_color;
+}
+			
+
+// Greys out one of the rating buttons
+StumbleGlobals.disable_toolbar = function(rating)
+{
+	// enable everything first so we don't get StumbleGlobals.website_info collisions?
+	
+	StumbleGlobals.set_image("stumbleglobals_website_info",
+				"chrome://stumbleupon/content/skin/comment.png");
+	
+	// We use the disabled color for the thumbup button text when the user has already 
+	// rated the site
+	var disabledColor = StumbleGlobals.get_disabled_button_color();
+	StumbleGlobals.get_element("stumbleglobals_thumbup").style.color = disabledColor;
+	
+	if (rating > 0)
+	{
+		StumbleGlobals.set_attribute("stumbleglobals_thumbup", "mode", "thumbup");
+		StumbleGlobals.set_attribute("stumbleglobals_thumbdown", "mode", "thumbup");
+		StumbleGlobals.set_image("stumbleglobals_referral_menu", 
+					"chrome://stumbleupon/content/skin/icon_tb_share2.png");
+	}
+	else
+	{
+		StumbleGlobals.set_attribute("stumbleglobals_thumbup", "mode", "thumbdown");
+		StumbleGlobals.set_attribute("stumbleglobals_thumbdown", "mode", "thumbdown");
+		StumbleGlobals.set_image("stumbleglobals_referral_menu", 
+					"chrome://stumbleupon/content/skin/icon_tb_share.png");
+	}
+
+	StumbleGlobals.toolbar_disabled = true;
+}
+
+// Un-greys all the rating buttons
+StumbleGlobals.enable_toolbar = function()
+{
+	StumbleGlobals.toolbar_disabled = false;
+	StumbleGlobals.remove_attribute("stumbleglobals_thumbup", "mode");
+	StumbleGlobals.get_element("stumbleglobals_thumbup").style.color = '';
+	StumbleGlobals.remove_attribute("stumbleglobals_thumbdown", "mode");
+	StumbleGlobals.get_element("stumbleglobals_thumbup").disabled = false;
+	StumbleGlobals.get_element("stumbleglobals_thumbdown").disabled = false;
+	if (!StumbleGlobals.get_element("stumbleglobals_website_info").image.indexOf('bubble'))
+		StumbleGlobals.get_element("stumbleglobals_website_info").image="chrome://stumbleupon/content/skin/bubble.png";
+	
+	StumbleGlobals.set_image("stumbleglobals_referral_menu", 
+				"chrome://stumbleupon/content/skin/icon_tb_share.png");
+}
+
+// called by the global configure-toolbar event, during init and by
+// the searchbox context menuitem listeners to set the autocomplete
+// type for the searchbox
+StumbleGlobals.set_autocomplete_type = function(type)
+{
+	var oldval = StumbleGlobals.ds.getValue("$autocomplete_type");
+	
+	var searchbox = StumbleGlobals.get_element('stumbleglobals_searchbox');
+	if ((type == "auto") && (oldval == "query"))
+		type = "query,tag";
+	else if ((type == "auto") && (oldval == "tag"))
+		type = "tag,query";
+	
+	if (type == "query,tag")
+	{
+		searchbox.contextItemAChecked = true;
+		searchbox.contextItemBChecked = false;
+		searchbox.contextItemCChecked = false;
+		StumbleGlobals.ds.setValue("$autocomplete_type", "query,tag");
+	}
+	else if (type == "tag,query")
+	{
+		searchbox.contextItemAChecked = true;
+		searchbox.contextItemBChecked = false;
+		searchbox.contextItemCChecked = false;
+		StumbleGlobals.ds.setValue("$autocomplete_type", "tag,query");
+	}
+	else if (type == "query")
+	{
+		StumbleGlobals.ds.setValue("$autocomplete_type", "query");
+		searchbox.contextItemAChecked = false;
+		searchbox.contextItemBChecked = true;
+		searchbox.contextItemCChecked = false;
+	}
+	else if (type == "tag")
+	{
+		StumbleGlobals.ds.setValue("$autocomplete_type", "tag");
+		searchbox.contextItemAChecked = false;
+		searchbox.contextItemBChecked = false;
+		searchbox.contextItemCChecked = true;
+	}
+
+	if (oldval != type)
+		searchbox.open = false;
+}
+
+// handles the click event for the searchbox
+StumbleGlobals.searchbox_click_kludge = function(eventId)
+{
+	// This handles value selection in the case where the user is 
+	// clicking back and forth between the searchbox and another field 
+	// (like urlbar).  Without this kludge, the text is selected only
+	// every second time.  (ref: Firefox 1.5, XP) -- JW
+	
+	switch (eventId)
+	{
+		case "click":
+			var searchbox = StumbleGlobals.get_element('stumbleglobals_searchbox');
+			var selected = (searchbox.value.length != 0)
+						&& ((searchbox.selectionEnd - searchbox.selectionStart) == searchbox.value.length);
+
+			if ((! StumbleGlobals.searchbox_was_focused) && (! selected))
+				searchbox.select();
+			
+			StumbleGlobals.searchbox_was_focused = true;
+		break;
+		case "blur":
+			StumbleGlobals.searchbox_was_focused = false;
+		break;
+	}
+
+	return true;
+}
+
+// handles the focus event for the searchbox
+StumbleGlobals.handle_searchbox_focus = function(event)
+{
+	var searchbox = StumbleGlobals.get_element('stumbleglobals_searchbox');
+
+	StumbleGlobals.visited_searchbox = 1;
+	
+	if (searchbox.value == StumbleGlobals.tag_instructions)
+	{
+		searchbox.value = '';
+		searchbox.removeAttribute("mode");
+	}
+	else
+	{
+		if (StumbleGlobals.url_has_tag)
+		{	
+			StumbleGlobals.old_search = searchbox.value;
+
+			StumbleGlobals.enable_tag_toolbar();
+		}
+		
+		if (! StumbleGlobals.keep_searchbox_focus)
+			searchbox.select();
+	}
+}
+
+// handles the blur event for the searchbox
+StumbleGlobals.handle_searchbox_blur = function()
+{
+	StumbleGlobals.searchbox_click_kludge("blur");
+}
+
+// handles the keyup event for the searchbox
+StumbleGlobals.handle_searchbox_keyup = function(evt)
+{
+	var searchbox = StumbleGlobals.get_element('stumbleglobals_searchbox');
+
+	if(searchbox.value == StumbleGlobals.old_search)
+		return false;
+	
+	StumbleGlobals.old_search = searchbox.value;
+	
+	// save the time we last did this        	
+	var da = new Date();
+	StumbleGlobals.last_typed_tag = da.getTime();
+
+	searchbox.removeAttribute("mode");
+	
+	if (StumbleGlobals.old_search == "")
+		StumbleGlobals.get_element('stumbleglobals_tag').setAttribute("tooltiptext", StumbleGlobals.get_element('stumbleglobals_tag').getAttribute("tooltiptext2"));
+	else
+		StumbleGlobals.get_element('stumbleglobals_tag').setAttribute("tooltiptext", "Tag this page as '" + 	StumbleGlobals.get_element('stumbleglobals_searchbox').value + "'");
+
+	return true;
+}
+
+// handles the textentered event for the searchbox
+StumbleGlobals.handle_searchbox_textentered = function(event)
+{
+	var autocomplete_type = StumbleGlobals.ds.getValue("$autocomplete_type");
+	if (event.shiftKey)
+	{	
+		if (autocomplete_type == "query,tag")
+			StumbleGlobals.ds.setValue("$autocomplete_type", "tag,query");
+		
+		// Shift+Enter tags
+		StumbleGlobals.handle_tag_command(false);
+	}
+	else
+	{
+		if (autocomplete_type == "tag,query")
+			StumbleGlobals.ds.setValue("$autocomplete_type", "query,tag");
+		
+		StumbleGlobals.old_search = StumbleGlobals.get_element('stumbleglobals_searchbox').value;
+
+		// when you search, we know it's not a tag on i-like-it
+		StumbleGlobals.last_typed_tag = 0;
+
+		var new_tab = false;
+		var platform_ctrl_key = (StumbleGlobals.host.mac) ? ((event.keyCode == 77) ? event.ctrlKey : event.metaKey) : event.ctrlKey;
+
+		if ((event.button == 1) || platform_ctrl_key)
+			new_tab = true;
+		new_tab = new_tab || StumbleGlobals.ds.getValue("$search_new_window");
+	
+		var query = StumbleGlobals.get_element("stumbleglobals_searchbox").value;
+	
+		StumbleGlobals.stumble_in_tag(StumbleGlobals.get_element('stumbleglobals_searchbox').value, new_tab);	
+	}
+}
+
+// handles the textreverted event for the searchbox
+StumbleGlobals.handle_searchbox_textreverted = function()
+{
+	if (StumbleGlobals.old_search != "")
+	{
+		StumbleGlobals.get_element("stumbleglobals_searchbox").value = StumbleGlobals.old_search;
+		StumbleGlobals.get_element("stumbleglobals_searchbox").select();
+		StumbleGlobals.get_element("stumbleglobals_searchbox").removeAttribute("mode");
+	}
+	else if (StumbleGlobals.url_has_tag)
+	{
+		StumbleGlobals.disable_tag_toolbar(StumbleGlobals.tag_lists_by_url[StumbleGlobals.get_browser_url()]);
+	}
+}
+
+/*
+StumbleGlobals.handle_searchbox_pagenavigationkey = function(event)
+{
+	StumbleGlobals.keep_searchbox_focus = false;
+	StumbleGlobals.unfocus_searchbox();
+	setTimeout(function (win, event) { win.StumbleGlobals.handle_searchbox_pagenavigationkey_wrapped(event); } , 1000, window, event.keyCode);
+}
+
+StumbleGlobals.handle_searchbox_pagenavigationkey_wrapped = function(keyCode)
+{
+	var evt = document.createEvent("KeyboardEvent");
+	evt.initKeyEvent(
+				"keypress",        //  in DOMString typeArg,
+				true,             //  in boolean canBubbleArg,
+				true,             //  in boolean cancelableArg,
+				null,             //  in nsIDOMAbstractView viewArg,  Specifies UIEvent.view. This value may be null.     
+				false,            //  in boolean ctrlKeyArg,
+				false,            //  in boolean altKeyArg,
+				false,            //  in boolean shiftKeyArg,
+				false,            //  in boolean metaKeyArg,
+				keyCode,         //  in unsigned long keyCodeArg,
+				0);              //  in unsigned long charCodeArg);
+	getBrowser().dispatchEvent(evt);
+//	StumbleGlobals.get_element("stumbleglobals_searchbox").focus();
+}
+*/
+
+StumbleGlobals.get_autocomplete_results = function(autocomplete_type, str, max_item_count, supplemental_candidates)
+{
+	var types = autocomplete_type.split(",");
+	
+	var i;
+	var items = new Array();
+	for (i = 0; i < types.length; i++)
+		items = StumbleGlobals.get_autocomplete_results2(types[i], str, max_item_count, items, supplemental_candidates);
+	
+	return items;
+}
+
+// ultimately called by the searchbox to get an array of items to
+// populate the autocomplete list
+StumbleGlobals.get_autocomplete_results2 = function(autocomplete_type, str, max_item_count, items, supplemental_candidates)
+{
+	// Each array item is an object with properties that are analogous
+	// to attributes of the autocomplete list item.  In other words, 
+	// item.label results in the search widget doing something like:
+	// autocomplete-item.setAttribute("label", item.label);
+	// -- JW
+	
+	// Supplemental candidate matches are placed at the top of the 
+	// results.  Other items are ranked in the autocomplete list in the
+	// same order as they appear in the queries and tags files, which 
+	// is to say in reverse chronological order.  But we may want to 
+	// add a heuristic that places more frequently used tags & queries 
+	// near the top. -- JW
+	var pre_items_count = items.length;
+	var source;
+	var o;
+
+	if ((str == "") || (str == StumbleGlobals.tag_instructions))
+	{
+		// add recent items
+
+		if (autocomplete_type == "query")
+		{
+			StumbleGlobals.load_queries();
+			source = StumbleGlobals.queries;
+		}
+		else if (autocomplete_type == "tag")
+		{
+			StumbleGlobals.load_tags(null);
+			source = StumbleGlobals.tags;
+		}
+
+		for (var i = (- supplemental_candidates.length); (i < source.length) && (items.length <= max_item_count); i++)
+		{
+			var candidate;
+			if (i < 0)
+			{
+				candidate = supplemental_candidates[-i - 1];
+			}
+			else
+			{
+				if (source == StumbleGlobals.queries)
+					candidate = source[i];
+				else if (source == StumbleGlobals.tags)
+					candidate = source[i].tag_list;
+			}
+				
+			if (candidate.search(/^\s*$/) != -1)
+				continue;
+
+			var duplicate = false;
+			for (var j = 0; j < items.length; j++)
+			{
+				if (candidate == items[j].label)
+				{
+					duplicate = true;
+					if (j < pre_items_count)
+						items[j].style = "color:#ff3300;";
+					break;
+				}
+			}
+			if (! duplicate)
+			{
+				o = new Object();
+				o.label = candidate;
+				if (autocomplete_type == "tag")
+					o.style = "color:#ff3300;";
+				items.push(o);
+			}
+		}
+	}
+	else 
+	{
+		// add the subset of items
+		
+		if (autocomplete_type == "query")
+		{
+			if (str.length == 1)
+				StumbleGlobals.load_queries();
+			source = StumbleGlobals.queries;
+		}
+		else if (autocomplete_type == "tag")
+		{
+			if (str.length == 1)
+				StumbleGlobals.load_tags(null);
+			source = StumbleGlobals.tags;
+		}
+
+		str = StumbleGlobals.normalize_tag(str);
+		str = StumbleGlobals.escape_regexp_chars(str);
+
+		var pattern = new RegExp("^" + str + "|, " + str, "i");
+
+		for (var i = (- supplemental_candidates.length); (i < source.length) && (items.length <= max_item_count); i++)
+		{
+			var candidate
+			if (i < 0)
+			{
+				candidate = supplemental_candidates[-i - 1];
+			}
+			else
+			{
+				if (source == StumbleGlobals.queries)
+					candidate = source[i];
+				else if (source == StumbleGlobals.tags)
+					candidate = source[i].tag_list;
+			}
+
+			if (candidate.search(/^\s*$/) != -1)
+				continue;
+
+			if (candidate.search(pattern) != -1)
+			{
+				
+				var duplicate = false;
+				for (var j = 0; j < items.length; j++)
+				{
+					if (candidate == items[j].label)
+					{
+						duplicate = true;
+						if (j < pre_items_count)
+							items[j].style = "color:#ff3300;";
+						break;
+					}
+				}
+				if (! duplicate)
+				{
+					o = new Object();
+					o.label = candidate;
+					if (autocomplete_type == "tag")
+						o.style = "color:#ff3300;";
+					items.push(o);
+				}
+			}
+		}
+	}
+	
+//	o = new Object();
+//	o.style = "-moz-binding: url(chrome://global/content/bindings/menu.xml#menuitem-iconic);";
+//	o.image = "chrome://stumbleupon/content/skin/icon_tb_photo_hover.png";
+//	o.label = "Photos";
+//	items.push(o);
+	
+	return items;
+	
+}
+
+// adds tag to toolbar
+StumbleGlobals.disable_tag_toolbar = function(tag)
+{
+	if (!StumbleGlobals.url_has_tag)
+		StumbleGlobals.old_search = StumbleGlobals.get_element("stumbleglobals_searchbox").value;
+
+	StumbleGlobals.url_has_tag = true;
+	
+	StumbleGlobals.get_element("stumbleglobals_searchbox").value = tag;
+
+	// This timeout kludge fixes a bug where DOM change events aren't being 
+	// generated when setAttribute is called within the execution path of a
+	// textreverted event handler for the StumbleGlobals.searchbox.  (ref: Firefox 1.5, 
+	// XP) -- JW
+	setTimeout('StumbleGlobals.get_element("stumbleglobals_searchbox").setAttribute("mode", "tag")', 0);
+
+	StumbleGlobals.get_element("stumbleglobals_tag").image="chrome://stumbleupon/content/skin/tag2.png";
+	StumbleGlobals.get_element('stumbleglobals_tag').setAttribute("tooltiptext", "Page tagged as '" + tag + "'. Click to remove.");
+	StumbleGlobals.get_element("stumbleglobals_tag2").image="chrome://stumbleupon/content/skin/tag2.png";
+	StumbleGlobals.get_element('stumbleglobals_tag2').setAttribute("tooltiptext", "Page tagged as '" + tag + "'. Click to remove.");
+}
+
+// removes tag from toolbar
+StumbleGlobals.enable_tag_toolbar = function()
+{
+	StumbleGlobals.url_has_tag = false;
+
+	if (StumbleGlobals.visited_searchbox == 0)
+	{
+		StumbleGlobals.get_element("stumbleglobals_searchbox").value = StumbleGlobals.tag_instructions;
+		StumbleGlobals.get_element("stumbleglobals_searchbox").setAttribute("mode", "prompt");
+	}
+	else if (StumbleGlobals.old_search != "")
+	{
+		StumbleGlobals.get_element("stumbleglobals_searchbox").value = StumbleGlobals.old_search;
+		StumbleGlobals.get_element("stumbleglobals_searchbox").removeAttribute("mode");
+	}
+	else
+	{
+		StumbleGlobals.get_element("stumbleglobals_searchbox").removeAttribute("mode");
+	}
+
+	StumbleGlobals.get_element("stumbleglobals_tag").image="chrome://stumbleupon/content/skin/tag.png";
+	StumbleGlobals.get_element("stumbleglobals_tag2").image="chrome://stumbleupon/content/skin/tag.png";
+
+	if (StumbleGlobals.old_search == "")
+	{
+		StumbleGlobals.get_element('stumbleglobals_tag').setAttribute("tooltiptext", StumbleGlobals.get_element('stumbleglobals_tag').getAttribute("tooltiptext2"));
+		StumbleGlobals.get_element('stumbleglobals_tag2').setAttribute("tooltiptext", StumbleGlobals.get_element('stumbleglobals_tag2').getAttribute("tooltiptext2"));
+	}
+	else
+	{
+		StumbleGlobals.get_element('stumbleglobals_tag').setAttribute("tooltiptext", "Tag this page as '" + StumbleGlobals.old_search + "'");
+		StumbleGlobals.get_element('stumbleglobals_tag2').setAttribute("tooltiptext", "Tag this page as '" + StumbleGlobals.old_search + "'");
+	}
+
+	return true;
+}
+
+// StumbleGlobals.sign_up_page is the web site's sign up page
+StumbleGlobals.sign_up_page = function(url)
+{
+	StumbleGlobals.visited_login_page = true;
+	StumbleGlobals.verify_cookie_perms(false);
+	StumbleGlobals.ds.setValue("~visited_signup", true);
+	if (StumbleGlobals.is_server_page(url, "sign_up.php?pre2=login"))
+		StumbleGlobals.login_behavior_page();
+}
+
+StumbleGlobals.login_behavior_page = function()
+{
+	StumbleGlobals.visited_login_page = true;
+	setTimeout(StumbleGlobals.show_signin_dialog, 0);
+}
+
+StumbleGlobals.attach_api = function(doc)
+{
+	// Only do this for Gecko 1.9 or later because we are using wrappedJSObject for script interaction
+	// and that is risky with previous versions of Gecko.  We are technically only embedding the script
+	// in our own stumbleupon.com pages and presumably those are safe, but we want security in depth
+	// and this avoids additional risk if, for example, stumbleupon.com has an XSS vulnerability.
+	if(!StumbleGlobals.gecko19orlater)
+		return;
+	
+	try
+	{
+		var win = doc.defaultView.wrappedJSObject;
+		win.suExtensionApi = new StumbleGlobals.extension_api(win);
+	}
+	catch(ex)
+	{
+		// Older browsers might not support wrappedJSObject, be defensive here.
+	}
+}
+
+StumbleGlobals.wire_portal_links = function(doc)
+{
+	var el;
+	var links;
+	var i;
+	
+	//!!! This could be pretty expensive on pages with large link count.
+	//    Unfortunately, we link to login.php many places besides the
+	//    header (i.e. a send message error on the public view of
+	//    a Favorites page).
+//	el = doc.getElementById("headerLoginLink");
+//	if (el)
+//		el.addEventListener("click", StumbleGlobals.handle_page_login_click, true);
+	
+	el = doc.getElementById("downloadFavoritesLink");
+	if (el)
+		el.addEventListener("click", StumbleGlobals.handle_page_favorites_download_click, true);
+	
+	el = doc.getElementById("stumble_search");
+	if (el)
+		el.addEventListener("click", StumbleGlobals.handle_page_search_click, true);
+}
+
+StumbleGlobals.handle_page_login_click = function(event)
+{
+	setTimeout(StumbleGlobals.show_signin_dialog, 0);
+	return StumbleGlobals.cancel_event(event);
+}
+
+StumbleGlobals.handle_page_logout_click = function(event)
+{
+	if (StumbleGlobals.stumbleid == 0)
+		return true;
+	
+	setTimeout("StumbleGlobals.handle_logout(true)", 0);
+	
+	return StumbleGlobals.cancel_event(event);
+}
+
+StumbleGlobals.handle_page_favorites_download_click = function(event)
+{
+	var ps;
+	
+	if (! StumbleGlobals.host.places)
+	{
+		ps = StumbleGlobals.get_service(
+				"@mozilla.org/embedcomp/prompt-service;1",
+				"nsIPromptService");
+		ps.alert(window, "StumbleUpon", "You must have Firefox 3 or greater to download favorites.");
+		return;
+	}	
+	
+	if (StumbleGlobals.stumbleid == 0)
+	{
+		ps = StumbleGlobals.get_service(
+				"@mozilla.org/embedcomp/prompt-service;1",
+				"nsIPromptService");
+		ps.confirm(window, "StumbleUpon", "You must be signed-in to download favorites.");
+		return;
+	}
+	
+	setTimeout(StumbleGlobals.handle_download_favs_command, 0);
+	
+	return StumbleGlobals.cancel_event(event);
+}
+
+StumbleGlobals.handle_page_search_click = function(event)
+{
+	var el;
+	var doc = event.target.ownerDocument;
+	
+	el = doc.getElementById("search_q");
+	
+	if (el.value != "")
+		StumbleGlobals.stumble_in_tag(el.value, StumbleGlobals.new_tab(event));
+	
+	return StumbleGlobals.cancel_event(event);
+}
+
+// StumbleGlobals.signup_page is the sign up page that the toolbars sends them to.
+StumbleGlobals.signup_page = function(doc)
+{
+	StumbleGlobals.verify_cookie_perms(false);
+
+	var el;
+	el = doc.getElementById("interests");
+	if (el)
+		StumbleGlobals.set_legacy_user_interests(el.innerHTML);
+	
+	var init_toolbar = (doc.getElementById("signup_success") != null);
+	
+	el = doc.getElementById("challenge");
+	if (el && el.hasAttribute("value") && (el.getAttribute("value") != ""))
+	{
+		StumbleGlobals.init_new_user(el.getAttribute("value"), init_toolbar);
+	}
+	else if (init_toolbar)
+	{
+		StumbleGlobals.new_user = false;
+		var detail = new Object();
+		detail.skip_cookies = false;
+		detail.ignore_cookies = true;
+		detail.new_profile = true;
+		detail.new_user_prompt = true;
+		StumbleGlobals.invoke_global_event("login", detail);
+	}
+	else if (StumbleGlobals.stumbleid != 0)
+	{
+		StumbleGlobals.store_user_interests();
+		StumbleGlobals.refresh_category_selector_batched();
+	}
+}
+
+StumbleGlobals.login_page_after = function()
+{
+	var userid_saved = StumbleGlobals.stumbleid;
+	var profile_change = StumbleGlobals.process_cookies(false);
+	
+	if (profile_change && (StumbleGlobals.stumbleid != userid_saved))
+	{
+		var detail = new Object();
+		detail.skip_cookies = true;
+		detail.ignore_cookies = true;
+		detail.new_profile = profile_change.new_profile;
+		detail.new_user_prompt = false;
+		StumbleGlobals.invoke_global_event("login", detail);
+	}
+}
+
+StumbleGlobals.find_friends_page = function(url)
+{
+	StumbleGlobals.ds.setValue("~visited_find_friends", true);
+	var userid_saved = StumbleGlobals.stumbleid;
+	var profile_change = StumbleGlobals.process_cookies(false);
+	if (profile_change && (StumbleGlobals.stumbleid != userid_saved))
+	{
+		var detail = new Object();
+		detail.skip_cookies = true;
+		detail.ignore_cookies = true;
+		detail.new_profile = true;
+		detail.new_user_prompt = true;
+		StumbleGlobals.invoke_global_event("login", detail);
+	}
+	else
+	{
+		if (StumbleGlobals.ds.getValue("#find_friends_optin"))
+		{
+			StumbleGlobals.ds.incrementValue("$shown_find_friends_clicks");
+			if ((! StumbleGlobals.ds.getValue("$show_searchlinks_score")) &&
+						(! StumbleGlobals.ds.getValue("$show_searchlinks_friends")))
+			{
+				StumbleGlobals.ds.setValue("$show_searchlinks_score", true);
+				StumbleGlobals.ds.setValue("$show_searchlinks_friends", true);
+			}
+			else
+			{
+				StumbleGlobals.ds.setValue("$show_searchlinks_friends", true);
+			}
+			StumbleGlobals.ds.setValue("#find_friends_optin", false);
+		}
+	}
+	
+	if (StumbleGlobals.stumbleid)
+		StumbleGlobals.ds.setValue("$shown_find_friends", true);
+
+	StumbleGlobals.ds.flushPrefs();
+}
+
+StumbleGlobals.find_friends_after_page = function()
+{
+	StumbleGlobals.ds.setValue("$shown_find_friends", true);
+	
+	var now_s = StumbleGlobals.get_time_s();
+	var pre = StumbleGlobals.ds.getValue("#find_friends_pre");
+	if (pre == "facebook")
+		StumbleGlobals.ds.setValue("$imported_fbcontacts_time_s", now_s);
+	
+	else
+		StumbleGlobals.ds.setValue("$imported_contacts_time_s", now_s);
+	
+	StumbleGlobals.ds.setValue("#find_friends_pre", "");
+	
+	StumbleGlobals.ds.flushPrefs();
+	setTimeout("StumbleGlobals.import_contacts();", 15000);
+}
+
+StumbleGlobals.stumblevideo_page = function(doc, from_load)
+{
+	var el = doc.getElementById("url_command");
+
+	if (! el)
+		return;
+
+	StumbleGlobals.handle_stumblevideo_change(null, doc);
+
+	el.removeEventListener("DOMAttrModified", StumbleGlobals.handle_stumblevideo_change, false);
+	el.addEventListener("DOMAttrModified", StumbleGlobals.handle_stumblevideo_change, false);
+	
+	var el2 = doc.getElementById("login_count");
+	if (el2)
+	{
+		el2.removeEventListener("DOMAttrModified", StumbleGlobals.handle_stumblevideo_login, false);
+		el2.addEventListener("DOMAttrModified", StumbleGlobals.handle_stumblevideo_login, false);
+	}
+	
+	el = doc.getElementById("thumbUp");
+	if (el)
+	{
+		el.removeEventListener("DOMAttrModified", StumbleGlobals.handle_stumblevideo_rate, false);
+		el.addEventListener("DOMAttrModified", StumbleGlobals.handle_stumblevideo_rate, false)
+	}
+	
+	el = doc.getElementById("thumbDown");
+	if (el)
+	{
+		el.removeEventListener("DOMAttrModified", StumbleGlobals.handle_stumblevideo_rate, false);
+		el.addEventListener("DOMAttrModified", StumbleGlobals.handle_stumblevideo_rate, false)
+	}
+
+//	if (StumbleGlobals.pending_stumblevideo_stumble)
+//		StumbleGlobals.dispatch_click(doc, "stumbleButton");
+//	
+//	StumbleGlobals.pending_stumblevideo_stumble = false;
+}
+
+StumbleGlobals.handle_stumblevideo_login = function(event)
+{
+	if (event.target.id != "login_count")
+		return true;
+	
+	var userid_saved = StumbleGlobals.stumbleid;
+	var profile_change = StumbleGlobals.process_cookies(false);
+	if (profile_change && (StumbleGlobals.stumbleid != userid_saved))
+	{
+		var detail = new Object();
+		detail.skip_cookies = true;
+		detail.ignore_cookies = true;
+		detail.new_profile = profile_change.new_profile;
+		detail.new_user_prompt = false;
+		StumbleGlobals.invoke_global_event("login", detail);
+	}
+	return true;
+}
+
+StumbleGlobals.get_browser_from_doc = function(doc)
+{
+	var browsers = getBrowser().browsers;
+	var i;
+	var browser = null;
+	for (i = 0; i < browsers.length; i++)
+	{
+		if (browsers[i].contentDocument == doc)
+		{
+			browser = browsers[i];
+			break;
+		}
+	}
+	if (! browser)
+		StumbleGlobals.log("MISSING BROWSER");
+	return browser;
+}
+
+StumbleGlobals.handle_stumblevideo_change = function(opt_event, opt_doc)
+{
+	StumbleGlobals.stumble_async_context = null;
+	StumbleGlobals.get_element("stumbleglobals_stumble").image="chrome://stumbleupon/content/skin/stumble.png";
+	var command;
+	var doc;
+	if (opt_event)
+	{
+		if (opt_event.target.id != "url_command")
+			return true;
+		
+		command = opt_event.newValue;
+		doc = opt_event.target.ownerDocument;
+	}
+	else if (opt_doc)
+	{
+		doc = opt_doc;
+		var el = doc.getElementById("url_command");
+		if (! el)
+			return true;
+		
+		if (! el.hasAttribute("value"))
+			return true;
+		
+		command = el.getAttribute("value");
+	}
+
+	if (command.indexOf("URL ") != 0)
+		return true;
+	
+	var target_browser = StumbleGlobals.get_browser_from_doc(doc);
+	if (! target_browser)
+		return true;
+	
+	var overlay_url_detail = StumbleGlobals.deserialize_url_command_params(command.substr(4), false);
+	
+	var display_url = StumbleGlobals.get_browser_url(doc, true);
+	var url_detail = StumbleGlobals.ds.lookup("url:url_detail", display_url);
+	if (url_detail)
+	{
+		url_detail.url = overlay_url_detail.url;
+		url_detail.display_url = display_url;
+	}
+	else
+	{
+		url_detail = overlay_url_detail;
+		url_detail.display_url = display_url;
+	}
+	
+	if (target_browser.stumbleglobals_url_detail &&
+			(url_detail != target_browser.stumbleglobals_url_detail) &&
+			target_browser.stumbleglobals_url_detail.messageid)
+		StumbleGlobals.close_message(target_browser.stumbleglobals_url_detail.messageid, true);
+	
+	target_browser.stumbleglobals_url_detail = url_detail; 
+	
+//	StumbleGlobals.dd("setstumbled", 2, url_detail.url);
+	StumbleGlobals.stumbled_url = url_detail.url;
+	StumbleGlobals.redirect_url = url_detail.url;
+	StumbleGlobals.stumbled_redirect = "";
+//	StumbleGlobals.dd("reset", 3);
+	StumbleGlobals.refresh_pagemeta(true, 4);
+	
+	return true;
+}
+
+StumbleGlobals.get_stumblevideo_detail = function(opt_doc)
+{
+	var browser = null;
+	
+	if (opt_doc)
+	{
+		browser = StumbleGlobals.get_browser_from_doc(opt_doc);
+		if (! browser)
+			return null;
+	}
+	else
+	{
+		browser = getBrowser().selectedBrowser;
+	}
+	
+	if (! browser.stumbleglobals_url_detail)
+		return null;
+
+	var cmp_url = browser.currentURI.asciiSpec;
+	
+//	StumbleGlobals.log("svdetail.1");
+	if (! ((cmp_url.indexOf("http://video." + StumbleGlobals.servername + "/#p") == 0) ||
+			(cmp_url.indexOf("http://video." + StumbleGlobals.servername + "/?p") == 0)))
+		return null;
+//	StumbleGlobals.log("svdetail.2");
+	return browser.stumbleglobals_url_detail;
+}
+
+StumbleGlobals.handle_stumblevideo_rate = function(opt_event, opt_doc)
+{
+	// Determine the rating
+	var rating = null;
+	var unrate = false;
+	var other_button;
+	var doc;
+	if (opt_event)
+	{
+		var event = opt_event;
+		
+		if (event.attrName != "src")
+			return true;
+	
+		doc = event.target.ownerDocument;
+		
+		if (event.target.id == "thumbUp")
+		{
+			other_button = doc.getElementById("thumbDown");
+			if (event.newValue.indexOf("_sel") != -1)
+				rating = 1;
+			else if ((event.prevValue.indexOf("_sel") != -1) && 
+						(event.newValue.indexOf("_sel") == -1) &&
+						(other_button.src.indexOf("_sel") == -1))
+				unrate = true;
+		}	
+		else if (event.target.id == "thumbDown")
+		{
+			other_button = doc.getElementById("thumbUp");
+			if (event.newValue.indexOf("_sel") != -1)
+				rating = 0;
+			else if ((event.prevValue.indexOf("_sel") != -1) && 
+						(event.newValue.indexOf("_sel") == -1) &&
+						(other_button.src.indexOf("_sel") == -1))
+				unrate = true;
+		}
+	}
+	else if (opt_doc)
+	{
+		var doc = opt_doc;
+		var thumbup = 	doc.getElementById("thumbUp");
+		var thumbdown = doc.getEementById("thumbDown");
+		if (thumbup && thumbup.src && (thumbup.src.indexOf("_sel") != -1))
+			rating = 1;
+		else if (thumbdown && thumbdown.src && (thumbdown.src.indexOf("_sel") != -1))
+			rating = 0;
+		else if (thumbup && thumbdown && thumbup.src && thumbdown.src &&
+			(thumbup.src.indexOf("_sel") == -1) && (thumbdown.src.indexOf("_sel") == -1))
+			unrate = true;
+	}
+
+	if (! (unrate || (rating != null)))
+		return true;
+	
+	// Record the rating
+	
+	var url_detail = StumbleGlobals.get_stumblevideo_detail(doc);
+	
+//	StumbleGlobals.log(1);
+	if (! url_detail)
+	{
+		return true;
+	}
+//	StumbleGlobals.log(2);
+	
+	var context = new StumbleGlobals.AsyncContext();
+	context.rating = rating;
+	context.url = url_detail.url;
+
+	if (rating != null)
+	{
+		if (doc == getBrowser().contentDocument)
+			context.browser = getBrowser().selectedBrowser;
+		else
+			contect.browser = null;
+		context.title = null;
+		context.force_nostumble = true;
+		context.force_comment = null;
+		context.timestamp = null;
+		context.open_reviews = null;
+		context.charset = null;
+		context.referrer = null;
+		context.stumblevideo_mode = (StumbleGlobals.stumblevideo_toolbar_rate) ? 
+					"toolbar" : "page";
+	}
+
+	var res = new Object();
+	res.detail = context;
+	res.status = 200;
+	res.responseText = "";
+	
+	if (context.rating == null)
+	{
+		url_detail.rating = -1;
+		setTimeout(StumbleGlobals.unrate_done, 0, res);
+		setTimeout(StumbleGlobals.rate_getmeta, 0, context.url, true);
+	}
+	else
+	{
+		url_detail.rating = rating;
+		setTimeout(StumbleGlobals.rate_done, 0, res);
+		setTimeout(StumbleGlobals.rate_getmeta, 0, context.url, true);
+	}
+	
+	return true;
+}
+
+StumbleGlobals.rate_getmeta = function(url, new_rating)
+{
+	if (! StumbleGlobals.host.places)
+		return;
+	
+	var params = "";
+	params = StumbleGlobals.arp(params, "url", url); 
+	params = StumbleGlobals.append_sync_params(params);
+	
+	var context = new StumbleGlobals.AsyncContext();
+	context.url = url;
+	context.ref_url = url;
+	context.quiet = true;
+	
+	var loc = (new_rating) ? "getmetanew.php" : "getmetahist.php";
+	
+	StumbleGlobals.post_url_server_async(
+				loc,
+				params,
+				null,
+				StumbleGlobals.rate_getmeta_done,
+				context);
+}
+
+StumbleGlobals.rate_getmeta_done = function(res)
+{
+	var context = res.detail;
+	
+	try {
+		if (res.status != 200)
+			return;
+	} catch (e) { return; }
+
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+	
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response " + context.request_target, s);
+	
+	StumbleGlobals.process_commands(s, context);
+	
+	StumbleGlobals.refresh_pagemeta(false, 8);
+}
+
+StumbleGlobals.facebook_page = function(doc, url)
+{
+	if (url.match(/^http.*?\/\/[^\/]*?\.facebook\.com\/home\.php/))
+		StumbleGlobals.facebookhome_page(doc);
+	
+	else if (url.match(/^http.*?\/\/[^\/]*?\.facebook\.com\/friends\.php\?r/))
+		StumbleGlobals.facebookfriends_page(doc);
+	
+	if (StumbleGlobals.ds.getValue("@facebook_user") &&
+				(StumbleGlobals.ds.getValue("@id_list") == "") && 
+				(! StumbleGlobals.ds.getValue("~shown_prompt2")) &&
+				StumbleGlobals.ds.getValue("@enable_prompt2") &&
+				(! StumbleGlobals.ds.getValue("~visited_find_friends")))
+	{
+		StumbleGlobals.ds.setValue("~shown_prompt2", true);
+		
+		var detail = new Object();
+		detail.post_url = url;
+		
+		StumbleGlobals.show_banner(
+					"Join StumbleUpon to share you discoveries with your friends on Facebook",
+					"chrome://stumbleupon/content/skin/stumble.png",
+					function () { StumbleGlobals.handle_prompt_click("prompt2", "accept", detail); },
+					function () { StumbleGlobals.handle_prompt_click("prompt2", "decline", detail); });
+
+//		var detail = new Object();
+//		detail.target = "prompt2";
+//		detail.post_url = doc.location.toString();
+//		StumbleGlobals.show_notifier(
+//					"Create a StumbleUpon account to see ratings, reviews and recommendations by Facebook friends.",
+//					"chrome://stumbleupon/content/skin/logo32.png",
+//					"notifierIcon32",
+//					5000,
+//					detail);
+	}
+	
+	var fbuserid = StumbleGlobals.get_facebook_userid();
+	if (fbuserid)
+	{
+		StumbleGlobals.ds.setValue("#facebook_userid", fbuserid); 
+		StumbleGlobals.ds.setValue("#checked_facebook", false);
+		StumbleGlobals.ds.setValue("@facebook_user", true);
+	}
+}
+
+StumbleGlobals.facebookhome_page = function(doc)
+{
+	if (StumbleGlobals.stumbleid == 0)
+		return;
+	
+	var now_s;
+	var shown_time_s;
+	
+	if (! StumbleGlobals.test_facebookhome_prompt)
+	{
+		if (StumbleGlobals.ds.getValue("$facebook_added"))
+			return;
+		
+		if (StumbleGlobals.ds.getValue("$facebook_homeprompt_optout"))
+			return;
+		
+		if (! StumbleGlobals.ds.getValue("@toolbar-visible"))
+			return;
+	
+		now_s = StumbleGlobals.get_time_s();
+		shown_time_s = StumbleGlobals.ds.getValue("$facebook_homeprompt_time_s"); 
+		
+		if (shown_time_s && ((now_s - shown_time_s) > (2 * 7 * 24 * 60 * 60)))
+			return;
+		
+		if (! StumbleGlobals.ds.getValue("#checked_facebook"))
+		{
+			StumbleGlobals.get_facebook(doc);
+			return;
+		}
+		
+		if (! StumbleGlobals.get_facebook_userid())
+			return;
+	}
+	
+	var target = null;
+	
+	var el = doc.getElementById("home_main");
+	if (! el)
+		return;
+	
+	var hs = el.getElementsByTagName("h2");
+	var i;
+	for (i = 0; i < hs.length; i++)
+	{
+		if (hs[i].innerHTML.indexOf("News Feed") != -1)
+		{
+			target = hs[i];
+			break;
+		}
+	}
+	
+	if (! target)
+		return;
+	
+	if (! target.parentNode)
+		return;
+	
+	var sibling = target.nextSibling;
+	
+	if (sibling != target.parentNode.lastChild)
+		return;
+	
+//	var sibling = sibling.firstChild;
+	
+	if (! sibling)
+		return;
+	
+	var tooltip = "Share websites with friends";
+	
+	var str = "";
+	
+	str += '      ';
+
+	str += '<a style="text-decoration:none;" title="' + tooltip +
+				'" href="http://apps.facebook.com/stumbleupon/"><img border="0" width="13" height="13" style="display:inline;position:relative;top:2px;" src="chrome://stumbleupon/content/skin/smallstumble.png"/>  </a><a title="' + tooltip +
+				'" href="http://apps.facebook.com/stumbleupon/">Add StumbleUpon</a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-c.png"/>';
+	
+//	str += "   <span style="text-size:small;">·</span>   ";
+	
+	el = doc.createElement("span");
+	el.innerHTML = str;
+	el.setAttribute("style", "float:left;");
+	
+	sibling.parentNode.insertBefore(el, sibling);
+	
+	el.lastChild.addEventListener("click", StumbleGlobals.handle_facebook_homeprompt_optout_click, false);
+
+	if (! StumbleGlobals.test_facebookhome_prompt)
+	{
+		if (! shown_time_s)
+			StumbleGlobals.ds.setValue("$facebook_homeprompt_time_s", now_s);
+	}
+}
+
+StumbleGlobals.handle_searchpageprompt_optout_click = function(event)
+{
+	StumbleGlobals.handle_prompt_optout_click(event, "search");
+}
+
+StumbleGlobals.handle_facebook_homeprompt_optout_click = function(event)
+{
+	StumbleGlobals.handle_prompt_optout_click(event, "fbhome");
+}
+
+StumbleGlobals.handle_prompt_optout_click = function(event, promptid)
+{
+	var ps = StumbleGlobals.get_service(
+				"@mozilla.org/embedcomp/prompt-service;1",
+				"nsIPromptService");
+	var out = ps.confirmEx(
+				window,
+				"StumbleUpon Confirm",
+				"Do you want to permanently remove this StumbleUpon link?",
+				ps.STD_YES_NO_BUTTONS,
+				null,
+				null,
+				null,
+				null,
+				{});
+	if (out == 0)
+	{
+		switch (promptid)
+		{
+			case "fbhome":
+				var target = event.target.parentNode;
+				target.parentNode.removeChild(target);
+				StumbleGlobals.ds.setValue("$facebook_homeprompt_optout", true);
+				break;
+			case "search":
+				var target = event.target.parentNode;
+				target.parentNode.removeChild(target);
+				StumbleGlobals.ds.setValue("$shown_find_friends_optout", true);
+				break;
+		}
+	}
+}
+
+StumbleGlobals.facebookfriends_page = function(doc)
+{
+	if (! StumbleGlobals.ds.getValue("@toolbar-visible"))
+		return;
+	
+	var el = doc.getElementById("friendtables");
+	if (! el)
+		return;
+	var as = el.getElementsByTagName("a");
+	var targets = new Array();
+	var userids = new Array();
+	for (i = 0; i < as.length; i++)
+	{
+		var match = as.item(i).href.match(/http\:\/\/[^\/]*\.facebook\.com\/addfriend\.php\?id=(.*)/);
+
+		if (! match)
+			match = as.item(i).href.match(/http\:\/\/[^\/]*\.facebook\.com\/friends\.php\?remove_friend=1\&friend_id=(.*)/);
+		
+		if (! match)
+			continue;
+
+		var target = as.item(i).parentNode;
+		
+		if (! target)
+			continue;
+		
+		if (target.className != "actions")
+			continue;
+		
+		userids.push(match[1]);
+		targets.push(target);
+	}
+	
+	if (userids.length == 0)
+		return;
+	
+	
+	// StumbleGlobals.check_facebook_contacts(userids, targets);
+}
+
+/*
+StumbleGlobals.check_facebook_contacts = function(fb_userids, targets)
+{
+	var i;
+	var contact;
+	var contacts = StumbleGlobals.ds.selectAllRows("contact");
+	var contacts_by_fbid = new Object();
+	var now_s = StumbleGlobals.get_time_s();
+	var checked_time_s = StumbleGlobals.ds.getValue("$facebook_contacts_time_s"); 
+	var refresh_cache = (checked_time_s && ((now_s - checked_time_s) > (18 * 60 * 60)));
+	var anonymize_nonmutuals = refresh_cache;
+
+	for (i = 0; i < contacts.length; i++)
+	{
+		contact = contacts[i];
+		if (contact.fbid)
+		{
+			contacts_by_fbid[contact.fbid] = contact;
+			if (anonymize_nonmutuals && contact.contactid && (! contact.mutual))
+			{
+				contact.contactid = "";
+				contact.nickname = "";
+				StumbleGlobals.ds.updateRow(contact);
+			}
+		}
+	}
+	
+	for (i = 0; i < fb_userids.length; i++)
+	{
+		if (contacts_by_fbid[fb_userids[i]])
+			contact
+		
+		var contactid = friends[i].split(".")[0];
+		var nickname = friends[i].split(".")[1];
+		var facebookid = friends[i].split(".")[2];
+		
+		fbfriends[contactid] = true;
+
+		contact = null;
+		
+		if (contacts_by_id[contactid])
+			contact = contacts_by_id[contactid];
+		
+		if (contact)
+		{
+			contact.nickname = nickname;
+			contact.fbid = facebookid;
+			StumbleGlobals.ds.updateRow(contact);
+		}
+		else
+		{
+			contact = new Object();
+			contact.contactid = contactid;
+			contact.nickname = nickname;
+			contact.fbid = facebookid;
+			StumbleGlobals.ds.insertRow("contact", contact);
+			contacts_by_id[contactid] = contact;
+		}
+	}
+
+	for (i = 0; i < contacts.length; i++)
+	{
+		if ((typeof (contacts[i].contactid)) != "undefined")
+		{
+			if (contacts[i].fbid && (! fbfriends[contacts[i].contactid]))
+				contacts[i].fbid = 0;
+			
+			StumbleGlobals.ds.updateRow(contacts[i]);
+		}
+	}
+	
+	if (userids)
+	{
+		
+	}
+	
+}
+*/
+
+StumbleGlobals.search_results_page = function(doc, service_id)
+{
+	StumbleGlobals.search_service_page(doc, service_id);
+	StumbleGlobals.augment_links(doc, service_id);
+}
+
+StumbleGlobals.search_service_page = function(doc, service_id)
+{
+	var now_s;
+	var shown_time_s;
+	if (! StumbleGlobals.test_searchpage_prompt)
+	{
+		if (! StumbleGlobals.ds.hasFeature("$sociallinks"))
+			return;
+		
+		if (! StumbleGlobals.ds.getValue("@toolbar-visible"))
+			return;
+		
+		if (StumbleGlobals.ds.getValue("$imported_contacts_time_s"))
+			return;
+		
+		if (StumbleGlobals.ds.getValue("$shown_find_friends_optout"))
+			return;
+		
+//		if ((! StumbleGlobals.ds.hasFeature("$unlimitedslpromptclicks") &&
+//					(StumbleGlobals.ds.getValue("$shown_find_friends_clicks") >= 3)))
+//			return;
+	
+		now_s = StumbleGlobals.get_time_s();
+		shown_time_s = StumbleGlobals.ds.getValue("$shown_find_friends_time_s"); 
+	
+		if (shown_time_s && ((now_s - shown_time_s) > (3 * 7 * 24 * 60 * 60)))
+			return;
+	}
+	
+	var tooltip = "Add StumbleUpon friends to see which search results they prefer";
+	var str = '<a style="text-decoration:none;" title="' + 
+				tooltip + '" href="' + StumbleGlobals.serverhttp + 
+				'find_friends.php?pre3=' + service_id + '">';
+	
+	if (StumbleGlobals.ds.getValue("$show_searchlinks_logo"))
+		str += '<img border="0" width="13" height="13" style="display:inline;position:relative;top:1px;" src="http://cdn.stumble-upon.com/images/embed/smallstumble.png"> <u style="position:relative;top:-1px;">See friend reviews</u></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-c.png"/>';
+	else
+		str += '<u>See StumbleUpon friend reviews</u></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-c.png"/>';
+	
+	switch (service_id)
+	{
+		case "google":
+			var el = doc.getElementById("gbar");
+			if (! el)
+				return;
+			var us = el.getElementsByTagName("u");
+			var target = null;
+			var i;
+			for (i = 0; i < us.length; i++)
+			{
+				if (us[i].innerHTML == "more")
+				{
+					target = us[i];
+					break;
+				}
+			}
+			if (! target)
+				return;
+			
+			target = target.parentNode;
+			
+			if (! target)
+				return;
+			
+//			target = target.parentNode;
+			
+//			if (! target)
+//				return;
+		
+			if (! target.parentNode)
+				return;
+			
+			el = doc.createElement("td");
+			el.id = "__stumbleglobals__service_ff";
+			el.setAttribute("nowrap", "nowrap");
+			el.innerHTML = str;
+			target.parentNode.appendChild(el);
+			el.lastChild.addEventListener("click", StumbleGlobals.handle_searchpageprompt_optout_click, false);
+			break;
+		case "yahoo":
+			str = '    <a style="text-decoration:none;" title="' + 
+						tooltip + '" href="' + StumbleGlobals.serverhttp + 
+						'find_friends.php?pre3=' + service_id + '">';
+						
+			if (StumbleGlobals.ds.getValue("$show_searchlinks_logo"))
+				str += '<img border="0" width="13" height="13" style="display:inline;position:relative;top:2px;" src="http://cdn.stumble-upon.com/images/embed/smallstumble.png"> <u style="color:rgb(21,73,193);">See friend reviews</u></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-c.png"/>';
+			else
+				str += '<u style="color:rgb(21,73,193);">See StumbleUpon friend reviews</u></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-c.png"/>';
+	
+			var target = doc.getElementById("tabs");
+			var style = "white-space:nowrap;position:relative;top:-1px;"
+			if (! target)
+			{
+				target = doc.getElementById("eb");
+				style = "white-space:nowrap;position:relative;top:-2px;";
+			}
+			if (! target)
+				return;
+			target.setAttribute("style", "white-space:nowrap;");
+			var el = doc.createElement("span");
+			el.setAttribute("style", style);
+			el.innerHTML = str;
+			target.appendChild(el);
+			el.lastChild.addEventListener("click", StumbleGlobals.handle_searchpageprompt_optout_click, false);
+			break;
+		case "ask":
+			str = '  <a style="text-decoration:none;" title="' + 
+						tooltip + '" href="' + StumbleGlobals.serverhttp + 
+						'find_friends.php?pre3=' + service_id + '">';
+				
+			if (StumbleGlobals.ds.getValue("$show_searchlinks_logo"))
+				str += '<img border="0" width="13" height="13" style="display:inline;position:relative;top:1px;" src="http://cdn.stumble-upon.com/images/embed/smallstumble.png"> <span style="color:blue;">See friend reviews</span></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-d.png"/>';
+			else
+				str += '<span style="color:blue;">See StumbleUpon friend reviews</span></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-d.png"/>';
+			var target = doc.getElementById("navbar_tabs");
+			if (! target)
+				return;
+			var el = doc.createElement("span");
+			el.innerHTML = str;
+			target.appendChild(el);
+			el.lastChild.addEventListener("click", StumbleGlobals.handle_searchpageprompt_optout_click, false);
+			break;
+		case "aol":
+			var target = doc.getElementById("morecsb");
+			if (! target)
+				return;
+			target = target.parentNode;
+			if (! target)
+				return;
+			target = target.parentNode;
+			if (! target)
+				return;
+			var el = doc.createElement("span");
+			el.innerHTML = str;
+			target.appendChild(el);
+			el.lastChild.addEventListener("click", StumbleGlobals.handle_searchpageprompt_optout_click, false);
+			break;
+	}
+	if (! StumbleGlobals.test_searchpage_prompt)
+	{
+		if (! shown_time_s)
+			StumbleGlobals.ds.setValue("$shown_find_friends_time_s", now_s);
+	}
+}
+
+//
+// StumbleGlobals.check_google_augment
+//
+// Handles Google instant search by waiting until Xms after the last
+// node is inserted before checking links.php
+//
+StumbleGlobals.check_google_augment = function(doc)
+{
+	var now = (new Date()).getTime();
+	var googleTimeout = StumbleGlobals.ds.getValue("@google_is_timeout_ms");
+
+	// First, set up a DOMNodeInserted listener
+	if(!doc.__stumbleglobals__listening)
+	{
+		doc.__stumbleglobals__listening = true;
+		doc.addEventListener("DOMNodeInserted", function(event) {
+			doc.__stumbleglobals__lastupdateevent = (new Date()).getTime();
+			StumbleGlobals.check_google_augment(doc);
+		}, false);
+	}
+
+	// If we don't have a start time, then start now
+	if(!doc.__stumbleglobals__lastupdateevent)
+		doc.__stumbleglobals__lastupdateevent = now;
+
+	// If a timeout is active then clear it and set a new one
+	if(doc.__stumbleglobals__active_timeout)
+		window.clearTimeout(doc.__stumbleglobals__active_timeout);
+
+	if((now - doc.__stumbleglobals__lastupdateevent) < googleTimeout)
+	{
+		// Not enough time has elapsed, check back later
+		doc.__stumbleglobals__active_timeout = window.setTimeout(function() {
+			StumbleGlobals.check_google_augment(doc);
+		}, googleTimeout + 10);
+	}
+	else
+	{
+		// Enough time has passed since the last insert, try augmenting the page again
+		StumbleGlobals.augment_links(doc, "google", true);
+	}
+}
+
+// extracts links from a page and calls links.php
+StumbleGlobals.augment_links = function(doc, service_id, from_google_check)
+{
+	if ((! StumbleGlobals.ds.getValue("$show_searchlinks_score")) &&
+				(! StumbleGlobals.ds.getValue("$show_searchlinks_friends")) &&
+				(! StumbleGlobals.ds.getValue("$show_searchlinks_topic")))
+		return;
+
+	if (! StumbleGlobals.ds.getValue("@toolbar-visible"))
+		return;
+
+	var as;
+	var target;
+	var el;
+	switch (service_id)
+	{
+		case "wikipedia":
+			el = doc.getElementById("top");
+			while (el)
+			{
+				if (el.className == "firstHeading")
+					break;
+				el = el.nextSibling;
+			}
+			if (! el)
+				return;
+			var title = el;
+			var title_text = title.innerHTML;
+			title.innerHTML = "";
+			var inline = doc.createElement("span");
+			title.appendChild(inline);
+			target = doc.createElement("span");
+			target.innerHTML = title_text;
+			inline.appendChild(target);
+			break;
+		case "cnn":
+			var el = doc.getElementById("cnnSearchResults");
+			if (! el)
+				return;
+			as = el.getElementsByTagName("a");
+			break;
+		default:
+			as = doc.getElementsByTagName("a");
+			break;
+	}
+	var urls = new Array();
+	var targets = new Array();
+	var hrefs = urls;
+	var i;
+	
+	var linked_color = "rgb(130, 132, 204)";
+	var unlinked_color = "rgb(0, 0, 0)";
+	var underline = true;
+	var font_size = "100%";
+	var force_no_logo = false;
+	var force_inline = false;
+	var soft_wrap = false;
+	var hard_wrap = false;
+	var force_logo = false;
+	var before_targets = targets;
+	var after_targets = targets;
+	var include_topic = false;
+	var image_baseline = false;
+	var enable_click_tracking = true;
+
+	switch (service_id)
+	{
+		case "google":
+			var googleInstantSearch = false;
+
+			var elOn = doc.getElementById("po-on-message");
+			var now = (new Date()).getTime();
+			
+			if(elOn && (elOn.style.display != "none"))
+				googleInstantSearch = true;
+
+			if(googleInstantSearch && !from_google_check)
+			{
+				// Call the special code that knows how to handle instant search.
+				StumbleGlobals.check_google_augment(doc);
+				return;
+			}
+
+			var url = StumbleGlobals.get_browser_url(doc);
+
+			// Do not augment for Google Updates, because if someone leaves that page open, we may get too many
+			// links.php requests.
+			if(url.indexOf("tbs=mbl") != -1)
+				return;
+			
+			after_targets = new Array();
+			linked_color = "#7777cc";
+			unlinked_color = linked_color;
+			font_size = "smaller";
+			
+			for (i = 0; i < as.length; i++)
+			{
+				var cn = as.item(i).className;
+				if(!cn)
+					continue;
+				
+				// See if the class names include "l"
+				if (cn.match(/(^| )l($| )/))
+				{
+					if (as.item(i).firstChild && (as.item(i).firstChild.tagName == "IMG") &&
+								(as.item(i).firstChild.src.indexOf("/mapfiles/") != -1))
+						continue; // at top
+					
+					if(as[i].__stumbleglobals__anchortested)
+						continue;
+					as[i].__stumbleglobals__anchortested = true;
+
+					var redir_match = as.item(i).href.match(/^http.*?\/\/[^\/]*?(google\.[^\.]+|google\.co\.[^\.]+)\/(url.*[?&]q=)([^&]+)/);
+					if (redir_match && redir_match.length >= 4)
+						urls.push(decodeURIComponent(redir_match[3]));
+					else
+						urls.push(as.item(i).href);
+					targets.push(as.item(i));
+					if (as.item(i).parentNode.nextSibling && as.item(i).parentNode.nextSibling.tagName == "FONT" && as.item(i).parentNode.nextSibling.firstChild && as.item(i).parentNode.className != "r")
+						after_targets.push(as.item(i).parentNode.nextSibling.firstChild);
+					else
+						after_targets.push(as.item(i));
+				}
+			}
+			break;
+		case "ask":
+			linked_color = "auto";
+			for (i = 0; i < as.length; i++)
+			{
+				if (as.item(i).className == "L4")
+				{
+					var matches = as.item(i).href.match(/&u=([^&]*)/);
+					if(matches && matches[1])
+					{
+						urls.push(decodeURIComponent(matches[1]));
+					}
+					else
+					{
+						urls.push(as.item(i).href);
+					}
+					targets.push(as.item(i));
+				}
+			}
+			break;
+		case "bing":
+			var h3s = doc.getElementsByTagName("h3");
+			for (var i = 0; i < h3s.length; i++)
+			{
+				var anchors = h3s[i].getElementsByTagName("a");
+				if (anchors.length == 1)
+				{
+					var a = anchors[0];
+					urls.push(a.href);
+					targets.push(a);
+				}
+			}
+			break;
+		case "bing-news":
+			var headlines = doc.getElementsByClassName("Headline");
+			for (var i = 0; i < headlines.length; i++)
+			{
+				var anchors = headlines[i].getElementsByTagName("a");
+				if (anchors.length == 1)
+				{
+					var a = anchors[0];
+					urls.push(a.href);
+					targets.push(a);
+				}
+			}
+			break;
+		case "nyt":
+			force_inline = true;
+			var h3s = doc.getElementsByTagName("h3");
+			for (var i = 0; i < h3s.length; i++)
+			{
+				var anchors = h3s[i].getElementsByTagName("a");
+				if (anchors.length == 1)
+				{
+					var href = anchors[0].href;
+					// They include search referral and search term information at the end of the URL, 
+					// past the ?scp=, so we strip that out if it exists.
+					var match = href.match(/(.*?)(\?scp=.*)/);
+					if(match)
+					{
+						href = match[1];
+					}
+					urls.push(href);
+					targets.push(anchors[0]);
+				}
+			}
+			break;
+		case "yahoo":
+			// Yahoo changes the href with global script, so we have to wait for
+			// the "load" event at which point the href will have been set to the final URL.
+			if(!doc.__stumbleglobals__listening)
+			{
+				doc.__stumbleglobals__listening = true;
+				doc.defaultView.addEventListener("load", function(event) {
+					if(event.target.__stumbleglobals__listening)
+					{
+						StumbleGlobals.augment_links(doc, service_id);
+					}
+				}, false);
+				return;
+			}
+			
+			// We got back in here from the load event, now do our work.
+			soft_wrap = true;
+			hrefs = new Array();
+			for (i = 0; i < as.length; i++)
+			{
+				if ((as.item(i).className.indexOf("yschttl") != -1) )// && as.item(i).href.match(/\*\*(.*)/))
+				{
+					var href = as.item(i).href;
+					var match = href.match(/http\:\/\/rds.yahoo.com.*?\*\*(.*)/);
+					if(match && match[1])
+					{
+						href = decodeURIComponent(match[1]);
+					}
+					urls.push(href);
+					hrefs.push(href);
+					targets.push(as.item(i));
+				}
+			}
+			break;
+		case "aol":
+			font_size = "larger";
+			hrefs = new Array();
+			for (i = 0; i < as.length; i++)
+			{
+				if (as.item(i).className == "find")
+				{
+					hrefs.push(as.item(i).href);
+					urls.push(as.item(i).href);
+					targets.push(as.item(i));
+				}
+			}
+			break;
+		case "myspace":
+			for (i = 0; i < as.length; i++)
+			{
+				var anchor = as.item(i);
+				if( anchor.parentNode &&
+					anchor.parentNode.parentNode &&
+					(anchor.parentNode.parentNode.className.indexOf("searchResults") != -1) )
+				{
+					urls.push(anchor.href);
+					targets.push(anchor);
+				}
+			}
+			break;
+		case "youtube":
+			underline = false;
+			soft_wrap = true;
+			font_size = "small";
+			for (i = 0; i < as.length; i++)
+			{
+				if (as.item(i).id.indexOf("video-long-title") == 0)
+				{
+					urls.push(as.item(i).href);
+					targets.push(as.item(i));
+				}
+			}
+			break;
+		case "wikipedia":
+			font_size = "small";
+			underline = false;
+			image_baseline = true;
+			// include_topic = true;
+			enable_click_tracking = StumbleGlobals.ds.hasFeature("$titleclicktracking");
+			urls.push(doc.location.href);
+			targets.push(target);
+			break;
+		case "flickr":
+			underline = false;
+			hard_wrap = true;
+			soft_wrap = true;
+			linked_color = "auto";
+			font_size = "small";
+			for (i = 0; i < as.length; i++)
+			{
+				var anchor = as.item(i);
+				var ancestor = StumbleGlobals.get_ancestor_by_prop_value(anchor,
+							"className", "ResultsThumbsChild", 4);
+				if (ancestor && anchor.firstChild && 
+					anchor.firstChild.className &&
+				    (anchor.firstChild.className.indexOf("pc_img") != -1))
+				{
+					urls.push(anchor.href);
+					targets.push(anchor);
+				}
+			}
+			break;
+		case "cnn":
+			for (i = 0; i < as.length; i++)
+			{
+				if (as[i].className == "cnnSearchResultsHeadline")
+				{
+					var redir_match = as.item(i).href.match(/arProcessing\.jsp.*?[?&]dest=([^?&]+)/);
+					if (redir_match && redir_match.length >= 0)
+						urls.push(redir_match[1]);
+					else
+						urls.push(as.item(i).href);
+					targets.push(as.item(i));
+				}
+			}
+			break;
+		case "cbsnews":
+			for (i = 0; i < as.length; i++)
+			{
+				if (as.item(i).className == "storyTitle")
+				{
+					urls.push(as.item(i).href);
+					targets.push(as.item(i));
+				}
+			}
+			break;
+		case "cnetnews":
+			force_inline = true;
+			for (i = 0; i < as.length; i++)
+			{
+				if (as.item(i).className == "resultName")
+				{
+					urls.push(as.item(i).href);
+					targets.push(as.item(i));
+				}
+			}
+			break;
+		case "abcnews":
+			for (i = 0; i < as.length; i++)
+			{
+				if (as.item(i).className == "title")
+				{
+					urls.push(as.item(i).href);
+					targets.push(as.item(i));
+				}
+			}
+			break;
+		case "msnbc":
+			for (i = 0; i < as.length; i++)
+			{
+				var anchor = as.item(i);
+				if(anchor.parentNode.tagName == "H4")
+				{
+					urls.push(anchor.href);
+					targets.push(anchor);
+				}
+			}
+			break;
+	}
+	
+	if (urls.length == 0)
+		return;
+	
+	var url = StumbleGlobals.get_browser_url(doc);
+	
+	var query_detail = StumbleGlobals.get_search_query_detail(service_id, url);
+	
+	var now = (new Date()).getTime();
+	
+	var slstats = new Object();
+	slstats.timestamp = now;
+	slstats.slq = 0;
+	slstats.term_count = query_detail.term_count;
+	slstats.url_count = hrefs.length;
+	slstats.decorated_count = 0;
+	slstats.first_decorated_num = 0;
+
+	if (enable_click_tracking)
+	{
+		StumbleGlobals.ds.globals.sls.push(slstats);
+		var slq = StumbleGlobals.ds.globals.sls.length;
+		slstats.slq = slq;
+		StumbleGlobals.ds.globals.sluqh[url] = slq;
+		var slistats = StumbleGlobals.ds.getValue("$slistats").split(":");
+		for (i = 0; i < urls.length; i++)
+		{
+			var slt = "" + slq + StumbleGlobals.service.getSha1(hrefs[i]);
+			var sli = new Object();
+			sli.i = i;
+			StumbleGlobals.ds.globals.sltih[slt] = sli;
+			if (i < 10)
+				slistats[i] = parseInt(slistats[i]) + 1;
+		}
+		StumbleGlobals.ds.setValue("$slistats", slistats.join(":"));
+	}
+	
+	
+	var context = new Object();
+	context.slstats = slstats;
+	context.done = false;
+	context.batch_count = 0;
+	context.url_start_index = 0;
+	context.doc = doc;
+	context.timestamp = now;
+	context.query_detail = query_detail;
+	context.before_targets = before_targets;
+	context.after_targets = after_targets;
+	context.urls = urls;
+	context.hrefs = hrefs;
+	context.linked_color = linked_color;
+	context.underline = underline;
+	context.unlinked_color = unlinked_color;
+	context.font_size = font_size;
+	context.force_logo = force_logo;
+	context.soft_wrap = soft_wrap;
+	context.hard_wrap = hard_wrap;
+	context.include_topic = include_topic || StumbleGlobals.ds.getValue("$show_searchlinks_topic");
+	context.image_baseline = image_baseline;
+	context.enable_click_tracking = enable_click_tracking;
+	context.force_inline = force_inline;
+	
+	StumbleGlobals.augment_links2(context);
+}
+
+StumbleGlobals.augment_links2 = function(context)
+{
+	// Enforce a time separation between queries to links.php.  This is a DOS
+	// mitigation.
+	var now = (new Date()).getTime();
+	var min_links_query_separation = StumbleGlobals.ds.getValue("@min_links_separation_ms");
+	if(now - StumbleGlobals.last_links_query < min_links_query_separation)
+		return;
+	StumbleGlobals.last_links_query = now;
+	
+	var query = "";
+	if (0) //(StumbleGlobals.ds.hasFeature("$unbatchedlinks"))
+	{
+		context.done = true;
+		for (i = 0; i < context.urls.length; i++)
+		{
+			if (query != "")
+				query += '%09';
+			query += encodeURIComponent(context.urls[i]);
+		}
+	}
+	else
+	{
+		var url_count = 0;
+		var i = (context.batch_count * 10);
+		context.url_start_index = i;
+		while ((url_count < 10) && (i < context.urls.length))
+		{
+			url_count++;
+			if (query != "")
+				query += '%09';
+			query += encodeURIComponent(context.urls[i]);
+			i++;
+		}
+		context.batch_count++;
+		if (StumbleGlobals.ds.hasFeature("$limitedlinks"))
+			context.done = true;
+		else
+			context.done = (i == context.urls.length);
+	}
+	
+	if (query == "")
+		return;
+	
+	var params = "u=" + query;
+	params = StumbleGlobals.arp(params, "f",
+				StumbleGlobals.ds.getValue("$show_searchlinks_friends") ? 1 : 0);
+	params = StumbleGlobals.arp(params, "s",
+				StumbleGlobals.ds.getValue("$show_searchlinks_score") ? 1 : 0);
+	params = StumbleGlobals.arp(params, "t",
+				StumbleGlobals.ds.getValue("$show_searchlinks_topic") ? 1 : 0);
+	params = StumbleGlobals.arp(params, "m", StumbleGlobals.ds.getValue("@dd_links_m"));
+	params = StumbleGlobals.arp(params, "domain", context.query_detail.domain);
+	params = StumbleGlobals.arp(params, "termcount", context.query_detail.term_count);
+	params = StumbleGlobals.arp(params, "firstpage", context.query_detail.is_first_page ? 1 : 0);
+	params = StumbleGlobals.arp(params, "timestamp", context.timestamp);
+	params = StumbleGlobals.arp(params, "batch", context.batch_count);
+	
+	var loc = "links.php";
+	if (StumbleGlobals.ds.getValue("@dd_links_m") == "alt")
+		loc = "test_links.php";
+	
+	StumbleGlobals.post_url_server_async(
+				loc, 
+				params,
+				60000,
+				StumbleGlobals.augment_links_done,
+				context);
+}
+
+// handles response to links.php; adds content for the links
+StumbleGlobals.augment_links_done = function(res)
+{
+	try {
+		if ((res.status != 200) || res.aborted)
+			return;
+	} catch (e) { return; }
+
+	var context = res.detail;
+
+	var s = "";
+	if (typeof(res.responseText) != "undefined")
+		s = res.responseText;
+
+	if (StumbleGlobals.log_communication)
+		StumbleGlobals.log("response links.php", s);
+
+	if (s == "")
+		return;
+	
+	var ss;
+
+	ss = s.split("\n");
+
+	var sss = ss[0].split(" ");
+
+	if (sss[0] == "ERROR")
+		return;
+
+	var i;
+	var slt;
+	var slistats = StumbleGlobals.ds.getValue("$slistats").split(":");
+	var slidfstats = StumbleGlobals.ds.getValue("$slidfstats").split(":");
+	for (i = 0; i < ss.length; i++)
+	{
+		if (ss[i] == "")
+			continue;
+		
+		var url_index = context.url_start_index + i;
+		
+		context.slstats.decorated_count++;
+		if (! context.slstats.first_decorated_num)
+			context.slstats.first_decorated_num = (i + 1);
+		
+		var fields = ss[i].split("\t");
+		var comment_level = parseInt(fields[0]);
+		var thumbed = fields[1];
+		if (StumbleGlobals.ratings[context.hrefs[url_index]])
+			thumbed = "1";
+		var score = parseInt(fields[2]);
+		var topic = fields[3];
+
+		var friends = new Array();
+		var j;
+		if (typeof(fields[4]) != "undefined" && fields[4] != "" && StumbleGlobals.ds.getValue("$show_searchlinks_friends"))
+		{
+			var f = fields[4].split(",");
+			for (j = 0; j < f.length; j++)
+			{
+				if (f[j] == '')
+					continue;
+				friends.push(f[j]);
+			}
+		}
+		
+		var comment_count = null;
+		if (typeof(fields[5]) != "undefined" && fields[5] != "")
+			comment_count = parseInt(fields[5]);
+		
+		var comment_id = null;
+		if (typeof(fields[6]) != "undefined" && fields[6] != "")
+			comment_id = fields[6];
+		
+		var comment_text = null;
+		if (typeof(fields[7]) != "undefined" && fields[7] != "")
+			comment_text = fields[7].replace(/\|/g, " ");
+		
+		slt = "";
+		if (StumbleGlobals.host.sha1 && StumbleGlobals.ds.getValue("@enable_slstats") && context.enable_click_tracking)
+		{
+			slt = "" + context.slstats.slq + StumbleGlobals.service.getSha1(context.hrefs[url_index]);
+			var sli = StumbleGlobals.ds.globals.sltih[slt];
+			var detail = new Object();
+			sli.detail = detail;
+			detail.q = context.slstats.slq;
+			detail.d = 1;
+			detail.i = url_index;
+			detail.dt = (thumbed) ? 1 : 0;
+			detail.dc = (comment_count) ? comment_count : 0;
+			detail.ds = score;
+			detail.dl = comment_level;
+			detail.df = friends.length;
+			detail.dr = (comment_text) ? 1 : 0;
+			detail.dz = (context.include_topic && (typeof(StumbleGlobals.catnames[topic]) != "undefined")) ? 1 : 0;
+			
+			if (url_index < 10 && detail.df)
+			{
+				slistats[url_index] = parseInt(slistats[url_index]) - 1;
+				slidfstats[url_index] = parseInt(slidfstats[url_index]) + 1;
+			}
+		}
+		
+		if (! score)
+			score = 1;
+		
+		var after;
+		var before;
+		var after_parts =  new Array();
+		var reviewHref = StumbleGlobals.base_url + "url/" + StumbleGlobals.review_url(context.urls[url_index]);
+
+		
+		// The 'float:none;padding:0;' and 'display:inline;' css rules in
+		// here mostly cater to AOL.
+		
+		before = "";
+		if (thumbed == "1")
+		{
+			before = '<img border="0" width="13" height="13" style="display:inline;';
+			if (context.image_baseline)
+				before += 'vertical-align:baseline;';
+			before += '" src="chrome://stumbleupon/content/skin/smallgreenthumbup.png"> ';
+		}
+		
+		after = '';
+		if (context.hard_wrap)
+		{
+			after_parts.push("<br />");
+		}
+		else if ((score <= 0) && (! StumbleGlobals.ds.getValue("$show_searchlinks_logo")))
+		{
+			after += '<span style="font-size:' + context.font_size + 
+				';color:' + context.unlinked_color +
+				';float:none;padding:0;"> ·</span>';
+		}
+		else
+		{
+			after += ' ';
+		}
+
+		after += '<a ondblclick="slu" slt="' + slt + '"';
+
+		if ((! context.include_topic) && (typeof(StumbleGlobals.catnames[topic]) != "undefined"))
+		{
+			after += ' title="';
+			if (comment_count)
+			{
+				if (comment_count == 1)
+					after += 'Read 1 review';
+				else
+					after += 'Read ' + comment_count + ' reviews';
+				after += ' in topic ' + StumbleGlobals.catnames[topic] + '"';
+			}
+			else
+			{
+				after += 'See who liked this"';
+			}
+		}
+		else if (comment_count)
+		{
+			after += ' title="';
+			if (comment_count == 1)
+				after += 'Read 1 review"';
+			else
+				after += 'Read ' + comment_count + ' reviews"';
+		}
+		else
+		{
+			after += ' title="See who liked this"';
+		}
+
+		after += ' style="text-decoration:none;float:none;padding:0;font-size:' + 
+					context.font_size + ';color:' + 
+					context.linked_color + ';" href="' + reviewHref + '">';
+
+		var imgStyle = "display:inline;float:none;border:none;margin:0px;padding:0px;";
+		if (context.force_logo || StumbleGlobals.ds.getValue("$show_searchlinks_logo"))
+		{
+			after += '<img ondblclick="slu" border="0" width="13" height="13" style="' + imgStyle;
+			if (context.image_baseline)
+				after += 'vertical-align:baseline;';
+			after += '" src="chrome://stumbleupon/content/skin/smallstumble.png">';
+		}
+		
+		if ((score > 0) && StumbleGlobals.ds.getValue("$show_searchlinks_score"))
+		{
+			after += ' ';
+		
+			for (j = 0; j < score; j++)
+			{
+				after += '<img ondblclick="slu" border="0" width="10" height="10" style="' + imgStyle;
+				if (context.image_baseline)
+					after += 'vertical-align:baseline;';
+				after += '" src="chrome://stumbleupon/content/skin/star.png">';
+			}
+		}
+//		else if ((friends.length == 0) || 
+//					(! StumbleGlobals.ds.getValue("$show_searchlinks_friends")))
+//		{
+//			if (context.underline)
+//				after += ' <u ondblclick="slu">Reviews</u>';
+//			else
+//				after += ' Reviews';
+//		}
+
+		if ((comment_level > 0) && StumbleGlobals.ds.getValue("$show_searchlinks_comment_icon"))
+		{
+			after += ' <img ondblclick="slu" border="0" width="13" height="13" style="' + imgStyle;
+			if (context.image_baseline)
+				after+= 'vertical-align:baseline;';
+			after += '" src="chrome://stumbleupon/content/skin/smallbubble' + comment_level + '.png">';
+		}
+
+		after += '</a>';			
+		after_parts.push(after);
+		
+		after = '';
+		if (friends.length && StumbleGlobals.ds.getValue("$show_searchlinks_friends"))
+		{
+			for (j = 0; j < friends.length; j++)
+			{
+				if (j == 0)
+				{
+					after = '<span style="text-decoration:none;float:none;padding:0;font-size:' + 
+								context.font_size + ';color:' + 
+								context.unlinked_color + ';"> · </span><a ondblclick="slp" slt="' +
+								slt + '" style="text-decoration:none;float:none;padding:0;font-size:' + 
+								context.font_size + ';color:' + 
+								context.linked_color + ';" title="'; 
+					
+					if (comment_text)
+						after += comment_text;
+					else
+						after += friends[j] + ' likes this page';
+					
+					after += '" href="' + reviewHref + '">';
+					
+					after += '<img ondblclick="slp" border="0" width="13" height="13" style="' + imgStyle;
+					if (context.image_baseline)
+						after += 'vertical-align:baseline;';
+					
+					after += '" src="chrome://stumbleupon/content/skin/smallredman.png"> ';
+					
+					if (context.underline)
+						after += '<u ondblclick="slp">' + friends[j] + '</u>';
+					else
+						after += friends[j];
+					
+					after += '</a>';
+					
+//					after_parts.push(after);
+					
+				}
+				else if (j == 1)
+				{
+					after += '<span style="text-decoration:none;float:none;padding:0;font-size:' + 
+								context.font_size + ';color:' + 
+								context.unlinked_color + ';"> + </span>';
+					
+					after += '<a ondblclick="sln" slt="' + slt + 
+								'" style="text-decoration:none;float:none;padding:0;font-size:' + 
+								context.font_size + ';color:' + 
+								context.linked_color + ';" href="' + reviewHref + '" title="' + 
+								friends[0] + ', ' + friends[1];
+				}
+				else
+				{
+					after += ', ' + friends[j];
+				}
+			}
+			
+			if (friends.length > 1)
+			{
+				after += ' like';
+			
+				if (friends.length == 1)
+					after += 's';
+				
+				after += ' this page">' + (friends.length - 1) + '</a>';
+			}
+		}
+		
+		if (context.include_topic && (typeof(StumbleGlobals.catnames[topic]) != "undefined"))
+		{
+			after += '<span style="text-decoration:none;float:none;padding:0;font-size:' + 
+						context.font_size + ';color:' + 
+						context.unlinked_color + ';"> · </span><a ondblclick="slz" slt="' + slt + 
+						'" title="See related pages" style="text-decoration:none;float:none;padding:0;font-size:' + 
+						context.font_size + ';color:' + 
+						context.linked_color + ';"href="' + StumbleGlobals.serverhttp + 
+						'tag/' + StumbleGlobals.catnames[topic].toLowerCase() + '/">';
+			if (context.underline)
+				after += '<u ondblclick="slz">' + StumbleGlobals.catnames[topic] + '</u>';
+			else
+				after += StumbleGlobals.catnames[topic];
+			after += '</a>';
+		}
+		
+		if (after != '')
+			after_parts.push(after);
+	
+		var el;
+		if (before != "")
+		{
+			el = context.doc.createElement("SPAN");
+			el.style.cssText = "white-space:nowrap!important; float:none!important; padding:0!important; text-decoration:none!important;";
+			el.innerHTML = before;
+			context.before_targets[url_index].parentNode.insertBefore(el, context.before_targets[url_index]);
+		}
+		
+		var after_target = context.after_targets[url_index];
+		
+		if (! context.soft_wrap)
+			after_parts = new Array(after_parts.join(""));
+		
+		for (j = 0; j < after_parts.length; j++)
+		{
+			el = context.doc.createElement("SPAN");
+			var cssText = "white-space:nowrap!important; float:none!important; padding:0!important; text-decoration:none!important;";
+			if(context.force_inline)
+			{
+				cssText += "display:inline!important;";
+			}
+			if (context.soft_wrap)
+				el.innerHTML = after_parts[j].replace(/ /g, " ");
+			else
+				el.innerHTML = after_parts[j];
+			if (after_target.nextSibling)
+				after_target.parentNode.insertBefore(el, after_target.nextSibling);
+			else
+				after_target.parentNode.appendChild(el);
+			after_target = el;
+			el.style.cssText = cssText;
+		}
+	}
+	
+	if (context.enable_click_tracking)
+	{
+		var str = "";
+		var sls = StumbleGlobals.ds.globals.sls;
+		for (i = 0; i < sls.length; i++)
+		{
+			var slstats = sls[i]
+			str += slstats.timestamp + "\t" + slstats.slq + "\t" + 
+					slstats.term_count + "\t" + slstats.url_count + "\t" +
+					slstats.decorated_count + "\t" + 
+					slstats.first_decorated_num + "\t:";
+		}
+		
+		StumbleGlobals.ds.setValue("$slstats", str);
+		StumbleGlobals.ds.setValue("$slistats", slistats.join(":"));
+		StumbleGlobals.ds.setValue("$slidfstats", slidfstats.join(":"));
+	}
+	
+	if (! context.done)
+		StumbleGlobals.augment_links2(context);
+}
+
+StumbleGlobals.handle_upgrade_click = function(event)
+{
+	var target = "https://addons.mozilla.org/firefox/138/";
+	StumbleGlobals.set_location(target, null, StumbleGlobals.new_tab(event));
+	StumbleGlobals.set_visible("stumbleglobals_upgrade", false);
+}
+
+StumbleGlobals.handle_stumble_topic_click = function(event, url)
+{
+	StumbleGlobals.set_server_location(
+				"url/" + StumbleGlobals.review_url(url),
+				null,
+				StumbleGlobals.new_tab(event));
+}
+
+// Generates the topic menu
+StumbleGlobals.prepare_stumble_topic_menu = function(event, url)
+{
+	var menuEl;
+	if (StumbleGlobals.ds.getValue("$stumble_topics_style") == 1)
+		menuEl = StumbleGlobals.get_element("stumbleglobals_stumble_topic_menu_right_popup")
+	else
+		menuEl = StumbleGlobals.get_element("stumbleglobals_stumble_topic_menu_left_popup");
+	
+	if (event.originalTarget != menuEl)
+		return;
+	
+	if (menuEl.getAttribute("data-url") == url)
+		return;
+	
+	menuEl.removeAttribute("data-url");
+	menuEl.setAttribute("data-url", url);
+
+	// Check if a menu already exists -> If so, we need to remove it
+	while(menuEl.childNodes.length)
+		menuEl.removeChild(menuEl.firstChild);
+	
+	var url_detail = StumbleGlobals.ds.lookup("url:url_detail", url);
+	var item;
+	var submenu;
+
+	item = document.createElement("menu");
+	item.setAttribute("label", " Report a problem");
+	item.setAttribute("tooltiptext", "Report...");
+	menuEl.appendChild(item);
+	submenu = document.createElement("menupopup");
+	submenu.setAttribute("id", "stumbleglobals_report_popup");
+	item.appendChild(submenu);
+	
+	StumbleGlobals.prepare_reporting_menu(submenu, url_detail, false, url_detail.url);
+	
+	item = document.createElement("menuseparator");
+	menuEl.appendChild(item);
+	
+	item = document.createElement("menuitem");
+	item.setAttribute("label", "This page is about:");
+	item.setAttribute("tooltiptext", "Change topic to...");
+	item.setAttribute("style", "font-weight: bold; color: #404040;");
+	item.setAttribute("disabled", "true");
+	menuEl.appendChild(item);
+	
+	var stumbler_name = StumbleGlobals.get_profile_nickname(url);
+	
+	if (stumbler_name)
+	{
+		item = document.createElement("menuitem")
+		item.setAttribute("label", "Stumbler"); // note: actual name is 'Stumblers'
+		if (url_detail.cur_catid == 44)
+		{
+			item.setAttribute("type", "checkbox");
+			item.setAttribute("checked", "true");
+			item.setAttribute("tooltiptext", "This is a stumbler profile");
+			item.setAttribute("oncommand", 'StumbleGlobals.handle_recat_reset_checkbox();');
+			item.style.fontWeight = 'bold';
+			item.style.color = "#008B00";
+		}
+		else
+		{
+			item.setAttribute("tooltiptext", "Request topic change from " + url_detail.cur_topic_name + " to Stumblers");
+			item.setAttribute("oncommand",
+					'StumbleGlobals.handle_recat_page(event, "' + url + '", 44, "Stumbler");');
+		}
+		menuEl.appendChild(item);
+		
+		item = document.createElement("menuitem")
+		item.setAttribute("label", "Adult Stumbler");
+		if (url_detail.cur_catid == 520)
+		{
+			item.setAttribute("type", "checkbox");
+			item.setAttribute("checked", "true");
+			item.setAttribute("tooltiptext", "This is an adult stumbler profile");
+			item.setAttribute("oncommand", 'StumbleGlobals.handle_recat_reset_checkbox();');
+			item.style.fontWeight = 'bold';
+			item.style.color = "#008B00";
+		}
+		else
+		{
+			item.setAttribute("tooltiptext", "Request topic change from " + url_detail.cur_topic_name + " to Adult Stumbler");
+			item.setAttribute("oncommand",
+					'StumbleGlobals.handle_recat_page(event, "' + url + '", 520, "Adult Stumbler");');
+		}
+		menuEl.appendChild(item);
+		
+		return;
+	}
+
+	var recat_adult = StumbleGlobals.ds.getValue("$recat_adult");
+	
+	// Add list of topics
+	var folders = new Array();
+	var folders_sorted = new Array();
+	var cats_sorted = new Array();
+	for (var cat in StumbleGlobals.catnames)
+	{
+		if (typeof(StumbleGlobals.topicfolders[cat]) == "undefined")
+			continue;
+		var folder = StumbleGlobals.topicfolders[cat];
+		var name = StumbleGlobals.catnames[cat];
+		if (typeof(folders[folder]) == "undefined")
+		{
+			folders[folder] = new Array();
+			folders_sorted.push(folder);
+			cats_sorted[folder] = new Array();
+		}
+	
+		folders[folder][name]=cat;
+		cats_sorted[folder].push(name);
+	}
+	
+	folders_sorted.sort();
+	
+	var nickname = StumbleGlobals.get_profile_nickname(url);
+	
+	for (var i = 0 ; i < folders_sorted.length ; i++)
+	{
+		var folder = folders_sorted[i];
+		
+		if (folder == "0")
+			continue; // Special treatment for the "StumbleUpon news" cat
+		
+		var item = document.createElement("menu");
+		item.setAttribute("label", folder);
+		item.setAttribute("tooltiptext", "Change topic to...");
+		//item.setAttribute("oncommand",
+		//		'StumbleGlobals.handle_stumble_topic_click(event, "' + url + '");');
+		menuEl.appendChild(item);
+		var foldermenu = document.createElement("menupopup");
+		item.appendChild(foldermenu);
+		
+		cats_sorted[folder].sort();
+		for ( var j = 0 ; j < cats_sorted[folder].length ; j++)
+		{
+			var cat = cats_sorted[folder][j];
+			var jcatid = folders[folder][cat];
+			if (folder == "Adult")
+			{
+				if (recat_adult == 0 && nickname && jcatid != 520)
+					continue;
+				else if (recat_adult == 0 && jcatid != 6 && jcatid != 500)
+					continue;
+				else if (recat_adult == 1 && jcatid != 6 && StumbleGlobals.ds.lookup("catid:x_flag", jcatid))
+					continue;
+			}
+			
+			var itemCat = document.createElement("menuitem")
+			itemCat.setAttribute("label", cat);
+			if (jcatid == url_detail.cur_catid)
+			{
+				itemCat.setAttribute("type", "checkbox");
+				itemCat.setAttribute("checked", "true");
+				itemCat.setAttribute("tooltiptext", "This page is about " + url_detail.cur_topic_name);
+				itemCat.setAttribute("oncommand", 'StumbleGlobals.handle_recat_reset_checkbox();');
+				item.style.fontWeight = 'bold';
+				item.style.color = "#008B00";
+			}
+			else
+			{
+				itemCat.setAttribute("tooltiptext", "Request topic change from " + url_detail.cur_topic_name + " to " + cat);
+				itemCat.setAttribute("oncommand",
+						'StumbleGlobals.handle_recat_page(event, "' + url + '", "' + jcatid + '", "' + cat + '");');
+			}
+			foldermenu.appendChild(itemCat);
+			
+			if (jcatid == url_detail.cur_catid)
+			{
+				itemCat.style.fontWeight = 'bold';
+				itemCat.style.color = "#008B00";
+			}
+		}
+	}
+	
+	var catid2 = url_detail.catid2;
+	var catid3 = url_detail.catid3;
+	var has_cat2 = (catid2 && catid2 != url_detail.cur_catid && StumbleGlobals.catnames[catid2] && StumbleGlobals.catnames[catid2] != '');
+	var has_cat3 = (catid3 && catid3 != url_detail.cur_catid && catid3 != catid2 && StumbleGlobals.catnames[catid3] && StumbleGlobals.catnames[catid3] != '');
+	
+	if (has_cat2 || has_cat3)
+	{
+		item = document.createElement("menuitem");
+		item.setAttribute("label", "Suggested:");
+		item.setAttribute("tooltiptext", "Change topic to...");
+//		if (has_cat2 && has_cat3)
+//			item.setAttribute("label", "Suggested alternates:");
+//		else
+//			item.setAttribute("label", "Suggested alternate:");
+		item.setAttribute("disabled", "true");
+		item.setAttribute("style", "font-weight: bold; color: #707070;");
+		menuEl.appendChild(item);
+	}
+	
+	// Add possible choices
+	if (has_cat2)
+	{
+		var itemCat = document.createElement("menuitem")
+		itemCat.setAttribute("label", " " + StumbleGlobals.catnames[catid2]);
+		itemCat.setAttribute("tooltiptext", "Request topic change from " + url_detail.cur_topic_name + " to " + StumbleGlobals.catnames[catid2]);
+		itemCat.setAttribute("oncommand",
+			'StumbleGlobals.handle_recat_page(event, "' + url + '", "' + catid2 + '", "' + StumbleGlobals.catnames[catid2] + '");');
+		menuEl.appendChild(itemCat);
+	}
+	
+	if (has_cat3)
+	{
+		var itemCat = document.createElement("menuitem")
+		itemCat.setAttribute("label", " " + StumbleGlobals.catnames[catid3]);
+		itemCat.setAttribute("tooltiptext", "Request topic change from " + url_detail.cur_topic_name + " to " + StumbleGlobals.catnames[catid3]);
+		itemCat.setAttribute("oncommand",
+			'StumbleGlobals.handle_recat_page(event, "' + url + '", "' + catid3 + '", "' + StumbleGlobals.catnames[catid3] + '");');
+		menuEl.appendChild(itemCat);
+	}
+
+}
+
+StumbleGlobals.handle_recat_reset_checkbox = function()
+{
+	StumbleGlobals.check_progress_listener();
+	
+	var menuEl;
+	if (StumbleGlobals.ds.getValue("$stumble_topics_style") == 1)
+		menuEl = StumbleGlobals.get_element("stumbleglobals_stumble_topic_menu_right_popup")
+	else
+		menuEl = StumbleGlobals.get_element("stumbleglobals_stumble_topic_menu_left_popup");
+	
+	// Menu will be recreated
+	menuEl.removeAttribute("data-url");
+}
+
+// Handle recat of a stumble page using the topic menu
+StumbleGlobals.handle_recat_page = function(event, url, catid, topic_name)
+{
+	StumbleGlobals.check_progress_listener();
+	
+	var detail = new Object();
+	detail.url = url;
+	detail.new_catid = catid;
+	detail.new_topic_name = topic_name;
+
+	var url_detail = StumbleGlobals.ds.lookup("url:url_detail", url);
+	if (url_detail)
+	{
+		detail.old_catid = url_detail.cur_catid;
+		detail.old_topic_name = url_detail.cur_topic_name;
+	}
+	else
+	{
+		detail.old_catid = 0;
+		detail.old_topic_name = "unknown";
+	}
+	
+	window.openDialog(
+				"chrome://stumbleupon/content/reportTopicDialog.xul",
+				"",
+				"chrome,titlebar,close,dialog,centerscreen,dependent",
+				detail);
+}
+
+StumbleGlobals.handle_report_topic_dialog_accept = function(detail)
+{
+	var url_detail = StumbleGlobals.ds.lookup("url:url_detail", detail.url);
+	url_detail.cur_catid = detail.new_catid;
+	url_detail.cur_topic_name = detail.new_topic_name;
+	StumbleGlobals.change_local_catid(detail.url, detail.new_catid);
+	
+	var menuEl;
+	if (StumbleGlobals.ds.getValue("$stumble_topics_style") == 1)
+		menuEl = StumbleGlobals.get_element("stumbleglobals_stumble_topic_menu_right_popup")
+	else
+		menuEl = StumbleGlobals.get_element("stumbleglobals_stumble_topic_menu_left_popup");
+	
+	// Menu will be recreated
+	menuEl.removeAttribute("data-url");
+	menuEl.setAttribute("onpopupshowing",
+			'StumbleGlobals.prepare_stumble_topic_menu(event, "' + detail.url + '");');
+	menuEl.parentNode.setAttribute("label", detail.new_topic_name);
+	
+	// Tell the server to recat the page
+	var doc = getBrowser().contentDocument;
+	var context = new StumbleGlobals.AsyncContext();
+	context.url = detail.url;
+	context.ref_url = StumbleGlobals.get_browser_url(doc, true);
+	context.title = StumbleGlobals.get_title(doc, context.ref_url);
+	
+	var params = "";
+	params = StumbleGlobals.arp(params, "url", detail.url);
+	params = StumbleGlobals.arp(params, "redirect", url_detail.redirect_url);
+	params = StumbleGlobals.arp(params, "current", StumbleGlobals.get_browser_url());
+	params = StumbleGlobals.arp(params, "newcatid", detail.new_catid);
+	
+	params = StumbleGlobals.append_sync_params(params);
+	
+	StumbleGlobals.post_url_server_async(
+				"recat.php",
+				params,
+				null,
+				StumbleGlobals.generic_done,
+				context);
+
+	StumbleGlobals.check_progress_listener();
+}
+
+StumbleGlobals.handle_sponsor_click = function(event)
+{
+	var target = "sponsored_page.html";
+	StumbleGlobals.set_server_location(target, null, StumbleGlobals.new_tab(event));
+}
+
+StumbleGlobals.handle_bug_command = function()
+{
+	var email = "joe at stumbleupon.com";
+	var date = new Date();
+	var str;
+	
+	str = "";
+	str += "The toolbar will now open two tabs:\n\n";
+	str += "o The first tab will attempt to open your e-mail application.\n\n";
+	str += "o The second tab will display the error report.  Use this if you\n";
+	str += "   prefer to copy-and-paste into a web-based e-mail account.\n";
+	str += " ";
+	var response = confirm(str);
+	
+	if (! response)
+		return;
+	
+	str = "[";
+	if ((StumbleGlobals.stumbleid != 0) && StumbleGlobals.ds && (StumbleGlobals.ds.getValue("$nick") != "")) 
+		str += StumbleGlobals.ds.getValue("$nick") + ":";
+	if (StumbleGlobals.stumbleid != 0)
+		str += StumbleGlobals.stumbleid + "] ";
+	str += "toolbar bug report";
+	var subject = str;
+	
+	
+	str = "=== behavior ===\n";
+	str += "\n";
+	str += "Please describe the action(s) you performed.\n";
+	str += "\n";
+	str += "Then describe how the toolbar responded.\n";
+	str += "\n";
+	str += "Feel free to attach screenshots if applicable.\n";
+	str += "\n";
+	str += "\n";
+	str += "=== platform ===\n";
+	str += StumbleGlobals.host.desc + "\n";
+	str += navigator.userAgent + "\n";
+	str += StumbleGlobals.useragent + "\n";
+	str += date.toUTCString() + "\n";
+	if (StumbleGlobals.service && (StumbleGlobals.service._messageLog != ""))
+	{
+		str += "\n";
+		str += "\n";
+		str += "=== log ===";
+		str += StumbleGlobals.service._messageLog;
+	}
+	try {
+		str += "\n\n" + StumbleGlobals.get_addons_desc();
+	} catch (e) {}
+	var body = str;
+	
+	
+	str = "mailto:" + email + "?subject=";
+	str += encodeURIComponent(subject) + "&body=";
+	str += encodeURIComponent(body);
+	
+	StumbleGlobals.set_location(str, null, true);
+	
+	str = "\n     TO: " + email + "\n";
+	str += "SUBJECT: " + subject + "\n\n\n" 
+	str += body;
+	
+	var filename = date.getTime() + ".txt"; 
+	StumbleGlobals.ds.writeFile(
+				StumbleGlobals.ds.getResourceNSIFile("reports", filename), 
+				str);
+	
+	StumbleGlobals.set_location(
+				StumbleGlobals.ds.getResourceURLFromName("reports", filename),
+				null,
+				true);
+}
+
+StumbleGlobals.get_addons_desc = function()
+{
+	// @todo: nsiExtensionManager doesn't exist in FF4.
+	var i;
+	var extension_manager = StumbleGlobals.get_service(
+				"@mozilla.org/extensions/manager;1",
+				"nsIExtensionManager");
+	if(!extension_manager)
+		return "";
+	
+	var datasource = extension_manager.datasource;
+	var root = StumbleGlobals.get_rdf_resource("urn:mozilla:item:root");
+	var container = StumbleGlobals.create_instance(
+				"@mozilla.org/rdf/container;1",
+				"nsIRDFContainer");
+	container.Init(datasource, root);
+	var elements = container.GetElements();
+
+	var attributes = new Array(
+				"name",
+				"version",
+				"appDisabled",
+				"userDisabled",
+				"internalName");
+				
+	var extensions = new Array();
+	var themes = new Array();
+
+	while(elements.hasMoreElements())
+	{
+		var element = elements.getNext();
+		var item = new Object();
+		for (i = 0; i < attributes.length; i++)
+		{
+			item[attributes[i]] = StumbleGlobals.get_rdf_arc_literal(
+						datasource,
+						element,
+						"http://www.mozilla.org/2004/em-rdf#" + attributes[i]);
+		}
+
+		var type_id = StumbleGlobals.get_rdf_arc_int(
+					datasource,
+					element,
+					"http://www.mozilla.org/2004/em-rdf#type");
+					
+		switch (type_id)
+		{
+			case 2: extensions.push(item); break;
+			case 4: themes.push(item); break;
+		}
+	}
+	
+	extensions.sort(function (a, b)
+				{ 
+					return a.name.toLowerCase() > b.name.toLowerCase();
+				});
+
+	themes.sort(function (a, b)
+				{
+					return a.name.toLowerCase() > b.name.toLowerCase();
+				});
+	
+	var str = "=== extensions ===\n";
+	for (i = 0; i < extensions.length; i++)
+	{
+		str += extensions[i].name + " ";
+		str += extensions[i].version;
+		if (extensions[i].appDisabled || extensions[i].userDisabled)
+			str += " [disabled]";
+		str += "\n";
+	}
+	
+	var current_theme = null;
+	try {
+		current_theme = StumbleGlobals.ds.getValue("general.skins.selectedSkin");
+	} catch(e) {}
+
+	str += "\n\n=== themes ===\n";
+	for (i = 0; i < themes.length; i++)
+	{
+		str += themes[i].name + " ";
+		str += themes[i].version;
+		if (themes[i].internalName == current_theme)
+			str += " [selected]";
+		str += "\n";
+	}
+	return str;
+}
+
+
+StumbleGlobals.refresh_pagemeta = function(from_stumblevideo_page, from)
+{
+	if (StumbleGlobals.refreshing_pagemeta)
+		return;
+	
+	StumbleGlobals.refreshing_pagemeta = true;
+	
+	setTimeout(
+				StumbleGlobals.update_pagemeta,
+				100,
+				from_stumblevideo_page,
+				from);
+}
+
+// Handler for when the page being viewed changes.
+StumbleGlobals.update_pagemeta = function(from_stumblevideo_page, from)
+{
+	//!!! This needs either (a) to get some code documentation or (b)
+	//    to be refactored into several functions with descriptive
+	//    names. -- JW
+	// Refactoring into several functions is in progress. -- JW
+	StumbleGlobals.refreshing_pagemeta = false;
+
+	if (StumbleGlobals.new_user)
+		return;
+	
+	var doc = getBrowser().contentDocument;
+	var new_url = StumbleGlobals.get_browser_url(doc);
+	var raw_url = StumbleGlobals.get_browser_url(doc, true);
+	
+	var new_tld;
+	var rateable = false;
+	var rec_url = null;
+	var url_detail = null;
+	var stumblevideo = StumbleGlobals.is_matching_domain(raw_url, "video." + StumbleGlobals.servername);
+	if (stumblevideo && (! from_stumblevideo_page))
+		StumbleGlobals.stumblevideo_page(doc, false);
+	
+	try {
+		if (! url_detail)
+			url_detail = StumbleGlobals.ds.lookup("url:url_detail", new_url);
+		
+		if (url_detail)
+		{
+			new_url = url_detail.url;
+			new_tld = url_detail.tld;
+			rateable = true;
+			rec_url = url_detail.url;
+		}
+		else if (StumbleGlobals.stumbleid)
+		{
+			new_tld = StumbleGlobals.get_tld(new_url);
+			rateable = StumbleGlobals.is_url_rateable(new_url, new_tld);
+			if (StumbleGlobals.ds.lookup("url:from_portal_flag", new_url))
+			{
+				rec_url = new_url;
+			}
+			else if (StumbleGlobals.get_tld(StumbleGlobals.get_browser_referrer_url(doc)) == StumbleGlobals.servername)
+			{
+				StumbleGlobals.ds.define("url:from_portal_flag", new_url, 1);
+				rec_url = new_url;
+			}
+		}
+	} catch (e) { StumbleGlobals.log_error("PAGEVIEW DETAILLOOKUP", e); }
+	
+    if (StumbleGlobals.promo_mode && (StumbleGlobals.stumbleid == 0))
+	{
+		
+		try {
+			StumbleGlobals.update_website_info_promo(new_url);
+		} catch (e) { StumbleGlobals.log_error("PAGEVIEW INFOPROMO", e); }
+		
+		try {
+			if (StumbleGlobals.get_stumblevideo_detail())
+				StumbleGlobals.set_visible("stumbleglobals_thumbdown", true);
+			else
+				StumbleGlobals.set_visible("stumbleglobals_thumbdown", false);
+	
+			//!!! we do enable all the time to fix thet problem where sometimes the comment button doesn't get cleared?
+			if (typeof(StumbleGlobals.ratings[new_url]) != "undefined")
+				StumbleGlobals.disable_toolbar(StumbleGlobals.ratings[new_url]);
+			else
+				StumbleGlobals.enable_toolbar();
+		} catch (e) { StumbleGlobals.log_error("PAGEVIEW PROMORATEBUTTONS", e); }
+		
+		return;
+	}
+	else if (StumbleGlobals.stumbleid == 0)
+	{
+		return;	
+	}
+	
+	var stumbler_name = null; 
+	
+	if ((new_tld == StumbleGlobals.servername) || (new_tld == 'stumbleupon.com'))
+		stumbler_name = StumbleGlobals.get_profile_nickname(new_url);
+	
+	if (stumbler_name)
+		rec_url = new_url;
+	
+	var non_self_stumbler = (stumbler_name &&
+			(stumbler_name != StumbleGlobals.stumbleid) &&
+			(stumbler_name != StumbleGlobals.ds.getValue("$nick")));
+
+	var browser = getBrowser().selectedBrowser;
+	
+	var tab_url_detail = (browser.stumbleglobals_url_detail) ? browser.stumbleglobals_url_detail : null;
+	
+	try {
+		StumbleGlobals.update_thru_domain(new_url, new_tld, url_detail, stumblevideo, false);
+	} catch (e) { StumbleGlobals.log_error("PAGEVIEW FAVICON", e); }
+	try {
+		StumbleGlobals.update_message(tab_url_detail, url_detail, new_url, new_tld, stumblevideo);
+	} catch (e) { StumbleGlobals.log_error("PAGEVIEW MESSAGE", e); }
+	try {
+		StumbleGlobals.update_page_feature_prompt(new_url);
+	} catch (e) { StumbleGlobals.log_error("PAGEVIEW FEATUREPROMPT", e); }
+	try {
+		StumbleGlobals.update_firstrater(url_detail);
+	} catch (e) { StumbleGlobals.log_error("PAGEVIEW FIRSTRATER", e); }
+	try {
+		StumbleGlobals.update_topic_and_reporting(tab_url_detail, url_detail, new_tld, false, rec_url);
+	} catch (e) { StumbleGlobals.log_error("PAGEVIEW TOPIC", e); }
+//	try {
+//		StumbleGlobals.update_language(url_detail, false);
+//	} catch (e) { StumbleGlobals.log_error("PAGEVIEW LANGUAGE", e); }
+	try {
+		StumbleGlobals.update_comment_level(url_detail, rateable);
+	} catch (e) { StumbleGlobals.log_error("PAGEVIEW COMMENT", e); }
+	try {
+		StumbleGlobals.update_referral_menu_tooltip(url_detail, stumblevideo);
+	} catch (e) { StumbleGlobals.log_error("PAGEVIEW TOOLTIP", e); }
+	try {
+		StumbleGlobals.update_thumbs(new_url, rateable, non_self_stumbler, stumblevideo, url_detail);
+	} catch (e) { StumbleGlobals.log_error("PAGEVIEW THUMBS", e); }
+	try {
+		StumbleGlobals.update_stumbling_options(non_self_stumbler, stumbler_name); 
+	} catch (e) { StumbleGlobals.log_error("PAGEVIEW STUMBLER", e); }
+	try {
+		StumbleGlobals.update_tags(new_url)
+	} catch (e) { StumbleGlobals.log_error("PAGEVIEW TAGS", e); }
+	
+	
+	// See if this is a tag page
+	// only do this is text is on
+	var tag_page = 0;
+	var tag_name = '';
+
+	try {
+		if (new_url.indexOf(StumbleGlobals.base_url + "tag/") == 0)
+		{
+			spliturl = new_url.split("/");
+			if (spliturl.length > 4 && spliturl[4] != '')
+			{
+				tag_name = spliturl[4];
+				//alert("tag " + tag_name);
+				tag_page = 1;
+			}
+		}
+	
+		if (tag_page)
+		{
+			// change favorites of
+			el = StumbleGlobals.get_element("stumbleglobals_cat_stumble_tags");
+			if (el)
+			{
+				el.setAttribute("label", "Through " + tag_name + "...");
+				el.setAttribute("oncommand", "StumbleGlobals.select_topic('TAG_" + tag_name + "', '" + tag_name + "', false);");
+				el.setAttribute("tooltiptext", stumbler_name + "'s Pages");				
+			}
+			StumbleGlobals.set_image("stumbleglobals_category", "chrome://stumbleupon/content/skin/tag.png");
+		}
+		else
+		{
+			el = StumbleGlobals.get_element("stumbleglobals_cat_stumble_tags");
+			if (el)
+			{
+				el.setAttribute("label", "Search");
+				el.setAttribute("oncommand", 'StumbleGlobals.handle_mode_click(event, "Search");');
+				el.setAttribute("tooltiptext", "Stumble within a query");
+			}
+		}
+	} catch (e) { StumbleGlobals.log_error("PAGEVIEW TAG", e); }
+
+
+	try {
+		// Reset message when we hit the message page
+		if (new_url.indexOf("." + StumbleGlobals.servername + "/inbox/")!=-1)
+		{
+			StumbleGlobals.ds.setValue("$newmessage", false);
+			StumbleGlobals.set_inbox_status('');
+		}
+	} catch (e) { StumbleGlobals.log_error("PAGEVIEW INBOX", e); }
+
+
+	setTimeout("StumbleGlobals.reflow_toolbar(15)", 80);
+	
+}
+
+StumbleGlobals.update_thumbs = function(url, rateable, non_self_stumbler, stumblevideo, url_detail)
+{
+	if (stumblevideo)
+		StumbleGlobals.get_element("stumbleglobals_thumbdown").type = "";
+	else
+		StumbleGlobals.get_element("stumbleglobals_thumbdown").type = "menu-button";
+	
+	var rating;
+	if (rateable)
+		rating = StumbleGlobals.get_rating(url, stumblevideo, url_detail);
+	else
+		rating = null;
+	
+	//!!! we do enable all the time to fix thet problem where sometimes the comment button doesn't get cleared?
+	if (rating == null)
+		StumbleGlobals.enable_toolbar();
+	else
+		StumbleGlobals.disable_toolbar(rating);
+		
+	// disable rating buttons on url pages
+	if (rateable)
+	{
+//			StumbleGlobals.get_element("stumbleglobals_thumbdown").disabled=false;
+		// if the thumb isn't green, we should enable it
+		StumbleGlobals.get_element("stumbleglobals_thumbup").disabled=false;
+		StumbleGlobals.get_element("stumbleglobals_thumbdown").disabled=false;
+		StumbleGlobals.get_element("stumbleglobals_thumbup").setAttribute("onclick", StumbleGlobals.get_element("stumbleglobals_thumbup").getAttribute("onclick2"));
+	}
+	else
+	{
+		// disable rating buttons
+		StumbleGlobals.get_element("stumbleglobals_thumbup").disabled=true;
+		StumbleGlobals.get_element("stumbleglobals_thumbdown").disabled=true;
+		StumbleGlobals.get_element("stumbleglobals_thumbup").setAttribute("onclick", "");
+	}
+	
+	if (StumbleGlobals.ds.getValue("$icons") != "icons-only")
+	{
+		if (non_self_stumbler)
+			StumbleGlobals.set_label("stumbleglobals_thumbup", StumbleGlobals.get_element("stumbleglobals_thumbup").getAttribute('showlabel2'));
+		
+		else			
+			StumbleGlobals.set_label("stumbleglobals_thumbup", StumbleGlobals.get_element("stumbleglobals_thumbup").getAttribute('showlabel'));
+	}
+}
+
+StumbleGlobals.update_tags = function(new_url)
+{
+	var tag_list = StumbleGlobals.get_tag_list(new_url);
+	
+	if (tag_list)
+		StumbleGlobals.disable_tag_toolbar(tag_list);
+	else
+		StumbleGlobals.enable_tag_toolbar();
+}
+
+StumbleGlobals.update_stumbling_options = function(non_self_stumbler, stumbler_name)
+{
+	var el;
+	
+	if (non_self_stumbler)
+	{
+		el = StumbleGlobals.get_element("stumbleglobals_cat_favorites_of2");
+		if (el)
+		{
+			el.setAttribute("label", stumbler_name + "'s Favorites");
+			el.setAttribute("onclick", 'StumbleGlobals.handle_mode_click(event, "' + stumbler_name + '");');
+			el.setAttribute("tooltiptext", stumbler_name + "'s favorites");				
+			if (StumbleGlobals.is_mutual_friend(stumbler_name))
+				el.setAttribute("image", "chrome://stumbleupon/content/skin/mutual_favorites.png");
+			else
+				el.setAttribute("image", "chrome://stumbleupon/content/skin/stumbler_favorites.png");
+			el.setAttribute("hidden", "false");
+		}
+
+		el = StumbleGlobals.get_element("stumbleglobals_mode_stumbler");
+		el.setAttribute("tooltiptext", "Stumble " + stumbler_name + "'s favorites");
+		el.setAttribute("onclick", 'StumbleGlobals.handle_mode_click(event, "' + stumbler_name + '");');
+		if (StumbleGlobals.is_mutual_friend(stumbler_name))
+			StumbleGlobals.set_image("stumbleglobals_mode_stumbler", "chrome://stumbleupon/content/skin/mutual_favorites.png");
+		else
+			StumbleGlobals.set_image("stumbleglobals_mode_stumbler", "chrome://stumbleupon/content/skin/stumbler_favorites.png");
+		StumbleGlobals.set_visible("stumbleglobals_mode_stumbler", true);
+	}
+	else
+	{
+		el = StumbleGlobals.get_element("stumbleglobals_cat_favorites_of2");
+		if(el)
+		{
+			el.setAttribute("hidden", "true");
+		}
+		
+		StumbleGlobals.set_visible("stumbleglobals_mode_stumbler", (! StumbleGlobals.ds.getValue("$show_mode_stumbler")));
+	}
+}
+
+StumbleGlobals.get_profile_nickname = function(url)
+{
+	var domain = StumbleGlobals.get_tld(url);
+	
+	if (domain == 'stumbleupon.com')
+	{
+		var spliturl = url.split("/");
+		
+		var domains = spliturl[2].split(".");
+		
+		if (domains.length != 3)
+			return null;
+			
+		if (StumbleGlobals.ds.lookup("nickname:bad_nick_flag", domains[0]))
+			return null;
+		
+		return domains[0];
+	}
+	else if ((StumbleGlobals.servername != 'stumbleupon.com')
+			&& (domain == StumbleGlobals.servername))
+	{
+		var spliturl = url.split("/");
+		
+		var domains = spliturl[2].split(".");
+		
+		var serverparts = StumbleGlobals.servername.split(".");
+
+		if (domains.length != (serverparts.length + 1))
+			return null;
+			
+		if (StumbleGlobals.ds.lookup("nickname:bad_nick_flag", domains[0]))
+			return null;
+		
+		return domains[0];
+	}
+	else
+	{
+		return null;
+	}
+}
+
+StumbleGlobals.get_service_id = function(url, results_page_only)
+{
+	if (! url.match(/(google|yahoo|ask|myspace|youtube|flickr|wikipedia|aol|cnn|bing|nytimes|cbsnews|cnet|abcnews|msnbc)/i))
+		return null;
+	
+	url = url.toLowerCase();
+	
+	if (url.match(/^http.*?\/\/[^\/]*?(google\.[^\.]+|google\.co\.[^\.]+)\/$|((search|custom|webhp|\#)(q|.*[?&](q|as_q))=)/))
+		return "google";
+
+	else if (url.match(/^http.*?\/\/[^\/]*?(www\.ask\.com)\/(web.*[?&]q=)/))
+		return "ask";
+	
+	else if (url.match(/^http.*?\/\/[^\/]*?(www\.bing\.com)\/(search.*?q=)/))
+		return "bing";
+	
+	else if (url.match(/^http.*?\/\/[^\/]*?(www\.bing\.com)\/news\/(search.*?q=)/))
+		return "bing-news";
+	
+	else if (url.match(/^http.*?\/\/[^\/]*?((search|custom)(\.)(.*(\.))?yahoo(\.).*)\/(search.*[?&]p=)/))
+		return "yahoo";
+
+	else if (url.match(/^http.*?\/\/[^\/]*?(search(\.)(.*(\.))?aol(\.).*)\/(search.*[?&]query=)/))
+		return "aol";
+	
+	else if (url.match(/^http.*?\/\/[^\/]*?(searchservice\.myspace\.com)\/.*[?&]fuseaction=sitesearch\.results/))
+		return "myspace";
+	
+	else if (url.match(/^http.*?\/\/[^\/]*?(youtube\.com)\/results.*[?&]search_query=/))
+		return "youtube";
+	
+	else if (url.match(/^http.*?\/\/[^\/]*?flickr\.[^\.]+\/(search|.*[?&]q=)/))
+		return "flickr";
+	
+	else if (url.match(/^http.*?\/\/[^\/]*\.wikipedia\.org\/wiki\//))
+		return "wikipedia";
+	
+	else if (url.match(/^http:\/\/search\.cnn\.com\/search.*[?&]query=/))
+		return "cnn";
+	
+	else if (url.match(/^http:\/\/query\.nytimes\.com\/search\/.*[?&]query=/))
+		return "nyt";
+	
+	else if (url.match(/^http.*?\/\/(search|www)\.cbsnews\.com.*[?&]query=/))
+		return "cbsnews";
+	
+	else if (url.match(/^http.*?\/\/news\.cnet\.com.*[?&]query=/))
+		return "cnetnews";
+	
+	else if (url.match(/^http.*?\/\/abcnews\.go\.com.*[?&]searchtext=/))
+		return "abcnews";
+	
+	else if (url.match(/^http:\/\/([^\.]*?\.)?msnbc\.msn\.com\/.*[?&]q=/))
+		return "msnbc";
+	
+	else if (results_page_only)
+		return null;
+
+	else if (url.match(/^http.*?\/\/((www|news|video)\.google\.[^\.]+|(www|news|video)\.google\.co\.[^\.]+)/))
+		return "google";
+	
+	else if (url.indexOf("http://www.ask.com") == 0)
+		return "ask";
+	
+	else if (url.indexOf("http://www.yahoo.com") == 0)
+		return "yahoo";
+	
+	else if (url.indexOf("http://www.aol.com") == 0)
+		return "aol";
+    
+	else
+		return null;
+
+	
+// Porting search page filters from the iebar follows the general 
+// pattern below.  Note that migrating from strings to literal regular
+// expressions involves changing some escaping.
+//	    else if (url.match(/^http.*?\/\/[^/]*?(URL_HOST_MATCH)/(PATH_MATCH)/))
+// -- JW
+}
+
+StumbleGlobals.get_service_meta = function(url, results_page_only)
+{
+	var service_id = StumbleGlobals.get_service_id(url, results_page_only);
+
+	if (! service_id)
+		return null;
+
+	var detail = new Object();
+	
+	detail.id = service_id;	
+	switch (service_id)
+	{
+		case "google":
+			detail.name = "Google";
+			detail.icon = "chrome://stumbleupon/content/skin/favicon_google.png";
+			break;
+		case "ask":
+			detail.name = "Ask";
+			detail.icon = "chrome://stumbleupon/content/skin/favicon_ask.png";
+			break;
+        case "bing":
+            detail.name = "Bing";
+            detail.icon = "chrome://stumbleupon/content/skin/bubble.png";
+            break;
+		case "yahoo":
+			detail.name = "Yahoo";
+			detail.icon = "chrome://stumbleupon/content/skin/favicon_yahoo.png";
+			break;
+		case "aol":
+			detail.name = "AOL";
+			detail.icon = "chrome://stumbleupon/content/skin/favicon_aol.png";
+			break;
+		case "youtube":
+			detail.name = "YouTube";
+			detail.icon = "chrome://stumbleupon/content/skin/favicon_youtube.png";
+			break;
+		case "flickr":
+			detail.name = "Flickr";
+			detail.icon = "chrome://stumbleupon/content/skin/favicon_flickr.png";
+			break;
+		default:
+			detail = null;
+			break;
+	}
+	
+	if (detail)
+	{
+		detail.prompt_label = "See ratings on " + detail.name;
+		detail.prompt_tooltip = "See who likes your " + detail.name + " search results";
+	}
+	
+	return detail;
+}
+
+StumbleGlobals.get_search_query_detail = function(opt_service_id, opt_url)
+{
+	var url;
+	if (opt_url)
+		url = opt_url;
+	else
+		url = StumbleGlobals.get_browser_url();
+	
+	var service_id;
+	if (opt_service_id)
+		service_id = opt_service_id;
+	else
+		service_id = StumbleGlobals.get_service_id(url, true);
+	
+	var detail = new Object();
+	detail.term_count = 0;
+	detail.is_query_results = false;
+	detail.is_short_query_results = false;
+	detail.is_first_page = true;
+	detail.domain = StumbleGlobals.get_domain(url);
+	detail.service_id = service_id;
+	
+	var query_match;
+	var page_match;
+	switch (service_id)
+	{
+		case "google":
+			page_match = url.match(/[?&](start=)/);
+			query_match = url.match(/[?&]q=([^&]*)/);
+			break;
+		case "ask":
+			page_match = url.match(/[?&](page=)/);
+			query_match = url.match(/[?&]q=([^&]*)/);
+			break;
+        case "bing":
+            page_match = url.match(/[?&](first=)/);
+            query_match = url.match(/[?&]q=([^&]*)/);
+            break;
+		case "yahoo":
+			page_match = url.match(/[?&](b=)/);
+			query_match = url.match(/[?&]p=([^&]*)/);
+			break;
+		case "aol":
+			page_match = url.match(/[?&](page=)/);
+			query_match = url.match(/[?&]query=([^&]*)/);
+			break;
+	}
+	
+	if (query_match && query_match[1])
+		detail.term_count = query_match[1].split("+").length;
+
+	if (query_match)
+		detail.is_query_results = true;
+	
+	if ((detail.term_count > 0) && (detail.term_count < 3))
+		detail.is_short_query_results = true;
+	
+	if (page_match && page_match[1])
+		detail.is_first_page = false;
+	
+	return detail;
+}
+
+function checkReportPhishing(doc)
+{
+	try {
+		if( (StumbleGlobals.stumbleid == 0) || !StumbleGlobals.ds.getValue("@report_phishing") )
+			return;
+		
+		if(doc && doc.documentURI)
+		{
+			var uri = doc.documentURI;
+			if(uri.indexOf("about:blocked") == 0)
+			{
+				var regexReason = /[\?&]e=([^&]*)/;
+				var regexUrl = /[\?&]u=([^&]*)/;
+				
+				var params = "";
+				var match = uri.match(regexUrl);
+				if(!match)
+					return;  // Can't report it if we don't have it!
+				
+				var url = decodeURIComponent(match[1]);
+				var url_detail = StumbleGlobals.ds.lookup("url:url_detail", url);
+				if (url_detail)
+				{
+					var params = "";
+					params = StumbleGlobals.arp(params, "url", url);
+					
+					if(url_detail.urlid)
+						params = StumbleGlobals.arp(params, "urlid", url_detail.urlid);
+					if(url_detail.publicid)
+						params = StumbleGlobals.arp(params, "publicid", url_detail.publicid);
+					
+					match = uri.match(regexReason);
+					if(match)
+					{
+						var reason = decodeURIComponent(match[1]);
+						params = StumbleGlobals.arp(params, "reason", reason);
+					}
+					
+					StumbleGlobals.post_url_server_async(
+							"phishing.php",
+							params,
+							15000,
+							StumbleGlobals.generic_done);
+				}
+			}
+		}
+	} catch (e) {}
+}
+
+// handles the DOMContentLoaded event
+StumbleGlobals.on_load_page = function(event)
+{
+	var doc = event.target;
+	checkReportPhishing(doc);
+
+	var url;
+	try {
+		url = StumbleGlobals.get_browser_url(doc).toLowerCase();
+	} catch (e) { return; }
+
+		
+	try {
+		var win = doc.defaultView.wrappedJSObject;
+		
+		try {
+			// Track the first "load" event, even for child elements, this more closely
+			// matches the semantics of the iPhone
+			StumbleGlobals.requestTracker.trackEvent(win.top.location.href, "load");
+		} catch (e) {}
+		
+		if (win.top != win)
+			return;
+	} catch (e) {}
+	
+	var tld = StumbleGlobals.get_tld(url);
+	var portal_http = false;
+	var portal_tld = false;
+	
+	// Track this page load
+	StumbleGlobals.requestTracker.trackEvent(url, "pageLoaded");		
+
+	if (tld == StumbleGlobals.servername)
+	{
+		portal_tld = true;
+		
+		StumbleGlobals.attach_api(doc);
+		
+		StumbleGlobals.wire_portal_links(doc);
+
+		if (StumbleGlobals.visited_login_page)
+			StumbleGlobals.login_page_after();
+		
+		if (StumbleGlobals.is_server_page(url, ""))
+		{
+			portal_http = true;
+			
+			// signup.php -- the page we send them to
+			if (StumbleGlobals.is_server_page(url, "signup.php"))
+				StumbleGlobals.signup_page(doc);
+			
+			// sign_up.php -- the page they go to if they click "Join stumbleupon"
+			// from the web site
+			else if (StumbleGlobals.is_server_page(url, "sign_up.php"))
+				StumbleGlobals.sign_up_page(url);
+			
+			else if (StumbleGlobals.is_server_page(url, "find_friends.php"))
+				StumbleGlobals.find_friends_page(url);
+			
+			else if (StumbleGlobals.is_server_page(url, "login.php"))
+				StumbleGlobals.login_behavior_page();
+		}
+		else if (StumbleGlobals.is_matching_domain(url, "video." + StumbleGlobals.servername))
+		{
+			StumbleGlobals.stumblevideo_page(doc, true);
+		}
+	}
+	else if (tld == "facebook.com")
+	{
+		StumbleGlobals.facebook_page(doc, url);
+	}
+	
+	setTimeout(StumbleGlobals.check_progress_listener, 0);
+	
+	if (StumbleGlobals.stumbleid == 0)
+		return;
+	
+	if (StumbleGlobals.has_searchbox)
+	{
+		setTimeout(StumbleGlobals.restore_searchbox_focus, 100);
+		setTimeout(StumbleGlobals.restore_searchbox_focus, 300);
+		setTimeout(StumbleGlobals.restore_searchbox_focus, 1000);
+		setTimeout(StumbleGlobals.restore_searchbox_focus, 3000);
+	}
+	
+	var search_results_service_id = StumbleGlobals.get_service_id(url, true);
+	var search_service_id =  StumbleGlobals.get_service_id(url, false);
+	
+	if (search_results_service_id)
+		StumbleGlobals.search_results_page(doc, search_results_service_id);
+	
+	else if (search_service_id)
+		StumbleGlobals.search_service_page(doc, search_service_id);
+	
+	else if (portal_http)
+	{
+		StumbleGlobals.portal_http_page(doc);
+		
+		if (url.indexOf(StumbleGlobals.serverhttp + "tag/") == 0)
+			StumbleGlobals.tag_page(doc);
+
+		else if (url.indexOf(StumbleGlobals.serverhttp + "find_friends_after.php") == 0)
+			StumbleGlobals.find_friends_after_page();
+	
+		else if (url.indexOf(StumbleGlobals.serverhttp + "interests_after.php") == 0)
+			StumbleGlobals.legacy_interests_after_page(doc);
+		
+		else if (url.indexOf(StumbleGlobals.serverhttp + "topic/") == 0)
+			StumbleGlobals.tag_page(doc);
+	}
+	
+	else if (portal_tld)
+	{
+		var host = StumbleGlobals.ds.getValue("$nick").toLowerCase() + "." + StumbleGlobals.servername + "/";
+		var profilehttp = "http://" + host;
+		var profilehttps = "https://" + host;
+		if ((url.indexOf(profilehttp + "prefs/interests")==0) ||
+			(url.indexOf(profilehttps + "prefs/interests")==0))
+			StumbleGlobals.interests_page(doc);
+		else if ((url.indexOf(profilehttp + "prefs/" )==0) ||
+				(url.indexOf(profilehttps + "prefs/" )==0))
+			StumbleGlobals.prefs_page(doc);
+	}
+	
+	StumbleGlobals.refresh_pagemeta(false, 7);
+}
+
+StumbleGlobals.get_debug_header = function()
+{
+	// @todo: nsIExtensionManager doesn't exist in FF4, use the AddonManager
+	var extension_manager = StumbleGlobals.get_service(
+				"@mozilla.org/extensions/manager;1",
+				"nsIExtensionManager");
+	
+	if(!extension_manager)
+		return "";
+	
+	var datasource = extension_manager.datasource;
+	var root = StumbleGlobals.get_rdf_resource("urn:mozilla:item:root");
+	var container = StumbleGlobals.create_instance(
+				"@mozilla.org/rdf/container;1",
+				"nsIRDFContainer");
+	container.Init(datasource, root);
+	var elements = container.GetElements();
+
+	var attributes = new Array(
+				"name",
+				"version",
+				"appDisabled",
+				"userDisabled");
+				
+	var gm_detail = null;
+	var ns_detail = null;
+	while(elements.hasMoreElements())
+	{
+		var element = elements.getNext();
+		var item = new Object();
+		for (i = 0; i < attributes.length; i++)
+		{
+			item[attributes[i]] = StumbleGlobals.get_rdf_arc_literal(
+						datasource,
+						element,
+						"http://www.mozilla.org/2004/em-rdf#" + attributes[i]);
+		}
+
+		var type_id = StumbleGlobals.get_rdf_arc_int(
+					datasource,
+					element,
+					"http://www.mozilla.org/2004/em-rdf#type");
+		
+		if (type_id == 2 && item.name && item.name == "Greasemonkey")
+		{
+			gm_detail = new Object();
+			gm_detail.version = item.version;
+			gm_detail.enabled = (item.appDisabled || item.userDisabled) ? 0 : 1;
+		}
+		else if (type_id == 2 && item.name && item.name == "NoScript")
+		{
+			ns_detail = new Object();
+			ns_detail.version = item.version;
+			ns_detail.enabled = (item.appDisabled || item.userDisabled) ? 0 : 1;
+		}
+		
+		if (gm_detail && ns_detail)
+			break;
+	}
+	
+	if ((! gm_detail) && (! ns_detail))
+		return null;
+	
+	var obj = new Object();
+
+	if (gm_detail)
+	{
+		if (StumbleGlobals.ds.isPrefDefined("greasemonkey.enabled"))
+			gm_detail.running = (StumbleGlobals.ds.getValue("greasemonkey.enabled")) ? 1 : 0;
+			
+		var scripts = StumbleGlobals.get_gm_scripts();
+		if (scripts)
+			gm_detail.scripts = scripts;
+
+		obj.greasemonkey = gm_detail;
+	}
+	
+	if (ns_detail)
+	{
+		if (StumbleGlobals.ds.isPrefDefined("noscript.global"))
+			ns_detail.running = (StumbleGlobals.ds.getValue("noscript.global")) ? 0 : 1;
+
+		obj.noscript = ns_detail;
+	}
+	
+	return StumbleGlobals.ds.serialize(obj, false);
+}
+
+//
+// StumbleGlobals.dotversion_compare
+//
+// Compares two version numbers of the form a.b.c.d.
+// Results are:
+//    ver1 > ver2  : +1
+//    ver1 < ver2  : -1
+//    ver1 == ver2 : 0
+//    poorly formatted version number : null
+//
+// If they are different lengths, for example:
+//     1.9.3
+//     1.9.3.4
+// Then the longer version is considered larger.
+//
+StumbleGlobals.dotversion_compare = function(ver1, ver2)
+{
+	var parts1 = ver1.split(".");
+	var parts2 = ver2.split(".");
+	
+	for(var i=0; (i < parts1.length) && (i < parts2.length); i++)
+	{
+		var n1 = parseInt(parts1[i]);
+		var n2 = parseInt(parts2[i]);
+		if(isNaN(n1) || isNaN(n2))
+			return null;
+		
+		if(n1 > n2)
+			return 1;
+		else if(n1 < n2)
+			return -1;
+	}
+	
+	if(i == 0)
+		return null;
+	
+	if(parts1.length > parts2.length)
+		return 1;
+	else if(parts1.length < parts2.length)
+		return -1;
+	else
+		return 0;
+}
+
+StumbleGlobals.get_gm_scripts = function()
+{
+	var file = StumbleGlobals.get_service(
+				"@mozilla.org/file/directory_service;1",
+				"nsIProperties")
+				.get("ProfD", Components.interfaces.nsILocalFile);
+	file.append("gm_scripts");
+	
+	if (! file.exists())
+	{
+		file = StumbleGlobals.ds.getChromeNSIFile("chrome://greasemonkey/content").parent;
+		file.append("scripts");
+	}
+	
+	file.append("config.xml");
+	
+	if (! file.exists())
+		return null;
+	
+	var str = StumbleGlobals.ds.readFile(file);
+	
+	if (str == "")
+		return null;
+	
+	var doc = StumbleGlobals.create_instance(
+				"@mozilla.org/xmlextras/domparser;1",
+				"nsIDOMParser")
+				.parseFromString(str, "text/xml");
+	
+	var nodes = doc.evaluate("/UserScriptConfig/Script", doc, null, 0, null);
+
+	var scripts = new Array();
+	var node;
+	for (node = null; (node = nodes.iterateNext()); )
+	{
+		var detail = new Object();
+
+		var i;
+		var childNode;
+//		detail.su = 0;
+//		for (i = 0, childNode = null; (childNode = node.childNodes[i]); i++)
+//		{
+//			if (childNode.nodeName == "Include") 
+//				detail.su = (childNode.firstChild.nodeValue.toLowerCase().indexOf("stumbleupon") != -1) ? 1 : 0;
+//			
+//			if (detail.su)
+//				break;
+//		}
+		detail.name = node.getAttribute("name");
+		detail.enabled = (node.getAttribute("enabled") == true.toString()) ? 1 : 0;
+
+		scripts.push(detail);
+	}
+	
+	return scripts;
+}
+
+StumbleGlobals.handle_prefetch_load_start = function()
+{
+	var original_target = StumbleGlobals.prefetcher.getCurrentTarget();
+	var ultimate_target = StumbleGlobals.prefetcher.getRedirectTarget(original_target);
+	var status = StumbleGlobals.prefetcher.getHttpResponseStatus(original_target);
+	if ((status == 301) || ((status == 302) && 
+				(StumbleGlobals.get_tld(original_target) != StumbleGlobals.get_tld(ultimate_target))))
+	{
+		// The url is a permanent redirect (301) or a 302 redirect
+		// to a different domain.
+		StumbleGlobals.report_redirect(url, status, ultimate_target);
+	}
+}
+
+StumbleGlobals.report_redirect = function(url, status, new_target)
+{
+	if (StumbleGlobals.ds.lookup("url:reported_404_flag", url))
+		return;
+
+	StumbleGlobals.ds.define("url:reported_404_flag", url, 1);
+
+	var context = new Object();
+	context.quiet = true;
+	
+	var params = "";
+	params = StumbleGlobals.arp(params, "url", url);
+	params = StumbleGlobals.arp(params, "status", status);
+	params = StumbleGlobals.arp(params, "newurl", new_target);
+	
+	StumbleGlobals.post_url_server_async(
+			"404.php",
+			params,
+			15000,
+			StumbleGlobals.generic_done,
+			context);
+}
+
+StumbleGlobals.report_404 = function(url, status)
+{
+	if (StumbleGlobals.ds.lookup("url:reported_404_flag", url))
+		return;
+	
+	StumbleGlobals.ds.define("url:reported_404_flag", url, 1);
+
+	var context = new Object();
+	context.quiet = true;
+	
+	var params = "";
+	params = StumbleGlobals.arp(params, "url", url);
+	params = StumbleGlobals.arp(params, "status", status);
+	
+	StumbleGlobals.post_url_server_async(
+			"404.php",
+			params,
+			15000,
+			StumbleGlobals.generic_done,
+			context);
+}
+
+StumbleGlobals.preload_images = function()
+{
+	var el = document.createElement("image");
+	var id = "stumbleglobals_image_loader" + StumbleGlobals.load_image_count;
+	StumbleGlobals.load_image_count++;
+	el.setAttribute("id", id);
+	el.setAttribute("src", "chrome://stumbleupon/content/skin/arrow_green-b.png");
+	el.setAttribute("style", "visibility:hidden;border:0px solid black;width:0px;height:0px;");
+}
+
+StumbleGlobals.handle_resource_installed = function(event)
+{
+	var el = document.createElement("image");
+	var id = "stumbleglobals_image_loader" + StumbleGlobals.load_image_count;
+	StumbleGlobals.load_image_count++;
+	el.setAttribute("src", 
+				StumbleGlobals.ds.getResourceURLFromSourceURL(event.URL));
+	el.setAttribute("id", id);
+	el.setAttribute("style", "visibility:hidden;border:0px solid black;width:0px;height:0px;");
+	el.setAttribute("onload", 'StumbleGlobals.handle_resource_image_load(event, "' + event.URL + '", "' + id + '");');
+	el.setAttribute("onerror", 'StumbleGlobals.handle_resource_image_load(event, "' + event.URL + '", "' + id + '");');
+	document.getElementById("main-window").appendChild(el);
+}
+
+StumbleGlobals.handle_resource_image_load = function(event, source_url, testid)
+{
+	var iconpic_regex = new RegExp("^http://cdn.stumble-upon.com/iconpics/(\\d*)\\.jpg$");
+	var iconpic_match = source_url.match(iconpic_regex);
+	var favicon_regex = new RegExp("^http://cdn.stumble-upon.com/images/stumblethru/(.*\\.ico)$");
+	if (StumbleGlobals.test_stumblethru_update)
+		favicon_regex = new RegExp("^" + StumbleGlobals.serverhttp + "images/stumblethru/(.*\\.ico)$");
+	var favicon_match = source_url.match(favicon_regex);
+	var searchlinks_regex = new RegExp("^http://cdn.stumble-upon.com/images/(.*searchlinks.*_prompt.gif)$");
+	var searchlinks_match = source_url.match(searchlinks_regex);
+	if (iconpic_match)
+	{
+		var contactid = iconpic_match[1];
+		var contact = StumbleGlobals.ds.selectRow("contact", "contactid", contactid);
+		if (event.type == "load")
+		{
+			if (contact)
+			{
+				contact.iconpic = StumbleGlobals.get_time_s();
+				StumbleGlobals.ds.updateRow(contact);
+				StumbleGlobals.refresh_referral_menu(9);
+			}
+		}
+		else
+		{
+			if (contact)
+			{
+				contact.iconpic = 0;
+				StumbleGlobals.ds.updateRow(contact);
+			}
+			StumbleGlobals.ds.deleteFile(
+						StumbleGlobals.ds.getResourceNSIFile("iconpics", contactid + ".jpg"));
+		}
+	}
+	else if (searchlinks_match)
+	{
+		var filename = searchlinks_match[1];
+		if (event.type == "load")
+		{
+			if (StumbleGlobals.searchlinks_dialog_detail)
+			{
+				var detail = StumbleGlobals.searchlinks_dialog_detail;
+				StumbleGlobals.searchlinks_dialog_detail = null;
+				StumbleGlobals.handle_searchlinks_dialog_resource_load(detail);
+			}
+		}
+		else
+		{
+			StumbleGlobals.ds.setValue("$shown_searchlinks_dialog", false);
+			StumbleGlobals.ds.setValue("$show_searchlinks_score", false);
+			StumbleGlobals.ds.setValue("$show_searchlinks_friends", false);
+			StumbleGlobals.ds.setValue("$show_searchlinks_topic", false);
+			StumbleGlobals.ds.flushPrefs();
+			StumbleGlobals.ds.deleteFile(
+						StumbleGlobals.ds.getResourceNSIFile("images", filename));
+			if (StumbleGlobals.searchlinks_dialog_detail)
+			{
+				var detail = StumbleGlobals.searchlinks_dialog_detail;
+				StumbleGlobals.searchlinks_dialog_detail = null;
+				if (detail.stumble)
+					StumbleGlobals.stumble(stumble.new_tab, true);
+			}
+		}
+	}
+	else if (favicon_match)
+	{
+		if (event.type == "load")
+		{
+			StumbleGlobals.refresh_dyn_channels();
+		}
+		else
+		{
+			var filename = favicon_match[1];
+			StumbleGlobals.ds.deleteFile(
+						StumbleGlobals.ds.getResourceNSIFile("favicons", filename));
+		}
+	}
+	
+	var el = document.getElementById(testid);
+	el.parentNode.removeChild(el);
+}
+
+StumbleGlobals.handle_extensionapi_message = function(msg)
+{
+	switch(msg.messageId)
+	{
+	case "msgLogin":
+		StumbleGlobals.handle_new_login_credentials(msg.data, true);
+		break;
+	case "msgLogout":
+		StumbleGlobals.invoke_global_event("logout", null)
+		break;
+	}
+}
+
+// in Firefox 1.5+, this observer service listener detects application
+// event, like uninstalling the toolbar or quitting the application
+StumbleGlobals.host_observer =
+{
+	observe : function(subject,topic,data)
+	{
+		subject = subject.QueryInterface(Components.interfaces.nsIUpdateItem);
+
+		if ((topic == "em-action-requested") && (subject.name == "StumbleUpon") && 
+					(data == "item-uninstalled"))
+		{
+			StumbleGlobals.handle_em_uninstall();
+		}
+	}
+}
+
+// each window's load() registers an event_observer; when a window 
+// invokes an event using invoke_global_event(), the observerService 
+// dispatches a notification to each event_observer
+StumbleGlobals.event_observer =
+{
+	observe : function (subject, topic, data)
+	{
+		var detail = null;
+		if (data && data != "")
+			detail = StumbleGlobals.ds.deserialize(data);
+		
+		switch (topic)
+		{
+			case "stumbleglobals_login":
+				var skip_cookies = (detail && detail.skip_cookies);
+				var ignore_cookies = (detail && detail.ignore_cookies);
+				var new_profile = (detail && detail.new_profile);
+				var new_user_prompt = (detail && detail.new_user_prompt);
+				StumbleGlobals.login(skip_cookies, ignore_cookies, new_profile, new_user_prompt);
+				break;
+			case "stumbleglobals_logout":
+				StumbleGlobals.logout();
+				break;
+			case "stumbleglobals_change-password":
+				StumbleGlobals.change_password();
+				break;
+			case "stumbleglobals_configure-toolbar":
+				var from_preference_dialog = (detail && detail.from_preference_dialog);
+				StumbleGlobals.configure_toolbar(from_preference_dialog);
+				break;
+			case "stumbleglobals_referral-menu-dirty":
+				StumbleGlobals.referral_menu_dirty = true;
+				break;
+			case "stumbleglobals_update-referral-menu":
+				StumbleGlobals.update_referral_menu();
+				break;
+			case "stumbleglobals_refresh-category-selector":
+				StumbleGlobals.refresh_category_selector();
+				break;
+			case "stumbleglobals_dyn-channels-dirty":
+				StumbleGlobals.dyn_channels_dirty = true;
+				break;
+			case "stumbleglobals_update-dyn-channels":
+				StumbleGlobals.update_dyn_channels();
+				break;
+			case "stumbleglobals_schedule-remove-data":
+				StumbleGlobals.schedule_remove_data();
+				break;
+			case "stumbleglobals_message-button-click":
+				StumbleGlobals.handle_message_button_click(subject);
+				break;
+			case "stumbleglobals_extensionapi_message":
+				StumbleGlobals.handle_extensionapi_message(msg);
+				break;
+		}
+	},
+	
+	// Addon manager events
+	onUninstalling:function(addon) {
+		if(addon.id == "{AE93811A-5C9A-4d34-8462-F7B864FC4696}")
+		{
+			StumbleGlobals.handle_em_uninstall();
+		}
+	}
+}
+
+StumbleGlobals.verify_cookie_perms = function(notify_upon_modify)
+{
+	if (! StumbleGlobals.ds.isPrefDefined("network.cookie.cookieBehavior") || !StumbleGlobals.ds.getValue("@auto_cookie_exceptions"))
+		return;
+	
+	var supr_domain = StumbleGlobals.ds.getValue("@supr_domain");
+	var domains = new Array(StumbleGlobals.servername, "video." + StumbleGlobals.servername, supr_domain);
+	
+	var perm_man = StumbleGlobals.get_service(
+				"@mozilla.org/permissionmanager;1",
+				"nsIPermissionManager");
+	
+	var modified = false;
+	if (StumbleGlobals.ds.getValue("network.cookie.cookieBehavior") != 0)
+	{
+		modified = true;
+		var i;
+		for (i = 0; i < domains.length; i++)
+		{
+			var nsiuri = StumbleGlobals.get_nsiuri(domains[i]);
+			perm_man.add(nsiuri, "cookie", perm_man.ALLOW_ACTION);
+		}
+	}
+	
+	if (modified && notify_upon_modify)
+	{
+		setTimeout(StumbleGlobals.alert_cookie_change, 100);
+	}
+}
+
+StumbleGlobals.alert_cookie_change = function()
+{
+	var ps = StumbleGlobals.get_service(
+				"@mozilla.org/embedcomp/prompt-service;1",
+				"nsIPromptService");
+	
+	ps.alert(window,
+				"StumbleUpon",
+				"Exceptions to allow StumbleUpon cookies have been added.\n\n" + 
+				"This is required for the StumbleUpon toolbar to be fully functional.\n\n");
+}
+
+StumbleGlobals.show_new_install_page = function()
+{
+	var loc = "firefox_start.php";
+	if (StumbleGlobals.host.dist)
+		loc = "campus_start.php";
+	
+	StumbleGlobals.set_server_location(loc, null, true);
+}
+
+StumbleGlobals.get_ocid = function()
+{
+	var id = '';
+	try
+	{
+		var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
+				.createInstance(Components.interfaces.nsIWindowsRegKey);
+		wrk.open(wrk.ROOT_KEY_CURRENT_USER, 
+				 "SOFTWARE\\StumbleUpon\\mozbar",
+				 wrk.ACCESS_READ);
+		id = wrk.readStringValue("ocid");
+		wrk.close();
+	}
+	catch(ex)
+	{
+	}
+	
+	return id;
+}
+
+//
+// StumbleGlobals.check_handle_new_client
+//
+// Handles new client installs and upgrades.
+//
+StumbleGlobals.check_handle_new_client = function()
+{
+	if(!StumbleGlobals.new_install && !StumbleGlobals.new_upgrade)
+		return;
+	
+	if(StumbleGlobals.new_upgrade)
+	{
+		// We clear the stumble cache on upgrade to allow for any new caching logic
+		StumbleGlobals.clear_stumbles();
+	}
+	
+	if(StumbleGlobals.new_install)
+	{
+		try {
+			// block popups from external applications ( a major new source of unwanted popups )
+			// Only do this once, in case they have a reason to set it back
+			StumbleGlobals.ds.setValue("privacy.popups.disable_from_plugins", 2);
+			
+		} catch (e) { StumbleGlobals.log_error("PREPARE BROWSER", e); }
+	}
+	
+	// TODO:  "method" is redundant, but apparently the services API isn't picking up
+	// the method from the command-line when you use POST.  Fix this server-side.
+	var params = "";
+	params = StumbleGlobals.arp(params, "method", "firstrun");
+	params = StumbleGlobals.arp(params, "client_type", "mozbar");
+	params = StumbleGlobals.arp(params, "version", StumbleGlobals.useragent);
+	
+	var ocid = StumbleGlobals.get_ocid();
+	if(ocid)
+		params = StumbleGlobals.arp(params, "ocid", ocid);
+	
+	// Add the current client id if it exists
+	var clientid = StumbleGlobals.ds.getValue("@clientid");
+	if(clientid)
+	{
+		params = StumbleGlobals.arp(params, "clientid", clientid);
+	}
+
+	if(StumbleGlobals.new_upgrade && StumbleGlobals.prev_version)
+		params = StumbleGlobals.arp(params, "prev_version", StumbleGlobals.prev_version);
+	
+	// Sock away StumbleGlobals.new_install and StumbleGlobals.new_upgrade because this is an asynchronous
+	// operation and they are reset when this routine completes
+	var context = {};
+	context.quiet = true;
+	context.new_install = StumbleGlobals.new_install;
+	context.new_upgrade = StumbleGlobals.new_upgrade;
+	
+	StumbleGlobals.post_url_async(
+		StumbleGlobals.serviceshttp + "client.firstrun",
+		params,
+		15000,
+		StumbleGlobals.get_firstrun_done,
+		context);
+	
+	StumbleGlobals.new_install = false;
+	StumbleGlobals.new_upgrade = false;
+}
+
+StumbleGlobals.get_firstrun_done = function(res)
+{
+	var result = null;
+	var context = res.detail;
+	
+	try {
+		if (res.status == 200)
+		{
+			var s = "";
+			if (typeof(res.responseText) != "undefined")
+				s = res.responseText;
+			
+			if (StumbleGlobals.log_communication)
+				StumbleGlobals.log("response client.firstRun", s);
+		
+			if (s)
+			{
+				result = StumbleGlobals.ds.deserialize(s);
+				if(result && result.clientid)
+				{
+					StumbleGlobals.ds.setValue("@clientid", result.clientid);
+					StumbleGlobals.ds.flushPrefs();
+				}
+			}
+		}
+	} catch (e) {
+		// Ignore errors, because we still want to show the new install page
+	} 
+	
+	// Show the new install page, or an upgrade page if firstrun asked for one
+	if (result && result.showurl)
+	{
+		StumbleGlobals.set_location(result.showurl, null, true);
+	}
+	else if(context.new_install)
+	{
+		StumbleGlobals.show_new_install_page();
+	}
+		
+}
+
+StumbleGlobals.gui_render = function()
+{
+	var test_ids = [
+				"stumbleglobals_render",
+				"stumbleglobals_overflow_popup",
+				"stumbleglobals_stumble_topic",
+				"stumbleglobals_page_feature_prompt",
+				"stumbleglobals_messages",
+				"firstrater",
+				"stumbleglobals_searchbox",
+				"stumbleglobals_category",
+				"stumbleglobals_referral_menu",
+				"stumbleglobals_website_info",
+				"stumbleglobals_thumbdown",
+				"stumbleglobals_thumbup",
+//				"stumbleglobals_inbox-count",
+				"stumbleglobals_referred",
+				"stumbleglobals_stumble",
+				"stumbleglobals_splitter_first_flexbox",
+				"stumbleglobals_spacer"];
+				
+	// keep trying until we find the gui
+	var i;
+	for (i = 0; i < test_ids.length; i++)
+	{
+		if (! StumbleGlobals.get_element(test_ids[i]))
+		{
+			setTimeout("StumbleGlobals.gui_render()", 100);
+			return;
+		}
+	}
+
+	
+//	if ((StumbleGlobals.get_element("stumbleglobals_render") == null) ||
+//				(StumbleGlobals.get_element("stumbleglobals_category") == null))
+//	{
+//		setTimeout("StumbleGlobals.gui_render()", 100);
+//		return;
+//	}
+	
+	StumbleGlobals.set_visible("stumbleglobals_bug", StumbleGlobals.enable_message_log);
+	
+	// These configure toolbars correctly when opening a new browser
+	// window after changing toolbar elements but before persisting.
+	// There may be a better way to handle this, by figuring out how
+	// to persist without breaking urlbar; for now it works. -- JW
+//	try {
+//		StumbleGlobals.prevent_toolbar_sharing();
+//	} catch (e) { StumbleGlobals.log_error("INIT SHARING", e); }
+	try {
+		StumbleGlobals.refresh_toggle_button(true);
+	} catch (e) { StumbleGlobals.log_error("INIT TOGGLE", e); }
+	
+	// Netscape 8.0.x needs a separator to push the stumble button past
+	// the NS logo.
+	if (StumbleGlobals.host.netscape && (StumbleGlobals.host.version.indexOf("8.0") != -1))
+		StumbleGlobals.get_element("stumbleglobals_spacer").collapsed = false;
+
+	try {
+		StumbleGlobals.verify_cookie_perms(StumbleGlobals.new_install);
+	} catch (e) { StumbleGlobals.log_error("ALLOW COOKIES", e); }
+
+	StumbleGlobals.check_handle_new_client();
+	
+	StumbleGlobals.dist_time();
+	
+	var installed = StumbleGlobals.ds.getIntValue("@installed");
+	var now_s = StumbleGlobals.get_time_s();
+//	if ((now_s - installed) > (3600 * 24))
+//		StumbleGlobals.promo_mode = true;
+
+	if (StumbleGlobals.stumbleid == 0)
+	{
+		StumbleGlobals.move_toolbar(true, 2);
+		StumbleGlobals.configure_toolbar(false);
+		StumbleGlobals.check_progress_listener();
+	}
+	else
+	{
+		StumbleGlobals.show_searchlinks_dialog(false, false, false);
+		StumbleGlobals.load_data2(false);  // calls configure_toolbar()
+	}
+	
+	if (window.onViewToolbarsPopupShowing)
+	{
+		// This is a bit tricky.  Basically, we're replacing a browser-
+		// defined function with our own function.  For details, see the
+		// comments in function 
+		// StumbleGlobals.replacement_onViewToolbarsPopupShowing.
+		window.StumbleGlobals.saved_onViewToolbarsPopupShowing = window.onViewToolbarsPopupShowing;
+		window.onViewToolbarsPopupShowing = window.StumbleGlobals.replacement_onViewToolbarsPopupShowing;
+	}
+	
+	if (window.BrowserCustomizeToolbar)
+	{
+		// This is a bit tricky.  Basically, we're replacing a browser-
+		// defined function with our own function.  For details, see the
+		// comments in function 
+		// StumbleGlobals.replacement_onViewToolbarsPopupShowing.
+		window.StumbleGlobals.saved_BrowserCustomizeToolbar = window.BrowserCustomizeToolbar;
+		window.BrowserCustomizeToolbar = window.StumbleGlobals.replacement_BrowserCustomizeToolbar;
+	}
+
+	if (window.BrowserToolboxCustomizeDone)
+	{
+		// This hack is similar to the one above.  See function
+		// StumbleGlobals.replacement_BrowserToolboxCustomizeDone.
+		window.StumbleGlobals.saved_BrowserToolboxCustomizeDone = window.BrowserToolboxCustomizeDone;
+		var toolbox = document.getElementById("navigator-toolbox");
+		toolbox.customizeDone = window.StumbleGlobals.replacement_BrowserToolboxCustomizeDone;
+	}
+	
+	if (window.foxytunesSetFoxyTunesPosition)
+	{
+		window.StumbleGlobals.saved_foxytunesSetFoxyTunesPosition = window.foxytunesSetFoxyTunesPosition;
+		window.foxytunesSetFoxyTunesPosition = window.StumbleGlobals.replacement_foxytunesSetFoxyTunesPosition;
+	}	
+	
+	window.addEventListener("resize", StumbleGlobals.handle_window_resize, false);
+	window.addEventListener("focus", StumbleGlobals.handle_window_focus, true);
+	
+	// for instances where we still need a load listener (such as interests_after.php)
+	window.addEventListener("DOMContentLoaded", StumbleGlobals.on_load_page, true);
+
+	getBrowser().addEventListener("click", StumbleGlobals.handle_content_click, false);
+	
+//	We may have to do this if onLocationChange stops working.
+//	if (StumbleGlobals.host.ff2plus)
+//		getBrowser().tabContainer.addEventListener("TabSelect", StumbleGlobals.handle_tabselect, false);
+	
+	StumbleGlobals.gui_initialized = true;
+	StumbleGlobals.ds.prefRetries = 15;
+	
+	setTimeout("StumbleGlobals.reflow_toolbar(3);", 0);
+	setTimeout("StumbleGlobals.reflow_toolbar(3);", 500);
+	setTimeout("StumbleGlobals.cleanup_toolbox(true, false)", 550);
+	setInterval("StumbleGlobals.process_quarter_hourly()", 15 * 60 * 1000);
+}
+
+//	We may have to do this if onLocationChange stops working.
+//StumbleGlobals.handle_tabselect = function(event)
+//{
+//  StumbleGlobals.refresh_pagemeta(false, 11);
+//}
+
+StumbleGlobals.photoBlogContext = function() 
+{
+	if (gContextMenu) 
+	{
+		menuitem = StumbleGlobals.get_element('context-photoblog-ilikeit');
+
+		if (menuitem)
+		{
+			menuitem.hidden = !gContextMenu.onImage;
+			//alert("photo " + !gContextMenu.onImage);
+			
+		}
+		// menuitem = StumbleGlobals.get_element('context-photoblog-notforme');
+		// if(menuitem)
+		// 	menuitem.hidden = !gContextMenu.onImage;
+		
+		// look for selected text
+		var selectedText = StumbleGlobals.getSelectedText(" ");
+//		alert("?" + selectedText);
+
+		if (selectedText != "")
+		{
+			// tag button	
+			//!!! only do this if size isn't greater than maximum tag size...
+			menuitem = StumbleGlobals.get_element('context-stumble-tagit');
+			menuitem.hidden = false;
+			var selectedText2 = selectedText;
+			if (selectedText2.length > 15)
+				selectedText2 = selectedText.substring(0, 15) + "...";	
+			menuitem.label = "Tag this page as '" + selectedText2 + "'";
+			menuitem.setAttribute("class", "menuitem-iconic");
+			menuitem.setAttribute("image", "chrome://stumbleupon/content/skin/tag.png");		
+			
+			// search
+			//!!! only do this if absolute enable_search == yes
+			
+			//!!! We've stopped prompting for enable_search, so we'll leave
+			// it as is for now.
+			
+			menuitem = StumbleGlobals.get_element('context-stumble-search');
+			menuitem.hidden = false;
+			selectedText2 = selectedText;
+			if (selectedText2.length > 15)
+				selectedText2 = selectedText.substring(0, 15) + "...";	
+			menuitem.label = "StumbleThru '" + selectedText2 + "'";
+			menuitem.setAttribute("class", "menuitem-iconic");
+			menuitem.setAttribute("image", "chrome://stumbleupon/content/skin/stumble.png");
+		}
+		else
+		{
+			menuitem = StumbleGlobals.get_element('context-stumble-tagit');
+			menuitem.hidden = true;
+			
+			menuitem = StumbleGlobals.get_element('context-stumble-search');
+			menuitem.hidden = true;
+		}	     
+	}
+}
+
+StumbleGlobals.contextTag = function()
+{
+	var current_url = StumbleGlobals.get_browser_url();
+	var selectedText = StumbleGlobals.getSelectedText(" ");
+	StumbleGlobals.get_element("stumbleglobals_searchbox").value = selectedText;
+	StumbleGlobals.tagit(current_url, selectedText, 0, StumbleGlobals.get_title(), StumbleGlobals.get_browser_url(null, true));
+}
+
+StumbleGlobals.contextSearch = function(event)
+{
+	var selectedText = StumbleGlobals.getSelectedText(" ");
+	StumbleGlobals.old_search = selectedText;
+	StumbleGlobals.visited_searchbox = 1;
+	
+	StumbleGlobals.get_element('stumbleglobals_searchbox').removeAttribute("mode");
+
+	if (StumbleGlobals.url_has_tag)
+	{	
+		StumbleGlobals.url_has_tag = false;
+		StumbleGlobals.get_element('stumbleglobals_searchbox').value = '';
+		StumbleGlobals.get_element('stumbleglobals_searchbox').removeAttribute("mode");
+
+		StumbleGlobals.get_element("stumbleglobals_tag").image="chrome://stumbleupon/content/skin/tag.png";
+		StumbleGlobals.get_element('stumbleglobals_tag').setAttribute("tooltiptext", StumbleGlobals.get_element('stumbleglobals_tag').getAttribute("tooltiptext2"));
+		StumbleGlobals.get_element("stumbleglobals_tag2").image="chrome://stumbleupon/content/skin/tag.png";
+		StumbleGlobals.get_element('stumbleglobals_tag2').setAttribute("tooltiptext", StumbleGlobals.get_element('stumbleglobals_tag2').getAttribute("tooltiptext2"));
+	}
+	
+	var searchbox = StumbleGlobals.get_element("stumbleglobals_searchbox");
+	searchbox.value = selectedText;
+	if (! (searchbox.hasAttribute("focused") && 
+				(searchbox.getAttribute("focused") == "true")))
+	{
+		searchbox.focus();
+	}
+	
+	var new_tab = StumbleGlobals.new_tab(event);
+	new_tab = new_tab || StumbleGlobals.ds.getValue("$search_new_window");
+	StumbleGlobals.stumble_in_tag(selectedText, new_tab);	
+}
+
+StumbleGlobals.getSelectedText = function(concationationChar)
+{
+	var node = document.popupNode;
+	var selection = "";
+
+	if ((node instanceof HTMLTextAreaElement) || (node instanceof HTMLInputElement && node.type == "text"))
+	{
+		selection = node.value.substring(node.selectionStart, node.selectionEnd);
+	} 
+	else {
+		var focusedWindow = new XPCNativeWrapper(document.commandDispatcher.focusedWindow, 'document', 'getSelection()');
+		selection = focusedWindow.getSelection().toString();
+	}
+
+	// Limit length to 150 to optimize performance. Longer does not make sense
+	if (selection.length>=150)
+		selection = selection.substring(0, 149);
+
+	selection = selection.replace(/(\n|\r|\t)+/g, " ");
+	// Strip spaces at start and end.
+	selection = selection.replace(/(^\s+)|(\s+$)/g, "");
+
+	selection = selection.split(" ");
+ 
+	// Remove certain characters at the beginning and end of every word
+	for (i=0; i<selection.length; i++)
+	{
+		selection[i]=selection[i].replace(/^(\&|\(|\)|\[|\]|\{|\}|"|,|\.|!|\?|'|:|;)+/, "");
+		selection[i]=selection[i].replace(/(\&|\(|\)|\[|\]|\{|\}|"|,|\.|!|\?|'|:|;)+$/, "");
+	}   
+	selection = selection.join(concationationChar);   
+	return selection; 
+}
+
+StumbleGlobals.show_banner = function(prompt, icon, accept_callback, decline_callback)
+{
+	var box = getBrowser().getNotificationBox();
+	var notification = box.getNotificationWithValue("stumbleglobals_message");
+	if (notification)
+		return;
+	
+	var buttons = new Array();
+	
+	buttons.push({
+				label: "Join StumbleUpon Now",
+				accessKey: "J",
+				popup: null,
+				callback: accept_callback});
+	
+	buttons.push({
+				label: "No thanks",
+				accessKey: "N",
+				popup: null,
+				callback: decline_callback});
+	
+	buttons.push({
+				label: "Later",
+				accessKey: "L",
+				popup: null,
+				callback: function(){}});
+	
+	const priority = box.PRIORITY_WARNING_MEDIUM;
+	
+	box.appendNotification(
+				prompt,
+				"stumbleglobals_prompt",
+				icon,
+				priority,
+				buttons);
+}
+
+StumbleGlobals.handle_prompt_click = function(prompt, button_name, detail)
+{
+	if (button_name == "accept")
+	{
+		StumbleGlobals.verify_cookie_perms(false);
+		var params = "";
+		var loc = "sign_up.php"; 
+		params = StumbleGlobals.arp(params, "version", StumbleGlobals.useragent);
+		
+		if (StumbleGlobals.host.dist)
+			loc = StumbleGlobals.arp(loc, "dist", StumbleGlobals.host.dist, true);
+		
+		if (StumbleGlobals.ds.getValue("@facebook_user"))
+			loc = StumbleGlobals.arp(loc, "pre", "facebook", true);
+		
+		loc = StumbleGlobals.arp(loc, "pre2", prompt, true);
+		
+		params = StumbleGlobals.arp(params, "post_url", detail.post_url);
+
+		StumbleGlobals.set_server_location(
+					loc,
+					params,
+					detail.new_tab);
+	}
+	else if ((button_name == "decline") && (prompt == "prompt1"))
+	{
+		StumbleGlobals.ds.setValue("@enable_prompt1", false);
+	}
+	else if ((button_name == "decline") && (prompt == "prompt2"))
+	{
+		StumbleGlobals.ds.setValue("@enable_prompt2", false);
+	}
+}
+
+
+// handles the window load event
+StumbleGlobals.handle_window_load = function()
+{
+	if (! StumbleGlobals.login_initialized)
+	{
+		setTimeout(StumbleGlobals.handle_window_load, 1000);
+		return;
+	}
+	
+	if(StumbleGlobals.window_load_called)
+		return;
+	StumbleGlobals.window_load_called = true;
+
+	if (StumbleGlobals.stumbleid != 0)
+	{
+		if ((StumbleGlobals.get_browser_window_count() == 1) && StumbleGlobals.ds.getValue("$autologout"))
+			StumbleGlobals.logout_auth();
+		else
+			StumbleGlobals.load_data1(false);
+	}
+
+	// we need to wait until the gui is rendered before we do most things
+	setTimeout("StumbleGlobals.gui_render()", 100);
+
+	// Initialize photoblog context menu
+	var menu = StumbleGlobals.get_element("contentAreaContextMenu");
+	menu.addEventListener("popupshowing", StumbleGlobals.photoBlogContext, false); 
+}
+
+// handles the window unload event
+StumbleGlobals.handle_window_unload = function()
+{
+	try {
+	  // Remove addonManager observation -- note that this is Fx4 only, so put it in try/catch
+	  if(AddonManager)
+	  {
+	  	  try {
+	  	  	  AddonManager.removeAddonListener(StumbleGlobals.event_observer);
+	  	  } catch(ex) {}
+	  }
+		
+	// To avoid a memory leak, this block needs to run per XUL window.
+	// -- JW
+	var observer_service = StumbleGlobals.get_service(
+				"@mozilla.org/observer-service;1",
+				"nsIObserverService");
+	observer_service.removeObserver(StumbleGlobals.http_observer, "http-on-modify-request");
+	observer_service.removeObserver(StumbleGlobals.http_observer, "http-on-examine-response");
+	observer_service.removeObserver(StumbleGlobals.http_observer, "http-on-examine-cached-response");
+	observer_service.removeObserver(StumbleGlobals.host_observer, "em-action-requested");
+	observer_service.removeObserver(StumbleGlobals.event_observer, "stumbleglobals_login");
+	observer_service.removeObserver(StumbleGlobals.event_observer, "stumbleglobals_logout");
+	observer_service.removeObserver(StumbleGlobals.event_observer, "stumbleglobals_change-password");
+	observer_service.removeObserver(StumbleGlobals.event_observer, "stumbleglobals_configure-toolbar");
+	observer_service.removeObserver(StumbleGlobals.event_observer, "stumbleglobals_referral-menu-dirty");
+	observer_service.removeObserver(StumbleGlobals.event_observer, "stumbleglobals_update-referral-menu");
+	observer_service.removeObserver(StumbleGlobals.event_observer, "stumbleglobals_dyn-channels-dirty");
+	observer_service.removeObserver(StumbleGlobals.event_observer, "stumbleglobals_update-dyn-channels");
+	observer_service.removeObserver(StumbleGlobals.event_observer, "stumbleglobals_refresh-category-selector");
+	observer_service.removeObserver(StumbleGlobals.event_observer, "stumbleglobals_schedule-remove-data");
+	observer_service.removeObserver(StumbleGlobals.event_observer, "stumbleglobals_message-button-click");
+	observer_service.removeObserver(StumbleGlobals.event_observer, "stumbleglobals_extensionapi_message");	
+
+    var processed_ids = new Object();
+	while (StumbleGlobals.persist_queue.length)
+	{
+		// Doing document.persist can break the urlbar, so we do it upon
+		// window close (ref: Firefox 2RC1). -- JW
+		var id = StumbleGlobals.persist_queue.pop();
+		if (processed_ids[id])
+			continue;
+		
+		processed_ids[id] = true;
+
+		document.persist(id, "currentset");
+	}
+	
+	if (StumbleGlobals.get_browser_window_count() == 0)
+		StumbleGlobals.handle_last_browser_window_unload();
+	
+	} catch (e) {
+	}
+}
+
+StumbleGlobals.handle_last_browser_window_unload = function()
+{
+	var i;
+	if (StumbleGlobals.ds.getValue("@clear_favicons"))
+	{
+		StumbleGlobals.ds.setValue("@clear_favicons", false);
+		var channels = StumbleGlobals.ds.getThruDomainChannels(false);
+		
+		if (channels)
+		{
+			for (i = 0; i < channels.length; i++)
+			{
+				StumbleGlobals.ds.deleteResource(
+							"favicons",
+							StumbleGlobals.get_channel_id(channels[i].domain) + ".ico");
+			}
+		}
+	}
+
+	if(!StumbleGlobals.remove_data_scheduled)
+	{
+		StumbleGlobals.check_clear_history();
+
+		if (StumbleGlobals.preference_dialog)
+			StumbleGlobals.preference_dialog.cancelDialog();
+
+		if ((StumbleGlobals.stumbleid != 0) &&	StumbleGlobals.ds.getValue("$autologout"))
+			StumbleGlobals.logout();
+		
+		StumbleGlobals.ds.flushPrefs();
+	}
+	
+	if (StumbleGlobals.remove_data_scheduled)
+		StumbleGlobals.remove_data();
+}
+
+// handles the window click event
+StumbleGlobals.handle_window_mousedown = function(event)
+{
+	if (! StumbleGlobals.has_searchbox)
+		return true;
+	//	StumbleGlobals.recent_platform_ctrl_key_state = (StumbleGlobals.host.mac) ? event.metaKey : event.ctrlKey;
+
+	if (! event.target.id)
+		return;
+	
+	switch (event.target.id)
+	{
+		case "stumbleglobals_searchbox":
+			StumbleGlobals.keep_searchbox_focus = true;
+			break;
+		case "stumbleglobals_stumble":
+		case "stumbleglobals_category":
+		case "stumbleglobals_thumbup":
+		case "stumbleglobals_thumbdown":
+		case "stumbleglobals_website_info":
+		case "stumbleglobals_tag":
+		case "stumbleglobals_tag2":
+			break;
+		default:
+			StumbleGlobals.keep_searchbox_focus = false;
+			break;
+	}
+	return true;
+}
+
+// handles the window focus event
+StumbleGlobals.handle_window_focus = function(event)
+{
+	if (! StumbleGlobals.has_searchbox)
+		return true;
+
+	if (StumbleGlobals.keep_searchbox_focus && event.target.location && 
+				(event.target.location.href == "chrome://browser/content/browser.xul"))
+	{
+		setTimeout(StumbleGlobals.restore_searchbox_focus, 100);
+	}
+	else if (StumbleGlobals.keep_searchbox_focus && event.target.id && 
+				(event.target.id == "content"))
+	{
+		setTimeout(StumbleGlobals.restore_searchbox_focus, 100);
+	}
+}
+
+// restores the searchbox
+StumbleGlobals.restore_searchbox_focus = function()
+{
+	if (StumbleGlobals.keep_searchbox_focus)
+	{
+		var searchbox = StumbleGlobals.get_element("stumbleglobals_searchbox");
+		if (! (searchbox.hasAttribute("focused") && (searchbox.getAttribute("focused") == "true")))
+			searchbox.focus();
+	}
+}
+
+// handles the window keypress event; see also handle_window_keyup
+StumbleGlobals.handle_window_keypress = function(event)
+{
+//	StumbleGlobals.recent_platform_ctrl_key_state = (StumbleGlobals.host.mac) ? event.metaKey : event.ctrlKey;
+	
+  var str = "";
+
+	if (event.altKey)   str += "Alt+";
+	if (event.ctrlKey)  str += "Ctrl+";
+	if (event.metaKey)  str += "Command+";
+	if (event.shiftKey) str += "Shift+";
+
+	StumbleGlobals.recent_keypress_modifiers = str;
+
+	return true;
+}
+
+// handles the window keyup event using commands defined by 
+// refresh_keybindings(); note that we need both a keypress listener
+// and a keyup listener because the former gives us modifiers and the
+// latter gives us keyCodes that distinquish between the numeric
+// keypad w/ numlock on and the number row
+StumbleGlobals.handle_window_keyup = function(event)
+{
+	var keyid;
+	keyid = StumbleGlobals.keyids_by_eventkeycode[event.keyCode];
+
+	var keyspec = StumbleGlobals.recent_keypress_modifiers + keyid;
+	
+	if (StumbleGlobals.commands_by_keyspec[keyspec])
+		StumbleGlobals.commands_by_keyspec[keyspec].doCommand();
+
+	return true;
+}
+
+StumbleGlobals.move_to_bookmark_bar = function()
+{
+	StumbleGlobals.ds.setValue("@toolbar-position", "PersonalToolbar");
+	StumbleGlobals.ds.setValue("@position-group", "first");
+	
+	StumbleGlobals.move_toolbar(true, 9);
+}
+
+// called by the global configure-toolbar event and during init to
+// move the top-level toolbar elements
+StumbleGlobals.move_toolbar = function(force, from)
+{
+	var toolbar_position = StumbleGlobals.ds.getValue("@toolbar-position");
+	var position_group = StumbleGlobals.ds.getValue("@position-group");
+	var toolbar = StumbleGlobals.get_element(toolbar_position);
+	var toolbaritem;
+	var new_parent;
+	var popup;
+	if (! toolbar)
+	{
+		toolbar_position = "stumbleupon";
+		position_group = "first";
+		StumbleGlobals.ds.setValue("@toolbar-position", toolbar_position);
+		StumbleGlobals.ds.setValue("@position-group", position_group);
+		toolbar = StumbleGlobals.get_element(toolbar_position);
+		StumbleGlobals.ds.flushPrefs();
+	}
+	
+	if (force && (toolbar.tagName == "toolbar") && 
+				window.BrowserCustomizeToolbar && 
+				((position_group == "first") || (position_group == "last")))
+	{
+		var splitter = StumbleGlobals.get_element("stumbleglobals_right-justify-splitter");
+		if (splitter)
+			splitter.collapsed = true;
+	
+		// If we don't hide the popup, the menu gets munged if we move the
+		// toolbar somewhere else.
+		popup = StumbleGlobals.get_element("stumbleglobals_stumble_popup");
+		if (typeof(popup.hidePopup) == "function")
+			popup.hidePopup();
+		if (StumbleGlobals.overflow_popup_open)
+		{
+			popup = StumbleGlobals.get_element("stumbleglobals_overflow_popup"); 
+			if (typeof(popup.hidePopup) == "function")
+				popup.hidePopup();
+		}
+		new_parent = StumbleGlobals.get_element("stumbleglobals_container");
+		new_parent.hidden = true;
+//		StumbleGlobals.dp("moving to hbox");
+		StumbleGlobals.move_toolbar_elements(new_parent, null, 1);
+		
+		var toolbars = document.getElementsByTagName("toolbar");
+		var target_index = -1;
+		var prev_index = -1;
+		var i;
+
+		// First, find the toolbar locations
+		for (i = 0; i < toolbars.length; i++)
+		{
+			if(StumbleGlobals.is_item_in_toolbox(false, "stumbleglobals_toolbaritem", toolbars[i]))
+			{
+				prev_index = i;
+				if(target_index != -1) break;
+			}
+
+			if (! toolbars[i].hasAttribute("customizable"))
+				continue;
+			
+			if (toolbars[i].getAttribute("customizable").toLowerCase() != "true")
+				continue;
+
+			if (toolbars[i].id == toolbar_position)
+			{
+				target_index = i;
+				if(prev_index != -1) break;
+			}
+		}
+
+		if(target_index != -1)
+		{
+			// Add it to the new
+			StumbleGlobals.place_toolbaritem(toolbars[target_index], position_group);
+			// Remove it from the old
+			if(target_index != prev_index)
+			{
+				try {
+					StumbleGlobals.is_item_in_toolbox(true, "stumbleglobals_toolbaritem", toolbars[prev_index]);
+				} catch (e) {};
+			}
+		}
+		
+		if((target_index == -1)  && (toolbar_position != "status-bar"))
+		{
+			// If we didn't find a valid (customizable) toolbar parent, then force our
+			// toolbar to the default location.
+			toolbar_position = "stumbleupon";
+			position_group = "first";
+			StumbleGlobals.ds.setValue("@toolbar-position", toolbar_position);
+			StumbleGlobals.ds.setValue("@position-group", position_group);
+			toolbar = StumbleGlobals.get_element(toolbar_position);
+			StumbleGlobals.place_toolbaritem(toolbar, position_group);
+			StumbleGlobals.ds.flushPrefs();
+		}
+	}
+
+	toolbaritem = StumbleGlobals.get_element("stumbleglobals_toolbaritem");
+	
+	var drop = false;
+	var new_bar;
+	if ((toolbar_position == "status-bar") || 
+				(toolbar_position == "yahoo-toolbar"))
+	{
+		new_parent = StumbleGlobals.get_element(toolbar_position);
+		new_bar = new_parent;
+	}
+	else if (toolbaritem)
+	{
+		new_bar = toolbaritem.parentNode;
+		var drop = true;
+		if (StumbleGlobals.is_element_on_bar(false, "gtbToolbar", "stumbleglobals_toolbaritem"))
+		{
+			toolbar_position = "gtbToolbar";
+			new_parent = StumbleGlobals.get_element("gtbToolbar");
+//			StumbleGlobals.dp("toolbaritem is on gtbToolbar", new_parent.id);
+			position_group = "first";
+			
+			if (toolbaritem.hasAttribute("flex"))
+				toolbaritem.removeAttribute("flex");
+			
+			toolbaritem.setAttribute("width", 0);
+			StumbleGlobals.ds.setValue("@toolbar-position", toolbar_position);
+		}
+		else
+		{
+			new_parent = StumbleGlobals.get_element("stumbleglobals_toolbar_container");
+			try {
+				position_group = "drop";
+				toolbar_position = StumbleGlobals.get_parent_toolbar_id(new_parent);
+			}
+			catch (e) {
+				//!!! This is a failsafe case that gets hit by some seamonkey
+				//    1.1 and Firefox 2.0.0.2 users.
+				if ((toolbar_position == "stumbleupon") && (position_group == "first"))
+					StumbleGlobals.log_error("MOVE ERROR1", e);
+				else
+					StumbleGlobals.log_error("MOVE FAILSAFE1", e, toolbar_position, position_group);
+				toolbar_position = "stumbleupon";
+				position_group = "first";
+				new_parent = StumbleGlobals.get_element("stumbleglobals_container");
+				new_bar = new_parent.parentNode;
+				new_parent.hidden = false;
+			}
+			StumbleGlobals.ds.setValue("@toolbar-position", toolbar_position);
+			StumbleGlobals.ds.setValue("@position-group", position_group);
+		}
+	}
+	else if (toolbar_position == "stumbleupon")
+	{
+		new_parent = StumbleGlobals.get_element("stumbleglobals_container");
+		position_group = "first";
+		StumbleGlobals.ds.setValue("@toolbar-position", toolbar_position);
+		StumbleGlobals.ds.setValue("@position-group", position_group);
+		new_bar = new_parent.parentNode;
+		new_parent.hidden = false;
+	}
+	else
+	{
+//		StumbleGlobals.dp("no toolbaritem");
+		new_parent = StumbleGlobals.get_element(toolbar_position);
+		new_bar = new_parent;
+	}
+
+	// If the selected toolbar is missing, use the default location.
+	if (! new_parent)
+	{
+//		StumbleGlobals.dp("no new parent");
+		toolbar_position = "stumbleupon";
+		position_group = "first";
+		StumbleGlobals.ds.setValue("@toolbar-position", toolbar_position);
+		StumbleGlobals.ds.setValue("@position-group", position_group);
+		new_parent = StumbleGlobals.get_element("stumbleglobals_container");
+		new_bar = new_parent.parentNode;
+		force = true;
+	}
+
+	// if force, then make sure the toolbar they are moving to is not hidden
+	if (force)
+	{
+		new_bar.hidden = false;
+		new_bar.collapsed = false;
+	}
+
+	var hidden_state = ! StumbleGlobals.ds.getValue("@toolbar-visible");
+
+	if (toolbar_position == "stumbleupon")
+	{
+		StumbleGlobals.get_element("stumbleupon").collapsed = hidden_state;
+	}
+	else
+	{
+		StumbleGlobals.get_element("stumbleupon").collapsed = true;
+		if (hidden_state)
+		{
+//			StumbleGlobals.dp("hidden");
+			// To hide the toolbar elements, we move them to the collapsed
+			// toolbar. -- JW
+			if (toolbaritem)
+			{
+				if (toolbaritem.hasAttribute("flex"))
+					toolbaritem.removeAttribute("flex");
+				
+				toolbaritem.setAttribute("width", 0);
+			}
+			toolbar_position = "stumbleupon";
+			new_parent = StumbleGlobals.get_element("stumbleglobals_container");
+		}
+	}
+	
+	var old_parent = StumbleGlobals.get_element("stumbleglobals_splitter_first_flexbox").parentNode;
+	
+	
+	if ((toolbar_position == StumbleGlobals.old_toolbar_position) && 
+				(position_group == StumbleGlobals.old_toolbar_position_group) &&
+				(old_parent.id != "stumbleglobals_container"))
+	{
+		setTimeout(
+					function (win) {
+						win.StumbleGlobals.cleanup_toolbox(true, false); },
+					0,
+					window);
+	
+		StumbleGlobals.init_splitters();
+		return;
+	}
+
+/*	
+	if (toolbaritem)
+	{
+		if (toolbaritem.hasAttribute("width"))
+			toolbaritem.removeAttribute("width");
+		
+		if (! toolbaritem.hasAttribute("flex"))
+			toolbaritem.setAttribute("flex", 1);
+	}
+*/
+
+	StumbleGlobals.bookmarks_sibling_loc = null;
+	StumbleGlobals.old_toolbar_position = toolbar_position;
+	StumbleGlobals.old_toolbar_position_group = position_group;
+	
+	StumbleGlobals.moving_toolbar = true;
+	
+
+	// If we don't hide the popup, the menu gets munged if we move the
+	// toolbar somewhere else.
+	popup = StumbleGlobals.get_element("stumbleglobals_stumble_popup");
+	if (typeof(popup.hidePopup) == "function")
+		popup.hidePopup();
+	if (StumbleGlobals.overflow_popup_open)
+	{
+		popup = StumbleGlobals.get_element("stumbleglobals_overflow_popup"); 
+		if (typeof(popup.hidePopup) == "function")
+			popup.hidePopup();
+	}
+
+	if (toolbar_position == "stumbleupon")
+	{
+		StumbleGlobals.toolbar_justification = "left";
+//		StumbleGlobals.dp("id", StumbleGlobals.get_parent_toolbar_id(new_parent));
+		StumbleGlobals.move_toolbar_elements(new_parent, null, 2);
+		
+		// The following contains workarounds to fix the bug where the
+		// toolbar appears 150px tall in old browsers (ref: Netscape 7.2,
+		// XP and Firefox 1.0RC1, XP) -- JW
+		if (new_parent.parentNode.boxObject.height > 100)
+		{
+			StumbleGlobals.get_element("stumbleglobals_field").style.height = "32px";
+			new_parent.style.height = "32px";
+			new_parent.parentNode.style.height = "32px";
+		}
+		new_parent.hidden = false;
+	}
+	else if (toolbar_position == "gtbToolbar")
+	{
+//		StumbleGlobals.dp("moving toolbar to gtbToolbar", new_parent.id);
+		StumbleGlobals.toolbar_justification = "left";
+		hbox = document.createElement("hbox");
+		hbox.setAttribute("id", "stumbleglobals_googlebar_container");
+		new_parent.insertBefore(hbox, new_parent.firstChild);
+		hbox.__defineSetter__("collapsed", function() {});
+		new_parent = hbox;
+		StumbleGlobals.move_toolbar_elements(new_parent, null, 3);
+	}
+	else if ((position_group == "last") || (position_group == "drop"))
+	{
+		var sibling;
+		if (position_group == "drop")
+		{
+//			StumbleGlobals.dp("survey");
+			try {
+				StumbleGlobals.survey_toolbar_siblings(toolbaritem);
+				sibling = toolbaritem.previousSibling;
+			}
+			catch (e) {
+				if ((toolbar_position == "stumbleupon") && (position_group == "first"))
+					StumbleGlobals.log_error("MOVE ERROR2", e);
+				else
+					StumbleGlobals.log_error("MOVE FAILSAFE2", e, toolbar_position, position_group);
+				StumbleGlobals.ds.setValue("@toolbar-position", "stumbleupon");
+				StumbleGlobals.ds.setValue("@position-group", "first");
+				StumbleGlobals.ds.setValue("@toolbar-visible", true);
+			}	
+		}
+		else
+		{
+			sibling = new_parent.lastChild;
+		}
+		
+		if ((toolbar_position == "PersonalToolbar") && 
+					(position_group == "last"))
+			StumbleGlobals.toolbar_justification = "right";
+		else
+			StumbleGlobals.toolbar_justification = (StumbleGlobals.test_previous_sibling_flexibility(sibling)) ? "right" : "left";
+		
+//		StumbleGlobals.dp("justification", StumbleGlobals.toolbar_justification);
+		if (StumbleGlobals.toolbar_justification == "left")
+		{
+			if (old_parent.id != "stumbleglobals_toolbar_container")
+				StumbleGlobals.move_toolbar_elements(new_parent, null, 4);
+		}
+		else if (StumbleGlobals.toolbar_justification == "right")
+		{
+			if ((old_parent.id == "stumbleglobals_toolbar_container") && 
+						(StumbleGlobals.ds.getValue("@toolbar-position") != "status-bar"))
+			{
+				if ((old_parent.parentNode.id != new_parent.id) && 
+							(position_group == "last"))
+					new_parent.appendChild(old_parent);
+			}
+			else
+			{
+				if (position_group == "last")
+				{
+					var hbox;
+					if (StumbleGlobals.ds.getValue("@toolbar-position") == "status-bar")
+						hbox = StumbleGlobals.get_element("stumbleglobals_statusbar_container");
+					else
+						hbox = StumbleGlobals.get_element("stumbleglobals_otherbar_container");
+					
+					if (! hbox)
+					{
+						hbox = document.createElement("hbox")
+						if (StumbleGlobals.ds.getValue("@toolbar-position") == "status-bar")
+							hbox.setAttribute("id", "stumbleglobals_statusbar_container");
+						else
+							hbox.setAttribute("id", "stumbleglobals_otherbar_container");
+						hbox.setAttribute("flex", "1");
+					
+						new_parent.appendChild(hbox);
+					}
+					new_parent = hbox;
+				}
+				StumbleGlobals.move_toolbar_elements(new_parent, null, 5);
+				
+				var outer_container = StumbleGlobals.get_toolbar_outer_container();
+				var width = outer_container.boxObject.width;
+				width = StumbleGlobals.ds.getPrefValue("@right-justify-width", width);
+				outer_container.setAttribute("width", width + "px");
+				if (outer_container.hasAttribute("flex"))
+					outer_container.removeAttribute("flex");
+				
+				if (StumbleGlobals.bookmarks_sibling_loc)
+					setTimeout(StumbleGlobals.move_toolbar_bookmarks, 1000, new_parent);
+			}
+		}
+	}
+	else
+	{
+		StumbleGlobals.toolbar_justification = "left";
+		StumbleGlobals.move_toolbar_elements(new_parent, new_parent.firstChild, 6);
+	}
+	
+	StumbleGlobals.moving_toolbar = false;
+
+	// change state of mozilla suite menuitem
+	var menuitem = StumbleGlobals.get_element("view_stumble_menuitem");
+	if (menuitem)
+	{
+		if (hidden_state)
+			menuitem.removeAttribute("checked");
+		else
+			menuitem.setAttribute("checked", "true");
+	}
+
+	setTimeout(
+				function (win) {
+					win.StumbleGlobals.cleanup_toolbox(true, false); },
+				0,
+				window);
+
+	StumbleGlobals.init_splitters();
+}
+
+StumbleGlobals.verify_toolbar_move = function(from)
+{
+	if (StumbleGlobals.get_element("stumbleglobals_stumble"))
+		return;
+	
+	// If we can't find the stumble button, recover upon browser
+	// restart.
+	StumbleGlobals.log_error(
+				"MOVE FAILSAFE4",
+				new Object(),
+				from,
+				StumbleGlobals.ds.getValue("@toolbar-position"),
+				StumbleGlobals.ds.getValue("@position-group"));
+	
+	StumbleGlobals.ds.setValue("@toolbar-position", "stumbleupon");
+	StumbleGlobals.ds.setValue("@position-group", "first");
+	
+	if (from == 5)
+	{
+		setTimeout(alert, 50, 
+				"StumbleUpon cannot accommodate this new configuration.\n\n" +
+				"Please restart the browser to recover from this error.\n\n");
+	}
+	else if (from == 6)
+	{
+		setTimeout(alert, 50, 
+				"The specified toolbar movement cannot be completed.\n\n" +
+				"Please restart the browser to recover from this error.\n\n");
+	}
+}
+
+StumbleGlobals.place_toolbaritem = function(toolbar, position_group)
+{
+	var currents;
+	if ((typeof toolbar.currentSet) == "string")
+		currents = toolbar.currentSet.split(",");
+	else if (toolbar.hasAttribute("currentset"))
+		currents = toolbar.getAttribute("currentset").split(",");
+	else
+		currents = new Array();
+	
+	if (position_group == "first")
+	{
+		if ((toolbar.id == "toolbar-menubar") && 
+					(currents[0] == "menubar-items"))
+		{
+			currents.splice(1, 0, "stumbleglobals_toolbaritem");
+			var previous = StumbleGlobals.get_element("menubar-items");
+			if (previous)
+			{
+				try {
+					toolbar.insertItem(
+								"stumbleglobals_toolbaritem",
+								previous.nextSibling,
+								null,
+								false);
+				} catch (e) { StumbleGlobals.log("PLACE ERROR1", toolbar.id, position_group); }
+			}
+			else
+			{
+				try {
+					toolbar.insertItem(
+								"stumbleglobals_toolbaritem",
+								toolbar.firstChild,
+								null,
+								true);
+				} catch (e) { StumbleGlobals.log("PLACE ERROR2", toolbar.id, position_group); }
+			}
+		}
+		else
+		{
+			currents.splice(0, 0, "stumbleglobals_toolbaritem");
+			try {
+				toolbar.insertItem(
+							"stumbleglobals_toolbaritem",
+							toolbar.firstChild,
+							null,
+							true);
+			} catch (e) { StumbleGlobals.log("PLACE ERROR3", toolbar.id, position_group); }
+		}
+	}
+	else if (position_group == "last")
+	{
+		currents.push("stumbleglobals_toolbaritem");
+		
+		toolbar.insertItem(
+					"stumbleglobals_toolbaritem",
+					null,
+					null,
+					false);
+	}
+	
+	toolbar.setAttribute("currentset", currents.join(","));
+	StumbleGlobals.persist_queue.push(toolbar.id);
+}
+
+StumbleGlobals.move_toolbar_bookmarks = function(container)
+{
+	var width = StumbleGlobals.ds.getValue("@right-justify-width");
+	container.setAttribute("width", width + "px");
+	if (container.hasAttribute("flex"))
+		container.removeAttribute("flex");
+
+	setTimeout(StumbleGlobals.reflow_toolbar, 1000, 4);
+}
+
+StumbleGlobals.get_parent_toolbar_id = function(el)
+{
+	var toolbar = StumbleGlobals.get_parent_toolbar(el);
+	if (toolbar)
+		return toolbar.id;
+	else
+		return null;
+}
+
+StumbleGlobals.get_parent_toolbar = function(el)
+{
+	var depth = 0;
+	while ((el.tagName != "toolbar") && (el.tagName != "statusbar"))
+	{
+		depth++;
+		if (depth == 1000)
+		{
+			break;
+		}
+		
+		el = el.parentNode;
+	}
+	
+	if (depth == 1000)
+	{
+		StumbleGlobals.log_error("PARENT FIND", ((el && el.id) ? el.id : ("no id " + (typeof el))), StumbleGlobals.ds.getValue("@toolbar-position"), StumbleGlobals.ds.getValue("@position-group"));
+		StumbleGlobals.ds.setValue("@toolbar-position", "stumbleupon");
+		StumbleGlobals.ds.setValue("@position-group", "first");
+		StumbleGlobals.ds.setValue("@toolbar-visible", true);
+		return null;
+	}
+	return el;
+}
+
+StumbleGlobals.survey_toolbar_siblings = function(outer_container)
+{
+	StumbleGlobals.bookmarks_sibling_loc = null;
+	if (! outer_container)
+		return;
+	var sibling = outer_container.parentNode.firstChild;
+	var seen_container = false;
+	while (sibling)
+	{
+		if (! sibling.id)
+		{
+			sibling = sibling.nextSibling;
+			continue;
+		}
+		
+		if (sibling == outer_container)
+			seen_container = true;
+		if (sibling.id == "personal-bookmarks")
+		{
+			StumbleGlobals.bookmarks_sibling_loc = (seen_container) ? "right" : "left";
+			break;
+		}
+		sibling = sibling.nextSibling;
+	}
+}
+
+// used by move_toolbar() to determine whether any previous sibling
+// of the toolbar is a flexible element; if one is, then the toolbar
+// is right-justified
+StumbleGlobals.test_previous_sibling_flexibility = function(previous_sibling)
+{
+	var sibling = previous_sibling;
+	var regexp = new RegExp("^spring\\d+$");
+	
+	var found_flexible_element = false;
+	while (sibling)
+	{
+		if (sibling.hasAttribute("flex") || (sibling.id && (sibling.id.search(regexp) == 0)))
+		{
+			found_flexible_element = true;
+			break;
+		}
+		sibling = sibling.previousSibling;
+	}
+	return found_flexible_element;
+}
+
+
+// moves the top-level toolbar elements from
+// StumbleGlobals.splitter_first_flexbox through either StumbleGlobals.site-box-count or
+// StumbleGlobals.overflow_menu to a new location subsequent to argument 
+// target_next_sibling
+StumbleGlobals.move_toolbar_elements = function(target_parent, target_next_sibling, from)
+{
+	try {
+//	throw("t");
+
+	var sibling = StumbleGlobals.get_element("stumbleglobals_splitter_first_flexbox");
+	var previous_sibling_id = "";
+	var old_parent = sibling.parentNode;
+//	StumbleGlobals.dp("move elements", old_parent.id, target_parent.id, from);
+	
+	var depth = 0;
+	
+	while (previous_sibling_id != "stumbleglobals_overflow_menu")
+	{
+		depth++;
+		if (depth == 1000)
+		{
+			break;
+		}
+		
+		previous_sibling_id = sibling.id;
+		var element = sibling;
+		sibling = sibling.nextSibling;
+		var new_element;
+		if ((element.id == "stumbleglobals_stumble_menu") || (element.id =="stumbleglobals_category") ||
+					(element.id == "stumbleglobals_field") || (element.id == "stumbleglobals_referral_menu") ||
+					(element.id == "stumbleglobals_overflow_menu"))
+		{
+			new_element = element;
+		}
+		else
+		{
+			new_element = element.cloneNode(true);
+			element.parentNode.removeChild(element);
+		}
+		
+		if (target_next_sibling)
+			target_parent.insertBefore(new_element, target_next_sibling);
+		else
+			target_parent.appendChild(new_element);
+		
+		if (new_element.id == "stumbleglobals_field")
+		{
+			var width = StumbleGlobals.ds.getValue("@search-width");
+			new_element.setAttribute("width", width + "px");
+		}
+	}
+	
+	if (depth == 1000)
+	{
+		StumbleGlobals.log_error("MOVE LOOP", from, StumbleGlobals.ds.getValue("@toolbar-position"), StumbleGlobals.ds.getValue("@position-group"));
+		StumbleGlobals.ds.setValue("@toolbar-position", "stumbleupon");
+		StumbleGlobals.ds.setValue("@position-group", "first");
+		StumbleGlobals.ds.setValue("@toolbar-visible", true);
+	}
+	
+	if ((old_parent.id == "stumbleglobals_statusbar_container") && 
+				(target_parent.id != "stumbleglobals_statusbar_container"))
+		old_parent.parentNode.removeChild(old_parent);
+	
+	if ((old_parent.id == "stumbleglobals_googlebar_container") && 
+				(target_parent.id != "stumbleglobals_googlebar_container"))
+		old_parent.parentNode.removeChild(old_parent);
+	
+	if ((old_parent.id == "stumbleglobals_otherbar_container") && 
+				(target_parent.id != "stumbleglobals_otherbar_container"))
+		old_parent.parentNode.removeChild(old_parent);
+	
+	} catch (e) {
+		StumbleGlobals.log_error("MOVE TOOLBAR", e, from, StumbleGlobals.ds.getValue("@toolbar-position"), StumbleGlobals.ds.getValue("@position-group"));
+		
+		StumbleGlobals.ds.setValue("@toolbar-position", "stumbleupon");
+		StumbleGlobals.ds.setValue("@position-group", "first");
+		StumbleGlobals.ds.setValue("@toolbar-visible", true);
+	}
+}
+
+StumbleGlobals.refresh_toggle_button = function(force)
+{
+	if (! window.BrowserCustomizeToolbar)
+		return;
+	
+	var visible = StumbleGlobals.ds.getValue("@toolbar_toggle_visible");
+	var found = false;
+
+	found = StumbleGlobals.is_item_in_toolbox((force && (! visible)), "stumbleglobals_toggle");
+	
+	if (! force)
+		StumbleGlobals.ds.setValue("@toolbar_toggle_visible", found);
+
+	if (force && (! found) && visible)
+		StumbleGlobals.add_toggle_button();
+}
+
+StumbleGlobals.add_toggle_button = function()
+{
+	if (document.getElementById("stumbleglobals_toggle"))
+		return;
+	
+	var urlbar = StumbleGlobals.get_element("urlbar-container");
+	
+	var target = null;
+	if (urlbar)
+		target = urlbar.parentNode;
+	
+	if (target && target.collapsed)
+		target = null;
+	
+	var preferred_target = (target) ? true : false;
+	
+	if (! target)
+		target = StumbleGlobals.get_element("nav-bar");
+	
+	if (target && target.collapsed)
+		target = null;
+	
+	if (! target)
+		target = StumbleGlobals.get_element("toolbar-menubar");
+	
+	if (target && target.collapsed)
+		target = null;
+	
+	if (target && target.hasAttribute("customizable") && 
+				(target.getAttribute("customizable").toLowerCase() == "true"))
+	{
+		var currents = target.currentSet.split(",");
+		if (preferred_target)
+		{
+			var i;
+			for (i = 0; i < currents.length; i++)
+			{
+				if (currents[i] == "urlbar-container")
+				{
+					currents.splice(i, 0, "stumbleglobals_toggle");
+					break;
+				}
+			}
+			target.insertItem("stumbleglobals_toggle", urlbar, null, false);
+		}
+		else
+		{
+			currents.push("stumbleglobals_toggle");
+			
+			target.insertItem("stumbleglobals_toggle", null, null, false);
+		}
+		
+		target.setAttribute("currentset", currents.join(","));
+		StumbleGlobals.persist_queue.push(target.id);
+	}
+	else
+	{
+		StumbleGlobals.ds.setValue("@toolbar_toggle_visible", false);
+	}
+}
+
+StumbleGlobals.is_item_in_toolbox = function(remove, id, opt_toolbar)
+{
+	var toolbars;
+	if (opt_toolbar)
+	{
+		toolbars = new Array();
+		toolbars.push(opt_toolbar);
+	}
+	else
+	{
+		toolbars = document.getElementsByTagName("toolbar");
+	}
+
+	var found = false;
+	var i;
+	for (i = 0; i < toolbars.length; i++)
+	{
+		var item = StumbleGlobals.get_element(id);
+		
+		if (remove)
+			StumbleGlobals.is_element_on_bar(true, toolbars[i].id, id);
+
+		if (! toolbars[i].hasAttribute("customizable"))
+			continue;
+		
+		if (! toolbars[i].getAttribute("customizable").toLowerCase() == "true")
+			continue;
+		
+		var currents;
+		if ((typeof toolbars[i].currentSet) == "string")
+			currents = toolbars[i].currentSet.split(",");
+		else
+			currents = new Array();
+
+		var new_currents = new Array();
+		while(currents.length)
+		{
+			if (currents[0] == id)
+			{
+				found = true;
+				if (remove)
+					currents.shift();
+				else
+					new_currents.push(currents.shift());
+			}
+			else
+			{
+				new_currents.push(currents.shift());
+			}
+		}
+		
+		var current_set = new_currents.join(",");
+		
+		var old_set;
+		if (toolbars[i].hasAttribute("currentset"))
+			old_set = toolbars[i].getAttribute("currentset");
+		else
+			old_set = "";
+		
+		toolbars[i].setAttribute("currentset", current_set);
+		if (current_set != old_set)
+			StumbleGlobals.persist_queue.push(toolbars[i].id);
+	}
+	return found;
+}
+
+StumbleGlobals.is_element_on_bar = function(remove, toolbar_id, id)
+{
+	// This works around a browser bug where el.parentNode.id can report
+	// the wrong id when parentNode is a toolbar (ref: Firefox 2.0rc1, 
+	// Linux).  --  JW
+	var toolbar = StumbleGlobals.get_element(toolbar_id);
+	
+	if (! toolbar)
+		return false;
+	
+	var found = false;
+	var sibling = toolbar.firstChild;
+	var count = 0;
+	var el;
+	while (sibling)
+	{
+		count++;
+		if (count == 1000)
+		{
+			break;
+		}
+		el = sibling;
+		sibling = sibling.nextSibling;
+		if (el.id == id)
+		{
+			found = true;
+			if (remove)
+				toolbar.removeChild(el);
+		}
+	}
+	
+	if (count == 1000)
+		StumbleGlobals.log_error("ON LOOP");
+	
+	return found;
+}
+
+
+// this is part of a hack that redefines behavior of the view->
+// toolbars->StumbleUpon menuitem in Firefox-derived browsers
+StumbleGlobals.replacement_onViewToolbarsPopupShowing = function(event)
+{
+	// During initialization, we make 
+	// window.StumbleGlobals.saved_onViewToolbarsPopupShowing point to the browser-
+	// defined function window.onViewToolbarsPopupShowing (ref Firefox
+	// 1.5).  Then we make window.onViewToolbarsPopupShowing point to
+	// this function.  So this function runs when the browser invokes
+	// window.onViewToolbarsPopupShowing(..).
+	//
+	// This function executes the original browser-defined routine 
+	// before locating and modifying the StumbleUpon Toolbar menuitem. 
+	// -- JW
+	
+	window.StumbleGlobals.saved_onViewToolbarsPopupShowing(event);
+	
+	var sibling = event.target.firstChild;
+	
+	var found = false;
+	while (sibling)
+	{
+		if (sibling.getAttribute("label").indexOf("StumbleUpon Toolbar") == 0)
+		{
+			found = true;
+			break;
+		}
+		sibling = sibling.nextSibling;
+	}
+	
+	if (found)
+	{
+		var menuitem = sibling;
+		menuitem.setAttribute("checked", StumbleGlobals.ds.getValue("@toolbar-visible"));
+		menuitem.removeEventListener("command", onViewToolbarCommand, false);
+		menuitem.addEventListener("command", StumbleGlobals.handle_view_toolbar_command, false);
+	}
+}
+
+StumbleGlobals.replacement_BrowserCustomizeToolbar = function()
+{
+	var toolbars = document.getElementsByTagName("toolbar");
+	var i;
+	var found = false;
+	for (i = 0; i < toolbars.length; i++)
+	{
+		if (toolbars[i].hasAttribute("currentset"))
+		{
+			var currents = toolbars[i].getAttribute("currentset").split(",");
+			var j;
+			for (j = 0; j < currents.length; j++)
+			{
+				if (currents[j] == "stumbleglobals_toolbaritem")
+				{
+					found = true;
+					break;
+				}
+			}
+		}
+	}
+	
+	if (! found)
+	{
+		var item = StumbleGlobals.get_element("stumbleglobals_toolbaritem");
+		var toolbar = StumbleGlobals.get_element("stumbleupon");
+		toolbar.setAttribute("currentset", "stumbleglobals_toolbaritem");
+		toolbar.insertItem("stumbleglobals_toolbaritem", null, null, true);
+		StumbleGlobals.persist_queue.push("stumbleupon");
+	}
+	
+	setTimeout("StumbleGlobals.replacement_BrowserCustomizeToolbar2();", 200);
+
+	var position = StumbleGlobals.ds.getValue("@toolbar-position"); 
+	
+	if ((position == "status-bar") || (position == "yahoo-toolbar"))
+		return;
+	
+	
+	var el = StumbleGlobals.get_element("bookmarks-ptf");
+	if (el)
+		el.hidden = true;
+
+	var new_parent = StumbleGlobals.get_element("stumbleglobals_container");
+	new_parent.hidden = true;
+
+	var splitter = StumbleGlobals.get_element("stumbleglobals_right-justify-splitter");
+	if (splitter)
+		splitter.collapsed = true;
+
+	StumbleGlobals.move_toolbar_elements(new_parent, null, 7);
+	
+	var needs_cleanup = false;
+
+	var container = StumbleGlobals.get_element("stumbleglobals_googlebar_container");
+	if (container)
+	{
+		needs_cleanup = true;
+		container.parentNode.removeChild(container);
+	}
+
+	var toolbaritem = StumbleGlobals.get_element("stumbleglobals_toolbaritem");
+	if (toolbaritem)
+	{
+		needs_cleanup = true;
+		if (toolbaritem.hasAttribute("width"))
+			toolbaritem.removeAttribute("width");
+		
+		if (toolbaritem.hasAttribute("flex"))
+			toolbaritem.removeAttribute("flex");
+	}
+	
+	if (needs_cleanup)
+		StumbleGlobals.cleanup_toolbox(true, true);
+}
+
+StumbleGlobals.replacement_BrowserCustomizeToolbar2 = function()
+{
+	window.StumbleGlobals.saved_BrowserCustomizeToolbar();
+	
+	var position = StumbleGlobals.ds.getValue("@toolbar-position"); 
+	if ((position == "status-bar") || (position == "yahoo-toolbar"))
+	{
+		StumbleGlobals.get_element("stumbleupon").collapsed = true;
+		StumbleGlobals.get_element("stumbleglobals_toolbar_customize_label").value = "";
+	}
+	else
+	{
+		var shortcut = StumbleGlobals.ds.getValue("$shortcut_toolbar");
+		var label = "StumbleUpon Toolbar Items";
+		if (shortcut != "")
+		{
+			label += " (" + 
+						StumbleGlobals.get_display_keyspec(shortcut) + 
+						")";
+		}
+		
+		StumbleGlobals.get_element("stumbleupon").collapsed = false;
+		StumbleGlobals.get_element("stumbleglobals_toolbar_customize_label").value = label;
+	}
+}
+
+StumbleGlobals.replacement_BrowserToolboxCustomizeDone = function(aToolboxChanged)
+{
+	if (window.StumbleGlobals.saved_BrowserToolboxCustomizeDone)
+		window.StumbleGlobals.saved_BrowserToolboxCustomizeDone(aToolboxChanged);
+	
+	StumbleGlobals.refresh_toggle_button(false);
+	
+	var position = StumbleGlobals.ds.getValue("@toolbar-position");
+	if ((position == "status-bar") || (position == "yahoo-toolbar"))
+		return;
+	
+	var el = StumbleGlobals.get_element("bookmarks-ptf");
+	if (el)
+		el.hidden = false;
+	
+	var outer_container = StumbleGlobals.get_element("stumbleglobals_toolbaritem");
+	if (outer_container)
+	{
+		setTimeout(StumbleGlobals.replacement_BrowserToolboxCustomizeDone2, 0);
+	}
+	else
+	{
+		StumbleGlobals.get_element("stumbleupon").collapsed = true;
+		var toolbar = StumbleGlobals.get_element("stumbleupon");
+		var currents = toolbar.currentSet.split(",");
+		currents.push("stumbleglobals_toolbaritem");
+		toolbar.setAttribute("currentset", currents.join(","));
+		toolbar.insertItem("stumbleglobals_toolbaritem", null, null, true); 
+		StumbleGlobals.ds.setValue("@toolbar-visible", false);
+		StumbleGlobals.persist_queue.push("stumbleupon");
+	}
+	if (StumbleGlobals.customize_invoked_from_preference_dialog)
+	{
+		StumbleGlobals.customize_invoked_from_preference_dialog = false;
+		setTimeout(StumbleGlobals.preferences, 1000);
+	}
+
+	StumbleGlobals.get_element("stumbleglobals_toolbar_customize_label").value = "";
+}
+
+StumbleGlobals.replacement_BrowserToolboxCustomizeDone2 = function()
+{
+	StumbleGlobals.move_toolbar(false, 5)
+	StumbleGlobals.reflow_toolbar(5);
+	setTimeout(StumbleGlobals.verify_toolbar_move, 0, 5);
+}
+
+StumbleGlobals.replacement_foxytunesSetFoxyTunesPosition = function()
+{
+	try {
+		StumbleGlobals.saved_foxytunesSetFoxyTunesPosition();
+	} catch (e) {}
+	setTimeout(StumbleGlobals.replacement_BrowserToolboxCustomizeDone2, 200);
+}
+
+StumbleGlobals.is_toolbar_shared = function()
+{
+	var toolbar = StumbleGlobals.get_element("stumbleupon");
+	var sibling = toolbar.firstChild;
+	var count = 0;
+	var el;
+	while (sibling)
+	{
+		count++;
+		if (count == 1000)
+			break;
+		
+		el = sibling;
+		sibling = sibling.nextSibling;
+		switch (el.id)
+		{
+			case "stumbleglobals_toolbaritem":
+			case "stringbundleset":
+			case "bundle_stumble":
+			case "stumbleglobals_commandset":
+			case "stumbleglobals_keyset":
+			case "stumbleglobals_container":
+			case "stumbleglobals_render":
+				break;
+			default:
+				return true;
+		}
+	}
+	
+	return false;
+}
+
+StumbleGlobals.prevent_toolbar_sharing = function()
+{
+	if (! window.BrowserCustomizeToolbar)
+		return;
+	
+	var toolbar = StumbleGlobals.get_element("stumbleupon");
+	var currents = toolbar.currentSet.split(",");
+	var new_currents = new Array();
+	var i;
+	var modified = false;
+	var el;
+	for (i = 0; i < currents.length; i++)
+	{
+		switch (currents[i])
+		{
+			case "__empty":
+			case "stumbleglobals_toolbaritem":
+				new_currents.push(currents[i]);
+				break;
+			default:
+				modified = true;
+				break;
+		}
+	}
+	
+	var sibling = toolbar.firstChild;
+	var count = 0;
+	while (sibling)
+	{
+		count++;
+		if (count == 1000)
+		{
+			break;
+		}
+		el = sibling;
+		sibling = sibling.nextSibling;
+		switch (el.id)
+		{
+			case "stumbleglobals_toolbaritem":
+			case "stringbundleset":
+			case "bundle_stumble":
+			case "stumbleglobals_commandset":
+			case "stumbleglobals_keyset":
+			case "stumbleglobals_container":
+			case "stumbleglobals_render":
+				break;
+			default:
+				toolbar.removeChild(el);
+		}
+	}
+	
+	if (count == 1000)
+		StumbleGlobals.log_error("SHARING LOOP");
+	
+	if (modified)
+	{
+		var new_parent = StumbleGlobals.get_element("stumbleupon-hbox");
+		new_parent.hidden = true;
+		StumbleGlobals.move_toolbar_elements(new_parent, null, 8);
+
+		toolbar.setAttribute("currentset", currents.join(","));
+		StumbleGlobals.persist_queue.push("stumbleupon");
+		setTimeout("StumbleGlobals.move_toolbar(false, 3);", 0);
+		setTimeout(StumbleGlobals.reflow_toolbar, 0, 6);
+	}
+}
+
+StumbleGlobals.customize_toolbox = function()
+{
+	StumbleGlobals.customize_invoked_from_preference_dialog = true;
+	document.getElementById("cmd_CustomizeToolbars").doCommand();
+}
+
+// forwards the view->toolbars menuitem command event in Firefox-
+// derived browsers
+StumbleGlobals.handle_view_toolbar_command = function(event)
+{
+	setTimeout("StumbleGlobals.toggle_toolbar();", 0);
+}
+
+// ultimately called by the view->toolbars menuitem in Firefox-
+// derived browsers
+StumbleGlobals.toggle_toolbar = function()
+{
+	StumbleGlobals.toggling_toolbar = true;
+
+	var toolbar_position = StumbleGlobals.ds.getValue("@toolbar-position");
+
+	var new_visible_state;
+	if (toolbar_position == "stumbleupon")
+		new_visible_state = StumbleGlobals.get_element("stumbleupon").collapsed;
+	else
+		new_visible_state = ! StumbleGlobals.ds.getValue("@toolbar-visible");
+
+	StumbleGlobals.ds.setValue("@toolbar-visible", new_visible_state);
+	
+	StumbleGlobals.move_toolbar(false, 4);
+
+	StumbleGlobals.toggling_toolbar = false;
+
+	if (new_visible_state)
+		StumbleGlobals.reflow_toolbar(7);
+
+/*
+	if (StumbleGlobals.new_install && (! StumbleGlobals.ds.getValue("@shown_toolbar")))
+	{
+		StumbleGlobals.ds.setValue("@shown_toolbar", true);
+		StumbleGlobals.stumble(0);
+	}
+*/
+
+	StumbleGlobals.ds.flushPrefs();
+	
+	// And update the referral count
+	StumbleGlobals.update_referred();
+}
+
+// handles the mousedown event for the splitter to the right of the 
+// search box
+StumbleGlobals.handle_splitter_search_right_mousedown = function(event)
+{
+	StumbleGlobals.moving_splitter = true;
+	var outer_container = StumbleGlobals.get_element("stumbleglobals_toolbaritem");
+	if (outer_container || (StumbleGlobals.toolbar_justification == "right"))
+		StumbleGlobals.shorten_toolbar_to_element("stumbleglobals_splitter_search_right");
+	StumbleGlobals.set_toolbar_element_widths(StumbleGlobals.get_element("stumbleglobals_stumble"));
+
+	return true;
+}
+
+// handles the mouseup event for the splitter to the right of the 
+// search box
+StumbleGlobals.handle_splitter_search_right_mouseup = function(event)
+{
+	setTimeout('StumbleGlobals.remove_toolbar_element_widths(StumbleGlobals.get_element("stumbleglobals_stumble"))', 0);		
+	StumbleGlobals.moving_splitter = false;
+	if (StumbleGlobals.get_element("stumbleglobals_field").boxObject.width > 400)
+		setTimeout('StumbleGlobals.get_element("stumbleglobals_field").setAttribute("width", "400px")');
+
+	setTimeout("StumbleGlobals.refresh_splitters(false)", 0);
+	return true;
+}
+
+StumbleGlobals.get_toolbar_outer_container = function()
+{
+	var position = StumbleGlobals.ds.getValue("@toolbar-position");
+	var container;
+	if ((position == "status-bar") && 
+				(StumbleGlobals.ds.getValue("@position-group") == "last"))
+	{
+		container = StumbleGlobals.get_element("stumbleglobals_statusbar_container");
+	}
+	else if (StumbleGlobals.ds.getValue("@position-group") == "last")
+	{
+		container = StumbleGlobals.get_element("stumbleglobals_otherbar_container");
+	}
+	else if (position == "gtbToolbar")
+	{
+		container = StumbleGlobals.get_element("stumbleglobals_googlebar_container");
+	}
+	
+	if (! container)
+	{
+		container = StumbleGlobals.get_element("stumbleglobals_stumble").parentNode;
+	}
+	
+	if (container.id == "stumbleglobals_toolbar_container")
+	{
+		container = StumbleGlobals.get_element("stumbleglobals_toolbaritem");
+	}
+	return container;
+}
+
+// handles the mouseup event for the dynamic splitter that's created
+// when the toolbar is right-justified
+StumbleGlobals.handle_right_justify_splitter_mousedown = function(event)
+{
+	StumbleGlobals.moving_splitter = true;
+	
+	StumbleGlobals.shorten_toolbar_to_element("stumbleglobals_thumbdown");
+	
+	StumbleGlobals.set_toolbar_element_widths(StumbleGlobals.get_toolbar_outer_container());
+	
+	return true;
+}
+
+// handles the mousedown event for the dynamic splitter that's
+// created when the toolbar is right-justified
+StumbleGlobals.handle_right_justify_splitter_mouseup = function(event)
+{
+	var hbox = StumbleGlobals.get_toolbar_outer_container();
+
+	StumbleGlobals.ds.setValue("@right-justify-width", hbox.boxObject.width);
+	
+	setTimeout('StumbleGlobals.remove_toolbar_element_widths(StumbleGlobals.get_element("' + 
+				hbox.id + '"))', 0);		
+	StumbleGlobals.moving_splitter = false;
+	setTimeout("StumbleGlobals.refresh_splitters(false)", 0);
+	
+	return true;
+}
+
+// used by splitter mousedown listeners to set temporary minwidths 
+// for adjacent elements
+StumbleGlobals.set_toolbar_element_widths = function(sibling)
+{
+	sibling = sibling.parentNode.firstChild;
+
+	while (sibling != null)
+	{
+		if (sibling.id == "personal-bookmarks")
+		{
+			var el = StumbleGlobals.get_element("bookmarks-stack");
+			if (el)
+				el.hidden = true;
+		}
+		else if (sibling.id && (sibling.id.indexOf("spring") != 0) && 
+					(sibling.id != "stumbleglobals_splitter_first_flexbox") &&
+					(sibling.id != "stumbleglobals_field") &&
+					(sibling.id != "stumbleglobals_toolbar_container") &&
+					(sibling.id != "stumbleglobals_toolbaritem") &&
+					(sibling.id != "stumbleglobals_statusbar_container") &&
+					(sibling.id != "stumbleglobals_otherbar_container") &&
+					(sibling.id != "stumbleglobals_googlebar_container") &&
+					(sibling.tagName != "tooltip") &&
+					(! sibling.hasAttribute("flex")))
+		{
+			if (sibling.hasAttribute("minwidth"))
+				sibling.setAttribute("stumbleglobals_savedminwidth", sibling.getAttribute("minwidth"));
+
+			if (sibling.hasAttribute("width"))
+				sibling.setAttribute("stumbleglobals_hadwidth", "true");
+			
+			sibling.setAttribute("minwidth", sibling.boxObject.width + "px");
+		}
+		
+		sibling = sibling.nextSibling;
+	}
+}
+
+// used by splitter mouseup listeners to remove the temporary 
+// minwidths set by set_toolbar_element_widths
+StumbleGlobals.remove_toolbar_element_widths = function(sibling)
+{
+	sibling = sibling.parentNode.firstChild;
+
+	while (sibling != null)
+	{
+		if (sibling.hasAttribute("stumbleglobals_savedminwidth"))
+			sibling.setAttribute("minwidth", sibling.getAttribute("stumbleglobals_savedminwidth"));
+		else
+			sibling.removeAttribute("minwidth");
+
+		if (sibling.id == "personal-bookmarks")
+		{
+			var el = StumbleGlobals.get_element("bookmarks-stack");
+			if (el)
+			{
+				el.hidden = false;
+			}
+		}
+		else if ((sibling.id != "stumbleglobals_splitter_first_flexbox") && 
+					(sibling.id != "stumbleglobals_field") &&
+					(sibling.id != "stumbleglobals_toolbar_container") && 
+					(sibling.id != "stumbleglobals_toolbaritem") &&
+					(sibling.id != "stumbleglobals_statusbar_container") &&
+					(sibling.id != "stumbleglobals_otherbar_container") &&
+					(sibling.id != "stumbleglobals_googlebar_container") &&
+					(sibling.tagName != "tooltip"))
+		{
+			if (sibling.hasAttribute("stumbleglobals_hadwidth"))
+				sibling.removeAttribute("stumbleglobals_hadwidth");
+			else
+				sibling.removeAttribute("width");
+		}
+		sibling = sibling.nextSibling;
+	}
+}
+
+StumbleGlobals.shorten_toolbar_to_element = function(stop_id)
+{
+	var popup = StumbleGlobals.get_element("stumbleglobals_overflow_popup");
+	var i;
+	var item;
+	for (i = 0; i < popup.childNodes.length; i++)
+	{
+		item = popup.childNodes[i];
+		if (item.id && (item.id == stop_id))
+			return;
+	}
+	
+	var container = StumbleGlobals.get_element("stumbleglobals_stumble").parentNode;
+	
+	var menuified_one = false;
+	for (i = container.childNodes.length - 2; i >= 0; i--)
+	{
+		item = container.childNodes[i];
+		if (item.id && (item.id == stop_id))
+			break;
+		StumbleGlobals.menuify_toolbar_element(item);
+		menuified_one = true;
+	}
+	if (menuified_one)
+	{
+		var menu = StumbleGlobals.get_element("stumbleglobals_overflow_menu");
+		menu.collapsed = false;
+		menu.hidden = false;
+	}
+	StumbleGlobals.cleanup_overflow_flexbox()
+}
+
+// handles the left margin splitter mousedown event
+StumbleGlobals.handle_splitter_first_mousedown = function(event)
+{
+	StumbleGlobals.moving_splitter = true;
+	return true;
+}
+
+// handles the left margin splitter mouseup event
+StumbleGlobals.handle_splitter_first_mouseup = function(event)
+{
+	StumbleGlobals.moving_splitter = false;
+	setTimeout("StumbleGlobals.refresh_splitters(false)", 0);
+	return true;
+}
+
+// handles the sidebar splitter mouseup event
+StumbleGlobals.handle_sidebar_mouseup = function(event)
+{
+	setTimeout("StumbleGlobals.refresh_splitters(false)", 0);
+	return true;
+}
+
+// handles the sidebar splitter attr modified event
+StumbleGlobals.handle_sidebar_attr_modified = function(event)
+{
+	if (event.attrName == "hidden")
+		setTimeout("StumbleGlobals.refresh_splitters(false)", 0);
+
+	return true;
+}
+
+// queues a change to the hidden state of a top-level toolbar element
+StumbleGlobals.set_visible = function(id, state)
+{
+	state = ! state;
+	var element = StumbleGlobals.get_element(id);
+	var changed = false;
+	if (element.parentNode.id == "stumbleglobals_overflow_popup")
+	{
+		if (element.hasAttribute("savedhidden"))
+			element.setAttribute("savedhidden", state);
+		else
+			element.collapsed = state;
+	}
+	else
+	{
+		if (element.hasAttribute("stumbleglobals_ismode"))
+		{
+			changed = (element.hidden != state);
+			element.hidden = state;
+		}
+		else
+		{
+			changed = (element.collapsed != state);
+			element.collapsed = state;
+		}
+	}
+	
+	if ((! state) && (id == "stumbleglobals_referred"))
+		setTimeout(StumbleGlobals.stop_referred_throbber, StumbleGlobals.ds.getValue("$referral_throbber_interval_ms")) 
+	
+	if (changed)
+		setTimeout("StumbleGlobals.reflow_toolbar(8)", 10);
+}
+
+StumbleGlobals.stop_referred_throbber = function()
+{
+	StumbleGlobals.set_attribute("stumbleglobals_referred", "busy", "false");
+}
+
+// for future use, to fix the textonly bug
+//StumbleGlobals.is_toolbar_textonly = function()
+//{
+//	var toolbar = StumbleGlobals.get_parent_toolbar(StumbleGlobals.get_element("stumbleglobals_stumble"));
+//	if (! toolbar)
+//		return false;
+//	
+//	if (toolbar.hasAttribute("mode") &&
+//				(toolbar.getAttribute("mode") == "text"))
+//		return true;
+//}
+
+// queues a change to the label of a top-level toolbar element
+StumbleGlobals.set_label = function(id, str)
+{
+	var element = StumbleGlobals.get_element(id);
+	var menuified = (element.parentNode.id == "stumbleglobals_overflow_popup");
+
+	if (id == "stumbleglobals_mode")
+	{
+		StumbleGlobals.get_element("stumbleglobals_mode_label").collapsed = (! StumbleGlobals.get_label_visibility(id, menuified));
+		return;
+	}
+	else if (id == "stumbleglobals_category" && str == "All")
+	{
+		str += " ";
+	}
+
+	// When str is null, use the value in the showlabel attribute.
+	// -- JW
+
+	if (StumbleGlobals.get_label_visibility(id, menuified))
+	{
+		if ((!str) && element.hasAttribute("showlabel"))
+			str = element.getAttribute("showlabel");
+	}
+	else
+	{
+		str = "";
+	}
+
+	var changed = (element.label != str);
+	str = (str) ? str : "";
+	
+	if (str == "")
+	{
+		if (menuified)
+			element.className = "su-hidetext-menuified";
+		else
+			element.className = "su-hidetext";
+	}
+	else
+	{
+		if (menuified)
+			element.className = "su-showtext-menuified";
+		else
+		{
+			if (element.id == "stumbleglobals_stumble_topic")
+				element.className = "su-hideicon-showtext";
+			else
+				element.className = "su-showtext";
+		}
+		element.label = str;
+	}
+	
+	if (changed)
+		setTimeout("StumbleGlobals.reflow_toolbar(9)", 10);
+}
+
+StumbleGlobals.set_attribute = function(id, attr_name, value)
+{
+	var el = StumbleGlobals.get_element(id);
+	if (! el)
+		return;
+	el.setAttribute(attr_name, value);
+}
+
+StumbleGlobals.remove_attribute = function(id, attr_name, value)
+{
+	var el = StumbleGlobals.get_element(id);
+	if (! el)
+		return;
+	if (el.hasAttribute(attr_name))
+		el.removeAttribute(attr_name);
+}
+
+// used by the toolbar refresh routines to determine whether the 
+// label associated with a top-level toolbar element is to be 
+// displayed when it has the specified menuified state
+StumbleGlobals.get_label_visibility = function(id, menuified)
+{
+	var always_visible_ids = ",stumbleglobals_login,stumbleglobals_start,stumbleglobals_referred,stumbleglobals_site-count-box,stumbleglobals_recthumbup,stumbleglobals_category,stumbleglobals_stumble_topic," +
+				"stumbleglobals_stumble_topic_menu_left,stumbleglobals_stumble_topic_menu_right," +
+				"stumbleglobals_page_feature_prompt,stumbleglobals_grab,stumbleglobals_approve,stumbleglobals_idx,stumbleglobals_tld,";
+	var text_icons_mode_visible_ids = ",stumbleglobals_stumble,stumbleglobals_thumbup,stumbleglobals_profile," + 
+				"stumbleglobals_friends,stumbleglobals_referral_menu,firstrater,stumbleglobals_sponsor," + 
+				"stumbleglobals_mode,stumbleglobals_stumble_menu,stumbleglobals_website_info,";
+	var element = StumbleGlobals.get_element(id);
+	var query = "," + id + ",";
+	
+	if ((StumbleGlobals.stumbleid != 0) && StumbleGlobals.ds.getValue("$show_firstrater_label_always"))
+		always_visible_ids += "firstrater,stumbleglobals_sponsor,";
+	
+	if (StumbleGlobals.promo_mode && (StumbleGlobals.stumbleid == 0))
+		always_visible_ids += "stumbleglobals_referral_promo,stumbleglobals_website_info_promo,stumbleglobals_sites_promo,stumbleglobals_video_promo,"
+	
+	var text_icons = true;
+	
+	if (StumbleGlobals.stumbleid != 0)
+		text_icons = (StumbleGlobals.ds.getValue("$icons") == "text-icons"); 
+	
+	// Visible if:
+	// (1) it's always visible
+	// (2) we're configured to text-icons, and this is in the visible subset
+	// (3) it's in the overflow popup, and it has a showlabel attribute
+	// -- JW
+	return (always_visible_ids.indexOf(query) != -1) ||
+				(text_icons && 
+				(text_icons_mode_visible_ids.indexOf(query) != -1)) ||
+				(menuified && element.hasAttribute("showlabel") && 
+					(id != "stumbleglobals_mode"));
+}
+
+// queues a change to the image of a top-level toolbar element
+StumbleGlobals.set_image = function(id, uri)
+{
+	var element = StumbleGlobals.get_element(id);
+
+	var changed = (element.image != uri);
+	if (changed)
+	{
+		element.image = uri;
+		setTimeout("StumbleGlobals.reflow_toolbar(10)", 10);
+	}
+}
+
+// used by splitter mouseup handlers and the splitter init routine to
+// set splitter visibility and to store new state
+StumbleGlobals.refresh_splitters = function(use_saved_latch_state)
+{
+	try {
+	var content_x = StumbleGlobals.get_element("content").boxObject.x;
+	var toolbar_x = StumbleGlobals.get_element("stumbleglobals_stumble").boxObject.x;
+	var sidebar_hidden = StumbleGlobals.get_element("sidebar-splitter").hidden || 
+				StumbleGlobals.get_element("sidebar-box").collapsed;
+	var align_with_content = StumbleGlobals.ds.getValue("@latch-to-sidebar");
+	var splitter_first = StumbleGlobals.get_element("stumbleglobals_splitter_first");
+	var first_flexbox = StumbleGlobals.get_element("stumbleglobals_splitter_first_flexbox");
+	
+	var splitter = StumbleGlobals.get_element("stumbleglobals_right-justify-splitter")
+
+	if ((StumbleGlobals.toolbar_justification == "left") && (splitter))
+	{
+		splitter.parentNode.removeChild(splitter);
+	}
+	else if ((StumbleGlobals.toolbar_justification == "right") && (! splitter))
+	{
+		var splitter = document.createElement("splitter");
+		splitter.setAttribute("id", "stumbleglobals_right-justify-splitter");
+		splitter.setAttribute("class", "stumbleglobals_splitter");
+		splitter.setAttribute("state", "open");
+		splitter.setAttribute("collapse", "none");
+		splitter.setAttribute("resizebefore", "grow");
+		splitter.setAttribute("resizeafter", "closest");
+		splitter.setAttribute("onmousedown", "return StumbleGlobals.handle_right_justify_splitter_mousedown(event);");
+		splitter.setAttribute("onmouseup", "return StumbleGlobals.handle_right_justify_splitter_mouseup(event);");
+		
+		var sibling = StumbleGlobals.get_toolbar_outer_container();
+		sibling.parentNode.insertBefore(splitter, sibling);
+	}
+	else if ((StumbleGlobals.toolbar_justification == "right") && (splitter))
+	{
+		splitter.collapsed = false;
+		var sibling = StumbleGlobals.get_toolbar_outer_container();
+		
+		sibling.parentNode.insertBefore(splitter, sibling);
+	}
+	
+	// Determine whether the toolbar should be latched to the sidebar.
+	if (StumbleGlobals.is_toolbar_shared())
+	{
+		align_with_content = false;
+		splitter_first.collapsed = true;
+	}
+	else if (StumbleGlobals.ds.getValue("@toolbar-position") == "stumbleupon")
+	{
+		splitter_first.collapsed = sidebar_hidden;
+		if (! use_saved_latch_state)
+		{
+			if ((StumbleGlobals.sidebar_was_hidden == sidebar_hidden) && (StumbleGlobals.old_toolbar_x != toolbar_x))
+			{
+				var latch_to_sidebar = StumbleGlobals.ds.getValue("@latch-to-sidebar");
+				
+				if (latch_to_sidebar)
+					align_with_content = (toolbar_x >= (content_x - 20));
+				else
+					align_with_content = (first_flexbox.boxObject.width > 20);
+			}
+			StumbleGlobals.ds.setValue("@latch-to-sidebar", align_with_content);
+		}
+	}
+	else
+	{
+		align_with_content = false;
+		splitter_first.collapsed = true;
+	}
+
+	var new_width;
+	if (align_with_content)
+	{
+		// If latched, move the toolbar to match.
+	
+		if (sidebar_hidden)
+		{
+			new_width = 0;
+		}
+		else
+		{
+			// This hidden statement works around an apparent browser bug
+			// (ref: Firefox 2.0.0.2, Linux). -- JW
+			splitter_first.hidden = false;
+			new_width = content_x - first_flexbox.boxObject.x - splitter_first.boxObject.width;
+			if (new_width < 0)
+				new_width = 0;
+		}
+	}
+	else
+	{
+		new_width = 0;
+	}
+	first_flexbox.setAttribute("width", new_width + "px");
+	
+	var search = StumbleGlobals.get_element("stumbleglobals_field");
+	if (! search.collapsed)
+	{
+		var width = search.boxObject.width;
+		if (width != 0)
+		{
+			// The zero test above fixes an issue where the search box 
+			// width gets set to zero upon toggling visibility (ref: 
+			// Firefox 1.5, XP). -- JW
+			StumbleGlobals.ds.setValue("@search-width", width);
+		}
+	}
+	StumbleGlobals.old_toolbar_x = StumbleGlobals.get_element("stumbleglobals_stumble").boxObject.x;
+	StumbleGlobals.sidebar_was_hidden = sidebar_hidden;
+	StumbleGlobals.reflow_toolbar(11);
+	if (StumbleGlobals.bookmarks_sibling_loc)
+		StumbleGlobals.reflow_bookmarks_toolbar();
+	
+	} catch (e) { StumbleGlobals.log_error("REFRESH SPLITTERS", e, StumbleGlobals.ds.getValue("@toolbar-position"), StumbleGlobals.ds.getValue("@position-group")); }
+}
+	
+// handles the window resize event
+StumbleGlobals.handle_window_resize = function(event)
+{
+	var width = window.innerWidth;
+	
+	if (width != StumbleGlobals.resize_window_width)
+	{
+		StumbleGlobals.resize_window_width = width;
+		StumbleGlobals.reflow_toolbar(12);
+	}
+	else if (! StumbleGlobals.resize_window_dirty)
+	{
+		// handles window maximize case
+		StumbleGlobals.resize_window_dirty = true;
+		setTimeout(StumbleGlobals.handle_window_resize2, 500);
+	}
+
+	return true;
+}
+
+StumbleGlobals.handle_window_resize2 = function()
+{
+	if (! StumbleGlobals.resize_window_dirty)
+		return;
+	
+	StumbleGlobals.reflow_toolbar(14);
+	
+	StumbleGlobals.resize_window_dirty = false;
+}
+
+StumbleGlobals.reflow_toolbar = function(from)
+{
+	try {
+	if (! StumbleGlobals.gui_initialized)
+		return;	
+
+	// Nuke the flexbox.
+	var flexbox = StumbleGlobals.get_element("stumbleglobals_overflow_flexbox"); 
+	if (flexbox)
+		flexbox.parentNode.removeChild(flexbox);
+	
+	var container = StumbleGlobals.get_element("stumbleglobals_stumble").parentNode;
+	var outer_container = StumbleGlobals.get_toolbar_outer_container();
+	
+	if (container.id == "stumbleglobals_container")
+	{
+		container.setAttribute("flex", "1");
+	}
+	else
+	{
+		var hbox = StumbleGlobals.get_element("stumbleglobals_container");
+		if (hbox.hasAttribute("flex"))
+			hbox.removeAttribute("flex");
+	}
+
+	// If we're invisible, hide the outer_container.
+	if (! StumbleGlobals.ds.getValue("@toolbar-visible"))
+	{
+		outer_container.setAttribute("width", 0);
+		return;
+	}
+	
+	// Demenuify everything.
+	var popup = StumbleGlobals.get_element("stumbleglobals_overflow_popup"); 
+	while (popup.hasChildNodes())
+		StumbleGlobals.demenuify_toolbar_element(popup.firstChild);
+	
+	var sibling;
+	sibling = StumbleGlobals.get_element("stumbleglobals_stumble").parentNode.firstChild;
+	while (sibling)
+	{
+		sibling.hidden = false;
+		sibling = sibling.nextSibling;
+	}
+
+	var position = StumbleGlobals.ds.getValue("@toolbar-position");
+	if ((position == "gtbToolbar") && (! StumbleGlobals.reflow_delayed))
+	{
+		// If we're on the google toolbar, expand to max width, and allow
+		// the toolbar to reflow.
+		outer_container.setAttribute("width", 
+					container.lastChild.boxObject.x + 
+					container.lastChild.boxObject.width - 20 + "px");
+		StumbleGlobals.reflow_delayed = true;
+		setTimeout(StumbleGlobals.reflow_toolbar, 0, 13);
+		return;
+	}
+	StumbleGlobals.reflow_delayed = false;
+
+	var menu = StumbleGlobals.get_element("stumbleglobals_overflow_menu");
+	menu.collapsed = false;
+	var chevron_width = menu.boxObject.width;
+	menu.collapsed = true;
+	
+
+	// Compute available width.
+
+	var toolbar = StumbleGlobals.get_element(StumbleGlobals.get_parent_toolbar_id(container));
+	var available = window.innerWidth;
+	var regexp = new RegExp("^spring\\d+$");
+	var i;
+	var in_toolbar_elements = false;
+	var google_sibling_found = false;
+	var has_flexible_sibling = false;
+	var max;
+	for (i = 0; i < toolbar.childNodes.length; i++)
+	{
+		var sibling = toolbar.childNodes[i];
+		var pre = available;
+		var id = (sibling.id) ? sibling.id : "";
+		if (id == "stumbleglobals_splitter_first_flexbox")
+		{
+			in_toolbar_elements = true;
+		}
+		else if (in_toolbar_elements)
+		{
+//			if (StumbleGlobals.host.mac)
+//				sibling.hidden = false;
+			
+			if (id == "stumbleglobals_overflow_menu")
+			{
+				in_toolbar_elements = false;
+				max = sibling.boxObject.x + sibling.boxObject.width;
+			}
+		}
+		else if (id == "nav-bar-inner")
+		{
+			available -= 300;  // Seamonkey url bar
+		}
+		else if (id == "urlbar-container")
+		{
+			available -= 300;  // Firefox url bar
+		}
+		else if ((id == "search-container") && sibling.hasAttribute("flex"))
+		{
+			available -= 185;  // Firefox search box for 2.0+
+		}
+		else if (id == "statusbar-display")
+		{
+			available -= 185;  // Status bar content
+		}
+		else if ((id != "stumbleglobals_toolbaritem") && 
+					(id != "stumbleglobals_toolbar_container") &&
+					(id != "stumbleglobals_statusbar_container") &&
+					(id != "stumbleglobals_otherbar_container") &&
+					(id != "stumbleglobals_googlebar_container") &&
+					(id != "stumbleglobals_container") &&
+					(id != "bookmarks-ptf") &&        // Seamonkey bookmarks
+					(id != "personal-bookmarks") &&   //   Firefox bookmarks
+					(sibling.tagName != "tooltip") && // Seamonkey tooltips
+					(id.search(regexp) != 0))
+		{
+			if (sibling.boxObject.width != 0)
+				google_sibling_found = true;
+			available -= sibling.boxObject.width;
+		}
+	}
+	
+	if (StumbleGlobals.toolbar_justification == "right")
+	{
+		// If we're right-justified, limit to @right-justify-width.
+		var justify_width = StumbleGlobals.ds.getValue("@right-justify-width");
+
+		if (available > justify_width)
+			available = justify_width;
+	}
+	else if (position == "gtbToolbar")
+	{
+		var gtb_chevron = StumbleGlobals.get_element("gtbChevron");
+		if (google_sibling_found)
+		{
+			// Leave the previously set max width.
+			if (gtb_chevron)
+				gtb_chevron.collapsed = false;
+			return;
+		}
+		else
+		{
+			// Limit width to window width.
+			if (gtb_chevron)
+				gtb_chevron.collapsed = true;
+
+			available = window.innerWidth;
+			container.setAttribute("width", available + "px");
+		}
+	}
+	else
+	{
+		if (StumbleGlobals.ds.getValue("@position-group") == "first")
+		{
+			// Push companion elements to the right.
+			available = document.getElementById("main-window").boxObject.width;
+		}
+		
+//		if ((! max) && (StumbleGlobals.ds.getValue("@toolbar-position") != "stumbleupon"))
+		if (! max)
+		{
+			var box = StumbleGlobals.get_element("stumbleglobals_overflow_menu").boxObject;
+			max = box.x + box.width;
+		}
+		
+//		if ((outer_container.id != "status-bar") && 
+//					(StumbleGlobals.ds.getValue("@toolbar-position") != "stumbleupon"))
+		if (outer_container.id != "status-bar")
+		{
+			if (available > max)
+				available = max;
+			outer_container.setAttribute("width", available + "px");
+		}
+	}
+
+	// For each element that won't fit, move it into the overflow menu.
+	var overflowed = false;
+	var first = true;
+	in_toolbar_elements = false;
+	for (i = container.childNodes.length - 2; i >= 0; i--)
+	{
+		var item = container.childNodes[i];
+
+		var consumed = item.boxObject.x - container.boxObject.x + 
+					item.boxObject.width + ((first) ? 0 : chevron_width);
+		
+		first = false;
+		
+		var id = (item.id) ? item.id : "";
+		
+		if ((id == "stumbleglobals_overflow_menu") || (id == "stumbleglobals_site-count-box"))
+		{
+			in_toolbar_elements = true;
+			if (id == "stumbleglobals_overflow_menu")
+				continue;
+		}
+		if (! in_toolbar_elements)
+		{
+			continue;
+		}
+		else if ((consumed > available) && (id != "stumbleglobals_thumbdown"))
+		{
+			overflowed = true;
+			StumbleGlobals.menuify_toolbar_element(item);
+		}
+		else
+		{
+			if (id.indexOf("stumbleglobals_separator") == 0)
+				StumbleGlobals.menuify_toolbar_element(item);
+			break;
+		}
+	}
+	
+	if (overflowed)
+	{
+		menu.collapsed = false;
+		StumbleGlobals.cleanup_overflow_menuseparators();
+	}
+	StumbleGlobals.cleanup_overflow_flexbox();
+
+	sibling = StumbleGlobals.get_element("stumbleglobals_stumble").parentNode.firstChild;
+	while (sibling)
+	{
+		sibling.hidden = sibling.collapsed;
+		sibling = sibling.nextSibling;
+	}
+	
+	setTimeout(StumbleGlobals.refresh_info, 0);
+	
+	if (from != "retry")
+		setTimeout(StumbleGlobals.verify_reflow, 500);
+	
+	}
+	catch (e) {
+		var toolbar_position = StumbleGlobals.ds.getValue("@toolbar-position");
+		var position_group = StumbleGlobals.ds.getValue("@position-group");
+		if ((toolbar_position == "stumbleupon") && (position_group == "first"))
+		{
+			StumbleGlobals.log_error("REFLOW ERROR", e, from);
+		}
+		else
+		{
+			StumbleGlobals.log_error("REFLOW FAILSAFE", e, from, toolbar_position, position_group);
+			StumbleGlobals.ds.setValue("@toolbar-position", "stumbleupon");
+			StumbleGlobals.ds.setValue("@position-group", "first");
+		}
+	}
+	
+}
+
+StumbleGlobals.reflow_bookmarks_toolbar = function()
+{
+	if (StumbleGlobals.get_element("bookmarks-ptf") && window.BMSVC
+			&& ((typeof (window.BMSVC.getBookmarksToolbarFolder)) == "function")
+			&& window.BookmarksToolbarRDFObserver)
+	{
+		// ref: Firefox 2.0
+		var bt = StumbleGlobals.get_element("bookmarks-ptf");
+		var btf = BMSVC.getBookmarksToolbarFolder().Value;
+		var btchevron = document.getElementById("bookmarks-chevron");
+		bt.ref = btf;
+		btchevron.ref = btf;
+		// no uniqueness is guaranteed, so we have to remove first
+		try {
+			bt.database.RemoveObserver(BookmarksToolbarRDFObserver);
+		} catch (ex) {
+			// ignore
+		}
+		bt.database.AddObserver(BookmarksToolbarRDFObserver);
+		bt.builder.rebuild();
+		btchevron.builder.rebuild();
+
+		// fake a resize; this function takes care of flowing bookmarks
+		// from the bar to the overflow item
+		BookmarksToolbar.resizeFunc(null);
+	}
+	else if (StumbleGlobals.get_element("bookmarksBarContent")
+		&& (typeof (StumbleGlobals.get_element("bookmarksBarContent").updateChevron) == "function"))
+			
+	{
+		// ref: Firefox 3.6rc
+		var bar_content = StumbleGlobals.get_element("bookmarksBarContent");
+		bar_content.updateChevron();
+	}
+}	
+
+StumbleGlobals.verify_reflow = function()
+{
+	//!!! This is very primitive; it only helps when the stumbleupon 
+	// elements are the last time on the bar.  This is the most common
+	// case.  Eventually, we have to discover why it's necessary at all
+	// an why it's off by 2 px every time.
+	var box = StumbleGlobals.get_element("stumbleglobals_overflow_menu").boxObject;
+	
+	if (((box.x + box.width) - window.innerWidth) > 3)
+	{
+		setTimeout(StumbleGlobals.reflow_toolbar, 0, "retry");
+	}
+}
+
+StumbleGlobals.cleanup_toolbox = function(force, update_urlbar)
+{
+	var position = StumbleGlobals.ds.getValue("@toolbar-position");
+
+	if ((force || (position == "gtbToolbar")) && 
+				((typeof GTB_GoogleToolbarOverlay) != "undefined") && 
+				GTB_GoogleToolbarOverlay.chevron && 
+				((typeof GTB_GoogleToolbarOverlay.chevron.doResize) == 
+				"function"))
+	{
+		try {
+			GTB_GoogleToolbarOverlay.chevron.doResize();
+		} catch (e) {};
+	}
+	
+	if ((force || (position == "yahoo-toolbar")) &&
+				((typeof yahooToolbarOverflowDelay) == "function"))
+	{
+		try {
+			yahooToolbarOverflowDelay();
+		} catch (e) {};
+	}
+	
+	try {
+		StumbleGlobals.reflow_bookmarks_toolbar();
+	} catch (e) { StumbleGlobals.log("BOOKMARKS CLEANUP", e); }
+	
+	if ((force || (position == "prefbar")) &&
+				((typeof prefbarUpdateToolbar) == "function"))
+	{
+		setTimeout(prefbarUpdateToolbar, 0);
+	}
+
+	if (update_urlbar)
+	{
+		try {
+		// Update the urlbar
+			var url = getWebNavigation().currentURI.spec;
+			if (window.gURLBar)
+			{
+				if (url == "about:blank")
+				{
+					gURLBar.value = "";
+					SetPageProxyState("invalid");
+				}
+				else
+				{
+					gURLBar.value = url;
+					SetPageProxyState("valid");
+				}
+				FeedHandler.updateFeeds();
+			}
+		} catch (e) {}
+	}
+}
+
+// used by shorten_toolbar to move an element from the toolbar to the
+// overflow menu
+StumbleGlobals.menuify_toolbar_element = function(element)
+{
+	var popup = StumbleGlobals.get_element("stumbleglobals_overflow_popup");
+	
+	var new_element;
+	if ((element.id == "stumbleglobals_referral_menu") || (element.id == "stumbleglobals_stumble_menu"))
+	{
+		new_element = element;
+		new_element.label = new_element.getAttribute("showlabel");
+	}
+	else if (element.id == "stumbleglobals_mode")
+	{
+		new_element = element;
+		StumbleGlobals.get_element("stumbleglobals_mode_label").collapsed = true;
+	}
+	else if (element.id == "stumbleglobals_field")
+	{
+		new_element = element;
+		new_element.setAttribute("savedhidden", new_element.collapsed);
+		new_element.collapsed = true;
+	}
+	else if (element.tagName == "splitter")
+	{
+		new_element = element.cloneNode(true);
+		new_element.setAttribute("savedhidden", new_element.collapsed);
+		new_element.collapsed = true;
+	}
+	else if ((element.tagName == "toolbarbutton") && element.hasAttribute("showlabel"))
+	{
+		new_element = element.cloneNode(true);
+		new_element.label = new_element.getAttribute("showlabel");
+	}
+	else if (element.id.indexOf("stumbleglobals_separator") == 0)
+	{
+		new_element = document.createElement("menuseparator");
+		new_element.id = element.id;
+		new_element.collapsed = element.collapsed;
+	}
+	else
+	{
+		new_element = element.cloneNode(true);
+//		new_element.hidden = element.collapsed;
+//		new_element.collapsed = false;
+	}
+
+	element.parentNode.removeChild(element);
+
+	if (new_element.className == "su-showtext")
+		new_element.className =  "su-showtext-menuified";
+
+	else if (new_element.className == "su-hidetext")
+		new_element.className = "su-hidetext-menuified";
+	
+	new_element.hidden = new_element.collapsed;
+	
+	popup.insertBefore(new_element, popup.firstChild);
+}
+
+// used by lengthen_toolbar to move an element from the overflow menu
+// to the toolbar
+StumbleGlobals.demenuify_toolbar_element = function(element)
+{
+	var new_element;
+
+	if (element.id == "stumbleglobals_field")
+	{
+		new_element = element;
+		new_element.collapsed = (new_element.getAttribute("savedhidden") == "true");
+		new_element.removeAttribute("savedhidden");
+	}
+	else if (element.id == "stumbleglobals_mode")
+	{
+		new_element = element;
+		StumbleGlobals.get_element("stumbleglobals_mode_label").collapsed = (StumbleGlobals.ds.getValue("$icons") == "icons-only");
+	}
+	else if (element.tagName == "splitter")
+	{
+		new_element = element.cloneNode(true);
+		new_element.collapsed = (new_element.getAttribute("savedhidden") == "true");
+		new_element.removeAttribute("savedhidden");
+	}
+	else if (element.id.indexOf("stumbleglobals_separator") == 0)
+	{
+		// These DIVs fix the bug where spurious separators were appearing
+		// after the user Customizes the toolbar area in Firefox.
+		// Analysis:
+		// Customize stores element ids in localstore.rdf, but it doesn't
+		// save the ids of separators (since they have identical 
+		// rendering).  Upon restart, ids duplicated elsewhere by our 
+		// toolbar elements are ignored, but the unlabeled separators
+		// remain where Customize recorded them to be.  Workaround is to
+		// wrap our separators so that an id will be recorded. -- JW
+
+		new_element = document.createElement("div");
+		new_element.id = element.id;
+		var tmp = document.createElement("toolbarseparator");
+		new_element.appendChild(tmp);
+
+		if (element.hasAttribute("savedhidden"))
+			new_element.collapsed = (element.getAttribute("savedhidden") == "true");
+		else
+			new_element.collapsed = element.collapsed;
+	}
+	else if (element.tagName == "toolbarbutton")
+	{
+		new_element = element.cloneNode(true);
+		if (! StumbleGlobals.get_label_visibility(element.id, false))
+			new_element.label = "";
+	}
+	else
+	{
+		new_element = element.cloneNode(true);
+//		new_element.collapsed = element.hidden;
+//		new_element.hidden = false;
+	}
+	
+	var next_sibling = StumbleGlobals.get_element("stumbleglobals_overflow_menu");
+
+	if (next_sibling.previousSibling.id == "stumbleglobals_overflow_flexbox")
+	{
+		// Skip the flexbox.
+		next_sibling = next_sibling.previousSibling;
+	}
+
+	if (new_element.hasAttribute("savedwidth"))
+		new_element.removeAttribute("savedwidth");
+
+	element.parentNode.removeChild(element);
+	
+	next_sibling.parentNode.insertBefore(new_element, next_sibling);
+	
+	//!!! This may be causing a reflow bug; new width may not be
+	//    set soon enough for it to be used in the reflow calculation.
+	//    -- JW
+	if (new_element.className == "su-showtext-menuified")
+		new_element.className = "su-showtext";
+
+	if (new_element.className == "su-hidetext-menuified")
+		new_element.className = "su-hidetext";
+}
+
+// used by refresh_toolbar_gated() to add or destroy the overflow 
+// flexbox as required
+StumbleGlobals.cleanup_overflow_flexbox = function()
+{
+	var menu = StumbleGlobals.get_element("stumbleglobals_overflow_menu");
+	// The overflow flexbox right-justifies the overflow menu when the 
+	// toolbar elements are in the stumbleupon toolbar or are 
+	// right-justified. -- JW
+	if (((menu.parentNode.id == "stumbleglobals_container") || 
+				(menu.parentNode.id == "stumbleglobals_toolbar_container") || 
+				(menu.parentNode.id == "stumbleglobals_statusbar_container") || 
+				(menu.parentNode.id == "stumbleglobals_otherbar_container") || 
+				(menu.parentNode.id == "stumbleglobals_googlebar_container")) && 
+				(menu.previousSibling.id != "stumbleglobals_overflow_flexbox"))
+	{
+		var flexbox = document.createElement("vbox");
+		flexbox.setAttribute("id", "stumbleglobals_overflow_flexbox");
+		flexbox.setAttribute("flex", "1");
+
+		menu.parentNode.insertBefore(flexbox, menu);
+	}
+	else if ((menu.parentNode.id != "stumbleglobals_container") && 
+				(menu.parentNode.id != "stumbleglobals_toolbar_container") && 
+				(menu.parentNode.id != "stumbleglobals_statusbar_container") &&
+				(menu.parentNode.id != "stumbleglobals_otherbar_container") &&
+				(menu.parentNode.id != "stumbleglobals_googlebar_container") &&
+				(menu.previousSibling.id == "stumbleglobals_overflow_flexbox"))
+	{
+		menu.parentNode.removeChild(menu.previousSibling);
+	}
+}
+
+// used by refresh_toolbar_gated() to make sure the top item in the 
+// overflow menu isn't a menuseparator
+StumbleGlobals.cleanup_overflow_menuseparators = function()
+{
+	try {
+	var sibling = StumbleGlobals.get_element("stumbleglobals_overflow_popup").firstChild;
+
+	var before_first_visible_element = true;
+
+	while (sibling)
+	{
+		if (sibling.collapsed)
+		{
+			sibling = sibling.nextSibling;
+			continue;
+		}
+		else if (sibling.tagName == "menuseparator")
+		{
+			if (before_first_visible_element)
+			{
+				before_first_visible_element = false;
+				sibling.setAttribute("savedhidden", "false");
+				sibling.collapsed = true;
+			}
+			else
+			{
+				if (sibling.hasAttribute("savedhidden"))
+				{
+					sibling.collapsed = (sibling.getAttribute("savedhidden") == "true");
+					sibling.removeAttribute("savedhidden");
+				}
+			}
+		}
+		else
+		{
+			before_first_visible_element = false;
+		}
+		sibling = sibling.nextSibling;
+	}
+	} catch (e) { StumbleGlobals.log_error("CLEANUP MENUSEPARATORS", e, StumbleGlobals.ds.getValue("@toolbar-position"), StumbleGlobals.ds.getValue("@position-group")); }
+}
+
+// handles the popuphiding event for the overflow menu popup; sets a
+// flag that delays toolbar refresh
+StumbleGlobals.handle_popupshowing = function(event)
+{
+	switch (event.target.id)
+	{
+		case "stumbleglobals_referred_popup":  StumbleGlobals.referred_popup_open = true; break;
+		case "stumbleglobals_referral_popup":
+			var current_page = StumbleGlobals.get_browser_url();		
+			if(!current_page.match(/^https?\:|^ftp\:/))
+			{	
+				event.preventDefault();
+				alert("Sorry, sharing of this page is not allowed");
+				return;
+			}
+			
+			StumbleGlobals.referral_popup_open = true;
+			break;
+		case "stumbleglobals_mode_more_popup": StumbleGlobals.mode_more_popup_open = true; break;
+		case "stumbleglobals_overflow_popup":  StumbleGlobals.overflow_popup_open = true; break;
+	}
+}
+
+// handles the popuphidden event for the overflow menu popup; clears
+// a flag that otherwise delays toolbar refresh
+StumbleGlobals.handle_popuphidden = function(event)
+{
+	switch (event.target.id)
+	{
+		case "stumbleglobals_referred_popup":
+			StumbleGlobals.referred_popup_open = false;
+			break;
+		case "stumbleglobals_referral_popup":
+			StumbleGlobals.referral_popup_open = false;
+			// Refresh it immediately because it has checked items
+			window.setTimeout(StumbleGlobals.update_referral_menu2, 0);
+			break;
+		case "stumbleglobals_mode_more_popup":
+			StumbleGlobals.mode_more_popup_open = false;
+			StumbleGlobals.refresh_dyn_channels();
+			break;
+		case "stumbleglobals_overflow_popup":
+			StumbleGlobals.overflow_popup_open = false;
+			break;
+	}
+}
+
+StumbleGlobals.show_search_dialog = function(new_tab)
+{
+	var detail = new Object();
+	detail.query = "";
+	detail.query_default = StumbleGlobals.get_element("stumbleglobals_searchbox").value;
+	detail.new_tab = new_tab;
+	if (detail.query_default == StumbleGlobals.tag_instructions)
+		detail.query_default = "";
+
+	window.openDialog(
+				"chrome://stumbleupon/content/searchDialog.xul",
+				"",
+				"chrome,dialog,centerscreen,dependent",
+				detail);
+}
+
+StumbleGlobals.search_dialog_accept = function(detail)
+{
+	StumbleGlobals.stumble_in_tag(StumbleGlobals.trim(detail.query), detail.new_tab);
+}
+
+// old search implementations
+//var theurl = "http://www.google.ca/search?q=" + escape(query);
+//var theurl = "http://www.google.com/custom?q=" + escape(query) + "&sa=Search&client=pub-1501742633103790&forid=1&channel=3900634926&cof=" + escape("GFNT:#7777cc;GL:0;VLC:663399;AH:left;BGC:white;LC:#0000FF;ALC:#0000FF;T:000000;FORID:1;");
+//var theurl = "http://search.stumbleupon.com/?q=" + escape(query);
+
+
+StumbleGlobals.stumble_in_tag = function(tag, new_tab)
+{
+	if (tag == "")
+		return;
+
+	// put it in the box
+	StumbleGlobals.get_element("stumbleglobals_searchbox").value = tag;
+	StumbleGlobals.get_element("stumbleglobals_searchbox").removeAttribute("mode");
+	StumbleGlobals.old_search = tag;
+	StumbleGlobals.last_typed_tag = 0;
+	StumbleGlobals.visited_searchbox = 1;
+
+	// select and do it
+	StumbleGlobals.select_topic('TAG_' + tag, tag, new_tab);
+	
+	StumbleGlobals.previous_query_category = "TAG_" + tag;
+	
+	StumbleGlobals.queries.unshift(tag);
+	
+	var i;
+	for (i = 1; i < StumbleGlobals.queries.length; i++)
+	{
+		if (StumbleGlobals.queries[i] == tag)
+		{
+			// nuke duplicate
+			StumbleGlobals.queries.splice(i, 1);
+			break;
+		}
+	}
+	
+	StumbleGlobals.store_queries();
+}
+
+StumbleGlobals.skip_stumble = function(context)
+{
+//	StumbleGlobals.dd("skip");
+	// losing connectivity could cause many skips, so we stop at 3
+	context.skip_count++;
+	
+	if (context.skip_count >= 3)
+		return;
+	
+	StumbleGlobals.get_unseen_url(
+			context.user_cat,
+			1,
+			function(unseen, context) { window.stumble_done(unseen, context); },
+			context);
+}
+
+StumbleGlobals.is_404_status = function(status)
+{
+	if (status == null)
+		return false;
+	
+	switch (status)
+	{
+		case 401:
+		case 403:
+		case 404:
+		case 0:
+			return true;
+	}
+	return false;
+}
+
+StumbleGlobals.StumbleProgressListener = function (url_detail, context)
+{
+	this.url_detail = url_detail;
+	this.context = context;
+	this.skipping_stumble = false;
+}
+
+StumbleGlobals.StumbleProgressListener.prototype =
+{
+	QueryInterface: function (iid)
+	{
+		if (!iid.equals(Components.interfaces.nsIWebProgressListener) &&
+				!iid.equals(Components.interfaces.nsISupportsWeakReference) && // not implemented
+				!iid.equals(Components.interfaces.nsISupports))
+		{
+			throw Components.results.NS_ERROR_NO_INTERFACE;
+		}
+		
+		return this;
+	},
+	
+	onStateChange: function (aWebProgress, aRequest, aStateFlags, aStatus)
+	{
+		const nsIWPL = Components.interfaces.nsIWebProgressListener;
+		var original_url;
+		// do a try, we don't want to mess with state change...
+		try {
+			if (aWebProgress.DOMWindow != aWebProgress.DOMWindow.top)
+				return;
+			
+			aRequest.QueryInterface(Components.interfaces.nsIChannel);
+			
+			original_url = aRequest.originalURI.asciiSpec;
+			
+			if (original_url != this.url_detail.url)
+				return;
+			
+		} catch (e) { return; } // ignore error accessing DOMWindow.top
+			
+		try {
+			if (aStateFlags & nsIWPL.STATE_STOP)
+			{			
+				try {
+					var channel = this.context.target_browser.docShell.currentDocumentChannel;
+					var status = channel.responseStatus;
+					if (StumbleGlobals.is_404_status(status))
+					{
+						if ((this.url_detail.cluster_type != 3) &&
+								(this.url_detail.cluster_type != 4))
+						{
+							this.skipping_stumble = true;
+							setTimeout(StumbleGlobals.skip_stumble, 0, this.context);
+						}
+						StumbleGlobals.report_404(this.url_detail.url, status);
+					}
+				} catch (e) {}
+				this.destroy();
+				return;
+			}
+			
+			if (this.skipping_stumble)
+				return;
+			
+			var redirect_url = aRequest.URI.asciiSpec;
+			
+			if (this.url_detail.redirect_url == redirect_url)
+				return;
+			
+			this.url_detail.redirect_url = redirect_url;
+			
+			StumbleGlobals.ds.define("url:url_detail", redirect_url, this.url_detail);
+			
+			var domain = StumbleGlobals.get_tld(redirect_url);
+			
+			if ((this.url_detail.cluster_type != 4) && StumbleGlobals.is_domain_blocked(domain))
+			{
+				this.skipping_stumble = true;
+				setTimeout(StumbleGlobals.skip_stumble, 0, this.context);
+			}
+			else if (domain != this.url_detail.tld)
+			{
+				if ((this.url_detail.cluster_type != 3) && (this.url_detail.cluster_type != 4))
+				{
+					this.skipping_stumble = true;
+					setTimeout(StumbleGlobals.skip_stumble, 0, this.context);
+				}
+				StumbleGlobals.report_redirect(original_url, 302, redirect_url);
+			}
+		} catch (e) { StumbleGlobals.log_error("FILTER ERROR", e); }
+		
+	},
+	
+	destroy: function ()
+	{
+		if (! this.context)
+			return;
+
+		this.context.target_browser.removeProgressListener(this);
+		this.context = null;
+		this.url_detail = null;
+	},
+	
+	onProgressChange: function (aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {},
+	
+	// see: http://developer.mozilla.org/en/docs/nsIDownloadProgressListener#onLocationChange.28.29
+	onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {},
+	
+	onSecurityChange: function (aWebProgress, aRequest, aState) {},
+	
+	// required only for tabbrowser?
+	onLinkIconAvailable: function (aBrowser, aHref) {},
+	
+	// required only for tabbrowser?
+	// also: http://developer.mozilla.org/en/docs/nsIDownloadProgressListener#onLocationChange.28.29
+	onLocationChange: function (aWebProgress, aRequest, aLocation) {}
+}
+
+StumbleGlobals.downloadProgressListener = 
+{
+	QueryInterface : function (iid)
+	{
+		if (!iid.equals(Components.interfaces.nsIWebProgressListener) &&
+			!iid.equals(Components.interfaces.nsISupportsWeakReference) && // not implemented
+			!iid.equals(Components.interfaces.nsISupports))
+		{
+			throw Components.results.NS_ERROR_NO_INTERFACE;
+		}
+
+		return this;
+	},
+
+	onLocationChange : function(aWebProgress, aRequest, aLocation)
+	{
+		// Supposedly removed in ff3, but it's still being called by
+		// ff3 tabbrowser.
+		// 
+		// See:
+		// http://developer.mozilla.org/en/docs/nsIDownloadProgressListener#onLocationChange.28.29
+		var domWindow = aWebProgress.DOMWindow;
+	
+		// Update urlbar only if a new page was loaded on the primary content area
+		// this helps us weed out frames loading...
+		if (domWindow == domWindow.top && aLocation != null)
+			StumbleGlobals.refresh_pagemeta(false, 1);
+	},
+	
+	onProgressChange : function (aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {},
+	
+	onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus)
+	{
+		const nsIWPL = Components.interfaces.nsIWebProgressListener;
+		
+		// do a try, we don't want to mess with state change...
+		try {
+
+			if (StumbleGlobals.stumbleid == 0)
+				return;
+			
+			if (aWebProgress.DOMWindow != aWebProgress.DOMWindow.top)
+				return;
+		} catch (e) { return; }
+		
+		if ((aStateFlags & nsIWPL.STATE_START) && (aStateFlags & nsIWPL.STATE_IS_REQUEST))
+		{
+			try {
+				StumbleGlobals.prefetcher.pause();
+			} catch (e) { StumbleGlobals.log_error("PREFETCHER 2", e); }
+			
+			try {
+				aRequest.QueryInterface(Components.interfaces.nsIChannel);
+			}
+			catch (e) { return; }
+			
+			var redirect_url = aRequest.URI.asciiSpec;
+			var original_url = aRequest.originalURI.asciiSpec;
+			
+			if (original_url == StumbleGlobals.stumbled_url)
+				StumbleGlobals.redirect_url = redirect_url;
+						
+			// make sure url is beginning of request!!!!
+			if (original_url.indexOf(StumbleGlobals.base_url + "stumble/") == 0)
+			{
+				// pull out the tag...
+				var spliturl = original_url.split("/");
+				if (spliturl.length >= 5)
+				{
+					var tag = spliturl[4];
+					var new_url = StumbleGlobals.get_browser_url(null, true);
+					
+					// make sure new_url is "http://www.stumbleupon.com/explore.php"
+					if (new_url.indexOf(StumbleGlobals.base_url + "explore.php") == 0)
+					{
+						aRequest.cancel(0);
+										
+						StumbleGlobals.unfocus_searchbox(); 
+						
+						var searchtag = (StumbleGlobals.ds.isThruDomain(tag)) ? "" : tag;
+
+						// put it in the box
+						StumbleGlobals.get_element("stumbleglobals_searchbox").value = searchtag;
+						StumbleGlobals.get_element("stumbleglobals_searchbox").removeAttribute("mode");
+						StumbleGlobals.old_search = searchtag;
+						StumbleGlobals.last_typed_tag = 0;
+						StumbleGlobals.visited_searchbox = 1;
+
+						// select and do it
+						setTimeout(StumbleGlobals.select_topic, 100, "TAG_" + tag, tag, false);
+					}
+				}
+			}
+			else if (original_url.indexOf(StumbleGlobals.base_url + "through.php?") == 0)
+			{
+				aRequest.cancel(0);
+			}
+		}
+		else if ((aStateFlags & nsIWPL.STATE_STOP) && (StumbleGlobals.stumble_action_count > 0))
+		{
+// Note: The following causes execution to stop without throwing an
+// error (ref: FF3, linux): 
+//				if (aWebProgress)
+//					aWebProgress.StumbleGlobals.loaded = true;
+			try {
+				if (StumbleGlobals.ds.getValue("$prefetch")	)
+					StumbleGlobals.prefetcher.start();
+			} catch (e) { StumbleGlobals.log_error("PREFETCHER 3", e); }
+		}
+
+		
+	},
+
+	onLinkIconAvailable : function(aBrowser, aHref)
+	{},
+
+	onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
+	{
+		try {
+			// Removed in ff3  See:
+			// http://developer.mozilla.org/en/docs/nsIDownloadProgressListener#onStatusChange.28.29		if (aRequest)
+			aRequest.QueryInterface(Components.interfaces.nsIChannel);
+			var original_url = aRequest.originalURI.asciiSpec;
+			
+			// auto-stumble, done in click
+			if (original_url.indexOf(StumbleGlobals.base_url + "through.php?") != 0)
+				aRequest.cancel(0);
+		} catch (e) {}
+	},
+
+	onSecurityChange : function(aWebProgress, aRequest, aState)
+	{}
+};
+
+StumbleGlobals.http_observer = 
+{
+	// This is the observerService's observe listener.
+	observe: function(aSubject, aTopic, aData) 
+	{
+		if (aTopic == 'http-on-modify-request') 
+		{
+			//!!! sometimes we get "Components is not defined" here? (why?)
+			if (typeof(Components) != "undefined")
+			{
+				aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
+				this.onModifyRequest(aSubject);
+			}
+		} 
+		else if (aTopic == 'http-on-examine-response') 
+		{
+			//!!! sometimes we get "Components is not defined" here? (why?)
+			if (typeof(Components) != "undefined")
+			{
+				aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
+				this.onExamineResponse(aSubject);
+			}
+		}
+		else if (aTopic == 'http-on-examine-cached-response')
+		{
+			//!!! sometimes we get "Components is not defined" here? (why?)
+			if (typeof(Components) != "undefined")
+			{
+				aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
+				this.onExamineCachedResponse(aSubject);
+			}
+		}
+		
+	},
+
+	onModifyRequest : function (oHttp)
+	{
+		var has_version = false;
+		if (StumbleGlobals.is_server_page(oHttp.URI.asciiSpec, ""))
+		{
+			has_version = true;
+			oHttp.setRequestHeader("X-SU-Version", StumbleGlobals.useragent, 0);
+			if(StumbleGlobals.stumbleid == 0)
+			{
+				var clientid = StumbleGlobals.ds.getValue("@clientid");
+				if(clientid)
+				{
+					oHttp.setRequestHeader("X-SU-ClientID", clientid, 0);
+				}
+	
+				var first = StumbleGlobals.ds.getValue("@first_version");
+				if(first != "")
+				{
+					first += " " + StumbleGlobals.ds.getValue("@first_run_time");
+					oHttp.setRequestHeader("X-SU-First", first, 0);
+				}
+				var nowUtc = StumbleGlobals.get_time_s();
+				oHttp.setRequestHeader("X-SU-Client-Time", nowUtc, 0);
+			}
+		}
+
+		if (! StumbleGlobals.is_auth_allowed(oHttp.URI.asciiSpec))
+			return;
+	
+
+		// send authentication headers
+		if (StumbleGlobals.stumbleid == 0)
+		{
+			if (StumbleGlobals.host && StumbleGlobals.host.dist)
+			{
+				if (! has_version)
+					oHttp.setRequestHeader("X-SU-Version", StumbleGlobals.useragent, 0);
+				oHttp.setRequestHeader('X-SU-Dist', StumbleGlobals.host.dist, 0);
+			}
+			return;
+		}
+		
+		var url = oHttp.URI.asciiSpec;
+		var sldetail = StumbleGlobals.ds.getValue("#sldetail");
+		if (sldetail && (url == sldetail.target))
+		{
+			oHttp.setRequestHeader('X-SU-Sldomain', sldetail.domain, 0);
+			oHttp.setRequestHeader('X-SU-Sltermcount', sldetail.term_count + "", 0);
+			oHttp.setRequestHeader('X-SU-Slfirstpage', ((sldetail.is_first_page) ? 1 : 0) + "", 0);
+			StumbleGlobals.ds.setValue("#sldetail", null);
+		}
+		
+		url = url.toLowerCase();
+		
+		// 0 = do not merge header with old headers, replace them
+		oHttp.setRequestHeader('X-SU-Username', StumbleGlobals.stumbleid, 0);
+		oHttp.setRequestHeader('X-SU-Password', StumbleGlobals.stumblepass, 0);
+		if (! has_version)
+			oHttp.setRequestHeader("X-SU-Version", StumbleGlobals.useragent, 0);
+		if (StumbleGlobals.host && StumbleGlobals.host.dist)
+			oHttp.setRequestHeader('X-SU-Dist', StumbleGlobals.host.dist, 0);
+		
+		if (url.indexOf(StumbleGlobals.serverhttp + "find_friends.php") != -1)
+		{
+			if (url.indexOf("pre3=") != -1)
+			{
+				StumbleGlobals.ds.setValue("#find_friends_optin", true);
+				StumbleGlobals.ds.setValue("#find_friends_pre", "socialsearch");
+			}
+			else if (url.indexOf("pre=facebook") != -1)
+			{
+				StumbleGlobals.ds.setValue("#find_friends_pre", "facebook");
+			}
+		}
+		
+		if (oHttp.requestMethod != "POST")
+			return;
+		
+		if (url.indexOf(StumbleGlobals.serverhttp + "thanks.php") == 0)
+		{
+			try {
+				var str = StumbleGlobals.get_debug_header();
+				if (str)
+					oHttp.setRequestHeader("X-SU-Debug", str, 0);
+			} catch (e) { StumbleGlobals.log_error("DEBUG HEADER", e); }
+			return;
+		}
+		
+		var bug_groups = ["stumbleupon", "help", "bugs", "beta", "firefox", "ie" ];
+		var i;
+		for (i = 0; i < bug_groups.length; i++)
+		{
+			if (url.indexOf("http://" + bug_groups[i] + ".group." + 
+						StumbleGlobals.servername + "/forum/") == 0)
+			{
+				try {
+					var str = StumbleGlobals.get_debug_header();
+					if (str)
+						oHttp.setRequestHeader("X-SU-Debug", str, 0);
+				} catch (e) { StumbleGlobals.log_error("DEBUG HEADER", e); }
+				break;
+			}
+		}
+	},
+	
+	onExamineResponse: function (oHttp)
+	{
+		// Notify the request tracker
+		if(oHttp.originalURI.asciiSpec)
+		{
+			StumbleGlobals.requestTracker.trackEvent(oHttp.originalURI.asciiSpec, "response");
+		}
+		
+		// And then handle it
+		this._onExamineResponse(oHttp);
+	},
+	
+	onExamineCachedResponse : function (oHttp)
+	{
+		// Notify the request tracker
+		if(oHttp.originalURI.asciiSpec)
+			StumbleGlobals.requestTracker.trackEvent(oHttp.originalURI.asciiSpec, "cachedResponse");
+		
+		// Do the default handling
+		this._onExamineResponse(oHttp);
+	},
+
+	_onExamineResponse : function (oHttp)
+	{
+		if (StumbleGlobals.stumbleid == 0)
+			return;
+		
+		//!!! grab oHttp.loadFlags and look for LOAD_FLAGS_IS_REFRESH to grab meta refreshes?
+		var redirect_url = oHttp.URI.asciiSpec;
+		var original_url = oHttp.originalURI.asciiSpec;
+		
+		if (StumbleGlobals.log_mimetype)
+			StumbleGlobals.log("mimetype", original_url, redirect_url, oHttp.contentType);
+		
+//		if (original_url == "http://media.tumblr.com/mlsyKxOF8fzc9kd1zQ37q9b8o1_500.jpg")
+//			StumbleGlobals.dd("response", StumbleGlobals.stumbled_url, original_url, redirect_url);
+		
+		var status = oHttp.responseStatus;
+		if (StumbleGlobals.stumbled_url != "" && original_url == StumbleGlobals.stumbled_url && original_url != redirect_url)
+		{
+//			StumbleGlobals.dd("set", 1, originval_url, redirect_url);
+			// we have a stumble that has redirected to another page
+			// NOTE: this will fire once for each redirect in a chain of redirects
+			StumbleGlobals.stumbled_redirect = redirect_url;
+			// StumbleGlobals.dp("STUMBLE REDIRECT", "ORIGINAL" + StumbleGlobals.stumbled_url, "REDIRECT " + StumbleGlobals.stumbled_redirect, "STATUS " + status);
+		}
+		
+//		if (original_url == "http://media.tumblr.com/mlsyKxOF8fzc9kd1zQ37q9b8o1_500.jpg")
+//			StumbleGlobals.dd("after", StumbleGlobals.stumbled_url, original_url, redirect_url);
+		
+		if (!StumbleGlobals.is_server_page(original_url, ""))
+			return;
+		
+		if (status != 200)
+			return;
+		
+		if ((original_url.indexOf(StumbleGlobals.serverhttp + "user.php?friend=") == 0) ||
+					(original_url.indexOf(StumbleGlobals.serverhttp + "user.php?removefriend=") == 0))
+		{
+			setTimeout(StumbleGlobals.get_friends, 0);
+		}
+		else if (original_url.match(/^http:\/\/[^\/]*\/badge\/badge_controller\.php\?a=thumbupurl&u=([^&]+)/))
+		{
+			var badge_match = original_url.match(/^http:\/\/[^\/]*\/badge\/badge_controller\.php\?a=thumbupurl&u=([^&]+)/);			
+			if (badge_match.length < 2)
+				return;
+			var url = decodeURIComponent(badge_match[1]);
+			
+			var url_detail = StumbleGlobals.ds.lookup("url:url_detail", url);
+			if (url_detail)
+			{
+				url_detail.rating = 1;
+				StumbleGlobals.refresh_pagemeta(12);
+			}
+			StumbleGlobals.rate_getmeta(url, true);
+		}
+	}
+};
+
+StumbleGlobals.check_enable_default_toggle_button = function()
+{
+	// We only have a single bit in the ab_bits for now, a 1 or 0 for the toggle button
+	var ab_bits = 0;
+	
+	if(!StumbleGlobals.ds.isPrefDefined("@ab_bits"))
+	{
+		if(StumbleGlobals.new_install)
+		{
+			// On new installs we force the toggle button 10% of the time
+			var n = Math.floor(10 * Math.random());
+			ab_bits = (n == 1) ? 1 : 0;
+			
+			if(ab_bits)
+			{
+				// Set an indicator so we know we forced this so we don't do it again
+				StumbleGlobals.ds.setValue("@did_force_toggle", true);
+				StumbleGlobals.ds.setValue("@toolbar_toggle_visible", true);
+			}
+		}
+
+		// Store the value
+		StumbleGlobals.ds.setValue("@ab_bits", ab_bits);
+	}
+	else
+	{
+		ab_bits = StumbleGlobals.ds.getValue("@ab_bits");
+	}
+	
+	return !!ab_bits;		
+}
+
+StumbleGlobals.get_source_label = function()
+{
+	if(StumbleGlobals.check_enable_default_toggle_button())
+		return StumbleGlobals.source_label + "-1";
+	else
+		return StumbleGlobals.source_label + "-0";
+}	
+
+StumbleGlobals.service.setLogResourceCFD(StumbleGlobals.log_resource_cfd);
+StumbleGlobals.service.setMessageLogEnabled(StumbleGlobals.enable_message_log);
+StumbleGlobals.service.setForceCampusDistEnabled(StumbleGlobals.test_campus_dist);
+StumbleGlobals.service.setLogErrorDomain(StumbleGlobals.servername);
+
+StumbleGlobals.ds = StumbleGlobals.service.getDatastore();
+
+StumbleGlobals.log_communication = StumbleGlobals.ds.getValue("@log_communication");
+StumbleGlobals.service.setLogCommunicationEnabled(StumbleGlobals.log_communication);
+
+StumbleGlobals.host = StumbleGlobals.service.getHostSpec(navigator);
+
+StumbleGlobals.stumbleReporter = StumbleGlobals.service.getStumbleReporter();
+
+StumbleGlobals.enable_hashed_password = StumbleGlobals.host.sha1;
+
+// current_user was used as far back as 4/2004, and ids was used between that and the usage of id_list.
+StumbleGlobals.new_install =(!StumbleGlobals.ds.isPrefDefined("@first_version") && !StumbleGlobals.ds.isPrefDefined("@id_list") && !StumbleGlobals.ds.isPrefDefined("@ids") &&
+				 (!StumbleGlobals.ds.isPrefDefined("@current_user") || (StumbleGlobals.ds.getValue("@current_user") == "")));
+
+StumbleGlobals.service.setAgentDesc(StumbleGlobals.useragent);
+
+StumbleGlobals.useragent += " " + StumbleGlobals.private_label;
+StumbleGlobals.useragent += " " + StumbleGlobals.get_source_label();
+
+StumbleGlobals.verstring = escape(StumbleGlobals.useragent);
+
+if (StumbleGlobals.new_install)
+{
+	var first_info = StumbleGlobals.useragent;
+	var utc = StumbleGlobals.get_time_s();
+	StumbleGlobals.ds.setValue("@first_version", first_info);
+	StumbleGlobals.ds.setValue("@first_run_time", utc);
+	StumbleGlobals.ds.setValue("javascript.options.showInConsole", true);
+//		StumbleGlobals.ds.setValue("javascript.options.strict", true);
+}
+
+// Note that "load" is handled by initOverlay.js
+window.addEventListener("unload", StumbleGlobals.handle_window_unload, false);
+
+StumbleGlobals.init_login(false, false);
+
+StumbleGlobals.login_initialized = true;
+
+StumbleGlobals.migrate_version();
+
+try {
+	StumbleGlobals.prefetcher = new StumbleGlobals.Prefetcher();
+} catch (e) { StumbleGlobals.log_error("INSTANTIATE PREFETCHER", e); }
+
+StumbleGlobals.observer_service = StumbleGlobals.get_service(
+			"@mozilla.org/observer-service;1",
+			"nsIObserverService");
+
+// We should move the http and em-action-requested observers into
+// stumbleuponService.js after the FF3 release. -- JW
+
+// Register the request and response observer.
+StumbleGlobals.observer_service.addObserver(StumbleGlobals.http_observer, "http-on-modify-request", false);
+StumbleGlobals.observer_service.addObserver(StumbleGlobals.http_observer, "http-on-examine-response", false);
+StumbleGlobals.observer_service.addObserver(StumbleGlobals.http_observer, "http-on-examine-cached-response", false);
+
+// Register the host observer.
+StumbleGlobals.observer_service.addObserver(StumbleGlobals.host_observer, "em-action-requested", false);
+
+// Register the global event observer.
+StumbleGlobals.observer_service.addObserver(StumbleGlobals.event_observer, "stumbleglobals_login", false);
+StumbleGlobals.observer_service.addObserver(StumbleGlobals.event_observer, "stumbleglobals_logout", false);
+StumbleGlobals.observer_service.addObserver(StumbleGlobals.event_observer, "stumbleglobals_change-password", false);
+StumbleGlobals.observer_service.addObserver(StumbleGlobals.event_observer, "stumbleglobals_configure-toolbar", false);
+StumbleGlobals.observer_service.addObserver(StumbleGlobals.event_observer, "stumbleglobals_referral-menu-dirty", false);
+StumbleGlobals.observer_service.addObserver(StumbleGlobals.event_observer, "stumbleglobals_update-referral-menu", false);
+StumbleGlobals.observer_service.addObserver(StumbleGlobals.event_observer, "stumbleglobals_refresh-category-selector", false);
+StumbleGlobals.observer_service.addObserver(StumbleGlobals.event_observer, "stumbleglobals_dyn-channels-dirty", false);
+StumbleGlobals.observer_service.addObserver(StumbleGlobals.event_observer, "stumbleglobals_update-dyn-channels", false);
+StumbleGlobals.observer_service.addObserver(StumbleGlobals.event_observer, "stumbleglobals_schedule-remove-data", false);
+StumbleGlobals.observer_service.addObserver(StumbleGlobals.event_observer, "stumbleglobals_message-button-click", false);
+StumbleGlobals.observer_service.addObserver(StumbleGlobals.event_observer, "stumbleglobals_extensionapi_message", false);
+
+// Register with the add-on manager (in try/catch because this is only available in Fx4)
+try {
+Components.utils.import("resource://gre/modules/AddonManager.jsm");
+AddonManager.addAddonListener(StumbleGlobals.event_observer);
+}
+catch(ex)
+{
+}
+
+// StumbleGlobals.include extra.js
+// StumbleGlobals.include("chrome://stumbleupon/content/extra.js");
+
diff --git a/content/stumbleuponOverlay.xul b/content/stumbleuponOverlay.xul
new file mode 100644
index 0000000..6fbd101
--- /dev/null
+++ b/content/stumbleuponOverlay.xul
@@ -0,0 +1,752 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<?xml-styleshe href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://stumbleupon/content/skin/stumbleuponOverlay.css" type="text/css"?>
+
+<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
+
+<overlay id="stumbleuponToolbar" 
+	xmlns:html="http://www.w3.org/1999/xhtml"
+	xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+	xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+	orient="vertical">
+
+
+<popup id="contentAreaContextMenu">
+	<menuitem id="context-photoblog-ilikeit"
+		label="StumbleUpon PhotoBlog It!"
+		image="chrome://stumbleupon/content/skin/thumbup.png"
+		class="menuitem-iconic" 
+		oncommand="StumbleGlobals.blogImage(1);"/>
+	<menuitem id="context-stumble-tagit" oncommand="StumbleGlobals.contextTag()" insertafter="context-searchselect"/>
+	<menuitem id="context-stumble-search" oncommand="StumbleGlobals.contextSearch(event)" insertafter="context-searchselect"/>
+</popup>
+
+<menupopup id="view_toolbars_popup">
+<menuitem id="view_stumble_menuitem" 
+	label="&menu.stumbleupon;"
+	class="menuitem-iconic" 
+	type="checkbox"
+	oncommand="StumbleGlobals.toggle_toolbar();"
+	persist="checked"/>
+</menupopup>
+
+<keyset id="mainKeyset">
+	<key id="key_StumbleUpon:ToggleToolbar"
+		keycode="VK_F11"
+		modifiers="accel"
+		command="StumbleUpon:ToggleToolbar"
+		savedcommand="StumbleUpon:ToggleToolbar"/>
+</keyset>
+
+<popupset id="mainPopupSet">
+	<popup id="stumbleglobals_intropopup" style="background:transparent;width:50px;height:50px;">
+	</popup>
+</popupset>
+
+<!--
+<script type="application/x-javascript" src="datastore.js"/>
+<script type="application/x-javascript" src="migrate.js"/>
+<script type="application/x-javascript" src="prefetcher.js"/>
+
+<hbox id="stumbleglobals_toolbar_info"
+	flex="1"
+	hidden="true">
+	<vbox>
+		<spacer height="15px"/>
+		<label value="bob"/>
+	</vbox>
+</hbox>
+-->
+<script type="application/x-javascript" src="namespace.js" />
+<script type="application/x-javascript" src="json_sans_eval.js" />
+
+<!-- initoverlay.js will delay-load stumbleuponOverlay.js _if_ it isn't already loaded -->
+<!-- delay-load increases Fx startup time -->
+<script type="application/x-javascript" src="initOverlay.js"/>
+
+<!-- In dev, include stumbleuponOverlay.js directly so you can debug it -->
+<!--<script type="application/x-javascript" src="stumbleuponOverlay.js"/>-->
+
+<toolbarpalette id="BrowserToolbarPalette">
+	<toolbarbutton id="stumbleglobals_toggle"
+		class="su-toggle-button chromeclass-toolbar-additional toolbarbutton-1"
+		label="StumbleUpon"
+		tooltiptext="StumbleUpon"
+		command="StumbleUpon:ToggleToolbar"/>
+	<toolbaritem id="stumbleglobals_toolbaritem">
+		<stack id="stumbleglobals_toolbar-stack"
+			flex="1">
+			<toolbarbutton class="stumbleglobals_toolbar-palette"
+				image="chrome://stumbleupon/skin/thumbup.png"
+				label="StumbleUpon Bar"/>
+			<hbox id="stumbleglobals_toolbar_container"
+				class="stumbleglobals_toolbar-container"
+				flex="1"/>
+			<hbox class="stumbleglobals_toolbar-customize"
+				flex="1">
+				<vbox>
+					<spacer flex="1"/>
+					<image src="chrome://stumbleupon/skin/stumble.png"
+						width="16px"
+						height="16px"/>
+					<spacer flex="1"/>
+				</vbox>
+				<vbox flex="1">
+					<spacer flex="1"/>
+					<label id="stumbleglobals_toolbar_customize_label" value=""/>
+					<spacer flex="1"/>
+				</vbox>
+			</hbox>
+		</stack>	
+	</toolbaritem>
+</toolbarpalette>
+<!--
+			style="min-width:0px; width:0px;"
+-->
+
+<toolbox id="navigator-toolbox">
+<toolbar id="stumbleupon" 
+	class="chromeclass-toolbar"
+	persist="collapsed,hidden" 
+	hidden="false" 
+	inherits="hidden"
+	collapsed="false"
+	toolbarname="StumbleUpon Toolbar (Ctrl-F11)"
+	savedtoolbarname="StumbleUpon Toolbar (Ctrl-F11)"
+	accesskey="S"
+	context="toolbar-context-menu"
+	customizable="true"
+	fullscreentoolbar="true"
+	defaultset="stumbleglobals_toolbaritem"
+	currentset="stumbleglobals_toolbaritem"
+	pack="start">
+
+<stringbundleset id="stringbundleset">
+	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
+</stringbundleset>
+
+<commandset id="stumbleglobals_commandset">
+	<command id="StumbleUpon:Stumble"             oncommand="StumbleGlobals.stumble(0);"/>
+	<command id="StumbleUpon:ViewReferrals"       oncommand="StumbleGlobals.handle_referral_throbber_click(event);"/>
+	<command id="StumbleUpon:ViewReviews"         oncommand="StumbleGlobals.website_info(0,'', 0);"/>
+	<command id="StumbleUpon:RateThumbup"         oncommand="StumbleGlobals.rate(1, false, false, false, 0);"/>
+	<command id="StumbleUpon:RateThumbdown"       oncommand="StumbleGlobals.rate(0, false, false, false, 0);"/>
+	<command id="StumbleUpon:Tag"                 oncommand="StumbleGlobals.handle_tag_command(true);"/>
+	<command id="StumbleUpon:ToggleToolbar"       oncommand="StumbleGlobals.toggle_toolbar();"/>
+<!--
+	<command id="StumbleUpon:RateThumbupDetailed" oncommand="StumbleGlobals.rate(1, 0, 1, 1);"/>
+-->
+</commandset>
+
+<keyset id="stumbleglobals_keyset"/>
+
+<hbox id="stumbleglobals_container"
+	class="chromeclass-toolbar-additional"
+	hidden="true"
+	flex="1">
+
+<toolbarbutton id="stumbleglobals_spacer" label="                    " collapsed="true"/>
+
+<hbox id="stumbleglobals_splitter_first_flexbox"
+	collapsed="true"/>
+
+<splitter id="stumbleglobals_splitter_first"
+	state="open"
+	class="chromeclass-toolbar-additional"
+	collapsed="true"
+	collapse="none"
+	resizebefore="grow"
+	resizeafter="grow"
+	onmousedown="StumbleGlobals.handle_splitter_first_mousedown(event);"
+	onmouseup="StumbleGlobals.handle_splitter_first_mouseup(event);"/>
+
+<toolbarbutton id="stumbleglobals_start"
+	class="su-showtext"
+	onclick="StumbleGlobals.clickstumble(event)"
+	tooltiptext="Create an account"
+	label="Start Stumbling..."
+	showlabel="Start Stumbling..."
+	image="chrome://stumbleupon/content/skin/stumble.png"/>
+
+<toolbarbutton id="stumbleglobals_stumble"
+	collapsed="true"
+	class="su-showtext"
+	onclick="StumbleGlobals.clickstumble(event)"
+	tooltiptext="Show next page"
+	showlabel="Stumble!"
+	label="Stumble!"
+	image="chrome://stumbleupon/content/skin/stumble.png"
+	image2=""
+	validate2="never"/>
+
+<hbox id="stumbleglobals_login"
+	collapsed="true">
+	<vbox>
+		<spacer flex="1"/>
+		<label value=" or "/>
+		<spacer flex="1"/>
+	</vbox>
+	<toolbarbutton
+		class="su-showtext"
+		image="chrome://stumbleupon/content/skin/icon_signin.png"
+		oncommand="StumbleGlobals.show_signin_dialog();"
+		showlabel="Sign-in"
+		label="Sign-in"/>
+</hbox>
+
+<toolbarbutton id="stumbleglobals_category"
+	type="menu"
+	class="su-hideicon-showtext"
+	container="true"
+	collapsed="true"
+	tooltiptext="Choose your stumble mode">
+	<menupopup/>
+</toolbarbutton>
+
+<toolbarbutton id="stumbleglobals_referred"
+	collapsed="true"
+	class="su-showtext"
+	onclick="StumbleGlobals.handle_referral_throbber_click(event);">
+</toolbarbutton>
+
+<!--
+<vbox id="stumbleglobals_inbox-count"
+	collapsed="true"
+	onclick='StumbleGlobals.handle_mode_click(event, "All");'>
+	<spacer flex="1"/>
+	<description id="stumbleglobals_inbox-count-label"
+		class="inbox"
+		value="10"
+		tooltiptext="&button.inbox-count.tooltip;"/>
+	<spacer flex="1"/>
+</vbox>
+-->
+
+<toolbarbutton id="stumbleglobals_upgrade"
+	class="su-showtext"
+	collapsed="true"
+	tooltiptext="A new version of StumbleUpon is available.  Click here to upgrade."
+	image="chrome://stumbleupon/content/skin/upgrade.png"
+	oncommand="StumbleGlobals.handle_upgrade_command();"/>
+
+<toolbarbutton id="stumbleglobals_thumbup" 
+	class="su-showtext" 
+	collapsed="true" 
+	label="" 
+	showlabel="&button.ilikeit;" 
+	showlabel2="&button.ilikethem;"
+	onclick="StumbleGlobals.handle_rate_click(event, 1)" 
+	onclick2="StumbleGlobals.handle_rate_click(event, 1)" 
+	tooltiptext="Add to favorites, show more like this" 
+	showtooltiptext="Add to favorites, show more like this"/>
+
+<toolbarbutton id="stumbleglobals_recthumbup" 
+	class="su-showtext" 
+	collapsed="true" 
+	label=""
+	showlabel="&button.ilikeit;" 
+	onclick="StumbleGlobals.handle_rate_click(event, 2)" 
+	onclick2="StumbleGlobals.handle_rate_click(event, 2)" 
+	tooltiptext="Recthumb 2" 
+	image="chrome://stumbleupon/content/skin/bug.png"/>
+
+<toolbarbutton id="stumbleglobals_thumbdown"
+	class="su-hidetext"
+	collapsed="true"
+	oncommand="if (event.target == this) StumbleGlobals.handle_rate_click(event, 0);"
+	oncommand2="if (event.target == this) StumbleGlobals.handle_rate_click(event, 0);"
+	onclick=""
+	onclick2=""
+	tooltiptext="&button.notforme.tooltip;"
+	showtooltiptext="&button.notforme.tooltip;">
+	<menupopup onpopupshowing="StumbleGlobals.prepare_thumbdown_menu();">
+		<menuitem id="stumbleglobals_thumbdown_menu_notforme"
+			label="&menu.notforme;"
+			type="checkbox" 
+			autocheck="false"
+			tooltiptext=""
+			oncommand="StumbleGlobals.handle_rate_click(event, -2);" />
+		<menuseparator />
+		<menuitem id="stumbleglobals_thumbdown_menu_spam"
+			label="&menu.spam;"
+			type="checkbox"
+			authocheck="false"
+			tooltiptext=""
+			oncommand="StumbleGlobals.handle_rate_click(event, -5);" />
+		<menuitem id="stumbleglobals_thumbdown_menu_dupe"
+			label="&menu.dupe;"
+			type="checkbox" 
+			autocheck="false"
+			tooltiptext=""
+			oncommand="StumbleGlobals.handle_rate_click(event, -3);" />
+		<menuseparator
+			id="stumbleglobals_thumbdown_menu_separator"/>
+		<menuitem id="stumbleglobals_thumbdown_menu_blockdomain"
+			label="&menu.blockdomain;"
+			type="checkbox" 
+			tooltiptext=""
+			oncommand="StumbleGlobals.block_domain();" />
+	</menupopup>
+</toolbarbutton>
+
+<div id="stumbleglobals_separator_category"
+	style="height: 100%;"
+	collapsed="true">
+	<toolbarseparator
+		style="height: 100%;"/>
+</div>
+
+<toolbarbutton 
+    id="stumbleglobals_stumble_topic_menu_left" 
+    class="su-hideicon-showtext" 
+    collapsed="true" 
+    label="" 
+    type="menu"
+    tooltiptext="Report a problem with this page">
+    <menupopup id="stumbleglobals_stumble_topic_menu_left_popup">
+    </menupopup>
+</toolbarbutton>
+
+<!--
+<toolbarbutton id="stumbleglobals_thumbdown_dupe"
+	class="su-showtext"
+	collapsed="true"
+	label="Dupe Content"
+	onclick="StumbleGlobals.handle_rate_click(event, 3)"
+	image="chrome://stumbleupon/content/skin/thumbdown2.png"/>
+
+<toolbarbutton id="stumbleglobals_thumbdown_targeting"
+	class="su-showtext"
+	collapsed="true"
+	label="Bad Targeting"
+	onclick="StumbleGlobals.handle_rate_click(event, 4)"
+	image="chrome://stumbleupon/content/skin/thumbdown2.png"/>
+
+<toolbarbutton id="stumbleglobals_thumbdown_spam"
+	class="su-showtext"
+	collapsed="true"
+	label="Spammy"
+	onclick="StumbleGlobals.handle_rate_click(event, 5)"
+	image="chrome://stumbleupon/content/skin/thumbdown2.png"/>
+-->
+
+<div id="stumbleglobals_separator2"
+	style="height: 100%;"
+	collapsed="true">
+	<toolbarseparator
+		style="height: 100%;"/>
+</div>
+
+<toolbarbutton id="stumbleglobals_tag2"
+	class="su-hidetext"
+	collapsed="true"
+	label=""
+	showlabel="&button.tag;"
+	tooltiptext="Tag this page"
+	tooltiptext2="Tag this page"
+	image="chrome://stumbleupon/content/skin/tag.png"
+	oncommand="StumbleGlobals.handle_tag_command(true);"/>
+
+<toolbarbutton id="stumbleglobals_fbshare"
+	class="su-hidetext"
+	collapsed="true"
+	label=""
+	showlabel="Share with Facebook"
+	tooltiptext="Share this page with your friends on Facebook"
+	image="chrome://stumbleupon/content/skin/favicon_facebook.gif"
+	oncommand="StumbleGlobals.share_facebook()">
+</toolbarbutton>
+
+<toolbarbutton id="stumbleglobals_referral_menu"
+	class="su-showtext"
+	type="menu"
+	collapsed="true"
+	label=""
+	showlabel="Share"
+	container="true"
+	tooltiptext="Send this page to friends"
+	popup="stumbleglobals_referral_popup"
+	image="chrome://stumbleupon/content/skin/icon_tb_share.png">
+</toolbarbutton>
+
+<toolbarbutton id="stumbleglobals_referral_promo"
+	class="su-showtext"
+	collapsed="true"
+	label=""
+	showlabel="Share"
+	tooltiptext="Send this page to a friend"
+	image="chrome://stumbleupon/content/skin/icon_tb_share.png"
+	onclick="StumbleGlobals.handle_promo_click(event, 'referral');"/>
+	
+<toolbarbutton id="stumbleglobals_website_info"
+	class="su-showtext"
+	collapsed="true"
+	label="&button.info;"
+	showlabel="&button.info;"
+	tooltiptext="People who like this"
+	image="chrome://stumbleupon/content/skin/bubble.png"
+	onclick="StumbleGlobals.handle_website_info_click(event);"/>
+
+<toolbarseparator
+	id="stumbleglobals_separator_promo"
+	collapsed="true"
+	style="height: 100%;"/>
+
+<toolbaritem id="stumbleglobals_field"
+	align="center"
+	collapsed="true"
+	title="search">
+	<popupset id="stumbleglobals_searchpopupset">
+		<popup id="stumbleglobals_searchpopup"/>
+	</popupset>
+	<textbox id="stumbleglobals_searchbox"
+		maxrows="14"
+		flex="1"
+		autocompletepopup="stumbleglobals_searchpopup"
+		inputtooltiptext="Enter Search or Tag Terms separated by Commas"
+		ontextentered="StumbleGlobals.handle_searchbox_textentered(arguments[1]);"
+		ontextreverted="StumbleGlobals.handle_searchbox_textreverted()"
+		onpagenavigationkey="StumbleGlobals.handle_searchbox_pagenavigationkey(arguments[1]);"
+		onkeyup="StumbleGlobals.handle_searchbox_keyup(event)"
+		onfocus="StumbleGlobals.handle_searchbox_focus()"
+		onclick="StumbleGlobals.searchbox_click_kludge('click')"
+		onblur="StumbleGlobals.handle_searchbox_blur()"
+		contextitemalabel="Auto"
+		contextitemaaccesskey="A"
+		contextitemaoncommand="StumbleGlobals.set_autocomplete_type('auto');"
+		contextitemblabel="&menu.autocompletequeries;"
+		contextitembaccesskey="&menu.autocompletequeries.accesskey;"
+		contextitemboncommand="StumbleGlobals.set_autocomplete_type('query');"
+		contextitemclabel="&menu.autocompletetags;"
+		contextitemcaccesskey="&menu.autocompletetags.accesskey;"
+		contextitemconcommand="StumbleGlobals.set_autocomplete_type('tag');"
+		reflectpopuplabel="true"
+		sizetopopup="none"
+		minwidth="50"
+		width="150"/>	
+</toolbaritem>
+<!--
+	oninput="StumbleGlobals.onSearchInput(event);"
+	oncommand="StumbleGlobals.onSearchSelect(event);"
+	onmousedown="StumbleGlobals.onSearchBoxMouseDown(event, this);"
+	onclick="StumbleGlobals.onSearchBoxClick(event,this);"
+-->
+
+<splitter id="stumbleglobals_splitter_search_right"
+	class="stumbleglobals_splitter"
+	state="open"
+	collapsed="true"
+	collapse="none"
+	resizebefore="closest"
+	resizeafter="grow"
+	onmousedown="return StumbleGlobals.handle_splitter_search_right_mousedown(event);"
+	onmouseup="return StumbleGlobals.handle_splitter_search_right_mouseup(event);"/>
+	
+<toolbarbutton id="stumbleglobals_tag"
+	class="su-hidetext"
+	collapsed="true"
+	label=""
+	showlabel="&button.tag;"
+	tooltiptext="Tag this page"
+	tooltiptext2="Tag this page"
+	image="chrome://stumbleupon/content/skin/tag.png"
+	oncommand="StumbleGlobals.handle_tag_command(false);"/>
+
+<toolbarbutton id="stumbleglobals_website_info_promo"
+	class="su-showtext"
+	collapsed="true"
+	label=""
+	showlabel="People who like this"
+	tooltiptext="People who like this"
+	image="chrome://stumbleupon/content/skin/bubble.png"
+	onclick="StumbleGlobals.handle_website_info_promo_click(event, 'info');"/>
+	
+<toolbarseparator id="stumbleglobals_separator6"
+	collapsed="true"
+	style="height: 100%;"/>
+
+
+<hbox id="stumbleglobals_mode"
+	collapsed="true">
+	<vbox id="stumbleglobals_mode_label">
+		<spacer flex="1"/>
+		<label value="Channels:"/>
+		<spacer flex="1"/>
+	</vbox>
+	<toolbarbutton id="stumbleglobals_mode_stumbler"
+		class="su-hidetext"
+		stumbleglobals_ismode="1"
+		hidden="true"/>
+	<toolbarbutton id="stumbleglobals_mode_domain"
+		class="su-hidetext"
+		stumbleglobals_ismode="1"
+		hidden="true"
+		validate="never"/>
+	<toolbarbutton id="stumbleglobals_mode_all"
+		class="su-hidetext"
+		hidden="true"
+		stumbleglobals_ismode="1"
+		tooltiptext="Stumble all"
+		image="chrome://stumbleupon/content/skin/all.png"
+		onclick='StumbleGlobals.handle_mode_click(event, "All");'/>
+	<toolbarbutton id="stumbleglobals_mode_friends"
+		class="su-hidetext"
+		hidden="true"
+		stumbleglobals_ismode="1"
+		tooltiptext="Sites from people you are following"
+		image="chrome://stumbleupon/content/skin/icon_tb_people.png"
+		onclick='StumbleGlobals.handle_mode_click(event, "Friends");'/>
+	<toolbarbutton id="stumbleglobals_mode_photo"
+		class="su-hidetext"
+		hidden="true"
+		stumbleglobals_ismode="1"
+		tooltiptext="Stumble images"
+		image="chrome://stumbleupon/content/skin/icon_tb_photo_hover.png"
+		onclick='StumbleGlobals.handle_mode_click(event, "Photos");'/>
+	<toolbarbutton id="stumbleglobals_mode_video"
+		class="su-hidetext"
+		hidden="true"
+		stumbleglobals_ismode="1"
+		tooltiptext="Stumble videos"
+		image="chrome://stumbleupon/content/skin/video.png"
+		onclick='StumbleGlobals.handle_mode_click(event, "Videos");'/>
+	<toolbarbutton id="stumbleglobals_mode_more"
+		type="menu"
+		class="su-hidetext"
+		stumbleglobals_ismode="1"
+		hidden="true"
+		tooltiptext="StumbleThru a website"
+		image="chrome://stumbleupon/content/skin/domain.png">
+		<menupopup id="stumbleglobals_mode_more_popup"
+			onpopupshowing="StumbleGlobals.handle_popupshowing(event);"
+			onpopuphidden="StumbleGlobals.handle_popuphidden(event);"/>
+	</toolbarbutton>
+	<toolbarbutton id="stumbleglobals_mode_stumblers"
+		class="su-hidetext"
+		hidden="true"
+		stumbleglobals_ismode="1"
+		tooltiptext="Stumble profiles"
+		image="chrome://stumbleupon/content/skin/stumblers.png"
+		onclick='StumbleGlobals.handle_mode_click(event, "Profiles");'/>
+	<toolbarbutton id="stumbleglobals_mode_search"
+		class="su-hidetext"
+		hidden="true"
+		stumbleglobals_ismode="1"
+		tooltiptext="Stumble within a query"
+		image="chrome://stumbleupon/content/skin/search.png"
+		onclick='StumbleGlobals.handle_mode_click(event, "Search");'/>
+	<toolbarbutton id="stumbleglobals_mode_news"
+		class="su-hidetext"
+		hidden="true"
+		stumbleglobals_ismode="1"
+		tooltiptext="Stumble news items"
+		image="chrome://stumbleupon/content/skin/icon_tb_news.png"
+		onclick='StumbleGlobals.handle_mode_click(event, "News");'/>
+	<toolbarbutton id="stumbleglobals_mode_wiki"
+		class="su-hidetext"
+		hidden="true"
+		stumbleglobals_ismode="1"
+		tooltiptext="Stumble wiki articles"
+		image="chrome://stumbleupon/content/skin/wiki.png"
+		onclick='StumbleGlobals.handle_mode_click(event, "Wiki");'/>
+</hbox>
+
+<toolbarbutton id="stumbleglobals_sites_promo"
+	class="su-showtext"
+	collapsed="true"
+	label=""
+	showlabel="Sites"
+	tooltiptext="Stumble a website"
+	image="chrome://stumbleupon/content/skin/all_disabled.png"
+	onclick="StumbleGlobals.handle_promo_click(event, 'sites');"/>
+	
+<toolbarbutton id="stumbleglobals_video_promo"
+	class="su-showtext"
+	collapsed="true"
+	label=""
+	showlabel="Videos"
+	tooltiptext="Stumble videos"
+	image="chrome://stumbleupon/content/skin/video.png"
+	onclick="StumbleGlobals.handle_video_promo_click(event);"/>
+	
+<toolbarseparator id="stumbleglobals_separator4"
+	collapsed="true"
+	style="height: 100%;"/>
+
+<hbox id="stumbleglobals_filter"
+	collapsed="true">
+	<toolbarbutton
+		label="X"
+		image="chrome://stumbleupon/content/skin/x.png"
+		oncommand="StumbleGlobals.handle_filter_command(2);"/>
+	<toolbarbutton
+		label="R"
+		image="chrome://stumbleupon/content/skin/r.png"
+		oncommand="StumbleGlobals.handle_filter_command(1);"/>
+	<toolbarbutton
+		label="G"
+		image="chrome://stumbleupon/content/skin/g.png"
+		oncommand="StumbleGlobals.handle_filter_command(0);"/>
+	<toolbarseparator id="stumbleglobals_separator8"/>
+</hbox>
+
+<toolbarbutton id="firstrater"  class="su-showtext" collapsed="true" label="" tooltiptext="" image="chrome://stumbleupon/content/skin/firstrater.png" onclick="StumbleGlobals.firstrater_func(event);"/>
+
+<toolbarbutton id="stumbleglobals_stumble_topic" class="su-hideicon-showtext" collapsed="true" label="" tooltiptext="This is the category of the current page"/>
+
+<toolbarbutton 
+    id="stumbleglobals_stumble_topic_menu_right" 
+    class="su-hideicon-showtext" 
+    collapsed="true" 
+    label="" 
+    type="menu"
+    tooltiptext="Report a problem with this page">
+    <menupopup id="stumbleglobals_stumble_topic_menu_right_popup">
+    </menupopup>
+</toolbarbutton>
+
+<toolbarseparator id="stumbleglobals_separator7"
+	collapsed="true"
+	style="height: 100%;"/>
+
+<!-- <toolbarbutton id="stumbleglobals_aboutme"  class="su-hidetext" collapsed="true" label="" showlabel="&button.profile;" tooltiptext="&button.profile.tooltip;" image="chrome://stumbleupon/content/skin/profile.png" onclick="StumbleGlobals.redir_tab(event,'home');"/> -->
+<toolbarbutton id="stumbleglobals_profile"  class="su-hidetext" collapsed="true" label="" showlabel="Favorites" tooltiptext="Things I have liked" image="chrome://stumbleupon/content/skin/icon_tb_favorites_hover.png" onclick="StumbleGlobals.redir_tab(event,'');"/>
+<toolbarbutton id="stumbleglobals_aboutme"  class="su-hidetext" collapsed="true" label="" showlabel="What's New" tooltiptext="Recent activity from people you are following" image="chrome://stumbleupon/content/skin/icon_tb_user_comment.png" onclick="StumbleGlobals.redir_tab(event,'home');"/>
+<toolbarbutton id="stumbleglobals_friends"  class="su-showtext" collapsed="true" label="" showlabel="&button.friends;" tooltiptext="&button.friends.tooltip;" image="chrome://stumbleupon/content/skin/friend.png" onclick="StumbleGlobals.redir_tab(event,'friends');"/>
+<toolbarbutton id="stumbleglobals_messages" class="su-hidetext" collapsed="true" label="" showlabel="&button.messages;" tooltiptext="&button.messages.tooltip;" image="chrome://stumbleupon/content/skin/mail.png" onclick="StumbleGlobals.redir_tab(event,'inbox');"/>
+
+<toolbarbutton id="stumbleglobals_page_feature_prompt"
+	class="su-showtext"
+	collapsed="true"
+	label=""
+	showlabel="See ratings on results"
+	tooltiptext="See who likes your search results"
+	image="chrome://stumbleupon/content/skin/bubble.png"
+	onclick="StumbleGlobals.handle_page_feature_prompt_click(event);"/>
+	
+<toolbarbutton id="stumbleglobals_groups"   class="su-hidetext" collapsed="true" label="" showlabel="&button.groups;" tooltiptext="Group conversations" image="chrome://stumbleupon/content/skin/forum.png" onclick="StumbleGlobals.redir_tab(event,'groups');"/>
+<toolbarbutton id="stumbleglobals_network"  class="su-hidetext" collapsed="true" label="" showlabel="Classic Network" tooltiptext="Classic network" image="chrome://stumbleupon/content/skin/stumblers.png" onclick="StumbleGlobals.redir_tab(event, 'network');"/>
+<!-- <toolbarbutton id="stumbleglobals_forum"    class="su-hidetext" collapsed="true" label="" showlabel="Classic Forums" tooltiptext="Classic forums" image="chrome://stumbleupon/content/skin/legacy_forum.png" onclick="StumbleGlobals.redir_tab(event,'forum');"/> -->
+<toolbarbutton id="stumbleglobals_matches"  class="su-hidetext" collapsed="true" label="" showlabel="Find People" tooltiptext="Browse people by interest, age, location" image="chrome://stumbleupon/content/skin/icon_tb_search_user.png" onclick="StumbleGlobals.redir_tab(event,'matches');"/>
+
+<!-- may be obsolete -->
+<toolbarseparator id="stumbleglobals_separator5"
+	collapsed="true"
+	style="height: 100%;"/>
+
+
+<toolbarbutton id="stumbleglobals_sponsor"  class="su-hidetext" collapsed="true" tooltiptext="" image="chrome://stumbleupon/content/skin/sponsor.png" onclick="StumbleGlobals.handle_sponsor_click(event);"/>
+
+<toolbarbutton id="stumbleglobals_myinfo" class="su-showtext" collapsed="true" label="" showlabel="Preferences" tooltiptext="&button.edit.tooltip;" image="chrome://stumbleupon/content/skin/editinfo.png" onclick="StumbleGlobals.redir_tab(event,'prefs');"/>
+
+<toolbarbutton id="stumbleglobals_bug"
+	class="su-hidetext"
+	collapsed="true"
+	tooltiptext="Submit a bug report via e-mail"
+	image="chrome://stumbleupon/content/skin/bug.png"
+	oncommand="StumbleGlobals.handle_bug_command();"/>
+	
+<toolbarbutton id="stumbleglobals_stumble_menu"
+	type="menu"
+	class="su-showtext"
+	container="true"
+	collapsed="true"
+	label="Tools"
+	showlabel="Tools"
+	tooltiptext="Configuration and reporting tools">
+	<menupopup id="stumbleglobals_stumble_popup">
+		<menu id = "stumbleglobals_stumble_report_menu"
+			label="Report this stumble as"
+			tooltiptext="Report...">
+			<menupopup id="stumbleglobals_stumble_report_popup"
+				onpopupshowing="StumbleGlobals.prepare_stumble_report_menu(event, null);"/>
+		</menu>
+		<menuitem label="Toolbar Options" tooltiptext="Change preferences for this toolbar" oncommand="StumbleGlobals.preferences();"/>
+		<menuitem label="Account Settings" tooltiptext="Change your StumbleUpon account settings" onclick="StumbleGlobals.redir_tab(event,'prefs');"/>
+		<menuitem label="&menu.updateinterests;" tooltiptext="Sign up for new topics" oncommand="StumbleGlobals.interests();"/>
+		<menuitem label="View Suggested Topics" tooltiptext="Suggest additional topics you may be interested in" oncommand="StumbleGlobals.suggest();"/>
+		<menuitem label="Find Friends" tooltiptext="Invite friends to join StumbleUpon" onclick="StumbleGlobals.invite(event);"/>
+		<menuseparator/>
+		
+		<menuitem label="Change Password" tooltiptext="Change your password" oncommand="StumbleGlobals.handle_change_password();"/>
+		<menuitem type="checkbox" autocheck="false" style="display:none" checked="true" label="Sign-in..." tooltiptext="Sign in to a different StumbleUpon account" oncommand="StumbleGlobals.show_signin_dialog();"/>
+		<menuitem label="Sign-out" tooltiptext="Sign out from this account" oncommand="StumbleGlobals.handle_logout(false);"/>
+	
+		<menuseparator/>
+		
+		<menuitem label="Help Center" tooltiptext="Frequently Asked Questions" oncommand="getBrowser().contentDocument.location=StumbleGlobals.serverhttp + 'faq.html'"/>
+		<menu label="About StumbleUpon" tooltiptext="Get help with StumbleUpon">
+			<menupopup>
+				<menuitem label="&menu.stumblehome;" tooltiptext="StumbleUpon.com Home Page" oncommand="getBrowser().contentDocument.location=StumbleGlobals.serverhttp"/>
+				<menuitem label="Help Forum" tooltiptext="Get help from other stumblers" oncommand="getBrowser().contentDocument.location='http://getsatisfaction.com/stumbleupon/products/stumbleupon_stumbleupon_toolbar'"/>
+				<menuitem label="Stumble News" tooltiptext="Read the latest news about StumbleUpon services" oncommand="getBrowser().contentDocument.location=StumbleGlobals.serverhttp + 'news.php'"/>
+				<menuitem label="&menu.topstumblers;" tooltiptext="See the most helpful stumblers" oncommand="getBrowser().contentDocument.location=StumbleGlobals.serverhttp + 'topstumblers.php'"/>
+				<menuseparator/>
+				<menuitem label="&menu.contact;" tooltiptext="Send questions or comments to StumbleUpon" oncommand="StumbleGlobals.feedback();"/>
+				<menuitem label="Privacy Policy" tooltiptext="View StumbleUpon's privacy policy" oncommand="getBrowser().contentDocument.location=StumbleGlobals.serverhttp + 'privacy.html'"/>
+				<menuitem label="Uninstall Instructions" tooltiptext="Learn how to uninstall the toolbar" oncommand="getBrowser().contentDocument.location=StumbleGlobals.serverhttp + 'help/How_do_I_uninstall_the_toolbar/'"/>
+				<menuitem label="Toolbar Version" tooltiptext="Your current toolbar version, along with new versions" oncommand="StumbleGlobals.about();"/>
+			</menupopup>
+		</menu>
+	</menupopup>
+</toolbarbutton>
+
+<toolbarseparator id="stumbleglobals_separator3"
+	collapsed="true"
+	style="height: 100%;"/>
+
+
+<toolbarbutton id="stumbleglobals_grab"     class="su-showtext" label="G" collapsed="true" tooltiptext="Next" image="chrome://stumbleupon/content/skin/stumble.png" oncommand="StumbleGlobals.grab();"/>
+<toolbarbutton id="stumbleglobals_approve"  class="su-showtext" label="OK" collapsed="true" tooltiptext="Approve" image="chrome://stumbleupon/content/skin/thumbup.png" oncommand="StumbleGlobals.approve();"/>
+
+<toolbarbutton id="stumbleglobals_idx"                          label="IDX" collapsed="true" tooltiptext="Direct to IDX" image="chrome://stumbleupon/content/skin/thumbup.png" oncommand="toidx();"/>
+<toolbarbutton id="stumbleglobals_tld"                          label="TLD" collapsed="true" tooltiptext="Go to TLD for this page" image="chrome://stumbleupon/content/skin/arrow.png" oncommand="grab_tld();"/>
+
+<toolbarbutton id="stumbleglobals_grab_category"
+	type="menu"
+	class="su-showtext"
+	contain="true"
+	collapsed="true"
+	label='topic'>
+	<menupopup class="topic-selector">
+	</menupopup>
+</toolbarbutton>
+
+<vbox id="stumbleglobals_site-count-box"
+	collapsed="true">
+	<spacer flex="1"/>
+	<description id="stumbleglobals_site-count"
+		class="inbox"
+		value=""
+		tooltiptext=""/>
+	<spacer flex="1"/>
+</vbox>
+
+<toolbarbutton id="stumbleglobals_overflow_menu"
+	type="menu"
+	width="20px"
+	collapsed="true"
+	image="chrome://stumbleupon/content/skin/chevron.png">
+	
+	<menupopup id="stumbleglobals_overflow_popup"
+		onpopupshowing="StumbleGlobals.handle_popupshowing(event)"
+		onpopuphidden="StumbleGlobals.handle_popuphidden(event)"/>
+	
+</toolbarbutton>
+
+</hbox>
+
+<hbox id="stumbleglobals_render"
+	class="chromeclass-extrachrome"
+	width="0"
+	height="0"/>
+
+</toolbar>
+<toolbar id="stumbleglobals_info_toolbar"
+	class="chromeclass-toolbar"
+	customizable="false"
+	collapsed="true"/>
+</toolbox>
+
+</overlay>
diff --git a/chrome/stumbleupon.jar!/content/taggingDialog.js b/content/taggingDialog.js
similarity index 84%
rename from chrome/stumbleupon.jar!/content/taggingDialog.js
rename to content/taggingDialog.js
index 39e6ad8..5b8df81 100644
--- a/chrome/stumbleupon.jar!/content/taggingDialog.js
+++ b/content/taggingDialog.js
@@ -1,108 +1,108 @@
-var detail = window.arguments[0];
-var tags_was_focused = false;
-var old_tags_value = "";
-
-function init()
-{
-	var tags = document.getElementById("tags");
-	tags.autocompleteDatasource =
-				{
-					getResults : function ()
-					{
-						var tags = document.getElementById("tags");
-						return opener.su_get_autocomplete_results(
-									"tag",
-									tags.value,
-									tags.maxRows,
-									new Array());
-					}
-				}
-	tags.value = detail.tags_default;
-}
-
-function doOK()
-{
-	var tags = document.getElementById("tags").value;
-	if (tags == null)
-		return true;
-
-	var tagerror = opener.su_validate_tagstring(tags);
-	if (tagerror != null)
-	{
-		alert(tagerror);
-		document.getElementById("tags").focus();
-		return false;
-	}	
-	
-	if (tags != '')
-	{
-		opener.document.getElementById("su_searchbox").value = tags;
-		opener.setTimeout(
-					function(parent_window, url, tags){
-						parent_window.su_tagit(url, tags, false);},
-					0,
-					opener,
-					detail.url,
-					tags);
-	}
-
-	return true;
-}
-
-function tags_click_kludge(eventId)
-{
-	// This handles value selection in the case where the user is
-	// clicking back and forth between tags and another field.  Without
-	// this kludge, the text is selected only every second time.  (ref: 
-	// Firefox 1.5, XP)  This may not be necessary on this window since 
-	// the dialog has only one field, but it's here in case we need it 
-	// later. -- JW
-
-	switch (eventId)
-	{
-		case "click":
-			var tags = document.getElementById('tags');
-			var selected = (tags.value.length != 0)
-						&& ((tags.selectionEnd - tags.selectionStart) == tags.value.length);
-
-			if ((! tags_was_focused) && (! selected))
-			{
-				tags.select();
-			}
-			tags_was_focused = true;
-		break;
-		case "blur":
-			tags_was_focused = false;
-		break;
-	}
-
-	return true;
-}
-
-function handle_tags_focus(evt)
-{
-	var tags = document.getElementById('tags');
-
-	if (tags.value != "")
-	{
-		tags.select();
-	}
-}
-
-function handle_tags_keyup(evt)
-{
-	old_tags_value = document.getElementById("tags").value;
-	return true;
-}
-
-function handle_tags_textentered()
-{
-	document.getElementById("stumble_tagging_dialog").acceptDialog();
-}
-
-function handle_tags_textreverted()
-{
-	document.getElementById("tags").value = old_tags_value;
-	document.getElementById("tags").select();
-}
-
+var detail = window.arguments[0];
+var tags_was_focused = false;
+var old_tags_value = "";
+
+function init()
+{
+	var tags = document.getElementById("tags");
+	tags.autocompleteDatasource =
+				{
+					getResults : function ()
+					{
+						var tags = document.getElementById("tags");
+						return opener.StumbleGlobals.get_autocomplete_results(
+									"tag",
+									tags.value,
+									tags.maxRows,
+									new Array());
+					}
+				}
+	tags.value = detail.tags_default;
+}
+
+function doOK()
+{
+	var tags = document.getElementById("tags").value;
+	if (tags == null)
+		return true;
+
+	var tagerror = opener.StumbleGlobals.validate_tagstring(tags);
+	if (tagerror != null)
+	{
+		alert(tagerror);
+		document.getElementById("tags").focus();
+		return false;
+	}	
+	
+	if (tags != '')
+	{
+		opener.document.getElementById("stumbleglobals_searchbox").value = tags;
+		opener.setTimeout(
+					function(parent_window, url, tags){
+						parent_window.StumbleGlobals.tagit(url, tags, false);},
+					0,
+					opener,
+					detail.url,
+					tags);
+	}
+
+	return true;
+}
+
+function tags_click_kludge(eventId)
+{
+	// This handles value selection in the case where the user is
+	// clicking back and forth between tags and another field.  Without
+	// this kludge, the text is selected only every second time.  (ref: 
+	// Firefox 1.5, XP)  This may not be necessary on this window since 
+	// the dialog has only one field, but it's here in case we need it 
+	// later. -- JW
+
+	switch (eventId)
+	{
+		case "click":
+			var tags = document.getElementById('tags');
+			var selected = (tags.value.length != 0)
+						&& ((tags.selectionEnd - tags.selectionStart) == tags.value.length);
+
+			if ((! tags_was_focused) && (! selected))
+			{
+				tags.select();
+			}
+			tags_was_focused = true;
+		break;
+		case "blur":
+			tags_was_focused = false;
+		break;
+	}
+
+	return true;
+}
+
+function handle_tags_focus(evt)
+{
+	var tags = document.getElementById('tags');
+
+	if (tags.value != "")
+	{
+		tags.select();
+	}
+}
+
+function handle_tags_keyup(evt)
+{
+	old_tags_value = document.getElementById("tags").value;
+	return true;
+}
+
+function handle_tags_textentered()
+{
+	document.getElementById("stumble_tagging_dialog").acceptDialog();
+}
+
+function handle_tags_textreverted()
+{
+	document.getElementById("tags").value = old_tags_value;
+	document.getElementById("tags").select();
+}
+
diff --git a/chrome/stumbleupon.jar!/content/taggingDialog.xul b/content/taggingDialog.xul
similarity index 96%
rename from chrome/stumbleupon.jar!/content/taggingDialog.xul
rename to content/taggingDialog.xul
index 741edd7..d6289b8 100644
--- a/chrome/stumbleupon.jar!/content/taggingDialog.xul
+++ b/content/taggingDialog.xul
@@ -1,55 +1,55 @@
-<?xml version="1.0"?>
-
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-<?xml-stylesheet href="chrome://stumbleupon/skin/taggingDialog.css" type="text/css"?>
-
-<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
-
-<dialog id="stumble_tagging_dialog2" title="StumbleUpon Tag"
-  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-  buttons="accept,cancel"
-  persist="screenX screenY"
-  ondialogaccept="return doOK();"
-  onload="init()">
-
-<stringbundleset id="stringbundleset">
-	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
-</stringbundleset>
-
-<script type="application/x-javascript" src="taggingDialog.js"/>
-
-<popupset>
-	<popup id="tagspopup"/>
-</popupset>
-
-<grid flex="1" style="margin:10px">
-  <columns>
-    <column flex="1"/>
-  </columns>
-  <rows>
-    <row>
-			<label value="Enter up to 5 tags, separated by commas:"/>
-		</row>
-		<row>
-			<textbox id="tags"
-				maxrows="14"
-				flex="1"
-				autocompletepopup="tagspopup"
-				inputtooltiptext="Enter Tag Terms separated by Commas"
-				ontextentered="handle_tags_textentered()"
-				ontextreverted="handle_tags_textreverted()"
-				onkeyup="handle_tags_keyup(event)"
-				onfocus="handle_tags_focus()"
-				onclick="tags_click_kludge('click')"
-				onblur="tags_click_kludge('blur')"
-				reflectpopuplabel="true"
-				sizetopopup="none"
-				maxLength="150"/>
-		</row>
-		<row>
-			<label value="Spaces are allowed in a tag." style="color:grey;"/>
-		</row>
-	</rows>
-</grid>
-
-</dialog>
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://stumbleupon/skin/taggingDialog.css" type="text/css"?>
+
+<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
+
+<dialog id="stumble_tagging_dialog2" title="StumbleUpon Tag"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+  buttons="accept,cancel"
+  persist="screenX screenY"
+  ondialogaccept="return doOK();"
+  onload="init()">
+
+<stringbundleset id="stringbundleset">
+	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
+</stringbundleset>
+
+<script type="application/x-javascript" src="taggingDialog.js"/>
+
+<popupset>
+	<popup id="tagspopup"/>
+</popupset>
+
+<grid flex="1" style="margin:10px">
+  <columns>
+    <column flex="1"/>
+  </columns>
+  <rows>
+    <row>
+			<label value="Enter up to 5 tags, separated by commas:"/>
+		</row>
+		<row>
+			<textbox id="tags"
+				maxrows="14"
+				flex="1"
+				autocompletepopup="tagspopup"
+				inputtooltiptext="Enter Tag Terms separated by Commas"
+				ontextentered="handle_tags_textentered()"
+				ontextreverted="handle_tags_textreverted()"
+				onkeyup="handle_tags_keyup(event)"
+				onfocus="handle_tags_focus()"
+				onclick="tags_click_kludge('click')"
+				onblur="tags_click_kludge('blur')"
+				reflectpopuplabel="true"
+				sizetopopup="none"
+				maxLength="150"/>
+		</row>
+		<row>
+			<label value="Spaces are allowed in a tag." style="color:grey;"/>
+		</row>
+	</rows>
+</grid>
+
+</dialog>
diff --git a/chrome/stumbleupon.jar!/content/tldEmulation.js b/content/tldEmulation.js
similarity index 98%
rename from chrome/stumbleupon.jar!/content/tldEmulation.js
rename to content/tldEmulation.js
index 98fc269..f637ea3 100644
--- a/chrome/stumbleupon.jar!/content/tldEmulation.js
+++ b/content/tldEmulation.js
@@ -1,63 +1,67 @@
-/***** BEGIN LICENSE BLOCK *****
-
-NoScript - a Firefox extension for whitelist driven safe JavaScript execution
-Copyright (C) 2004-2008 Giorgio Maone - g.maone at informaction.com
-
-Contributors: 
-  Higmmer
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-=== StumbleUpon inclusion notes ==
-Changes by StumbleUpon to this file:
- * Added this license block, which is copied from noscriptOverlay.js
- * Added the 'su_' prefix to the global object to move it into the
-   StumbleUpon namespace.
-=====
-
-***** END LICENSE BLOCK *****/
-
-var su_EmulatedTLDService = {
-  _idnService: Components.classes["@mozilla.org/network/idn-service;1"].
-            getService(Components.interfaces.nsIIDNService),
-
-  getBaseDomainFromHost: function(domain) {
-    domain = this._idnService.normalize(domain);
-    var pos = domain.search(this._tldEx);
-    if(pos < 0) {
-      pos = domain.search(this._tldRx);
-      if(pos >= 0) pos = domain.lastIndexOf(".", pos - 1) + 1;
-    } else if(domain[pos] == ".") {
-      ++pos;
-    }
-    return pos < 0 ? domain : domain.substring(pos);
-  },
-
-  getPublicSuffixFromHost: function(domain) {
-    domain = this._idnService.normalize(domain);
-    var pos = domain.search(this._tldEx);
-    if(pos < 0) {
-      pos = domain.search(this._tldRx);
-      if(pos >= 0 && domain[pos] == ".") pos++;
-    } else {
-      pos = domain.indexOf(".", pos + 1) + 1;
-    }
-    return pos < 0 ? "" : domain.substring(pos);
-  },
-  
-  _tldRx: /(?:\.|^)(?:a(?:c(?:\.(?:a[et]|i[mnr]|[bs]e|[cv]n|jp|[kp]r|[mr]w|tj|ug)|cident-(?:investiga|preven)tion\.aero|t\.(?:edu|gov)\.au|a\.pro)?|d(?:ult\.ht|\.jp)?|e(?:ro(?:(?:batic|club|drome)\.aero|port\.fr|\.tt)?|jrie\.no)?|g(?:r(?:ar\.hu|igento\.it|o\.pl)|(?:ents\.aer|denes\.n)o|\.it)?|i(?:r(?:-(?:surveillance|traffic-control)\.aero|(?:(?:craf|por)t|line|traffic)\.aero)|d\.pl)?|m(?:(?:(?:bulance|usement)\.aer|(?:li|ot)\.n)o)?|s(?:s(?:o(?:\.(?:dz|fr|ht|mc|re)|ciation\.aero)|edic\.fr|n\.lk)|coli\-?piceno\.it|n(?:\.lv|es\.no)|k(?:er|im|voll|[oø]y)\.no|ti\.it|eral\.no)?|u(?:t(?:hor\.aero|o\.pl)|r(?:skog-h[oø]land\.no|(?:e|land)\.no)|st(?:evoll|rheim)\.no|(?:dnedaln|kra)\.no|gustow\.pl)|f(?:jord\.no)?|n(?:d(?:ebu|[oø]y|asuolo)\.no|(?:cona)?\.it)?|o(?:st[ae]\.it|\.it)?|q(?:(?:uila)?\.it)?|t(?:\.it|m\.pl)?|z(?:\.us)?|b\.(?:ca|se)|h\.(?:cn|no)|r(?:t(?:\.(?:dz|ht|pl)|s\.(?:nf|ro))|e(?:zzo\.it|(?:mark|ndal)\.no)|\.(?:it|us)|(?:na|dal)\.no)|v(?:o(?:cat|ues)\.fr|e(?:r[oø]y\.no|llino\.it)|\.it)|l(?:es(?:sandria\.it|und\.no)|\.(?:it|no|us)|t(?:o\-?adige\.it|a\.no)|(?:gard|stahaug|aheadju|vdal)\.no)|a(?:rborte)?\.no|k(?:(?:rehamn|noluokta)\.no|\.us)|[wx]|p\.it)|c(?:o(?:m(?:\.(?:a[cfgilnwz]|b[abmos]|c[nu]|d[mz]|e[ces]|g[eipr]|h[knrt]|k[giyz]|l[ckvy]|m[gkow]|n[fr]|p[fhklrst]|r[eouw]|s[cdg]|t[jtw]|u[az]|v[in]|fr|is|jo)|o\.it)?|n(?:f(?:erence\.aero|\.lv)|sult(?:ant|ing)\.aero|trol\.aero)|\.(?:a[gt]|i[mnrt]|j[ep]|m[aw]|t[jt]|u[gsz]|ba|gg|hu|kr|ls|pn|rw)|op(?:\.(?:[ht]t|mw))?|uncil\.aero|senza\.it)|a(?:t(?:an(?:ia|zaro)\.it|ering\.aero)?|s(?:ino\.hu|erta\.it)|\.(?:it|us)|(?:(?:a|rgo)\.aer|hcesuolo\.n)o|(?:gliari|ltanissetta|mpobasso)\.it)?|e(?:rtification\.aero|\.it)|h(?:a(?:m(?:pionship\.aero|bagri\.fr)|rter\.aero)|i(?:rurgiens-dentistes\.fr|eti\.it)|er(?:n(?:igov|ovtsy)\.ua|kassy\.ua)|\.it)?|i(?:vilaviation\.aero|ty\.hu|eszyn\.pl)?|l(?:ub\.(?:aero|tw)|\.it)?|r(?:e(?:w\.aero|mona\.it)|(?:otone)?\.it|imea\.ua)|c(?:i\.fr)?|n(?:\.(?:it|ua))?|u(?:neo\.it)?|v(?:\.ua)?|z(?:e(?:ladz|st)\.pl|\.it)?|t\.(?:it|us)|[dfgmx]|q\.cn|[bs]\.it|(?:áhcesuolo\.n|pa\.pr)o|\.se|k\.ua)|e(?:d(?:u(?:\.(?:a[cflnz]|b[abmos]|c[nu]|e[cs]|g[eipr]|h[knt]|i[nqs]|k[giyz]|l[ckvy]|m[gknow]|p[fhklnrst]|s[cdg]|t[jtw]|v[in]|dz|jo|nr|rw|ua)|cator\.aero)?|\.jp)|n(?:g(?:ine(?:er)?\.aero|(?:erdal\.n|\.pr)o)|(?:tertainment\.aer|ebakk\.n)o|(?:na)?\.it)|x(?:p(?:ress\.aero|erts-comptables\.fr)|change\.aero)|s(?:t\.pr)?|roti[ck]a\.hu|i(?:d(?:s(?:(?:ber|ko)g|voll)\.no|(?:fjord)?\.no)|gersund\.no)|l(?:verum\.no|(?:blag|k)\.pl)|tne(?:dal)?\.no|v(?:en(?:es|(?:ass|ášš)i)\.no|je-og-hornnes\.no)|(?:(?:mergency|quipment)\.aer|gersund\.n)o|164\.arpa|[cu]|(?:\.s)?e|biz\.tw)|g(?:o(?:v(?:\.(?:a[ceflz]|b[abmos]|c[nu]|e(?:c|du)|g[egir]|i[mnqrs]|j[eo]|k[giyz]|l[ckvy]|m[agknow]|p[hklnrst]|s[cdg]|t[jtw]|v[in]|dz|hk|nr|rw|ua)|ernment\.aero)?|b\.(?:bo|es|hn|pk)|uv\.(?:fr|ht|rw)|r(?:izia\.it|lice\.pl)|\.(?:it|jp|kr|tj|ug)|l\.no|[knpsa]\.pk)|l(?:i(?:ding\.aero|wice\.pl)|o(?:ppen\.no|gow\.pl))?|r(?:o(?:u(?:ndhandling|p)\.aero|sseto\.it|ng\.no)|\.(?:it|jp)|a(?:n(?:e|vin)?\.no|tangen\.no|jewo\.pl)|eta\.fr|p\.lk|(?:imstad|ue)\.no)?|d(?:a(?:nsk)?\.pl|\.cn|ynia\.pl)?|s(?:\.(?:a[ah]\.no|h[lm]\.no|n[lt]\.no|o(?:[fl]|slo)\.no|s(?:[ft]|valbard)\.no|t[mr]\.no|v[af]\.no|cn|(?:bu|fm|jan-mayen|mr|rl)\.no)|m\.pl)?|e(?:n(?:ov?a\.it|\.in)|ometre-expert\.fr|\.it)?|a(?:m(?:e(?:s\.hu|\.tw)|vik\.no)|u(?:lar|sdal)\.no|(?:ngaviik|ls|ivuotn)a\.no|\.us)?|i(?:ldesk[aå]l\.no|(?:ske|ehtavuoatna)\.no)?|m(?:ina\.pl)?|á(?:ŋgaviika|(?:lsá|ivuotna)\.no)|j(?:e(?:r(?:drum|stad)\.no|(?:mnes|sdal)\.no)|[oø]vik\.no)|u(?:len|ovdageaidnu)\.no|v\.at|[zx]\.cn|[fgpqwy]|niezno\.pl|\.se)|n(?:e(?:t(?:\.(?:a[cefgilnz]|b[abmos]|c[nu]|d[mz]|g[egpr]|h[knt]|i[mnrs]|j[eo]|k[giyz]|l[kvy]|m[akow]|n[fr]|p[hklnrst]|r[uw]|s[cdg]|t[jtw]|ec|ua|vn))?|\.(?:u[gs]|jp|kr)|s(?:odd(?:tang)?en\.no|\.(?:akershus|buskerud)\.no|se(?:by|t)\.no|na\.no)|ws\.hu|dre-eiker\.no)?|o(?:m(?:\.(?:a[dg]|r[eo]|es|fr|mg|pl)|e\.pt)|t(?:aires\.fr|(?:odden|teroy)\.no)|r(?:d(?:-(?:(?:aur|o)dal|fron)\.no|re(?:-land|isa)\.no|(?:dal|kapp)\.no)|e-og-uvdal\.no)|(?:vara)?\.it|waruda\.pl)?|a(?:m(?:e(?:\.(?:a[ez]|t[jt]|[hp]r|vn))?|s(?:os|skogan)\.no|dalseid\.no)|v(?:igation\.aer|uotna\.n)o|p(?:oli|les)\.it|r(?:vi(?:k|ika)\.no|oy\.no)|\.it|(?:amesjevuemie|nnestad|ustdal)\.no|klo\.pl)?|s(?:w\.(?:edu|gov)\.au|\.ca|n\.us)|t\.(?:(?:edu|gov)\.au|ca|[nr]o)|f(?:\.ca)?|l(?:\.(?:ca|no))?|u(?:\.(?:ca|it)|oro\.it)?|m\.(?:cn|us)|i(?:c\.i[mn]|(?:ss|tt)edal\.no|eruchomosci\.pl|kolaev\.ua)|g(?:o\.(?:p[hl]|lk))?|c(?:\.us)?|y(?:sa\.pl|\.us)|b\.ca|x\.cn|(?:ávuotna|ååmesjevuemie|(?:æ|øtte)røy)\.no|r|\.se|[dhjv]\.us)|m(?:i(?:l(?:\.(?:a[cez]|b[ao]|k[gz]|p[hl]|t[jw]|ec|[gs]e|[hi]n|[jn]o|lv|mg|rw)|ano?\.it)?|\.(?:it|us)|d(?:sund|tre-gauldal)\.no|el(?:ec|no)\.pl|crolight\.aero|asta\.pl)|a(?:i(?:ntenance\.aero|l\.pl)|r(?:ke(?:tplace\.aer|r\.n)o|nardal\.no)|n(?:tova\.it|dal\.no)|s(?:sa\-?carrara\.it|(?:oy|fjorden)\.no)|t(?:era\.it|ta-varjjat\.no)|l(?:(?:vik|selv|atvuopmi)\.no|(?:bork|opolska)\.pl)|z(?:owsze|ury)\.pl|gazine\.aero|cerata\.it|\.us)?|e(?:d(?:ia\.(?:aero|hu|pl)|\.(?:p(?:l|ro)|ec|ht|ly|sd)|ecin\.fr)|\.(?:it|us)|l(?:and|dal|hus|[oø]y)\.no|r[aå]ker\.no|ssina\.it)|o(?:d(?:e(?:lling\.aero|na\.it)|\.gi|(?:alen|um)\.no)|\.(?:it|us)|bi(?:\.tt)?|s(?:j[oø]en\.no|(?:(?:kene)?s|vik)\.no)|nza\.it|(?:-i-rana|(?:[aå]rek|ld)e)\.no)?|b(?:\.ca|one\.pl)|c(?:\.it)?|n(?:\.(?:it|us))?|s(?:\.(?:it|us))?|t\.(?:it|us)|d(?:\.us)?|k(?:\.ua)?|r(?:\.no|agowo\.pl)?|u(?:seum(?:\.(?:no|tt))?|os[aá]t\.no)?|j[oø]ndalen\.no|å(?:søy|lselv)\.no|á(?:latvuopmi|tta-várjjat)\.no|yname\.jo|[ghpqw]|\.se)|o(?:r(?:g(?:\.(?:a[cefgilnz]|b[abmos]|c[nu]|d[mz]|e[ces]|g[egipr]|h[kntu]|i[mnrs]|j[eo]|k[giyz]|l[cksvy]|m[agknow]|p(?:[fhknrst]|l )|r[ou]|s[cdeg]|t[jtw]|v[in]|nr|ua))?|\.(?:u[gs]|[ai]t|jp|kr)|k(?:anger|dal)\.no|s(?:kog|ta)\.no|istano\.it|land\.no)|f(?:f\.ai|\.no)|l(?:\.no|(?:awa|ecko|kusz|sztyn)\.pl)|s(?:\.h(?:edmark|ordaland)\.no|t(?:er[oø]y\.no|r(?:o(?:w(?:iec|wlkp)\.pl|(?:d|lek)a\.pl)|e-toten\.no))|(?:(?:l|[oø]yr)o|en)\.no)|d(?:da\.no|(?:essa)?\.ua)|k(?:snes\.no|\.us)|p(?:p(?:eg[aå]rd\.no|dal\.no)|o(?:czno|le)\.pl)|v(?:erhalla|re-eiker)\.no|y(?:er|garden|stre-slidre)\.no|n\.ca|ther\.nf|masvuotna\.no|\.se|h\.us)|s(?:c(?:h\.(?:l[ky]|[aj]e|gg|ir)|\.(?:u[gs]|cn)|ientist\.aero)?|a(?:\.(?:(?:edu|gov)\.au|it)|l(?:erno\.it|(?:angen|tdal)\.no)|n(?:d(?:nes(?:sj[oø]en\.no|\.no)|e(?:\.(?:m[oø]re-og-romsdal\.no|vestfold\.no)|fjord\.no)|[oø]y\.no)|ok\.pl)|u(?:da|herad)\.no|(?:fety\.aer|(?:mnanger|rpsborg)\.n)o|(?:ssari|vona)\.it)|e(?:x\.(?:hu|pl)|l(?:j(?:e|ord)\.no|(?:bu)?\.no)|rvices\.aero|jny\.pl|c\.ps|bastopol\.ua)?|h(?:o(?:p\.(?:h[tu]|pl)|w\.aero)|\.cn)?|k(?:edsmo(?:korset)?\.no|a(?:n(?:land|it)\.no|un\.no)|i(?:e(?:rv[aá]\.no|n\.no)|(?:ptvet)?\.no)|j(?:erv[oø]y\.no|[aå]k\.no)|o(?:dje\.no|czow\.pl)|(?:ydiving\.aer|(?:ånland|ánit)\.n)o|\.ca|lep\.pl)?|o(?:n(?:dr(?:io\.it|e-land\.no)|gdalen\.no)|\.(?:it|gov\.pl)|gn(?:dal|e)\.no|l(?:a|und)\.no|r(?:-(?:(?:aur|o)dal|fron|varanger)\.no|(?:(?:tlan|fol)d|reisa|um)\.no)|s(?:nowiec)?\.pl|(?:ftware\.aer|(?:kndal|mna)\.n)o|c\.lk|pot\.pl)|t(?:o(?:r(?:e\.(?:nf|ro)|d(?:al)?\.no|(?:-elvdal|fjord)\.no)|kke\.no)|a(?:t(?:helle)?\.no|v(?:ern|anger)\.no|r(?:ostwo\.gov|achowice|gard)\.pl|nge\.no|lowa-wola\.pl)|j(?:ordal(?:shalsen)?\.no|ørdal(?:shalsen)?\.no)|ei(?:gen|nkjer)\.no|r(?:anda?\.no|yn\.no)|(?:udent\.aer|\.n)o)?|d(?:\.(?:cn|us))?|n(?:a(?:sa|ase)\.no|å(?:sa|ase)\.no|\.cn|(?:illfjord|oasa)\.no)?|p(?:ort\.hu|\.it|(?:jelkavik|ydeberg)\.no)|u(?:l(?:i\.hu|(?:a|dal)\.no)|n(?:d|ndal)\.no|edtirol\.it|rnadal\.no|walki\.pl|my\.ua)?|z(?:cz(?:ecin|ytno)\.pl|ex\.hu|kola\.pl)?|v(?:e(?:io|lvik)\.no|\.it|albard\.no)|i(?:e(?:na\.it|llak\.no)|r(?:acusa\.it|dal\.no)|\.it|(?:gdal|ljan)\.no)?|r(?:\.(?:it|gov\.pl))?|l(?:a(?:ttum\.no|sk\.pl)|upsk\.pl)?|ál[áa]t\.no|m(?:[oø]la\.no)?|ø(?:r(?:-(?:(?:aur|o)dal|fron|varanger)\.no|(?:fold|reisa|um)\.no)|(?:gne|mna|ndre-land)\.no)|wi(?:dnica|ebodzin|noujscie)\.pl|x\.cn|s\.it|(?:f|ykkylven)\.no|\.se|g)|p(?:r(?:o(?:\.(?:ae|ec|[ht]t|pr|vn)|duction\.aero|chowice\.pl|f\.pr)?|ess(?:\.(?:aero|se)|e\.fr)|i(?:v\.(?:hu|no|pl)|\.ee)|d\.(?:fr|mg)|(?:ato)?\.it|(?:uszkow|zeworsk)\.pl)?|a(?:r(?:a(?:chut|glid)ing\.aero|ma\.it|ti\.se)|d(?:ov|u)a\.it|\.(?:it|gov\.pl|us)|ssenger-association\.aero|(?:lermo|via)\.it)|i(?:l(?:ot\.aero|a\.pl)|s(?:(?:toi)?a\.it|z\.pl)|(?:acenza)?\.it)|p\.(?:az|ru|se)|e(?:\.(?:ca|it|kr)|r(?:\.(?:nf|sg)|(?:so\.h|ugia\.i)t)|s(?:aro\-?urbino\.it|cara\.it))|o(?:l(?:\.(?:dz|ht)|kowice\.pl|tava\.ua)|r(?:s(?:ang(?:er|u)\.no|(?:áŋgu|grunn)\.no)|t\.fr|denone\.it)|\.(?:it|gov\.pl)|d(?:hal|lasi)e\.pl|mor(?:z|ski)e\.pl|tenza\.it|(?:wiat|znan)\.pl)|h(?:armacien\.fr)?|v(?:t\.ge|\.it)|l(?:c\.(?:co\.im|ly)|o\.ps|\.ua)?|u(?:(?:\.i|bl\.p)t|lawy\.pl)|c\.(?:it|pl)|t(?:\.it)?|n(?:\.it)?|[dgz]\.it|[fks])|b(?:a(?:l(?:l(?:ooning\.aer|angen\.n)o|s(?:an\.it|fjord\.no)|(?:estrand|at)\.no)|r(?:letta(?:andria|-andria-)trani\.it|i\.it|(?:(?:du|um)\.n|\.pr)o)|hcc?avuotna\.no|\.it|(?:mble|(?:jd|i)dar|daddja|tsfjord)\.no|bia-gora\.pl)?|r(?:o(?:nnoy(?:sund)?\.no|ker\.aero)|e(?:scia\.it|manger\.no)|ønnøy(?:sund)?\.no|(?:indisi)?\.it|(?:umunddal|yne)\.no)|i(?:z(?:\.(?:p[klr]|t[jt]|az|ki|mw|nr|vn))?|e(?:l(?:la\.it|awa\.pl)|v[aá]t\.no|szczady\.pl)|al(?:owieza|ystok)\.pl|\.it|(?:ndal|rkenes)\.no)?|e(?:r(?:g(?:amo\.it|(?:en)?\.no)|lev[aå]g\.no)|ar(?:alv[aá]hki\.no|du\.no)|(?:llun|nevent)o\.it|iarn\.no|(?:dzin|skidy)\.pl)?|g(?:\.it)?|j(?:ark[oø]y\.no|\.cn|(?:erkreim|ugn)\.no)?|o(?:l(?:t\.hu|(?:ogna|zano)\.it|eslawiec\.pl)|\.(?:it|(?:telemark|nordland)\.no)|d[oø]\.no|zen\.it|(?:kn|mlo)\.no)?|s(?:\.it)?|y(?:(?:gland|kle)\.no|(?:dgoszcz|tom)\.pl)?|z(?:\.it)?|u(?:dejju)?\.no|á(?:hcc?avuotna\.no|(?:lát|(?:jdda|idá)r)\.no)|å(?:dåddjå|tsfjord)\.no|ø(?:\.(?:telemark|nordland)\.no|mlo\.no)|[bfhmw]|c\.ca|[ln]\.it|ærum\.no|d\.se)|d(?:e(?:(?:sign\.aer|(?:p|atnu)\.n)o|\.us)?|r(?:a(?:mmen|ngedal)\.no|[oø]bak\.no)|o(?:n(?:na\.no|etsk\.ua)|vre\.no)|yr[oø]y\.no|avve(?:nj[aá]rga\.no|siida\.no)|i(?:vt(?:asvuod|tasvuot)na\.no|elddanuorri\.no)|n(?:(?:epropetrovsk)?\.ua|i\.us)|(?:gca\.aer|ønna\.n)o|[jkmz]|lugoleka\.pl|\.se|p\.ua|c\.us)|f(?:e(?:d(?:(?:eration\.aer|je\.n)o|\.us)|r(?:mo|rara)\.it|t(?:sund)?\.no|\.it)|l(?:or(?:ence\.it|[oøa]\.no)|a(?:kstad|tanger)?\.no|e(?:kkefjord|sberg)\.no|(?:ight\.aer|å\.n)o|\.us)|r(?:e(?:i(?:ght\.aer|\.n)o|drikstad\.no)|o(?:s(?:inone\.it|ta\.no)|m\.hr|(?:gn|land|ya)\.no)|\.it|(?:[aæ]n|øy)a\.no)?|u(?:o(?:ssko|isku)\.no|(?:el\.aer|sa\.n)o)|j(?:\.cn|(?:aler|ell)\.no)|i(?:n(?:n[oø]y\.no|\.ec)|r(?:m\.(?:ht|in|nf|ro)|enze\.it)|e\.ee|lm\.hu|\.it|tjar\.no)?|m(?:\.no)?|o(?:r(?:li\-?cesena\.it|um\.hu|(?:sand|de)\.no)|l(?:kebib|lda)l\.no|ggia\.it|snes\.no)?|y(?:lkesbib|resda)l\.no|a(?:(?:rsund|uske)\.no|m\.pk)|[gc]\.it|(?:hs|ørde)\.no|\.se)|h(?:a(?:\.(?:cn|no)|l(?:den|sa)\.no|m(?:ar(?:oy)?\.no|m(?:erfest|arfeasta)\.no)|r(?:am|(?:ei|sta)d)\.no|(?:nggliding\.aer|(?:(?:dse|ttfjellda)l|(?:bme|pmi)r|svik|(?:ugesun|gebosta)d)\.n)o)|o(?:tel\.(?:hu|lk)|b[oø]l\.no|l(?:t[aå]len\.no|(?:e|mestrand)?\.no)|r(?:nindal|ten)\.no|y(?:anger|landet)\.no|(?:mebuilt\.aer|(?:kksund|nefoss|f)\.n)o)|e(?:r(?:oy\.(?:more-og-romsdal|nordland)\.no|øy\.(?:møre-og-romsdal|nordland)\.no|ad\.no )|m(?:nes?\.no|sedal\.no)|(?:\.c|alth\.v)n)|i(?:\.(?:cn|us)|tra\.no)|l\.(?:cn|no)|n(?:\.cn)?|u(?:r(?:dal|um)\.no|issier-justice\.fr)?|m(?:\.no)?|ø(?:y(?:anger|landet)\.no|nefoss\.no)|á(?:(?:bme|pmi)r|mmárfeasta)\.no|j(?:artdal|elmeland)\.no|b\.cn|[krt]|(?:valer|(?:ylle|ægebo)stad|å)\.no|\.se)|i(?:n(?:t(?:\.(?:r[uw]|t[jt]|az|bo|is|lk|mw|pt|vn))?|f(?:o(?:\.(?:h[tu]|n[fr]|p[klr]|az|ec|ki|ro|sd|tt|vn))?|\.cu)|d(?:er[oø]y\.no|\.in)|surance\.aero|-addr\.arpa|gatlan\.hu|\.us)?|d(?:v\.(?:hk|tw)|\.(?:l[vy]|ir|us)|rett\.no)|m(?:(?:peria)?\.it)?|r(?:c\.pl)?|s(?:(?:ernia)?\.it|la\.pr|a\.us)?|v(?:(?:eland|gu)\.no|ano-frankivsk\.ua)|l(?:awa\.pl|\.us)|(?:p6\.arp|f\.u)a|z\.hr|(?:\.s)?e|(?:bestad\.n)?o|[qt]|a\.us)|j(?:o(?:urnal(?:ist)?\.aero|bs(?:\.tt)?|gasz\.hu|(?:rpeland|ndal|lster)\.no)?|e(?:(?:ssheim|vnaker)\.no|lenia-gora\.pl)?|a(?:n-mayen\.no|worzno\.pl)|ø(?:rpeland|lster)\.no|[lsx]\.cn|p|gora\.pl|ur\.pro)|l(?:e(?:a(?:sing\.aer|ngaviika\.n)o|cc[eo]\.it|i(?:r(?:vik|fjord)\.no|kanger\.no)|b(?:esby\.no|ork\.pl)|k(?:a|svik)\.no|\.it|(?:nvik|(?:a?gaviik|sj)a|vanger|rdal)\.no|(?:gnica|zajsk)\.pl)|o(?:di(?:\.it|ngen\.no)|ab[aá]t\.no|m(?:\.no|za\.pl)|(?:gistics\.aer|(?:ppa|renskog|ten)\.n)o|\.it|wicz\.pl)|t(?:d\.(?:gi|co\.im|lk)|\.it)?|a(?:ngev[aå]g\.no|r(?:vik|dal)\.no|va(?:ngen|gis)\.no|kas\.hu|(?:quil|\-?spezi|tin)a\.it|(?:(?:hppi|akesvuemie)\.n|w\.pr)o|py\.pl|\.us)?|c(?:\.it)?|i(?:er(?:ne)?\.no|lle(?:hammer|sand)\.no|nd(?:esne|[aå])s\.no|(?:vorno)?\.it|manowa\.pl)?|u(?:n(?:d|ner)\.no|r[oø]y\.no|(?:cca)?\.it|ster\.no|(?:bin|kow)\.pl|(?:gan|t)sk\.ua)?|g\.(?:jp|ua)|v(?:iv\.ua)?|y(?:ng(?:dal|en)\.no)?|ærdal(?:\.no)?|ø(?:(?:ding|t)en|renskog)\.no|n\.cn|[ks]|áhppi\.no)|r(?:e(?:c(?:\.(?:nf|ro)|reation\.aero)|s(?:\.(?:aero|in)|earch\.aero)|l\.(?:ht|pl)|ggio(?:-(?:calabr|emil)ia\.it|(?:calabr|emil)ia\.it)|\.(?:it|kr)|n(?:ne(?:s[oø]y\.no|bu\.no)|dalen\.no)|pbody\.aero|klam\.hu|alestate\.pl)?|o(?:m(?:s(?:kog|a)\.no|[ae]\.it)|v(?:igo\.it|no\.ua)|y(?:ken|rvik)\.no|(?:torcraft\.aer|(?:an|llag|doy|ros|st)\.n)o|\.it)?|a(?:h(?:olt|kkeravju)\.no|d(?:o(?:y\.no|m\.pl)|(?:øy|e)\.no)|n(?:a|daberg)\.no|(?:(?:gus|venn)a)?\.it|(?:(?:is|um)a|kkestad|lingen)\.no|wa-maz\.pl)|i(?:\.(?:it|us)|n(?:g(?:e(?:bu|rike)\.no|saker\.no)|dal\.no)|s(?:sa|[oø]r)\.no|(?:et|min)i\.it)|å(?:holt|de)\.no|á(?:hkkerávju|isa)\.no|u(?:ovat\.no)?|y(?:gge\.no|bnik\.pl)|ø(?:y(?:ken|rvik)\.no|(?:døy|mskog|ros|st)\.no)|(?:s\.b|v\.u)a|[gcnm]\.it|(?:l|ælingen)\.no|zeszow\.pl|w)|t(?:a(?:s\.(?:edu|gov)\.au|r(?:anto\.it|(?:gi|nobrzeg)\.pl)|na(?:nger)?\.no|xi\.aero|\.it)|r(?:a(?:d(?:er|ing)\.aero|n(?:[boø]y|a)\.no|vel(?:\.(?:pl|tt))?|iner\.aero|pani\.it)|\.(?:it|no)|e(?:nt(?:in)?o\.it|viso\.it)|o(?:ms[oøa]\.no|(?:ndheim|andin|gstad)\.no)|ieste\.it|(?:ysil|æna|øgstad)\.no)|v(?:\.(?:bo|it|sd)|edestrand\.no)?|j(?:\.cn|(?:eldsund|[oø]me)\.no)?|m(?:\.(?:m[cg]|fr|hu|[nr]o|pl|se))?|o(?:r(?:ino\.it|sken\.no)|zsde\.hu|\.it|(?:kke|lga|nsberg)\.no|urism\.pl)?|e(?:r(?:n(?:i\.it|opil\.ua)|amo\.it)|\.(?:it|ua))|ur(?:in\.it|(?:ystyka|ek)\.pl)|n(?:\.(?:it|us))?|i(?:n(?:gvoll|n)\.no|me\.no)|y(?:s(?:v[aæ]r\.no|(?:fjord|nes)\.no)|(?:dal|nset)\.no|chy\.pl)|g(?:ory\.pl)?|(?:[ps]\.i)?t|ønsberg\.no|\.se|[cdfklw]|x\.us)|u(?:n(?:j[aá]rga\.no|ion\.aero|(?:sa|bi)\.ba)|r[in]\.arpa|t(?:azas\.hu|sira\.no|\.us)|d(?:ine)?\.it|l(?:lens(?:aker|vang)\.no|vik\.no)|g(?:\.gov\.pl)?|s(?:(?:enet|tka)\.pl)?|z(?:(?:hgorod)?\.ua)?|(?:(?:po)?w|m)\.gov\.pl|\.se|a)|w(?:o(?:rk(?:inggroup|s)\.aero|(?:dzislaw|lomin)\.pl)|a(?:\.(?:(?:edu|gov)\.au|us)|r(?:mi|szaw)a\.pl|(?:lbrzych|w)\.pl)|e(?:b\.(?:[lp]k|nf|tj)|grow\.pl)|i(?:elun\.pl|\.us)|locl(?:awek)?\.pl|roc(?:law)?\.pl|ww\.ro|\.se|(?:[vy]\.u)?s)|[^\.]+\.(?:a(?:[ru]|(?:(?:ich|omor)i|kita)\.jp)|b[dnrt]|c(?:[kory]|hiba\.jp)|e(?:[grt]|hime\.jp)|f(?:uku(?:i|(?:ok|shim)a)\.jp|[jk])|g(?:u(?:nma\.jp)?|[hnt]|ifu\.jp)|i(?:[dl]|(?:baraki|shikawa|wate)\.jp)|h(?:iroshima|(?:okkaid|yog)o)\.jp|k(?:a(?:g(?:aw|oshim)a\.jp|(?:nagawa|wasaki)\.jp)|o(?:be|chi)\.jp|(?:itakyushu|(?:umam|y)oto)\.jp|[ehw])|m(?:i(?:ya(?:g|zak)i\.jp|e\.jp)|[lmtvxyz])|n(?:a(?:g(?:a(?:no|saki)\.jp|oya\.jp)|ra\.jp)|i(?:igata\.jp)?|[pz])|o(?:k(?:ayam|inaw)a\.jp|(?:it|sak)a\.jp|m)|s(?:a(?:(?:(?:g|itam)a|pporo)\.jp)?|hi(?:(?:g|zuok)a|mane)\.jp|endai\.jp|[bvy]|ch\.uk)|t(?:o(?:k(?:ushima|yo)\.jp|(?:(?:chig|ttor)i|yama)\.jp)|[hrz])|y(?:ama(?:g(?:ata|uchi)\.jp|nashi\.jp)|okohama\.jp|[eu])|l[br]|p[aegwy]|u[ky]|z[amw]|do|jm|wakayama\.jp|qa|ve)|q(?:ld\.(?:edu|gov)\.au|c\.ca|h\.cn)|v(?:i(?:c(?:\.(?:edu|gov)\.au|enza\.it)|bo\-?valentia\.it|k(?:na)?\.no|n(?:dafjord\.no|nica\.ua)|deo\.hu|(?:terbo)?\.it)?|e(?:n(?:(?:ezia|ice)\.it|nesla\.no)|r(?:(?:(?:bani|on)a|celli)\.it|(?:dal|ran)\.no)|g(?:a(?:rshei)?\.no|årshei\.no)|st(?:re-(?:slidre|toten)\.no|v(?:ago|ågø)y\.no|(?:by|nes)\.no)|terinaire\.fr|\.it|(?:fsn|velstad)\.no)|a(?:r(?:d[oø]\.no|ese\.it|(?:ggat|oy)\.no)|\.(?:it|no|us)|ds[oø]\.no|l(?:er\.(?:ostfold|hedmark)\.no|le\.no)|n(?:g|ylven)\.no|g(?:an?\.no|soy\.no)|(?:ksdal|apste)\.no)?|c(?:\.it)?|t\.(?:it|us)|g(?:s\.no)?|o(?:ss(?:evangen)?\.no|(?:lda|agat)\.no)|å(?:g(?:an|søy|å)\.no|ler\.(?:østfold|hedmark)\.no)|n(?:\.ua)?|[brv]\.it|(?:f|árggát|ærøy)\.no|u)|y(?:k\.ca|n\.cn|\.se)|x(?:[jz]\.cn|\.se)|z(?:a(?:(?:chpomor|gan|row|kopane)\.pl|porizhzhe\.ua)|gor(?:a\.pl|zelec\.pl )|j\.cn|\.se|(?:[pt]|hitomir)\.ua)|k(?:o(?:n(?:gs(?:berg|vinger)\.no|yvelo\.hu|(?:in|skowola)\.pl)|(?:mmune|pervik)\.no|(?:bierzyce|lobrzeg)\.pl)|r(?:\.(?:it|ua)|o(?:kstadelva|dsherad)\.no|a(?:ger[oø]\.no|anghke\.no|kow\.pl)|istians[au]nd\.no|(?:åanghke|ødsherad)\.no)?|i(?:r(?:kenes\.no|ovograd\.ua)|ev\.ua|ds\.us)?|m(?:\.ua)?|y(?:\.us)?|a(?:r(?:asjo(?:k|hka)\.no|m[oø]y\.no|lsoy\.no|(?:pacz|tuzy)\.pl)|(?:utokeino|fjord)\.no|(?:lisz|(?:zimierz-doln|szub)y|towice)\.pl)|l(?:(?:epp|[aæ]bu)\.no|odzko\.pl)|v(?:a(?:(?:lsun|fjor)d|m|nangen)\.no|i(?:n(?:esdal|nherad)\.no|t(?:s[oø]y\.no|eseid\.no))|æ(?:fjord|nangen)\.no)|e(?:pno|trzyn)\.pl|h(?:arkov|erson)?\.ua|s\.u[as]|[gnz]|(?:árášjohka|åfjord)\.no|utno\.pl|\.se)|å(?:l(?:(?:går|esun)d)?\.no|m(?:li|ot)\.no|s(?:eral|nes)?\.no|(?:krehamn|fjord|rdal)\.no)|á(?:l(?:tá|aheadju)\.no|kŋoluokta\.no)|ø(?:r(?:s(?:kog|ta)\.no|land\.no)|y(?:er|garden|stre-slidre)\.no|(?:stre-toten|vre-eiker)\.no)|2000\.hu|한글\.kr|`øksnes\.no|6bone\.pl|(?:網路|組織|商業)\.tw)$/
-  ,
-  _tldEx: /(?:\.|^)(?:c(?:ity\.(?:k(?:awasaki|itakyushu|obe|yoto)\.jp|s(?:a(?:itama|pporo)\.jp|(?:endai|hizuoka)\.jp)|(?:chib|(?:fukuo|osa)k|(?:hiroshi|yokoha)m|nagoy)a\.jp)|ongresodelalengua3\.ar)|me(?:con\.ar|tro\.tokyo\.jp)|n(?:a(?:cion\.ar|tional-library-scotland\.uk)|ic\.ar|(?:el|ls)\.uk)|p(?:r(?:ef\.(?:a(?:(?:ich|omor)i|kita)\.jp|fuku(?:i|(?:ok|shim)a)\.jp|g(?:ifu|unma)\.jp|h(?:iroshima|(?:okkaid|yog)o)\.jp|i(?:baraki|shikawa|wate)\.jp|k(?:a(?:g(?:aw|oshim)a\.jp|nagawa\.jp)|(?:ochi|(?:umam|y)oto)\.jp)|mi(?:ya(?:g|zak)i\.jp|e\.jp)|n(?:a(?:ga(?:no|saki)\.jp|ra\.jp)|iigata\.jp)|o(?:k(?:ayam|inaw)a\.jp|(?:it|sak)a\.jp)|s(?:a(?:g|itam)a\.jp|hi(?:(?:g|zuok)a|mane)\.jp)|to(?:(?:chig|ttor)i|(?:kushi|ya)ma)\.jp|yama(?:g(?:ata|uchi)\.jp|nashi\.jp)|(?:(?:chib|wakayam)a|ehime)\.jp)|omocion\.ar)|arliament\.uk)|b(?:l|ritish-library)\.uk|(?:educ|gobiernoelectronico|(?:retin|ub)a)\.ar|(?:icn|j)et\.uk)$/
-}
+/*
+
+**** BEGIN LICENSE BLOCK *****
+
+NoScript - a Firefox extension for whitelist driven safe JavaScript execution
+Copyright (C) 2004-2008 Giorgio Maone - g.maone at informaction.com
+
+Contributors: 
+  Higmmer
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+=== StumbleUpon inclusion notes ==
+Changes by StumbleUpon to this file:
+ * Added this license block, which is copied from noscriptOverlay.js
+ * Added the 'stumbleglobals_' prefix to the global object to move it into the
+   StumbleUpon namespace.
+=====
+
+***** END LICENSE BLOCK ****
+
+*/
+
+StumbleGlobals.EmulatedTLDService = {
+  _idnService: Components.classes["@mozilla.org/network/idn-service;1"].
+            getService(Components.interfaces.nsIIDNService),
+
+  getBaseDomainFromHost: function(domain) {
+    domain = this._idnService.normalize(domain);
+    var pos = domain.search(this._tldEx);
+    if(pos < 0) {
+      pos = domain.search(this._tldRx);
+      if(pos >= 0) pos = domain.lastIndexOf(".", pos - 1) + 1;
+    } else if(domain[pos] == ".") {
+      ++pos;
+    }
+    return pos < 0 ? domain : domain.substring(pos);
+  },
+
+  getPublicSuffixFromHost: function(domain) {
+    domain = this._idnService.normalize(domain);
+    var pos = domain.search(this._tldEx);
+    if(pos < 0) {
+      pos = domain.search(this._tldRx);
+      if(pos >= 0 && domain[pos] == ".") pos++;
+    } else {
+      pos = domain.indexOf(".", pos + 1) + 1;
+    }
+    return pos < 0 ? "" : domain.substring(pos);
+  },
+  
+  _tldRx: /(?:\.|^)(?:a(?:c(?:\.(?:a[et]|i[mnr]|[bs]e|[cv]n|jp|[kp]r|[mr]w|tj|ug)|cident-(?:investiga|preven)tion\.aero|t\.(?:edu|gov)\.au|a\.pro)?|d(?:ult\.ht|\.jp)?|e(?:ro(?:(?:batic|club|drome)\.aero|port\.fr|\.tt)?|jrie\.no)?|g(?:r(?:ar\.hu|igento\.it|o\.pl)|(?:ents\.aer|denes\.n)o|\.it)?|i(?:r(?:-(?:surveillance|traffic-control)\.aero|(?:(?:craf|por)t|line|traffic)\.aero)|d\.pl)?|m(?:(?:(?:bulance|usement)\.aer|(?:li|ot)\.n)o)?|s(?:s(?:o(?:\.(?:dz|fr|ht|mc|re)|ciation\.aero)|edic\.fr|n\.lk)|coli\-?piceno\.it|n(?:\.lv|es\.no)|k(?:er|im|voll|[oø]y)\.no|ti\.it|eral\.no)?|u(?:t(?:hor\.aero|o\.pl)|r(?:skog-h[oø]land\.no|(?:e|land)\.no)|st(?:evoll|rheim)\.no|(?:dnedaln|kra)\.no|gustow\.pl)|f(?:jord\.no)?|n(?:d(?:ebu|[oø]y|asuolo)\.no|(?:cona)?\.it)?|o(?:st[ae]\.it|\.it)?|q(?:(?:uila)?\.it)?|t(?:\.it|m\.pl)?|z(?:\.us)?|b\.(?:ca|se)|h\.(?:cn|no)|r(?:t(?:\.(?:dz|ht|pl)|s\.(?:nf|ro))|e(?:zzo\.it|(?:mark|ndal)\.no)|\.(?:it|us)|(?:na|dal)\.no)|v(?:o(?:cat|ues)\.fr|e(?:r[oø]y\.no|llino\.it)|\.it)|l(?:es(?:sandria\.it|und\.no)|\.(?:it|no|us)|t(?:o\-?adige\.it|a\.no)|(?:gard|stahaug|aheadju|vdal)\.no)|a(?:rborte)?\.no|k(?:(?:rehamn|noluokta)\.no|\.us)|[wx]|p\.it)|c(?:o(?:m(?:\.(?:a[cfgilnwz]|b[abmos]|c[nu]|d[mz]|e[ces]|g[eipr]|h[knrt]|k[giyz]|l[ckvy]|m[gkow]|n[fr]|p[fhklrst]|r[eouw]|s[cdg]|t[jtw]|u[az]|v[in]|fr|is|jo)|o\.it)?|n(?:f(?:erence\.aero|\.lv)|sult(?:ant|ing)\.aero|trol\.aero)|\.(?:a[gt]|i[mnrt]|j[ep]|m[aw]|t[jt]|u[gsz]|ba|gg|hu|kr|ls|pn|rw)|op(?:\.(?:[ht]t|mw))?|uncil\.aero|senza\.it)|a(?:t(?:an(?:ia|zaro)\.it|ering\.aero)?|s(?:ino\.hu|erta\.it)|\.(?:it|us)|(?:(?:a|rgo)\.aer|hcesuolo\.n)o|(?:gliari|ltanissetta|mpobasso)\.it)?|e(?:rtification\.aero|\.it)|h(?:a(?:m(?:pionship\.aero|bagri\.fr)|rter\.aero)|i(?:rurgiens-dentistes\.fr|eti\.it)|er(?:n(?:igov|ovtsy)\.ua|kassy\.ua)|\.it)?|i(?:vilaviation\.aero|ty\.hu|eszyn\.pl)?|l(?:ub\.(?:aero|tw)|\.it)?|r(?:e(?:w\.aero|mona\.it)|(?:otone)?\.it|imea\.ua)|c(?:i\.fr)?|n(?:\.(?:it|ua))?|u(?:neo\.it)?|v(?:\.ua)?|z(?:e(?:ladz|st)\.pl|\.it)?|t\.(?:it|us)|[dfgmx]|q\.cn|[bs]\.it|(?:áhcesuolo\.n|pa\.pr)o|\.se|k\.ua)|e(?:d(?:u(?:\.(?:a[cflnz]|b[abmos]|c[nu]|e[cs]|g[eipr]|h[knt]|i[nqs]|k[giyz]|l[ckvy]|m[gknow]|p[fhklnrst]|s[cdg]|t[jtw]|v[in]|dz|jo|nr|rw|ua)|cator\.aero)?|\.jp)|n(?:g(?:ine(?:er)?\.aero|(?:erdal\.n|\.pr)o)|(?:tertainment\.aer|ebakk\.n)o|(?:na)?\.it)|x(?:p(?:ress\.aero|erts-comptables\.fr)|change\.aero)|s(?:t\.pr)?|roti[ck]a\.hu|i(?:d(?:s(?:(?:ber|ko)g|voll)\.no|(?:fjord)?\.no)|gersund\.no)|l(?:verum\.no|(?:blag|k)\.pl)|tne(?:dal)?\.no|v(?:en(?:es|(?:ass|ášš)i)\.no|je-og-hornnes\.no)|(?:(?:mergency|quipment)\.aer|gersund\.n)o|164\.arpa|[cu]|(?:\.s)?e|biz\.tw)|g(?:o(?:v(?:\.(?:a[ceflz]|b[abmos]|c[nu]|e(?:c|du)|g[egir]|i[mnqrs]|j[eo]|k[giyz]|l[ckvy]|m[agknow]|p[hklnrst]|s[cdg]|t[jtw]|v[in]|dz|hk|nr|rw|ua)|ernment\.aero)?|b\.(?:bo|es|hn|pk)|uv\.(?:fr|ht|rw)|r(?:izia\.it|lice\.pl)|\.(?:it|jp|kr|tj|ug)|l\.no|[knpsa]\.pk)|l(?:i(?:ding\.aero|wice\.pl)|o(?:ppen\.no|gow\.pl))?|r(?:o(?:u(?:ndhandling|p)\.aero|sseto\.it|ng\.no)|\.(?:it|jp)|a(?:n(?:e|vin)?\.no|tangen\.no|jewo\.pl)|eta\.fr|p\.lk|(?:imstad|ue)\.no)?|d(?:a(?:nsk)?\.pl|\.cn|ynia\.pl)?|s(?:\.(?:a[ah]\.no|h[lm]\.no|n[lt]\.no|o(?:[fl]|slo)\.no|s(?:[ft]|valbard)\.no|t[mr]\.no|v[af]\.no|cn|(?:bu|fm|jan-mayen|mr|rl)\.no)|m\.pl)?|e(?:n(?:ov?a\.it|\.in)|ometre-expert\.fr|\.it)?|a(?:m(?:e(?:s\.hu|\.tw)|vik\.no)|u(?:lar|sdal)\.no|(?:ngaviik|ls|ivuotn)a\.no|\.us)?|i(?:ldesk[aå]l\.no|(?:ske|ehtavuoatna)\.no)?|m(?:ina\.pl)?|á(?:ŋgaviika|(?:lsá|ivuotna)\.no)|j(?:e(?:r(?:drum|stad)\.no|(?:mnes|sdal)\.no)|[oø]vik\.no)|u(?:len|ovdageaidnu)\.no|v\.at|[zx]\.cn|[fgpqwy]|niezno\.pl|\.se)|n(?:e(?:t(?:\.(?:a[cefgilnz]|b[abmos]|c[nu]|d[mz]|g[egpr]|h[knt]|i[mnrs]|j[eo]|k[giyz]|l[kvy]|m[akow]|n[fr]|p[hklnrst]|r[uw]|s[cdg]|t[jtw]|ec|ua|vn))?|\.(?:u[gs]|jp|kr)|s(?:odd(?:tang)?en\.no|\.(?:akershus|buskerud)\.no|se(?:by|t)\.no|na\.no)|ws\.hu|dre-eiker\.no)?|o(?:m(?:\.(?:a[dg]|r[eo]|es|fr|mg|pl)|e\.pt)|t(?:aires\.fr|(?:odden|teroy)\.no)|r(?:d(?:-(?:(?:aur|o)dal|fron)\.no|re(?:-land|isa)\.no|(?:dal|kapp)\.no)|e-og-uvdal\.no)|(?:vara)?\.it|waruda\.pl)?|a(?:m(?:e(?:\.(?:a[ez]|t[jt]|[hp]r|vn))?|s(?:os|skogan)\.no|dalseid\.no)|v(?:igation\.aer|uotna\.n)o|p(?:oli|les)\.it|r(?:vi(?:k|ika)\.no|oy\.no)|\.it|(?:amesjevuemie|nnestad|ustdal)\.no|klo\.pl)?|s(?:w\.(?:edu|gov)\.au|\.ca|n\.us)|t\.(?:(?:edu|gov)\.au|ca|[nr]o)|f(?:\.ca)?|l(?:\.(?:ca|no))?|u(?:\.(?:ca|it)|oro\.it)?|m\.(?:cn|us)|i(?:c\.i[mn]|(?:ss|tt)edal\.no|eruchomosci\.pl|kolaev\.ua)|g(?:o\.(?:p[hl]|lk))?|c(?:\.us)?|y(?:sa\.pl|\.us)|b\.ca|x\.cn|(?:ávuotna|ååmesjevuemie|(?:æ|øtte)røy)\.no|r|\.se|[dhjv]\.us)|m(?:i(?:l(?:\.(?:a[cez]|b[ao]|k[gz]|p[hl]|t[jw]|ec|[gs]e|[hi]n|[jn]o|lv|mg|rw)|ano?\.it)?|\.(?:it|us)|d(?:sund|tre-gauldal)\.no|el(?:ec|no)\.pl|crolight\.aero|asta\.pl)|a(?:i(?:ntenance\.aero|l\.pl)|r(?:ke(?:tplace\.aer|r\.n)o|nardal\.no)|n(?:tova\.it|dal\.no)|s(?:sa\-?carrara\.it|(?:oy|fjorden)\.no)|t(?:era\.it|ta-varjjat\.no)|l(?:(?:vik|selv|atvuopmi)\.no|(?:bork|opolska)\.pl)|z(?:owsze|ury)\.pl|gazine\.aero|cerata\.it|\.us)?|e(?:d(?:ia\.(?:aero|hu|pl)|\.(?:p(?:l|ro)|ec|ht|ly|sd)|ecin\.fr)|\.(?:it|us)|l(?:and|dal|hus|[oø]y)\.no|r[aå]ker\.no|ssina\.it)|o(?:d(?:e(?:lling\.aero|na\.it)|\.gi|(?:alen|um)\.no)|\.(?:it|us)|bi(?:\.tt)?|s(?:j[oø]en\.no|(?:(?:kene)?s|vik)\.no)|nza\.it|(?:-i-rana|(?:[aå]rek|ld)e)\.no)?|b(?:\.ca|one\.pl)|c(?:\.it)?|n(?:\.(?:it|us))?|s(?:\.(?:it|us))?|t\.(?:it|us)|d(?:\.us)?|k(?:\.ua)?|r(?:\.no|agowo\.pl)?|u(?:seum(?:\.(?:no|tt))?|os[aá]t\.no)?|j[oø]ndalen\.no|å(?:søy|lselv)\.no|á(?:latvuopmi|tta-várjjat)\.no|yname\.jo|[ghpqw]|\.se)|o(?:r(?:g(?:\.(?:a[cefgilnz]|b[abmos]|c[nu]|d[mz]|e[ces]|g[egipr]|h[kntu]|i[mnrs]|j[eo]|k[giyz]|l[cksvy]|m[agknow]|p(?:[fhknrst]|l )|r[ou]|s[cdeg]|t[jtw]|v[in]|nr|ua))?|\.(?:u[gs]|[ai]t|jp|kr)|k(?:anger|dal)\.no|s(?:kog|ta)\.no|istano\.it|land\.no)|f(?:f\.ai|\.no)|l(?:\.no|(?:awa|ecko|kusz|sztyn)\.pl)|s(?:\.h(?:edmark|ordaland)\.no|t(?:er[oø]y\.no|r(?:o(?:w(?:iec|wlkp)\.pl|(?:d|lek)a\.pl)|e-toten\.no))|(?:(?:l|[oø]yr)o|en)\.no)|d(?:da\.no|(?:essa)?\.ua)|k(?:snes\.no|\.us)|p(?:p(?:eg[aå]rd\.no|dal\.no)|o(?:czno|le)\.pl)|v(?:erhalla|re-eiker)\.no|y(?:er|garden|stre-slidre)\.no|n\.ca|ther\.nf|masvuotna\.no|\.se|h\.us)|s(?:c(?:h\.(?:l[ky]|[aj]e|gg|ir)|\.(?:u[gs]|cn)|ientist\.aero)?|a(?:\.(?:(?:edu|gov)\.au|it)|l(?:erno\.it|(?:angen|tdal)\.no)|n(?:d(?:nes(?:sj[oø]en\.no|\.no)|e(?:\.(?:m[oø]re-og-romsdal\.no|vestfold\.no)|fjord\.no)|[oø]y\.no)|ok\.pl)|u(?:da|herad)\.no|(?:fety\.aer|(?:mnanger|rpsborg)\.n)o|(?:ssari|vona)\.it)|e(?:x\.(?:hu|pl)|l(?:j(?:e|ord)\.no|(?:bu)?\.no)|rvices\.aero|jny\.pl|c\.ps|bastopol\.ua)?|h(?:o(?:p\.(?:h[tu]|pl)|w\.aero)|\.cn)?|k(?:edsmo(?:korset)?\.no|a(?:n(?:land|it)\.no|un\.no)|i(?:e(?:rv[aá]\.no|n\.no)|(?:ptvet)?\.no)|j(?:erv[oø]y\.no|[aå]k\.no)|o(?:dje\.no|czow\.pl)|(?:ydiving\.aer|(?:ånland|ánit)\.n)o|\.ca|lep\.pl)?|o(?:n(?:dr(?:io\.it|e-land\.no)|gdalen\.no)|\.(?:it|gov\.pl)|gn(?:dal|e)\.no|l(?:a|und)\.no|r(?:-(?:(?:aur|o)dal|fron|varanger)\.no|(?:(?:tlan|fol)d|reisa|um)\.no)|s(?:nowiec)?\.pl|(?:ftware\.aer|(?:kndal|mna)\.n)o|c\.lk|pot\.pl)|t(?:o(?:r(?:e\.(?:nf|ro)|d(?:al)?\.no|(?:-elvdal|fjord)\.no)|kke\.no)|a(?:t(?:helle)?\.no|v(?:ern|anger)\.no|r(?:ostwo\.gov|achowice|gard)\.pl|nge\.no|lowa-wola\.pl)|j(?:ordal(?:shalsen)?\.no|ørdal(?:shalsen)?\.no)|ei(?:gen|nkjer)\.no|r(?:anda?\.no|yn\.no)|(?:udent\.aer|\.n)o)?|d(?:\.(?:cn|us))?|n(?:a(?:sa|ase)\.no|å(?:sa|ase)\.no|\.cn|(?:illfjord|oasa)\.no)?|p(?:ort\.hu|\.it|(?:jelkavik|ydeberg)\.no)|u(?:l(?:i\.hu|(?:a|dal)\.no)|n(?:d|ndal)\.no|edtirol\.it|rnadal\.no|walki\.pl|my\.ua)?|z(?:cz(?:ecin|ytno)\.pl|ex\.hu|kola\.pl)?|v(?:e(?:io|lvik)\.no|\.it|albard\.no)|i(?:e(?:na\.it|llak\.no)|r(?:acusa\.it|dal\.no)|\.it|(?:gdal|ljan)\.no)?|r(?:\.(?:it|gov\.pl))?|l(?:a(?:ttum\.no|sk\.pl)|upsk\.pl)?|ál[áa]t\.no|m(?:[oø]la\.no)?|ø(?:r(?:-(?:(?:aur|o)dal|fron|varanger)\.no|(?:fold|reisa|um)\.no)|(?:gne|mna|ndre-land)\.no)|wi(?:dnica|ebodzin|noujscie)\.pl|x\.cn|s\.it|(?:f|ykkylven)\.no|\.se|g)|p(?:r(?:o(?:\.(?:ae|ec|[ht]t|pr|vn)|duction\.aero|chowice\.pl|f\.pr)?|ess(?:\.(?:aero|se)|e\.fr)|i(?:v\.(?:hu|no|pl)|\.ee)|d\.(?:fr|mg)|(?:ato)?\.it|(?:uszkow|zeworsk)\.pl)?|a(?:r(?:a(?:chut|glid)ing\.aero|ma\.it|ti\.se)|d(?:ov|u)a\.it|\.(?:it|gov\.pl|us)|ssenger-association\.aero|(?:lermo|via)\.it)|i(?:l(?:ot\.aero|a\.pl)|s(?:(?:toi)?a\.it|z\.pl)|(?:acenza)?\.it)|p\.(?:az|ru|se)|e(?:\.(?:ca|it|kr)|r(?:\.(?:nf|sg)|(?:so\.h|ugia\.i)t)|s(?:aro\-?urbino\.it|cara\.it))|o(?:l(?:\.(?:dz|ht)|kowice\.pl|tava\.ua)|r(?:s(?:ang(?:er|u)\.no|(?:áŋgu|grunn)\.no)|t\.fr|denone\.it)|\.(?:it|gov\.pl)|d(?:hal|lasi)e\.pl|mor(?:z|ski)e\.pl|tenza\.it|(?:wiat|znan)\.pl)|h(?:armacien\.fr)?|v(?:t\.ge|\.it)|l(?:c\.(?:co\.im|ly)|o\.ps|\.ua)?|u(?:(?:\.i|bl\.p)t|lawy\.pl)|c\.(?:it|pl)|t(?:\.it)?|n(?:\.it)?|[dgz]\.it|[fks])|b(?:a(?:l(?:l(?:ooning\.aer|angen\.n)o|s(?:an\.it|fjord\.no)|(?:estrand|at)\.no)|r(?:letta(?:andria|-andria-)trani\.it|i\.it|(?:(?:du|um)\.n|\.pr)o)|hcc?avuotna\.no|\.it|(?:mble|(?:jd|i)dar|daddja|tsfjord)\.no|bia-gora\.pl)?|r(?:o(?:nnoy(?:sund)?\.no|ker\.aero)|e(?:scia\.it|manger\.no)|ønnøy(?:sund)?\.no|(?:indisi)?\.it|(?:umunddal|yne)\.no)|i(?:z(?:\.(?:p[klr]|t[jt]|az|ki|mw|nr|vn))?|e(?:l(?:la\.it|awa\.pl)|v[aá]t\.no|szczady\.pl)|al(?:owieza|ystok)\.pl|\.it|(?:ndal|rkenes)\.no)?|e(?:r(?:g(?:amo\.it|(?:en)?\.no)|lev[aå]g\.no)|ar(?:alv[aá]hki\.no|du\.no)|(?:llun|nevent)o\.it|iarn\.no|(?:dzin|skidy)\.pl)?|g(?:\.it)?|j(?:ark[oø]y\.no|\.cn|(?:erkreim|ugn)\.no)?|o(?:l(?:t\.hu|(?:ogna|zano)\.it|eslawiec\.pl)|\.(?:it|(?:telemark|nordland)\.no)|d[oø]\.no|zen\.it|(?:kn|mlo)\.no)?|s(?:\.it)?|y(?:(?:gland|kle)\.no|(?:dgoszcz|tom)\.pl)?|z(?:\.it)?|u(?:dejju)?\.no|á(?:hcc?avuotna\.no|(?:lát|(?:jdda|idá)r)\.no)|å(?:dåddjå|tsfjord)\.no|ø(?:\.(?:telemark|nordland)\.no|mlo\.no)|[bfhmw]|c\.ca|[ln]\.it|ærum\.no|d\.se)|d(?:e(?:(?:sign\.aer|(?:p|atnu)\.n)o|\.us)?|r(?:a(?:mmen|ngedal)\.no|[oø]bak\.no)|o(?:n(?:na\.no|etsk\.ua)|vre\.no)|yr[oø]y\.no|avve(?:nj[aá]rga\.no|siida\.no)|i(?:vt(?:asvuod|tasvuot)na\.no|elddanuorri\.no)|n(?:(?:epropetrovsk)?\.ua|i\.us)|(?:gca\.aer|ønna\.n)o|[jkmz]|lugoleka\.pl|\.se|p\.ua|c\.us)|f(?:e(?:d(?:(?:eration\.aer|je\.n)o|\.us)|r(?:mo|rara)\.it|t(?:sund)?\.no|\.it)|l(?:or(?:ence\.it|[oøa]\.no)|a(?:kstad|tanger)?\.no|e(?:kkefjord|sberg)\.no|(?:ight\.aer|å\.n)o|\.us)|r(?:e(?:i(?:ght\.aer|\.n)o|drikstad\.no)|o(?:s(?:inone\.it|ta\.no)|m\.hr|(?:gn|land|ya)\.no)|\.it|(?:[aæ]n|øy)a\.no)?|u(?:o(?:ssko|isku)\.no|(?:el\.aer|sa\.n)o)|j(?:\.cn|(?:aler|ell)\.no)|i(?:n(?:n[oø]y\.no|\.ec)|r(?:m\.(?:ht|in|nf|ro)|enze\.it)|e\.ee|lm\.hu|\.it|tjar\.no)?|m(?:\.no)?|o(?:r(?:li\-?cesena\.it|um\.hu|(?:sand|de)\.no)|l(?:kebib|lda)l\.no|ggia\.it|snes\.no)?|y(?:lkesbib|resda)l\.no|a(?:(?:rsund|uske)\.no|m\.pk)|[gc]\.it|(?:hs|ørde)\.no|\.se)|h(?:a(?:\.(?:cn|no)|l(?:den|sa)\.no|m(?:ar(?:oy)?\.no|m(?:erfest|arfeasta)\.no)|r(?:am|(?:ei|sta)d)\.no|(?:nggliding\.aer|(?:(?:dse|ttfjellda)l|(?:bme|pmi)r|svik|(?:ugesun|gebosta)d)\.n)o)|o(?:tel\.(?:hu|lk)|b[oø]l\.no|l(?:t[aå]len\.no|(?:e|mestrand)?\.no)|r(?:nindal|ten)\.no|y(?:anger|landet)\.no|(?:mebuilt\.aer|(?:kksund|nefoss|f)\.n)o)|e(?:r(?:oy\.(?:more-og-romsdal|nordland)\.no|øy\.(?:møre-og-romsdal|nordland)\.no|ad\.no )|m(?:nes?\.no|sedal\.no)|(?:\.c|alth\.v)n)|i(?:\.(?:cn|us)|tra\.no)|l\.(?:cn|no)|n(?:\.cn)?|u(?:r(?:dal|um)\.no|issier-justice\.fr)?|m(?:\.no)?|ø(?:y(?:anger|landet)\.no|nefoss\.no)|á(?:(?:bme|pmi)r|mmárfeasta)\.no|j(?:artdal|elmeland)\.no|b\.cn|[krt]|(?:valer|(?:ylle|ægebo)stad|å)\.no|\.se)|i(?:n(?:t(?:\.(?:r[uw]|t[jt]|az|bo|is|lk|mw|pt|vn))?|f(?:o(?:\.(?:h[tu]|n[fr]|p[klr]|az|ec|ki|ro|sd|tt|vn))?|\.cu)|d(?:er[oø]y\.no|\.in)|surance\.aero|-addr\.arpa|gatlan\.hu|\.us)?|d(?:v\.(?:hk|tw)|\.(?:l[vy]|ir|us)|rett\.no)|m(?:(?:peria)?\.it)?|r(?:c\.pl)?|s(?:(?:ernia)?\.it|la\.pr|a\.us)?|v(?:(?:eland|gu)\.no|ano-frankivsk\.ua)|l(?:awa\.pl|\.us)|(?:p6\.arp|f\.u)a|z\.hr|(?:\.s)?e|(?:bestad\.n)?o|[qt]|a\.us)|j(?:o(?:urnal(?:ist)?\.aero|bs(?:\.tt)?|gasz\.hu|(?:rpeland|ndal|lster)\.no)?|e(?:(?:ssheim|vnaker)\.no|lenia-gora\.pl)?|a(?:n-mayen\.no|worzno\.pl)|ø(?:rpeland|lster)\.no|[lsx]\.cn|p|gora\.pl|ur\.pro)|l(?:e(?:a(?:sing\.aer|ngaviika\.n)o|cc[eo]\.it|i(?:r(?:vik|fjord)\.no|kanger\.no)|b(?:esby\.no|ork\.pl)|k(?:a|svik)\.no|\.it|(?:nvik|(?:a?gaviik|sj)a|vanger|rdal)\.no|(?:gnica|zajsk)\.pl)|o(?:di(?:\.it|ngen\.no)|ab[aá]t\.no|m(?:\.no|za\.pl)|(?:gistics\.aer|(?:ppa|renskog|ten)\.n)o|\.it|wicz\.pl)|t(?:d\.(?:gi|co\.im|lk)|\.it)?|a(?:ngev[aå]g\.no|r(?:vik|dal)\.no|va(?:ngen|gis)\.no|kas\.hu|(?:quil|\-?spezi|tin)a\.it|(?:(?:hppi|akesvuemie)\.n|w\.pr)o|py\.pl|\.us)?|c(?:\.it)?|i(?:er(?:ne)?\.no|lle(?:hammer|sand)\.no|nd(?:esne|[aå])s\.no|(?:vorno)?\.it|manowa\.pl)?|u(?:n(?:d|ner)\.no|r[oø]y\.no|(?:cca)?\.it|ster\.no|(?:bin|kow)\.pl|(?:gan|t)sk\.ua)?|g\.(?:jp|ua)|v(?:iv\.ua)?|y(?:ng(?:dal|en)\.no)?|ærdal(?:\.no)?|ø(?:(?:ding|t)en|renskog)\.no|n\.cn|[ks]|áhppi\.no)|r(?:e(?:c(?:\.(?:nf|ro)|reation\.aero)|s(?:\.(?:aero|in)|earch\.aero)|l\.(?:ht|pl)|ggio(?:-(?:calabr|emil)ia\.it|(?:calabr|emil)ia\.it)|\.(?:it|kr)|n(?:ne(?:s[oø]y\.no|bu\.no)|dalen\.no)|pbody\.aero|klam\.hu|alestate\.pl)?|o(?:m(?:s(?:kog|a)\.no|[ae]\.it)|v(?:igo\.it|no\.ua)|y(?:ken|rvik)\.no|(?:torcraft\.aer|(?:an|llag|doy|ros|st)\.n)o|\.it)?|a(?:h(?:olt|kkeravju)\.no|d(?:o(?:y\.no|m\.pl)|(?:øy|e)\.no)|n(?:a|daberg)\.no|(?:(?:gus|venn)a)?\.it|(?:(?:is|um)a|kkestad|lingen)\.no|wa-maz\.pl)|i(?:\.(?:it|us)|n(?:g(?:e(?:bu|rike)\.no|saker\.no)|dal\.no)|s(?:sa|[oø]r)\.no|(?:et|min)i\.it)|å(?:holt|de)\.no|á(?:hkkerávju|isa)\.no|u(?:ovat\.no)?|y(?:gge\.no|bnik\.pl)|ø(?:y(?:ken|rvik)\.no|(?:døy|mskog|ros|st)\.no)|(?:s\.b|v\.u)a|[gcnm]\.it|(?:l|ælingen)\.no|zeszow\.pl|w)|t(?:a(?:s\.(?:edu|gov)\.au|r(?:anto\.it|(?:gi|nobrzeg)\.pl)|na(?:nger)?\.no|xi\.aero|\.it)|r(?:a(?:d(?:er|ing)\.aero|n(?:[boø]y|a)\.no|vel(?:\.(?:pl|tt))?|iner\.aero|pani\.it)|\.(?:it|no)|e(?:nt(?:in)?o\.it|viso\.it)|o(?:ms[oøa]\.no|(?:ndheim|andin|gstad)\.no)|ieste\.it|(?:ysil|æna|øgstad)\.no)|v(?:\.(?:bo|it|sd)|edestrand\.no)?|j(?:\.cn|(?:eldsund|[oø]me)\.no)?|m(?:\.(?:m[cg]|fr|hu|[nr]o|pl|se))?|o(?:r(?:ino\.it|sken\.no)|zsde\.hu|\.it|(?:kke|lga|nsberg)\.no|urism\.pl)?|e(?:r(?:n(?:i\.it|opil\.ua)|amo\.it)|\.(?:it|ua))|ur(?:in\.it|(?:ystyka|ek)\.pl)|n(?:\.(?:it|us))?|i(?:n(?:gvoll|n)\.no|me\.no)|y(?:s(?:v[aæ]r\.no|(?:fjord|nes)\.no)|(?:dal|nset)\.no|chy\.pl)|g(?:ory\.pl)?|(?:[ps]\.i)?t|ønsberg\.no|\.se|[cdfklw]|x\.us)|u(?:n(?:j[aá]rga\.no|ion\.aero|(?:sa|bi)\.ba)|r[in]\.arpa|t(?:azas\.hu|sira\.no|\.us)|d(?:ine)?\.it|l(?:lens(?:aker|vang)\.no|vik\.no)|g(?:\.gov\.pl)?|s(?:(?:enet|tka)\.pl)?|z(?:(?:hgorod)?\.ua)?|(?:(?:po)?w|m)\.gov\.pl|\.se|a)|w(?:o(?:rk(?:inggroup|s)\.aero|(?:dzislaw|lomin)\.pl)|a(?:\.(?:(?:edu|gov)\.au|us)|r(?:mi|szaw)a\.pl|(?:lbrzych|w)\.pl)|e(?:b\.(?:[lp]k|nf|tj)|grow\.pl)|i(?:elun\.pl|\.us)|locl(?:awek)?\.pl|roc(?:law)?\.pl|ww\.ro|\.se|(?:[vy]\.u)?s)|[^\.]+\.(?:a(?:[ru]|(?:(?:ich|omor)i|kita)\.jp)|b[dnrt]|c(?:[kory]|hiba\.jp)|e(?:[grt]|hime\.jp)|f(?:uku(?:i|(?:ok|shim)a)\.jp|[jk])|g(?:u(?:nma\.jp)?|[hnt]|ifu\.jp)|i(?:[dl]|(?:baraki|shikawa|wate)\.jp)|h(?:iroshima|(?:okkaid|yog)o)\.jp|k(?:a(?:g(?:aw|oshim)a\.jp|(?:nagawa|wasaki)\.jp)|o(?:be|chi)\.jp|(?:itakyushu|(?:umam|y)oto)\.jp|[ehw])|m(?:i(?:ya(?:g|zak)i\.jp|e\.jp)|[lmtvxyz])|n(?:a(?:g(?:a(?:no|saki)\.jp|oya\.jp)|ra\.jp)|i(?:igata\.jp)?|[pz])|o(?:k(?:ayam|inaw)a\.jp|(?:it|sak)a\.jp|m)|s(?:a(?:(?:(?:g|itam)a|pporo)\.jp)?|hi(?:(?:g|zuok)a|mane)\.jp|endai\.jp|[bvy]|ch\.uk)|t(?:o(?:k(?:ushima|yo)\.jp|(?:(?:chig|ttor)i|yama)\.jp)|[hrz])|y(?:ama(?:g(?:ata|uchi)\.jp|nashi\.jp)|okohama\.jp|[eu])|l[br]|p[aegwy]|u[ky]|z[amw]|do|jm|wakayama\.jp|qa|ve)|q(?:ld\.(?:edu|gov)\.au|c\.ca|h\.cn)|v(?:i(?:c(?:\.(?:edu|gov)\.au|enza\.it)|bo\-?valentia\.it|k(?:na)?\.no|n(?:dafjord\.no|nica\.ua)|deo\.hu|(?:terbo)?\.it)?|e(?:n(?:(?:ezia|ice)\.it|nesla\.no)|r(?:(?:(?:bani|on)a|celli)\.it|(?:dal|ran)\.no)|g(?:a(?:rshei)?\.no|årshei\.no)|st(?:re-(?:slidre|toten)\.no|v(?:ago|ågø)y\.no|(?:by|nes)\.no)|terinaire\.fr|\.it|(?:fsn|velstad)\.no)|a(?:r(?:d[oø]\.no|ese\.it|(?:ggat|oy)\.no)|\.(?:it|no|us)|ds[oø]\.no|l(?:er\.(?:ostfold|hedmark)\.no|le\.no)|n(?:g|ylven)\.no|g(?:an?\.no|soy\.no)|(?:ksdal|apste)\.no)?|c(?:\.it)?|t\.(?:it|us)|g(?:s\.no)?|o(?:ss(?:evangen)?\.no|(?:lda|agat)\.no)|å(?:g(?:an|søy|å)\.no|ler\.(?:østfold|hedmark)\.no)|n(?:\.ua)?|[brv]\.it|(?:f|árggát|ærøy)\.no|u)|y(?:k\.ca|n\.cn|\.se)|x(?:[jz]\.cn|\.se)|z(?:a(?:(?:chpomor|gan|row|kopane)\.pl|porizhzhe\.ua)|gor(?:a\.pl|zelec\.pl )|j\.cn|\.se|(?:[pt]|hitomir)\.ua)|k(?:o(?:n(?:gs(?:berg|vinger)\.no|yvelo\.hu|(?:in|skowola)\.pl)|(?:mmune|pervik)\.no|(?:bierzyce|lobrzeg)\.pl)|r(?:\.(?:it|ua)|o(?:kstadelva|dsherad)\.no|a(?:ger[oø]\.no|anghke\.no|kow\.pl)|istians[au]nd\.no|(?:åanghke|ødsherad)\.no)?|i(?:r(?:kenes\.no|ovograd\.ua)|ev\.ua|ds\.us)?|m(?:\.ua)?|y(?:\.us)?|a(?:r(?:asjo(?:k|hka)\.no|m[oø]y\.no|lsoy\.no|(?:pacz|tuzy)\.pl)|(?:utokeino|fjord)\.no|(?:lisz|(?:zimierz-doln|szub)y|towice)\.pl)|l(?:(?:epp|[aæ]bu)\.no|odzko\.pl)|v(?:a(?:(?:lsun|fjor)d|m|nangen)\.no|i(?:n(?:esdal|nherad)\.no|t(?:s[oø]y\.no|eseid\.no))|æ(?:fjord|nangen)\.no)|e(?:pno|trzyn)\.pl|h(?:arkov|erson)?\.ua|s\.u[as]|[gnz]|(?:árášjohka|åfjord)\.no|utno\.pl|\.se)|å(?:l(?:(?:går|esun)d)?\.no|m(?:li|ot)\.no|s(?:eral|nes)?\.no|(?:krehamn|fjord|rdal)\.no)|á(?:l(?:tá|aheadju)\.no|kŋoluokta\.no)|ø(?:r(?:s(?:kog|ta)\.no|land\.no)|y(?:er|garden|stre-slidre)\.no|(?:stre-toten|vre-eiker)\.no)|2000\.hu|한글\.kr|`øksnes\.no|6bone\.pl|(?:網路|組織|商業)\.tw)$/
+  ,
+  _tldEx: /(?:\.|^)(?:c(?:ity\.(?:k(?:awasaki|itakyushu|obe|yoto)\.jp|s(?:a(?:itama|pporo)\.jp|(?:endai|hizuoka)\.jp)|(?:chib|(?:fukuo|osa)k|(?:hiroshi|yokoha)m|nagoy)a\.jp)|ongresodelalengua3\.ar)|me(?:con\.ar|tro\.tokyo\.jp)|n(?:a(?:cion\.ar|tional-library-scotland\.uk)|ic\.ar|(?:el|ls)\.uk)|p(?:r(?:ef\.(?:a(?:(?:ich|omor)i|kita)\.jp|fuku(?:i|(?:ok|shim)a)\.jp|g(?:ifu|unma)\.jp|h(?:iroshima|(?:okkaid|yog)o)\.jp|i(?:baraki|shikawa|wate)\.jp|k(?:a(?:g(?:aw|oshim)a\.jp|nagawa\.jp)|(?:ochi|(?:umam|y)oto)\.jp)|mi(?:ya(?:g|zak)i\.jp|e\.jp)|n(?:a(?:ga(?:no|saki)\.jp|ra\.jp)|iigata\.jp)|o(?:k(?:ayam|inaw)a\.jp|(?:it|sak)a\.jp)|s(?:a(?:g|itam)a\.jp|hi(?:(?:g|zuok)a|mane)\.jp)|to(?:(?:chig|ttor)i|(?:kushi|ya)ma)\.jp|yama(?:g(?:ata|uchi)\.jp|nashi\.jp)|(?:(?:chib|wakayam)a|ehime)\.jp)|omocion\.ar)|arliament\.uk)|b(?:l|ritish-library)\.uk|(?:educ|gobiernoelectronico|(?:retin|ub)a)\.ar|(?:icn|j)et\.uk)$/
+}
diff --git a/chrome/stumbleupon.jar!/content/topics.csv b/content/topics.csv
similarity index 100%
rename from chrome/stumbleupon.jar!/content/topics.csv
rename to content/topics.csv
diff --git a/chrome/stumbleupon.jar!/content/uninstallDialog.xul b/content/uninstallDialog.xul
similarity index 81%
rename from chrome/stumbleupon.jar!/content/uninstallDialog.xul
rename to content/uninstallDialog.xul
index c6ac313..26a281e 100644
--- a/chrome/stumbleupon.jar!/content/uninstallDialog.xul
+++ b/content/uninstallDialog.xul
@@ -1,152 +1,135 @@
-<?xml version="1.0"?>
-
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-
-<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
-
-<dialog id="stumble_signin_dialog" title="StumbleUpon Uninstall Options"
-  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-  buttons="accept"
-  ondialogaccept="return doOK();"
-  onload="init()">
-
-<stringbundleset id="stringbundleset">
-	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
-</stringbundleset>
-
-<script type="application/x-javascript">
-<![CDATA[
-
-var detail;
-var logout;
-var remove_data;
-//var delete_account;
-
-function init()
-{
-	detail = window.arguments[0];
-	logout = document.getElementById("logout");
-	remove_data = document.getElementById("remove-data");
-//	delete_account = document.getElementById("delete-account");
-
-	var logout_warning = document.getElementById("logout-warning");
-	var label_color = document.defaultView.getComputedStyle(logout_warning, "").getPropertyValue("color");
-	
-	if (opener.stumbleid != 0)
-	{
-		var id_str = opener.su_ds.getValue("$nick");
-		id_str = (id_str == "") ? opener.stumbleid.toString() : id_str;
-		logout.label = "Sign out from account '" + id_str + "'.";
-		logout.hidden = false;
-		document.getElementById("logout-warning").hidden = false;
-//		delete_account.label = "Schedule account '" + id_str + "' to be deleted.";
-//		delete_account.hidden = false;
-	}
-	
-	var uninstall = document.getElementById("uninstall");
-	setCheckboxLabelColor(uninstall, label_color);
-	
-	logout.checked = detail.logout;
-	logout.setAttribute("checked-preferred", detail.logout);
-	setCheckboxLabelColor(logout, label_color);
-	
-	remove_data.checked = detail.remove_data;
-	remove_data.setAttribute("checked-preferred", detail.remove_data);
-	setCheckboxLabelColor(remove_data, label_color);
-	
-//	delete_account.checked = detail.delete_account;
-//	delete_account.setAttribute("checked-preferred", detail.delete_account);
-
-	refresh();
-}
-
-function setCheckboxLabelColor(element, color)
-{
-	var label = document.getAnonymousElementByAttribute(element, "class", "checkbox-label");
-	label.setAttribute("style", "color: " + color + ";");
-}
-
-function refresh()
-{
-	var logout = document.getElementById("logout");
-	var remove_data = document.getElementById("remove-data");
-//	var delete_account = document.getElementById("delete-account");
-	
-//	if (delete_account.checked)
-//	{
-//		remove_data.checked = true;
-//		remove_data.disabled = true;
-//	}
-//	else
-//	{
-		remove_data.disabled = false;
-		remove_data.checked = (remove_data.getAttribute("checked-preferred") == "true");
-//	}
-	if (remove_data.checked)
-	{
-		logout.checked = true;
-		logout.disabled = true;
-	}
-	else
-	{
-		logout.disabled = false;
-		logout.checked = (logout.getAttribute("checked-preferred") == "true");
-	}
-}
-
-function handle_checkbox_command(element)
-{
-	element.setAttribute("checked-preferred", element.checked);
-	refresh();
-}
-
-function doOK()
-{
-	detail.logout = logout.checked;
-	detail.remove_data = remove_data.checked;
-//	detail.delete_account = delete_account.checked;
-	
-	return true;
-}
-
- ]]>
-</script>
-
-<vbox style="margin:5px">
-	<groupbox>
-		<caption label="Uninstall Options"/>
-		<checkbox id="uninstall"
-			label="Uninstall the StumbleUpon Toolbar extension."
-			disabled="true"
-			checked="true"/>
-		<hbox>
-			<checkbox id="logout"
-				checked="false"
-				hidden="true"
-				oncommand="handle_checkbox_command(this);"/>
-			<spacer flex="1"/>
-		</hbox>
-		<label id="logout-warning"
-			value="WARNING: If you don't know your password, you will LOSE THIS ACCOUNT."
-			style="margin-left: 28px;"
-			hidden="true"/>
-		<hbox>
-			<checkbox id="remove-data"
-				label="Remove all configuration files."
-				checked="false"
-				oncommand="handle_checkbox_command(this);"/>
-				<spacer flex="1"/>
-		</hbox>
-<!--
-		<hbox>
-			<checkbox id="delete-account"
-				checked="false"
-				hidden="true"
-				oncommand="handle_checkbox_command(this);"/>
-			<spacer flex="1"/>
-		</hbox>
--->
-	</groupbox>
-</vbox>
-
-</dialog>
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<!DOCTYPE window SYSTEM "chrome://stumbleupon/locale/stumbleupon.dtd" >
+
+<dialog id="stumble_signin_dialog" title="StumbleUpon Uninstall Options"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+  buttons="accept"
+  ondialogaccept="return doOK();"
+  onload="init()">
+
+<stringbundleset id="stringbundleset">
+	<stringbundle id="bundle_stumble" src="chrome://stumbleupon/locale/stumbleupon.properties"/>
+</stringbundleset>
+
+<script type="application/x-javascript">
+<![CDATA[
+
+var detail;
+var logout;
+var remove_data;
+
+function init()
+{
+	detail = window.arguments[0];
+	logout = document.getElementById("logout");
+	remove_data = document.getElementById("remove-data");
+
+	var logout_warning = document.getElementById("logout-warning");
+	var label_color = document.defaultView.getComputedStyle(logout_warning, "").getPropertyValue("color");
+	
+	if (opener.stumbleid != 0)
+	{
+		var id_str = opener.StumbleGlobals.ds.getValue("$nick");
+		id_str = (id_str == "") ? opener.stumbleid.toString() : id_str;
+		logout.label = "Sign out from account '" + id_str + "'.";
+		logout.hidden = false;
+		document.getElementById("logout-warning").hidden = false;
+	}
+	
+	var uninstall = document.getElementById("uninstall");
+	setCheckboxLabelColor(uninstall, label_color);
+	
+	logout.checked = detail.logout;
+	logout.setAttribute("checked-preferred", detail.logout);
+	setCheckboxLabelColor(logout, label_color);
+	
+	remove_data.checked = detail.remove_data;
+	remove_data.setAttribute("checked-preferred", detail.remove_data);
+	setCheckboxLabelColor(remove_data, label_color);
+	
+	refresh();
+}
+
+function setCheckboxLabelColor(element, color)
+{
+	var label = document.getAnonymousElementByAttribute(element, "class", "checkbox-label");
+	label.setAttribute("style", "color: " + color + ";");
+}
+
+function refresh()
+{
+	var logout = document.getElementById("logout");
+	var remove_data = document.getElementById("remove-data");
+	remove_data.disabled = false;
+	remove_data.checked = (remove_data.getAttribute("checked-preferred") == "true");
+
+	if (remove_data.checked)
+	{
+		logout.checked = true;
+		logout.disabled = true;
+	}
+	else
+	{
+		logout.disabled = false;
+		logout.checked = (logout.getAttribute("checked-preferred") == "true");
+	}
+}
+
+function handle_checkbox_command(element)
+{
+	element.setAttribute("checked-preferred", element.checked);
+	refresh();
+}
+
+function doOK()
+{
+	detail.logout = logout.checked;
+	detail.remove_data = remove_data.checked;
+	
+	return true;
+}
+
+ ]]>
+</script>
+
+<vbox style="margin:5px">
+	<groupbox>
+		<caption label="Uninstall Options"/>
+		<checkbox id="uninstall"
+			label="Uninstall the StumbleUpon Toolbar extension."
+			disabled="true"
+			checked="true"/>
+		<hbox>
+			<checkbox id="logout"
+				checked="false"
+				hidden="true"
+				oncommand="handle_checkbox_command(this);"/>
+			<spacer flex="1"/>
+		</hbox>
+		<label id="logout-warning"
+			value="WARNING: If you don't know your password, you will LOSE THIS ACCOUNT."
+			style="margin-left: 28px;"
+			hidden="true"/>
+		<hbox>
+			<checkbox id="remove-data"
+				label="Remove all configuration files."
+				checked="false"
+				oncommand="handle_checkbox_command(this);"/>
+				<spacer flex="1"/>
+		</hbox>
+<!--
+		<hbox>
+			<checkbox id="delete-account"
+				checked="false"
+				hidden="true"
+				oncommand="handle_checkbox_command(this);"/>
+			<spacer flex="1"/>
+		</hbox>
+-->
+	</groupbox>
+</vbox>
+
+</dialog>
diff --git a/chrome/stumbleupon.jar!/content/userdb.sql b/content/userdb.sql
similarity index 95%
rename from chrome/stumbleupon.jar!/content/userdb.sql
rename to content/userdb.sql
index 6edaaf0..b8b4608 100644
--- a/chrome/stumbleupon.jar!/content/userdb.sql
+++ b/content/userdb.sql
@@ -1,85 +1,85 @@
--- 1
-
--- metadata for url
-CREATE TABLE IF NOT EXISTS url (
-  urlid TEXT,
-  title TEXT,
-  catid INT,
-  rating INT,
-  rating_applied INT,
-  comment_level INT DEFAULT 0,
-  score INT DEFAULT 0,
-  PRIMARY KEY ( urlid )
-);
-CREATE INDEX IF NOT EXISTS url__rate_event ON url( rating, rating_applied );
-
--- canonizing url map
-CREATE TABLE IF NOT EXISTS url_map (
-  url TEXT,
-  urlid TEXT,
-  PRIMARY KEY ( url )
-);
-
--- canonizing tag map
-CREATE TABLE IF NOT EXISTS tag_map (
-  tag TEXT,
-  tagid INT,
-  PRIMARY KEY ( tag )
-);
-CREATE INDEX IF NOT EXISTS tag_map__tagid ON tag_map( tagid );
-
--- tags for url
-CREATE TABLE IF NOT EXISTS url_tag (
-  urlid TEXT,
-  tagid INT,
-  seq INT DEFAULT 0, -- tag display order
-  tag_applied INT, -- when last applied
-  UNIQUE ( urlid, tagid )
-);
-CREATE INDEX IF NOT EXISTS url_tag__urlid ON url_tag( urlid );
-CREATE INDEX IF NOT EXISTS url_tag__tag_event ON url_tag( tag_applied );
-
-CREATE TABLE IF NOT EXISTS supertopic (
-  label TEXT,
-  bm_folderid INT DEFAULT 0,
-  PRIMARY KEY ( label )
-  UNIQUE ( bm_folderid )
-);
-
-CREATE TABLE IF NOT EXISTS event_log (
-  eventid INTEGER PRIMARY KEY AUTOINCREMENT,
-  type TEXT,
-  detail TEXT DEFAULT '',
-  occurred INT
-);
-CREATE INDEX IF NOT EXISTS event_log__type_occurred ON event_log ( type, occurred );
-
-CREATE TABLE IF NOT EXISTS settings (
-  name TEXT PRIMARY KEY,
-  value TEXT
-);
-
-CREATE TABLE IF NOT EXISTS blocked_domain (
-  domain TEXT,
-  modified INT,
-  active INT,
-  PRIMARY KEY (domain) ON CONFLICT REPLACE
-);
-
-CREATE TABLE IF NOT EXISTS command_queue (
-  seqid INTEGER PRIMARY KEY AUTOINCREMENT,
-  priority INT,
-  command TEXT
-);
-CREATE INDEX IF NOT EXISTS command_queue__priority ON command_queue ( priority DESC, seqid );
-
-CREATE TABLE IF NOT EXISTS stumble_visited_urls (
-  publicid TEXT,
-  stumbletime INT,
-  referralid TEXT DEFAULT '',
-  retrycount INT DEFAULT 0,
-  PRIMARY KEY (publicid, referralid) ON CONFLICT REPLACE
-);
-CREATE INDEX IF NOT EXISTS stumble_visited_urls__stumbletime ON stumble_visited_urls( stumbletime );
-
-
+-- 1
+
+-- metadata for url
+CREATE TABLE IF NOT EXISTS url (
+  urlid TEXT,
+  title TEXT,
+  catid INT,
+  rating INT,
+  rating_applied INT,
+  comment_level INT DEFAULT 0,
+  score INT DEFAULT 0,
+  PRIMARY KEY ( urlid )
+);
+CREATE INDEX IF NOT EXISTS url__rate_event ON url( rating, rating_applied );
+
+-- canonizing url map
+CREATE TABLE IF NOT EXISTS url_map (
+  url TEXT,
+  urlid TEXT,
+  PRIMARY KEY ( url )
+);
+
+-- canonizing tag map
+CREATE TABLE IF NOT EXISTS tag_map (
+  tag TEXT,
+  tagid INT,
+  PRIMARY KEY ( tag )
+);
+CREATE INDEX IF NOT EXISTS tag_map__tagid ON tag_map( tagid );
+
+-- tags for url
+CREATE TABLE IF NOT EXISTS url_tag (
+  urlid TEXT,
+  tagid INT,
+  seq INT DEFAULT 0, -- tag display order
+  tag_applied INT, -- when last applied
+  UNIQUE ( urlid, tagid )
+);
+CREATE INDEX IF NOT EXISTS url_tag__urlid ON url_tag( urlid );
+CREATE INDEX IF NOT EXISTS url_tag__tag_event ON url_tag( tag_applied );
+
+CREATE TABLE IF NOT EXISTS supertopic (
+  label TEXT,
+  bm_folderid INT DEFAULT 0,
+  PRIMARY KEY ( label )
+  UNIQUE ( bm_folderid )
+);
+
+CREATE TABLE IF NOT EXISTS event_log (
+  eventid INTEGER PRIMARY KEY AUTOINCREMENT,
+  type TEXT,
+  detail TEXT DEFAULT '',
+  occurred INT
+);
+CREATE INDEX IF NOT EXISTS event_log__type_occurred ON event_log ( type, occurred );
+
+CREATE TABLE IF NOT EXISTS settings (
+  name TEXT PRIMARY KEY,
+  value TEXT
+);
+
+CREATE TABLE IF NOT EXISTS blocked_domain (
+  domain TEXT,
+  modified INT,
+  active INT,
+  PRIMARY KEY (domain) ON CONFLICT REPLACE
+);
+
+CREATE TABLE IF NOT EXISTS command_queue (
+  seqid INTEGER PRIMARY KEY AUTOINCREMENT,
+  priority INT,
+  command TEXT
+);
+CREATE INDEX IF NOT EXISTS command_queue__priority ON command_queue ( priority DESC, seqid );
+
+CREATE TABLE IF NOT EXISTS stumble_visited_urls (
+  publicid TEXT,
+  stumbletime INT,
+  referralid TEXT DEFAULT '',
+  retrycount INT DEFAULT 0,
+  PRIMARY KEY (publicid, referralid) ON CONFLICT REPLACE
+);
+CREATE INDEX IF NOT EXISTS stumble_visited_urls__stumbletime ON stumble_visited_urls( stumbletime );
+
+
diff --git a/chrome/stumbleupon.jar!/content/widgets.xml b/content/widgets.xml
similarity index 82%
rename from chrome/stumbleupon.jar!/content/widgets.xml
rename to content/widgets.xml
index 909744b..13fe326 100644
--- a/chrome/stumbleupon.jar!/content/widgets.xml
+++ b/content/widgets.xml
@@ -5,14 +5,14 @@
   %textcontextDTD;
 ]>
 
-<bindings id="su_bindings"
+<bindings id="stumbleglobals_bindings"
 			xmlns="http://www.mozilla.org/xbl"
 			xmlns:html="http://www.w3.org/1999/xhtml"
 			xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
 			xmlns:xbl="http://www.mozilla.org/xbl">
 
 			
-  <binding id="su_toolbarbutton" display="xul:button"
+  <binding id="stumbleglobals_toolbarbutton" display="xul:button"
            extends="chrome://global/content/bindings/button.xml#button-base">
     <resources>
       <stylesheet src="chrome://global/skin/toolbarbutton.css"/>
@@ -27,8 +27,136 @@
     </content>
   </binding>
 
+	<binding id="stumbleglobals_referral-menuitem" extends="chrome://global/content/bindings/menu.xml#menuitem">
+		<content>
+			<xul:checkbox anonid="checkbox" style="margin:0px;padding:4px 8px 4px 8px;" allowevents="true" />
+			<xul:vbox anonid="imagebox" allowevents2="true" style="cursor:pointer;width:32px" align="center">
+				<xul:image anonid="image"  xbl:inherits="src=image" style="cursor:pointer" />
+			</xul:vbox>
+			<xul:label anonid="label" allowevents2="true" style="cursor:pointer" xbl:inherits="xbl:text=label,tooltiptext=tooltiptext" />
+			<children />	
+		</content>
+		
+		<implementation>
+			<constructor><![CDATA[
+				// Decide whether to show or hide the checkbox.  Note that we use visibility because
+				// we want to maintain a consistent layout
+				var checkbox = document.getAnonymousElementByAttribute(this, "anonid", "checkbox");
+				
+				var check_enabled = this.getAttribute("checkbox");
+				if(!check_enabled || (check_enabled == "false"))
+					checkbox.style.visibility = "hidden";
+
+				checkbox.addEventListener("click", function(event) {
+					StumbleGlobals.referral_menuitem_checked(event);
+					event.preventDefault();
+				}, false);
+
+				var image_box = document.getAnonymousElementByAttribute(this, "anonid", "imagebox");
+				if(!this.getAttribute("image"))
+					image_box.style.display = "none";
+
+				// We have to do this here because menupopup elements are not XBL bound until they are displayed
+				if(this.checked)
+					checkbox.checked = true;
+
+				// ======================================
+				// Firefox menu activattion bug workaround
+				//
+				// Child elements that have allowevents will cause the menu activation / highlighting
+				// to get messed up when the mouse moves over them (the item gets de-activated).
+				// And this happens asynchronously.  mouseover and mouseout on the parent menuitem are
+				// still behaving properly though, so we use that to track the actual activation and
+				// check at key points whether the activation should be changed. 
+				// ======================================
+				this.is_mouseactive = false;
+
+				var fn_update_menuactive = function(menuitem) {
+					if(menuitem.is_mouseactive)
+					{
+						menuitem.setAttribute("_moz-menuactive", "true");
+					}
+					else
+					{
+						menuitem.removeAttribute("_moz-menuactive");
+					}
+				}
+
+				checkbox.addEventListener("mouseover", function(event) {
+					var menuitem = event.target.parentNode;
+					window.setTimeout(function() {
+						fn_update_menuactive(menuitem);	
+					}, 10);
+				}, false);
+				
+				this.addEventListener("mouseover", function(event) {
+					var me = event.target;
+					me.is_mouseactive = true;
+				}, false);
+				
+				this.addEventListener("mouseout", function(event) {
+					var me = event.target;
+					me.is_mouseactive = false;
+					window.setTimeout(function() {
+						fn_update_menuactive(me);
+					}, 10);
+				}, false);
+			]]></constructor>
+
+			<property	name="checked"
+						onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'checkbox').checked;"
+						onset="document.getAnonymousElementByAttribute(this, 'anonid', 'checkbox').checked = val; return val;" />
+			
+		</implementation>
+	</binding>
+  
+	<binding id="stumbleglobals_referral-popup" extends="chrome://global/content/bindings/popup.xml#popup">
+		<content>
+			<xul:arrowscrollbox class="popup-internal-box" flex="1" orient="vertical">
+				<xul:deck id="stumbleglobals_referral_deck" selectedIndex="0" class="su-referral-popup-topdeck">
+					<xul:vbox id="stumbleglobals_referral_send_facebook_twitter_container">
+							<xul:menuitem class="su-referral-menuitem"
+								image="chrome://stumbleupon/content/skin/favicon_facebook.gif"
+								label="Facebook"
+								onclick="StumbleGlobals.share_facebook()"
+								tooltiptext="Share on Facebook" />
+			
+							<xul:menuitem class="su-referral-menuitem"
+								image="chrome://stumbleupon/content/skin/favicon_twitter.gif"
+								label="Twitter"
+								onclick="StumbleGlobals.share_twitter()"
+								tooltiptext="Share on Twitter" />
+					</xul:vbox>
+					<xul:vbox id="stumbleglobals_referral_send_container" align="center">
+						<xul:hbox flex="1" align="center">
+							<xul:button id="stumbleglobals_referral_send_button" label="Send" oncommand="StumbleGlobals.referral_sendbutton_clicked(event);"/>
+						</xul:hbox>
+					</xul:vbox>
+				</xul:deck>
+				<children />
+			</xul:arrowscrollbox>
+		</content>
+	</binding>
+  
+	<binding id="su-toggle-button" display="xul:button" extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton">
+		<content>
+			<children includes="observes|template|menupopup|panel|tooltip"/>
+			<xul:stack pack="end">
+				<xul:hbox>
+					<xul:image xbl:inherits="validate,src=image,toolbarmode,buttonstyle,label"/>
+				</xul:hbox>
+				<xul:hbox align="end" >
+					<xul:spring flex="1" />
+					<xul:vbox>
+						<xul:label xbl:inherits="value=badge" class="su-toggle-badge" />
+					</xul:vbox>
+				</xul:hbox>
+			</xul:stack>
+			<xul:label class="toolbarbutton-text" crop="right" flex="1" xbl:inherits="value=label,accesskey,crop,toolbarmode,buttonstyle"/>
+		</content>
+	</binding>
 
-  <binding id="su_menuitem-iconic" extends="chrome://global/content/bindings/menu.xml#menuitem">
+  <binding id="stumbleglobals_menuitem-iconic" extends="chrome://global/content/bindings/menu.xml#menuitem">
     <content>
       <xul:hbox class="menu-iconic-left" align="center" pack="end"
                 xbl:inherits="selected,_moz-menuactive,disabled,checked">
@@ -42,7 +170,7 @@
     </content>
   </binding>
 
-	<binding id="su_autocomplete"
+	<binding id="stumbleglobals_autocomplete"
 				extends="chrome://global/content/bindings/textbox.xml#textbox">
 		<resources>
       <stylesheet src="chrome://global/skin/autocomplete.css"/>
@@ -366,7 +494,7 @@
 							var item = document.createElement("menuitem");
 
 							if (navigator.platform.toLowerCase().indexOf("mac") != -1)
-								item.setAttribute("class", "su_macpopup");
+								item.setAttribute("class", "stumbleglobals_macpopup");
 
 							for (var j in results[i])
 							{
@@ -750,7 +878,7 @@
 	</binding>
 
 
-	<binding id="su_autocompletepopup" extends="chrome://global/content/bindings/popup.xml#popup">
+	<binding id="stumbleglobals_autocompletepopup" extends="chrome://global/content/bindings/popup.xml#popup">
 		<implementation>
 			<constructor><![CDATA[
 				this.setAttribute("ignorekeys", "true");
@@ -773,7 +901,7 @@
 	</binding>
 
 
-	<binding id="su_autocompletedropmarker" extends="xul:button">
+	<binding id="stumbleglobals_autocompletedropmarker" extends="xul:button">
 		<content>
 			<xul:image/>
 		</content>
@@ -794,7 +922,7 @@
 		</handlers>
 	</binding>
 
-  <binding id="su_autocompletecontext">
+  <binding id="stumbleglobals_autocompletecontext">
     <content context="_child">
       <children/>
       <xul:menupopup anonid="input-box-contextmenu"
diff --git a/debian/README.debian b/debian/README.debian
deleted file mode 100644
index 1984546..0000000
--- a/debian/README.debian
+++ /dev/null
@@ -1,6 +0,0 @@
-mozilla-stumbleupon for DEBIAN
-----------------------------
-# For detailed insructions see http://www.stumbleupon.com/instructions.html 
-# See http://www.stumbleupon.com/faq.html for a list of Freqeuently asked questions
-
- -- Alan Woodland <ajw2 at aber.ac.uk>, Mon,  2 Jun 2003 12:01:19 +0100.
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644
index 1b1a9fa..0000000
--- a/debian/changelog
+++ /dev/null
@@ -1,343 +0,0 @@
-stumbleupon (3.62-1) unstable; urgency=low
-
-  * New upstream release.
-  * Switch to 3.0 (quilt) source format to get rid of uudecode workaround.
-  * Add debian/source/include-binaries.
-  * Do not mangle upstream version in debian/watch.
-  * Make debian/rules dead simple.
-  * Refresh private_label.patch and local_help.patch.
-  * Add myself to uploaders.
-  * Drop unused build dependencies sharutils and unzip.
-  * Mention Firefox in description.
-  * Bump Standards-Version to 3.8.4.
-  * Add Homepage field.
-  * Add Vcs-Browser and Vcs-Git links.
-  * Rename binary package from mozilla-stumbleupon to xul-ext-stumbleupon
-    according to new policy.
-
- -- Benjamin Drung <bdrung at ubuntu.com>  Thu, 28 Jan 2010 21:53:43 +0100
-
-stumbleupon (3.3.8-3) unstable; urgency=low
-
-  [ Andrea Veri ]
-  * debian/control:
-    - source package renamed from mozilla-stumbleupon to
-      stumbleupon according to xul-ext-$NAME.
-    - bumped standards-version to 3.8.3
-    - added myself as uploader plus DM tag
-    - removed all depends and added xpi:enhances, xpi:recommends,
-      xpi:provides fields introduced with the new m-d 0.16.
-    - bumped dh to level 7.
-    - removed zip B-D, no more needed now.
-    - maintainer moved to Debian Mozilla Extension Maintainers
-      <pkg-mozext-maintainers at lists.alioth.debian.org>
-  * debian/mozilla-stumbleupon.links:
-    - all links removed apart doc one, which is still needed.
-  * debian/rules:
-    - adapted to m-d.
-    - added some override rules to have docs/* installed and decoded
-      properly.
-  * removed all useless scripts such as postrm / postinst, unistall,
-    *.install, chrome.manifest, they are no more needed with 
-    m-d.
-  * debian/patches:
-    - created moving the two needed patches (local_help.patch,
-      private_label.patch) in it.
-  * debian/*.patches:
-    - removed, as far as they are no more needed.
-  * debian/changelog:
-    - target moved from mozilla-stumbleupon to stumbleupon, as per
-      debian/control change.
-  * debian/compat:
-    - bumped to level 7.
-
-  [ Alan Woodland ]
-  * Severely hacked build rule to apply patches!
-
- -- Alan Woodland <awoodland at debian.org>  Sun, 27 Sep 2009 12:28:30 +0100
-
-mozilla-stumbleupon (3.3.8-2) unstable; urgency=low
-
-  * Really fixed standards to 3.8.2 this time
-  * Updated debhelper to version 5
-
- -- Alan Woodland <awoodland at debian.org>  Sat, 25 Jul 2009 20:59:57 +0100
-
-mozilla-stumbleupon (3.3.8-1) unstable; urgency=low
-
-  * New upstream version (Closes: #456285)
-  * Update to standards 3.8.2 (no changes needed)
-  * Merge NMUs (No diffs)
-
- -- Alan Woodland <awoodland at debian.org>  Sat, 25 Jul 2009 20:31:00 +0100
-
-mozilla-stumbleupon (3.1.2-1.1) unstable; urgency=low
-
-  * Non-maintainer upload.
-  * Allow mozilla-stumbleupon to install on iceweasel 3.0.
-    (Closes: #514026).
-
- -- Miguel Landaeta <miguel at miguel.cc>  Tue, 03 Feb 2009 16:49:55 -0430
-
-mozilla-stumbleupon (3.1.2-1) unstable; urgency=low
-
-  * New upstream version
-  * Fixed watch file
-
- -- Alan Woodland <awoodland at debian.org>  Wed, 24 Oct 2007 22:06:31 +0100
-
-mozilla-stumbleupon (3.0.6-1) unstable; urgency=low
-
-  * New upstream release 
-
- -- Alan Woodland <awoodland at debian.org>  Thu, 05 Jul 2007 23:45:05 +0100
-
-mozilla-stumbleupon (2.9.0-1) unstable; urgency=low
-
-  * New upstream version
-  * Fixed depends now to allow iceape or iceweasel (Closes: #406806) 
-
- -- Alan Woodland <awoodland at debian.org>  Sun, 11 Feb 2007 19:06:39 +0000
-
-mozilla-stumbleupon (2.8.9-4) unstable; urgency=low
-
-  * Moved files to /usr/share/iceape/chrome (Closes: #404302) 
-
- -- Alan Woodland <awoodland at debian.org>  Fri, 29 Dec 2006 13:54:29 +0000
-
-mozilla-stumbleupon (2.8.9-3) unstable; urgency=low
-
-  * Adding iceape support 
-
- -- Alan Woodland <awoodland at debian.org>  Mon, 11 Dec 2006 20:05:41 +0000
-
-mozilla-stumbleupon (2.8.9-2) unstable; urgency=low
-
-  * Adding iceweasel support
-  * Dropping obsoleted Mozilla suite support
-  * Fixed possible problem with de-DE locale
-
- -- Alan Woodland <awoodland at debian.org>  Tue, 21 Nov 2006 21:19:05 +0000
-
-mozilla-stumbleupon (2.8.9-1) unstable; urgency=low
-
-  * New upstream release.
-
- -- Alan Woodland <awoodland at debian.org>  Sat, 18 Nov 2006 18:47:34 +0000
-
-mozilla-stumbleupon (2.8.3-1) unstable; urgency=low
-
-  * New upstream release
-  * Hopefully fixed debian/watch now. 
-
- -- Alan Woodland <awoodland at debian.org>  Wed, 26 Jul 2006 22:36:39 +0100
-
-mozilla-stumbleupon (2.7.8-1) unstable; urgency=low
-
-  * New upstream release
-  * Added debian/watch file
-
- -- Alan Woodland <awoodland at debian.org>  Tue,  6 Jun 2006 12:20:10 +0100
-
-mozilla-stumbleupon (2.7.5-1) unstable; urgency=low
-
-  * New upstream release
-  * Updated to standards 3.7.2 (No changes required) 
-
- -- Alan Woodland <awoodland at debian.org>  Thu, 18 May 2006 13:56:34 +0100
-
-mozilla-stumbleupon (2.6.1-1) unstable; urgency=low
-
-  * New upstream release
-  * Updated standards version
-  * Fixed policy violation with locatoin of help
-  * Updated debian/rules to use dh_install and dh_installdirs better
-
- -- Alan Woodland <awoodland at debian.org>  Fri, 21 Apr 2006 00:37:01 +0100
-
-mozilla-stumbleupon (2.6-2) unstable; urgency=low
-
-  * Fixed firefox support
-  * Restructuring for neatnes
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Mon,  3 Apr 2006 14:16:58 +0100
-
-mozilla-stumbleupon (2.6-1) unstable; urgency=low
-
-  * New upstream release
-  * Updated FAQ and help files
-
- -- Alan Woodland <awoodland at debian.org>  Fri, 17 Mar 2006 13:15:21 +0000
-
-mozilla-stumbleupon (2.2-1) unstable; urgency=low
-
-  * New upstream version (Closes: #347332)
-  * Changed maintainer field to reflect new email address
-
- -- Alan Woodland <awoodland at debian.org>  Thu, 16 Mar 2006 16:24:57 +0000
-
-mozilla-stumbleupon (1.99.95-1) unstable; urgency=medium
-
-  * New upstream release
-  * Fixes conflicts with other extensions
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Mon, 25 Apr 2005 00:19:19 +0000
-
-mozilla-stumbleupon (1.99.9-3) unstable; urgency=low
-
-  * Bug with OK button in options menu fixed
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Wed, 10 Nov 2004 21:24:58 +0000
-
-mozilla-stumbleupon (1.99.9-2) unstable; urgency=low
-
-  * Removed legacy extention registration stuff from mozilla-firefox support
-  * Removed mozilla-snapshot references
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Wed, 10 Nov 2004 01:39:27 +0000
-
-mozilla-stumbleupon (1.99.9-1) unstable; urgency=medium
-
-  * New upstream release should solve any problems with Firefox 1.0/RC series
-  * Extension should now be more friendly towards other extensions 
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Tue,  9 Nov 2004 11:54:04 +0000
-
-mozilla-stumbleupon (1.99.8-1) unstable; urgency=low
-
-  *  New upstream release
-  *  Proper thunderbird/firefox extension support (Closes: #244228)
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Sun, 19 Sep 2004 18:26:21 +0100
-
-mozilla-stumbleupon (1.99-1) unstable; urgency=low
-
-  * New upstream release 
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Thu,  3 Jun 2004 20:11:57 +0000
-
-mozilla-stumbleupon (1.90.9-1) unstable; urgency=low
-
-  * New release
-  * Removed firebird dependency (Closes: #237159)
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Sun,  2 May 2004 15:08:42 +0000
-
-mozilla-stumbleupon (1.90.8-1) unstable; urgency=medium
-
-  * Fixes several bugs
-  * New upstream release
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Thu, 15 Apr 2004 17:43:08 +0000
-
-mozilla-stumbleupon (1.90.4-1) unstable; urgency=low
-
-  * Added offline documenatation (Closes: #223510)
-  * New upstream release
-  * Changed to policy version 3.6.1
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Thu, 15 Apr 2004 17:42:57 +0000
-
-mozilla-stumbleupon (1.90.2-1) unstable; urgency=low
-
-  * New upstream relase includes support for Photoblogging amongst other
-    things
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Mon, 19 Jan 2004 11:18:59 +0000
-
-mozilla-stumbleupon (1.90.1-1) unstable; urgency=low
-
-  * New release, general fixes
-  * Added Localisation and French language support
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Wed, 14 Jan 2004 23:28:18 +0000
-
-mozilla-stumbleupon (1.89.9-1) unstable; urgency=high
-
-  * New release, fixes some pretty serious bugs with versions prior to 1.89.5
-    which caused problems server side.
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Tue, 25 Nov 2003 00:39:36 +0000
-
-mozilla-stumbleupon (1.89.5-1) unstable; urgency=low
-
-  * New upstream reslease with several important fixes
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Sun, 16 Nov 2003 15:02:29 +0000
-
-mozilla-stumbleupon (1.89-1) unstable; urgency=low
-
-  * New upstream release again 
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Tue, 28 Oct 2003 13:25:53 +0000
-
-mozilla-stumbleupon (1.87-1) unstable; urgency=low
-
-  * New upstream release, forgot to upload previous one. (Closes: 211216)
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Thu, 25 Sep 2003 10:59:09 +0000
-
-mozilla-stumbleupon (1.82-1) unstable; urgency=low
-
-  * New upstream release
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Thu,  4 Sep 2003 22:37:26 +0000
-
-mozilla-stumbleupon (1.80-1) unstable; urgency=low
-
-  * New Upstream release
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Fri, 15 Aug 2003 00:06:12 +0000
-
-mozilla-stumbleupon (1.79-1) unstable; urgency=low
-
-  * New Upstream release
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Mon,  4 Aug 2003 12:35:23 +0000
-
-mozilla-stumbleupon (1.76-1) unstable; urgency=low
-
-  * New upstream release, adds precaching of urls.
-  * No auto upgrade on debian patch merged upstream
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Fri, 18 Jul 2003 01:54:09 +0000
-
-mozilla-stumbleupon (1.75-1) unstable; urgency=low
-
-  * New Upstream release
-  * Changed to standards version 3.6.0
-  * Removed redundant .xvpics dir that appeared in stumbleupon.jar with this
-    release
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Tue, 15 Jul 2003 00:56:03 +0000
-
-mozilla-stumbleupon (1.73-2) unstable; urgency=low
-
-  * Disabled Autoupgrade feature (Closes: 198993)
-  * Changed to standrards version 3.5.10
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Sat, 28 Jun 2003 23:56:16 +0000
-
-mozilla-stumbleupon (1.73-1) unstable; urgency=low
-
-  * New Upstream release
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Sun,  8 Jun 2003 22:06:12 +0000
-
-mozilla-stumbleupon (1.69-2) unstable; urgency=low
-
-  * Fixed a bug (I hope) with the instalation scripts
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Tue,  3 Jun 2003 16:08:59 +0000
-
-mozilla-stumbleupon (1.69-1) unstable; urgency=low
-
-  * Upstream is now licensed under the MPL
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Mon,  1 Jun 2003 21:48:16 +0100
-
-mozilla-stumbleupon (1.66-1) unstable; urgency=low
-
-  * Initial release (Closes: 195241)
-
- -- Alan Woodland <ajw2 at aber.ac.uk>  Thu, 29 May 2003 13:42:19 +0100
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index 7f8f011..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-7
diff --git a/debian/control b/debian/control
deleted file mode 100644
index 095d7c8..0000000
--- a/debian/control
+++ /dev/null
@@ -1,37 +0,0 @@
-Source: stumbleupon
-Section: web
-Priority: optional
-Maintainer: Debian Mozilla Extension Maintainers <pkg-mozext-maintainers at lists.alioth.debian.org>
-Uploaders: Alan Woodland <awoodland at debian.org>,
-           Andrea Veri <and at debian.org>,
-           Benjamin Drung <bdrung at ubuntu.com>
-DM-Upload-Allowed: yes
-Build-Depends: cdbs, debhelper (>= 7), mozilla-devscripts (>= 0.16~)
-Standards-Version: 3.8.4
-Homepage: https://addons.mozilla.org/firefox/addon/138
-Vcs-Browser: http://git.debian.org/?p=pkg-mozext/stumbleupon.git;a=summary
-Vcs-Git: git://git.debian.org/pkg-mozext/stumbleupon.git
-
-Package: xul-ext-stumbleupon
-Architecture: all
-Depends: ${misc:Depends}
-Recommends: ${xpi:Recommends}
-Provides: ${xpi:Provides}
-Enhances: ${xpi:Enhances}
-Replaces: mozilla-stumbleupon (<< 3.62-1)
-Description: Iceweasel/Firefox addon for sharing interesting websites
- StumbleUpon is a toolbar for Iceweasel/Firefox which
- acts as an intelligent web-browsing tool.
- .
- It facilitates discovery and sharing of great web sites.
- Using collaborative filtering, web page ratings are used
- to recommend high quality pages tailored to your
- preferences.
-
-Package: mozilla-stumbleupon
-Architecture: all
-Depends: xul-ext-stumbleupon, ${misc:Depends}
-Description: transitional dummy package
- This is a transitional dummy package to ease the migration
- from the mozilla-stumbleupon to the new xul-ext-stumbleupon package.
- You can remove it safely.
diff --git a/debian/copyright b/debian/copyright
deleted file mode 100644
index 912d920..0000000
--- a/debian/copyright
+++ /dev/null
@@ -1,464 +0,0 @@
-This package was debianized by Alan Woodland <ajw2 at aber.ac.uk> on
-Thu, 29 May 2003 13:42:19 +0100
-
-It was downloaded from:
-http://stumbleupon.mozdev.org/
-
-Copyright:
-Geoff Smith <geoff at stumbleupon.com>
-
-License:
-
-========================================================================
-Version: MPL 1.1
-
-The contents of these files are subject to the Mozilla Public License Version 
-1.1 (the "License"); you may not use these files except in compliance with 
-the License. You may obtain a copy of the License at 
-http://www.mozilla.org/MPL/ or from the same directory as this file
-
-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 Optimoz.
-
-The Initial Developer of the Original Code is Geoff Smith
-<geoff at stumbleupon.com>
-Portions created by the Initial Developer are Copyright (C) 2002,2003
-the Initial Developer. All Rights Reserved.
-
-Contributor(s):
-Garrett Camp <gmc at stumbleupon.com>
-
-The full text of the MPL is included below:
-
-
-
-
-                          MOZILLA PUBLIC LICENSE
-                                Version 1.1
-
-                              ---------------
-
-1. Definitions.
-
-     1.0.1. "Commercial Use" means distribution or otherwise making the
-     Covered Code available to a third party.
-
-     1.1. "Contributor" means each entity that creates or contributes to
-     the creation of Modifications.
-
-     1.2. "Contributor Version" means the combination of the Original
-     Code, prior Modifications used by a Contributor, and the Modifications
-     made by that particular Contributor.
-
-     1.3. "Covered Code" means the Original Code or Modifications or the
-     combination of the Original Code and Modifications, in each case
-     including portions thereof.
-
-     1.4. "Electronic Distribution Mechanism" means a mechanism generally
-     accepted in the software development community for the electronic
-     transfer of data.
-
-     1.5. "Executable" means Covered Code in any form other than Source
-     Code.
-
-     1.6. "Initial Developer" means the individual or entity identified
-     as the Initial Developer in the Source Code notice required by Exhibit
-     A.
-
-     1.7. "Larger Work" means a work which combines Covered Code or
-     portions thereof with code not governed by the terms of this License.
-
-     1.8. "License" means this document.
-
-     1.8.1. "Licensable" means having the right to grant, to the maximum
-     extent possible, whether at the time of the initial grant or
-     subsequently acquired, any and all of the rights conveyed herein.
-
-     1.9. "Modifications" means any addition to or deletion from the
-     substance or structure of either the Original Code or any previous
-     Modifications. When Covered Code is released as a series of files, a
-     Modification is:
-          A. Any addition to or deletion from the contents of a file
-          containing Original Code or previous Modifications.
-
-          B. Any new file that contains any part of the Original Code or
-          previous Modifications.
-
-     1.10. "Original Code" means Source Code of computer software code
-     which is described in the Source Code notice required by Exhibit A as
-     Original Code, and which, at the time of its release under this
-     License is not already Covered Code governed by this License.
-
-     1.10.1. "Patent Claims" means any patent claim(s), now owned or
-     hereafter acquired, including without limitation,  method, process,
-     and apparatus claims, in any patent Licensable by grantor.
-
-     1.11. "Source Code" means the preferred form of the Covered Code for
-     making modifications to it, including all modules it contains, plus
-     any associated interface definition files, scripts used to control
-     compilation and installation of an Executable, or source code
-     differential comparisons against either the Original Code or another
-     well known, available Covered Code of the Contributor's choice. The
-     Source Code can be in a compressed or archival form, provided the
-     appropriate decompression or de-archiving software is widely available
-     for no charge.
-
-     1.12. "You" (or "Your")  means an individual or a legal entity
-     exercising rights under, and complying with all of the terms of, this
-     License or a future version of this License issued under Section 6.1.
-     For legal entities, "You" includes any entity which controls, is
-     controlled by, or is under common control with You. For purposes of
-     this definition, "control" means (a) the power, direct or indirect,
-     to cause the direction or management of such entity, whether by
-     contract or otherwise, or (b) ownership of more than fifty percent
-     (50%) of the outstanding shares or beneficial ownership of such
-     entity.
-
-2. Source Code License.
-
-     2.1. The Initial Developer Grant.
-     The Initial Developer hereby grants You a world-wide, royalty-free,
-     non-exclusive license, subject to third party intellectual property
-     claims:
-          (a)  under intellectual property rights (other than patent or
-          trademark) Licensable by Initial Developer to use, reproduce,
-          modify, display, perform, sublicense and distribute the Original
-          Code (or portions thereof) with or without Modifications, and/or
-          as part of a Larger Work; and
-
-          (b) under Patents Claims infringed by the making, using or
-          selling of Original Code, to make, have made, use, practice,
-          sell, and offer for sale, and/or otherwise dispose of the
-          Original Code (or portions thereof).
-
-          (c) the licenses granted in this Section 2.1(a) and (b) are
-          effective on the date Initial Developer first distributes
-          Original Code under the terms of this License.
-
-          (d) Notwithstanding Section 2.1(b) above, no patent license is
-          granted: 1) for code that You delete from the Original Code; 2)
-          separate from the Original Code;  or 3) for infringements caused
-          by: i) the modification of the Original Code or ii) the
-          combination of the Original Code with other software or devices.
-
-     2.2. Contributor Grant.
-     Subject to third party intellectual property claims, each Contributor
-     hereby grants You a world-wide, royalty-free, non-exclusive license
-
-          (a)  under intellectual property rights (other than patent or
-          trademark) Licensable by Contributor, to use, reproduce, modify,
-          display, perform, sublicense and distribute the Modifications
-          created by such Contributor (or portions thereof) either on an
-          unmodified basis, with other Modifications, as Covered Code
-          and/or as part of a Larger Work; and
-
-          (b) under Patent Claims infringed by the making, using, or
-          selling of  Modifications made by that Contributor either alone
-          and/or in combination with its Contributor Version (or portions
-          of such combination), to make, use, sell, offer for sale, have
-          made, and/or otherwise dispose of: 1) Modifications made by that
-          Contributor (or portions thereof); and 2) the combination of
-          Modifications made by that Contributor with its Contributor
-          Version (or portions of such combination).
-
-          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
-          effective on the date Contributor first makes Commercial Use of
-          the Covered Code.
-
-          (d)    Notwithstanding Section 2.2(b) above, no patent license is
-          granted: 1) for any code that Contributor has deleted from the
-          Contributor Version; 2)  separate from the Contributor Version;
-          3)  for infringements caused by: i) third party modifications of
-          Contributor Version or ii)  the combination of Modifications made
-          by that Contributor with other software  (except as part of the
-          Contributor Version) or other devices; or 4) under Patent Claims
-          infringed by Covered Code in the absence of Modifications made by
-          that Contributor.
-
-3. Distribution Obligations.
-
-     3.1. Application of License.
-     The Modifications which You create or to which You contribute are
-     governed by the terms of this License, including without limitation
-     Section 2.2. The Source Code version of Covered Code may be
-     distributed only under the terms of this License or a future version
-     of this License released under Section 6.1, and You must include a
-     copy of this License with every copy of the Source Code You
-     distribute. You may not offer or impose any terms on any Source Code
-     version that alters or restricts the applicable version of this
-     License or the recipients' rights hereunder. However, You may include
-     an additional document offering the additional rights described in
-     Section 3.5.
-
-     3.2. Availability of Source Code.
-     Any Modification which You create or to which You contribute must be
-     made available in Source Code form under the terms of this License
-     either on the same media as an Executable version or via an accepted
-     Electronic Distribution Mechanism to anyone to whom you made an
-     Executable version available; and if made available via Electronic
-     Distribution Mechanism, must remain available for at least twelve (12)
-     months after the date it initially became available, or at least six
-     (6) months after a subsequent version of that particular Modification
-     has been made available to such recipients. You are responsible for
-     ensuring that the Source Code version remains available even if the
-     Electronic Distribution Mechanism is maintained by a third party.
-
-     3.3. Description of Modifications.
-     You must cause all Covered Code to which You contribute to contain a
-     file documenting the changes You made to create that Covered Code and
-     the date of any change. You must include a prominent statement that
-     the Modification is derived, directly or indirectly, from Original
-     Code provided by the Initial Developer and including the name of the
-     Initial Developer in (a) the Source Code, and (b) in any notice in an
-     Executable version or related documentation in which You describe the
-     origin or ownership of the Covered Code.
-
-     3.4. Intellectual Property Matters
-          (a) Third Party Claims.
-          If Contributor has knowledge that a license under a third party's
-          intellectual property rights is required to exercise the rights
-          granted by such Contributor under Sections 2.1 or 2.2,
-          Contributor must include a text file with the Source Code
-          distribution titled "LEGAL" which describes the claim and the
-          party making the claim in sufficient detail that a recipient will
-          know whom to contact. If Contributor obtains such knowledge after
-          the Modification is made available as described in Section 3.2,
-          Contributor shall promptly modify the LEGAL file in all copies
-          Contributor makes available thereafter and shall take other steps
-          (such as notifying appropriate mailing lists or newsgroups)
-          reasonably calculated to inform those who received the Covered
-          Code that new knowledge has been obtained.
-
-          (b) Contributor APIs.
-          If Contributor's Modifications include an application programming
-          interface and Contributor has knowledge of patent licenses which
-          are reasonably necessary to implement that API, Contributor must
-          also include this information in the LEGAL file.
-
-               (c)    Representations.
-          Contributor represents that, except as disclosed pursuant to
-          Section 3.4(a) above, Contributor believes that Contributor's
-          Modifications are Contributor's original creation(s) and/or
-          Contributor has sufficient rights to grant the rights conveyed by
-          this License.
-
-     3.5. Required Notices.
-     You must duplicate the notice in Exhibit A in each file of the Source
-     Code.  If it is not possible to put such notice in a particular Source
-     Code file due to its structure, then You must include such notice in a
-     location (such as a relevant directory) where a user would be likely
-     to look for such a notice.  If You created one or more Modification(s)
-     You may add your name as a Contributor to the notice described in
-     Exhibit A.  You must also duplicate this License in any documentation
-     for the Source Code where You describe recipients' rights or ownership
-     rights relating to Covered Code.  You may choose to offer, and to
-     charge a fee for, warranty, support, indemnity or liability
-     obligations to one or more recipients of Covered Code. However, You
-     may do so only on Your own behalf, and not on behalf of the Initial
-     Developer or any Contributor. You must make it absolutely clear than
-     any such warranty, support, indemnity or liability obligation is
-     offered by You alone, and You hereby agree to indemnify the Initial
-     Developer and every Contributor for any liability incurred by the
-     Initial Developer or such Contributor as a result of warranty,
-     support, indemnity or liability terms You offer.
-
-     3.6. Distribution of Executable Versions.
-     You may distribute Covered Code in Executable form only if the
-     requirements of Section 3.1-3.5 have been met for that Covered Code,
-     and if You include a notice stating that the Source Code version of
-     the Covered Code is available under the terms of this License,
-     including a description of how and where You have fulfilled the
-     obligations of Section 3.2. The notice must be conspicuously included
-     in any notice in an Executable version, related documentation or
-     collateral in which You describe recipients' rights relating to the
-     Covered Code. You may distribute the Executable version of Covered
-     Code or ownership rights under a license of Your choice, which may
-     contain terms different from this License, provided that You are in
-     compliance with the terms of this License and that the license for the
-     Executable version does not attempt to limit or alter the recipient's
-     rights in the Source Code version from the rights set forth in this
-     License. If You distribute the Executable version under a different
-     license You must make it absolutely clear that any terms which differ
-     from this License are offered by You alone, not by the Initial
-     Developer or any Contributor. You hereby agree to indemnify the
-     Initial Developer and every Contributor for any liability incurred by
-     the Initial Developer or such Contributor as a result of any such
-     terms You offer.
-
-     3.7. Larger Works.
-     You may create a Larger Work by combining Covered Code with other code
-     not governed by the terms of this License and distribute the Larger
-     Work as a single product. In such a case, You must make sure the
-     requirements of this License are fulfilled for the Covered Code.
-
-4. Inability to Comply Due to Statute or Regulation.
-
-     If it is impossible for You to comply with any of the terms of this
-     License with respect to some or all of the Covered Code due to
-     statute, judicial order, or regulation then You must: (a) comply with
-     the terms of this License to the maximum extent possible; and (b)
-     describe the limitations and the code they affect. Such description
-     must be included in the LEGAL file described in Section 3.4 and must
-     be included with all distributions of the Source Code. Except to the
-     extent prohibited by statute or regulation, such description must be
-     sufficiently detailed for a recipient of ordinary skill to be able to
-     understand it.
-
-5. Application of this License.
-
-     This License applies to code to which the Initial Developer has
-     attached the notice in Exhibit A and to related Covered Code.
-
-6. Versions of the License.
-
-     6.1. New Versions.
-     Netscape Communications Corporation ("Netscape") may publish revised
-     and/or new versions of the License from time to time. Each version
-     will be given a distinguishing version number.
-
-     6.2. Effect of New Versions.
-     Once Covered Code has been published under a particular version of the
-     License, You may always continue to use it under the terms of that
-     version. You may also choose to use such Covered Code under the terms
-     of any subsequent version of the License published by Netscape. No one
-     other than Netscape has the right to modify the terms applicable to
-     Covered Code created under this License.
-
-     6.3. Derivative Works.
-     If You create or use a modified version of this License (which you may
-     only do in order to apply it to code which is not already Covered Code
-     governed by this License), You must (a) rename Your license so that
-     the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
-     "MPL", "NPL" or any confusingly similar phrase do not appear in your
-     license (except to note that your license differs from this License)
-     and (b) otherwise make it clear that Your version of the license
-     contains terms which differ from the Mozilla Public License and
-     Netscape Public License. (Filling in the name of the Initial
-     Developer, Original Code or Contributor in the notice described in
-     Exhibit A shall not of themselves be deemed to be modifications of
-     this License.)
-
-7. DISCLAIMER OF WARRANTY.
-
-     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
-     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
-     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
-     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
-     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
-     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
-     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
-     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
-     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
-     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-8. TERMINATION.
-
-     8.1.  This License and the rights granted hereunder will terminate
-     automatically if You fail to comply with terms herein and fail to cure
-     such breach within 30 days of becoming aware of the breach. All
-     sublicenses to the Covered Code which are properly granted shall
-     survive any termination of this License. Provisions which, by their
-     nature, must remain in effect beyond the termination of this License
-     shall survive.
-
-     8.2.  If You initiate litigation by asserting a patent infringement
-     claim (excluding declatory judgment actions) against Initial Developer
-     or a Contributor (the Initial Developer or Contributor against whom
-     You file such action is referred to as "Participant")  alleging that:
-
-     (a)  such Participant's Contributor Version directly or indirectly
-     infringes any patent, then any and all rights granted by such
-     Participant to You under Sections 2.1 and/or 2.2 of this License
-     shall, upon 60 days notice from Participant terminate prospectively,
-     unless if within 60 days after receipt of notice You either: (i)
-     agree in writing to pay Participant a mutually agreeable reasonable
-     royalty for Your past and future use of Modifications made by such
-     Participant, or (ii) withdraw Your litigation claim with respect to
-     the Contributor Version against such Participant.  If within 60 days
-     of notice, a reasonable royalty and payment arrangement are not
-     mutually agreed upon in writing by the parties or the litigation claim
-     is not withdrawn, the rights granted by Participant to You under
-     Sections 2.1 and/or 2.2 automatically terminate at the expiration of
-     the 60 day notice period specified above.
-
-     (b)  any software, hardware, or device, other than such Participant's
-     Contributor Version, directly or indirectly infringes any patent, then
-     any rights granted to You by such Participant under Sections 2.1(b)
-     and 2.2(b) are revoked effective as of the date You first made, used,
-     sold, distributed, or had made, Modifications made by that
-     Participant.
-
-     8.3.  If You assert a patent infringement claim against Participant
-     alleging that such Participant's Contributor Version directly or
-     indirectly infringes any patent where such claim is resolved (such as
-     by license or settlement) prior to the initiation of patent
-     infringement litigation, then the reasonable value of the licenses
-     granted by such Participant under Sections 2.1 or 2.2 shall be taken
-     into account in determining the amount or value of any payment or
-     license.
-
-     8.4.  In the event of termination under Sections 8.1 or 8.2 above,
-     all end user license agreements (excluding distributors and resellers)
-     which have been validly granted by You or any distributor hereunder
-     prior to termination shall survive termination.
-
-9. LIMITATION OF LIABILITY.
-
-     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
-     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
-     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
-     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
-     ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
-     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
-     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
-     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
-     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
-     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
-     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
-     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
-     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
-     THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
-
-10. U.S. GOVERNMENT END USERS.
-
-     The Covered Code is a "commercial item," as that term is defined in
-     48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
-     software" and "commercial computer software documentation," as such
-     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
-     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
-     all U.S. Government End Users acquire Covered Code with only those
-     rights set forth herein.
-
-11. MISCELLANEOUS.
-
-     This License represents the complete agreement concerning subject
-     matter hereof. If any provision of this License is held to be
-     unenforceable, such provision shall be reformed only to the extent
-     necessary to make it enforceable. This License shall be governed by
-     California law provisions (except to the extent applicable law, if
-     any, provides otherwise), excluding its conflict-of-law provisions.
-     With respect to disputes in which at least one party is a citizen of,
-     or an entity chartered or registered to do business in the United
-     States of America, any litigation relating to this License shall be
-     subject to the jurisdiction of the Federal Courts of the Northern
-     District of California, with venue lying in Santa Clara County,
-     California, with the losing party responsible for costs, including
-     without limitation, court costs and reasonable attorneys' fees and
-     expenses. The application of the United Nations Convention on
-     Contracts for the International Sale of Goods is expressly excluded.
-     Any law or regulation which provides that the language of a contract
-     shall be construed against the drafter shall not apply to this
-     License.
-
-12. RESPONSIBILITY FOR CLAIMS.
-
-     As between Initial Developer and the Contributors, each party is
-     responsible for claims and damages arising, directly or indirectly,
-     out of its utilization of rights under this License and You agree to
-     work with Initial Developer and Contributors to distribute such
-     responsibility on an equitable basis. Nothing herein is intended or
-     shall be deemed to constitute any admission of liability.
diff --git a/debian/doc/faq.html b/debian/doc/faq.html
deleted file mode 100644
index d45d9fd..0000000
--- a/debian/doc/faq.html
+++ /dev/null
@@ -1,256 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
-
-<title>StumbleUpon FAQ</title>
-
-<link href="stumble.css" rel="stylesheet" type="text/css" />
-</head>
-
-<body>
-<table cellspacing=0 cellpadding=10>
-<tr><td>
-<table width=100% cellpadding=8><tr><td class=lightbg>
-<br>
-
-<form method=post action='http://www.stumbleupon.com/ask.php'>
-
-<table cellpadding=0 cellspacing=0><tr><td><input type=text size=50 maxlength=64 name=question value=""><td><input value='Ask Question' type=submit></table>
-</form>
-
-
-<br><span class=bold>A. Stumbling</span><ul><li><a href="#wrongrating">I accidently rated the wrong page, what do I do?</a>
-
-<li><a href="#favorites">Where did My Favorites or Stumble History go?</a>
-<li><a href="#deletehistory">How do I delete my stumble history?</a>
-<li><a href="#shortcuts">Are there keyboard shortcuts for the StumbleUpon toolbar?</a>
-<li><a href="#interests">I changed my interests and clicked Stumble! but nothing changed.</a>
-<li><a href="#localized">How do I see stumbles in my language or relevant to my particular region?</a>
-<li><a href="#popups">Why am I getting pop-up ads?</a>
-</ul><span class=bold>B. Searching</span><ul><li><a href="#searchdiff">What makes StumbleUpon Search different from other search engines?</a>
-</ul><span class=bold>C. Tagging</span><ul><li><a href="#howtotag">How do I apply tags?</a>
-
-<li><a href="#tags">What are tags?</a>
-</ul><span class=bold>D. StumbleUpon Profiles</span><ul><li><a href="#html">How do I add HTML markup to my blog?</a>
-<li><a href="#rss">How do I use the RSS feed on my blog page?</a>
-<li><a href="#fans">What is the colored bar beside stumblers' names?</a>
-</ul><span class=bold>E. Websites in StumbleUpon</span><ul><li><a href="#statistics">How do I see the statistics for a webpage?</a>
-<li><a href="#average">Why don't you show average ratings for websites or top 100 lists?</a>
-<li><a href="#whichtopic">How does StumbleUpon figure out what topic a website is in?</a>
-<li><a href="#brokenlink">How do I report broken links?</a>
-
-<li><a href="#wrongtopic">How do I change a page's topic?</a>
-<li><a href="#spam">Won't StumbleUpon get spammed by people promoting their websites?</a>
-<li><a href="#suggest">How do I suggest a site to be included in your database?</a>
-</ul><span class=bold>F. Your Account</span><ul><li><a href="#twocomputers">How do I use the same account on 2 different computers?</a>
-<li><a href="#twoaccounts">Can I create 2 different accounts on the same computer?</a>
-<li><a href="#email">Where did the email address I entered go?</a>
-<li><a href="#sponsoredstumble">Why can't I change the picture on my profile?</a>
-<li><a href="#restrictions">Why am I unable to post to groups and/or message other stumblers?</a>
-
-<li><a href="#wrongpassword">I changed my password on 1 computer, and now I am getting a wrong password error on my other computer?</a>
-<li><a href="#picture">How do I change my picture?</a>
-<li><a href="#deleteaccount">How do I delete my account?</a>
-<li><a href="#changepassword">How do I change my password?</a>
-<li><a href="#forgotpassword">I forgot my username/password, how do I get it back?</a>
-<li><a href="#badauth">I keep getting Bad Authentication or Wrong Password errors.  How do I fix this?</a>
-<li><a href="#audience">What is audience?</a>
-<li><a href="#aboutme">I put HTML into my 'about me' field and now I can't edit my profile</a>
-<li><a href="#changeinfo">How do I change my personal information?</a>
-
-<li><a href="#nickname">How do I change my nickname?</a>
-</ul><span class=bold>G. Community</span><ul><li><a href="#topstumbler">How do I become a Top Stumbler?</a>
-<li><a href="#ignore">How do I stop another stumbler from messaging me?</a>
-</ul><span class=bold>H. Groups</span><ul><li><a href="#newgroup">How do I start a new group?</a>
-</ul><span class=bold>I. Privacy</span><ul><li><a href="#spyware">Is this spyware?</a>
-</ul><span class=bold>J. StumbleUpon Sponsors</span><ul><li><a href="#sponsors">What are Sponsors?</a>
-</ul><span class=bold>K. Advertising</span><ul><li><a href="#promote">How can I promote StumbleUpon on my site?</a>
-
-</ul><span class=bold>L. Installing/Uninstalling</span><ul><li><a href="#unsupported">Why don't you support Safari or Opera?</a>
-<li><a href="#upgrade">How do I upgrade the StumbleUpon Toolbar?</a>
-<li><a href="#uninstall">How do I uninstall the StumbleUpon Toolbar?</a>
-<li><a href="#browser">StumbleUpon keeps misdetecting my browser</a>
-<li><a href="#install">Why can't I install StumbleUpon?</a>
-</ul><span class=bold>M. Miscellaneous</span><ul><li><a href="#bugs">I found a bug, how do I report it?</a>
-<li><a href="#beta">Are there beta versions of the StumbleUpon toolbar available?</a>
-<li><a href="#hidetoolbar">How do I temporarily hide the toolbar?</a>
-
-<li><a href="#movetoolbar">How do I move the Mozilla/Firefox toolbar to another line?</a>
-<li><a href="#ownclient">Can I write my own client or script to access the StumbleUpon database?</a>
-</ul><br><br><a name="deletehistory"><span class=text1>How do I delete my stumble history?</span></a><br>You currently cannot delete your stumble history, you can only delete your ratings. Stumble history is necessary to make sure you don't see the same sites over and over again. If you are trying to delete your stumble history because someone else is using your computer, the best solution is simply to sign out of your account when you are not using your computer.  Before you sign out, make sure you write down your username and password. Note that no one else can see your stumbles except for you.<p>
-<a name="favorites"><span class=text1>Where did My Favorites or Stumble History go?</span></a><br>My Favorites and Stumble History have been merged into the <i>Pages</i> tab on your profile.  To see them, select <i>Pages I Like</i> or <i>Stumbles</i> from the drop down menu.  Delete buttons for this page will be available soon, for now if you want to delete a site from your favorites, click on it then click the rating button again to undo the rating.<p>
-
-<a name="interests"><span class=text1>I changed my interests and clicked Stumble! but nothing changed.</span></a><br>Remember to click <span class=bold>Save Changes</span> after altering your interests, otherwise you will retain your old interests.<p>
-<a name="localized"><span class=text1>How do I see stumbles in my language or relevant to my particular region?</span></a><br>Currently, StumbleUpon has limited support for languages and region-specific pages.  Correctly entering the languages you would like to see stumbles in, your country, and signing up for any regional topics will increase the chance of seeing localized stumbles.  In the future, StumbleUpon will improve this support and allow stumbling exclusively in non-english pages.<p>
-<a name="popups"><span class=text1>Why am I getting pop-up ads?</span></a><br>Please note that <span class=bold>it is not StumbleUpon generating these ads</span>; it is the site you are stumbling upon. However, they can be removed by using Ad blocking software. To install this software on <i>Internet Explorer</i>, select <span class=bold><i>'Help->Download Ad Blocking'</i></span> from the Toolbars drop down menu. Running this installer (or other adblocking software if you prefer) will stop popups. In <span class=bold>Mozilla or Firefox</span>, popups are blocked automatically by the browser.<p>
-
-<a name="shortcuts"><span class=text1>Are there keyboard shortcuts for the StumbleUpon toolbar?</span></a><br>Only the Netscape/Mozilla/Firefox toolbar has keyboard shortcuts at the moment. The IE Toolbar will have hotkeys in the future. The keys are as follows:<br><br><center> 
-
-<table cellpadding=2 cellspacing=0> <tr><td align=left><b>Function</b></td>
- <td><b>Windows</b></td> 
-<td><b>Mac/Linux</b></td></tr> 
-<tr><td>Stumble!</td> <td>Alt-F1</td> <td>Alt-ESCAPE</td></tr>
-
-<tr><td>Rate the page "I like it!"</td> <td>Alt-F2</td> <td>Alt-F1</td></tr> 
-<tr><td>Rate the page "Not-for-me"</td> <td>Alt-F3</td> <td>Alt-F2</td></tr> 
-<tr><td>View Site Review Page</td> <td>Alt-F5</td><td>Alt-F3</td></tr> 
-
-<tr><td>Toggle toolbar visibility</td> <td>Alt-F11</td> <td>Alt-F11</td></tr> </table></center><p>
-<a name="wrongrating"><span class=text1>I accidently rated the wrong page, what do I do?</span></a><br>If you did not mean to rate the page at all, you can click the same rating button again to undo the rating. If you do not know the exact url of the site you rated, click on your home button, then select <i>Pages I Like</i> from the dropdown to find the site in question. If you are the only person to rate this site, undo-ing the rating will also remove it from the database completely. Please do not ask us to remove a site from our database that other people have rated unless you have an *extremely* good reason. (eg. page includes illegal content)<p>
-<a name="searchdiff"><span class=text1>What makes StumbleUpon Search different from other search engines?</span></a><br>There are 4 main differences:<br>
-<ul>
-
-<li>You can search entirely with the keyboard.  Use the arrow keys to scroll up and down and to go to the next result page, and use the number keys to open results in a new window or tab.  You'll especially appreciate this if you use a laptop.
-<li>Results you have thumbed "I like it" are bumped to the top.
-<li>You get StumbleUpon information on results, including the site's topic, the quality of the site denoted by stars, and the number of reviews.
-<li>Results are personalized to your interests, so different people will see different results for the same search terms.
-</ul><p>
-<a name="howtotag"><span class=text1>How do I apply tags?</span></a><br>There are 3 ways to apply a tag to a website:<br><br>
-1. Using the toolbar... enter some keywords seperated by commas and click the tag icon.<br>
-<img src="images/205screenshot.png"><br><br>
-2. From the reviews page... click "Add Tags or Review" to select from a list of your most popular tags.<br><br>
-3. Using the "Edit" link on your "Entire Blog". Clicking this link will let you add additional tags to sites which you have already commented on.<p>
-<a name="tags"><span class=text1>What are tags?</span></a><br>Tags are descriptive keywords used to organize sites you like. You can apply tags to sites you come across so you can find them easily later, and this also lets other stumblers discover useful sites you've found. You may apply up to 3 tags per website, with each tag having up to 3 words seperated by spaces (maximum 32 characters).<p>
-
-<a name="fans"><span class=text1>What is the colored bar beside stumblers' names?</span></a><br>That bar is the "fan meter". It is a general measure of how many people have added you to their list of friends. The more bars, the the more fans you have relative to other stumblers.<p>
-<a name="html"><span class=text1>How do I add HTML markup to my blog?</span></a><br>Here are some basic HTML markups for your page, but for a more indepth list, please go to <a href="http://mr-helpful.stumbleupon.com/"><b>Mr Helpful's Blog</b></a>.
-
-<p align="left"><b><span class="text1">I want to center my text:</b></span><br />
-</p><center><center>makes my text centered</center></center><br />
-
-<p align="left"><b><span class="text1">I want to make my text look different:<br /></b></p>
-<ul><b>makes <b>bold text</b></b><br />
-
-<i>makes <i>italic text</i></i><br />
-<u>makes <u>underlined text</u></u></ul>
-
-<p align="left"><b><span class="text1">I want my text to be big and red:</b></span><br /></p>
-<ul><font size="4" color="#FF0000">makes <font color="#ff0000" size="4">big red text</font></font></ul>
-
-<p align="left"><b><span class="text1">Text in different sizes</b></span><br /></p>
-<ul><font size="4"><font size="4">makes size 4 text</font></font><br />
-<font size="2"><font size="2">makes size 2 text</font></font><br />
-<font size="1"><font size="1">makes size 1 text</font></font></ul>
-
-<p align="left"><b><span class="text1">I hate Times New Roman. How do I change the font?</b></span><br /></p>
-
-<ul><font face="Arial">makes <font face="Arial">the text in Arial font</font></font><br />
-<font face="Courier New"> <font face="Courier New">makes the text in Courier New</font></font></ul>
-
-<p align="left"><b><span class="text1">How do I make a space in the text?</b></span><br /></p>
-<ul>Typing in &nbsp; will make a   space</ul>
-
-<p align="left"><b><span class="text1">How do I put a break between lines?</b></span><br /></p>
-<ul>Typing in <br> <br />will make the text go down to the next line</ul>
-<ul>Typing in <br> twice (ie: <br><br>)<br /><br />will make the text go down two lines</ul>
-
-Or, if you are typing in basic text, just hit the enter key once for one line, and twice or more for more lines.<br />
-
-<p align="left"><b><span class="text1">I want to add an image to my page:</b></span><br /></p>
-<img src="http://www.stumbleupon.com/images/smalllogo2.jpg"><br /><br />
-Looks like:<br /><br />
-<img src="images/smalllogo2.png"><br /><br />If you're stumbling, just right click the image and choose "StumbleUpon Photoblog It!" <br /><br />* You can also save the image and upload it to one of those free image hosts, like <a href="http://www.photobucket.com">photobucket</a>, <a href="http://www.flickr.com/">flickr</a>, <a href="http://www.imageshack.us">imageshack</a>, <a href="http://www.free-webhosts.com/free-image-hosting.php">etc</a>, then link to it from there.</p>
-
-<p align="left"><b><span class="text1">How do I make a plain text link?</b></span><br /></p>
-<a href="http://www.stumbleupon.com">Click here to visit this website</a><br />
-
-Gives you: <a href="http://www.stumbleupon.com">Click here to visit this website</a><br /></p>
-
-<p align="left"><b><span class="text1">How do I make an email address that people can click on to send me mail?</b></span><br /></p>
-<a href="mailto:yourname at yourwebsite.com">E-mail me</a><br />
-
-Gives you: <a href="mailto:yourname at yourwebsite.com">E-mail me</a><br />
-
-<p align="left"><b><span class="text1">I want to make an image sit to the Left of my text</b></span><br /></p>
-<img src="http://www.stumbleupon.com/images/smalllogo2.jpg" align="left">This is my image, sitting to the left of my text<br /><br />
-<img src="images/smalllogo2.png" align="left">StumbleUpon is an intelligent browsing tool for sharing and discovering great websites. As you click  Stumble!, you'll get high-quality pages matched to your personal preferences. These pages have been explicitly recommended (rated I like it) by friends and other SU members with similar interests. Rating these sites shares them with your friends and peers \u2013 you will automatically 'stumble upon' each others favorites sites.</p>
-
-<p align="left"><b><span class="text1">I want to make an image sit to the Right of my text</b></span><br /></p>
-<img src="http://www.stumbleupon.com/images/smalllogo2.jpg" align="right">This is my image, sitting to the right of my text<br /><br />
-
-<img src="images/smalllogo2.png" align="right">StumbleUpon is an intelligent browsing tool for sharing and discovering great websites. As you click  Stumble!, you'll get high-quality pages matched to your personal preferences. These pages have been explicitly recommended (rated I like it) by friends and other SU members with similar interests. Rating these sites shares them with your friends and peers \u2013 you will automatically 'stumble upon' each others favorites sites.</p><p>
-<a name="rss"><span class=text1>How do I use the RSS feed on my blog page?</span></a><br>There is a description of how to use a StumbleUpon RSS feed <a href="http://www.nogwa.com/article/283/using-the-stumbleupon-xml-feed">here</a>.<p>
-<a name="average"><span class=text1>Why don't you show average ratings for websites or top 100 lists?</span></a><br>Because these statistics foster a competitive atmosphere that would promote spamming among owners of the sites in question.  StumbleUpon is based on showing people sites personalized to their particular interests, not on absolutes like average rating and top 100 lists.<p>
-<a name="brokenlink"><span class=text1>How do I report broken links?</span></a><br>StumbleUpon toolbar detects broken links automatically. If the site is not reporting 404, but the content of the site is gone, you can report the site as misclassified and set it to "NOCAT". In Mozilla/Firefox you can also use Report->Report 404.<p>
-<a name="spam"><span class=text1>Won't StumbleUpon get spammed by people promoting their websites?</span></a><br>No. StumbleUpon recommends pages based on correlation and user clustering, rather than average ratings, so people rating their own sites as 'I like it!' cannot spam the database. Anyone attempting to circumvent or abuse this system is in violation of our <a target=_new href="http://www.stumbleupon.com/terms.html">terms of service</a>, and is subject to prosecution.<p>
-
-<a name="statistics"><span class=text1>How do I see the statistics for a webpage?</span></a><br>Click on the <img src="images/infobutton.png"> button on the StumbleUpon Toolbar while you are on the page in question.<p>
-<a name="suggest"><span class=text1>How do I suggest a site to be included in your database?</span></a><br>To suggest a site, simply visit the site and click <span class=bold>I like it!</span> (<img src="images/thumbup.png">). This allows the website to be instantly shared with other community members who share you interests. Please submit sites which are good starting points for exploration rather than deeply nested pages which are very specific. These sites are more useful to other stumblers, and <span class=bold>improve your future stumbles</span> in the process. If the page you submit is easy to identify and navigate, a larger number of other stumblers will explore and rate related sites. This makes it easy for other members to improve upon your suggestions, and help us find better sites for you! Submitting <span class=bold>interesting, high-quality sites</span> also improves your rank as a top stumbler, since a larger number of people will likely agree with your suggestions.<p>
-
-<a name="whichtopic"><span class=text1>How does StumbleUpon figure out what topic a website is in?</span></a><br>StumbleUpon automatically categorizes pages into over 500 different topics based on the words present on the pages. This system is approximately 90% effective, when it is not we rely on stumblers to correct the mistakes made by the categorizer. In particular, highly graphical pages are difficult to automatically categorize.<p>
-<a name="wrongtopic"><span class=text1>How do I change a page's topic?</span></a><br>Click the page review button ( <img src="images/infobutton.png"> ), then click the "update" link and enter the correct topic.<p>
-<a name="aboutme"><span class=text1>I put HTML into my 'about me' field and now I can't edit my profile</span></a><br>You can reset your about me field by going to <a href="http://www.stumbleupon.com/fix_about.php">this page</a>.<p>
-<a name="audience"><span class=text1>What is audience?</span></a><br>Audience is the number of people who "stumble upon" your favorite sites.  It contains only people who have been recently active. You can increase your audience by rating websites that other people will like, signing up for all topics you are interested in, and getting more people to make you their friend.<p>
-<a name="badauth"><span class=text1>I keep getting Bad Authentication or Wrong Password errors.  How do I fix this?</span></a><br>The first thing to try is to sign out and sign in again.  If you cannot sign in, then most likely you are using an invalid username/password combination.   You can <a href="http://www.stumbleupon.com/recover_password.php"><b>recover your password here</b></a> or you can also <a href="http://www.stumbleupon.com/new_account.php"><b>create a new account</b></a>.
-
-<br><br>
-If you continue to get this error, then you may have a program, extension, or proxy installed that is conflicting with StumbleUpon.  In particular, the "Privoxy" or "Junkbuster" proxies are known to break some websites, including StumbleUpon. Disabling these programs will fix the problem.<p>
-<a name="changeinfo"><span class=text1>How do I change my personal information?</span></a><br>You can change the information associated with your account by clicking the house icon on your toolbar, then clicking the "Prefs" link on the far right-hand side of your profile.<p>
-<a name="changepassword"><span class=text1>How do I change my password?</span></a><br>Select <i>change password</i> from the stumble menu, on the far right hand side of the stumble toolbar.<p>
-<a name="deleteaccount"><span class=text1>How do I delete my account?</span></a><br>Accounts will be deleted automatically if they are not used for a long period of time. If you would like to remove your personal information from your account, simply click the "edit my info" button and remove your personal information from your profile.  If you need your account deleted immediately, please use the <a href="http://www.stumbleupon.com/delete_account.php"><b>account deletion page</b></a>.<p>
-
-<a name="email"><span class=text1>Where did the email address I entered go?</span></a><br>If your email address is no longer on your Prefs tab, it has been removed automatically because StumbleUpon could not deliver mail to that address. This could be for a number of reasons, including an overly aggressive spam filter (in particular sites like earthlink.net that require an email address to be whitelisted) or a misconfigured mail server. You may also have made a typo in your email address. If you have an email address which a service such as earthlink.net, you will need to whitelist stumbleupon addresses before entering you email back into the system.<p>
-<a name="forgotpassword"><span class=text1>I forgot my username/password, how do I get it back?</span></a><br>If you can't remember your username or password, you can <a href="http://www.stumbleupon.com/recover_password.php"><b>recover them here</b></a> provided we have a correct email address on file. If you did not associate an valid email address with your account, your password cannot be emailed to you and you will have to <a href="http://www.stumbleupon.com/new_account.php"><b>create a new account</b></a>.  If you are attached to your old account and you think you can prove you own it, please use the feedback system.<p>
-<a name="nickname"><span class=text1>How do I change my nickname?</span></a><br>Once you have used StumbleUpon for a week and have chosen a nickname, you can no longer change it.  If it has not been a week, you can change it by clicking the house icon on your toolbar, then clicking the "Prefs" link on the far right-hand side of your profile.<p>
-<a name="picture"><span class=text1>How do I change my picture?</span></a><br>If you are uploading a new picture, and you find your picture isn't changing, try clicking "reload" on your browser while holding down the shift key. Your browser is most likely caching the old version of your picture.<p>
-
-<a name="restrictions"><span class=text1>Why am I unable to post to groups and/or message other stumblers?</span></a><br>StumbleUpon places various restrictions on new stumblers.  This allows new stumblers to get used to how StumbleUpon works before using some of the additional social features.  In particular, accounts may be restricted from messaging and posting to groups if they are:<br><br>
-1. less than 3 days old<br>
-2. have not stumbled a significant number of times<br>
-3. do not have a nickname<br>
-4. do not have a photo<br><p>
-<a name="sponsoredstumble"><span class=text1>Why can't I change the picture on my profile?</span></a><br>If you are uploading a new picture but the picture on your profile does not change, most likely your browser is caching your old photo.  You can remedy this by click shift-reload on a page with your old picture.  If this is not a problem, then it could be an issue with the photo you are using, try using another one.  Also make sure your image ends in either .jpg, .gif, or .png.<p>
-<a name="twoaccounts"><span class=text1>Can I create 2 different accounts on the same computer?</span></a><br>If you are creating 2 accounts for your own use, you must have permission from StumbleUpon as outlined in our <a target=_new href="http://www.stumbleupon.com/terms.html"><b>Terms of Service</b></a>. If you have permission or you are creating the account for someone else, you can <a href="http://www.stumbleupon.com/new_account.php"><b>create a new account here</b></a>.<p>
-
-<a name="twocomputers"><span class=text1>How do I use the same account on 2 different computers?</span></a><br>Install StumbleUpon on the second computer, select "Sign-in", and type in your username and password. If you do not know your password, you can type in a blank password and StumbleUpon will email it to you (just make sure your first account has an email address associated with it)<p>
-<a name="wrongpassword"><span class=text1>I changed my password on 1 computer, and now I am getting a wrong password error on my other computer?</span></a><br>To get rid of the error, select <span class=bold>Sign-in</span> and type in your stumbler ID and your new password.<p>
-<a name="ignore"><span class=text1>How do I stop another stumbler from messaging me?</span></a><br>Go to their profile and click the <i>ignore</i> button at the bottom of the page. Alternatively, there is a link in your inbox, beside each message. If you click the <i>ignore</i> link, it will stop that stumbler from sending you messages. It will also effectively stop you from seeing them in reviews, forum/group posts, and on your network page.<p>
-
-<a name="topstumbler"><span class=text1>How do I become a Top Stumbler?</span></a><br>Top Stumblers are our most active and helpful community members. These members frequently <span class=bold>suggest new sites</span> to be included in our database, and frequently rate new sites they stumble upon. When you submit a site, it is shown to other <span class=bold>stumblers</span>(<img src="images/man3.png">) for evaluation. If those people like your suggestion (by rating it I-like-it! often) your community 'Karma' will increase. Your Top Stumbler rank will also increase by <span class=bold>frequent rating</span>. You do not need to rate every site you see, but if it stands out as particularily excellent (a website you really like) or bad (you don't like it, or it is spam), make sure you rate it. This regular participation will increase your Top Stumbler rank.<p>
-<a name="newgroup"><span class=text1>How do I start a new group?</span></a><br>Only <a href="http://www.stumbleupon.com/sponsors.php"><b>sponsors</b></a> can create new groups.  If you are a sponsor, you can find the "Request New Group" link on the "About" section of your profile.<p>
-
-<a name="spyware"><span class=text1>Is this spyware?</span></a><br>No. Stumbleupon <span class=bold>does not automatically collect any personal or system information</span> from your computer. Stumbleupon records information you explicity provide such as your ratings of websites. This is necessary to share the sites with other community members and improve your future stumbles. Associating personal information with your userid, such as a name, nickname, or webpage is entirely voluntary and not required to use the StumbleUpon toolbar. For more information, see our <a href="privacy.html">privacy policy</a>.<p>
-<a name="sponsors"><span class=text1>What are Sponsors?</span></a><br>Sponsors are stumblers who have upgraded their account to receive extra features. These features include the ability to turn off advertising, create new groups and view sites which you have in common with stumblers. If you are interested in becoming a sponsor, <a href="http://www.stumbleupon.com/sponsors.php"><b>click here</b></a>.<p>
-<a name="promote"><span class=text1>How can I promote StumbleUpon on my site?</span></a><br>If you want to let other people know about StumbleUpon, mention us on your website. The more people who share your interests using StumbleUpon, the better the system will work for everyone. Adding this logo to your site will increase the number of people signing up who share your interests, in turn greatly improving the quality of your future stumbles! Simply download a <a href="http://www.stumbleupon.com/buttons.php"><b>button</b></a>. You can find more StumbleUpon buttons on our <a href="http://www.stumbleupon.com/buttons.php"><b>buttons page</b></a>.<p>
-
-<a name="browser"><span class=text1>StumbleUpon keeps misdetecting my browser</span></a><br>There are links directly to each version of StumbleUpon on <a href="http://stumbleupon.com/get_later.html">this page</a>.<p>
-<a name="install"><span class=text1>Why can't I install StumbleUpon?</span></a><br>If your toolbar installs but is not appearing, there are a few things you can try:<br><br>
-1. Select View→Toolbars→StumbleUpon<br>
-2. Restart your browser<br>
-3. Restart your computer<br>
-4. If you are using IE, try enabling the option Tools→Internet Options→ Advanced→Enable third party browser extensions, and then restart your computer.
-
-
-<br><br>If you get an error that says "Not a valid install package", try restarting your browser then attempt an install again.
-
-<br><br>If you get an error that says "Browser could not install this item because 'install-7bd.rdf' (provided by the item) is malformed", then you are most likely using a bad nightly build of Firefox.  Try installing the latest stable version of Firefox.
-
-<br><br>If after trying the above remedies, you are still unable to install the toolbar, please <a href="feedback.html"><b>contact us</b></a>.<p>
-<a name="uninstall"><span class=text1>How do I uninstall the StumbleUpon Toolbar?</span></a><br><span class=bold>Internet Explorer:</span> click the menu on the far right hand side of the stumble toolbar, then select <i>Help->Uninstall</i>. If for some reason that doesn't work, you can type "regsvr32 /u c:\winnt\stumble.dll" at the windows prompt. 
-<br><br><span class=bold>Firefox:</span> go to Tools->Extensions and then click on StumbleUpon then Uninstall. 
-<br><br><span class=bold>Mozilla/Netscape:</span> go <a href="https://addons.mozilla.org/extensions/moreinfo.php?application=mozilla&version=1.7&category=Miscellaneous&id=203"><b>here</b></a> and install the Extension Uninstaller, and then use it to uninstall StumbleUpon.<p>
-
-<a name="unsupported"><span class=text1>Why don't you support Safari or Opera?</span></a><br>We are unable to offer support for these browsers because they lack browser features on which the StumbleUpon Toolbar depends. If you are using one of the these browsers but want to become a member, the easiest way is to install <a href="http://www.mozilla.org/firefox/"><b>Firefox</b></a>. Firefox is fast and stable and has many other features which these browsers do not have. We have had very positive feedback from people who have switched to Firefox from these other browsers. Note also that <span class=bold>we do not support Avant Browser</span>. Please send requests for StumbleUpon support in this browser to the Avant forums.<p>
-<a name="upgrade"><span class=text1>How do I upgrade the StumbleUpon Toolbar?</span></a><br>To upgrade the toolbar, simply install it again from the StumbleUpon homepage and then restart your browser. To see if you have the latest version of the StumbleUpon Toolbar, select "Help->Toolbar Version" from the Stumble menu.<p>
-<a name="beta"><span class=text1>Are there beta versions of the StumbleUpon toolbar available?</span></a><br>Yes, you can download beta versions of the Firefox toolbar here:<br>
-<a href="http://www.stumbleupon.com/beta/">http://www.stumbleupon.com/beta/</a><br>Please be aware that beta versions may contain bugs or incomplete functionality.  If you are having difficulty with a beta version, go back to stumbleupon.com and install a stable version.<p>
-<a name="bugs"><span class=text1>I found a bug, how do I report it?</span></a><br>You can search for bugs and report new bugs on the <a href="http://bugs.stumbleupon.com/"><b>StumbleUpon Bugs Page</b></a>.  You can also try asking on <a href="http://bugs.stumbleupon.com/forum/"><b>Bugs Forum</b></a>. When you are reporting a bug, please provide as much information as possible.  If you are running StumbleUpon in Firefox, please have a look at Tools→Javascript Console and see if there are any errors that mention StumbleUpon generated when you experience the bug.<p>
-
-<a name="hidetoolbar"><span class=text1>How do I temporarily hide the toolbar?</span></a><br>In your browser, select View -> Toolbars -> StumbleUpon. In Firefox, you can also press Ctrl-F11. Do the same to unhide the toolbar.<p>
-<a name="movetoolbar"><span class=text1>How do I move the Mozilla/Firefox toolbar to another line?</span></a><br>From the stumble menu, select "Toolbar Options" then change the "Placement" selector to move the toolbar.<p>
-<a name="ownclient"><span class=text1>Can I write my own client or script to access the StumbleUpon database?</span></a><br>No. Only clients or webpages released by StumbleUpon may be used to access the StumbleUpon database. This is explained in more detail in our <a target=_new href="http://www.stumbleupon.com/terms.html">Terms of Service</a>.<p>
-</ul>
-</td></tr></table>
-
-<br>If your question isn't answered here, try the <a href="http://stumbleupon.theprawn.com/"><b>Unofficial FAQ</b></a><br><br>
-
-<br>
-</td></tr>
-</table>
-
-</body>
-</html>
-
-
-
diff --git a/debian/doc/guide.html b/debian/doc/guide.html
deleted file mode 100644
index ad41fdb..0000000
--- a/debian/doc/guide.html
+++ /dev/null
@@ -1,164 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
-
-<link href="stumble.css" rel="stylesheet" type="text/css" />
-</head>
-
-<body>
-
-<table width=100% cellspacing=0 cellpadding=0><tr>
-<td width=10>
-
-<td width=90>
-
-<td width=530>
-<br>
-<table width=100% cellspacing=10 cellpadding=10>
-
-<tr><td class=lightbg>
-The following is a description of all the buttons and menus available on the
-StumbleUpon toolbar.  If you do not find the answer here,
-you can also check out our <a href="faq.html"><b>FAQ</b></a>.  Failing that, feel free to <a
-href="feedback.html"><b>Contact us</b></a> for assistance, or ask your fellow
-stumblers for help using our <a href="http://help.group.stumbleupon.com/"><b>Help Forum</b></a>.
-
-<tr><td class=bg>
-<img src="images/happystumble.png" align=right vspace=5 hspace=15>
-<span class=bold>The Stumble Button: </span><Br>Clicking the Stumble Button shows you a new great site. These pages are
-<b>personalized</b> recommendations – sites from friends and like-minded people which match your interests.
-
-
-<tr><td class=lightbg>
-<img src="images/dropdown.png" align=right vspace=5 hspace=15>
-<span class=bold>The Topic Selector: </span><br>The topic selector allows you to choose the
-category of your next stumble.  This lets you discover new websites related to a given topic, or recommended by a friend. Selecting "All" will show you a site within any of your friends or interests - a random tour of interesting pages. 
-
-
-<tr><td class=bg>
-<img align=right vspace=5 hspace=15 src="images/ratings.png"> <span class=bold>The Rating
-Buttons: </span><br>The sites you 'stumble upon' have been suggested (rated <span class=bold>I like it!</span>) by friends or like-minded community members</span>. Whenever you click
-<span class=bold>'I like it'</span> you pass that page on to other stumblers. Pages you suggest are automatically classified and presented to others with matching interests – in effect you share sites with others who like the same things you do.<br><br> Rating pages you 'stumble upon' gives
-your opinion on their quality, refining your preferences in the process. The
-easiest way to improve your 'stumbles' is to <span class=bold>rate your favorite websites</span>
-(whether you 'stumbled upon' them or not). This lets other people see your
-favorites sites, and connects you to other members who like these pages.
-
-
-<tr><td class=lightbg>
-<img align=right vspace=5 hspace=15 src="images/info.gif"> 
-<span class=bold>Page Reviews Button: </span> <br>Clicking this button
-sends you to the comments page for the website you are currently viewing.  Read
-the opinions of other stumblers, or add your own...
-
-<tr><td class=bg>
-<img align=right vspace=5 hspace=15 src="images/firstrater.png" align=right hspace=15 vspace=10>
-<span class=bold>Stumbler Button: </span><br>Clicking this button takes you to the profile of the person who suggested the page you 'stumbled upon'. This is either the first person to say <span class=bold>'I like it'</span> or your friend who liked the page. When you get a great stumble this is the person to thank.
-
-
-<tr><td class=lightbg>
-<img align=right vspace=5 hspace=15 src="images/sendto.gif">
-<span class=bold>Send-To Button: </span>
-<br>Use this button to quickly send the page you are currently at to one of your friends.<Br><Br>This is a great way to pass on a Stumble which you know a friend would be interested in. If your friend isn't a member of StumbleUpon, you can also email them a site with a single click. 
-</td></tr>
-
-<!--
-<tr><td class=lightbg>
-<img align=right vspace=5 hspace=15 src="images/mystumblers.gif" align=right
-hspace=15 vspace=10> <span class=bold>Stumblers Button: </span>
-<br>This button takes you to a list of your friends, fans and site
-informants. It's also lets you view the people who have visited your
-profile, and send them messages.
--->
-
-<tr><td class=bg>
-<img align=right vspace=5 hspace=15 src="images/myhome.gif" align=right
-hspace=15 vspace=10> <span class=bold>Home Button: </span>
-<br>Takes you to your profile page, your personal space where other
-people see the interesting websites you find. This page, available to anyone at 
-<span class=text1>http://<b>nickname</b>.stumbleupon.com/</span>,  
-is updated every time you click <span class=bold>I like it!</span> or make a comment.
-
-<!--
-<tr><td class=lightbg>
-<img align=right vspace=5 hspace=15 src="images/editinfo.gif" align=right
-hspace=15 vspace=10> <span class=bold>Edit Info Button: </span>
-<br>Allows you to quickly edit your profile which will be seen by other
-stumblers. You may upload a photo, describe your interests, and let others know
-what kinds of books, music and movies you like.
--->
-
-<tr><td class=lightbg>
-<img align=right vspace=5 hspace=15 src="images/menu.gif">
-<a name=menu><span class=bold>The Stumble Menu: </span></a>
-<br><br>
-
-<span class=bold>My Favorites:</span>  Displays a list of webpages you have
-rated "I like it!", along with their topic and rating date.  
-<br><br>
-
-<span class=bold>Stumble History:</span>  Displays a list of webpages you have
-stumbled upon, along with their topic and stumble date. 
-<br><br>
-
-<span class=bold>Suggested Topics:</span>  Suggests interests the toolbar thinks you might be interested in on top of the interests you
-have already entered on the interests page.  Note that it can take up to 24
-hours from the first time you use the toolbar for it to come up with
-suggestions.
-<br><br>
-
-<span class=bold>Update Topics:</span>  Takes you to the interests page
-where you can let the toolbar know what sorts of topics you are
-interested in. We have nearly <span class=bold>500</span> topics to choose from.
-<br><br>
-
-<span class=bold>Invite Friends:</span> Lets your friends know about StumbleUpon.
-This increases the number people you share your favorite sites with (your
-audience size) and
-lets you 'stumble upon' your friends' favorite sites.
-<br><br>
-
-<span class=bold>Top Stumblers:</span>  Takes you to the Top Stumblers page, where
-we feature stumblers who have contributed a large number of consistently
-high-quality websites to the system.
-<br><br>
-
-<span class=bold>Chat:</span> Gives you instructions on how to join the StumbleUpon chatroom.
-<br><br>
-
-<span class=bold>Toolbar Options:</span>  Allows you to change the appearance and
-behaviour of the
-toolbar.
-<br><Br>
-<span class=bold>Change Current User:</span>  Allows you to access your stumble
-profile from another computer, or use multiple stumbleupon profiles
-on one computer.
-<br><br>
-<span class=bold>Change Password:</span>  Allows you to change
-your password, so you may easily access your account on different
-computers which have the StumbleUpon Toolbar.
-
-<br><br><span class=bold>StumbleUpon Homepage:</span>
-Brings you to our homepage.
-
-<br><br><span class=bold>Upgrade Now:</span>
-Information on how you can upgrade you StumbleUpon account.
-
-<br><br><span class=bold>Help Menu:</span> Links to our Help pages.
-
-
-</table>
-<br>
-
-<td width=10> 
-<td valign=top width=90 height=100%><br>
-<td width=10>
-
-
-</table>
-
-</body>
-</html>
-
-
diff --git a/debian/doc/images/205screenshot.png b/debian/doc/images/205screenshot.png
deleted file mode 100644
index 379c404..0000000
Binary files a/debian/doc/images/205screenshot.png and /dev/null differ
diff --git a/debian/doc/images/dropdown.png b/debian/doc/images/dropdown.png
deleted file mode 100644
index d0e0f42..0000000
Binary files a/debian/doc/images/dropdown.png and /dev/null differ
diff --git a/debian/doc/images/editinfo.png b/debian/doc/images/editinfo.png
deleted file mode 100644
index 9489a0a..0000000
Binary files a/debian/doc/images/editinfo.png and /dev/null differ
diff --git a/debian/doc/images/firstrater.png b/debian/doc/images/firstrater.png
deleted file mode 100644
index 1e5f306..0000000
Binary files a/debian/doc/images/firstrater.png and /dev/null differ
diff --git a/debian/doc/images/happystumble.png b/debian/doc/images/happystumble.png
deleted file mode 100644
index 0007776..0000000
Binary files a/debian/doc/images/happystumble.png and /dev/null differ
diff --git a/debian/doc/images/info.png b/debian/doc/images/info.png
deleted file mode 100644
index 1f9ade6..0000000
Binary files a/debian/doc/images/info.png and /dev/null differ
diff --git a/debian/doc/images/infobutton.png b/debian/doc/images/infobutton.png
deleted file mode 100644
index cd46b27..0000000
Binary files a/debian/doc/images/infobutton.png and /dev/null differ
diff --git a/debian/doc/images/man3.png b/debian/doc/images/man3.png
deleted file mode 100644
index 8545148..0000000
Binary files a/debian/doc/images/man3.png and /dev/null differ
diff --git a/debian/doc/images/menu.png b/debian/doc/images/menu.png
deleted file mode 100644
index fb30074..0000000
Binary files a/debian/doc/images/menu.png and /dev/null differ
diff --git a/debian/doc/images/myhome.png b/debian/doc/images/myhome.png
deleted file mode 100644
index 1c71d08..0000000
Binary files a/debian/doc/images/myhome.png and /dev/null differ
diff --git a/debian/doc/images/mystumblers.png b/debian/doc/images/mystumblers.png
deleted file mode 100644
index 15257cb..0000000
Binary files a/debian/doc/images/mystumblers.png and /dev/null differ
diff --git a/debian/doc/images/ratings.png b/debian/doc/images/ratings.png
deleted file mode 100644
index 8368d7f..0000000
Binary files a/debian/doc/images/ratings.png and /dev/null differ
diff --git a/debian/doc/images/thumbup.png b/debian/doc/images/thumbup.png
deleted file mode 100644
index 79e974e..0000000
Binary files a/debian/doc/images/thumbup.png and /dev/null differ
diff --git a/debian/doc/stumble.css b/debian/doc/stumble.css
deleted file mode 100644
index ca16043..0000000
--- a/debian/doc/stumble.css
+++ /dev/null
@@ -1,280 +0,0 @@
-body {
-padding:0; margin:0;
-font-family:Verdana, Tahoma, Arial, Helvetica, sans-serif; font-size:11px; line-height:16px;
-}
-
-img {border:none;}
-a{color:#266289; text-decoration:underline;}
-a:hover{text-decoration:none;}
-a:visited{color:#695269; text-decoration:none;}
-.banner {height:161px; background: url(../images/bg.png) repeat-x;}
-.content {width:764px; background:#fff; margin:0 auto;}
-
-div#centerBox {margin:0; padding:0; width:265px; background: url(../images/bg_center.gif) repeat-y;}
-div#centerBox img#stumblers {margin:15px 0 5px 100px; padding:0;}
-div#centerBox a img.center{margin:0; padding:0 0 0 15px;}
-div#centerBox div#interCenterBox {margin:0 0 0 15px; padding:0; width:228px;}
-div#centerBox div#interCenterBox p#bgT {margin:2px 0 0; padding:0; background: url(../images/bg_white_top.gif) repeat-y; line-height:10px; }
-div#centerBox div#interCenterBox p#bgB {margin:0; padding:0; background: url(../images/bg_white_bottom.gif) repeat-y; line-height:10px;}
-div#centerBox div#interCenterBox p {margin:0; padding:0 10px 0; color:#266289; font-weight:bold; font-size:13px; background: url(../images/bg_white.gif) repeat-y;}
-div#centerBox div#interCenterBox p a {text-decoration:none; line-height:1.4em;}
-
-p#backgroundT {margin:0; padding:0; background: url(../images/bg_center_top.gif) repeat-y; line-height:10px;}
-p#backgroundB {margin:0; padding:0; background: url(../images/bg_center_bottom.gif) repeat-y; line-height:10px;}
-
-div#centerBox div#centerNav {margin:0; padding:10px 0 14px 8px;}
-/* div#centerBox div#centerNav img {margin:0; padding:0 3px; display:inline; float:left;}
-div#centerBox div#centerNav a img {margin:0; padding:25px 0 0; display:inline; float:left;} */
-
-div#reviews {margin:5px 0 0; padding:0;}
-div#reviews img {margin:0; padding:7px 0 0 10px; display:inline;}
-
-#left {padding:30px 0 0 12px; width:240px; color:#323244; font-size:13px;}
-#left p {margin:7px 12px 20px 12px;}
-#left h2, #left h3, #right h2, #right h3{padding:0; margin:12px 12px 0 12px;}
-#left form {font-size:12px; color:#323244; width:188px; margin:0; display:block; padding:7px 12px 20px 12px;}
-#left form input {margin:3px 0 0 0; padding:0;}
-
-#center h2, #center h3{padding:0; margin:12px;}
-#center {padding:3px 0 0 0;}
-#center .content {background:#ebf8fd; width:264px; text-align:center; padding-bottom:15px; margin-bottom:12px;}
-
-.content td#copy {width:504px; padding:30px 0 0 12px; color:#323244; font-size:12px; }
-#copy h2, #copy h3{padding:0; margin:12px 12px 0 12px;}
-#copy  p {margin:7px 12px 20px 12px;}
-
-table.stumble_box {margin:0; padding:0;}
-
-#right{padding:30px 5px 0 8px;width:240px; color:#323244; font-size:13px;}
-#right p {margin:7px 12px 20px 12px;}
-#footer{padding: 0 22px 25px 22px;color:#266289;text-align:center;}
-#footer p {margin: 12px 0 0 0 ; padding:0; text-align:left;}
-#footer img{margin:0; }
-#footer a {text-decoration:none;}
-#footer a:hover {text-decoration:underline;}
-#footer .copyright {float:right; color:#323244;}
-.content .copyright {color:#323244;}
-
-/* Clearfix Settings
--------------------------------------------------------------------- */
-/* 	www.positioniseverything.net/easyclearing.html		 */
-.clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } 
-.clearfix { display: inline-table; /* IE/Mac */ } 
-/* Hides from IE-mac \*/ 
-* html .clearfix { height: 1%; } 
-.clearfix { display: block; }  
-/* End hide from IE-mac */
-
-.geoff {font-family:verdana,tahoma,arial,helvetica,sans-serif; font-size:13px; line-height:19px; text-align:center; font-weight:bold; background:#fff;}
-
-form { margin: 0px; }
-
-td.rightborder {
-	border-right-style: solid;
-	border-right-width: 1;
-	border-right-color: #e8eaf5;
-}
-
-td.leftborder {
-	border-left-style: solid;
-	border-left-width: 1;
-	border-left-color: #e8eaf5;
-}
-
-span.text1 {
-	color:#009900;
-	font-weight: bold;
-}
-
-span.text2 {
-	color:#888888;
-}
-
-span.bold {
-	color:#323244;
-	font-weight: bold;
-}
-
-span.red {
-	font-weight: bold;
-        color:#ee0000;
-}
-
-input.bold {
-        font-weight:bold;
-        color:#ee0000;
-}
-
-input.mini {
-        font-weight:bold;
-	font-size: 9px;
-        color:#ee0000;
-}
-
-
-
-.darkbox {background-color:#efeff5;}
-
-body,td {
-        font-size: 13px;
-        font-family:arial,helvetica;
-}
-.mini {
-        font-size: 11px;
-}
-
-.big {
-        font-size: 18px;
-	color:#222255;
-}
-
-#tablink {
-	text-decoration: none;
-	color:#002288;
-}
-#tablink:visited {
-	text-decoration: none;
-	color:#002288;
-}
-
-#tablink_highlight {
-	text-decoration: none;
-	color:#2040ee;
-}
-#tablink_highlight:visited {
-	text-decoration: none;
-	color:#2040ee;
-}
-
-#tablink2 {
-	text-decoration: none;
-	color:#002288;
-}
-#tablink2:visited {
-	text-decoration: none;
-	color:#002288;
-}
-
-#tablink2_highlight {
-	text-decoration: none;
-	color:#2040ee;
-}
-#tablink2_highlight:visited {
-	text-decoration: none;
-	color:#2040ee;
-}
-
-a {
-	text-decoration: none;
-}
-a:hover {
-	text-decoration: underline;
-}
-a:visited {
-	text-decoration: none;
-} 
-a:visited:hover {
-	text-decoration: underline;
-}
-
-.lightbg {
-	background-color: #ffffff; 
-}
-
-.bg {
-	background-color: #ebf8fd;
-}
-
-hr.bg {
-	border:0; 
-	background-color: #e8eaf5;
-	height: 1px; 
-	color: #e8eaf5;
-}
-
-.darkbg {
-	background-color: #cce3ec;
-}
-
-.darkerbg {
-	background-color: #cce3ec;
-}
-
-#tab {
-	cursor:pointer;
-	background-color: #ffffff; 
-}
-
-#highlight {
-	cursor:pointer;
-	background-color: #d6f1fb;
-}
-
-#tab2 {
-	cursor:pointer;
-	background-color: #d6f1fb;
-}
-
-#highlight2 {
-	cursor:pointer;
-	background-color: #ffffff; 
-}
-
-input.mini {
-	font-size:9px;
-}
-
-span.status {
-	color:#ff0000;
-	font-weight: bold;
-}
-
-span.white {
-	color:#ffffff;
-	font-weight: bold;
-}
-
-span.yellow {
-	color:#ffff00;
-	font-weight: bold;
-}
-
-
-
-/* start stuff that doesn't change... */
-
-
-span.menuselected {
-	color: #ff0000;
-	font-size: 15px;
-	font-weight: bold;
-}
-span.homedate {
-	color: #2b5a8f;
-}
-span.date {
-	color:#009900;
-	font-size: 11px;
-	font-weight: bold;
-}
-span.text2 {
-	color:#888888;
-}
-p {
-	font-family: arial, helvetica, san-serif;
-	font-size: 13px;
-	text-align: justify;
-}
-a.small {
-	font-family: arial, helvetica, san-serif;
-	font-size: 11px;
-	text-align: justify;
-}
-a.small:hover {
-	color:#ff0000;
-} 
-td.justify {
-	font-family: arial, helvetica, san-serif;
-	font-size: 13px;
-	text-align: justify; 
-}
diff --git a/debian/patches/local_help.patch b/debian/patches/local_help.patch
deleted file mode 100644
index 1ab35fd..0000000
--- a/debian/patches/local_help.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-Description: Use local help
-Author: Andrea Veri <and at debian.org>
-Forwarded: not-needed
-Last-Update: 2010-01-28
-
---- stumbleupon-3.62.orig/chrome/stumbleupon.jar!/content/stumbleuponOverlay.js
-+++ stumbleupon-3.62/chrome/stumbleupon.jar!/content/stumbleuponOverlay.js
-@@ -38,6 +38,7 @@ Copyright notes:
- ***/
- 
- //************** GLOBALS ****************/
-+var su_localdoc = "file:///usr/share/xul-ext-stumbleupon/html/";
- var su_private_label = "DEB";
- var su_source_label = "AM";
- var su_log_communication = true;
---- stumbleupon-3.62.orig/chrome/stumbleupon.jar!/content/stumbleuponOverlay.xul
-+++ stumbleupon-3.62/chrome/stumbleupon.jar!/content/stumbleuponOverlay.xul
-@@ -657,9 +657,9 @@
- 		<menuitem label="Sign-out..." tooltiptext="Sign out from this account" oncommand="su_handle_logout(false);"/>
- 	
- 		<menuseparator/>
--		
--		<menuitem label="Toolbar Guide" tooltiptext="View the toolbar primer" oncommand="getBrowser().contentDocument.location=su_serverhttp + 'guide.html'"/>
--		<menuitem label="Help" tooltiptext="Frequently Asked Questions" oncommand="getBrowser().contentDocument.location=su_serverhttp + 'faq.html'"/>
-+
-+		<menuitem label="Toolbar Guide" tooltiptext="View the toolbar primer" oncommand="getBrowser().contentDocument.location=(su_private_label=='DEB'?su_localdoc + 'guide.html':su_serverhttp + 'guide.html')"/>
-+		<menuitem label="Help" tooltiptext="Frequently Asked Questions" oncommand="getBrowser().contentDocument.location=(su_private_label=='DEB'? su_localdoc + 'faq.html' : su_serverhttp + 'faq.html')"/>
- 		<menu label="About StumbleUpon" tooltiptext="Get help with StumbleUpon">
- 			<menupopup>
- 				<menuitem label="&menu.stumblehome;" tooltiptext="StumbleUpon.com Home Page" oncommand="getBrowser().contentDocument.location=su_serverhttp"/>
-@@ -669,7 +669,6 @@
- 				<menuseparator/>
- 				<menuitem label="&menu.contact;" tooltiptext="Send questions or comments to StumbleUpon" oncommand="su_feedback();"/>
- 				<menuitem label="Privacy Policy" tooltiptext="View StumbleUpon's privacy policy" oncommand="getBrowser().contentDocument.location=su_serverhttp + 'privacy.html'"/>
--				<menuitem label="Uninstall Instructions" tooltiptext="Learn how to uninstall the toolbar" oncommand="getBrowser().contentDocument.location=su_serverhttp + 'help/How_do_I_uninstall_the_toolbar/'"/>
- 				<menuitem label="Toolbar Version" tooltiptext="Your current toolbar version, along with new versions" oncommand="su_about();"/>
- 			</menupopup>
- 		</menu>
diff --git a/debian/patches/private_label.patch b/debian/patches/private_label.patch
deleted file mode 100644
index fa2b322..0000000
--- a/debian/patches/private_label.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-Description: Change privat label to DEB
-Author: Andrea Veri <and at debian.org>
-Forwarded: not-needed
-Last-Update: 2010-01-28
-
---- stumbleupon-3.62.orig/chrome/stumbleupon.jar!/content/stumbleuponOverlay.js
-+++ stumbleupon-3.62/chrome/stumbleupon.jar!/content/stumbleuponOverlay.js
-@@ -38,7 +38,7 @@ Copyright notes:
- ***/
- 
- //************** GLOBALS ****************/
--var su_private_label = "2010012002";
-+var su_private_label = "DEB";
- var su_source_label = "AM";
- var su_log_communication = true;
- var su_log_sync = false;
diff --git a/debian/patches/series b/debian/patches/series
deleted file mode 100644
index de25941..0000000
--- a/debian/patches/series
+++ /dev/null
@@ -1,2 +0,0 @@
-private_label.patch
-local_help.patch
diff --git a/debian/rules b/debian/rules
deleted file mode 100755
index b280270..0000000
--- a/debian/rules
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/make -f
-
-include /usr/share/cdbs/1/rules/debhelper.mk
-include /usr/share/mozilla-devscripts/xpi.mk
diff --git a/debian/source/format b/debian/source/format
deleted file mode 100644
index 163aaf8..0000000
--- a/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/debian/source/include-binaries b/debian/source/include-binaries
deleted file mode 100644
index 7145310..0000000
--- a/debian/source/include-binaries
+++ /dev/null
@@ -1,13 +0,0 @@
-debian/doc/images/205screenshot.png
-debian/doc/images/dropdown.png
-debian/doc/images/editinfo.png
-debian/doc/images/firstrater.png
-debian/doc/images/happystumble.png
-debian/doc/images/info.png
-debian/doc/images/infobutton.png
-debian/doc/images/man3.png
-debian/doc/images/menu.png
-debian/doc/images/myhome.png
-debian/doc/images/mystumblers.png
-debian/doc/images/ratings.png
-debian/doc/images/thumbup.png
diff --git a/debian/watch b/debian/watch
deleted file mode 100644
index c6e0567..0000000
--- a/debian/watch
+++ /dev/null
@@ -1,2 +0,0 @@
-version=3
-http://ftp.mozilla.org/pub/mozilla.org/addons/138/stumbleupon-([\d\.]+)-.*.xpi
diff --git a/debian/xul-ext-stumbleupon.install b/debian/xul-ext-stumbleupon.install
deleted file mode 100644
index b153cd2..0000000
--- a/debian/xul-ext-stumbleupon.install
+++ /dev/null
@@ -1,3 +0,0 @@
-debian/doc/*.html usr/share/xul-ext-stumbleupon/html/
-debian/doc/images/*.png usr/share/xul-ext-stumbleupon/html/images/
-debian/doc/stumble.css usr/share/xul-ext-stumbleupon/html/
diff --git a/install.js b/install.js
index a1a8f81..b756545 100644
--- a/install.js
+++ b/install.js
@@ -1,13 +1,12 @@
 const APP_AUTHOR		= "Geoff Smith";
 const APP_NAME			= "StumbleUpon";
 const APP_CHROME_NAME		= "stumbleupon";
-const APP_VERSION		= "3.62";
+const APP_VERSION		= "3.91";
 const APP_FILE 			= "chrome/stumbleupon.jar";
 const APP_FILE2 		= "stumbleupon.jar";
 const APP_XPCOM_SERVICE = "stumbleuponService.js";
 const APP_CONTENTS_PATH		= "content/";
 const APP_LOCALE_ENUS_PATH	= "locale/en-US/";
-const APP_LOCALE_FRFR_PATH	= "locale/fr-FR/";
 //const APP_SKIN_PATH		= "skin/classic/stumbleupon/";
 
 initInstall(APP_NAME, APP_CHROME_NAME, APP_VERSION); 
@@ -23,7 +22,6 @@ error = addFile(APP_AUTHOR, APP_VERSION, APP_FILE, chromeFolder, null);
 var jarFolder = getFolder(chromeFolder, APP_FILE2);
 registerChrome(CONTENT | PROFILE_CHROME, jarFolder, APP_CONTENTS_PATH);
 registerChrome(LOCALE | PROFILE_CHROME, jarFolder, APP_LOCALE_ENUS_PATH);
-registerChrome(LOCALE | PROFILE_CHROME, jarFolder, APP_LOCALE_FRFR_PATH);
 //registerChrome(SKIN | PROFILE_CHROME, jarFolder, APP_SKIN_PATH);
 
 
diff --git a/install.rdf b/install.rdf
index c5047a2..1291512 100644
--- a/install.rdf
+++ b/install.rdf
@@ -2,10 +2,6 @@
 <RDF:RDF xmlns:em="http://www.mozilla.org/2004/em-rdf#"
          xmlns:NC="http://home.netscape.com/NC-rdf#"
          xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
-  <RDF:Description RDF:about="rdf:#$KB9V2"
-                   em:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
-                   em:minVersion="1.0"
-                   em:maxVersion="3.7a1pre" />
   <RDF:Description RDF:about="rdf:#$2C9V2"
                    em:id="{a463f10c-3994-11da-9945-000d60ca027b}"
                    em:minVersion="0.4"
@@ -14,20 +10,10 @@
                    em:id="{3db10fab-e461-4c80-8b97-957ad5f8ea47}"
                    em:minVersion="8.0"
                    em:maxVersion="9.0" />
-  <RDF:Description RDF:about="urn:mozilla:extension:file:stumbleupon.jar"
-                   em:package="content/"
-                   em:skin="content/skin/">
-    <em:locale>locale/en-US/</em:locale>
-    <em:locale>locale/fr-FR/</em:locale>
-  </RDF:Description>
-  <RDF:Description RDF:about="rdf:#$PB9V2"
-                   em:id="{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}"
-                   em:minVersion="1.0"
-                   em:maxVersion="2.1a1pre" />
   <RDF:Description RDF:about="urn:mozilla:install-manifest"
                    em:id="{AE93811A-5C9A-4d34-8462-F7B864FC4696}"
                    em:name="StumbleUpon"
-                   em:version="3.62"
+                   em:version="3.91"
                    em:description="StumbleUpon Toolbar"
                    em:creator="StumbleUpon"
                    em:homepageURL="http://www.stumbleupon.com/"
@@ -47,4 +33,17 @@
                    em:id="{86c18b42-e466-45a9-ae7a-9b95ba6f5640}"
                    em:minVersion="1.5"
                    em:maxVersion="1.8+" />
+  <RDF:Description RDF:about="urn:mozilla:extension:file:stumbleupon.jar"
+                   em:package="content/"
+                   em:skin="content/skin/">
+    <em:locale>locale/en-US/</em:locale>
+  </RDF:Description>
+  <RDF:Description RDF:about="rdf:#$PB9V2"
+                   em:id="{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}"
+                   em:minVersion="1.0"
+                   em:maxVersion="2.1a1pre" />
+  <RDF:Description RDF:about="rdf:#$KB9V2"
+                   em:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
+                   em:minVersion="1.0"
+                   em:maxVersion="4.0.*" />
 </RDF:RDF>
diff --git a/chrome/stumbleupon.jar!/locale/en-US/contents.rdf b/locale/en-US/contents.rdf
similarity index 100%
rename from chrome/stumbleupon.jar!/locale/en-US/contents.rdf
rename to locale/en-US/contents.rdf
diff --git a/chrome/stumbleupon.jar!/locale/de-DE/stumbleupon.dtd b/locale/en-US/stumbleupon.dtd
similarity index 100%
rename from chrome/stumbleupon.jar!/locale/de-DE/stumbleupon.dtd
rename to locale/en-US/stumbleupon.dtd
diff --git a/chrome/stumbleupon.jar!/locale/de-DE/stumbleupon.properties b/locale/en-US/stumbleupon.properties
similarity index 100%
rename from chrome/stumbleupon.jar!/locale/de-DE/stumbleupon.properties
rename to locale/en-US/stumbleupon.properties

-- 
Mozilla addon for sharing interesting websites



More information about the Pkg-mozext-commits mailing list