From b9a98fce8b5d1c19056553670dc27589ec99cac4 Mon Sep 17 00:00:00 2001 From: Victor Costa Date: Fri, 15 Aug 2014 09:32:54 -0300 Subject: [PATCH] Upgrade strophe.js to 1.1.3 --- app/views/shared/logged_in/xmpp_chat.html.erb | 2 +- public/javascripts/strophejs-1.0.1/LICENSE.txt | 19 ------------------- public/javascripts/strophejs-1.0.1/README.txt | 15 --------------- public/javascripts/strophejs-1.0.1/contrib/discojs/README.txt | 42 ------------------------------------------ public/javascripts/strophejs-1.0.1/contrib/discojs/css/disco.css | 16 ---------------- public/javascripts/strophejs-1.0.1/contrib/discojs/index.html | 47 ----------------------------------------------- public/javascripts/strophejs-1.0.1/contrib/discojs/punjab.tac | 18 ------------------ public/javascripts/strophejs-1.0.1/contrib/discojs/scripts/basic.js | 102 ------------------------------------------------------------------------------------------------------ public/javascripts/strophejs-1.0.1/contrib/discojs/scripts/disco.js | 60 ------------------------------------------------------------ public/javascripts/strophejs-1.0.1/doc/files/core-js.html | 189 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- public/javascripts/strophejs-1.0.1/doc/index.html | 1 - public/javascripts/strophejs-1.0.1/doc/javascript/main.js | 836 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- public/javascripts/strophejs-1.0.1/doc/javascript/searchdata.js | 152 -------------------------------------------------------------------------------------------------------------------------------------------------------- public/javascripts/strophejs-1.0.1/doc/search/ClassesS.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/ConstantsA.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/ConstantsB.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/ConstantsC.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/ConstantsD.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/ConstantsE.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/ConstantsF.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/ConstantsH.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/ConstantsI.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/ConstantsL.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/ConstantsM.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/ConstantsP.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/ConstantsR.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/ConstantsS.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/ConstantsV.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/ConstantsW.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/ConstantsX.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FilesS.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsA.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsB.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsC.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsD.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsE.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsF.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsG.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsI.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsL.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsP.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsR.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsS.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsSymbols.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsT.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsU.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsW.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/FunctionsX.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralA.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralB.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralC.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralD.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralE.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralF.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralG.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralH.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralI.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralL.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralM.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralP.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralR.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralS.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralSymbols.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralT.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralU.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralV.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralW.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/GeneralX.html | 20 -------------------- public/javascripts/strophejs-1.0.1/doc/search/NoResults.html | 15 --------------- public/javascripts/strophejs-1.0.1/doc/styles/main.css | 767 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- public/javascripts/strophejs-1.0.1/examples/attach/README | 37 ------------------------------------- public/javascripts/strophejs-1.0.1/examples/attach/__init__.py | 0 public/javascripts/strophejs-1.0.1/examples/attach/attacher/__init__.py | 0 public/javascripts/strophejs-1.0.1/examples/attach/attacher/views.py | 18 ------------------ public/javascripts/strophejs-1.0.1/examples/attach/boshclient.py | 152 -------------------------------------------------------------------------------------------------------------------------------------------------------- public/javascripts/strophejs-1.0.1/examples/attach/manage.py | 11 ----------- public/javascripts/strophejs-1.0.1/examples/attach/settings.py | 85 ------------------------------------------------------------------------------------- public/javascripts/strophejs-1.0.1/examples/attach/templates/attacher/index.html | 88 ---------------------------------------------------------------------------------------- public/javascripts/strophejs-1.0.1/examples/attach/urls.py | 19 ------------------- public/javascripts/strophejs-1.0.1/examples/basic.html | 25 ------------------------- public/javascripts/strophejs-1.0.1/examples/basic.js | 55 ------------------------------------------------------- public/javascripts/strophejs-1.0.1/examples/crossdomain.html | 32 -------------------------------- public/javascripts/strophejs-1.0.1/examples/crossdomain.js | 62 -------------------------------------------------------------- public/javascripts/strophejs-1.0.1/examples/crossdomain.xml | 12 ------------ public/javascripts/strophejs-1.0.1/examples/dojo-ping.html | 27 --------------------------- public/javascripts/strophejs-1.0.1/examples/dojo-ping.js | 56 -------------------------------------------------------- public/javascripts/strophejs-1.0.1/examples/echobot.html | 25 ------------------------- public/javascripts/strophejs-1.0.1/examples/echobot.js | 79 ------------------------------------------------------------------------------- public/javascripts/strophejs-1.0.1/examples/prebind.html | 39 --------------------------------------- public/javascripts/strophejs-1.0.1/examples/prebind.js | 103 ------------------------------------------------------------------------------------------------------- public/javascripts/strophejs-1.0.1/examples/prototype-ping.html | 27 --------------------------- public/javascripts/strophejs-1.0.1/examples/prototype-ping.js | 56 -------------------------------------------------------- public/javascripts/strophejs-1.0.1/examples/yui-ping.html | 26 -------------------------- public/javascripts/strophejs-1.0.1/examples/yui-ping.js | 58 ---------------------------------------------------------- public/javascripts/strophejs-1.0.1/plugins/strophe.flxhr.js | 31 ------------------------------- public/javascripts/strophejs-1.0.1/plugins/strophe.flxhr.min.js | 1 - public/javascripts/strophejs-1.0.1/plugins/strophe.pubsub.js | 270 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ public/javascripts/strophejs-1.0.1/plugins/strophe.pubsub.min.js | 1 - public/javascripts/strophejs-1.0.1/strophe.js | 3543 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- public/javascripts/strophejs-1.0.1/strophe.min.js | 1 - public/javascripts/strophejs-1.0.1/tests/jstests.js | 136 ---------------------------------------------------------------------------------------------------------------------------------------- public/javascripts/strophejs-1.0.1/tests/jsyuitests.js | 31 ------------------------------- public/javascripts/strophejs-1.0.1/tests/pubsub.html | 28 ---------------------------- public/javascripts/strophejs-1.0.1/tests/pubsub.js | 314 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- public/javascripts/strophejs-1.0.1/tests/strophe.html | 22 ---------------------- public/javascripts/strophejs-1.0.1/tests/testrunner.js | 735 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- public/javascripts/strophejs-1.0.1/tests/tests.js | 163 ------------------------------------------------------------------------------------------------------------------------------------------------------------------- public/javascripts/strophejs-1.0.1/tests/testsuite.css | 120 ------------------------------------------------------------------------------------------------------------------------ public/javascripts/strophejs-1.0.1/tests/yuitests.html | 20 -------------------- public/javascripts/strophejs-1.0.1/tests/yuitests.js | 26 -------------------------- public/javascripts/strophejs-1.1.3/LICENSE.txt | 19 +++++++++++++++++++ public/javascripts/strophejs-1.1.3/README.txt | 15 +++++++++++++++ public/javascripts/strophejs-1.1.3/contrib/discojs/README.txt | 42 ++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/contrib/discojs/css/disco.css | 16 ++++++++++++++++ public/javascripts/strophejs-1.1.3/contrib/discojs/index.html | 47 +++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/contrib/discojs/punjab.tac | 18 ++++++++++++++++++ public/javascripts/strophejs-1.1.3/contrib/discojs/scripts/basic.js | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/contrib/discojs/scripts/disco.js | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/files/strophe-js.html | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/index.html | 1 + public/javascripts/strophejs-1.1.3/doc/index/Classes.html | 33 +++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/index/Constants.html | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/index/Files.html | 41 +++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/index/Functions.html | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/index/General.html | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/index/General2.html | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/index/Variables.html | 41 +++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/javascript/main.js | 841 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/javascript/prettify.js | 1526 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/javascript/searchdata.js | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ClassesS.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ConstantsA.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ConstantsB.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ConstantsC.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ConstantsD.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ConstantsE.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ConstantsF.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ConstantsH.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ConstantsI.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ConstantsL.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ConstantsM.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ConstantsP.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ConstantsR.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ConstantsS.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ConstantsV.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ConstantsW.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/ConstantsX.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FilesB.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FilesS.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FilesW.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsA.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsB.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsC.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsD.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsE.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsF.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsG.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsH.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsI.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsL.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsP.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsR.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsS.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsSymbols.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsT.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsU.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsW.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/FunctionsX.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralA.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralB.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralC.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralD.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralE.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralF.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralG.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralH.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralI.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralL.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralM.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralP.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralR.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralS.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralSymbols.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralT.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralU.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralV.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralW.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/GeneralX.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/NoResults.html | 15 +++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/VariablesA.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/VariablesP.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/search/VariablesS.html | 20 ++++++++++++++++++++ public/javascripts/strophejs-1.1.3/doc/styles/main.css | 828 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/examples/attach/README | 37 +++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/examples/attach/__init__.py | 0 public/javascripts/strophejs-1.1.3/examples/attach/attacher/__init__.py | 0 public/javascripts/strophejs-1.1.3/examples/attach/attacher/views.py | 18 ++++++++++++++++++ public/javascripts/strophejs-1.1.3/examples/attach/boshclient.py | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/examples/attach/manage.py | 11 +++++++++++ public/javascripts/strophejs-1.1.3/examples/attach/settings.py | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/examples/attach/templates/attacher/index.html | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/examples/attach/urls.py | 19 +++++++++++++++++++ public/javascripts/strophejs-1.1.3/examples/basic.html | 22 ++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/examples/basic.js | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/examples/crossdomain.html | 32 ++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/examples/crossdomain.js | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/examples/crossdomain.xml | 12 ++++++++++++ public/javascripts/strophejs-1.1.3/examples/echobot.html | 25 +++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/examples/echobot.js | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/examples/prebind.html | 39 +++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/examples/prebind.js | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/examples/strophe.js | 5139 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/plugins/strophe.flxhr.js | 36 ++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/plugins/strophe.flxhr.min.js | 1 + public/javascripts/strophejs-1.1.3/strophe.js | 5139 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/strophe.min.js | 3 +++ public/javascripts/strophejs-1.1.3/tests/muc.html | 28 ++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/tests/muc.js | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/tests/pubsub.html | 28 ++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/tests/pubsub.js | 314 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/tests/strophe.html | 30 ++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/tests/strophe.js | 5139 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/tests/testrunner.js | 735 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/tests/tests.js | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public/javascripts/strophejs-1.1.3/tests/testsuite.css | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 225 files changed, 23621 insertions(+), 9914 deletions(-) delete mode 100644 public/javascripts/strophejs-1.0.1/LICENSE.txt delete mode 100644 public/javascripts/strophejs-1.0.1/README.txt delete mode 100644 public/javascripts/strophejs-1.0.1/contrib/discojs/README.txt delete mode 100644 public/javascripts/strophejs-1.0.1/contrib/discojs/css/disco.css delete mode 100644 public/javascripts/strophejs-1.0.1/contrib/discojs/index.html delete mode 100644 public/javascripts/strophejs-1.0.1/contrib/discojs/punjab.tac delete mode 100644 public/javascripts/strophejs-1.0.1/contrib/discojs/scripts/basic.js delete mode 100644 public/javascripts/strophejs-1.0.1/contrib/discojs/scripts/disco.js delete mode 100644 public/javascripts/strophejs-1.0.1/doc/files/core-js.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/index.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/javascript/main.js delete mode 100644 public/javascripts/strophejs-1.0.1/doc/javascript/searchdata.js delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ClassesS.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ConstantsA.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ConstantsB.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ConstantsC.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ConstantsD.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ConstantsE.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ConstantsF.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ConstantsH.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ConstantsI.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ConstantsL.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ConstantsM.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ConstantsP.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ConstantsR.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ConstantsS.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ConstantsV.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ConstantsW.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/ConstantsX.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FilesS.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsA.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsB.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsC.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsD.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsE.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsF.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsG.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsI.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsL.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsP.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsR.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsS.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsSymbols.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsT.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsU.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsW.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/FunctionsX.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralA.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralB.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralC.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralD.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralE.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralF.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralG.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralH.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralI.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralL.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralM.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralP.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralR.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralS.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralSymbols.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralT.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralU.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralV.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralW.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/GeneralX.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/search/NoResults.html delete mode 100644 public/javascripts/strophejs-1.0.1/doc/styles/main.css delete mode 100644 public/javascripts/strophejs-1.0.1/examples/attach/README delete mode 100644 public/javascripts/strophejs-1.0.1/examples/attach/__init__.py delete mode 100644 public/javascripts/strophejs-1.0.1/examples/attach/attacher/__init__.py delete mode 100644 public/javascripts/strophejs-1.0.1/examples/attach/attacher/views.py delete mode 100644 public/javascripts/strophejs-1.0.1/examples/attach/boshclient.py delete mode 100755 public/javascripts/strophejs-1.0.1/examples/attach/manage.py delete mode 100644 public/javascripts/strophejs-1.0.1/examples/attach/settings.py delete mode 100644 public/javascripts/strophejs-1.0.1/examples/attach/templates/attacher/index.html delete mode 100644 public/javascripts/strophejs-1.0.1/examples/attach/urls.py delete mode 100644 public/javascripts/strophejs-1.0.1/examples/basic.html delete mode 100644 public/javascripts/strophejs-1.0.1/examples/basic.js delete mode 100644 public/javascripts/strophejs-1.0.1/examples/crossdomain.html delete mode 100644 public/javascripts/strophejs-1.0.1/examples/crossdomain.js delete mode 100644 public/javascripts/strophejs-1.0.1/examples/crossdomain.xml delete mode 100644 public/javascripts/strophejs-1.0.1/examples/dojo-ping.html delete mode 100644 public/javascripts/strophejs-1.0.1/examples/dojo-ping.js delete mode 100644 public/javascripts/strophejs-1.0.1/examples/echobot.html delete mode 100644 public/javascripts/strophejs-1.0.1/examples/echobot.js delete mode 100644 public/javascripts/strophejs-1.0.1/examples/prebind.html delete mode 100644 public/javascripts/strophejs-1.0.1/examples/prebind.js delete mode 100644 public/javascripts/strophejs-1.0.1/examples/prototype-ping.html delete mode 100644 public/javascripts/strophejs-1.0.1/examples/prototype-ping.js delete mode 100644 public/javascripts/strophejs-1.0.1/examples/yui-ping.html delete mode 100644 public/javascripts/strophejs-1.0.1/examples/yui-ping.js delete mode 100644 public/javascripts/strophejs-1.0.1/plugins/strophe.flxhr.js delete mode 100644 public/javascripts/strophejs-1.0.1/plugins/strophe.flxhr.min.js delete mode 100644 public/javascripts/strophejs-1.0.1/plugins/strophe.pubsub.js delete mode 100644 public/javascripts/strophejs-1.0.1/plugins/strophe.pubsub.min.js delete mode 100644 public/javascripts/strophejs-1.0.1/strophe.js delete mode 100644 public/javascripts/strophejs-1.0.1/strophe.min.js delete mode 100644 public/javascripts/strophejs-1.0.1/tests/jstests.js delete mode 100644 public/javascripts/strophejs-1.0.1/tests/jsyuitests.js delete mode 100644 public/javascripts/strophejs-1.0.1/tests/pubsub.html delete mode 100644 public/javascripts/strophejs-1.0.1/tests/pubsub.js delete mode 100644 public/javascripts/strophejs-1.0.1/tests/strophe.html delete mode 100644 public/javascripts/strophejs-1.0.1/tests/testrunner.js delete mode 100644 public/javascripts/strophejs-1.0.1/tests/tests.js delete mode 100644 public/javascripts/strophejs-1.0.1/tests/testsuite.css delete mode 100644 public/javascripts/strophejs-1.0.1/tests/yuitests.html delete mode 100644 public/javascripts/strophejs-1.0.1/tests/yuitests.js create mode 100644 public/javascripts/strophejs-1.1.3/LICENSE.txt create mode 100644 public/javascripts/strophejs-1.1.3/README.txt create mode 100644 public/javascripts/strophejs-1.1.3/contrib/discojs/README.txt create mode 100644 public/javascripts/strophejs-1.1.3/contrib/discojs/css/disco.css create mode 100644 public/javascripts/strophejs-1.1.3/contrib/discojs/index.html create mode 100644 public/javascripts/strophejs-1.1.3/contrib/discojs/punjab.tac create mode 100644 public/javascripts/strophejs-1.1.3/contrib/discojs/scripts/basic.js create mode 100644 public/javascripts/strophejs-1.1.3/contrib/discojs/scripts/disco.js create mode 100644 public/javascripts/strophejs-1.1.3/doc/files/strophe-js.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/index.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/index/Classes.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/index/Constants.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/index/Files.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/index/Functions.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/index/General.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/index/General2.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/index/Variables.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/javascript/main.js create mode 100644 public/javascripts/strophejs-1.1.3/doc/javascript/prettify.js create mode 100644 public/javascripts/strophejs-1.1.3/doc/javascript/searchdata.js create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ClassesS.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ConstantsA.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ConstantsB.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ConstantsC.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ConstantsD.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ConstantsE.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ConstantsF.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ConstantsH.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ConstantsI.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ConstantsL.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ConstantsM.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ConstantsP.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ConstantsR.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ConstantsS.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ConstantsV.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ConstantsW.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/ConstantsX.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FilesB.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FilesS.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FilesW.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsA.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsB.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsC.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsD.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsE.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsF.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsG.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsH.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsI.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsL.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsP.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsR.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsS.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsSymbols.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsT.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsU.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsW.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/FunctionsX.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralA.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralB.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralC.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralD.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralE.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralF.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralG.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralH.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralI.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralL.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralM.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralP.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralR.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralS.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralSymbols.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralT.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralU.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralV.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralW.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/GeneralX.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/NoResults.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/VariablesA.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/VariablesP.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/search/VariablesS.html create mode 100644 public/javascripts/strophejs-1.1.3/doc/styles/main.css create mode 100644 public/javascripts/strophejs-1.1.3/examples/attach/README create mode 100644 public/javascripts/strophejs-1.1.3/examples/attach/__init__.py create mode 100644 public/javascripts/strophejs-1.1.3/examples/attach/attacher/__init__.py create mode 100644 public/javascripts/strophejs-1.1.3/examples/attach/attacher/views.py create mode 100644 public/javascripts/strophejs-1.1.3/examples/attach/boshclient.py create mode 100644 public/javascripts/strophejs-1.1.3/examples/attach/manage.py create mode 100644 public/javascripts/strophejs-1.1.3/examples/attach/settings.py create mode 100644 public/javascripts/strophejs-1.1.3/examples/attach/templates/attacher/index.html create mode 100644 public/javascripts/strophejs-1.1.3/examples/attach/urls.py create mode 100644 public/javascripts/strophejs-1.1.3/examples/basic.html create mode 100644 public/javascripts/strophejs-1.1.3/examples/basic.js create mode 100644 public/javascripts/strophejs-1.1.3/examples/crossdomain.html create mode 100644 public/javascripts/strophejs-1.1.3/examples/crossdomain.js create mode 100644 public/javascripts/strophejs-1.1.3/examples/crossdomain.xml create mode 100644 public/javascripts/strophejs-1.1.3/examples/echobot.html create mode 100644 public/javascripts/strophejs-1.1.3/examples/echobot.js create mode 100644 public/javascripts/strophejs-1.1.3/examples/prebind.html create mode 100644 public/javascripts/strophejs-1.1.3/examples/prebind.js create mode 100644 public/javascripts/strophejs-1.1.3/examples/strophe.js create mode 100644 public/javascripts/strophejs-1.1.3/plugins/strophe.flxhr.js create mode 100644 public/javascripts/strophejs-1.1.3/plugins/strophe.flxhr.min.js create mode 100644 public/javascripts/strophejs-1.1.3/strophe.js create mode 100644 public/javascripts/strophejs-1.1.3/strophe.min.js create mode 100644 public/javascripts/strophejs-1.1.3/tests/muc.html create mode 100644 public/javascripts/strophejs-1.1.3/tests/muc.js create mode 100644 public/javascripts/strophejs-1.1.3/tests/pubsub.html create mode 100644 public/javascripts/strophejs-1.1.3/tests/pubsub.js create mode 100644 public/javascripts/strophejs-1.1.3/tests/strophe.html create mode 100644 public/javascripts/strophejs-1.1.3/tests/strophe.js create mode 100644 public/javascripts/strophejs-1.1.3/tests/testrunner.js create mode 100644 public/javascripts/strophejs-1.1.3/tests/tests.js create mode 100644 public/javascripts/strophejs-1.1.3/tests/testsuite.css diff --git a/app/views/shared/logged_in/xmpp_chat.html.erb b/app/views/shared/logged_in/xmpp_chat.html.erb index 03a16ae..176fc9c 100644 --- a/app/views/shared/logged_in/xmpp_chat.html.erb +++ b/app/views/shared/logged_in/xmpp_chat.html.erb @@ -1,4 +1,4 @@ - <%= javascript_include_tag 'strophejs-1.0.1/strophe', 'jquery.emoticon', '../designs/icons/pidgin/emoticons.js', 'ba-linkify', 'jquery.ba-hashchange', 'jquery.sound', 'chat', 'perfect-scrollbar.min.js', 'perfect-scrollbar.with-mousewheel.min.js', :cache => 'cache/chat' %> + <%= javascript_include_tag 'strophejs-1.1.3/strophe.min', 'jquery.emoticon', '../designs/icons/pidgin/emoticons.js', 'ba-linkify', 'jquery.ba-hashchange', 'jquery.sound', 'chat', 'perfect-scrollbar.min.js', 'perfect-scrollbar.with-mousewheel.min.js', :cache => 'cache/chat' %> <%= stylesheet_link_tag 'perfect-scrollbar.min.css' %> <% extend ChatHelper %> diff --git a/public/javascripts/strophejs-1.0.1/LICENSE.txt b/public/javascripts/strophejs-1.0.1/LICENSE.txt deleted file mode 100644 index 06d6642..0000000 --- a/public/javascripts/strophejs-1.0.1/LICENSE.txt +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2006-2009 Collecta, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/public/javascripts/strophejs-1.0.1/README.txt b/public/javascripts/strophejs-1.0.1/README.txt deleted file mode 100644 index 971929b..0000000 --- a/public/javascripts/strophejs-1.0.1/README.txt +++ /dev/null @@ -1,15 +0,0 @@ -Strophe.js is a JavaScript library for speaking XMPP via BOSH (XEP 124 -and 206). It is licensed under the MIT license, except for the files -base64.js and md5.js, which are licensed as public domain and -BSD (see these files for details). - -It has been tested on Firefox 1.5, 2.x, and 3.x, IE 6, 7, and 8, Safari, Mobile -Safari, Chrome, and it should also work on the mobile Opera browser as -well as the desktop Opera browser. - -The homepage for Strophe is http://code.stanziq.com/strophe. - -The book Professional XMPP Programming with JavaScript and jQuery is -also available, which covers Strophe in detail in the context of web -applications. You can find more information at -http://professionalxmpp.com. diff --git a/public/javascripts/strophejs-1.0.1/contrib/discojs/README.txt b/public/javascripts/strophejs-1.0.1/contrib/discojs/README.txt deleted file mode 100644 index 78e1dbc..0000000 --- a/public/javascripts/strophejs-1.0.1/contrib/discojs/README.txt +++ /dev/null @@ -1,42 +0,0 @@ -Disco Dancing with XMPP - - There are many things one can do via XMPP. The list is - endlist. But one thing that some forget about is discovering - services a XMPP entity or server provides. In most cases a human or - user does not care about this information and should not care. But - you may have a website or web application that needs this - information in order to decide what options to show to your - users. You can do this very easily with JQuery, Strophe, and - Punjab. - - We start with Punjab or a BOSH connection manager. This is - needed so we can connect to a XMPP server. First, lets download - punjab. - - svn co https://code.stanziq.com/svn/punjab/trunk punjab - - After we have punjab go into the directory and install punjab. - - cd punjab - python setup.py install - - Then create a .tac file to configure Punjab. - - See punjab.tac - - Next, we will need Strophe. Lets download thelatest version from - svn too. - - cd /directory/where/you/configured/punjab/html - - svn co https://code.stanziq.com/svn/strophe/trunk/strophejs - - In your html directory you will then begin to create your disco browser. - - Version 1 we take the basic example and modify it to do disco. - - Version 2 we add anonymous login - - Version 3 we make it pretty - - Version 4 we add handlers for different services diff --git a/public/javascripts/strophejs-1.0.1/contrib/discojs/css/disco.css b/public/javascripts/strophejs-1.0.1/contrib/discojs/css/disco.css deleted file mode 100644 index 4ffdd97..0000000 --- a/public/javascripts/strophejs-1.0.1/contrib/discojs/css/disco.css +++ /dev/null @@ -1,16 +0,0 @@ -#login .leftinput -{ - margin-bottom: .5em; -} - -#login input -{ - margin-bottom: 10px; -} - -#log { - width: 100%; - height: 200px; - overflow: auto; - - } diff --git a/public/javascripts/strophejs-1.0.1/contrib/discojs/index.html b/public/javascripts/strophejs-1.0.1/contrib/discojs/index.html deleted file mode 100644 index e2ed869..0000000 --- a/public/javascripts/strophejs-1.0.1/contrib/discojs/index.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - XMPP Disco Dancing - - - - - - - - - - -
-
- - - - - -
-
-
-
-
-
-
-
-Status Log : -
- - diff --git a/public/javascripts/strophejs-1.0.1/contrib/discojs/punjab.tac b/public/javascripts/strophejs-1.0.1/contrib/discojs/punjab.tac deleted file mode 100644 index 7b2e8c6..0000000 --- a/public/javascripts/strophejs-1.0.1/contrib/discojs/punjab.tac +++ /dev/null @@ -1,18 +0,0 @@ -# punjab tac file -from twisted.web import server, resource, static -from twisted.application import service, internet - -from punjab.httpb import Httpb, HttpbService - -root = static.File("./") # This needs to be the directory - # where you will have your html - # and javascript. - -b = resource.IResource(HttpbService(1)) # turn on debug with 1 -root.putChild('bosh', b) - - -site = server.Site(root) - -application = service.Application("punjab") -internet.TCPServer(5280, site).setServiceParent(application) diff --git a/public/javascripts/strophejs-1.0.1/contrib/discojs/scripts/basic.js b/public/javascripts/strophejs-1.0.1/contrib/discojs/scripts/basic.js deleted file mode 100644 index 4e01f08..0000000 --- a/public/javascripts/strophejs-1.0.1/contrib/discojs/scripts/basic.js +++ /dev/null @@ -1,102 +0,0 @@ -var BOSH_SERVICE = 'http://localhost:5280/bosh'; - -var connection = null; -var browser = null; -var show_log = true; - -function log(msg) -{ - $('#log').append('
').append(document.createTextNode(msg)); -} - - -function rawInput(data) -{ - log('RECV: ' + data); -} - -function rawOutput(data) -{ - log('SENT: ' + data); -} - -function onConnect(status) -{ - if (status == Strophe.Status.CONNECTING) { - log('Strophe is connecting.'); - - } else if (status == Strophe.Status.CONNFAIL) { - log('Strophe failed to connect.'); - showConnect(); - } else if (status == Strophe.Status.DISCONNECTING) { - log('Strophe is disconnecting.'); - } else if (status == Strophe.Status.DISCONNECTED) { - log('Strophe is disconnected.'); - showConnect(); - - } else if (status == Strophe.Status.CONNECTED) { - log('Strophe is connected.'); - // Start up disco browser - browser.showBrowser(); - } -} - -function showConnect() -{ - var jid = $('#jid'); - var pass = $('#pass'); - var button = $('#connect').get(0); - - browser.closeBrowser(); - - $('label').show(); - jid.show(); - pass.show(); - $('#anon').show(); - button.value = 'connect'; - return false; -} - -function showDisconnect() -{ - var jid = $('#jid'); - var pass = $('#pass'); - var button = $('#connect').get(0); - - button.value = 'disconnect'; - pass.hide(); - jid.hide(); - $('label').hide(); - $('#anon').hide(); - return false; -} - -$(document).ready(function () { - connection = new Strophe.Connection(BOSH_SERVICE); - connection.rawInput = rawInput; - connection.rawOutput = rawOutput; - - browser = new Disco(); - - $("#log_container").bind('click', function () { - $("#log").toggle(); - } - ); - - $('#cred').bind('submit', function () { - var button = $('#connect').get(0); - var jid = $('#jid'); - var pass = $('#pass'); - - if (button.value == 'connect') { - showDisconnect(); - connection.connect(jid.get(0).value, - pass.get(0).value, - onConnect); - } else { - connection.disconnect(); - showConnect(); - } - return false; - }); -}); \ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/contrib/discojs/scripts/disco.js b/public/javascripts/strophejs-1.0.1/contrib/discojs/scripts/disco.js deleted file mode 100644 index a1d7ed5..0000000 --- a/public/javascripts/strophejs-1.0.1/contrib/discojs/scripts/disco.js +++ /dev/null @@ -1,60 +0,0 @@ - -var NS_DISCO_INFO = 'http://jabber.org/protocol/disco#info'; -var NS_DISCO_ITEM = 'http://jabber.org/protocol/disco#items'; - - -// Disco stuff -Disco = function () { - // Class that does nothing -}; - -Disco.prototype = { - showBrowser: function() { - // Browser Display - var disco = $('#disco'); - var jid = $('#jid'); - var server = connection.jid.split('@')[1]; - - // display input box - disco.append("
Server :
"); - - // add handler for search form - $("#browse").bind('submit', function () { - this.startBrowse($("#server").get(0).value); - return false; - }); - - this.startBrowse(server); - }, - - closeBrowser: function() { - var disco = $('#disco'); - - disco.empty(); - }, - - startBrowse: function(server) { - // build iq request - var id = 'startBrowse'; - - var discoiq = $iq({'from':connection.jid+"/"+connection.resource, - 'to':server, - 'id':id, - 'type':'get'} - ) - .c('query', {'xmlns': NS_DISCO_INFO}); - - connection.addHandler(this._cbBrowse, null, 'iq', 'result', id); - connection.send(discoiq.tree()); - - }, - - _cbBrowse: function(e) { - var elem = $(e); // make this Element a JQuery Element - alert(e); - - return false; // return false to remove the handler - }, - -}; - diff --git a/public/javascripts/strophejs-1.0.1/doc/files/core-js.html b/public/javascripts/strophejs-1.0.1/doc/files/core-js.html deleted file mode 100644 index 54097e1..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/files/core-js.html +++ /dev/null @@ -1,189 +0,0 @@ - - -strophe.js - - - - - - - - - -

strophe.js

A JavaScript library for XMPP BOSH.

This is the JavaScript version of the Strophe library.  Since JavaScript has no facilities for persistent TCP connections, this library uses Bidirectional-streams Over Synchronous HTTP (BOSH) to emulate a persistent, stateful, two-way connection to an XMPP server.  More information on BOSH can be found in XEP 124.

Summary
strophe.jsA JavaScript library for XMPP BOSH.
Functions
$buildCreate a Strophe.Builder.
$msgCreate a Strophe.Builder with a <message/> element as the root.
$iqCreate a Strophe.Builder with an <iq/> element as the root.
$presCreate a Strophe.Builder with a <presence/> element as the root.
StropheAn object container for all Strophe library functions.
Constants
VERSIONThe version of the Strophe library.
XMPP Namespace ConstantsCommon namespace constants from the XMPP RFCs and XEPs.
Functions
addNamespaceThis function is used to extend the current namespaces in Strophe.NS.
Constants
Connection Status ConstantsConnection status constants for use by the connection handler callback.
Log Level ConstantsLogging level indicators.
Functions
forEachChildMap a function over some or all child elements of a given element.
isTagEqualCompare an element’s tag name with a string.
xmlElementCreate an XML DOM element.
xmlescapeExcapes invalid xml characters.
xmlTextNodeCreates an XML DOM text node.
getTextGet the concatenation of all text children of an element.
copyElementCopy an XML DOM element.
escapeNodeEscape the node part (also called local part) of a JID.
unescapeNodeUnescape a node part (also called local part) of a JID.
getNodeFromJidGet the node portion of a JID String.
getDomainFromJidGet the domain portion of a JID String.
getResourceFromJidGet the resource portion of a JID String.
getBareJidFromJidGet the bare JID from a JID String.
logUser overrideable logging function.
debugLog a message at the Strophe.LogLevel.DEBUG level.
infoLog a message at the Strophe.LogLevel.INFO level.
warnLog a message at the Strophe.LogLevel.WARN level.
errorLog a message at the Strophe.LogLevel.ERROR level.
fatalLog a message at the Strophe.LogLevel.FATAL level.
serializeRender a DOM element and all descendants to a String.
addConnectionPluginExtends the Strophe.Connection object with the given plugin.
Strophe.BuilderXML DOM builder.
Functions
Strophe.BuilderCreate a Strophe.Builder object.
treeReturn the DOM tree.
toStringSerialize the DOM tree to a String.
upMake the current parent element the new current element.
attrsAdd or modify attributes of the current element.
cAdd a child to the current element and make it the new current element.
cnodeAdd a child to the current element and make it the new current element.
tAdd a child text element.
Strophe.ConnectionXMPP Connection manager.
Functions
Strophe.ConnectionCreate and initialize a Strophe.Connection object.
resetReset the connection.
pausePause the request manager.
resumeResume the request manager.
getUniqueIdGenerate a unique ID for use in <iq/> elements.
connectStarts the connection process.
attachAttach to an already created and authenticated BOSH session.
xmlInputUser overrideable function that receives XML data coming into the connection.
xmlOutputUser overrideable function that receives XML data sent to the connection.
rawInputUser overrideable function that receives raw data coming into the connection.
rawOutputUser overrideable function that receives raw data sent to the connection.
sendSend a stanza.
flushImmediately send any pending outgoing data.
sendIQHelper function to send IQ stanzas.
addTimedHandlerAdd a timed handler to the connection.
deleteTimedHandlerDelete a timed handler for a connection.
addHandlerAdd a stanza handler for the connection.
deleteHandlerDelete a stanza handler for a connection.
disconnectStart the graceful disconnection process.
- -

Functions

- -

$build

function $build(name,
attrs)

Create a Strophe.Builder.  This is an alias for ‘new Strophe.Builder(name, attrs)’.

Parameters

(String) nameThe root element name.
(Object) attrsThe attributes for the root element in object notation.

Returns

A new Strophe.Builder object.

- -

$msg

function $msg(attrs)

Create a Strophe.Builder with a <message/> element as the root.

Parmaeters

(Object) attrsThe <message/> element attributes in object notation.

Returns

A new Strophe.Builder object.

- -

$iq

function $iq(attrs)

Create a Strophe.Builder with an <iq/> element as the root.

Parameters

(Object) attrsThe <iq/> element attributes in object notation.

Returns

A new Strophe.Builder object.

- -

$pres

function $pres(attrs)

Create a Strophe.Builder with a <presence/> element as the root.

Parameters

(Object) attrsThe <presence/> element attributes in object notation.

Returns

A new Strophe.Builder object.

- -

Strophe

An object container for all Strophe library functions.

This class is just a container for all the objects and constants used in the library.  It is not meant to be instantiated, but to provide a namespace for library objects, constants, and functions.

Summary
Constants
VERSIONThe version of the Strophe library.
XMPP Namespace ConstantsCommon namespace constants from the XMPP RFCs and XEPs.
Functions
addNamespaceThis function is used to extend the current namespaces in Strophe.NS.
Constants
Connection Status ConstantsConnection status constants for use by the connection handler callback.
Log Level ConstantsLogging level indicators.
Functions
forEachChildMap a function over some or all child elements of a given element.
isTagEqualCompare an element’s tag name with a string.
xmlElementCreate an XML DOM element.
xmlescapeExcapes invalid xml characters.
xmlTextNodeCreates an XML DOM text node.
getTextGet the concatenation of all text children of an element.
copyElementCopy an XML DOM element.
escapeNodeEscape the node part (also called local part) of a JID.
unescapeNodeUnescape a node part (also called local part) of a JID.
getNodeFromJidGet the node portion of a JID String.
getDomainFromJidGet the domain portion of a JID String.
getResourceFromJidGet the resource portion of a JID String.
getBareJidFromJidGet the bare JID from a JID String.
logUser overrideable logging function.
debugLog a message at the Strophe.LogLevel.DEBUG level.
infoLog a message at the Strophe.LogLevel.INFO level.
warnLog a message at the Strophe.LogLevel.WARN level.
errorLog a message at the Strophe.LogLevel.ERROR level.
fatalLog a message at the Strophe.LogLevel.FATAL level.
serializeRender a DOM element and all descendants to a String.
addConnectionPluginExtends the Strophe.Connection object with the given plugin.
- -

Constants

- -

VERSION

The version of the Strophe library.  Unreleased builds will have a version of head-HASH where HASH is a partial revision.

- -

XMPP Namespace Constants

Common namespace constants from the XMPP RFCs and XEPs.

NS.HTTPBINDHTTP BIND namespace from XEP 124.
NS.BOSHBOSH namespace from XEP 206.
NS.CLIENTMain XMPP client namespace.
NS.AUTHLegacy authentication namespace.
NS.ROSTERRoster operations namespace.
NS.PROFILEProfile namespace.
NS.DISCO_INFOService discovery info namespace from XEP 30.
NS.DISCO_ITEMSService discovery items namespace from XEP 30.
NS.MUCMulti-User Chat namespace from XEP 45.
NS.SASLXMPP SASL namespace from RFC 3920.
NS.STREAMXMPP Streams namespace from RFC 3920.
NS.BINDXMPP Binding namespace from RFC 3920.
NS.SESSIONXMPP Session namespace from RFC 3920.
- -

Functions

- -

addNamespace

addNamespace: function (name,
value)

This function is used to extend the current namespaces in Strophe.NS.  It takes a key and a value with the key being the name of the new namespace, with its actual value.  For example: Strophe.addNamespace(‘PUBSUB’, “http://jabber.org/protocol/pubsub”);

Parameters

(String) nameThe name under which the namespace will be referenced under Strophe.NS
(String) valueThe actual namespace.
- -

Constants

- -

Connection Status Constants

Connection status constants for use by the connection handler callback.

Status.ERRORAn error has occurred
Status.CONNECTINGThe connection is currently being made
Status.CONNFAILThe connection attempt failed
Status.AUTHENTICATINGThe connection is authenticating
Status.AUTHFAILThe authentication attempt failed
Status.CONNECTEDThe connection has succeeded
Status.DISCONNECTEDThe connection has been terminated
Status.DISCONNECTINGThe connection is currently being terminated
Status.ATTACHEDThe connection has been attached
- -

Log Level Constants

Logging level indicators.

LogLevel.DEBUGDebug output
LogLevel.INFOInformational output
LogLevel.WARNWarnings
LogLevel.ERRORErrors
LogLevel.FATALFatal errors
- -

Functions

- -

forEachChild

forEachChild: function (elem,
elemName,
func)

Map a function over some or all child elements of a given element.

This is a small convenience function for mapping a function over some or all of the children of an element.  If elemName is null, all children will be passed to the function, otherwise only children whose tag names match elemName will be passed.

Parameters

(XMLElement) elemThe element to operate on.
(String) elemNameThe child element tag name filter.
(Function) funcThe function to apply to each child.  This function should take a single argument, a DOM element.
- -

isTagEqual

isTagEqual: function (el,
name)

Compare an element’s tag name with a string.

This function is case insensitive.

Parameters

(XMLElement) elA DOM element.
(String) nameThe element name.

Returns

true if the element’s tag name matches el, and false otherwise.

- -

xmlElement

xmlElement: function (name)

Create an XML DOM element.

This function creates an XML DOM element correctly across all implementations.  Specifically the Microsoft implementation of document.createElement makes DOM elements with 43+ default attributes unless elements are created with the ActiveX object Microsoft.XMLDOM.

Most DOMs force element names to lowercase, so we use the _realname attribute on the created element to store the case sensitive name.  This is required to generate proper XML for things like vCard avatars (XEP 153).  This attribute is stripped out before being sent over the wire or serialized, but you may notice it during debugging.

Parameters

(String) nameThe name for the element.
(Array) attrsAn optional array of key/value pairs to use as element attributes in the following format [[‘key1’, ‘value1’], [‘key2’, ‘value2’]]
(String) textThe text child data for the element.

Returns

A new XML DOM element.

- -

xmlescape

xmlescape: function(text)

Excapes invalid xml characters.

Parameters

(String) texttext to escape.

Returns

Escaped text.

- -

xmlTextNode

xmlTextNode: function (text)

Creates an XML DOM text node.

Provides a cross implementation version of document.createTextNode.

Parameters

(String) textThe content of the text node.

Returns

A new XML DOM text node.

- -

getText

getText: function (elem)

Get the concatenation of all text children of an element.

Parameters

(XMLElement) elemA DOM element.

Returns

A String with the concatenated text of all text element children.

- -

copyElement

copyElement: function (elem)

Copy an XML DOM element.

This function copies a DOM element and all its descendants and returns the new copy.

Parameters

(XMLElement) elemA DOM element.

Returns

A new, copied DOM element tree.

- -

escapeNode

escapeNode: function (node)

Escape the node part (also called local part) of a JID.

Parameters

(String) nodeA node (or local part).

Returns

An escaped node (or local part).

- -

unescapeNode

unescapeNode: function (node)

Unescape a node part (also called local part) of a JID.

Parameters

(String) nodeA node (or local part).

Returns

An unescaped node (or local part).

- -

getNodeFromJid

getNodeFromJid: function (jid)

Get the node portion of a JID String.

Parameters

(String) jidA JID.

Returns

A String containing the node.

- -

getDomainFromJid

getDomainFromJid: function (jid)

Get the domain portion of a JID String.

Parameters

(String) jidA JID.

Returns

A String containing the domain.

- -

getResourceFromJid

getResourceFromJid: function (jid)

Get the resource portion of a JID String.

Parameters

(String) jidA JID.

Returns

A String containing the resource.

- -

getBareJidFromJid

getBareJidFromJid: function (jid)

Get the bare JID from a JID String.

Parameters

(String) jidA JID.

Returns

A String containing the bare JID.

- -

log

log: function (level,
msg)

User overrideable logging function.

This function is called whenever the Strophe library calls any of the logging functions.  The default implementation of this function does nothing.  If client code wishes to handle the logging messages, it should override this with

Strophe.log = function (level, msg) {
-  (user code here)
-};

Please note that data sent and received over the wire is logged via Strophe.Connection.rawInput() and Strophe.Connection.rawOutput().

The different levels and their meanings are

DEBUGMessages useful for debugging purposes.
INFOInformational messages.  This is mostly information like ‘disconnect was called’ or ‘SASL auth succeeded’.
WARNWarnings about potential problems.  This is mostly used to report transient connection errors like request timeouts.
ERRORSome error occurred.
FATALA non-recoverable fatal error occurred.

Parameters

(Integer) levelThe log level of the log message.  This will be one of the values in Strophe.LogLevel.
(String) msgThe log message.
- -

debug

debug: function(msg)

Log a message at the Strophe.LogLevel.DEBUG level.

Parameters

(String) msgThe log message.
- -

info

info: function (msg)

Log a message at the Strophe.LogLevel.INFO level.

Parameters

(String) msgThe log message.
- -

warn

warn: function (msg)

Log a message at the Strophe.LogLevel.WARN level.

Parameters

(String) msgThe log message.
- -

error

error: function (msg)

Log a message at the Strophe.LogLevel.ERROR level.

Parameters

(String) msgThe log message.
- -

fatal

fatal: function (msg)

Log a message at the Strophe.LogLevel.FATAL level.

Parameters

(String) msgThe log message.
- -

serialize

serialize: function (elem)

Render a DOM element and all descendants to a String.

Parameters

(XMLElement) elemA DOM element.

Returns

The serialized element tree as a String.

- -

addConnectionPlugin

addConnectionPlugin: function (name,
ptype)

Extends the Strophe.Connection object with the given plugin.

Paramaters

(String) nameThe name of the extension.
(Object) ptypeThe plugin’s prototype.
- -

Strophe.Builder

XML DOM builder.

This object provides an interface similar to JQuery but for building DOM element easily and rapidly.  All the functions except for toString() and tree() return the object, so calls can be chained.  Here’s an example using the $iq() builder helper.

$iq({to: 'you': from: 'me': type: 'get', id: '1'})
-    .c('query', {xmlns: 'strophe:example'})
-    .c('example')
-    .toString()

The above generates this XML fragment

<iq to='you' from='me' type='get' id='1'>
-  <query xmlns='strophe:example'>
-    <example/>
-  </query>
-</iq>

The corresponding DOM manipulations to get a similar fragment would be a lot more tedious and probably involve several helper variables.

Since adding children makes new operations operate on the child, up() is provided to traverse up the tree.  To add two children, do

builder.c('child1', ...).up().c('child2', ...)

The next operation on the Builder will be relative to the second child.

Summary
Functions
Strophe.BuilderCreate a Strophe.Builder object.
treeReturn the DOM tree.
toStringSerialize the DOM tree to a String.
upMake the current parent element the new current element.
attrsAdd or modify attributes of the current element.
cAdd a child to the current element and make it the new current element.
cnodeAdd a child to the current element and make it the new current element.
tAdd a child text element.
- -

Functions

- -

Strophe.Builder

Strophe.Builder = function (name,
attrs)

Create a Strophe.Builder object.

The attributes should be passed in object notation.  For example

var b = new Builder('message', {to: 'you', from: 'me'});

or

var b = new Builder('messsage', {'xml:lang': 'en'});

Parameters

(String) nameThe name of the root element.
(Object) attrsThe attributes for the root element in object notation.

Returns

A new Strophe.Builder.

- -

tree

tree: function ()

Return the DOM tree.

This function returns the current DOM tree as an element object.  This is suitable for passing to functions like Strophe.Connection.send().

Returns

The DOM tree as a element object.

- -

toString

toString: function ()

Serialize the DOM tree to a String.

This function returns a string serialization of the current DOM tree.  It is often used internally to pass data to a Strophe.Request object.

Returns

The serialized DOM tree in a String.

- -

up

up: function ()

Make the current parent element the new current element.

This function is often used after c() to traverse back up the tree.  For example, to add two children to the same element

builder.c('child1', {}).up().c('child2', {});

Returns

The Stophe.Builder object.

- -

attrs

attrs: function (moreattrs)

Add or modify attributes of the current element.

The attributes should be passed in object notation.  This function does not move the current element pointer.

Parameters

(Object) moreattrsThe attributes to add/modify in object notation.

Returns

The Strophe.Builder object.

- -

c

c: function (name,
attrs)

Add a child to the current element and make it the new current element.

This function moves the current element pointer to the child.  If you need to add another child, it is necessary to use up() to go back to the parent in the tree.

Parameters

(String) nameThe name of the child.
(Object) attrsThe attributes of the child in object notation.

Returns

The Strophe.Builder object.

- -

cnode

cnode: function (elem)

Add a child to the current element and make it the new current element.

This function is the same as c() except that instead of using a name and an attributes object to create the child it uses an existing DOM element object.

Parameters

(XMLElement) elemA DOM element.

Returns

The Strophe.Builder object.

- -

t

t: function (text)

Add a child text element.

This does not make the child the new current element since there are no children of text elements.

Parameters

(String) textThe text data to append to the current element.

Returns

The Strophe.Builder object.

- -

Strophe.Connection

XMPP Connection manager.

Thie class is the main part of Strophe.  It manages a BOSH connection to an XMPP server and dispatches events to the user callbacks as data arrives.  It supports SASL PLAIN, SASL DIGEST-MD5, and legacy authentication.

After creating a Strophe.Connection object, the user will typically call connect() with a user supplied callback to handle connection level events like authentication failure, disconnection, or connection complete.

The user will also have several event handlers defined by using addHandler() and addTimedHandler().  These will allow the user code to respond to interesting stanzas or do something periodically with the connection.  These handlers will be active once authentication is finished.

To send data to the connection, use send().

Summary
Functions
Strophe.ConnectionCreate and initialize a Strophe.Connection object.
resetReset the connection.
pausePause the request manager.
resumeResume the request manager.
getUniqueIdGenerate a unique ID for use in <iq/> elements.
connectStarts the connection process.
attachAttach to an already created and authenticated BOSH session.
xmlInputUser overrideable function that receives XML data coming into the connection.
xmlOutputUser overrideable function that receives XML data sent to the connection.
rawInputUser overrideable function that receives raw data coming into the connection.
rawOutputUser overrideable function that receives raw data sent to the connection.
sendSend a stanza.
flushImmediately send any pending outgoing data.
sendIQHelper function to send IQ stanzas.
addTimedHandlerAdd a timed handler to the connection.
deleteTimedHandlerDelete a timed handler for a connection.
addHandlerAdd a stanza handler for the connection.
deleteHandlerDelete a stanza handler for a connection.
disconnectStart the graceful disconnection process.
- -

Functions

- -

Strophe.Connection

Strophe.Connection = function (service)

Create and initialize a Strophe.Connection object.

Parameters

(String) serviceThe BOSH service URL.

Returns

A new Strophe.Connection object.

- -

reset

reset: function ()

Reset the connection.

This function should be called after a connection is disconnected before that connection is reused.

- -

pause

pause: function ()

Pause the request manager.

This will prevent Strophe from sending any more requests to the server.  This is very useful for temporarily pausing while a lot of send() calls are happening quickly.  This causes Strophe to send the data in a single request, saving many request trips.

- -

resume

resume: function ()

Resume the request manager.

This resumes after pause() has been called.

- -

getUniqueId

getUniqueId: function (suffix)

Generate a unique ID for use in <iq/> elements.

All <iq/> stanzas are required to have unique id attributes.  This function makes creating these easy.  Each connection instance has a counter which starts from zero, and the value of this counter plus a colon followed by the suffix becomes the unique id.  If no suffix is supplied, the counter is used as the unique id.

Suffixes are used to make debugging easier when reading the stream data, and their use is recommended.  The counter resets to 0 for every new connection for the same reason.  For connections to the same server that authenticate the same way, all the ids should be the same, which makes it easy to see changes.  This is useful for automated testing as well.

Parameters

(String) suffixA optional suffix to append to the id.

Returns

A unique string to be used for the id attribute.

- -

connect

connect: function (jid,
pass,
callback,
wait,
hold)

Starts the connection process.

As the connection process proceeds, the user supplied callback will be triggered multiple times with status updates.  The callback should take two arguments - the status code and the error condition.

The status code will be one of the values in the Strophe.Status constants.  The error condition will be one of the conditions defined in RFC 3920 or the condition ‘strophe-parsererror’.

Please see XEP 124 for a more detailed explanation of the optional parameters below.

Parameters

(String) jidThe user’s JID.  This may be a bare JID, or a full JID.  If a node is not supplied, SASL ANONYMOUS authentication will be attempted.
(String) passThe user’s password.  (Function) callback The connect callback function.
(Integer) waitThe optional HTTPBIND wait value.  This is the time the server will wait before returning an empty result for a request.  The default setting of 60 seconds is recommended.  Other settings will require tweaks to the Strophe.TIMEOUT value.
(Integer) holdThe optional HTTPBIND hold value.  This is the number of connections the server will hold at one time.  This should almost always be set to 1 (the default).
- -

attach

attach: function (jid,
sid,
rid,
callback,
wait,
hold,
wind)

Attach to an already created and authenticated BOSH session.

This function is provided to allow Strophe to attach to BOSH sessions which have been created externally, perhaps by a Web application.  This is often used to support auto-login type features without putting user credentials into the page.

Parameters

(String) jidThe full JID that is bound by the session.
(String) sidThe SID of the BOSH session.
(String) ridThe current RID of the BOSH session.  This RID will be used by the next request.  (Function) callback The connect callback function.
(Integer) waitThe optional HTTPBIND wait value.  This is the time the server will wait before returning an empty result for a request.  The default setting of 60 seconds is recommended.  Other settings will require tweaks to the Strophe.TIMEOUT value.
(Integer) holdThe optional HTTPBIND hold value.  This is the number of connections the server will hold at one time.  This should almost always be set to 1 (the default).
(Integer) windThe optional HTTBIND window value.  This is the allowed range of request ids that are valid.  The default is 5.
- -

xmlInput

xmlInput: function (elem)

User overrideable function that receives XML data coming into the connection.

The default function does nothing.  User code can override this with

Strophe.Connection.xmlInput = function (elem) {
-  (user code)
-};

Parameters

(XMLElement) elemThe XML data received by the connection.
- -

xmlOutput

xmlOutput: function (elem)

User overrideable function that receives XML data sent to the connection.

The default function does nothing.  User code can override this with

Strophe.Connection.xmlOutput = function (elem) {
-  (user code)
-};

Parameters

(XMLElement) elemThe XMLdata sent by the connection.
- -

rawInput

rawInput: function (data)

User overrideable function that receives raw data coming into the connection.

The default function does nothing.  User code can override this with

Strophe.Connection.rawInput = function (data) {
-  (user code)
-};

Parameters

(String) dataThe data received by the connection.
- -

rawOutput

rawOutput: function (data)

User overrideable function that receives raw data sent to the connection.

The default function does nothing.  User code can override this with

Strophe.Connection.rawOutput = function (data) {
-  (user code)
-};

Parameters

(String) dataThe data sent by the connection.
- -

send

send: function (elem)

Send a stanza.

This function is called to push data onto the send queue to go out over the wire.  Whenever a request is sent to the BOSH server, all pending data is sent and the queue is flushed.

Parameters

(XMLElement | [XMLElement] | Strophe.Builder) elem - The stanza to send.

- -

flush

flush: function ()

Immediately send any pending outgoing data.

Normally send() queues outgoing data until the next idle period (100ms), which optimizes network use in the common cases when several send()s are called in succession. flush() can be used to immediately send all pending data.

- -

sendIQ

sendIQ: function(elem,
callback,
errback,
timeout)

Helper function to send IQ stanzas.

Parameters

(XMLElement) elemThe stanza to send.
(Function) callbackThe callback function for a successful request.
(Function) errbackThe callback function for a failed or timed out request.  On timeout, the stanza will be null.
(Integer) timeoutThe time specified in milliseconds for a timeout to occur.

Returns

The id used to send the IQ.

- -

addTimedHandler

addTimedHandler: function (period,
handler)

Add a timed handler to the connection.

This function adds a timed handler.  The provided handler will be called every period milliseconds until it returns false, the connection is terminated, or the handler is removed.  Handlers that wish to continue being invoked should return true.

Because of method binding it is necessary to save the result of this function if you wish to remove a handler with deleteTimedHandler().

Note that user handlers are not active until authentication is successful.

Parameters

(Integer) periodThe period of the handler.
(Function) handlerThe callback function.

Returns

A reference to the handler that can be used to remove it.

- -

deleteTimedHandler

deleteTimedHandler: function (handRef)

Delete a timed handler for a connection.

This function removes a timed handler from the connection.  The handRef parameter is not the function passed to addTimedHandler(), but is the reference returned from addTimedHandler().

Parameters

(Strophe.TimedHandler) handRefThe handler reference.
- -

addHandler

addHandler: function (handler,
ns,
name,
type,
id,
from,
options)

Add a stanza handler for the connection.

This function adds a stanza handler to the connection.  The handler callback will be called for any stanza that matches the parameters.  Note that if multiple parameters are supplied, they must all match for the handler to be invoked.

The handler will receive the stanza that triggered it as its argument.  The handler should return true if it is to be invoked again; returning false will remove the handler after it returns.

As a convenience, the ns parameters applies to the top level element and also any of its immediate children.  This is primarily to make matching /iq/query elements easy.

The options argument contains handler matching flags that affect how matches are determined.  Currently the only flag is matchBare (a boolean).  When matchBare is true, the from parameter and the from attribute on the stanza will be matched as bare JIDs instead of full JIDs.  To use this, pass {matchBare: true} as the value of options.  The default value for matchBare is false.

The return value should be saved if you wish to remove the handler with deleteHandler().

Parameters

(Function) handlerThe user callback.
(String) nsThe namespace to match.
(String) nameThe stanza name to match.
(String) typeThe stanza type attribute to match.
(String) idThe stanza id attribute to match.
(String) fromThe stanza from attribute to match.
(String) optionsThe handler options

Returns

A reference to the handler that can be used to remove it.

- -

deleteHandler

deleteHandler: function (handRef)

Delete a stanza handler for a connection.

This function removes a stanza handler from the connection.  The handRef parameter is not the function passed to addHandler(), but is the reference returned from addHandler().

Parameters

(Strophe.Handler) handRefThe handler reference.
- -

disconnect

disconnect: function (reason)

Start the graceful disconnection process.

This function starts the disconnection process.  This process starts by sending unavailable presence and sending BOSH body of type terminate.  A timeout handler makes sure that disconnection happens even if the BOSH server does not respond.

The user supplied connection callback will be notified of the progress as this process happens.

Parameters

(String) reasonThe reason the disconnect is occuring.
- -
- - - - - - - - - - -
function $build(name,
attrs)
Create a Strophe.Builder.
function $msg(attrs)
Create a Strophe.Builder with a message/ element as the root.
function $iq(attrs)
Create a Strophe.Builder with an iq/ element as the root.
function $pres(attrs)
Create a Strophe.Builder with a presence/ element as the root.
addNamespace: function (name,
value)
This function is used to extend the current namespaces in Strophe.NS.
forEachChild: function (elem,
elemName,
func)
Map a function over some or all child elements of a given element.
isTagEqual: function (el,
name)
Compare an element’s tag name with a string.
xmlElement: function (name)
Create an XML DOM element.
xmlescape: function(text)
Excapes invalid xml characters.
xmlTextNode: function (text)
Creates an XML DOM text node.
getText: function (elem)
Get the concatenation of all text children of an element.
copyElement: function (elem)
Copy an XML DOM element.
escapeNode: function (node)
Escape the node part (also called local part) of a JID.
unescapeNode: function (node)
Unescape a node part (also called local part) of a JID.
getNodeFromJid: function (jid)
Get the node portion of a JID String.
getDomainFromJid: function (jid)
Get the domain portion of a JID String.
getResourceFromJid: function (jid)
Get the resource portion of a JID String.
getBareJidFromJid: function (jid)
Get the bare JID from a JID String.
log: function (level,
msg)
User overrideable logging function.
debug: function(msg)
Log a message at the Strophe.LogLevel.DEBUG level.
info: function (msg)
Log a message at the Strophe.LogLevel.INFO level.
warn: function (msg)
Log a message at the Strophe.LogLevel.WARN level.
error: function (msg)
Log a message at the Strophe.LogLevel.ERROR level.
fatal: function (msg)
Log a message at the Strophe.LogLevel.FATAL level.
serialize: function (elem)
Render a DOM element and all descendants to a String.
addConnectionPlugin: function (name,
ptype)
Extends the Strophe.Connection object with the given plugin.
Strophe.Builder = function (name,
attrs)
Create a Strophe.Builder object.
tree: function ()
Return the DOM tree.
toString: function ()
Serialize the DOM tree to a String.
up: function ()
Make the current parent element the new current element.
attrs: function (moreattrs)
Add or modify attributes of the current element.
c: function (name,
attrs)
Add a child to the current element and make it the new current element.
cnode: function (elem)
Add a child to the current element and make it the new current element.
t: function (text)
Add a child text element.
Strophe.Connection = function (service)
Create and initialize a Strophe.Connection object.
reset: function ()
Reset the connection.
pause: function ()
Pause the request manager.
resume: function ()
Resume the request manager.
getUniqueId: function (suffix)
Generate a unique ID for use in iq/ elements.
connect: function (jid,
pass,
callback,
wait,
hold)
Starts the connection process.
attach: function (jid,
sid,
rid,
callback,
wait,
hold,
wind)
Attach to an already created and authenticated BOSH session.
xmlInput: function (elem)
User overrideable function that receives XML data coming into the connection.
xmlOutput: function (elem)
User overrideable function that receives XML data sent to the connection.
rawInput: function (data)
User overrideable function that receives raw data coming into the connection.
rawOutput: function (data)
User overrideable function that receives raw data sent to the connection.
send: function (elem)
Send a stanza.
flush: function ()
Immediately send any pending outgoing data.
sendIQ: function(elem,
callback,
errback,
timeout)
Helper function to send IQ stanzas.
addTimedHandler: function (period,
handler)
Add a timed handler to the connection.
deleteTimedHandler: function (handRef)
Delete a timed handler for a connection.
addHandler: function (handler,
ns,
name,
type,
id,
from,
options)
Add a stanza handler for the connection.
deleteHandler: function (handRef)
Delete a stanza handler for a connection.
disconnect: function (reason)
Start the graceful disconnection process.
- - - - -
Close
- - - \ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/index.html b/public/javascripts/strophejs-1.0.1/doc/index.html deleted file mode 100644 index 6c1a278..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/index.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/javascript/main.js b/public/javascripts/strophejs-1.0.1/doc/javascript/main.js deleted file mode 100644 index 91991f5..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/javascript/main.js +++ /dev/null @@ -1,836 +0,0 @@ -// This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure -// Natural Docs is licensed under the GPL - - -// -// Browser Styles -// ____________________________________________________________________________ - -var agt=navigator.userAgent.toLowerCase(); -var browserType; -var browserVer; - -if (agt.indexOf("opera") != -1) - { - browserType = "Opera"; - - if (agt.indexOf("opera 7") != -1 || agt.indexOf("opera/7") != -1) - { browserVer = "Opera7"; } - else if (agt.indexOf("opera 8") != -1 || agt.indexOf("opera/8") != -1) - { browserVer = "Opera8"; } - else if (agt.indexOf("opera 9") != -1 || agt.indexOf("opera/9") != -1) - { browserVer = "Opera9"; } - } - -else if (agt.indexOf("applewebkit") != -1) - { - browserType = "Safari"; - - if (agt.indexOf("version/3") != -1) - { browserVer = "Safari3"; } - else if (agt.indexOf("safari/4") != -1) - { browserVer = "Safari2"; } - } - -else if (agt.indexOf("khtml") != -1) - { - browserType = "Konqueror"; - } - -else if (agt.indexOf("msie") != -1) - { - browserType = "IE"; - - if (agt.indexOf("msie 6") != -1) - { browserVer = "IE6"; } - else if (agt.indexOf("msie 7") != -1) - { browserVer = "IE7"; } - } - -else if (agt.indexOf("gecko") != -1) - { - browserType = "Firefox"; - - if (agt.indexOf("rv:1.7") != -1) - { browserVer = "Firefox1"; } - else if (agt.indexOf("rv:1.8)") != -1 || agt.indexOf("rv:1.8.0") != -1) - { browserVer = "Firefox15"; } - else if (agt.indexOf("rv:1.8.1") != -1) - { browserVer = "Firefox2"; } - } - - -// -// Support Functions -// ____________________________________________________________________________ - - -function GetXPosition(item) - { - var position = 0; - - if (item.offsetWidth != null) - { - while (item != document.body && item != null) - { - position += item.offsetLeft; - item = item.offsetParent; - }; - }; - - return position; - }; - - -function GetYPosition(item) - { - var position = 0; - - if (item.offsetWidth != null) - { - while (item != document.body && item != null) - { - position += item.offsetTop; - item = item.offsetParent; - }; - }; - - return position; - }; - - -function MoveToPosition(item, x, y) - { - // Opera 5 chokes on the px extension, so it can use the Microsoft one instead. - - if (item.style.left != null) - { - item.style.left = x + "px"; - item.style.top = y + "px"; - } - else if (item.style.pixelLeft != null) - { - item.style.pixelLeft = x; - item.style.pixelTop = y; - }; - }; - - -// -// Menu -// ____________________________________________________________________________ - - -function ToggleMenu(id) - { - if (!window.document.getElementById) - { return; }; - - var display = window.document.getElementById(id).style.display; - - if (display == "none") - { display = "block"; } - else - { display = "none"; } - - window.document.getElementById(id).style.display = display; - } - -function HideAllBut(ids, max) - { - if (document.getElementById) - { - ids.sort( function(a,b) { return a - b; } ); - var number = 1; - - while (number < max) - { - if (ids.length > 0 && number == ids[0]) - { ids.shift(); } - else - { - document.getElementById("MGroupContent" + number).style.display = "none"; - }; - - number++; - }; - }; - } - - -// -// Tooltips -// ____________________________________________________________________________ - - -var tooltipTimer = 0; - -function ShowTip(event, tooltipID, linkID) - { - if (tooltipTimer) - { clearTimeout(tooltipTimer); }; - - var docX = event.clientX + window.pageXOffset; - var docY = event.clientY + window.pageYOffset; - - var showCommand = "ReallyShowTip('" + tooltipID + "', '" + linkID + "', " + docX + ", " + docY + ")"; - - tooltipTimer = setTimeout(showCommand, 1000); - } - -function ReallyShowTip(tooltipID, linkID, docX, docY) - { - tooltipTimer = 0; - - var tooltip; - var link; - - if (document.getElementById) - { - tooltip = document.getElementById(tooltipID); - link = document.getElementById(linkID); - } -/* else if (document.all) - { - tooltip = eval("document.all['" + tooltipID + "']"); - link = eval("document.all['" + linkID + "']"); - } -*/ - if (tooltip) - { - var left = GetXPosition(link); - var top = GetYPosition(link); - top += link.offsetHeight; - - - // The fallback method is to use the mouse X and Y relative to the document. We use a separate if and test if its a number - // in case some browser snuck through the above if statement but didn't support everything. - - if (!isFinite(top) || top == 0) - { - left = docX; - top = docY; - } - - // Some spacing to get it out from under the cursor. - - top += 10; - - // Make sure the tooltip doesnt get smushed by being too close to the edge, or in some browsers, go off the edge of the - // page. We do it here because Konqueror does get offsetWidth right even if it doesnt get the positioning right. - - if (tooltip.offsetWidth != null) - { - var width = tooltip.offsetWidth; - var docWidth = document.body.clientWidth; - - if (left + width > docWidth) - { left = docWidth - width - 1; } - - // If there's a horizontal scroll bar we could go past zero because it's using the page width, not the window width. - if (left < 0) - { left = 0; }; - } - - MoveToPosition(tooltip, left, top); - tooltip.style.visibility = "visible"; - } - } - -function HideTip(tooltipID) - { - if (tooltipTimer) - { - clearTimeout(tooltipTimer); - tooltipTimer = 0; - } - - var tooltip; - - if (document.getElementById) - { tooltip = document.getElementById(tooltipID); } - else if (document.all) - { tooltip = eval("document.all['" + tooltipID + "']"); } - - if (tooltip) - { tooltip.style.visibility = "hidden"; } - } - - -// -// Blockquote fix for IE -// ____________________________________________________________________________ - - -function NDOnLoad() - { - if (browserVer == "IE6") - { - var scrollboxes = document.getElementsByTagName('blockquote'); - - if (scrollboxes.item(0)) - { - NDDoResize(); - window.onresize=NDOnResize; - }; - }; - }; - - -var resizeTimer = 0; - -function NDOnResize() - { - if (resizeTimer != 0) - { clearTimeout(resizeTimer); }; - - resizeTimer = setTimeout(NDDoResize, 250); - }; - - -function NDDoResize() - { - var scrollboxes = document.getElementsByTagName('blockquote'); - - var i; - var item; - - i = 0; - while (item = scrollboxes.item(i)) - { - item.style.width = 100; - i++; - }; - - i = 0; - while (item = scrollboxes.item(i)) - { - item.style.width = item.parentNode.offsetWidth; - i++; - }; - - clearTimeout(resizeTimer); - resizeTimer = 0; - } - - - -/* ________________________________________________________________________________________________________ - - Class: SearchPanel - ________________________________________________________________________________________________________ - - A class handling everything associated with the search panel. - - Parameters: - - name - The name of the global variable that will be storing this instance. Is needed to be able to set timeouts. - mode - The mode the search is going to work in. Pass CommandLineOption()>, so the - value will be something like "HTML" or "FramedHTML". - - ________________________________________________________________________________________________________ -*/ - - -function SearchPanel(name, mode, resultsPath) - { - if (!name || !mode || !resultsPath) - { alert("Incorrect parameters to SearchPanel."); }; - - - // Group: Variables - // ________________________________________________________________________ - - /* - var: name - The name of the global variable that will be storing this instance of the class. - */ - this.name = name; - - /* - var: mode - The mode the search is going to work in, such as "HTML" or "FramedHTML". - */ - this.mode = mode; - - /* - var: resultsPath - The relative path from the current HTML page to the results page directory. - */ - this.resultsPath = resultsPath; - - /* - var: keyTimeout - The timeout used between a keystroke and when a search is performed. - */ - this.keyTimeout = 0; - - /* - var: keyTimeoutLength - The length of in thousandths of a second. - */ - this.keyTimeoutLength = 500; - - /* - var: lastSearchValue - The last search string executed, or an empty string if none. - */ - this.lastSearchValue = ""; - - /* - var: lastResultsPage - The last results page. The value is only relevant if is set. - */ - this.lastResultsPage = ""; - - /* - var: deactivateTimeout - - The timeout used between when a control is deactivated and when the entire panel is deactivated. Is necessary - because a control may be deactivated in favor of another control in the same panel, in which case it should stay - active. - */ - this.deactivateTimout = 0; - - /* - var: deactivateTimeoutLength - The length of in thousandths of a second. - */ - this.deactivateTimeoutLength = 200; - - - - - // Group: DOM Elements - // ________________________________________________________________________ - - - // Function: DOMSearchField - this.DOMSearchField = function() - { return document.getElementById("MSearchField"); }; - - // Function: DOMSearchType - this.DOMSearchType = function() - { return document.getElementById("MSearchType"); }; - - // Function: DOMPopupSearchResults - this.DOMPopupSearchResults = function() - { return document.getElementById("MSearchResults"); }; - - // Function: DOMPopupSearchResultsWindow - this.DOMPopupSearchResultsWindow = function() - { return document.getElementById("MSearchResultsWindow"); }; - - // Function: DOMSearchPanel - this.DOMSearchPanel = function() - { return document.getElementById("MSearchPanel"); }; - - - - - // Group: Event Handlers - // ________________________________________________________________________ - - - /* - Function: OnSearchFieldFocus - Called when focus is added or removed from the search field. - */ - this.OnSearchFieldFocus = function(isActive) - { - this.Activate(isActive); - }; - - - /* - Function: OnSearchFieldChange - Called when the content of the search field is changed. - */ - this.OnSearchFieldChange = function() - { - if (this.keyTimeout) - { - clearTimeout(this.keyTimeout); - this.keyTimeout = 0; - }; - - var searchValue = this.DOMSearchField().value.replace(/ +/g, ""); - - if (searchValue != this.lastSearchValue) - { - if (searchValue != "") - { - this.keyTimeout = setTimeout(this.name + ".Search()", this.keyTimeoutLength); - } - else - { - if (this.mode == "HTML") - { this.DOMPopupSearchResultsWindow().style.display = "none"; }; - this.lastSearchValue = ""; - }; - }; - }; - - - /* - Function: OnSearchTypeFocus - Called when focus is added or removed from the search type. - */ - this.OnSearchTypeFocus = function(isActive) - { - this.Activate(isActive); - }; - - - /* - Function: OnSearchTypeChange - Called when the search type is changed. - */ - this.OnSearchTypeChange = function() - { - var searchValue = this.DOMSearchField().value.replace(/ +/g, ""); - - if (searchValue != "") - { - this.Search(); - }; - }; - - - - // Group: Action Functions - // ________________________________________________________________________ - - - /* - Function: CloseResultsWindow - Closes the results window. - */ - this.CloseResultsWindow = function() - { - this.DOMPopupSearchResultsWindow().style.display = "none"; - this.Activate(false, true); - }; - - - /* - Function: Search - Performs a search. - */ - this.Search = function() - { - this.keyTimeout = 0; - - var searchValue = this.DOMSearchField().value.replace(/^ +/, ""); - var searchTopic = this.DOMSearchType().value; - - var pageExtension = searchValue.substr(0,1); - - if (pageExtension.match(/^[a-z]/i)) - { pageExtension = pageExtension.toUpperCase(); } - else if (pageExtension.match(/^[0-9]/)) - { pageExtension = 'Numbers'; } - else - { pageExtension = "Symbols"; }; - - var resultsPage; - var resultsPageWithSearch; - var hasResultsPage; - - // indexSectionsWithContent is defined in searchdata.js - if (indexSectionsWithContent[searchTopic][pageExtension] == true) - { - resultsPage = this.resultsPath + '/' + searchTopic + pageExtension + '.html'; - resultsPageWithSearch = resultsPage+'?'+escape(searchValue); - hasResultsPage = true; - } - else - { - resultsPage = this.resultsPath + '/NoResults.html'; - resultsPageWithSearch = resultsPage; - hasResultsPage = false; - }; - - var resultsFrame; - if (this.mode == "HTML") - { resultsFrame = window.frames.MSearchResults; } - else if (this.mode == "FramedHTML") - { resultsFrame = window.top.frames['Content']; }; - - - if (resultsPage != this.lastResultsPage || - - // Bug in IE. If everything becomes hidden in a run, none of them will be able to be reshown in the next for some - // reason. It counts the right number of results, and you can even read the display as "block" after setting it, but it - // just doesn't work in IE 6 or IE 7. So if we're on the right page but the previous search had no results, reload the - // page anyway to get around the bug. - (browserType == "IE" && hasResultsPage && - (!resultsFrame.searchResults || resultsFrame.searchResults.lastMatchCount == 0)) ) - - { - resultsFrame.location.href = resultsPageWithSearch; - } - - // So if the results page is right and there's no IE bug, reperform the search on the existing page. We have to check if there - // are results because NoResults.html doesn't have any JavaScript, and it would be useless to do anything on that page even - // if it did. - else if (hasResultsPage) - { - // We need to check if this exists in case the frame is present but didn't finish loading. - if (resultsFrame.searchResults) - { resultsFrame.searchResults.Search(searchValue); } - - // Otherwise just reload instead of waiting. - else - { resultsFrame.location.href = resultsPageWithSearch; }; - }; - - - var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); - - if (this.mode == "HTML" && domPopupSearchResultsWindow.style.display != "block") - { - var domSearchType = this.DOMSearchType(); - - var left = GetXPosition(domSearchType); - var top = GetYPosition(domSearchType) + domSearchType.offsetHeight; - - MoveToPosition(domPopupSearchResultsWindow, left, top); - domPopupSearchResultsWindow.style.display = 'block'; - }; - - - this.lastSearchValue = searchValue; - this.lastResultsPage = resultsPage; - }; - - - - // Group: Activation Functions - // Functions that handle whether the entire panel is active or not. - // ________________________________________________________________________ - - - /* - Function: Activate - - Activates or deactivates the search panel, resetting things to their default values if necessary. You can call this on every - control's OnBlur() and it will handle not deactivating the entire panel when focus is just switching between them transparently. - - Parameters: - - isActive - Whether you're activating or deactivating the panel. - ignoreDeactivateDelay - Set if you're positive the action will deactivate the panel and thus want to skip the delay. - */ - this.Activate = function(isActive, ignoreDeactivateDelay) - { - // We want to ignore isActive being false while the results window is open. - if (isActive || (this.mode == "HTML" && this.DOMPopupSearchResultsWindow().style.display == "block")) - { - if (this.inactivateTimeout) - { - clearTimeout(this.inactivateTimeout); - this.inactivateTimeout = 0; - }; - - this.DOMSearchPanel().className = 'MSearchPanelActive'; - - var searchField = this.DOMSearchField(); - - if (searchField.value == 'Search') - { searchField.value = ""; } - } - else if (!ignoreDeactivateDelay) - { - this.inactivateTimeout = setTimeout(this.name + ".InactivateAfterTimeout()", this.inactivateTimeoutLength); - } - else - { - this.InactivateAfterTimeout(); - }; - }; - - - /* - Function: InactivateAfterTimeout - - Called by , which is set by . Inactivation occurs on a timeout because a control may - receive OnBlur() when focus is really transferring to another control in the search panel. In this case we don't want to - actually deactivate the panel because not only would that cause a visible flicker but it could also reset the search value. - So by doing it on a timeout instead, there's a short period where the second control's OnFocus() can cancel the deactivation. - */ - this.InactivateAfterTimeout = function() - { - this.inactivateTimeout = 0; - - this.DOMSearchPanel().className = 'MSearchPanelInactive'; - this.DOMSearchField().value = "Search"; - - this.lastSearchValue = ""; - this.lastResultsPage = ""; - }; - }; - - - - -/* ________________________________________________________________________________________________________ - - Class: SearchResults - _________________________________________________________________________________________________________ - - The class that handles everything on the search results page. - _________________________________________________________________________________________________________ -*/ - - -function SearchResults(name, mode) - { - /* - var: mode - The mode the search is going to work in, such as "HTML" or "FramedHTML". - */ - this.mode = mode; - - /* - var: lastMatchCount - The number of matches from the last run of . - */ - this.lastMatchCount = 0; - - - /* - Function: Toggle - Toggles the visibility of the passed element ID. - */ - this.Toggle = function(id) - { - if (this.mode == "FramedHTML") - { return; }; - - var parentElement = document.getElementById(id); - - var element = parentElement.firstChild; - - while (element && element != parentElement) - { - if (element.nodeName == 'DIV' && element.className == 'ISubIndex') - { - if (element.style.display == 'block') - { element.style.display = "none"; } - else - { element.style.display = 'block'; } - }; - - if (element.nodeName == 'DIV' && element.hasChildNodes()) - { element = element.firstChild; } - else if (element.nextSibling) - { element = element.nextSibling; } - else - { - do - { - element = element.parentNode; - } - while (element && element != parentElement && !element.nextSibling); - - if (element && element != parentElement) - { element = element.nextSibling; }; - }; - }; - }; - - - /* - Function: Search - - Searches for the passed string. If there is no parameter, it takes it from the URL query. - - Always returns true, since other documents may try to call it and that may or may not be possible. - */ - this.Search = function(search) - { - if (!search) - { - search = window.location.search; - search = search.substring(1); // Remove the leading ? - search = unescape(search); - }; - - search = search.replace(/^ +/, ""); - search = search.replace(/ +$/, ""); - search = search.toLowerCase(); - - if (search.match(/[^a-z0-9]/)) // Just a little speedup so it doesn't have to go through the below unnecessarily. - { - search = search.replace(/\_/g, "_und"); - search = search.replace(/\ +/gi, "_spc"); - search = search.replace(/\~/g, "_til"); - search = search.replace(/\!/g, "_exc"); - search = search.replace(/\@/g, "_att"); - search = search.replace(/\#/g, "_num"); - search = search.replace(/\$/g, "_dol"); - search = search.replace(/\%/g, "_pct"); - search = search.replace(/\^/g, "_car"); - search = search.replace(/\&/g, "_amp"); - search = search.replace(/\*/g, "_ast"); - search = search.replace(/\(/g, "_lpa"); - search = search.replace(/\)/g, "_rpa"); - search = search.replace(/\-/g, "_min"); - search = search.replace(/\+/g, "_plu"); - search = search.replace(/\=/g, "_equ"); - search = search.replace(/\{/g, "_lbc"); - search = search.replace(/\}/g, "_rbc"); - search = search.replace(/\[/g, "_lbk"); - search = search.replace(/\]/g, "_rbk"); - search = search.replace(/\:/g, "_col"); - search = search.replace(/\;/g, "_sco"); - search = search.replace(/\"/g, "_quo"); - search = search.replace(/\'/g, "_apo"); - search = search.replace(/\/g, "_ran"); - search = search.replace(/\,/g, "_com"); - search = search.replace(/\./g, "_per"); - search = search.replace(/\?/g, "_que"); - search = search.replace(/\//g, "_sla"); - search = search.replace(/[^a-z0-9\_]i/gi, "_zzz"); - }; - - var resultRows = document.getElementsByTagName("div"); - var matches = 0; - - var i = 0; - while (i < resultRows.length) - { - var row = resultRows.item(i); - - if (row.className == "SRResult") - { - var rowMatchName = row.id.toLowerCase(); - rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); - - if (search.length <= rowMatchName.length && rowMatchName.substr(0, search.length) == search) - { - row.style.display = "block"; - matches++; - } - else - { row.style.display = "none"; }; - }; - - i++; - }; - - document.getElementById("Searching").style.display="none"; - - if (matches == 0) - { document.getElementById("NoMatches").style.display="block"; } - else - { document.getElementById("NoMatches").style.display="none"; } - - this.lastMatchCount = matches; - - return true; - }; - }; - diff --git a/public/javascripts/strophejs-1.0.1/doc/javascript/searchdata.js b/public/javascripts/strophejs-1.0.1/doc/javascript/searchdata.js deleted file mode 100644 index 544e6b8..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/javascript/searchdata.js +++ /dev/null @@ -1,152 +0,0 @@ -var indexSectionsWithContent = { - "General": { - "Symbols": true, - "Numbers": false, - "A": true, - "B": true, - "C": true, - "D": true, - "E": true, - "F": true, - "G": true, - "H": true, - "I": true, - "J": false, - "K": false, - "L": true, - "M": true, - "N": false, - "O": false, - "P": true, - "Q": false, - "R": true, - "S": true, - "T": true, - "U": true, - "V": true, - "W": true, - "X": true, - "Y": false, - "Z": false - }, - "Functions": { - "Symbols": true, - "Numbers": false, - "A": true, - "B": true, - "C": true, - "D": true, - "E": true, - "F": true, - "G": true, - "H": false, - "I": true, - "J": false, - "K": false, - "L": true, - "M": false, - "N": false, - "O": false, - "P": true, - "Q": false, - "R": true, - "S": true, - "T": true, - "U": true, - "V": false, - "W": true, - "X": true, - "Y": false, - "Z": false - }, - "Files": { - "Symbols": false, - "Numbers": false, - "A": false, - "B": false, - "C": false, - "D": false, - "E": false, - "F": false, - "G": false, - "H": false, - "I": false, - "J": false, - "K": false, - "L": false, - "M": false, - "N": false, - "O": false, - "P": false, - "Q": false, - "R": false, - "S": true, - "T": false, - "U": false, - "V": false, - "W": false, - "X": false, - "Y": false, - "Z": false - }, - "Constants": { - "Symbols": false, - "Numbers": false, - "A": true, - "B": true, - "C": true, - "D": true, - "E": true, - "F": true, - "G": false, - "H": true, - "I": true, - "J": false, - "K": false, - "L": true, - "M": true, - "N": false, - "O": false, - "P": true, - "Q": false, - "R": true, - "S": true, - "T": false, - "U": false, - "V": true, - "W": true, - "X": true, - "Y": false, - "Z": false - }, - "Classes": { - "Symbols": false, - "Numbers": false, - "A": false, - "B": false, - "C": false, - "D": false, - "E": false, - "F": false, - "G": false, - "H": false, - "I": false, - "J": false, - "K": false, - "L": false, - "M": false, - "N": false, - "O": false, - "P": false, - "Q": false, - "R": false, - "S": true, - "T": false, - "U": false, - "V": false, - "W": false, - "X": false, - "Y": false, - "Z": false - } - } \ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ClassesS.html b/public/javascripts/strophejs-1.0.1/doc/search/ClassesS.html deleted file mode 100644 index 28b7b8f..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ClassesS.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsA.html b/public/javascripts/strophejs-1.0.1/doc/search/ConstantsA.html deleted file mode 100644 index 9a055ea..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsA.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
ATTACHED, Strophe.Status
AUTH, Strophe.NS
AUTHENTICATING, Strophe.Status
AUTHFAIL, Strophe.Status
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsB.html b/public/javascripts/strophejs-1.0.1/doc/search/ConstantsB.html deleted file mode 100644 index 744e30e..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsB.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
BIND, Strophe.NS
BOSH, Strophe.NS
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsC.html b/public/javascripts/strophejs-1.0.1/doc/search/ConstantsC.html deleted file mode 100644 index c29394d..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsC.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
CLIENT, Strophe.NS
CONNECTED, Strophe.Status
CONNECTING, Strophe.Status
CONNFAIL, Strophe.Status
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsD.html b/public/javascripts/strophejs-1.0.1/doc/search/ConstantsD.html deleted file mode 100644 index 09e62fe..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsD.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
DEBUG, Strophe.LogLevel
DISCO_INFO, Strophe.NS
DISCO_ITEMS, Strophe.NS
DISCONNECTED, Strophe.Status
DISCONNECTING, Strophe.Status
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsE.html b/public/javascripts/strophejs-1.0.1/doc/search/ConstantsE.html deleted file mode 100644 index a1d6a0e..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsE.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsF.html b/public/javascripts/strophejs-1.0.1/doc/search/ConstantsF.html deleted file mode 100644 index ced88b3..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsF.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
FATAL, Strophe.LogLevel
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsH.html b/public/javascripts/strophejs-1.0.1/doc/search/ConstantsH.html deleted file mode 100644 index 7ac8386..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsH.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
HTTPBIND, Strophe.NS
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsI.html b/public/javascripts/strophejs-1.0.1/doc/search/ConstantsI.html deleted file mode 100644 index 72e02a1..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsI.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
INFO, Strophe.LogLevel
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsL.html b/public/javascripts/strophejs-1.0.1/doc/search/ConstantsL.html deleted file mode 100644 index f0b7edf..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsL.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsM.html b/public/javascripts/strophejs-1.0.1/doc/search/ConstantsM.html deleted file mode 100644 index 83eabe9..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsM.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
MUC, Strophe.NS
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsP.html b/public/javascripts/strophejs-1.0.1/doc/search/ConstantsP.html deleted file mode 100644 index 1fd637b..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsP.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
PROFILE, Strophe.NS
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsR.html b/public/javascripts/strophejs-1.0.1/doc/search/ConstantsR.html deleted file mode 100644 index e960e4a..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsR.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
ROSTER, Strophe.NS
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsS.html b/public/javascripts/strophejs-1.0.1/doc/search/ConstantsS.html deleted file mode 100644 index 07dfabf..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsS.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
SASL, Strophe.NS
SESSION, Strophe.NS
STREAM, Strophe.NS
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsV.html b/public/javascripts/strophejs-1.0.1/doc/search/ConstantsV.html deleted file mode 100644 index d9454e9..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsV.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
VERSION, Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsW.html b/public/javascripts/strophejs-1.0.1/doc/search/ConstantsW.html deleted file mode 100644 index 2eb92d5..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsW.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
WARN, Strophe.LogLevel
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsX.html b/public/javascripts/strophejs-1.0.1/doc/search/ConstantsX.html deleted file mode 100644 index 8347a8b..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/ConstantsX.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FilesS.html b/public/javascripts/strophejs-1.0.1/doc/search/FilesS.html deleted file mode 100644 index 8bc8b7f..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FilesS.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsA.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsA.html deleted file mode 100644 index a1609ee..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsA.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
addHandler, Strophe.Connection
addNamespace, Strophe
addTimedHandler, Strophe.Connection
attach, Strophe.Connection
attrs, Strophe.Builder
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsB.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsB.html deleted file mode 100644 index a7b6ca1..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsB.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
Builder, Strophe.Builder.Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsC.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsC.html deleted file mode 100644 index 1f94a41..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsC.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
c, Strophe.Builder
cnode, Strophe.Builder
connect, Strophe.Connection
Connection, Strophe.Connection.Strophe
copyElement, Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsD.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsD.html deleted file mode 100644 index 14da49e..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsD.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
debug, Strophe
deleteHandler, Strophe.Connection
deleteTimedHandler, Strophe.Connection
disconnect, Strophe.Connection
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsE.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsE.html deleted file mode 100644 index c6bd5a0..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsE.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
error, Strophe
escapeNode, Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsF.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsF.html deleted file mode 100644 index 1a60173..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsF.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
fatal, Strophe
flush, Strophe.Connection
forEachChild, Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsG.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsG.html deleted file mode 100644 index 1d31191..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsG.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
getText, Strophe
getUniqueId, Strophe.Connection
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsI.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsI.html deleted file mode 100644 index 2bf8815..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsI.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
info, Strophe
isTagEqual, Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsL.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsL.html deleted file mode 100644 index b53a03a..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsL.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
log, Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsP.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsP.html deleted file mode 100644 index 6ae461b..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsP.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
pause, Strophe.Connection
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsR.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsR.html deleted file mode 100644 index c248d26..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsR.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
rawInput, Strophe.Connection
rawOutput, Strophe.Connection
reset, Strophe.Connection
resume, Strophe.Connection
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsS.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsS.html deleted file mode 100644 index 1c05b76..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsS.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
send, Strophe.Connection
sendIQ, Strophe.Connection
serialize, Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsSymbols.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsSymbols.html deleted file mode 100644 index 51ade8c..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsSymbols.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsT.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsT.html deleted file mode 100644 index 9df6375..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsT.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
t, Strophe.Builder
toString, Strophe.Builder
tree, Strophe.Builder
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsU.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsU.html deleted file mode 100644 index cb31959..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsU.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
unescapeNode, Strophe
up, Strophe.Builder
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsW.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsW.html deleted file mode 100644 index 37b4354..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsW.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
warn, Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsX.html b/public/javascripts/strophejs-1.0.1/doc/search/FunctionsX.html deleted file mode 100644 index 04b517c..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/FunctionsX.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
xmlElement, Strophe
xmlescape, Strophe
xmlInput, Strophe.Connection
xmlOutput, Strophe.Connection
xmlTextNode, Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralA.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralA.html deleted file mode 100644 index 19b69bf..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralA.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
addHandler, Strophe.Connection
addNamespace, Strophe
addTimedHandler, Strophe.Connection
attach, Strophe.Connection
ATTACHED, Strophe.Status
attrs, Strophe.Builder
AUTH, Strophe.NS
AUTHENTICATING, Strophe.Status
AUTHFAIL, Strophe.Status
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralB.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralB.html deleted file mode 100644 index e32d8ce..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralB.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
BIND, Strophe.NS
BOSH, Strophe.NS
Builder, Strophe.Builder.Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralC.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralC.html deleted file mode 100644 index a0f954b..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralC.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
c, Strophe.Builder
CLIENT, Strophe.NS
cnode, Strophe.Builder
connect, Strophe.Connection
CONNECTED, Strophe.Status
CONNECTING, Strophe.Status
Connection, Strophe.Connection.Strophe
CONNFAIL, Strophe.Status
Constants, Strophe
copyElement, Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralD.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralD.html deleted file mode 100644 index a47438c..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralD.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
debug, Strophe
DEBUG, Strophe.LogLevel
deleteHandler, Strophe.Connection
deleteTimedHandler, Strophe.Connection
DISCO_INFO, Strophe.NS
DISCO_ITEMS, Strophe.NS
disconnect, Strophe.Connection
DISCONNECTED, Strophe.Status
DISCONNECTING, Strophe.Status
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralE.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralE.html deleted file mode 100644 index 420a7a9..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralE.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
error, Strophe
escapeNode, Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralF.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralF.html deleted file mode 100644 index 74d1ab0..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralF.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
fatal, Strophe
FATAL, Strophe.LogLevel
flush, Strophe.Connection
forEachChild, Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralG.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralG.html deleted file mode 100644 index 1d31191..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralG.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
getText, Strophe
getUniqueId, Strophe.Connection
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralH.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralH.html deleted file mode 100644 index 7ac8386..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralH.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
HTTPBIND, Strophe.NS
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralI.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralI.html deleted file mode 100644 index 58a1e8d..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralI.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
info, Strophe
INFO, Strophe.LogLevel
isTagEqual, Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralL.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralL.html deleted file mode 100644 index c40427e..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralL.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
log, Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralM.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralM.html deleted file mode 100644 index 83eabe9..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralM.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
MUC, Strophe.NS
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralP.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralP.html deleted file mode 100644 index 9284aa6..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralP.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
pause, Strophe.Connection
PROFILE, Strophe.NS
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralR.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralR.html deleted file mode 100644 index 02a819b..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralR.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
rawInput, Strophe.Connection
rawOutput, Strophe.Connection
reset, Strophe.Connection
resume, Strophe.Connection
ROSTER, Strophe.NS
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralS.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralS.html deleted file mode 100644 index 28884a3..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralS.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
SASL, Strophe.NS
send, Strophe.Connection
sendIQ, Strophe.Connection
serialize, Strophe
SESSION, Strophe.NS
STREAM, Strophe.NS
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralSymbols.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralSymbols.html deleted file mode 100644 index 51ade8c..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralSymbols.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralT.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralT.html deleted file mode 100644 index 9df6375..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralT.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
t, Strophe.Builder
toString, Strophe.Builder
tree, Strophe.Builder
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralU.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralU.html deleted file mode 100644 index cb31959..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralU.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
unescapeNode, Strophe
up, Strophe.Builder
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralV.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralV.html deleted file mode 100644 index d9454e9..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralV.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
VERSION, Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralW.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralW.html deleted file mode 100644 index 57e332b..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralW.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
warn, Strophe
WARN, Strophe.LogLevel
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/GeneralX.html b/public/javascripts/strophejs-1.0.1/doc/search/GeneralX.html deleted file mode 100644 index 8ba0857..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/GeneralX.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
Loading...
xmlElement, Strophe
xmlescape, Strophe
xmlInput, Strophe.Connection
xmlOutput, Strophe.Connection
xmlTextNode, Strophe
Searching...
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/search/NoResults.html b/public/javascripts/strophejs-1.0.1/doc/search/NoResults.html deleted file mode 100644 index 02ce888..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/search/NoResults.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - -
No Matches
\ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/doc/styles/main.css b/public/javascripts/strophejs-1.0.1/doc/styles/main.css deleted file mode 100644 index 134199a..0000000 --- a/public/javascripts/strophejs-1.0.1/doc/styles/main.css +++ /dev/null @@ -1,767 +0,0 @@ -/* - IMPORTANT: If you're editing this file in the output directory of one of - your projects, your changes will be overwritten the next time you run - Natural Docs. Instead, copy this file to your project directory, make your - changes, and you can use it with -s. Even better would be to make a CSS - file in your project directory with only your changes, which you can then - use with -s [original style] [your changes]. - - On the other hand, if you're editing this file in the Natural Docs styles - directory, the changes will automatically be applied to all your projects - that use this style the next time Natural Docs is run on them. - - This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure - Natural Docs is licensed under the GPL -*/ - -body { - font: 10pt Verdana, Arial, sans-serif; - color: #000000; - margin: 0; padding: 0; - } - -.ContentPage, -.IndexPage, -.FramedMenuPage { - background-color: #E8E8E8; - } -.FramedContentPage, -.FramedIndexPage, -.FramedSearchResultsPage, -.PopupSearchResultsPage { - background-color: #FFFFFF; - } - - -a:link, -a:visited { color: #900000; text-decoration: none } -a:hover { color: #900000; text-decoration: underline } -a:active { color: #FF0000; text-decoration: underline } - -td { - vertical-align: top } - -img { border: 0; } - - -/* - Comment out this line to use web-style paragraphs (blank line between - paragraphs, no indent) instead of print-style paragraphs (no blank line, - indented.) -*/ -p { - text-indent: 5ex; margin: 0 } - - -/* Opera doesn't break with just wbr, but will if you add this. */ -.Opera wbr:after { - content: "\00200B"; - } - - -/* Blockquotes are used as containers for things that may need to scroll. */ -blockquote { - padding: 0; - margin: 0; - overflow: auto; - } - - -.Firefox1 blockquote { - padding-bottom: .5em; - } - -/* Turn off scrolling when printing. */ -@media print { - blockquote { - overflow: visible; - } - .IE blockquote { - width: auto; - } - } - - - -#Menu { - font-size: 9pt; - padding: 10px 0 0 0; - } -.ContentPage #Menu, -.IndexPage #Menu { - position: absolute; - top: 0; - left: 0; - width: 31ex; - overflow: hidden; - } -.ContentPage .Firefox #Menu, -.IndexPage .Firefox #Menu { - width: 27ex; - } - - - .MTitle { - font-size: 16pt; font-weight: bold; font-variant: small-caps; - text-align: center; - padding: 5px 10px 15px 10px; - border-bottom: 1px dotted #000000; - margin-bottom: 15px } - - .MSubTitle { - font-size: 9pt; font-weight: normal; font-variant: normal; - margin-top: 1ex; margin-bottom: 5px } - - - .MEntry a:link, - .MEntry a:hover, - .MEntry a:visited { color: #606060; margin-right: 0 } - .MEntry a:active { color: #A00000; margin-right: 0 } - - - .MGroup { - font-variant: small-caps; font-weight: bold; - margin: 1em 0 1em 10px; - } - - .MGroupContent { - font-variant: normal; font-weight: normal } - - .MGroup a:link, - .MGroup a:hover, - .MGroup a:visited { color: #545454; margin-right: 10px } - .MGroup a:active { color: #A00000; margin-right: 10px } - - - .MFile, - .MText, - .MLink, - .MIndex { - padding: 1px 17px 2px 10px; - margin: .25em 0 .25em 0; - } - - .MText { - font-size: 8pt; font-style: italic } - - .MLink { - font-style: italic } - - #MSelected { - color: #000000; background-color: #FFFFFF; - /* Replace padding with border. */ - padding: 0 10px 0 10px; - border-width: 1px 2px 2px 0; border-style: solid; border-color: #000000; - margin-right: 5px; - } - - /* Close off the left side when its in a group. */ - .MGroup #MSelected { - padding-left: 9px; border-left-width: 1px } - - /* A treat for Mozilla users. Blatantly non-standard. Will be replaced with CSS 3 attributes when finalized/supported. */ - .Firefox #MSelected { - -moz-border-radius-topright: 10px; - -moz-border-radius-bottomright: 10px } - .Firefox .MGroup #MSelected { - -moz-border-radius-topleft: 10px; - -moz-border-radius-bottomleft: 10px } - - - #MSearchPanel { - padding: 0px 6px; - margin: .25em 0; - } - - - #MSearchField { - font: italic 9pt Verdana, sans-serif; - color: #606060; - background-color: #E8E8E8; - border: none; - padding: 2px 4px; - width: 100%; - } - /* Only Opera gets it right. */ - .Firefox #MSearchField, - .IE #MSearchField, - .Safari #MSearchField { - width: 94%; - } - .Opera9 #MSearchField, - .Konqueror #MSearchField { - width: 97%; - } - .FramedMenuPage .Firefox #MSearchField, - .FramedMenuPage .Safari #MSearchField, - .FramedMenuPage .Konqueror #MSearchField { - width: 98%; - } - - /* Firefox doesn't do this right in frames without #MSearchPanel added on. - It's presence doesn't hurt anything other browsers. */ - #MSearchPanel.MSearchPanelInactive:hover #MSearchField { - background-color: #FFFFFF; - border: 1px solid #C0C0C0; - padding: 1px 3px; - } - .MSearchPanelActive #MSearchField { - background-color: #FFFFFF; - border: 1px solid #C0C0C0; - font-style: normal; - padding: 1px 3px; - } - - #MSearchType { - visibility: hidden; - font: 8pt Verdana, sans-serif; - width: 98%; - padding: 0; - border: 1px solid #C0C0C0; - } - .MSearchPanelActive #MSearchType, - /* As mentioned above, Firefox doesn't do this right in frames without #MSearchPanel added on. */ - #MSearchPanel.MSearchPanelInactive:hover #MSearchType, - #MSearchType:focus { - visibility: visible; - color: #606060; - } - #MSearchType option#MSearchEverything { - font-weight: bold; - } - - .Opera8 .MSearchPanelInactive:hover, - .Opera8 .MSearchPanelActive { - margin-left: -1px; - } - - - iframe#MSearchResults { - width: 60ex; - height: 15em; - } - #MSearchResultsWindow { - display: none; - position: absolute; - left: 0; top: 0; - border: 1px solid #000000; - background-color: #E8E8E8; - } - #MSearchResultsWindowClose { - font-weight: bold; - font-size: 8pt; - display: block; - padding: 2px 5px; - } - #MSearchResultsWindowClose:link, - #MSearchResultsWindowClose:visited { - color: #000000; - text-decoration: none; - } - #MSearchResultsWindowClose:active, - #MSearchResultsWindowClose:hover { - color: #800000; - text-decoration: none; - background-color: #F4F4F4; - } - - - - -#Content { - padding-bottom: 15px; - } - -.ContentPage #Content { - border-width: 0 0 1px 1px; - border-style: solid; - border-color: #000000; - background-color: #FFFFFF; - font-size: 9pt; /* To make 31ex match the menu's 31ex. */ - margin-left: 31ex; - } -.ContentPage .Firefox #Content { - margin-left: 27ex; - } - - - - .CTopic { - font-size: 10pt; - margin-bottom: 3em; - } - - - .CTitle { - font-size: 12pt; font-weight: bold; - border-width: 0 0 1px 0; border-style: solid; border-color: #A0A0A0; - margin: 0 15px .5em 15px } - - .CGroup .CTitle { - font-size: 16pt; font-variant: small-caps; - padding-left: 15px; padding-right: 15px; - border-width: 0 0 2px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - .CClass .CTitle, - .CInterface .CTitle, - .CDatabase .CTitle, - .CDatabaseTable .CTitle, - .CSection .CTitle { - font-size: 18pt; - color: #FFFFFF; background-color: #A0A0A0; - padding: 10px 15px 10px 15px; - border-width: 2px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - #MainTopic .CTitle { - font-size: 20pt; - color: #FFFFFF; background-color: #7070C0; - padding: 10px 15px 10px 15px; - border-width: 0 0 3px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - .CBody { - margin-left: 15px; margin-right: 15px } - - - .CToolTip { - position: absolute; visibility: hidden; - left: 0; top: 0; - background-color: #FFFFE0; - padding: 5px; - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #000000; - font-size: 8pt; - } - - .Opera .CToolTip { - max-width: 98%; - } - - /* Scrollbars would be useless. */ - .CToolTip blockquote { - overflow: hidden; - } - .IE6 .CToolTip blockquote { - overflow: visible; - } - - .CHeading { - font-weight: bold; font-size: 10pt; - margin: 1.5em 0 .5em 0; - } - - .CBody pre { - font: 10pt "Courier New", Courier, monospace; - margin: 1em 0; - } - - .CBody ul { - /* I don't know why CBody's margin doesn't apply, but it's consistent across browsers so whatever. - Reapply it here as padding. */ - padding-left: 15px; padding-right: 15px; - margin: .5em 5ex .5em 5ex; - } - - .CDescriptionList { - margin: .5em 5ex 0 5ex } - - .CDLEntry { - font: 10pt "Courier New", Courier, monospace; color: #808080; - padding-bottom: .25em; - white-space: nowrap } - - .CDLDescription { - font-size: 10pt; /* For browsers that don't inherit correctly, like Opera 5. */ - padding-bottom: .5em; padding-left: 5ex } - - - .CTopic img { - text-align: center; - display: block; - margin: 1em auto; - } - .CImageCaption { - font-variant: small-caps; - font-size: 8pt; - color: #808080; - text-align: center; - position: relative; - top: 1em; - } - - .CImageLink { - color: #808080; - font-style: italic; - } - a.CImageLink:link, - a.CImageLink:visited, - a.CImageLink:hover { color: #808080 } - - - - - -.Prototype { - font: 10pt "Courier New", Courier, monospace; - padding: 5px 3ex; - border-width: 1px; border-style: solid; - margin: 0 5ex 1.5em 5ex; - } - - .Prototype td { - font-size: 10pt; - } - - .PDefaultValue, - .PDefaultValuePrefix, - .PTypePrefix { - color: #8F8F8F; - } - .PTypePrefix { - text-align: right; - } - .PAfterParameters { - vertical-align: bottom; - } - - .IE .Prototype table { - padding: 0; - } - - .CFunction .Prototype { - background-color: #F4F4F4; border-color: #D0D0D0 } - .CProperty .Prototype { - background-color: #F4F4FF; border-color: #C0C0E8 } - .CVariable .Prototype { - background-color: #FFFFF0; border-color: #E0E0A0 } - - .CClass .Prototype { - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0; - background-color: #F4F4F4; - } - .CInterface .Prototype { - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0D0; - background-color: #F4F4FF; - } - - .CDatabaseIndex .Prototype, - .CConstant .Prototype { - background-color: #D0D0D0; border-color: #000000 } - .CType .Prototype, - .CEnumeration .Prototype { - background-color: #FAF0F0; border-color: #E0B0B0; - } - .CDatabaseTrigger .Prototype, - .CEvent .Prototype, - .CDelegate .Prototype { - background-color: #F0FCF0; border-color: #B8E4B8 } - - .CToolTip .Prototype { - margin: 0 0 .5em 0; - white-space: nowrap; - } - - - - - -.Summary { - margin: 1.5em 5ex 0 5ex } - - .STitle { - font-size: 12pt; font-weight: bold; - margin-bottom: .5em } - - - .SBorder { - background-color: #FFFFF0; - padding: 15px; - border: 1px solid #C0C060 } - - /* In a frame IE 6 will make them too long unless you set the width to 100%. Without frames it will be correct without a width - or slightly too long (but not enough to scroll) with a width. This arbitrary weirdness simply astounds me. IE 7 has the same - problem with frames, haven't tested it without. */ - .FramedContentPage .IE .SBorder { - width: 100% } - - /* A treat for Mozilla users. Blatantly non-standard. Will be replaced with CSS 3 attributes when finalized/supported. */ - .Firefox .SBorder { - -moz-border-radius: 20px } - - - .STable { - font-size: 9pt; width: 100% } - - .SEntry { - width: 30% } - .SDescription { - width: 70% } - - - .SMarked { - background-color: #F8F8D8 } - - .SDescription { padding-left: 2ex } - .SIndent1 .SEntry { padding-left: 1.5ex } .SIndent1 .SDescription { padding-left: 3.5ex } - .SIndent2 .SEntry { padding-left: 3.0ex } .SIndent2 .SDescription { padding-left: 5.0ex } - .SIndent3 .SEntry { padding-left: 4.5ex } .SIndent3 .SDescription { padding-left: 6.5ex } - .SIndent4 .SEntry { padding-left: 6.0ex } .SIndent4 .SDescription { padding-left: 8.0ex } - .SIndent5 .SEntry { padding-left: 7.5ex } .SIndent5 .SDescription { padding-left: 9.5ex } - - .SDescription a { color: #800000} - .SDescription a:active { color: #A00000 } - - .SGroup td { - padding-top: .5em; padding-bottom: .25em } - - .SGroup .SEntry { - font-weight: bold; font-variant: small-caps } - - .SGroup .SEntry a { color: #800000 } - .SGroup .SEntry a:active { color: #F00000 } - - - .SMain td, - .SClass td, - .SDatabase td, - .SDatabaseTable td, - .SSection td { - font-size: 10pt; - padding-bottom: .25em } - - .SClass td, - .SDatabase td, - .SDatabaseTable td, - .SSection td { - padding-top: 1em } - - .SMain .SEntry, - .SClass .SEntry, - .SDatabase .SEntry, - .SDatabaseTable .SEntry, - .SSection .SEntry { - font-weight: bold; - } - - .SMain .SEntry a, - .SClass .SEntry a, - .SDatabase .SEntry a, - .SDatabaseTable .SEntry a, - .SSection .SEntry a { color: #000000 } - - .SMain .SEntry a:active, - .SClass .SEntry a:active, - .SDatabase .SEntry a:active, - .SDatabaseTable .SEntry a:active, - .SSection .SEntry a:active { color: #A00000 } - - - - - -.ClassHierarchy { - margin: 0 15px 1em 15px } - - .CHEntry { - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0; - margin-bottom: 3px; - padding: 2px 2ex; - font-size: 10pt; - background-color: #F4F4F4; color: #606060; - } - - .Firefox .CHEntry { - -moz-border-radius: 4px; - } - - .CHCurrent .CHEntry { - font-weight: bold; - border-color: #000000; - color: #000000; - } - - .CHChildNote .CHEntry { - font-style: italic; - font-size: 8pt; - } - - .CHIndent { - margin-left: 3ex; - } - - .CHEntry a:link, - .CHEntry a:visited, - .CHEntry a:hover { - color: #606060; - } - .CHEntry a:active { - color: #800000; - } - - - - - -#Index { - background-color: #FFFFFF; - } - -/* As opposed to .PopupSearchResultsPage #Index */ -.IndexPage #Index, -.FramedIndexPage #Index, -.FramedSearchResultsPage #Index { - padding: 15px; - } - -.IndexPage #Index { - border-width: 0 0 1px 1px; - border-style: solid; - border-color: #000000; - font-size: 9pt; /* To make 27ex match the menu's 27ex. */ - margin-left: 27ex; - } - - - .IPageTitle { - font-size: 20pt; font-weight: bold; - color: #FFFFFF; background-color: #7070C0; - padding: 10px 15px 10px 15px; - border-width: 0 0 3px 0; border-color: #000000; border-style: solid; - margin: -15px -15px 0 -15px } - - .FramedSearchResultsPage .IPageTitle { - margin-bottom: 15px; - } - - .INavigationBar { - font-size: 10pt; - text-align: center; - background-color: #FFFFF0; - padding: 5px; - border-bottom: solid 1px black; - margin: 0 -15px 15px -15px; - } - - .INavigationBar a { - font-weight: bold } - - .IHeading { - font-size: 16pt; font-weight: bold; - padding: 2.5em 0 .5em 0; - text-align: center; - width: 3.5ex; - } - #IFirstHeading { - padding-top: 0; - } - - .IEntry { - font-size: 10pt; - padding-left: 1ex; - } - .PopupSearchResultsPage .IEntry { - font-size: 8pt; - padding: 1px 5px; - } - .PopupSearchResultsPage .Opera9 .IEntry, - .FramedSearchResultsPage .Opera9 .IEntry { - text-align: left; - } - .FramedSearchResultsPage .IEntry { - padding: 0; - } - - .ISubIndex { - padding-left: 3ex; padding-bottom: .5em } - .PopupSearchResultsPage .ISubIndex { - display: none; - } - - /* While it may cause some entries to look like links when they aren't, I found it's much easier to read the - index if everything's the same color. */ - .ISymbol { - font-weight: bold; color: #900000 } - - .IndexPage .ISymbolPrefix, - .FramedIndexPage .ISymbolPrefix { - font-size: 10pt; - text-align: right; - color: #C47C7C; - background-color: #F8F8F8; - border-right: 3px solid #E0E0E0; - border-left: 1px solid #E0E0E0; - padding: 0 1px 0 2px; - } - .PopupSearchResultsPage .ISymbolPrefix, - .FramedSearchResultsPage .ISymbolPrefix { - color: #900000; - } - .PopupSearchResultsPage .ISymbolPrefix { - font-size: 8pt; - } - - .IndexPage #IFirstSymbolPrefix, - .FramedIndexPage #IFirstSymbolPrefix { - border-top: 1px solid #E0E0E0; - } - .IndexPage #ILastSymbolPrefix, - .FramedIndexPage #ILastSymbolPrefix { - border-bottom: 1px solid #E0E0E0; - } - .IndexPage #IOnlySymbolPrefix, - .FramedIndexPage #IOnlySymbolPrefix { - border-top: 1px solid #E0E0E0; - border-bottom: 1px solid #E0E0E0; - } - - a.IParent, - a.IFile { - display: block; - } - - .PopupSearchResultsPage .SRStatus { - padding: 2px 5px; - font-size: 8pt; - font-style: italic; - } - .FramedSearchResultsPage .SRStatus { - font-size: 10pt; - font-style: italic; - } - - .SRResult { - display: none; - } - - - -#Footer { - font-size: 8pt; - color: #989898; - text-align: right; - } - -#Footer p { - text-indent: 0; - margin-bottom: .5em; - } - -.ContentPage #Footer, -.IndexPage #Footer { - text-align: right; - margin: 2px; - } - -.FramedMenuPage #Footer { - text-align: center; - margin: 5em 10px 10px 10px; - padding-top: 1em; - border-top: 1px solid #C8C8C8; - } - - #Footer a:link, - #Footer a:hover, - #Footer a:visited { color: #989898 } - #Footer a:active { color: #A00000 } - diff --git a/public/javascripts/strophejs-1.0.1/examples/attach/README b/public/javascripts/strophejs-1.0.1/examples/attach/README deleted file mode 100644 index 3b190aa..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/attach/README +++ /dev/null @@ -1,37 +0,0 @@ -This is an example of Strophe attaching to a pre-existing BOSH session -that is created externally. This example requires a bit more than -HTML and JavaScript. Specifically it contains a very simple Web -application written in Django which creates a BOSH session before -rendering the page. - -Requirements: - -* Django 1.0 (http://www.djangoproject.com) -* Twisted 8.1.x (http://twistedmatrix.com) -* Punjab 0.3 (http://code.stanziq.com/punjab) - -Note that Twisted and Punjab are only used for small functions related -to JID and BOSH parsing. - -How It Works: - -The Django app contains one view which is tied to the root URL. This -view uses the BOSHClient class to start a BOSH session using the -settings from settings.py. - -Once the connection is established, Django passes the JID, SID, and -RID for the BOSH session into the template engine and renders the -page. - -The template assigns the JID, SID, and RID to global vars like so: - - var BOSH_JID = {{ jid }}; - var BOSH_SID = {{ sid }}; - var BOSH_RID = {{ rid }}; - -The connection is attached to Strophe by calling -Strophe.Connection.attach() with this data and a connection callback -handler. - -To show that the session is attached and works, a disco info ping is -done to jabber.org. diff --git a/public/javascripts/strophejs-1.0.1/examples/attach/__init__.py b/public/javascripts/strophejs-1.0.1/examples/attach/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/attach/__init__.py +++ /dev/null diff --git a/public/javascripts/strophejs-1.0.1/examples/attach/attacher/__init__.py b/public/javascripts/strophejs-1.0.1/examples/attach/attacher/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/attach/attacher/__init__.py +++ /dev/null diff --git a/public/javascripts/strophejs-1.0.1/examples/attach/attacher/views.py b/public/javascripts/strophejs-1.0.1/examples/attach/attacher/views.py deleted file mode 100644 index c495cab..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/attach/attacher/views.py +++ /dev/null @@ -1,18 +0,0 @@ -from django.http import HttpResponse -from django.template import Context, loader - -from attach.settings import BOSH_SERVICE, JABBERID, PASSWORD -from attach.boshclient import BOSHClient - -def index(request): - bc = BOSHClient(JABBERID, PASSWORD, BOSH_SERVICE) - bc.startSessionAndAuth() - - t = loader.get_template("attacher/index.html") - c = Context({ - 'jid': bc.jabberid.full(), - 'sid': bc.sid, - 'rid': bc.rid, - }) - - return HttpResponse(t.render(c)) diff --git a/public/javascripts/strophejs-1.0.1/examples/attach/boshclient.py b/public/javascripts/strophejs-1.0.1/examples/attach/boshclient.py deleted file mode 100644 index 7d797ef..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/attach/boshclient.py +++ /dev/null @@ -1,152 +0,0 @@ -import sys, os -import httplib, urllib -import random, binascii -from urlparse import urlparse - -from punjab.httpb import HttpbParse - -from twisted.words.xish import domish -from twisted.words.protocols.jabber import jid - -TLS_XMLNS = 'urn:ietf:params:xml:ns:xmpp-tls' -SASL_XMLNS = 'urn:ietf:params:xml:ns:xmpp-sasl' -BIND_XMLNS = 'urn:ietf:params:xml:ns:xmpp-bind' -SESSION_XMLNS = 'urn:ietf:params:xml:ns:xmpp-session' - - -class BOSHClient: - def __init__(self, jabberid, password, bosh_service): - self.rid = random.randint(0, 10000000) - self.jabberid = jid.internJID(jabberid) - self.password = password - - self.authid = None - self.sid = None - self.logged_in = False - self.headers = {"Content-type": "text/xml", - "Accept": "text/xml"} - - self.bosh_service = urlparse(bosh_service) - - def buildBody(self, child=None): - """Build a BOSH body. - """ - - body = domish.Element(("http://jabber.org/protocol/httpbind", "body")) - body['content'] = 'text/xml; charset=utf-8' - self.rid = self.rid + 1 - body['rid'] = str(self.rid) - body['sid'] = str(self.sid) - body['xml:lang'] = 'en' - - if child is not None: - body.addChild(child) - - return body - - def sendBody(self, body): - """Send the body. - """ - - parser = HttpbParse(True) - - # start new session - conn = httplib.HTTPConnection(self.bosh_service.netloc) - conn.request("POST", self.bosh_service.path, - body.toXml(), self.headers) - - response = conn.getresponse() - data = '' - if response.status == 200: - data = response.read() - conn.close() - - return parser.parse(data) - - def startSessionAndAuth(self, hold='1', wait='70'): - # Create a session - # create body - body = domish.Element(("http://jabber.org/protocol/httpbind", "body")) - - body['content'] = 'text/xml; charset=utf-8' - body['hold'] = hold - body['rid'] = str(self.rid) - body['to'] = self.jabberid.host - body['wait'] = wait - body['window'] = '5' - body['xml:lang'] = 'en' - - - retb, elems = self.sendBody(body) - if type(retb) != str and retb.hasAttribute('authid') and \ - retb.hasAttribute('sid'): - self.authid = retb['authid'] - self.sid = retb['sid'] - - # go ahead and auth - auth = domish.Element((SASL_XMLNS, 'auth')) - auth['mechanism'] = 'PLAIN' - - # TODO: add authzid - if auth['mechanism'] == 'PLAIN': - auth_str = "" - auth_str += "\000" - auth_str += self.jabberid.user.encode('utf-8') - auth_str += "\000" - try: - auth_str += self.password.encode('utf-8').strip() - except UnicodeDecodeError: - auth_str += self.password.decode('latin1') \ - .encode('utf-8').strip() - - auth.addContent(binascii.b2a_base64(auth_str)) - - retb, elems = self.sendBody(self.buildBody(auth)) - if len(elems) == 0: - # poll for data - retb, elems = self.sendBody(self.buildBody()) - - if len(elems) > 0: - if elems[0].name == 'success': - retb, elems = self.sendBody(self.buildBody()) - - if elems[0].firstChildElement().name == 'bind': - iq = domish.Element(('jabber:client', 'iq')) - iq['type'] = 'set' - iq.addUniqueId() - iq.addElement('bind') - iq.bind['xmlns'] = BIND_XMLNS - if self.jabberid.resource: - iq.bind.addElement('resource') - iq.bind.resource.addContent( - self.jabberid.resource) - - retb, elems = self.sendBody(self.buildBody(iq)) - if type(retb) != str and retb.name == 'body': - # send session - iq = domish.Element(('jabber:client', 'iq')) - iq['type'] = 'set' - iq.addUniqueId() - iq.addElement('session') - iq.session['xmlns'] = SESSION_XMLNS - - retb, elems = self.sendBody(self.buildBody(iq)) - - # did not bind, TODO - add a retry? - if type(retb) != str and retb.name == 'body': - self.logged_in = True - # bump up the rid, punjab already - # received self.rid - self.rid += 1 - - -if __name__ == '__main__': - USERNAME = sys.argv[1] - PASSWORD = sys.argv[2] - SERVICE = sys.argv[3] - - c = BOSHClient(USERNAME, PASSWORD, SERVICE) - c.startSessionAndAuth() - - print c.logged_in - diff --git a/public/javascripts/strophejs-1.0.1/examples/attach/manage.py b/public/javascripts/strophejs-1.0.1/examples/attach/manage.py deleted file mode 100755 index 5e78ea9..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/attach/manage.py +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env python -from django.core.management import execute_manager -try: - import settings # Assumed to be in the same directory. -except ImportError: - import sys - sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) - sys.exit(1) - -if __name__ == "__main__": - execute_manager(settings) diff --git a/public/javascripts/strophejs-1.0.1/examples/attach/settings.py b/public/javascripts/strophejs-1.0.1/examples/attach/settings.py deleted file mode 100644 index 419ec36..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/attach/settings.py +++ /dev/null @@ -1,85 +0,0 @@ -# Django settings for attach project. - -DEBUG = True -TEMPLATE_DEBUG = DEBUG - -ADMINS = ( - ('Some Body', 'romeo@example.com'), -) - -MANAGERS = ADMINS - -DATABASE_ENGINE = 'sqlite3' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. -DATABASE_NAME = '/path/to/attach.db' # Or path to database file if using sqlite3. -DATABASE_USER = '' # Not used with sqlite3. -DATABASE_PASSWORD = '' # Not used with sqlite3. -DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. -DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. - -# Local time zone for this installation. Choices can be found here: -# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name -# although not all choices may be available on all operating systems. -# If running in a Windows environment this must be set to the same as your -# system time zone. -TIME_ZONE = 'America/Denver' - -# Language code for this installation. All choices can be found here: -# http://www.i18nguy.com/unicode/language-identifiers.html -LANGUAGE_CODE = 'en-us' - -SITE_ID = 1 - -# If you set this to False, Django will make some optimizations so as not -# to load the internationalization machinery. -USE_I18N = True - -# Absolute path to the directory that holds media. -# Example: "/home/media/media.lawrence.com/" -MEDIA_ROOT = '' - -# URL that handles the media served from MEDIA_ROOT. Make sure to use a -# trailing slash if there is a path component (optional in other cases). -# Examples: "http://media.lawrence.com", "http://example.com/media/" -MEDIA_URL = '' - -# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a -# trailing slash. -# Examples: "http://foo.com/media/", "/media/". -ADMIN_MEDIA_PREFIX = '/media/' - -# Make this unique, and don't share it with anybody. -SECRET_KEY = 'asdf' - -# List of callables that know how to import templates from various sources. -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.load_template_source', - 'django.template.loaders.app_directories.load_template_source', -# 'django.template.loaders.eggs.load_template_source', -) - -MIDDLEWARE_CLASSES = ( - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', -) - -ROOT_URLCONF = 'attach.urls' - -TEMPLATE_DIRS = ( - # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". - # Always use forward slashes, even on Windows. - # Don't forget to use absolute paths, not relative paths. - '/path/to/attach/templates', -) - -INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'attach.attacher', -) - -BOSH_SERVICE = 'http://example.com/xmpp-httpbind' -JABBERID = 'romeo@example.com/bosh' -PASSWORD = 'juliet.is.hawt' diff --git a/public/javascripts/strophejs-1.0.1/examples/attach/templates/attacher/index.html b/public/javascripts/strophejs-1.0.1/examples/attach/templates/attacher/index.html deleted file mode 100644 index 14a7590..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/attach/templates/attacher/index.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - Strophe Attach Example - - - - - - - - -

Strophe Attach Example

-

This example shows how to attach to an existing BOSH session with - Strophe.

-

Log

-
-
- - \ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/examples/attach/urls.py b/public/javascripts/strophejs-1.0.1/examples/attach/urls.py deleted file mode 100644 index 387eb08..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/attach/urls.py +++ /dev/null @@ -1,19 +0,0 @@ -from django.conf.urls.defaults import * - -# Uncomment the next two lines to enable the admin: -# from django.contrib import admin -# admin.autodiscover() - -urlpatterns = patterns('', - # Example: - # (r'^attach/', include('attach.foo.urls')), - - # Uncomment the admin/doc line below and add 'django.contrib.admindocs' - # to INSTALLED_APPS to enable admin documentation: - # (r'^admin/doc/', include('django.contrib.admindocs.urls')), - - # Uncomment the next line to enable the admin: - # (r'^admin/(.*)', admin.site.root), - - (r'^$', 'attach.attacher.views.index'), -) diff --git a/public/javascripts/strophejs-1.0.1/examples/basic.html b/public/javascripts/strophejs-1.0.1/examples/basic.html deleted file mode 100644 index 0b1985d..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/basic.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - Strophe.js Basic Example - - - - - -
-
- - - - - -
-
-
-
- - diff --git a/public/javascripts/strophejs-1.0.1/examples/basic.js b/public/javascripts/strophejs-1.0.1/examples/basic.js deleted file mode 100644 index 0746ec1..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/basic.js +++ /dev/null @@ -1,55 +0,0 @@ -var BOSH_SERVICE = '/xmpp-httpbind' -var connection = null; - -function log(msg) -{ - $('#log').append('
').append(document.createTextNode(msg)); -} - -function rawInput(data) -{ - log('RECV: ' + data); -} - -function rawOutput(data) -{ - log('SENT: ' + data); -} - -function onConnect(status) -{ - if (status == Strophe.Status.CONNECTING) { - log('Strophe is connecting.'); - } else if (status == Strophe.Status.CONNFAIL) { - log('Strophe failed to connect.'); - $('#connect').get(0).value = 'connect'; - } else if (status == Strophe.Status.DISCONNECTING) { - log('Strophe is disconnecting.'); - } else if (status == Strophe.Status.DISCONNECTED) { - log('Strophe is disconnected.'); - $('#connect').get(0).value = 'connect'; - } else if (status == Strophe.Status.CONNECTED) { - log('Strophe is connected.'); - connection.disconnect(); - } -} - -$(document).ready(function () { - connection = new Strophe.Connection(BOSH_SERVICE); - connection.rawInput = rawInput; - connection.rawOutput = rawOutput; - - $('#connect').bind('click', function () { - var button = $('#connect').get(0); - if (button.value == 'connect') { - button.value = 'disconnect'; - - connection.connect($('#jid').get(0).value, - $('#pass').get(0).value, - onConnect); - } else { - button.value = 'connect'; - connection.disconnect(); - } - }); -}); \ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/examples/crossdomain.html b/public/javascripts/strophejs-1.0.1/examples/crossdomain.html deleted file mode 100644 index 4de9a93..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/crossdomain.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - Strophe.js Basic Cross-Domain Example - - - - - - - - - - -
-
- - - - - -
-
-
-
- - diff --git a/public/javascripts/strophejs-1.0.1/examples/crossdomain.js b/public/javascripts/strophejs-1.0.1/examples/crossdomain.js deleted file mode 100644 index 50a7f79..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/crossdomain.js +++ /dev/null @@ -1,62 +0,0 @@ -// The BOSH_SERVICE here doesn't need to be on the same domain/port, but -// it must have a /crossdomain.xml policy file that allows access from -// wherever crossdomain.html lives. -// -// Most BOSH connection managers can serve static html files, so you should -// be able to configure them to serve a /crossdomain.xml file to allow -// access. -var BOSH_SERVICE = 'http://localhost:5281/xmpp-httpbind' -var connection = null; - -function log(msg) -{ - $('#log').append('
').append(document.createTextNode(msg)); -} - -function rawInput(data) -{ - log('RECV: ' + data); -} - -function rawOutput(data) -{ - log('SENT: ' + data); -} - -function onConnect(status) -{ - if (status == Strophe.Status.CONNECTING) { - log('Strophe is connecting.'); - } else if (status == Strophe.Status.CONNFAIL) { - log('Strophe failed to connect.'); - $('#connect').get(0).value = 'connect'; - } else if (status == Strophe.Status.DISCONNECTING) { - log('Strophe is disconnecting.'); - } else if (status == Strophe.Status.DISCONNECTED) { - log('Strophe is disconnected.'); - $('#connect').get(0).value = 'connect'; - } else if (status == Strophe.Status.CONNECTED) { - log('Strophe is connected.'); - connection.disconnect(); - } -} - -$(document).ready(function () { - connection = new Strophe.Connection(BOSH_SERVICE); - connection.rawInput = rawInput; - connection.rawOutput = rawOutput; - - $('#connect').bind('click', function () { - var button = $('#connect').get(0); - if (button.value == 'connect') { - button.value = 'disconnect'; - - connection.connect($('#jid').get(0).value, - $('#pass').get(0).value, - onConnect); - } else { - button.value = 'connect'; - connection.disconnect(); - } - }); -}); \ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/examples/crossdomain.xml b/public/javascripts/strophejs-1.0.1/examples/crossdomain.xml deleted file mode 100644 index 3dce209..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/crossdomain.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/examples/dojo-ping.html b/public/javascripts/strophejs-1.0.1/examples/dojo-ping.html deleted file mode 100644 index 53a2cb3..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/dojo-ping.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - Strophe.js Dojo Ping Example - - - - - - -
-
-
- - - - - -
-
-
- -
- -
- - diff --git a/public/javascripts/strophejs-1.0.1/examples/dojo-ping.js b/public/javascripts/strophejs-1.0.1/examples/dojo-ping.js deleted file mode 100644 index 0e3bddf..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/dojo-ping.js +++ /dev/null @@ -1,56 +0,0 @@ -var DojoPing = { - BOSH_SERVICE: '/xmpp-httpbind', - TARGET: 'jabber.org', - connection: null -}; - -dojo.addOnLoad(function () { - dojo.connect(dojo.byId('connect'), "click", function (e) { - var jid = dojo.attr(dojo.byId('jid'), 'value'); - var pass_node = dojo.byId('pass'); - var pass = dojo.attr(pass_node, 'value'); - dojo.attr(pass_node, 'value', ''); - - DojoPing.connection = new Strophe.Connection(DojoPing.BOSH_SERVICE); - - dojo.place("

Connecting...

", "log"); - - DojoPing.connection.connect(jid, pass, function (status) { - if (status === Strophe.Status.CONNECTED) { - dojo.publish('connected'); - } else if (status === Strophe.Status.DISCONNECTED) { - dojo.publish('disconnected'); - } - }); - }); - - dojo.subscribe('connected', function () { - dojo.place("

Connected.

", "log"); - - var ping = $iq({to: DojoPing.TARGET, type: 'get'}) - .c('query', {xmlns: Strophe.NS.DISCO_ITEMS}); - - var sent_stamp = new Date(); - DojoPing.connection.sendIQ(ping, function (iq) { - var elapsed = new Date() - sent_stamp; - - // use dojo.query on incoming stanza - var items = dojo.query('items', iq); - console.log(items); - - dojo.place("

Disco#items response received after " + - elapsed + "ms." + DojoPing.TARGET + " reports " + - "it has " + items + " disco items.

", "log"); - - DojoPing.connection.disconnect(); - }); - - DojoPing.connection.send(ping); - - dojo.place("

Ping sent to " + DojoPing.TARGET + ".

", "log"); - }); - - dojo.subscribe('disconnected', function () { - dojo.place("

Disconnected.

", "log"); - }); -}); \ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/examples/echobot.html b/public/javascripts/strophejs-1.0.1/examples/echobot.html deleted file mode 100644 index 07f97f5..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/echobot.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - Strophe.js Echobot Example - - - - - -
-
- - - - - -
-
-
-
- - diff --git a/public/javascripts/strophejs-1.0.1/examples/echobot.js b/public/javascripts/strophejs-1.0.1/examples/echobot.js deleted file mode 100644 index 02ffc2a..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/echobot.js +++ /dev/null @@ -1,79 +0,0 @@ -var BOSH_SERVICE = '/http-bind'; -var connection = null; - -function log(msg) -{ - $('#log').append('
').append(document.createTextNode(msg)); -} - -function onConnect(status) -{ - if (status == Strophe.Status.CONNECTING) { - log('Strophe is connecting.'); - } else if (status == Strophe.Status.CONNFAIL) { - log('Strophe failed to connect.'); - $('#connect').get(0).value = 'connect'; - } else if (status == Strophe.Status.DISCONNECTING) { - log('Strophe is disconnecting.'); - } else if (status == Strophe.Status.DISCONNECTED) { - log('Strophe is disconnected.'); - $('#connect').get(0).value = 'connect'; - } else if (status == Strophe.Status.CONNECTED) { - log('Strophe is connected.'); - log('ECHOBOT: Send a message to ' + connection.jid + - ' to talk to me.'); - - connection.addHandler(onMessage, null, 'message', null, null, null); - connection.send($pres().tree()); - } -} - -function onMessage(msg) { - var to = msg.getAttribute('to'); - var from = msg.getAttribute('from'); - var type = msg.getAttribute('type'); - var elems = msg.getElementsByTagName('body'); - - if (type == "chat" && elems.length > 0) { - var body = elems[0]; - - log('ECHOBOT: I got a message from ' + from + ': ' + - Strophe.getText(body)); - - var reply = $msg({to: from, from: to, type: 'chat'}) - .cnode(Strophe.copyElement(body)); - connection.send(reply.tree()); - - log('ECHOBOT: I sent ' + from + ': ' + Strophe.getText(body)); - } - - // we must return true to keep the handler alive. - // returning false would remove it after it finishes. - return true; -} - -$(document).ready(function () { - connection = new Strophe.Connection(BOSH_SERVICE); - - // Uncomment the following lines to spy on the wire traffic. - //connection.rawInput = function (data) { log('RECV: ' + data); }; - //connection.rawOutput = function (data) { log('SEND: ' + data); }; - - // Uncomment the following line to see all the debug output. - //Strophe.log = function (level, msg) { log('LOG: ' + msg); }; - - - $('#connect').bind('click', function () { - var button = $('#connect').get(0); - if (button.value == 'connect') { - button.value = 'disconnect'; - - connection.connect($('#jid').get(0).value, - $('#pass').get(0).value, - onConnect); - } else { - button.value = 'connect'; - connection.disconnect(); - } - }); -}); diff --git a/public/javascripts/strophejs-1.0.1/examples/prebind.html b/public/javascripts/strophejs-1.0.1/examples/prebind.html deleted file mode 100644 index b9d4a34..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/prebind.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - Strophe.js Pre-Bind Example - - - - - - -
-
- - - - - -
-
- -
- -
- - diff --git a/public/javascripts/strophejs-1.0.1/examples/prebind.js b/public/javascripts/strophejs-1.0.1/examples/prebind.js deleted file mode 100644 index 009ac7d..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/prebind.js +++ /dev/null @@ -1,103 +0,0 @@ -// http-pre-bind example -// This example works with mod_http_pre_bind found here: -// http://github.com/thepug/Mod-Http-Pre-Bind -// -// It expects both /xmpp-httpbind to be proxied and /http-pre-bind -// -// If you want to test this out without setting it up, you can use Collecta's -// at http://www.collecta.com/xmpp-httpbind and -// http://www.collecta.com/http-pre-bind -// Use a JID of 'guest.collecta.com' to test. - -var BOSH_SERVICE = '/xmpp-httpbind'; -var PREBIND_SERVICE = '/http-pre-bind'; -var connection = null; - -function log(msg) -{ - $('#log').append('
').append(document.createTextNode(msg)); -} - -function rawInput(data) -{ - log('RECV: ' + data); -} - -function rawOutput(data) -{ - log('SENT: ' + data); -} - -function onConnect(status) -{ - if (status === Strophe.Status.CONNECTING) { - log('Strophe is connecting.'); - } else if (status === Strophe.Status.CONNFAIL) { - log('Strophe failed to connect.'); - $('#connect').get(0).value = 'connect'; - } else if (status === Strophe.Status.DISCONNECTING) { - log('Strophe is disconnecting.'); - } else if (status === Strophe.Status.DISCONNECTED) { - log('Strophe is disconnected.'); - $('#connect').get(0).value = 'connect'; - } else if (status === Strophe.Status.CONNECTED) { - log('Strophe is connected.'); - connection.disconnect(); - } else if (status === Strophe.Status.ATTACHED) { - log('Strophe is attached.'); - connection.disconnect(); - } -} - -function normal_connect() { - log('Prebind failed. Connecting normally...'); - - connection = new Strophe.Connection(BOSH_SERVICE); - connection.rawInput = rawInput; - connection.rawOutput = rawOutput; - - connection.connect($('#jid').val(), $('#pass').val(), onConnect); -} - -function attach(data) { - log('Prebind succeeded. Attaching...'); - - connection = new Strophe.Connection(BOSH_SERVICE); - connection.rawInput = rawInput; - connection.rawOutput = rawOutput; - - var $body = $(data.documentElement); - connection.attach($body.find('jid').text(), - $body.attr('sid'), - parseInt($body.attr('rid'), 10) + 1, - onConnect); -} - -$(document).ready(function () { - $('#connect').bind('click', function () { - var button = $('#connect').get(0); - if (button.value == 'connect') { - button.value = 'disconnect'; - - // attempt prebind - $.ajax({ - type: 'POST', - url: PREBIND_SERVICE, - contentType: 'text/xml', - processData: false, - data: $build('body', { - to: Strophe.getDomainFromJid($('#jid').val()), - rid: '' + Math.floor(Math.random() * 4294967295), - wait: '60', - hold: '1'}).toString(), - dataType: 'xml', - error: normal_connect, - success: attach}); - } else { - button.value = 'connect'; - if (connection) { - connection.disconnect(); - } - } - }); -}); \ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/examples/prototype-ping.html b/public/javascripts/strophejs-1.0.1/examples/prototype-ping.html deleted file mode 100644 index 990cc41..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/prototype-ping.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - Strophe.js Prototype Ping Example - - - - - - -
-
-
- - - - - -
-
-
- -
- -
- - diff --git a/public/javascripts/strophejs-1.0.1/examples/prototype-ping.js b/public/javascripts/strophejs-1.0.1/examples/prototype-ping.js deleted file mode 100644 index db2b423..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/prototype-ping.js +++ /dev/null @@ -1,56 +0,0 @@ -var ProtoPing = { - BOSH_SERVICE: '/xmpp-httpbind', - TARGET: 'jabber.org', - connection: null -}; - -document.observe('dom:loaded', function () { - var log = $('log'); - - $('connect').observe('click', function () { - var jid = $F('jid'); - var pass = $F('pass'); - Form.Element.setValue('pass', ''); - - ProtoPing.connection = new Strophe.Connection(ProtoPing.BOSH_SERVICE); - - log.insert("

Connecting...

"); - - ProtoPing.connection.connect(jid, pass, function (status) { - if (status === Strophe.Status.CONNECTED) { - document.fire('strophe:connected'); - } else if (status === Strophe.Status.DISCONNECTED) { - document.fire('strophe:disconnected'); - } - }); - }); - - document.observe('strophe:connected', function () { - log.insert('

Connected.

'); - - var ping = $iq({to: ProtoPing.TARGET, type: 'get'}) - .c('query', {xmlns: Strophe.NS.DISCO_ITEMS}); - - var sent_stamp = new Date(); - ProtoPing.connection.sendIQ(ping, function (iq) { - var elapsed = new Date() - sent_stamp; - - // use Prototype's selectors to access XMPP stanza - var items = Selector.findChildElements(iq, ['item']); - - log.insert("

Disco#items response received after " + - elapsed + "ms." + ProtoPing.TARGET + " reports " + - "it has " + items + " disco items.

"); - - ProtoPing.connection.disconnect(); - }); - - ProtoPing.connection.send(ping); - - log.insert("

Ping sent to " + ProtoPing.TARGET + ".

"); - }); - - document.observe('strophe:disconnected', function () { - log.insert('

Disconnected.

'); - }); -}); \ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/examples/yui-ping.html b/public/javascripts/strophejs-1.0.1/examples/yui-ping.html deleted file mode 100644 index 05ee3bd..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/yui-ping.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - Strophe.js YUI3 Ping Example - - - - - -
-
-
- - - - - -
-
-
- -
- -
- - diff --git a/public/javascripts/strophejs-1.0.1/examples/yui-ping.js b/public/javascripts/strophejs-1.0.1/examples/yui-ping.js deleted file mode 100644 index 6441009..0000000 --- a/public/javascripts/strophejs-1.0.1/examples/yui-ping.js +++ /dev/null @@ -1,58 +0,0 @@ -YUI().use('node', function (Y) { - var BOSH_SERVICE = '/xmpp-httpbind'; - var connection = null; - - var log = Y.one('#log'); - - Y.augment(Strophe.Connection, Y.EventTarget); - - Y.one('#connect').on('click', function (e) { - var jid = Y.one('#jid').get('value'); - var pass_node = Y.one('#pass'); - var pass = pass_node.get('value'); - pass_node.set('value', ''); - - connection = new Strophe.Connection(BOSH_SERVICE); - - log.append('

Connecting...

'); - - connection.connect(jid, pass, function (status) { - if (status === Strophe.Status.CONNECTED) { - connection.fire('connected'); - } else if (status === Strophe.Status.DISCONNECTED) { - connection.fire('disconnected'); - } - }); - - connection.on('connected', function () { - log.append('

Connected.

'); - - var ping = $iq({to: 'jabber.org', type: 'get'}) - .c('query', {xmlns: Strophe.NS.DISCO_ITEMS}); - - var sent_stamp = new Date(); - connection.sendIQ(ping, function (iq) { - var elapsed = new Date() - sent_stamp; - - // convert incoming XMPP stanza to a Node - var stanza = Y.Selector.query('item', iq, null, true); - window['stanza'] = iq; - window['Y'] = Y; - - console.log(stanza); - - log.append("

Disco#items response received after " + - elapsed + "ms. Jabber.org reports it has " + - items + " items.

"); - - connection.disconnect(); - }); - - log.append('

Ping sent.

'); - }); - - connection.on('disconnected', function () { - log.append('

Disconnected.

'); - }); - }); -}); \ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/plugins/strophe.flxhr.js b/public/javascripts/strophejs-1.0.1/plugins/strophe.flxhr.js deleted file mode 100644 index 0b0958e..0000000 --- a/public/javascripts/strophejs-1.0.1/plugins/strophe.flxhr.js +++ /dev/null @@ -1,31 +0,0 @@ -/* flXHR plugin -** -** This plugin implements cross-domain XmlHttpRequests via an invisible -** Flash plugin. -** -** In order for this to work, the BOSH service *must* serve a -** crossdomain.xml file that allows the client access. -** -** flXHR.js should be loaded before this plugin. -*/ - -Strophe.addConnectionPlugin('flxhr', { - init: function () { - // replace Strophe.Request._newXHR with new flXHR version - // if flXHR is detected - if (flensed && flensed.flXHR) { - Strophe.Request.prototype._newXHR = function () { - var xhr = new flensed.flXHR({ - autoUpdatePlayer: true, - instancePooling: true, - noCacheHeader: false}); - xhr.onreadystatechange = this.func.prependArg(this); - - return xhr; - }; - } else { - Strophe.error("flXHR plugin loaded, but flXHR not found." + - " Falling back to native XHR implementation."); - } - } -}); diff --git a/public/javascripts/strophejs-1.0.1/plugins/strophe.flxhr.min.js b/public/javascripts/strophejs-1.0.1/plugins/strophe.flxhr.min.js deleted file mode 100644 index 33f5e9c..0000000 --- a/public/javascripts/strophejs-1.0.1/plugins/strophe.flxhr.min.js +++ /dev/null @@ -1 +0,0 @@ -Strophe.addConnectionPlugin("flxhr",{init:function(){if(flensed&&flensed.flXHR){Strophe.Request.prototype._newXHR=function(){var xhr=new flensed.flXHR({autoUpdatePlayer:true,instancePooling:true,noCacheHeader:false});xhr.onreadystatechange=this.func.prependArg(this);return xhr}}else{Strophe.error("flXHR plugin loaded, but flXHR not found. Falling back to native XHR implementation.")}}}); \ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/plugins/strophe.pubsub.js b/public/javascripts/strophejs-1.0.1/plugins/strophe.pubsub.js deleted file mode 100644 index e2dc003..0000000 --- a/public/javascripts/strophejs-1.0.1/plugins/strophe.pubsub.js +++ /dev/null @@ -1,270 +0,0 @@ -/* - Copyright 2008, Stanziq Inc. -*/ - -Strophe.addConnectionPlugin('pubsub', { -/* - Extend connection object to have plugin name 'pubsub'. -*/ - _connection: null, - - //The plugin must have the init function. - init: function(conn) { - - this._connection = conn; - - /* - Function used to setup plugin. - */ - - /* extend name space - * NS.PUBSUB - XMPP Publish Subscribe namespace - * from XEP 60. - * - * NS.PUBSUB_SUBSCRIBE_OPTIONS - XMPP pubsub - * options namespace from XEP 60. - */ - Strophe.addNamespace('PUBSUB',"http://jabber.org/protocol/pubsub"); - Strophe.addNamespace('PUBSUB_SUBSCRIBE_OPTIONS', - Strophe.NS.PUBSUB+"#subscribe_options"); - Strophe.addNamespace('PUBSUB_ERRORS',Strophe.NS.PUBSUB+"#errors"); - Strophe.addNamespace('PUBSUB_EVENT',Strophe.NS.PUBSUB+"#event"); - Strophe.addNamespace('PUBSUB_OWNER',Strophe.NS.PUBSUB+"#owner"); - Strophe.addNamespace('PUBSUB_AUTO_CREATE', - Strophe.NS.PUBSUB+"#auto-create"); - Strophe.addNamespace('PUBSUB_PUBLISH_OPTIONS', - Strophe.NS.PUBSUB+"#publish-options"); - Strophe.addNamespace('PUBSUB_NODE_CONFIG', - Strophe.NS.PUBSUB+"#node_config"); - Strophe.addNamespace('PUBSUB_CREATE_AND_CONFIGURE', - Strophe.NS.PUBSUB+"#create-and-configure"); - Strophe.addNamespace('PUBSUB_SUBSCRIBE_AUTHORIZATION', - Strophe.NS.PUBSUB+"#subscribe_authorization"); - Strophe.addNamespace('PUBSUB_GET_PENDING', - Strophe.NS.PUBSUB+"#get-pending"); - Strophe.addNamespace('PUBSUB_MANAGE_SUBSCRIPTIONS', - Strophe.NS.PUBSUB+"#manage-subscriptions"); - Strophe.addNamespace('PUBSUB_META_DATA', - Strophe.NS.PUBSUB+"#meta-data"); - - }, - /***Function - - Create a pubsub node on the given service with the given node - name. - - Parameters: - (String) jid - The node owner's jid. - (String) service - The name of the pubsub service. - (String) node - The name of the pubsub node. - (Dictionary) options - The configuration options for the node. - (Function) call_back - Used to determine if node - creation was sucessful. - - Returns: - Iq id used to send subscription. - */ - createNode: function(jid,service,node,options, call_back) { - - var iqid = this._connection.getUniqueId("pubsubcreatenode"); - - var iq = $iq({from:jid, to:service, type:'set', id:iqid}); - - var c_options = Strophe.xmlElement("configure",[]); - var x = Strophe.xmlElement("x",[["xmlns","jabber:x:data"]]); - var form_field = Strophe.xmlElement("field",[["var","FORM_TYPE"], - ["type","hidden"]]); - var value = Strophe.xmlElement("value",[]); - var text = Strophe.xmlTextNode(Strophe.NS.PUBSUB+"#node_config"); - value.appendChild(text); - form_field.appendChild(value); - x.appendChild(form_field); - - for (var i in options) - { - var val = options[i]; - x.appendChild(val); - } - - if(options.length && options.length != 0) - { - c_options.appendChild(x); - } - - iq.c('pubsub', - {xmlns:Strophe.NS.PUBSUB}).c('create', - {node:node}).up().cnode(c_options); - - this._connection.addHandler(call_back, - null, - 'iq', - null, - iqid, - null); - this._connection.send(iq.tree()); - return iqid; - }, - /***Function - Subscribe to a node in order to receive event items. - - Parameters: - (String) jid - The node owner's jid. - (String) service - The name of the pubsub service. - (String) node - The name of the pubsub node. - (Array) options - The configuration options for the node. - (Function) event_cb - Used to recieve subscription events. - (Function) call_back - Used to determine if node - creation was sucessful. - - Returns: - Iq id used to send subscription. - */ - subscribe: function(jid,service,node,options, event_cb, call_back) { - - var subid = this._connection.getUniqueId("subscribenode"); - - //create subscription options - var sub_options = Strophe.xmlElement("options",[]); - var x = Strophe.xmlElement("x",[["xmlns","jabber:x:data"]]); - var form_field = Strophe.xmlElement("field",[["var","FORM_TYPE"], - ["type","hidden"]]); - var value = Strophe.xmlElement("value",[]); - var text = Strophe.xmlTextNode(Strophe.NS.PUBSUB_SUBSCRIBE_OPTIONS); - value.appendChild(text); - form_field.appendChild(value); - x.appendChild(form_field); - - var sub = $iq({from:jid, to:service, type:'set', id:subid}) - - if(options && options.length && options.length !== 0) - { - for (var i = 0; i < options.length; i++) - { - var val = options[i]; - x.appendChild(val); - } - sub_options.appendChild(x); - - sub.c('pubsub', { xmlns:Strophe.NS.PUBSUB }).c('subscribe', - {node:node,jid:jid}).up().cnode(sub_options); - } - else - { - - sub.c('pubsub', { xmlns:Strophe.NS.PUBSUB }).c('subscribe', - {node:node,jid:jid}); - } - - - this._connection.addHandler(call_back, - null, - 'iq', - null, - subid, - null); - - //add the event handler to receive items - this._connection.addHandler(event_cb, - null, - 'message', - null, - null, - null); - this._connection.send(sub.tree()); - return subid; - - }, - /***Function - Unsubscribe from a node. - - Parameters: - (String) jid - The node owner's jid. - (String) service - The name of the pubsub service. - (String) node - The name of the pubsub node. - (Function) call_back - Used to determine if node - creation was sucessful. - - */ - unsubscribe: function(jid,service,node, call_back) { - - var subid = this._connection.getUniqueId("unsubscribenode"); - - - var sub = $iq({from:jid, to:service, type:'set', id:subid}) - sub.c('pubsub', { xmlns:Strophe.NS.PUBSUB }).c('unsubscribe', - {node:node,jid:jid}); - - - - this._connection.addHandler(call_back, - null, - 'iq', - null, - subid, - null); - this._connection.send(sub.tree()); - - - return subid; - - }, - /***Function - - Publish and item to the given pubsub node. - - Parameters: - (String) jid - The node owner's jid. - (String) service - The name of the pubsub service. - (String) node - The name of the pubsub node. - (Array) items - The list of items to be published. - (Function) call_back - Used to determine if node - creation was sucessful. - */ - publish: function(jid, service, node, items, call_back) { - var pubid = this._connection.getUniqueId("publishnode"); - - - var publish_elem = Strophe.xmlElement("publish", - [["node", - node], - ["jid", - jid]]); - for (var i in items) - { - var item = Strophe.xmlElement("item",[]); - var entry = Strophe.xmlElement("entry",[]); - var t = Strophe.xmlTextNode(items[i]); - entry.appendChild(t); - item.appendChild(entry); - publish_elem.appendChild(item); - } - - var pub = $iq({from:jid, to:service, type:'set', id:pubid}) - pub.c('pubsub', { xmlns:Strophe.NS.PUBSUB }).cnode(publish_elem); - - - this._connection.addHandler(call_back, - null, - 'iq', - null, - pubid, - null); - this._connection.send(pub.tree()); - - - return pubid; - }, - /*Function: items - Used to retrieve the persistent items from the pubsub node. - - */ - items: function(jid,service,node,ok_callback,error_back) { - var pub = $iq({from:jid, to:service, type:'get'}) - - //ask for all items - pub.c('pubsub', - { xmlns:Strophe.NS.PUBSUB }).c('items',{node:node}); - - return this._connection.sendIQ(pub.tree(),ok_callback,error_back); - } -}); diff --git a/public/javascripts/strophejs-1.0.1/plugins/strophe.pubsub.min.js b/public/javascripts/strophejs-1.0.1/plugins/strophe.pubsub.min.js deleted file mode 100644 index 166f882..0000000 --- a/public/javascripts/strophejs-1.0.1/plugins/strophe.pubsub.min.js +++ /dev/null @@ -1 +0,0 @@ -Strophe.addConnectionPlugin("pubsub",{_connection:null,init:function(conn){this._connection=conn;Strophe.addNamespace("PUBSUB","http://jabber.org/protocol/pubsub");Strophe.addNamespace("PUBSUB_SUBSCRIBE_OPTIONS",Strophe.NS.PUBSUB+"#subscribe_options");Strophe.addNamespace("PUBSUB_ERRORS",Strophe.NS.PUBSUB+"#errors");Strophe.addNamespace("PUBSUB_EVENT",Strophe.NS.PUBSUB+"#event");Strophe.addNamespace("PUBSUB_OWNER",Strophe.NS.PUBSUB+"#owner");Strophe.addNamespace("PUBSUB_AUTO_CREATE",Strophe.NS.PUBSUB+"#auto-create");Strophe.addNamespace("PUBSUB_PUBLISH_OPTIONS",Strophe.NS.PUBSUB+"#publish-options");Strophe.addNamespace("PUBSUB_NODE_CONFIG",Strophe.NS.PUBSUB+"#node_config");Strophe.addNamespace("PUBSUB_CREATE_AND_CONFIGURE",Strophe.NS.PUBSUB+"#create-and-configure");Strophe.addNamespace("PUBSUB_SUBSCRIBE_AUTHORIZATION",Strophe.NS.PUBSUB+"#subscribe_authorization");Strophe.addNamespace("PUBSUB_GET_PENDING",Strophe.NS.PUBSUB+"#get-pending");Strophe.addNamespace("PUBSUB_MANAGE_SUBSCRIPTIONS",Strophe.NS.PUBSUB+"#manage-subscriptions");Strophe.addNamespace("PUBSUB_META_DATA",Strophe.NS.PUBSUB+"#meta-data")},createNode:function(jid,service,node,options,call_back){var iqid=this._connection.getUniqueId("pubsubcreatenode");var iq=$iq({from:jid,to:service,type:"set",id:iqid});var c_options=Strophe.xmlElement("configure",[]);var x=Strophe.xmlElement("x",[["xmlns","jabber:x:data"]]);var form_field=Strophe.xmlElement("field",[["var","FORM_TYPE"],["type","hidden"]]);var value=Strophe.xmlElement("value",[]);var text=Strophe.xmlTextNode(Strophe.NS.PUBSUB+"#node_config");value.appendChild(text);form_field.appendChild(value);x.appendChild(form_field);for(var i in options){var val=options[i];x.appendChild(val)}if(options.length&&options.length!=0){c_options.appendChild(x)}iq.c("pubsub",{xmlns:Strophe.NS.PUBSUB}).c("create",{node:node}).up().cnode(c_options);this._connection.addHandler(call_back,null,"iq",null,iqid,null);this._connection.send(iq.tree());return iqid},subscribe:function(jid,service,node,options,event_cb,call_back){var subid=this._connection.getUniqueId("subscribenode");var sub_options=Strophe.xmlElement("options",[]);var x=Strophe.xmlElement("x",[["xmlns","jabber:x:data"]]);var form_field=Strophe.xmlElement("field",[["var","FORM_TYPE"],["type","hidden"]]);var value=Strophe.xmlElement("value",[]);var text=Strophe.xmlTextNode(Strophe.NS.PUBSUB_SUBSCRIBE_OPTIONS);value.appendChild(text);form_field.appendChild(value);x.appendChild(form_field);var sub=$iq({from:jid,to:service,type:"set",id:subid});if(options&&options.length&&options.length!==0){for(var i=0;i> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } else if (isNaN(chr3)) { - enc4 = 64; - } - - output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + - keyStr.charAt(enc3) + keyStr.charAt(enc4); - } while (i < input.length); - - return output; - }, - - /** - * Decodes a base64 string. - * @param {String} input The string to decode. - */ - decode: function (input) { - var output = ""; - var chr1, chr2, chr3; - var enc1, enc2, enc3, enc4; - var i = 0; - - // remove all characters that are not A-Z, a-z, 0-9, +, /, or = - input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); - - do { - enc1 = keyStr.indexOf(input.charAt(i++)); - enc2 = keyStr.indexOf(input.charAt(i++)); - enc3 = keyStr.indexOf(input.charAt(i++)); - enc4 = keyStr.indexOf(input.charAt(i++)); - - chr1 = (enc1 << 2) | (enc2 >> 4); - chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); - chr3 = ((enc3 & 3) << 6) | enc4; - - output = output + String.fromCharCode(chr1); - - if (enc3 != 64) { - output = output + String.fromCharCode(chr2); - } - if (enc4 != 64) { - output = output + String.fromCharCode(chr3); - } - } while (i < input.length); - - return output; - } - }; - - return obj; -})(); -/* - * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message - * Digest Algorithm, as defined in RFC 1321. - * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002. - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * Distributed under the BSD License - * See http://pajhome.org.uk/crypt/md5 for more info. - */ - -var MD5 = (function () { - /* - * Configurable variables. You may need to tweak these to be compatible with - * the server-side, but the defaults work in most cases. - */ - var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ - var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ - var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ - - /* - * Add integers, wrapping at 2^32. This uses 16-bit operations internally - * to work around bugs in some JS interpreters. - */ - var safe_add = function (x, y) { - var lsw = (x & 0xFFFF) + (y & 0xFFFF); - var msw = (x >> 16) + (y >> 16) + (lsw >> 16); - return (msw << 16) | (lsw & 0xFFFF); - }; - - /* - * Bitwise rotate a 32-bit number to the left. - */ - var bit_rol = function (num, cnt) { - return (num << cnt) | (num >>> (32 - cnt)); - }; - - /* - * Convert a string to an array of little-endian words - * If chrsz is ASCII, characters >255 have their hi-byte silently ignored. - */ - var str2binl = function (str) { - var bin = []; - var mask = (1 << chrsz) - 1; - for(var i = 0; i < str.length * chrsz; i += chrsz) - { - bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); - } - return bin; - }; - - /* - * Convert an array of little-endian words to a string - */ - var binl2str = function (bin) { - var str = ""; - var mask = (1 << chrsz) - 1; - for(var i = 0; i < bin.length * 32; i += chrsz) - { - str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask); - } - return str; - }; - - /* - * Convert an array of little-endian words to a hex string. - */ - var binl2hex = function (binarray) { - var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; - var str = ""; - for(var i = 0; i < binarray.length * 4; i++) - { - str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) + - hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF); - } - return str; - }; - - /* - * Convert an array of little-endian words to a base-64 string - */ - var binl2b64 = function (binarray) { - var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - var str = ""; - var triplet, j; - for(var i = 0; i < binarray.length * 4; i += 3) - { - triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16) | - (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) | - ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF); - for(j = 0; j < 4; j++) - { - if(i * 8 + j * 6 > binarray.length * 32) { str += b64pad; } - else { str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); } - } - } - return str; - }; - - /* - * These functions implement the four basic operations the algorithm uses. - */ - var md5_cmn = function (q, a, b, x, s, t) { - return safe_add(bit_rol(safe_add(safe_add(a, q),safe_add(x, t)), s),b); - }; - - var md5_ff = function (a, b, c, d, x, s, t) { - return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); - }; - - var md5_gg = function (a, b, c, d, x, s, t) { - return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); - }; - - var md5_hh = function (a, b, c, d, x, s, t) { - return md5_cmn(b ^ c ^ d, a, b, x, s, t); - }; - - var md5_ii = function (a, b, c, d, x, s, t) { - return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); - }; - - /* - * Calculate the MD5 of an array of little-endian words, and a bit length - */ - var core_md5 = function (x, len) { - /* append padding */ - x[len >> 5] |= 0x80 << ((len) % 32); - x[(((len + 64) >>> 9) << 4) + 14] = len; - - var a = 1732584193; - var b = -271733879; - var c = -1732584194; - var d = 271733878; - - var olda, oldb, oldc, oldd; - for (var i = 0; i < x.length; i += 16) - { - olda = a; - oldb = b; - oldc = c; - oldd = d; - - a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); - d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); - c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); - b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); - a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); - d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); - c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); - b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); - a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); - d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); - c = md5_ff(c, d, a, b, x[i+10], 17, -42063); - b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); - a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); - d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); - c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); - b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); - - a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); - d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); - c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); - b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); - a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); - d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); - c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); - b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); - a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); - d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); - c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); - b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); - a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); - d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); - c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); - b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); - - a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); - d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); - c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); - b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); - a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); - d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); - c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); - b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); - a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); - d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); - c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); - b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); - a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); - d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); - c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); - b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); - - a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); - d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); - c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); - b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); - a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); - d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); - c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); - b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); - a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); - d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); - c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); - b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); - a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); - d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); - c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); - b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); - - a = safe_add(a, olda); - b = safe_add(b, oldb); - c = safe_add(c, oldc); - d = safe_add(d, oldd); - } - return [a, b, c, d]; - }; - - - /* - * Calculate the HMAC-MD5, of a key and some data - */ - var core_hmac_md5 = function (key, data) { - var bkey = str2binl(key); - if(bkey.length > 16) { bkey = core_md5(bkey, key.length * chrsz); } - - var ipad = new Array(16), opad = new Array(16); - for(var i = 0; i < 16; i++) - { - ipad[i] = bkey[i] ^ 0x36363636; - opad[i] = bkey[i] ^ 0x5C5C5C5C; - } - - var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz); - return core_md5(opad.concat(hash), 512 + 128); - }; - - var obj = { - /* - * These are the functions you'll usually want to call. - * They take string arguments and return either hex or base-64 encoded - * strings. - */ - hexdigest: function (s) { - return binl2hex(core_md5(str2binl(s), s.length * chrsz)); - }, - - b64digest: function (s) { - return binl2b64(core_md5(str2binl(s), s.length * chrsz)); - }, - - hash: function (s) { - return binl2str(core_md5(str2binl(s), s.length * chrsz)); - }, - - hmac_hexdigest: function (key, data) { - return binl2hex(core_hmac_md5(key, data)); - }, - - hmac_b64digest: function (key, data) { - return binl2b64(core_hmac_md5(key, data)); - }, - - hmac_hash: function (key, data) { - return binl2str(core_hmac_md5(key, data)); - }, - - /* - * Perform a simple self-test to see if the VM is working - */ - test: function () { - return MD5.hexdigest("abc") === "900150983cd24fb0d6963f7d28e17f72"; - } - }; - - return obj; -})(); - -/* - This program is distributed under the terms of the MIT license. - Please see the LICENSE file for details. - - Copyright 2006-2008, OGG, LLC -*/ - -/* jslint configuration: */ -/*global document, window, setTimeout, clearTimeout, console, - XMLHttpRequest, ActiveXObject, - Base64, MD5, - Strophe, $build, $msg, $iq, $pres */ - -/** File: strophe.js - * A JavaScript library for XMPP BOSH. - * - * This is the JavaScript version of the Strophe library. Since JavaScript - * has no facilities for persistent TCP connections, this library uses - * Bidirectional-streams Over Synchronous HTTP (BOSH) to emulate - * a persistent, stateful, two-way connection to an XMPP server. More - * information on BOSH can be found in XEP 124. - */ - -/** PrivateFunction: Function.prototype.bind - * Bind a function to an instance. - * - * This Function object extension method creates a bound method similar - * to those in Python. This means that the 'this' object will point - * to the instance you want. See - * Bound Functions and Function Imports in JavaScript - * for a complete explanation. - * - * This extension already exists in some browsers (namely, Firefox 3), but - * we provide it to support those that don't. - * - * Parameters: - * (Object) obj - The object that will become 'this' in the bound function. - * - * Returns: - * The bound function. - */ -if (!Function.prototype.bind) { - Function.prototype.bind = function (obj) - { - var func = this; - return function () { return func.apply(obj, arguments); }; - }; -} - -/** PrivateFunction: Function.prototype.prependArg - * Prepend an argument to a function. - * - * This Function object extension method returns a Function that will - * invoke the original function with an argument prepended. This is useful - * when some object has a callback that needs to get that same object as - * an argument. The following fragment illustrates a simple case of this - * > var obj = new Foo(this.someMethod); - * - * Foo's constructor can now use func.prependArg(this) to ensure the - * passed in callback function gets the instance of Foo as an argument. - * Doing this without prependArg would mean not setting the callback - * from the constructor. - * - * This is used inside Strophe for passing the Strophe.Request object to - * the onreadystatechange handler of XMLHttpRequests. - * - * Parameters: - * arg - The argument to pass as the first parameter to the function. - * - * Returns: - * A new Function which calls the original with the prepended argument. - */ -if (!Function.prototype.prependArg) { - Function.prototype.prependArg = function (arg) - { - var func = this; - - return function () { - var newargs = [arg]; - for (var i = 0; i < arguments.length; i++) { - newargs.push(arguments[i]); - } - return func.apply(this, newargs); - }; - }; -} - -/** PrivateFunction: Array.prototype.indexOf - * Return the index of an object in an array. - * - * This function is not supplied by some JavaScript implementations, so - * we provide it if it is missing. This code is from: - * http://developer.mozilla.org/En/Core_JavaScript_1.5_Reference:Objects:Array:indexOf - * - * Parameters: - * (Object) elt - The object to look for. - * (Integer) from - The index from which to start looking. (optional). - * - * Returns: - * The index of elt in the array or -1 if not found. - */ -if (!Array.prototype.indexOf) -{ - Array.prototype.indexOf = function(elt /*, from*/) - { - var len = this.length; - - var from = Number(arguments[1]) || 0; - from = (from < 0) ? Math.ceil(from) : Math.floor(from); - if (from < 0) { - from += len; - } - - for (; from < len; from++) { - if (from in this && this[from] === elt) { - return from; - } - } - - return -1; - }; -} - -/* All of the Strophe globals are defined in this special function below so - * that references to the globals become closures. This will ensure that - * on page reload, these references will still be available to callbacks - * that are still executing. - */ - -(function (callback) { -var Strophe; - -/** Function: $build - * Create a Strophe.Builder. - * This is an alias for 'new Strophe.Builder(name, attrs)'. - * - * Parameters: - * (String) name - The root element name. - * (Object) attrs - The attributes for the root element in object notation. - * - * Returns: - * A new Strophe.Builder object. - */ -function $build(name, attrs) { return new Strophe.Builder(name, attrs); } -/** Function: $msg - * Create a Strophe.Builder with a element as the root. - * - * Parmaeters: - * (Object) attrs - The element attributes in object notation. - * - * Returns: - * A new Strophe.Builder object. - */ -function $msg(attrs) { return new Strophe.Builder("message", attrs); } -/** Function: $iq - * Create a Strophe.Builder with an element as the root. - * - * Parameters: - * (Object) attrs - The element attributes in object notation. - * - * Returns: - * A new Strophe.Builder object. - */ -function $iq(attrs) { return new Strophe.Builder("iq", attrs); } -/** Function: $pres - * Create a Strophe.Builder with a element as the root. - * - * Parameters: - * (Object) attrs - The element attributes in object notation. - * - * Returns: - * A new Strophe.Builder object. - */ -function $pres(attrs) { return new Strophe.Builder("presence", attrs); } - -/** Class: Strophe - * An object container for all Strophe library functions. - * - * This class is just a container for all the objects and constants - * used in the library. It is not meant to be instantiated, but to - * provide a namespace for library objects, constants, and functions. - */ -Strophe = { - /** Constant: VERSION - * The version of the Strophe library. Unreleased builds will have - * a version of head-HASH where HASH is a partial revision. - */ - VERSION: "1.0.1", - - /** Constants: XMPP Namespace Constants - * Common namespace constants from the XMPP RFCs and XEPs. - * - * NS.HTTPBIND - HTTP BIND namespace from XEP 124. - * NS.BOSH - BOSH namespace from XEP 206. - * NS.CLIENT - Main XMPP client namespace. - * NS.AUTH - Legacy authentication namespace. - * NS.ROSTER - Roster operations namespace. - * NS.PROFILE - Profile namespace. - * NS.DISCO_INFO - Service discovery info namespace from XEP 30. - * NS.DISCO_ITEMS - Service discovery items namespace from XEP 30. - * NS.MUC - Multi-User Chat namespace from XEP 45. - * NS.SASL - XMPP SASL namespace from RFC 3920. - * NS.STREAM - XMPP Streams namespace from RFC 3920. - * NS.BIND - XMPP Binding namespace from RFC 3920. - * NS.SESSION - XMPP Session namespace from RFC 3920. - */ - NS: { - HTTPBIND: "http://jabber.org/protocol/httpbind", - BOSH: "urn:xmpp:xbosh", - CLIENT: "jabber:client", - AUTH: "jabber:iq:auth", - ROSTER: "jabber:iq:roster", - PROFILE: "jabber:iq:profile", - DISCO_INFO: "http://jabber.org/protocol/disco#info", - DISCO_ITEMS: "http://jabber.org/protocol/disco#items", - MUC: "http://jabber.org/protocol/muc", - SASL: "urn:ietf:params:xml:ns:xmpp-sasl", - STREAM: "http://etherx.jabber.org/streams", - BIND: "urn:ietf:params:xml:ns:xmpp-bind", - SESSION: "urn:ietf:params:xml:ns:xmpp-session", - VERSION: "jabber:iq:version", - STANZAS: "urn:ietf:params:xml:ns:xmpp-stanzas" - }, - - /** Function: addNamespace - * This function is used to extend the current namespaces in - * Strophe.NS. It takes a key and a value with the key being the - * name of the new namespace, with its actual value. - * For example: - * Strophe.addNamespace('PUBSUB', "http://jabber.org/protocol/pubsub"); - * - * Parameters: - * (String) name - The name under which the namespace will be - * referenced under Strophe.NS - * (String) value - The actual namespace. - */ - addNamespace: function (name, value) - { - Strophe.NS[name] = value; - }, - - /** Constants: Connection Status Constants - * Connection status constants for use by the connection handler - * callback. - * - * Status.ERROR - An error has occurred - * Status.CONNECTING - The connection is currently being made - * Status.CONNFAIL - The connection attempt failed - * Status.AUTHENTICATING - The connection is authenticating - * Status.AUTHFAIL - The authentication attempt failed - * Status.CONNECTED - The connection has succeeded - * Status.DISCONNECTED - The connection has been terminated - * Status.DISCONNECTING - The connection is currently being terminated - * Status.ATTACHED - The connection has been attached - */ - Status: { - ERROR: 0, - CONNECTING: 1, - CONNFAIL: 2, - AUTHENTICATING: 3, - AUTHFAIL: 4, - CONNECTED: 5, - DISCONNECTED: 6, - DISCONNECTING: 7, - ATTACHED: 8 - }, - - /** Constants: Log Level Constants - * Logging level indicators. - * - * LogLevel.DEBUG - Debug output - * LogLevel.INFO - Informational output - * LogLevel.WARN - Warnings - * LogLevel.ERROR - Errors - * LogLevel.FATAL - Fatal errors - */ - LogLevel: { - DEBUG: 0, - INFO: 1, - WARN: 2, - ERROR: 3, - FATAL: 4 - }, - - /** PrivateConstants: DOM Element Type Constants - * DOM element types. - * - * ElementType.NORMAL - Normal element. - * ElementType.TEXT - Text data element. - */ - ElementType: { - NORMAL: 1, - TEXT: 3 - }, - - /** PrivateConstants: Timeout Values - * Timeout values for error states. These values are in seconds. - * These should not be changed unless you know exactly what you are - * doing. - * - * TIMEOUT - Timeout multiplier. A waiting request will be considered - * failed after Math.floor(TIMEOUT * wait) seconds have elapsed. - * This defaults to 1.1, and with default wait, 66 seconds. - * SECONDARY_TIMEOUT - Secondary timeout multiplier. In cases where - * Strophe can detect early failure, it will consider the request - * failed if it doesn't return after - * Math.floor(SECONDARY_TIMEOUT * wait) seconds have elapsed. - * This defaults to 0.1, and with default wait, 6 seconds. - */ - TIMEOUT: 1.1, - SECONDARY_TIMEOUT: 0.1, - - /** Function: forEachChild - * Map a function over some or all child elements of a given element. - * - * This is a small convenience function for mapping a function over - * some or all of the children of an element. If elemName is null, all - * children will be passed to the function, otherwise only children - * whose tag names match elemName will be passed. - * - * Parameters: - * (XMLElement) elem - The element to operate on. - * (String) elemName - The child element tag name filter. - * (Function) func - The function to apply to each child. This - * function should take a single argument, a DOM element. - */ - forEachChild: function (elem, elemName, func) - { - var i, childNode; - - for (i = 0; i < elem.childNodes.length; i++) { - childNode = elem.childNodes[i]; - if (childNode.nodeType == Strophe.ElementType.NORMAL && - (!elemName || this.isTagEqual(childNode, elemName))) { - func(childNode); - } - } - }, - - /** Function: isTagEqual - * Compare an element's tag name with a string. - * - * This function is case insensitive. - * - * Parameters: - * (XMLElement) el - A DOM element. - * (String) name - The element name. - * - * Returns: - * true if the element's tag name matches _el_, and false - * otherwise. - */ - isTagEqual: function (el, name) - { - return el.tagName.toLowerCase() == name.toLowerCase(); - }, - - /** PrivateVariable: _xmlGenerator - * _Private_ variable that caches a DOM document to - * generate elements. - */ - _xmlGenerator: null, - - /** PrivateFunction: _makeGenerator - * _Private_ function that creates a dummy XML DOM document to serve as - * an element and text node generator. - */ - _makeGenerator: function () { - var doc; - - if (window.ActiveXObject) { - doc = new ActiveXObject("Microsoft.XMLDOM"); - doc.appendChild(doc.createElement('strophe')); - } else { - doc = document.implementation - .createDocument('jabber:client', 'strophe', null); - } - - return doc; - }, - - /** Function: xmlElement - * Create an XML DOM element. - * - * This function creates an XML DOM element correctly across all - * implementations. Specifically the Microsoft implementation of - * document.createElement makes DOM elements with 43+ default attributes - * unless elements are created with the ActiveX object Microsoft.XMLDOM. - * - * Most DOMs force element names to lowercase, so we use the - * _realname attribute on the created element to store the case - * sensitive name. This is required to generate proper XML for - * things like vCard avatars (XEP 153). This attribute is stripped - * out before being sent over the wire or serialized, but you may - * notice it during debugging. - * - * Parameters: - * (String) name - The name for the element. - * (Array) attrs - An optional array of key/value pairs to use as - * element attributes in the following format [['key1', 'value1'], - * ['key2', 'value2']] - * (String) text - The text child data for the element. - * - * Returns: - * A new XML DOM element. - */ - xmlElement: function (name) - { - if (!name) { return null; } - - var node = null; - if (!Strophe._xmlGenerator) { - Strophe._xmlGenerator = Strophe._makeGenerator(); - } - node = Strophe._xmlGenerator.createElement(name); - - // FIXME: this should throw errors if args are the wrong type or - // there are more than two optional args - var a, i, k; - for (a = 1; a < arguments.length; a++) { - if (!arguments[a]) { continue; } - if (typeof(arguments[a]) == "string" || - typeof(arguments[a]) == "number") { - node.appendChild(Strophe.xmlTextNode(arguments[a])); - } else if (typeof(arguments[a]) == "object" && - typeof(arguments[a].sort) == "function") { - for (i = 0; i < arguments[a].length; i++) { - if (typeof(arguments[a][i]) == "object" && - typeof(arguments[a][i].sort) == "function") { - node.setAttribute(arguments[a][i][0], - arguments[a][i][1]); - } - } - } else if (typeof(arguments[a]) == "object") { - for (k in arguments[a]) { - if (arguments[a].hasOwnProperty(k)) { - node.setAttribute(k, arguments[a][k]); - } - } - } - } - - return node; - }, - - /* Function: xmlescape - * Excapes invalid xml characters. - * - * Parameters: - * (String) text - text to escape. - * - * Returns: - * Escaped text. - */ - xmlescape: function(text) - { - text = text.replace(/\&/g, "&"); - text = text.replace(//g, ">"); - return text; - }, - - /** Function: xmlTextNode - * Creates an XML DOM text node. - * - * Provides a cross implementation version of document.createTextNode. - * - * Parameters: - * (String) text - The content of the text node. - * - * Returns: - * A new XML DOM text node. - */ - xmlTextNode: function (text) - { - //ensure text is escaped - text = Strophe.xmlescape(text); - - if (!Strophe._xmlGenerator) { - Strophe._xmlGenerator = Strophe._makeGenerator(); - } - return Strophe._xmlGenerator.createTextNode(text); - }, - - /** Function: getText - * Get the concatenation of all text children of an element. - * - * Parameters: - * (XMLElement) elem - A DOM element. - * - * Returns: - * A String with the concatenated text of all text element children. - */ - getText: function (elem) - { - if (!elem) { return null; } - - var str = ""; - if (elem.childNodes.length === 0 && elem.nodeType == - Strophe.ElementType.TEXT) { - str += elem.nodeValue; - } - - for (var i = 0; i < elem.childNodes.length; i++) { - if (elem.childNodes[i].nodeType == Strophe.ElementType.TEXT) { - str += elem.childNodes[i].nodeValue; - } - } - - return str; - }, - - /** Function: copyElement - * Copy an XML DOM element. - * - * This function copies a DOM element and all its descendants and returns - * the new copy. - * - * Parameters: - * (XMLElement) elem - A DOM element. - * - * Returns: - * A new, copied DOM element tree. - */ - copyElement: function (elem) - { - var i, el; - if (elem.nodeType == Strophe.ElementType.NORMAL) { - el = Strophe.xmlElement(elem.tagName); - - for (i = 0; i < elem.attributes.length; i++) { - el.setAttribute(elem.attributes[i].nodeName.toLowerCase(), - elem.attributes[i].value); - } - - for (i = 0; i < elem.childNodes.length; i++) { - el.appendChild(Strophe.copyElement(elem.childNodes[i])); - } - } else if (elem.nodeType == Strophe.ElementType.TEXT) { - el = Strophe.xmlTextNode(elem.nodeValue); - } - - return el; - }, - - /** Function: escapeNode - * Escape the node part (also called local part) of a JID. - * - * Parameters: - * (String) node - A node (or local part). - * - * Returns: - * An escaped node (or local part). - */ - escapeNode: function (node) - { - return node.replace(/^\s+|\s+$/g, '') - .replace(/\\/g, "\\5c") - .replace(/ /g, "\\20") - .replace(/\"/g, "\\22") - .replace(/\&/g, "\\26") - .replace(/\'/g, "\\27") - .replace(/\//g, "\\2f") - .replace(/:/g, "\\3a") - .replace(//g, "\\3e") - .replace(/@/g, "\\40"); - }, - - /** Function: unescapeNode - * Unescape a node part (also called local part) of a JID. - * - * Parameters: - * (String) node - A node (or local part). - * - * Returns: - * An unescaped node (or local part). - */ - unescapeNode: function (node) - { - return node.replace(/\\20/g, " ") - .replace(/\\22/g, '"') - .replace(/\\26/g, "&") - .replace(/\\27/g, "'") - .replace(/\\2f/g, "/") - .replace(/\\3a/g, ":") - .replace(/\\3c/g, "<") - .replace(/\\3e/g, ">") - .replace(/\\40/g, "@") - .replace(/\\5c/g, "\\"); - }, - - /** Function: getNodeFromJid - * Get the node portion of a JID String. - * - * Parameters: - * (String) jid - A JID. - * - * Returns: - * A String containing the node. - */ - getNodeFromJid: function (jid) - { - if (jid.indexOf("@") < 0) { return null; } - return jid.split("@")[0]; - }, - - /** Function: getDomainFromJid - * Get the domain portion of a JID String. - * - * Parameters: - * (String) jid - A JID. - * - * Returns: - * A String containing the domain. - */ - getDomainFromJid: function (jid) - { - var bare = Strophe.getBareJidFromJid(jid); - if (bare.indexOf("@") < 0) { - return bare; - } else { - var parts = bare.split("@"); - parts.splice(0, 1); - return parts.join('@'); - } - }, - - /** Function: getResourceFromJid - * Get the resource portion of a JID String. - * - * Parameters: - * (String) jid - A JID. - * - * Returns: - * A String containing the resource. - */ - getResourceFromJid: function (jid) - { - var s = jid.split("/"); - if (s.length < 2) { return null; } - s.splice(0, 1); - return s.join('/'); - }, - - /** Function: getBareJidFromJid - * Get the bare JID from a JID String. - * - * Parameters: - * (String) jid - A JID. - * - * Returns: - * A String containing the bare JID. - */ - getBareJidFromJid: function (jid) - { - return jid.split("/")[0]; - }, - - /** Function: log - * User overrideable logging function. - * - * This function is called whenever the Strophe library calls any - * of the logging functions. The default implementation of this - * function does nothing. If client code wishes to handle the logging - * messages, it should override this with - * > Strophe.log = function (level, msg) { - * > (user code here) - * > }; - * - * Please note that data sent and received over the wire is logged - * via Strophe.Connection.rawInput() and Strophe.Connection.rawOutput(). - * - * The different levels and their meanings are - * - * DEBUG - Messages useful for debugging purposes. - * INFO - Informational messages. This is mostly information like - * 'disconnect was called' or 'SASL auth succeeded'. - * WARN - Warnings about potential problems. This is mostly used - * to report transient connection errors like request timeouts. - * ERROR - Some error occurred. - * FATAL - A non-recoverable fatal error occurred. - * - * Parameters: - * (Integer) level - The log level of the log message. This will - * be one of the values in Strophe.LogLevel. - * (String) msg - The log message. - */ - log: function (level, msg) - { - return; - }, - - /** Function: debug - * Log a message at the Strophe.LogLevel.DEBUG level. - * - * Parameters: - * (String) msg - The log message. - */ - debug: function(msg) - { - this.log(this.LogLevel.DEBUG, msg); - }, - - /** Function: info - * Log a message at the Strophe.LogLevel.INFO level. - * - * Parameters: - * (String) msg - The log message. - */ - info: function (msg) - { - this.log(this.LogLevel.INFO, msg); - }, - - /** Function: warn - * Log a message at the Strophe.LogLevel.WARN level. - * - * Parameters: - * (String) msg - The log message. - */ - warn: function (msg) - { - this.log(this.LogLevel.WARN, msg); - }, - - /** Function: error - * Log a message at the Strophe.LogLevel.ERROR level. - * - * Parameters: - * (String) msg - The log message. - */ - error: function (msg) - { - this.log(this.LogLevel.ERROR, msg); - }, - - /** Function: fatal - * Log a message at the Strophe.LogLevel.FATAL level. - * - * Parameters: - * (String) msg - The log message. - */ - fatal: function (msg) - { - this.log(this.LogLevel.FATAL, msg); - }, - - /** Function: serialize - * Render a DOM element and all descendants to a String. - * - * Parameters: - * (XMLElement) elem - A DOM element. - * - * Returns: - * The serialized element tree as a String. - */ - serialize: function (elem) - { - var result; - - if (!elem) { return null; } - - if (typeof(elem.tree) === "function") { - elem = elem.tree(); - } - - var nodeName = elem.nodeName; - var i, child; - - if (elem.getAttribute("_realname")) { - nodeName = elem.getAttribute("_realname"); - } - - result = "<" + nodeName; - for (i = 0; i < elem.attributes.length; i++) { - if(elem.attributes[i].nodeName != "_realname") { - result += " " + elem.attributes[i].nodeName.toLowerCase() + - "='" + elem.attributes[i].value - .replace("&", "&") - .replace("'", "'") - .replace("<", "<") + "'"; - } - } - - if (elem.childNodes.length > 0) { - result += ">"; - for (i = 0; i < elem.childNodes.length; i++) { - child = elem.childNodes[i]; - if (child.nodeType == Strophe.ElementType.NORMAL) { - // normal element, so recurse - result += Strophe.serialize(child); - } else if (child.nodeType == Strophe.ElementType.TEXT) { - // text element - result += child.nodeValue; - } - } - result += ""; - } else { - result += "/>"; - } - - return result; - }, - - /** PrivateVariable: _requestId - * _Private_ variable that keeps track of the request ids for - * connections. - */ - _requestId: 0, - - /** PrivateVariable: Strophe.connectionPlugins - * _Private_ variable Used to store plugin names that need - * initialization on Strophe.Connection construction. - */ - _connectionPlugins: {}, - - /** Function: addConnectionPlugin - * Extends the Strophe.Connection object with the given plugin. - * - * Paramaters: - * (String) name - The name of the extension. - * (Object) ptype - The plugin's prototype. - */ - addConnectionPlugin: function (name, ptype) - { - Strophe._connectionPlugins[name] = ptype; - } -}; - -/** Class: Strophe.Builder - * XML DOM builder. - * - * This object provides an interface similar to JQuery but for building - * DOM element easily and rapidly. All the functions except for toString() - * and tree() return the object, so calls can be chained. Here's an - * example using the $iq() builder helper. - * > $iq({to: 'you': from: 'me': type: 'get', id: '1'}) - * > .c('query', {xmlns: 'strophe:example'}) - * > .c('example') - * > .toString() - * The above generates this XML fragment - * > - * > - * > - * > - * > - * The corresponding DOM manipulations to get a similar fragment would be - * a lot more tedious and probably involve several helper variables. - * - * Since adding children makes new operations operate on the child, up() - * is provided to traverse up the tree. To add two children, do - * > builder.c('child1', ...).up().c('child2', ...) - * The next operation on the Builder will be relative to the second child. - */ - -/** Constructor: Strophe.Builder - * Create a Strophe.Builder object. - * - * The attributes should be passed in object notation. For example - * > var b = new Builder('message', {to: 'you', from: 'me'}); - * or - * > var b = new Builder('messsage', {'xml:lang': 'en'}); - * - * Parameters: - * (String) name - The name of the root element. - * (Object) attrs - The attributes for the root element in object notation. - * - * Returns: - * A new Strophe.Builder. - */ -Strophe.Builder = function (name, attrs) -{ - // Set correct namespace for jabber:client elements - if (name == "presence" || name == "message" || name == "iq") { - if (attrs && !attrs.xmlns) { - attrs.xmlns = Strophe.NS.CLIENT; - } else if (!attrs) { - attrs = {xmlns: Strophe.NS.CLIENT}; - } - } - - // Holds the tree being built. - this.nodeTree = Strophe.xmlElement(name, attrs); - - // Points to the current operation node. - this.node = this.nodeTree; -}; - -Strophe.Builder.prototype = { - /** Function: tree - * Return the DOM tree. - * - * This function returns the current DOM tree as an element object. This - * is suitable for passing to functions like Strophe.Connection.send(). - * - * Returns: - * The DOM tree as a element object. - */ - tree: function () - { - return this.nodeTree; - }, - - /** Function: toString - * Serialize the DOM tree to a String. - * - * This function returns a string serialization of the current DOM - * tree. It is often used internally to pass data to a - * Strophe.Request object. - * - * Returns: - * The serialized DOM tree in a String. - */ - toString: function () - { - return Strophe.serialize(this.nodeTree); - }, - - /** Function: up - * Make the current parent element the new current element. - * - * This function is often used after c() to traverse back up the tree. - * For example, to add two children to the same element - * > builder.c('child1', {}).up().c('child2', {}); - * - * Returns: - * The Stophe.Builder object. - */ - up: function () - { - this.node = this.node.parentNode; - return this; - }, - - /** Function: attrs - * Add or modify attributes of the current element. - * - * The attributes should be passed in object notation. This function - * does not move the current element pointer. - * - * Parameters: - * (Object) moreattrs - The attributes to add/modify in object notation. - * - * Returns: - * The Strophe.Builder object. - */ - attrs: function (moreattrs) - { - for (var k in moreattrs) { - if (moreattrs.hasOwnProperty(k)) { - this.node.setAttribute(k, moreattrs[k]); - } - } - return this; - }, - - /** Function: c - * Add a child to the current element and make it the new current - * element. - * - * This function moves the current element pointer to the child. If you - * need to add another child, it is necessary to use up() to go back - * to the parent in the tree. - * - * Parameters: - * (String) name - The name of the child. - * (Object) attrs - The attributes of the child in object notation. - * - * Returns: - * The Strophe.Builder object. - */ - c: function (name, attrs) - { - var child = Strophe.xmlElement(name, attrs); - this.node.appendChild(child); - this.node = child; - return this; - }, - - /** Function: cnode - * Add a child to the current element and make it the new current - * element. - * - * This function is the same as c() except that instead of using a - * name and an attributes object to create the child it uses an - * existing DOM element object. - * - * Parameters: - * (XMLElement) elem - A DOM element. - * - * Returns: - * The Strophe.Builder object. - */ - cnode: function (elem) - { - this.node.appendChild(elem); - this.node = elem; - return this; - }, - - /** Function: t - * Add a child text element. - * - * This *does not* make the child the new current element since there - * are no children of text elements. - * - * Parameters: - * (String) text - The text data to append to the current element. - * - * Returns: - * The Strophe.Builder object. - */ - t: function (text) - { - var child = Strophe.xmlTextNode(text); - this.node.appendChild(child); - return this; - } -}; - - -/** PrivateClass: Strophe.Handler - * _Private_ helper class for managing stanza handlers. - * - * A Strophe.Handler encapsulates a user provided callback function to be - * executed when matching stanzas are received by the connection. - * Handlers can be either one-off or persistant depending on their - * return value. Returning true will cause a Handler to remain active, and - * returning false will remove the Handler. - * - * Users will not use Strophe.Handler objects directly, but instead they - * will use Strophe.Connection.addHandler() and - * Strophe.Connection.deleteHandler(). - */ - -/** PrivateConstructor: Strophe.Handler - * Create and initialize a new Strophe.Handler. - * - * Parameters: - * (Function) handler - A function to be executed when the handler is run. - * (String) ns - The namespace to match. - * (String) name - The element name to match. - * (String) type - The element type to match. - * (String) id - The element id attribute to match. - * (String) from - The element from attribute to match. - * (Object) options - Handler options - * - * Returns: - * A new Strophe.Handler object. - */ -Strophe.Handler = function (handler, ns, name, type, id, from, options) -{ - this.handler = handler; - this.ns = ns; - this.name = name; - this.type = type; - this.id = id; - this.options = options || {matchbare: false}; - - // default matchBare to false if undefined - if (!this.options.matchBare) { - this.options.matchBare = false; - } - - if (this.options.matchBare) { - this.from = Strophe.getBareJidFromJid(from); - } else { - this.from = from; - } - - // whether the handler is a user handler or a system handler - this.user = true; -}; - -Strophe.Handler.prototype = { - /** PrivateFunction: isMatch - * Tests if a stanza matches the Strophe.Handler. - * - * Parameters: - * (XMLElement) elem - The XML element to test. - * - * Returns: - * true if the stanza matches and false otherwise. - */ - isMatch: function (elem) - { - var nsMatch; - var from = null; - - if (this.options.matchBare) { - from = Strophe.getBareJidFromJid(elem.getAttribute('from')); - } else { - from = elem.getAttribute('from'); - } - - nsMatch = false; - if (!this.ns) { - nsMatch = true; - } else { - var self = this; - Strophe.forEachChild(elem, null, function (elem) { - if (elem.getAttribute("xmlns") == self.ns) { - nsMatch = true; - } - }); - - nsMatch = nsMatch || elem.getAttribute("xmlns") == this.ns; - } - - if (nsMatch && - (!this.name || Strophe.isTagEqual(elem, this.name)) && - (!this.type || elem.getAttribute("type") === this.type) && - (!this.id || elem.getAttribute("id") === this.id) && - (!this.from || from === this.from)) { - return true; - } - - return false; - }, - - /** PrivateFunction: run - * Run the callback on a matching stanza. - * - * Parameters: - * (XMLElement) elem - The DOM element that triggered the - * Strophe.Handler. - * - * Returns: - * A boolean indicating if the handler should remain active. - */ - run: function (elem) - { - var result = null; - try { - result = this.handler(elem); - } catch (e) { - if (e.sourceURL) { - Strophe.fatal("error: " + this.handler + - " " + e.sourceURL + ":" + - e.line + " - " + e.name + ": " + e.message); - } else if (e.fileName) { - if (typeof(console) != "undefined") { - console.trace(); - console.error(this.handler, " - error - ", e, e.message); - } - Strophe.fatal("error: " + this.handler + " " + - e.fileName + ":" + e.lineNumber + " - " + - e.name + ": " + e.message); - } else { - Strophe.fatal("error: " + this.handler); - } - - throw e; - } - - return result; - }, - - /** PrivateFunction: toString - * Get a String representation of the Strophe.Handler object. - * - * Returns: - * A String. - */ - toString: function () - { - return "{Handler: " + this.handler + "(" + this.name + "," + - this.id + "," + this.ns + ")}"; - } -}; - -/** PrivateClass: Strophe.TimedHandler - * _Private_ helper class for managing timed handlers. - * - * A Strophe.TimedHandler encapsulates a user provided callback that - * should be called after a certain period of time or at regular - * intervals. The return value of the callback determines whether the - * Strophe.TimedHandler will continue to fire. - * - * Users will not use Strophe.TimedHandler objects directly, but instead - * they will use Strophe.Connection.addTimedHandler() and - * Strophe.Connection.deleteTimedHandler(). - */ - -/** PrivateConstructor: Strophe.TimedHandler - * Create and initialize a new Strophe.TimedHandler object. - * - * Parameters: - * (Integer) period - The number of milliseconds to wait before the - * handler is called. - * (Function) handler - The callback to run when the handler fires. This - * function should take no arguments. - * - * Returns: - * A new Strophe.TimedHandler object. - */ -Strophe.TimedHandler = function (period, handler) -{ - this.period = period; - this.handler = handler; - - this.lastCalled = new Date().getTime(); - this.user = true; -}; - -Strophe.TimedHandler.prototype = { - /** PrivateFunction: run - * Run the callback for the Strophe.TimedHandler. - * - * Returns: - * true if the Strophe.TimedHandler should be called again, and false - * otherwise. - */ - run: function () - { - this.lastCalled = new Date().getTime(); - return this.handler(); - }, - - /** PrivateFunction: reset - * Reset the last called time for the Strophe.TimedHandler. - */ - reset: function () - { - this.lastCalled = new Date().getTime(); - }, - - /** PrivateFunction: toString - * Get a string representation of the Strophe.TimedHandler object. - * - * Returns: - * The string representation. - */ - toString: function () - { - return "{TimedHandler: " + this.handler + "(" + this.period +")}"; - } -}; - -/** PrivateClass: Strophe.Request - * _Private_ helper class that provides a cross implementation abstraction - * for a BOSH related XMLHttpRequest. - * - * The Strophe.Request class is used internally to encapsulate BOSH request - * information. It is not meant to be used from user's code. - */ - -/** PrivateConstructor: Strophe.Request - * Create and initialize a new Strophe.Request object. - * - * Parameters: - * (XMLElement) elem - The XML data to be sent in the request. - * (Function) func - The function that will be called when the - * XMLHttpRequest readyState changes. - * (Integer) rid - The BOSH rid attribute associated with this request. - * (Integer) sends - The number of times this same request has been - * sent. - */ -Strophe.Request = function (elem, func, rid, sends) -{ - this.id = ++Strophe._requestId; - this.xmlData = elem; - this.data = Strophe.serialize(elem); - // save original function in case we need to make a new request - // from this one. - this.origFunc = func; - this.func = func; - this.rid = rid; - this.date = NaN; - this.sends = sends || 0; - this.abort = false; - this.dead = null; - this.age = function () { - if (!this.date) { return 0; } - var now = new Date(); - return (now - this.date) / 1000; - }; - this.timeDead = function () { - if (!this.dead) { return 0; } - var now = new Date(); - return (now - this.dead) / 1000; - }; - this.xhr = this._newXHR(); -}; - -Strophe.Request.prototype = { - /** PrivateFunction: getResponse - * Get a response from the underlying XMLHttpRequest. - * - * This function attempts to get a response from the request and checks - * for errors. - * - * Throws: - * "parsererror" - A parser error occured. - * - * Returns: - * The DOM element tree of the response. - */ - getResponse: function () - { - var node = null; - if (this.xhr.responseXML && this.xhr.responseXML.documentElement) { - node = this.xhr.responseXML.documentElement; - if (node.tagName == "parsererror") { - Strophe.error("invalid response received"); - Strophe.error("responseText: " + this.xhr.responseText); - Strophe.error("responseXML: " + - Strophe.serialize(this.xhr.responseXML)); - throw "parsererror"; - } - } else if (this.xhr.responseText) { - Strophe.error("invalid response received"); - Strophe.error("responseText: " + this.xhr.responseText); - Strophe.error("responseXML: " + - Strophe.serialize(this.xhr.responseXML)); - } - - return node; - }, - - /** PrivateFunction: _newXHR - * _Private_ helper function to create XMLHttpRequests. - * - * This function creates XMLHttpRequests across all implementations. - * - * Returns: - * A new XMLHttpRequest. - */ - _newXHR: function () - { - var xhr = null; - if (window.XMLHttpRequest) { - xhr = new XMLHttpRequest(); - if (xhr.overrideMimeType) { - xhr.overrideMimeType("text/xml"); - } - } else if (window.ActiveXObject) { - xhr = new ActiveXObject("Microsoft.XMLHTTP"); - } - - xhr.onreadystatechange = this.func.prependArg(this); - - return xhr; - } -}; - -/** Class: Strophe.Connection - * XMPP Connection manager. - * - * Thie class is the main part of Strophe. It manages a BOSH connection - * to an XMPP server and dispatches events to the user callbacks as - * data arrives. It supports SASL PLAIN, SASL DIGEST-MD5, and legacy - * authentication. - * - * After creating a Strophe.Connection object, the user will typically - * call connect() with a user supplied callback to handle connection level - * events like authentication failure, disconnection, or connection - * complete. - * - * The user will also have several event handlers defined by using - * addHandler() and addTimedHandler(). These will allow the user code to - * respond to interesting stanzas or do something periodically with the - * connection. These handlers will be active once authentication is - * finished. - * - * To send data to the connection, use send(). - */ - -/** Constructor: Strophe.Connection - * Create and initialize a Strophe.Connection object. - * - * Parameters: - * (String) service - The BOSH service URL. - * - * Returns: - * A new Strophe.Connection object. - */ -Strophe.Connection = function (service) -{ - /* The path to the httpbind service. */ - this.service = service; - /* The connected JID. */ - this.jid = ""; - /* request id for body tags */ - this.rid = Math.floor(Math.random() * 4294967295); - /* The current session ID. */ - this.sid = null; - this.streamId = null; - - // SASL - this.do_session = false; - this.do_bind = false; - - // handler lists - this.timedHandlers = []; - this.handlers = []; - this.removeTimeds = []; - this.removeHandlers = []; - this.addTimeds = []; - this.addHandlers = []; - - this._idleTimeout = null; - this._disconnectTimeout = null; - - this.authenticated = false; - this.disconnecting = false; - this.connected = false; - - this.errors = 0; - - this.paused = false; - - // default BOSH values - this.hold = 1; - this.wait = 60; - this.window = 5; - - this._data = []; - this._requests = []; - this._uniqueId = Math.round(Math.random() * 10000); - - this._sasl_success_handler = null; - this._sasl_failure_handler = null; - this._sasl_challenge_handler = null; - - // setup onIdle callback every 1/10th of a second - this._idleTimeout = setTimeout(this._onIdle.bind(this), 100); - - // initialize plugins - for (var k in Strophe._connectionPlugins) { - if (Strophe._connectionPlugins.hasOwnProperty(k)) { - var ptype = Strophe._connectionPlugins[k]; - // jslint complaints about the below line, but this is fine - var F = function () {}; - F.prototype = ptype; - this[k] = new F(); - this[k].init(this); - } - } -}; - -Strophe.Connection.prototype = { - /** Function: reset - * Reset the connection. - * - * This function should be called after a connection is disconnected - * before that connection is reused. - */ - reset: function () - { - this.rid = Math.floor(Math.random() * 4294967295); - - this.sid = null; - this.streamId = null; - - // SASL - this.do_session = false; - this.do_bind = false; - - // handler lists - this.timedHandlers = []; - this.handlers = []; - this.removeTimeds = []; - this.removeHandlers = []; - this.addTimeds = []; - this.addHandlers = []; - - this.authenticated = false; - this.disconnecting = false; - this.connected = false; - - this.errors = 0; - - this._requests = []; - this._uniqueId = Math.round(Math.random()*10000); - }, - - /** Function: pause - * Pause the request manager. - * - * This will prevent Strophe from sending any more requests to the - * server. This is very useful for temporarily pausing while a lot - * of send() calls are happening quickly. This causes Strophe to - * send the data in a single request, saving many request trips. - */ - pause: function () - { - this.paused = true; - }, - - /** Function: resume - * Resume the request manager. - * - * This resumes after pause() has been called. - */ - resume: function () - { - this.paused = false; - }, - - /** Function: getUniqueId - * Generate a unique ID for use in elements. - * - * All stanzas are required to have unique id attributes. This - * function makes creating these easy. Each connection instance has - * a counter which starts from zero, and the value of this counter - * plus a colon followed by the suffix becomes the unique id. If no - * suffix is supplied, the counter is used as the unique id. - * - * Suffixes are used to make debugging easier when reading the stream - * data, and their use is recommended. The counter resets to 0 for - * every new connection for the same reason. For connections to the - * same server that authenticate the same way, all the ids should be - * the same, which makes it easy to see changes. This is useful for - * automated testing as well. - * - * Parameters: - * (String) suffix - A optional suffix to append to the id. - * - * Returns: - * A unique string to be used for the id attribute. - */ - getUniqueId: function (suffix) - { - if (typeof(suffix) == "string" || typeof(suffix) == "number") { - return ++this._uniqueId + ":" + suffix; - } else { - return ++this._uniqueId + ""; - } - }, - - /** Function: connect - * Starts the connection process. - * - * As the connection process proceeds, the user supplied callback will - * be triggered multiple times with status updates. The callback - * should take two arguments - the status code and the error condition. - * - * The status code will be one of the values in the Strophe.Status - * constants. The error condition will be one of the conditions - * defined in RFC 3920 or the condition 'strophe-parsererror'. - * - * Please see XEP 124 for a more detailed explanation of the optional - * parameters below. - * - * Parameters: - * (String) jid - The user's JID. This may be a bare JID, - * or a full JID. If a node is not supplied, SASL ANONYMOUS - * authentication will be attempted. - * (String) pass - The user's password. - * (Function) callback The connect callback function. - * (Integer) wait - The optional HTTPBIND wait value. This is the - * time the server will wait before returning an empty result for - * a request. The default setting of 60 seconds is recommended. - * Other settings will require tweaks to the Strophe.TIMEOUT value. - * (Integer) hold - The optional HTTPBIND hold value. This is the - * number of connections the server will hold at one time. This - * should almost always be set to 1 (the default). - */ - connect: function (jid, pass, callback, wait, hold) - { - this.jid = jid; - this.pass = pass; - this.connect_callback = callback; - this.disconnecting = false; - this.connected = false; - this.authenticated = false; - this.errors = 0; - - this.wait = wait || this.wait; - this.hold = hold || this.hold; - - // parse jid for domain and resource - this.domain = Strophe.getDomainFromJid(this.jid); - - // build the body tag - var body = this._buildBody().attrs({ - to: this.domain, - "xml:lang": "en", - wait: this.wait, - hold: this.hold, - content: "text/xml; charset=utf-8", - ver: "1.6", - "xmpp:version": "1.0", - "xmlns:xmpp": Strophe.NS.BOSH - }); - - this._changeConnectStatus(Strophe.Status.CONNECTING, null); - - this._requests.push( - new Strophe.Request(body.tree(), - this._onRequestStateChange.bind(this) - .prependArg(this._connect_cb.bind(this)), - body.tree().getAttribute("rid"))); - this._throttledRequestHandler(); - }, - - /** Function: attach - * Attach to an already created and authenticated BOSH session. - * - * This function is provided to allow Strophe to attach to BOSH - * sessions which have been created externally, perhaps by a Web - * application. This is often used to support auto-login type features - * without putting user credentials into the page. - * - * Parameters: - * (String) jid - The full JID that is bound by the session. - * (String) sid - The SID of the BOSH session. - * (String) rid - The current RID of the BOSH session. This RID - * will be used by the next request. - * (Function) callback The connect callback function. - * (Integer) wait - The optional HTTPBIND wait value. This is the - * time the server will wait before returning an empty result for - * a request. The default setting of 60 seconds is recommended. - * Other settings will require tweaks to the Strophe.TIMEOUT value. - * (Integer) hold - The optional HTTPBIND hold value. This is the - * number of connections the server will hold at one time. This - * should almost always be set to 1 (the default). - * (Integer) wind - The optional HTTBIND window value. This is the - * allowed range of request ids that are valid. The default is 5. - */ - attach: function (jid, sid, rid, callback, wait, hold, wind) - { - this.jid = jid; - this.sid = sid; - this.rid = rid; - this.connect_callback = callback; - - this.domain = Strophe.getDomainFromJid(this.jid); - - this.authenticated = true; - this.connected = true; - - this.wait = wait || this.wait; - this.hold = hold || this.hold; - this.window = wind || this.window; - - this._changeConnectStatus(Strophe.Status.ATTACHED, null); - }, - - /** Function: xmlInput - * User overrideable function that receives XML data coming into the - * connection. - * - * The default function does nothing. User code can override this with - * > Strophe.Connection.xmlInput = function (elem) { - * > (user code) - * > }; - * - * Parameters: - * (XMLElement) elem - The XML data received by the connection. - */ - xmlInput: function (elem) - { - return; - }, - - /** Function: xmlOutput - * User overrideable function that receives XML data sent to the - * connection. - * - * The default function does nothing. User code can override this with - * > Strophe.Connection.xmlOutput = function (elem) { - * > (user code) - * > }; - * - * Parameters: - * (XMLElement) elem - The XMLdata sent by the connection. - */ - xmlOutput: function (elem) - { - return; - }, - - /** Function: rawInput - * User overrideable function that receives raw data coming into the - * connection. - * - * The default function does nothing. User code can override this with - * > Strophe.Connection.rawInput = function (data) { - * > (user code) - * > }; - * - * Parameters: - * (String) data - The data received by the connection. - */ - rawInput: function (data) - { - return; - }, - - /** Function: rawOutput - * User overrideable function that receives raw data sent to the - * connection. - * - * The default function does nothing. User code can override this with - * > Strophe.Connection.rawOutput = function (data) { - * > (user code) - * > }; - * - * Parameters: - * (String) data - The data sent by the connection. - */ - rawOutput: function (data) - { - return; - }, - - /** Function: send - * Send a stanza. - * - * This function is called to push data onto the send queue to - * go out over the wire. Whenever a request is sent to the BOSH - * server, all pending data is sent and the queue is flushed. - * - * Parameters: - * (XMLElement | - * [XMLElement] | - * Strophe.Builder) elem - The stanza to send. - */ - send: function (elem) - { - if (elem === null) { return ; } - if (typeof(elem.sort) === "function") { - for (var i = 0; i < elem.length; i++) { - this._queueData(elem[i]); - } - } else if (typeof(elem.tree) === "function") { - this._queueData(elem.tree()); - } else { - this._queueData(elem); - } - - this._throttledRequestHandler(); - clearTimeout(this._idleTimeout); - this._idleTimeout = setTimeout(this._onIdle.bind(this), 100); - }, - - /** Function: flush - * Immediately send any pending outgoing data. - * - * Normally send() queues outgoing data until the next idle period - * (100ms), which optimizes network use in the common cases when - * several send()s are called in succession. flush() can be used to - * immediately send all pending data. - */ - flush: function () - { - // cancel the pending idle period and run the idle function - // immediately - clearTimeout(this._idleTimeout); - this._onIdle(); - }, - - /** Function: sendIQ - * Helper function to send IQ stanzas. - * - * Parameters: - * (XMLElement) elem - The stanza to send. - * (Function) callback - The callback function for a successful request. - * (Function) errback - The callback function for a failed or timed - * out request. On timeout, the stanza will be null. - * (Integer) timeout - The time specified in milliseconds for a - * timeout to occur. - * - * Returns: - * The id used to send the IQ. - */ - sendIQ: function(elem, callback, errback, timeout) { - var timeoutHandler = null; - var that = this; - - if (typeof(elem.tree) === "function") { - elem = elem.tree(); - } - var id = elem.getAttribute('id'); - - // inject id if not found - if (!id) { - id = this.getUniqueId("sendIQ"); - elem.setAttribute("id", id); - } - - var handler = this.addHandler(function (stanza) { - // remove timeout handler if there is one - if (timeoutHandler) { - that.deleteTimedHandler(timeoutHandler); - } - - var iqtype = stanza.getAttribute('type'); - if (iqtype === 'result') { - if (callback) { - callback(stanza); - } - } else if (iqtype === 'error') { - if (errback) { - errback(stanza); - } - } else { - throw { - name: "StropheError", - message: "Got bad IQ type of " + iqtype - }; - } - }, null, 'iq', null, id); - - // if timeout specified, setup timeout handler. - if (timeout) { - timeoutHandler = this.addTimedHandler(timeout, function () { - // get rid of normal handler - that.deleteHandler(handler); - - // call errback on timeout with null stanza - if (errback) { - errback(null); - } - return false; - }); - } - - this.send(elem); - - return id; - }, - - /** PrivateFunction: _queueData - * Queue outgoing data for later sending. Also ensures that the data - * is a DOMElement. - */ - _queueData: function (element) { - if (element === null || - !element.tagName || - !element.childNodes) { - throw { - name: "StropheError", - message: "Cannot queue non-DOMElement." - }; - } - - this._data.push(element); - }, - - /** PrivateFunction: _sendRestart - * Send an xmpp:restart stanza. - */ - _sendRestart: function () - { - this._data.push("restart"); - - this._throttledRequestHandler(); - clearTimeout(this._idleTimeout); - this._idleTimeout = setTimeout(this._onIdle.bind(this), 100); - }, - - /** Function: addTimedHandler - * Add a timed handler to the connection. - * - * This function adds a timed handler. The provided handler will - * be called every period milliseconds until it returns false, - * the connection is terminated, or the handler is removed. Handlers - * that wish to continue being invoked should return true. - * - * Because of method binding it is necessary to save the result of - * this function if you wish to remove a handler with - * deleteTimedHandler(). - * - * Note that user handlers are not active until authentication is - * successful. - * - * Parameters: - * (Integer) period - The period of the handler. - * (Function) handler - The callback function. - * - * Returns: - * A reference to the handler that can be used to remove it. - */ - addTimedHandler: function (period, handler) - { - var thand = new Strophe.TimedHandler(period, handler); - this.addTimeds.push(thand); - return thand; - }, - - /** Function: deleteTimedHandler - * Delete a timed handler for a connection. - * - * This function removes a timed handler from the connection. The - * handRef parameter is *not* the function passed to addTimedHandler(), - * but is the reference returned from addTimedHandler(). - * - * Parameters: - * (Strophe.TimedHandler) handRef - The handler reference. - */ - deleteTimedHandler: function (handRef) - { - // this must be done in the Idle loop so that we don't change - // the handlers during iteration - this.removeTimeds.push(handRef); - }, - - /** Function: addHandler - * Add a stanza handler for the connection. - * - * This function adds a stanza handler to the connection. The - * handler callback will be called for any stanza that matches - * the parameters. Note that if multiple parameters are supplied, - * they must all match for the handler to be invoked. - * - * The handler will receive the stanza that triggered it as its argument. - * The handler should return true if it is to be invoked again; - * returning false will remove the handler after it returns. - * - * As a convenience, the ns parameters applies to the top level element - * and also any of its immediate children. This is primarily to make - * matching /iq/query elements easy. - * - * The options argument contains handler matching flags that affect how - * matches are determined. Currently the only flag is matchBare (a - * boolean). When matchBare is true, the from parameter and the from - * attribute on the stanza will be matched as bare JIDs instead of - * full JIDs. To use this, pass {matchBare: true} as the value of - * options. The default value for matchBare is false. - * - * The return value should be saved if you wish to remove the handler - * with deleteHandler(). - * - * Parameters: - * (Function) handler - The user callback. - * (String) ns - The namespace to match. - * (String) name - The stanza name to match. - * (String) type - The stanza type attribute to match. - * (String) id - The stanza id attribute to match. - * (String) from - The stanza from attribute to match. - * (String) options - The handler options - * - * Returns: - * A reference to the handler that can be used to remove it. - */ - addHandler: function (handler, ns, name, type, id, from, options) - { - var hand = new Strophe.Handler(handler, ns, name, type, id, from, options); - this.addHandlers.push(hand); - return hand; - }, - - /** Function: deleteHandler - * Delete a stanza handler for a connection. - * - * This function removes a stanza handler from the connection. The - * handRef parameter is *not* the function passed to addHandler(), - * but is the reference returned from addHandler(). - * - * Parameters: - * (Strophe.Handler) handRef - The handler reference. - */ - deleteHandler: function (handRef) - { - // this must be done in the Idle loop so that we don't change - // the handlers during iteration - this.removeHandlers.push(handRef); - }, - - /** Function: disconnect - * Start the graceful disconnection process. - * - * This function starts the disconnection process. This process starts - * by sending unavailable presence and sending BOSH body of type - * terminate. A timeout handler makes sure that disconnection happens - * even if the BOSH server does not respond. - * - * The user supplied connection callback will be notified of the - * progress as this process happens. - * - * Parameters: - * (String) reason - The reason the disconnect is occuring. - */ - disconnect: function (reason) - { - this._changeConnectStatus(Strophe.Status.DISCONNECTING, reason); - - Strophe.info("Disconnect was called because: " + reason); - if (this.connected) { - // setup timeout handler - this._disconnectTimeout = this._addSysTimedHandler( - 3000, this._onDisconnectTimeout.bind(this)); - this._sendTerminate(); - } - }, - - /** PrivateFunction: _changeConnectStatus - * _Private_ helper function that makes sure plugins and the user's - * callback are notified of connection status changes. - * - * Parameters: - * (Integer) status - the new connection status, one of the values - * in Strophe.Status - * (String) condition - the error condition or null - */ - _changeConnectStatus: function (status, condition) - { - // notify all plugins listening for status changes - for (var k in Strophe._connectionPlugins) { - if (Strophe._connectionPlugins.hasOwnProperty(k)) { - var plugin = this[k]; - if (plugin.statusChanged) { - try { - plugin.statusChanged(status, condition); - } catch (err) { - Strophe.error("" + k + " plugin caused an exception " + - "changing status: " + err); - } - } - } - } - - // notify the user's callback - if (this.connect_callback) { - try { - this.connect_callback(status, condition); - } catch (e) { - Strophe.error("User connection callback caused an " + - "exception: " + e); - } - } - }, - - /** PrivateFunction: _buildBody - * _Private_ helper function to generate the wrapper for BOSH. - * - * Returns: - * A Strophe.Builder with a element. - */ - _buildBody: function () - { - var bodyWrap = $build('body', { - rid: this.rid++, - xmlns: Strophe.NS.HTTPBIND - }); - - if (this.sid !== null) { - bodyWrap.attrs({sid: this.sid}); - } - - return bodyWrap; - }, - - /** PrivateFunction: _removeRequest - * _Private_ function to remove a request from the queue. - * - * Parameters: - * (Strophe.Request) req - The request to remove. - */ - _removeRequest: function (req) - { - Strophe.debug("removing request"); - - var i; - for (i = this._requests.length - 1; i >= 0; i--) { - if (req == this._requests[i]) { - this._requests.splice(i, 1); - } - } - - // IE6 fails on setting to null, so set to empty function - req.xhr.onreadystatechange = function () {}; - - this._throttledRequestHandler(); - }, - - /** PrivateFunction: _restartRequest - * _Private_ function to restart a request that is presumed dead. - * - * Parameters: - * (Integer) i - The index of the request in the queue. - */ - _restartRequest: function (i) - { - var req = this._requests[i]; - if (req.dead === null) { - req.dead = new Date(); - } - - this._processRequest(i); - }, - - /** PrivateFunction: _processRequest - * _Private_ function to process a request in the queue. - * - * This function takes requests off the queue and sends them and - * restarts dead requests. - * - * Parameters: - * (Integer) i - The index of the request in the queue. - */ - _processRequest: function (i) - { - var req = this._requests[i]; - var reqStatus = -1; - - try { - if (req.xhr.readyState == 4) { - reqStatus = req.xhr.status; - } - } catch (e) { - Strophe.error("caught an error in _requests[" + i + - "], reqStatus: " + reqStatus); - } - - if (typeof(reqStatus) == "undefined") { - reqStatus = -1; - } - - var time_elapsed = req.age(); - var primaryTimeout = (!isNaN(time_elapsed) && - time_elapsed > Math.floor(Strophe.TIMEOUT * this.wait)); - var secondaryTimeout = (req.dead !== null && - req.timeDead() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait)); - var requestCompletedWithServerError = (req.xhr.readyState == 4 && - (reqStatus < 1 || - reqStatus >= 500)); - if (primaryTimeout || secondaryTimeout || - requestCompletedWithServerError) { - if (secondaryTimeout) { - Strophe.error("Request " + - this._requests[i].id + - " timed out (secondary), restarting"); - } - req.abort = true; - req.xhr.abort(); - // setting to null fails on IE6, so set to empty function - req.xhr.onreadystatechange = function () {}; - this._requests[i] = new Strophe.Request(req.xmlData, - req.origFunc, - req.rid, - req.sends); - req = this._requests[i]; - } - - if (req.xhr.readyState === 0) { - Strophe.debug("request id " + req.id + - "." + req.sends + " posting"); - - req.date = new Date(); - try { - req.xhr.open("POST", this.service, true); - } catch (e2) { - Strophe.error("XHR open failed."); - if (!this.connected) { - this._changeConnectStatus(Strophe.Status.CONNFAIL, - "bad-service"); - } - this.disconnect(); - return; - } - - // Fires the XHR request -- may be invoked immediately - // or on a gradually expanding retry window for reconnects - var sendFunc = function () { - req.xhr.send(req.data); - }; - - // Implement progressive backoff for reconnects -- - // First retry (send == 1) should also be instantaneous - if (req.sends > 1) { - // Using a cube of the retry number creats a nicely - // expanding retry window - var backoff = Math.pow(req.sends, 3) * 1000; - setTimeout(sendFunc, backoff); - } else { - sendFunc(); - } - - req.sends++; - - this.xmlOutput(req.xmlData); - this.rawOutput(req.data); - } else { - Strophe.debug("_processRequest: " + - (i === 0 ? "first" : "second") + - " request has readyState of " + - req.xhr.readyState); - } - }, - - /** PrivateFunction: _throttledRequestHandler - * _Private_ function to throttle requests to the connection window. - * - * This function makes sure we don't send requests so fast that the - * request ids overflow the connection window in the case that one - * request died. - */ - _throttledRequestHandler: function () - { - if (!this._requests) { - Strophe.debug("_throttledRequestHandler called with " + - "undefined requests"); - } else { - Strophe.debug("_throttledRequestHandler called with " + - this._requests.length + " requests"); - } - - if (!this._requests || this._requests.length === 0) { - return; - } - - if (this._requests.length > 0) { - this._processRequest(0); - } - - if (this._requests.length > 1 && - Math.abs(this._requests[0].rid - - this._requests[1].rid) < this.window - 1) { - this._processRequest(1); - } - }, - - /** PrivateFunction: _onRequestStateChange - * _Private_ handler for Strophe.Request state changes. - * - * This function is called when the XMLHttpRequest readyState changes. - * It contains a lot of error handling logic for the many ways that - * requests can fail, and calls the request callback when requests - * succeed. - * - * Parameters: - * (Function) func - The handler for the request. - * (Strophe.Request) req - The request that is changing readyState. - */ - _onRequestStateChange: function (func, req) - { - Strophe.debug("request id " + req.id + - "." + req.sends + " state changed to " + - req.xhr.readyState); - - if (req.abort) { - req.abort = false; - return; - } - - // request complete - var reqStatus; - if (req.xhr.readyState == 4) { - reqStatus = 0; - try { - reqStatus = req.xhr.status; - } catch (e) { - // ignore errors from undefined status attribute. works - // around a browser bug - } - - if (typeof(reqStatus) == "undefined") { - reqStatus = 0; - } - - if (this.disconnecting) { - if (reqStatus >= 400) { - this._hitError(reqStatus); - return; - } - } - - var reqIs0 = (this._requests[0] == req); - var reqIs1 = (this._requests[1] == req); - - if ((reqStatus > 0 && reqStatus < 500) || req.sends > 5) { - // remove from internal queue - this._removeRequest(req); - Strophe.debug("request id " + - req.id + - " should now be removed"); - } - - // request succeeded - if (reqStatus == 200) { - // if request 1 finished, or request 0 finished and request - // 1 is over Strophe.SECONDARY_TIMEOUT seconds old, we need to - // restart the other - both will be in the first spot, as the - // completed request has been removed from the queue already - if (reqIs1 || - (reqIs0 && this._requests.length > 0 && - this._requests[0].age() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait))) { - this._restartRequest(0); - } - // call handler - Strophe.debug("request id " + - req.id + "." + - req.sends + " got 200"); - func(req); - this.errors = 0; - } else { - Strophe.error("request id " + - req.id + "." + - req.sends + " error " + reqStatus + - " happened"); - if (reqStatus === 0 || - (reqStatus >= 400 && reqStatus < 600) || - reqStatus >= 12000) { - this._hitError(reqStatus); - if (reqStatus >= 400 && reqStatus < 500) { - this._changeConnectStatus(Strophe.Status.DISCONNECTING, - null); - this._doDisconnect(); - } - } - } - - if (!((reqStatus > 0 && reqStatus < 10000) || - req.sends > 5)) { - this._throttledRequestHandler(); - } - } - }, - - /** PrivateFunction: _hitError - * _Private_ function to handle the error count. - * - * Requests are resent automatically until their error count reaches - * 5. Each time an error is encountered, this function is called to - * increment the count and disconnect if the count is too high. - * - * Parameters: - * (Integer) reqStatus - The request status. - */ - _hitError: function (reqStatus) - { - this.errors++; - Strophe.warn("request errored, status: " + reqStatus + - ", number of errors: " + this.errors); - if (this.errors > 4) { - this._onDisconnectTimeout(); - } - }, - - /** PrivateFunction: _doDisconnect - * _Private_ function to disconnect. - * - * This is the last piece of the disconnection logic. This resets the - * connection and alerts the user's connection callback. - */ - _doDisconnect: function () - { - Strophe.info("_doDisconnect was called"); - this.authenticated = false; - this.disconnecting = false; - this.sid = null; - this.streamId = null; - this.rid = Math.floor(Math.random() * 4294967295); - - // tell the parent we disconnected - if (this.connected) { - this._changeConnectStatus(Strophe.Status.DISCONNECTED, null); - this.connected = false; - } - - // delete handlers - this.handlers = []; - this.timedHandlers = []; - this.removeTimeds = []; - this.removeHandlers = []; - this.addTimeds = []; - this.addHandlers = []; - }, - - /** PrivateFunction: _dataRecv - * _Private_ handler to processes incoming data from the the connection. - * - * Except for _connect_cb handling the initial connection request, - * this function handles the incoming data for all requests. This - * function also fires stanza handlers that match each incoming - * stanza. - * - * Parameters: - * (Strophe.Request) req - The request that has data ready. - */ - _dataRecv: function (req) - { - try { - var elem = req.getResponse(); - } catch (e) { - if (e != "parsererror") { throw e; } - this.disconnect("strophe-parsererror"); - } - if (elem === null) { return; } - - this.xmlInput(elem); - this.rawInput(Strophe.serialize(elem)); - - // remove handlers scheduled for deletion - var i, hand; - while (this.removeHandlers.length > 0) { - hand = this.removeHandlers.pop(); - i = this.handlers.indexOf(hand); - if (i >= 0) { - this.handlers.splice(i, 1); - } - } - - // add handlers scheduled for addition - while (this.addHandlers.length > 0) { - this.handlers.push(this.addHandlers.pop()); - } - - // handle graceful disconnect - if (this.disconnecting && this._requests.length === 0) { - this.deleteTimedHandler(this._disconnectTimeout); - this._disconnectTimeout = null; - this._doDisconnect(); - return; - } - - var typ = elem.getAttribute("type"); - var cond, conflict; - if (typ !== null && typ == "terminate") { - // an error occurred - cond = elem.getAttribute("condition"); - conflict = elem.getElementsByTagName("conflict"); - if (cond !== null) { - if (cond == "remote-stream-error" && conflict.length > 0) { - cond = "conflict"; - } - this._changeConnectStatus(Strophe.Status.CONNFAIL, cond); - } else { - this._changeConnectStatus(Strophe.Status.CONNFAIL, "unknown"); - } - this.disconnect(); - return; - } - - // send each incoming stanza through the handler chain - var self = this; - Strophe.forEachChild(elem, null, function (child) { - var i, newList; - // process handlers - newList = self.handlers; - self.handlers = []; - for (i = 0; i < newList.length; i++) { - var hand = newList[i]; - if (hand.isMatch(child) && - (self.authenticated || !hand.user)) { - if (hand.run(child)) { - self.handlers.push(hand); - } - } else { - self.handlers.push(hand); - } - } - }); - }, - - /** PrivateFunction: _sendTerminate - * _Private_ function to send initial disconnect sequence. - * - * This is the first step in a graceful disconnect. It sends - * the BOSH server a terminate body and includes an unavailable - * presence if authentication has completed. - */ - _sendTerminate: function () - { - Strophe.info("_sendTerminate was called"); - var body = this._buildBody().attrs({type: "terminate"}); - - if (this.authenticated) { - body.c('presence', { - xmlns: Strophe.NS.CLIENT, - type: 'unavailable' - }); - } - - this.disconnecting = true; - - var req = new Strophe.Request(body.tree(), - this._onRequestStateChange.bind(this) - .prependArg(this._dataRecv.bind(this)), - body.tree().getAttribute("rid")); - - this._requests.push(req); - this._throttledRequestHandler(); - }, - - /** PrivateFunction: _connect_cb - * _Private_ handler for initial connection request. - * - * This handler is used to process the initial connection request - * response from the BOSH server. It is used to set up authentication - * handlers and start the authentication process. - * - * SASL authentication will be attempted if available, otherwise - * the code will fall back to legacy authentication. - * - * Parameters: - * (Strophe.Request) req - The current request. - */ - _connect_cb: function (req) - { - Strophe.info("_connect_cb was called"); - - this.connected = true; - var bodyWrap = req.getResponse(); - if (!bodyWrap) { return; } - - this.xmlInput(bodyWrap); - this.rawInput(Strophe.serialize(bodyWrap)); - - var typ = bodyWrap.getAttribute("type"); - var cond, conflict; - if (typ !== null && typ == "terminate") { - // an error occurred - cond = bodyWrap.getAttribute("condition"); - conflict = bodyWrap.getElementsByTagName("conflict"); - if (cond !== null) { - if (cond == "remote-stream-error" && conflict.length > 0) { - cond = "conflict"; - } - this._changeConnectStatus(Strophe.Status.CONNFAIL, cond); - } else { - this._changeConnectStatus(Strophe.Status.CONNFAIL, "unknown"); - } - return; - } - - // check to make sure we don't overwrite these if _connect_cb is - // called multiple times in the case of missing stream:features - if (!this.sid) { - this.sid = bodyWrap.getAttribute("sid"); - } - if (!this.stream_id) { - this.stream_id = bodyWrap.getAttribute("authid"); - } - var wind = bodyWrap.getAttribute('requests'); - if (wind) { this.window = parseInt(wind, 10); } - var hold = bodyWrap.getAttribute('hold'); - if (hold) { this.hold = parseInt(hold, 10); } - var wait = bodyWrap.getAttribute('wait'); - if (wait) { this.wait = parseInt(wait, 10); } - - - var do_sasl_plain = false; - var do_sasl_digest_md5 = false; - var do_sasl_anonymous = false; - - var mechanisms = bodyWrap.getElementsByTagName("mechanism"); - var i, mech, auth_str, hashed_auth_str; - if (mechanisms.length > 0) { - for (i = 0; i < mechanisms.length; i++) { - mech = Strophe.getText(mechanisms[i]); - if (mech == 'DIGEST-MD5') { - do_sasl_digest_md5 = true; - } else if (mech == 'PLAIN') { - do_sasl_plain = true; - } else if (mech == 'ANONYMOUS') { - do_sasl_anonymous = true; - } - } - } else { - // we didn't get stream:features yet, so we need wait for it - // by sending a blank poll request - var body = this._buildBody(); - this._requests.push( - new Strophe.Request(body.tree(), - this._onRequestStateChange.bind(this) - .prependArg(this._connect_cb.bind(this)), - body.tree().getAttribute("rid"))); - this._throttledRequestHandler(); - return; - } - - if (Strophe.getNodeFromJid(this.jid) === null && - do_sasl_anonymous) { - this._changeConnectStatus(Strophe.Status.AUTHENTICATING, null); - this._sasl_success_handler = this._addSysHandler( - this._sasl_success_cb.bind(this), null, - "success", null, null); - this._sasl_failure_handler = this._addSysHandler( - this._sasl_failure_cb.bind(this), null, - "failure", null, null); - - this.send($build("auth", { - xmlns: Strophe.NS.SASL, - mechanism: "ANONYMOUS" - }).tree()); - } else if (Strophe.getNodeFromJid(this.jid) === null) { - // we don't have a node, which is required for non-anonymous - // client connections - this._changeConnectStatus(Strophe.Status.CONNFAIL, - 'x-strophe-bad-non-anon-jid'); - this.disconnect(); - } else if (do_sasl_digest_md5) { - this._changeConnectStatus(Strophe.Status.AUTHENTICATING, null); - this._sasl_challenge_handler = this._addSysHandler( - this._sasl_challenge1_cb.bind(this), null, - "challenge", null, null); - this._sasl_failure_handler = this._addSysHandler( - this._sasl_failure_cb.bind(this), null, - "failure", null, null); - - this.send($build("auth", { - xmlns: Strophe.NS.SASL, - mechanism: "DIGEST-MD5" - }).tree()); - } else if (do_sasl_plain) { - // Build the plain auth string (barejid null - // username null password) and base 64 encoded. - auth_str = Strophe.getBareJidFromJid(this.jid); - auth_str = auth_str + "\u0000"; - auth_str = auth_str + Strophe.getNodeFromJid(this.jid); - auth_str = auth_str + "\u0000"; - auth_str = auth_str + this.pass; - - this._changeConnectStatus(Strophe.Status.AUTHENTICATING, null); - this._sasl_success_handler = this._addSysHandler( - this._sasl_success_cb.bind(this), null, - "success", null, null); - this._sasl_failure_handler = this._addSysHandler( - this._sasl_failure_cb.bind(this), null, - "failure", null, null); - - hashed_auth_str = Base64.encode(auth_str); - this.send($build("auth", { - xmlns: Strophe.NS.SASL, - mechanism: "PLAIN" - }).t(hashed_auth_str).tree()); - } else { - this._changeConnectStatus(Strophe.Status.AUTHENTICATING, null); - this._addSysHandler(this._auth1_cb.bind(this), null, null, - null, "_auth_1"); - - this.send($iq({ - type: "get", - to: this.domain, - id: "_auth_1" - }).c("query", { - xmlns: Strophe.NS.AUTH - }).c("username", {}).t(Strophe.getNodeFromJid(this.jid)).tree()); - } - }, - - /** PrivateFunction: _sasl_challenge1_cb - * _Private_ handler for DIGEST-MD5 SASL authentication. - * - * Parameters: - * (XMLElement) elem - The challenge stanza. - * - * Returns: - * false to remove the handler. - */ - _sasl_challenge1_cb: function (elem) - { - var attribMatch = /([a-z]+)=("[^"]+"|[^,"]+)(?:,|$)/; - - var challenge = Base64.decode(Strophe.getText(elem)); - var cnonce = MD5.hexdigest(Math.random() * 1234567890); - var realm = ""; - var host = null; - var nonce = ""; - var qop = ""; - var matches; - - // remove unneeded handlers - this.deleteHandler(this._sasl_failure_handler); - - while (challenge.match(attribMatch)) { - matches = challenge.match(attribMatch); - challenge = challenge.replace(matches[0], ""); - matches[2] = matches[2].replace(/^"(.+)"$/, "$1"); - switch (matches[1]) { - case "realm": - realm = matches[2]; - break; - case "nonce": - nonce = matches[2]; - break; - case "qop": - qop = matches[2]; - break; - case "host": - host = matches[2]; - break; - } - } - - var digest_uri = "xmpp/" + this.domain; - if (host !== null) { - digest_uri = digest_uri + "/" + host; - } - - var A1 = MD5.hash(Strophe.getNodeFromJid(this.jid) + - ":" + realm + ":" + this.pass) + - ":" + nonce + ":" + cnonce; - var A2 = 'AUTHENTICATE:' + digest_uri; - - var responseText = ""; - responseText += 'username=' + - this._quote(Strophe.getNodeFromJid(this.jid)) + ','; - responseText += 'realm=' + this._quote(realm) + ','; - responseText += 'nonce=' + this._quote(nonce) + ','; - responseText += 'cnonce=' + this._quote(cnonce) + ','; - responseText += 'nc="00000001",'; - responseText += 'qop="auth",'; - responseText += 'digest-uri=' + this._quote(digest_uri) + ','; - responseText += 'response=' + this._quote( - MD5.hexdigest(MD5.hexdigest(A1) + ":" + - nonce + ":00000001:" + - cnonce + ":auth:" + - MD5.hexdigest(A2))) + ','; - responseText += 'charset="utf-8"'; - - this._sasl_challenge_handler = this._addSysHandler( - this._sasl_challenge2_cb.bind(this), null, - "challenge", null, null); - this._sasl_success_handler = this._addSysHandler( - this._sasl_success_cb.bind(this), null, - "success", null, null); - this._sasl_failure_handler = this._addSysHandler( - this._sasl_failure_cb.bind(this), null, - "failure", null, null); - - this.send($build('response', { - xmlns: Strophe.NS.SASL - }).t(Base64.encode(responseText)).tree()); - - return false; - }, - - /** PrivateFunction: _quote - * _Private_ utility function to backslash escape and quote strings. - * - * Parameters: - * (String) str - The string to be quoted. - * - * Returns: - * quoted string - */ - _quote: function (str) - { - return '"' + str.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '"'; - //" end string workaround for emacs - }, - - - /** PrivateFunction: _sasl_challenge2_cb - * _Private_ handler for second step of DIGEST-MD5 SASL authentication. - * - * Parameters: - * (XMLElement) elem - The challenge stanza. - * - * Returns: - * false to remove the handler. - */ - _sasl_challenge2_cb: function (elem) - { - // remove unneeded handlers - this.deleteHandler(this._sasl_success_handler); - this.deleteHandler(this._sasl_failure_handler); - - this._sasl_success_handler = this._addSysHandler( - this._sasl_success_cb.bind(this), null, - "success", null, null); - this._sasl_failure_handler = this._addSysHandler( - this._sasl_failure_cb.bind(this), null, - "failure", null, null); - this.send($build('response', {xmlns: Strophe.NS.SASL}).tree()); - return false; - }, - - /** PrivateFunction: _auth1_cb - * _Private_ handler for legacy authentication. - * - * This handler is called in response to the initial - * for legacy authentication. It builds an authentication and - * sends it, creating a handler (calling back to _auth2_cb()) to - * handle the result - * - * Parameters: - * (XMLElement) elem - The stanza that triggered the callback. - * - * Returns: - * false to remove the handler. - */ - _auth1_cb: function (elem) - { - // build plaintext auth iq - var iq = $iq({type: "set", id: "_auth_2"}) - .c('query', {xmlns: Strophe.NS.AUTH}) - .c('username', {}).t(Strophe.getNodeFromJid(this.jid)) - .up() - .c('password').t(this.pass); - - if (!Strophe.getResourceFromJid(this.jid)) { - // since the user has not supplied a resource, we pick - // a default one here. unlike other auth methods, the server - // cannot do this for us. - this.jid = Strophe.getBareJidFromJid(this.jid) + '/strophe'; - } - iq.up().c('resource', {}).t(Strophe.getResourceFromJid(this.jid)); - - this._addSysHandler(this._auth2_cb.bind(this), null, - null, null, "_auth_2"); - - this.send(iq.tree()); - - return false; - }, - - /** PrivateFunction: _sasl_success_cb - * _Private_ handler for succesful SASL authentication. - * - * Parameters: - * (XMLElement) elem - The matching stanza. - * - * Returns: - * false to remove the handler. - */ - _sasl_success_cb: function (elem) - { - Strophe.info("SASL authentication succeeded."); - - // remove old handlers - this.deleteHandler(this._sasl_failure_handler); - this._sasl_failure_handler = null; - if (this._sasl_challenge_handler) { - this.deleteHandler(this._sasl_challenge_handler); - this._sasl_challenge_handler = null; - } - - this._addSysHandler(this._sasl_auth1_cb.bind(this), null, - "stream:features", null, null); - - // we must send an xmpp:restart now - this._sendRestart(); - - return false; - }, - - /** PrivateFunction: _sasl_auth1_cb - * _Private_ handler to start stream binding. - * - * Parameters: - * (XMLElement) elem - The matching stanza. - * - * Returns: - * false to remove the handler. - */ - _sasl_auth1_cb: function (elem) - { - var i, child; - - for (i = 0; i < elem.childNodes.length; i++) { - child = elem.childNodes[i]; - if (child.nodeName == 'bind') { - this.do_bind = true; - } - - if (child.nodeName == 'session') { - this.do_session = true; - } - } - - if (!this.do_bind) { - this._changeConnectStatus(Strophe.Status.AUTHFAIL, null); - return false; - } else { - this._addSysHandler(this._sasl_bind_cb.bind(this), null, null, - null, "_bind_auth_2"); - - var resource = Strophe.getResourceFromJid(this.jid); - if (resource) { - this.send($iq({type: "set", id: "_bind_auth_2"}) - .c('bind', {xmlns: Strophe.NS.BIND}) - .c('resource', {}).t(resource).tree()); - } else { - this.send($iq({type: "set", id: "_bind_auth_2"}) - .c('bind', {xmlns: Strophe.NS.BIND}) - .tree()); - } - } - - return false; - }, - - /** PrivateFunction: _sasl_bind_cb - * _Private_ handler for binding result and session start. - * - * Parameters: - * (XMLElement) elem - The matching stanza. - * - * Returns: - * false to remove the handler. - */ - _sasl_bind_cb: function (elem) - { - if (elem.getAttribute("type") == "error") { - Strophe.info("SASL binding failed."); - this._changeConnectStatus(Strophe.Status.AUTHFAIL, null); - return false; - } - - // TODO - need to grab errors - var bind = elem.getElementsByTagName("bind"); - var jidNode; - if (bind.length > 0) { - // Grab jid - jidNode = bind[0].getElementsByTagName("jid"); - if (jidNode.length > 0) { - this.jid = Strophe.getText(jidNode[0]); - - if (this.do_session) { - this._addSysHandler(this._sasl_session_cb.bind(this), - null, null, null, "_session_auth_2"); - - this.send($iq({type: "set", id: "_session_auth_2"}) - .c('session', {xmlns: Strophe.NS.SESSION}) - .tree()); - } else { - this.authenticated = true; - this._changeConnectStatus(Strophe.Status.CONNECTED, null); - } - } - } else { - Strophe.info("SASL binding failed."); - this._changeConnectStatus(Strophe.Status.AUTHFAIL, null); - return false; - } - }, - - /** PrivateFunction: _sasl_session_cb - * _Private_ handler to finish successful SASL connection. - * - * This sets Connection.authenticated to true on success, which - * starts the processing of user handlers. - * - * Parameters: - * (XMLElement) elem - The matching stanza. - * - * Returns: - * false to remove the handler. - */ - _sasl_session_cb: function (elem) - { - if (elem.getAttribute("type") == "result") { - this.authenticated = true; - this._changeConnectStatus(Strophe.Status.CONNECTED, null); - } else if (elem.getAttribute("type") == "error") { - Strophe.info("Session creation failed."); - this._changeConnectStatus(Strophe.Status.AUTHFAIL, null); - return false; - } - - return false; - }, - - /** PrivateFunction: _sasl_failure_cb - * _Private_ handler for SASL authentication failure. - * - * Parameters: - * (XMLElement) elem - The matching stanza. - * - * Returns: - * false to remove the handler. - */ - _sasl_failure_cb: function (elem) - { - // delete unneeded handlers - if (this._sasl_success_handler) { - this.deleteHandler(this._sasl_success_handler); - this._sasl_success_handler = null; - } - if (this._sasl_challenge_handler) { - this.deleteHandler(this._sasl_challenge_handler); - this._sasl_challenge_handler = null; - } - - this._changeConnectStatus(Strophe.Status.AUTHFAIL, null); - return false; - }, - - /** PrivateFunction: _auth2_cb - * _Private_ handler to finish legacy authentication. - * - * This handler is called when the result from the jabber:iq:auth - * stanza is returned. - * - * Parameters: - * (XMLElement) elem - The stanza that triggered the callback. - * - * Returns: - * false to remove the handler. - */ - _auth2_cb: function (elem) - { - if (elem.getAttribute("type") == "result") { - this.authenticated = true; - this._changeConnectStatus(Strophe.Status.CONNECTED, null); - } else if (elem.getAttribute("type") == "error") { - this._changeConnectStatus(Strophe.Status.AUTHFAIL, null); - this.disconnect(); - } - - return false; - }, - - /** PrivateFunction: _addSysTimedHandler - * _Private_ function to add a system level timed handler. - * - * This function is used to add a Strophe.TimedHandler for the - * library code. System timed handlers are allowed to run before - * authentication is complete. - * - * Parameters: - * (Integer) period - The period of the handler. - * (Function) handler - The callback function. - */ - _addSysTimedHandler: function (period, handler) - { - var thand = new Strophe.TimedHandler(period, handler); - thand.user = false; - this.addTimeds.push(thand); - return thand; - }, - - /** PrivateFunction: _addSysHandler - * _Private_ function to add a system level stanza handler. - * - * This function is used to add a Strophe.Handler for the - * library code. System stanza handlers are allowed to run before - * authentication is complete. - * - * Parameters: - * (Function) handler - The callback function. - * (String) ns - The namespace to match. - * (String) name - The stanza name to match. - * (String) type - The stanza type attribute to match. - * (String) id - The stanza id attribute to match. - */ - _addSysHandler: function (handler, ns, name, type, id) - { - var hand = new Strophe.Handler(handler, ns, name, type, id); - hand.user = false; - this.addHandlers.push(hand); - return hand; - }, - - /** PrivateFunction: _onDisconnectTimeout - * _Private_ timeout handler for handling non-graceful disconnection. - * - * If the graceful disconnect process does not complete within the - * time allotted, this handler finishes the disconnect anyway. - * - * Returns: - * false to remove the handler. - */ - _onDisconnectTimeout: function () - { - Strophe.info("_onDisconnectTimeout was called"); - - // cancel all remaining requests and clear the queue - var req; - while (this._requests.length > 0) { - req = this._requests.pop(); - req.abort = true; - req.xhr.abort(); - // jslint complains, but this is fine. setting to empty func - // is necessary for IE6 - req.xhr.onreadystatechange = function () {}; - } - - // actually disconnect - this._doDisconnect(); - - return false; - }, - - /** PrivateFunction: _onIdle - * _Private_ handler to process events during idle cycle. - * - * This handler is called every 100ms to fire timed handlers that - * are ready and keep poll requests going. - */ - _onIdle: function () - { - var i, thand, since, newList; - - // remove timed handlers that have been scheduled for deletion - while (this.removeTimeds.length > 0) { - thand = this.removeTimeds.pop(); - i = this.timedHandlers.indexOf(thand); - if (i >= 0) { - this.timedHandlers.splice(i, 1); - } - } - - // add timed handlers scheduled for addition - while (this.addTimeds.length > 0) { - this.timedHandlers.push(this.addTimeds.pop()); - } - - // call ready timed handlers - var now = new Date().getTime(); - newList = []; - for (i = 0; i < this.timedHandlers.length; i++) { - thand = this.timedHandlers[i]; - if (this.authenticated || !thand.user) { - since = thand.lastCalled + thand.period; - if (since - now <= 0) { - if (thand.run()) { - newList.push(thand); - } - } else { - newList.push(thand); - } - } - } - this.timedHandlers = newList; - - var body, time_elapsed; - - // if no requests are in progress, poll - if (this.authenticated && this._requests.length === 0 && - this._data.length === 0 && !this.disconnecting) { - Strophe.info("no requests during idle cycle, sending " + - "blank request"); - this._data.push(null); - } - - if (this._requests.length < 2 && this._data.length > 0 && - !this.paused) { - body = this._buildBody(); - for (i = 0; i < this._data.length; i++) { - if (this._data[i] !== null) { - if (this._data[i] === "restart") { - body.attrs({ - to: this.domain, - "xml:lang": "en", - "xmpp:restart": "true", - "xmlns:xmpp": Strophe.NS.BOSH - }); - } else { - body.cnode(this._data[i]).up(); - } - } - } - delete this._data; - this._data = []; - this._requests.push( - new Strophe.Request(body.tree(), - this._onRequestStateChange.bind(this) - .prependArg(this._dataRecv.bind(this)), - body.tree().getAttribute("rid"))); - this._processRequest(this._requests.length - 1); - } - - if (this._requests.length > 0) { - time_elapsed = this._requests[0].age(); - if (this._requests[0].dead !== null) { - if (this._requests[0].timeDead() > - Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait)) { - this._throttledRequestHandler(); - } - } - - if (time_elapsed > Math.floor(Strophe.TIMEOUT * this.wait)) { - Strophe.warn("Request " + - this._requests[0].id + - " timed out, over " + Math.floor(Strophe.TIMEOUT * this.wait) + - " seconds since last activity"); - this._throttledRequestHandler(); - } - } - - // reactivate the timer - clearTimeout(this._idleTimeout); - this._idleTimeout = setTimeout(this._onIdle.bind(this), 100); - } -}; - -if (callback) { - callback(Strophe, $build, $msg, $iq, $pres); -} - -})(function () { - window.Strophe = arguments[0]; - window.$build = arguments[1]; - window.$msg = arguments[2]; - window.$iq = arguments[3]; - window.$pres = arguments[4]; -}); diff --git a/public/javascripts/strophejs-1.0.1/strophe.min.js b/public/javascripts/strophejs-1.0.1/strophe.min.js deleted file mode 100644 index f0eb179..0000000 --- a/public/javascripts/strophejs-1.0.1/strophe.min.js +++ /dev/null @@ -1 +0,0 @@ -var Base64=(function(){var keyStr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var obj={encode:function(input){var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;do{chr1=input.charCodeAt(i++);chr2=input.charCodeAt(i++);chr3=input.charCodeAt(i++);enc1=chr1>>2;enc2=((chr1&3)<<4)|(chr2>>4);enc3=((chr2&15)<<2)|(chr3>>6);enc4=chr3&63;if(isNaN(chr2)){enc3=enc4=64}else{if(isNaN(chr3)){enc4=64}}output=output+keyStr.charAt(enc1)+keyStr.charAt(enc2)+keyStr.charAt(enc3)+keyStr.charAt(enc4)}while(i>4);chr2=((enc2&15)<<4)|(enc3>>2);chr3=((enc3&3)<<6)|enc4;output=output+String.fromCharCode(chr1);if(enc3!=64){output=output+String.fromCharCode(chr2)}if(enc4!=64){output=output+String.fromCharCode(chr3)}}while(i>16)+(y>>16)+(lsw>>16);return(msw<<16)|(lsw&65535)};var bit_rol=function(num,cnt){return(num<>>(32-cnt))};var str2binl=function(str){var bin=[];var mask=(1<>5]|=(str.charCodeAt(i/chrsz)&mask)<<(i%32)}return bin};var binl2str=function(bin){var str="";var mask=(1<>5]>>>(i%32))&mask)}return str};var binl2hex=function(binarray){var hex_tab=hexcase?"0123456789ABCDEF":"0123456789abcdef";var str="";for(var i=0;i>2]>>((i%4)*8+4))&15)+hex_tab.charAt((binarray[i>>2]>>((i%4)*8))&15)}return str};var binl2b64=function(binarray){var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var str="";var triplet,j;for(var i=0;i>2]>>8*(i%4))&255)<<16)|(((binarray[i+1>>2]>>8*((i+1)%4))&255)<<8)|((binarray[i+2>>2]>>8*((i+2)%4))&255);for(j=0;j<4;j++){if(i*8+j*6>binarray.length*32){str+=b64pad}else{str+=tab.charAt((triplet>>6*(3-j))&63)}}}return str};var md5_cmn=function(q,a,b,x,s,t){return safe_add(bit_rol(safe_add(safe_add(a,q),safe_add(x,t)),s),b)};var md5_ff=function(a,b,c,d,x,s,t){return md5_cmn((b&c)|((~b)&d),a,b,x,s,t)};var md5_gg=function(a,b,c,d,x,s,t){return md5_cmn((b&d)|(c&(~d)),a,b,x,s,t)};var md5_hh=function(a,b,c,d,x,s,t){return md5_cmn(b^c^d,a,b,x,s,t)};var md5_ii=function(a,b,c,d,x,s,t){return md5_cmn(c^(b|(~d)),a,b,x,s,t)};var core_md5=function(x,len){x[len>>5]|=128<<((len)%32);x[(((len+64)>>>9)<<4)+14]=len;var a=1732584193;var b=-271733879;var c=-1732584194;var d=271733878;var olda,oldb,oldc,oldd;for(var i=0;i16){bkey=core_md5(bkey,key.length*chrsz)}var ipad=new Array(16),opad=new Array(16);for(var i=0;i<16;i++){ipad[i]=bkey[i]^909522486;opad[i]=bkey[i]^1549556828}var hash=core_md5(ipad.concat(str2binl(data)),512+data.length*chrsz);return core_md5(opad.concat(hash),512+128)};var obj={hexdigest:function(s){return binl2hex(core_md5(str2binl(s),s.length*chrsz))},b64digest:function(s){return binl2b64(core_md5(str2binl(s),s.length*chrsz))},hash:function(s){return binl2str(core_md5(str2binl(s),s.length*chrsz))},hmac_hexdigest:function(key,data){return binl2hex(core_hmac_md5(key,data))},hmac_b64digest:function(key,data){return binl2b64(core_hmac_md5(key,data))},hmac_hash:function(key,data){return binl2str(core_hmac_md5(key,data))},test:function(){return MD5.hexdigest("abc")==="900150983cd24fb0d6963f7d28e17f72"}};return obj})();if(!Function.prototype.bind){Function.prototype.bind=function(obj){var func=this;return function(){return func.apply(obj,arguments)}}}if(!Function.prototype.prependArg){Function.prototype.prependArg=function(arg){var func=this;return function(){var newargs=[arg];for(var i=0;i/g,">");return text},xmlTextNode:function(text){text=Strophe.xmlescape(text);if(!Strophe._xmlGenerator){Strophe._xmlGenerator=Strophe._makeGenerator()}return Strophe._xmlGenerator.createTextNode(text)},getText:function(elem){if(!elem){return null}var str="";if(elem.childNodes.length===0&&elem.nodeType==Strophe.ElementType.TEXT){str+=elem.nodeValue}for(var i=0;i/g,"\\3e").replace(/@/g,"\\40")},unescapeNode:function(node){return node.replace(/\\20/g," ").replace(/\\22/g,'"').replace(/\\26/g,"&").replace(/\\27/g,"'").replace(/\\2f/g,"/").replace(/\\3a/g,":").replace(/\\3c/g,"<").replace(/\\3e/g,">").replace(/\\40/g,"@").replace(/\\5c/g,"\\")},getNodeFromJid:function(jid){if(jid.indexOf("@")<0){return null}return jid.split("@")[0]},getDomainFromJid:function(jid){var bare=Strophe.getBareJidFromJid(jid);if(bare.indexOf("@")<0){return bare}else{var parts=bare.split("@");parts.splice(0,1);return parts.join("@")}},getResourceFromJid:function(jid){var s=jid.split("/");if(s.length<2){return null}s.splice(0,1);return s.join("/")},getBareJidFromJid:function(jid){return jid.split("/")[0]},log:function(level,msg){return},debug:function(msg){this.log(this.LogLevel.DEBUG,msg)},info:function(msg){this.log(this.LogLevel.INFO,msg)},warn:function(msg){this.log(this.LogLevel.WARN,msg)},error:function(msg){this.log(this.LogLevel.ERROR,msg)},fatal:function(msg){this.log(this.LogLevel.FATAL,msg)},serialize:function(elem){var result;if(!elem){return null}if(typeof(elem.tree)==="function"){elem=elem.tree()}var nodeName=elem.nodeName;var i,child;if(elem.getAttribute("_realname")){nodeName=elem.getAttribute("_realname")}result="<"+nodeName;for(i=0;i0){result+=">";for(i=0;i"}else{result+="/>"}return result},_requestId:0,_connectionPlugins:{},addConnectionPlugin:function(name,ptype){Strophe._connectionPlugins[name]=ptype}};Strophe.Builder=function(name,attrs){if(name=="presence"||name=="message"||name=="iq"){if(attrs&&!attrs.xmlns){attrs.xmlns=Strophe.NS.CLIENT}else{if(!attrs){attrs={xmlns:Strophe.NS.CLIENT}}}}this.nodeTree=Strophe.xmlElement(name,attrs);this.node=this.nodeTree};Strophe.Builder.prototype={tree:function(){return this.nodeTree},toString:function(){return Strophe.serialize(this.nodeTree)},up:function(){this.node=this.node.parentNode;return this},attrs:function(moreattrs){for(var k in moreattrs){if(moreattrs.hasOwnProperty(k)){this.node.setAttribute(k,moreattrs[k])}}return this},c:function(name,attrs){var child=Strophe.xmlElement(name,attrs);this.node.appendChild(child);this.node=child;return this},cnode:function(elem){this.node.appendChild(elem);this.node=elem;return this},t:function(text){var child=Strophe.xmlTextNode(text);this.node.appendChild(child);return this}};Strophe.Handler=function(handler,ns,name,type,id,from,options){this.handler=handler;this.ns=ns;this.name=name;this.type=type;this.id=id;this.options=options||{matchbare:false};if(!this.options.matchBare){this.options.matchBare=false}if(this.options.matchBare){this.from=Strophe.getBareJidFromJid(from)}else{this.from=from}this.user=true};Strophe.Handler.prototype={isMatch:function(elem){var nsMatch;var from=null;if(this.options.matchBare){from=Strophe.getBareJidFromJid(elem.getAttribute("from"))}else{from=elem.getAttribute("from")}nsMatch=false;if(!this.ns){nsMatch=true}else{var self=this;Strophe.forEachChild(elem,null,function(elem){if(elem.getAttribute("xmlns")==self.ns){nsMatch=true}});nsMatch=nsMatch||elem.getAttribute("xmlns")==this.ns}if(nsMatch&&(!this.name||Strophe.isTagEqual(elem,this.name))&&(!this.type||elem.getAttribute("type")===this.type)&&(!this.id||elem.getAttribute("id")===this.id)&&(!this.from||from===this.from)){return true}return false},run:function(elem){var result=null;try{result=this.handler(elem)}catch(e){if(e.sourceURL){Strophe.fatal("error: "+this.handler+" "+e.sourceURL+":"+e.line+" - "+e.name+": "+e.message)}else{if(e.fileName){if(typeof(console)!="undefined"){console.trace();console.error(this.handler," - error - ",e,e.message)}Strophe.fatal("error: "+this.handler+" "+e.fileName+":"+e.lineNumber+" - "+e.name+": "+e.message)}else{Strophe.fatal("error: "+this.handler)}}throw e}return result},toString:function(){return"{Handler: "+this.handler+"("+this.name+","+this.id+","+this.ns+")}"}};Strophe.TimedHandler=function(period,handler){this.period=period;this.handler=handler;this.lastCalled=new Date().getTime();this.user=true};Strophe.TimedHandler.prototype={run:function(){this.lastCalled=new Date().getTime();return this.handler()},reset:function(){this.lastCalled=new Date().getTime()},toString:function(){return"{TimedHandler: "+this.handler+"("+this.period+")}"}};Strophe.Request=function(elem,func,rid,sends){this.id=++Strophe._requestId;this.xmlData=elem;this.data=Strophe.serialize(elem);this.origFunc=func;this.func=func;this.rid=rid;this.date=NaN;this.sends=sends||0;this.abort=false;this.dead=null;this.age=function(){if(!this.date){return 0}var now=new Date();return(now-this.date)/1000};this.timeDead=function(){if(!this.dead){return 0}var now=new Date();return(now-this.dead)/1000};this.xhr=this._newXHR()};Strophe.Request.prototype={getResponse:function(){var node=null;if(this.xhr.responseXML&&this.xhr.responseXML.documentElement){node=this.xhr.responseXML.documentElement;if(node.tagName=="parsererror"){Strophe.error("invalid response received");Strophe.error("responseText: "+this.xhr.responseText);Strophe.error("responseXML: "+Strophe.serialize(this.xhr.responseXML));throw"parsererror"}}else{if(this.xhr.responseText){Strophe.error("invalid response received");Strophe.error("responseText: "+this.xhr.responseText);Strophe.error("responseXML: "+Strophe.serialize(this.xhr.responseXML))}}return node},_newXHR:function(){var xhr=null;if(window.XMLHttpRequest){xhr=new XMLHttpRequest();if(xhr.overrideMimeType){xhr.overrideMimeType("text/xml")}}else{if(window.ActiveXObject){xhr=new ActiveXObject("Microsoft.XMLHTTP")}}xhr.onreadystatechange=this.func.prependArg(this);return xhr}};Strophe.Connection=function(service){this.service=service;this.jid="";this.rid=Math.floor(Math.random()*4294967295);this.sid=null;this.streamId=null;this.do_session=false;this.do_bind=false;this.timedHandlers=[];this.handlers=[];this.removeTimeds=[];this.removeHandlers=[];this.addTimeds=[];this.addHandlers=[];this._idleTimeout=null;this._disconnectTimeout=null;this.authenticated=false;this.disconnecting=false;this.connected=false;this.errors=0;this.paused=false;this.hold=1;this.wait=60;this.window=5;this._data=[];this._requests=[];this._uniqueId=Math.round(Math.random()*10000);this._sasl_success_handler=null;this._sasl_failure_handler=null;this._sasl_challenge_handler=null;this._idleTimeout=setTimeout(this._onIdle.bind(this),100);for(var k in Strophe._connectionPlugins){if(Strophe._connectionPlugins.hasOwnProperty(k)){var ptype=Strophe._connectionPlugins[k];var F=function(){};F.prototype=ptype;this[k]=new F();this[k].init(this)}}};Strophe.Connection.prototype={reset:function(){this.rid=Math.floor(Math.random()*4294967295);this.sid=null;this.streamId=null;this.do_session=false;this.do_bind=false;this.timedHandlers=[];this.handlers=[];this.removeTimeds=[];this.removeHandlers=[];this.addTimeds=[];this.addHandlers=[];this.authenticated=false;this.disconnecting=false;this.connected=false;this.errors=0;this._requests=[];this._uniqueId=Math.round(Math.random()*10000)},pause:function(){this.paused=true},resume:function(){this.paused=false},getUniqueId:function(suffix){if(typeof(suffix)=="string"||typeof(suffix)=="number"){return ++this._uniqueId+":"+suffix}else{return ++this._uniqueId+""}},connect:function(jid,pass,callback,wait,hold){this.jid=jid;this.pass=pass;this.connect_callback=callback;this.disconnecting=false;this.connected=false;this.authenticated=false;this.errors=0;this.wait=wait||this.wait;this.hold=hold||this.hold;this.domain=Strophe.getDomainFromJid(this.jid);var body=this._buildBody().attrs({to:this.domain,"xml:lang":"en",wait:this.wait,hold:this.hold,content:"text/xml; charset=utf-8",ver:"1.6","xmpp:version":"1.0","xmlns:xmpp":Strophe.NS.BOSH});this._changeConnectStatus(Strophe.Status.CONNECTING,null);this._requests.push(new Strophe.Request(body.tree(),this._onRequestStateChange.bind(this).prependArg(this._connect_cb.bind(this)),body.tree().getAttribute("rid")));this._throttledRequestHandler()},attach:function(jid,sid,rid,callback,wait,hold,wind){this.jid=jid;this.sid=sid;this.rid=rid;this.connect_callback=callback;this.domain=Strophe.getDomainFromJid(this.jid);this.authenticated=true;this.connected=true;this.wait=wait||this.wait;this.hold=hold||this.hold;this.window=wind||this.window;this._changeConnectStatus(Strophe.Status.ATTACHED,null)},xmlInput:function(elem){return},xmlOutput:function(elem){return},rawInput:function(data){return},rawOutput:function(data){return},send:function(elem){if(elem===null){return}if(typeof(elem.sort)==="function"){for(var i=0;i=0;i--){if(req==this._requests[i]){this._requests.splice(i,1)}}req.xhr.onreadystatechange=function(){};this._throttledRequestHandler()},_restartRequest:function(i){var req=this._requests[i];if(req.dead===null){req.dead=new Date()}this._processRequest(i)},_processRequest:function(i){var req=this._requests[i];var reqStatus=-1;try{if(req.xhr.readyState==4){reqStatus=req.xhr.status}}catch(e){Strophe.error("caught an error in _requests["+i+"], reqStatus: "+reqStatus)}if(typeof(reqStatus)=="undefined"){reqStatus=-1}var time_elapsed=req.age();var primaryTimeout=(!isNaN(time_elapsed)&&time_elapsed>Math.floor(Strophe.TIMEOUT*this.wait));var secondaryTimeout=(req.dead!==null&&req.timeDead()>Math.floor(Strophe.SECONDARY_TIMEOUT*this.wait));var requestCompletedWithServerError=(req.xhr.readyState==4&&(reqStatus<1||reqStatus>=500));if(primaryTimeout||secondaryTimeout||requestCompletedWithServerError){if(secondaryTimeout){Strophe.error("Request "+this._requests[i].id+" timed out (secondary), restarting")}req.abort=true;req.xhr.abort();req.xhr.onreadystatechange=function(){};this._requests[i]=new Strophe.Request(req.xmlData,req.origFunc,req.rid,req.sends);req=this._requests[i]}if(req.xhr.readyState===0){Strophe.debug("request id "+req.id+"."+req.sends+" posting");req.date=new Date();try{req.xhr.open("POST",this.service,true)}catch(e2){Strophe.error("XHR open failed.");if(!this.connected){this._changeConnectStatus(Strophe.Status.CONNFAIL,"bad-service")}this.disconnect();return}var sendFunc=function(){req.xhr.send(req.data)};if(req.sends>1){var backoff=Math.pow(req.sends,3)*1000;setTimeout(sendFunc,backoff)}else{sendFunc()}req.sends++;this.xmlOutput(req.xmlData);this.rawOutput(req.data)}else{Strophe.debug("_processRequest: "+(i===0?"first":"second")+" request has readyState of "+req.xhr.readyState)}},_throttledRequestHandler:function(){if(!this._requests){Strophe.debug("_throttledRequestHandler called with undefined requests")}else{Strophe.debug("_throttledRequestHandler called with "+this._requests.length+" requests")}if(!this._requests||this._requests.length===0){return}if(this._requests.length>0){this._processRequest(0)}if(this._requests.length>1&&Math.abs(this._requests[0].rid-this._requests[1].rid)=400){this._hitError(reqStatus);return}}var reqIs0=(this._requests[0]==req);var reqIs1=(this._requests[1]==req);if((reqStatus>0&&reqStatus<500)||req.sends>5){this._removeRequest(req);Strophe.debug("request id "+req.id+" should now be removed")}if(reqStatus==200){if(reqIs1||(reqIs0&&this._requests.length>0&&this._requests[0].age()>Math.floor(Strophe.SECONDARY_TIMEOUT*this.wait))){this._restartRequest(0)}Strophe.debug("request id "+req.id+"."+req.sends+" got 200");func(req);this.errors=0}else{Strophe.error("request id "+req.id+"."+req.sends+" error "+reqStatus+" happened");if(reqStatus===0||(reqStatus>=400&&reqStatus<600)||reqStatus>=12000){this._hitError(reqStatus);if(reqStatus>=400&&reqStatus<500){this._changeConnectStatus(Strophe.Status.DISCONNECTING,null);this._doDisconnect()}}}if(!((reqStatus>0&&reqStatus<10000)||req.sends>5)){this._throttledRequestHandler()}}},_hitError:function(reqStatus){this.errors++;Strophe.warn("request errored, status: "+reqStatus+", number of errors: "+this.errors);if(this.errors>4){this._onDisconnectTimeout()}},_doDisconnect:function(){Strophe.info("_doDisconnect was called");this.authenticated=false;this.disconnecting=false;this.sid=null;this.streamId=null;this.rid=Math.floor(Math.random()*4294967295);if(this.connected){this._changeConnectStatus(Strophe.Status.DISCONNECTED,null);this.connected=false}this.handlers=[];this.timedHandlers=[];this.removeTimeds=[];this.removeHandlers=[];this.addTimeds=[];this.addHandlers=[]},_dataRecv:function(req){try{var elem=req.getResponse()}catch(e){if(e!="parsererror"){throw e}this.disconnect("strophe-parsererror")}if(elem===null){return}this.xmlInput(elem);this.rawInput(Strophe.serialize(elem));var i,hand;while(this.removeHandlers.length>0){hand=this.removeHandlers.pop();i=this.handlers.indexOf(hand);if(i>=0){this.handlers.splice(i,1)}}while(this.addHandlers.length>0){this.handlers.push(this.addHandlers.pop())}if(this.disconnecting&&this._requests.length===0){this.deleteTimedHandler(this._disconnectTimeout);this._disconnectTimeout=null;this._doDisconnect();return}var typ=elem.getAttribute("type");var cond,conflict;if(typ!==null&&typ=="terminate"){cond=elem.getAttribute("condition");conflict=elem.getElementsByTagName("conflict");if(cond!==null){if(cond=="remote-stream-error"&&conflict.length>0){cond="conflict"}this._changeConnectStatus(Strophe.Status.CONNFAIL,cond)}else{this._changeConnectStatus(Strophe.Status.CONNFAIL,"unknown")}this.disconnect();return}var self=this;Strophe.forEachChild(elem,null,function(child){var i,newList;newList=self.handlers;self.handlers=[];for(i=0;i0){cond="conflict"}this._changeConnectStatus(Strophe.Status.CONNFAIL,cond)}else{this._changeConnectStatus(Strophe.Status.CONNFAIL,"unknown")}return}if(!this.sid){this.sid=bodyWrap.getAttribute("sid")}if(!this.stream_id){this.stream_id=bodyWrap.getAttribute("authid")}var wind=bodyWrap.getAttribute("requests");if(wind){this.window=parseInt(wind,10)}var hold=bodyWrap.getAttribute("hold");if(hold){this.hold=parseInt(hold,10)}var wait=bodyWrap.getAttribute("wait");if(wait){this.wait=parseInt(wait,10)}var do_sasl_plain=false;var do_sasl_digest_md5=false;var do_sasl_anonymous=false;var mechanisms=bodyWrap.getElementsByTagName("mechanism");var i,mech,auth_str,hashed_auth_str;if(mechanisms.length>0){for(i=0;i0){jidNode=bind[0].getElementsByTagName("jid");if(jidNode.length>0){this.jid=Strophe.getText(jidNode[0]);if(this.do_session){this._addSysHandler(this._sasl_session_cb.bind(this),null,null,null,"_session_auth_2");this.send($iq({type:"set",id:"_session_auth_2"}).c("session",{xmlns:Strophe.NS.SESSION}).tree())}else{this.authenticated=true;this._changeConnectStatus(Strophe.Status.CONNECTED,null)}}}else{Strophe.info("SASL binding failed.");this._changeConnectStatus(Strophe.Status.AUTHFAIL,null);return false}},_sasl_session_cb:function(elem){if(elem.getAttribute("type")=="result"){this.authenticated=true;this._changeConnectStatus(Strophe.Status.CONNECTED,null)}else{if(elem.getAttribute("type")=="error"){Strophe.info("Session creation failed.");this._changeConnectStatus(Strophe.Status.AUTHFAIL,null);return false}}return false},_sasl_failure_cb:function(elem){if(this._sasl_success_handler){this.deleteHandler(this._sasl_success_handler);this._sasl_success_handler=null}if(this._sasl_challenge_handler){this.deleteHandler(this._sasl_challenge_handler);this._sasl_challenge_handler=null}this._changeConnectStatus(Strophe.Status.AUTHFAIL,null);return false},_auth2_cb:function(elem){if(elem.getAttribute("type")=="result"){this.authenticated=true;this._changeConnectStatus(Strophe.Status.CONNECTED,null)}else{if(elem.getAttribute("type")=="error"){this._changeConnectStatus(Strophe.Status.AUTHFAIL,null);this.disconnect()}}return false},_addSysTimedHandler:function(period,handler){var thand=new Strophe.TimedHandler(period,handler);thand.user=false;this.addTimeds.push(thand);return thand},_addSysHandler:function(handler,ns,name,type,id){var hand=new Strophe.Handler(handler,ns,name,type,id);hand.user=false;this.addHandlers.push(hand);return hand},_onDisconnectTimeout:function(){Strophe.info("_onDisconnectTimeout was called");var req;while(this._requests.length>0){req=this._requests.pop();req.abort=true;req.xhr.abort();req.xhr.onreadystatechange=function(){}}this._doDisconnect();return false},_onIdle:function(){var i,thand,since,newList;while(this.removeTimeds.length>0){thand=this.removeTimeds.pop();i=this.timedHandlers.indexOf(thand);if(i>=0){this.timedHandlers.splice(i,1)}}while(this.addTimeds.length>0){this.timedHandlers.push(this.addTimeds.pop())}var now=new Date().getTime();newList=[];for(i=0;i0&&!this.paused){body=this._buildBody();for(i=0;i0){time_elapsed=this._requests[0].age();if(this._requests[0].dead!==null){if(this._requests[0].timeDead()>Math.floor(Strophe.SECONDARY_TIMEOUT*this.wait)){this._throttledRequestHandler()}}if(time_elapsed>Math.floor(Strophe.TIMEOUT*this.wait)){Strophe.warn("Request "+this._requests[0].id+" timed out, over "+Math.floor(Strophe.TIMEOUT*this.wait)+" seconds since last activity");this._throttledRequestHandler()}}clearTimeout(this._idleTimeout);this._idleTimeout=setTimeout(this._onIdle.bind(this),100)}};if(callback){callback(Strophe,$build,$msg,$iq,$pres)}})(function(){window.Strophe=arguments[0];window.$build=arguments[1];window.$msg=arguments[2];window.$iq=arguments[3];window.$pres=arguments[4]}); \ No newline at end of file diff --git a/public/javascripts/strophejs-1.0.1/tests/jstests.js b/public/javascripts/strophejs-1.0.1/tests/jstests.js deleted file mode 100644 index bfc244e..0000000 --- a/public/javascripts/strophejs-1.0.1/tests/jstests.js +++ /dev/null @@ -1,136 +0,0 @@ -TestCase("JIDs", { - testNormalJid: function () { - var jid = "darcy@pemberley.lit/library"; - assertEquals("Node should be 'darcy'", - "darcy", Strophe.getNodeFromJid(jid)); - assertEquals("Domain should be 'pemberley.lit'", - "pemberley.lit", Strophe.getDomainFromJid(jid)); - assertEquals("Resource should be 'library'", - "library", Strophe.getResourceFromJid(jid)); - assertEquals("Bare JID should be 'darcy@pemberley.lit'", - "darcy@pemberley.lit", Strophe.getBareJidFromJid(jid)); - }, - - testWeirdNode: function () { - var jid = "darcy@netherfield.lit@pemberley.lit/library"; - assertEquals("Node should be 'darcy'", - "darcy", Strophe.getNodeFromJid(jid)); - assertEquals("Domain should be 'netherfield.lit@pemberley.lit'", - "netherfield.lit@pemberley.lit", - Strophe.getDomainFromJid(jid)); - assertEquals("Resource should be 'library'", - "library", Strophe.getResourceFromJid(jid)); - assertEquals("Bare JID should be 'darcy@netherfield.lit@pemberley.lit", - "darcy@netherfield.lit@pemberley.lit", - Strophe.getBareJidFromJid(jid)); - } -}); - -function foo() { - var $ = function () {}; - - test("Weird node (escaped)", function () { - var escapedNode = Strophe.escapeNode("darcy@netherfield.lit"); - var jid = escapedNode + "@pemberley.lit/library"; - equals(Strophe.getNodeFromJid(jid), "darcy\\40netherfield.lit", - "Node should be 'darcy\\40netherfield.lit'"); - equals(Strophe.getDomainFromJid(jid), - "pemberley.lit", - "Domain should be 'pemberley.lit'"); - equals(Strophe.getResourceFromJid(jid), "library", - "Resource should be 'library'"); - equals(Strophe.getBareJidFromJid(jid), - "darcy\\40netherfield.lit@pemberley.lit", - "Bare JID should be 'darcy\\40netherfield.lit@pemberley.lit'"); - }); - - test("Weird resource", function () { - var jid = "books@chat.pemberley.lit/darcy@pemberley.lit/library"; - equals(Strophe.getNodeFromJid(jid), "books", - "Node should be 'books'"); - equals(Strophe.getDomainFromJid(jid), "chat.pemberley.lit", - "Domain should be 'chat.pemberley.lit'"); - equals(Strophe.getResourceFromJid(jid), - "darcy@pemberley.lit/library", - "Resource should be 'darcy@pemberley.lit/library'"); - equals(Strophe.getBareJidFromJid(jid), - "books@chat.pemberley.lit", - "Bare JID should be 'books@chat.pemberley.lit'"); - }); - - module("Builder"); - - test("Correct namespace (#32)", function () { - var stanzas = [new Strophe.Builder("message", {foo: "asdf"}).tree(), - $build("iq", {}).tree(), - $pres().tree()]; - $.each(stanzas, function () { - equals($(this).attr('xmlns'), Strophe.NS.CLIENT, - "Namespace should be '" + Strophe.NS.CLIENT + "'"); - }); - }); - - test("send() accepts Builders (#27)", function () { - var stanza = $pres(); - var conn = new Strophe.Connection(""); - // fake connection callback to avoid errors - conn.connect_callback = function () {}; - - ok(conn._data.length === 0, "Output queue is clean"); - try { - conn.send(stanza); - } catch (e) {} - ok(conn._data.length === 1, "Output queue contains an element"); - }); - - test("send() does not accept strings", function () { - var stanza = ""; - var conn = new Strophe.Connection(""); - // fake connection callback to avoid errors - conn.connect_callback = function () {}; - expect(1); - try { - conn.send(stanza); - } catch (e) { - equals(e.name, "StropheError", "send() should throw exception"); - } - }); - - test("Builder with XML attribute escaping test", function () { - var text = ""; - var expected = ""; - var pres = $pres({to: text}); - equals(pres.toString(), expected, "< should be escaped"); - - text = "foo&bar"; - expected = ""; - pres = $pres({to: text}); - equals(pres.toString(), expected, "& should be escaped"); - }); - - module("XML"); - - test("XML escaping test", function () { - var text = "s & p"; - var textNode = Strophe.xmlTextNode(text); - equals(Strophe.getText(textNode), "s & p", "should be escaped"); - var text0 = "s < & > p"; - var textNode0 = Strophe.xmlTextNode(text0); - equals(Strophe.getText(textNode0), "s < & > p", "should be escaped"); - }); - - test("XML element creation", function () { - var elem = Strophe.xmlElement("message"); - equals(elem.tagName, "message", "Element name should be the same"); - }); - - module("Misc"); - - test("Quoting strings", function () { - var input = '"beep \\40"'; - var conn = new Strophe.Connection(); - var output = conn._quote(input); - equals(output, "\"\\\"beep \\\\40\\\"\"", - "string should be quoted and escaped"); - }); -} diff --git a/public/javascripts/strophejs-1.0.1/tests/jsyuitests.js b/public/javascripts/strophejs-1.0.1/tests/jsyuitests.js deleted file mode 100644 index 469f150..0000000 --- a/public/javascripts/strophejs-1.0.1/tests/jsyuitests.js +++ /dev/null @@ -1,31 +0,0 @@ -YUI.add('strophe.test', function (Y) { - Y.namespace("strophe.test"); - var R = Y.namespace("strophe.test.Runner"); - - R.add = function (suite) { - for (var i = 0; i < suite.items.length; i++) { - TestCase(suite.items[i].name, suite.items[i]); - } - }; -}, '1.0', {requires: ['test']}); - -YUI().use("test", "strophe.test", function (Y) { - var Assert = Y.Assert; - - var suite = new Y.Test.Suite("Strophe Tests"); - suite.add(new Y.Test.Case({ - name: "JIDs", - - testNormalJid: function () { - var jid = "darcy@pemberley.lit/library"; - - Assert.areSame("darcy", Strophe.getNodeFromJid(jid)); - Assert.areSame("pemberley.lit", Strophe.getDomainFromJid(jid)); - Assert.areSame("library", Strophe.getResourceFromJid(jid)); - Assert.areSame("darcy@pemberley.lit", - Strophe.getBareJidFromJid(jid)); - } - })); - - Y.strophe.test.Runner.add(suite); -}); diff --git a/public/javascripts/strophejs-1.0.1/tests/pubsub.html b/public/javascripts/strophejs-1.0.1/tests/pubsub.html deleted file mode 100644 index 42b8259..0000000 --- a/public/javascripts/strophejs-1.0.1/tests/pubsub.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - -

QUnit tests for Strophe

-

- -
-
-
    -
    - - diff --git a/public/javascripts/strophejs-1.0.1/tests/pubsub.js b/public/javascripts/strophejs-1.0.1/tests/pubsub.js deleted file mode 100644 index 50ce2de..0000000 --- a/public/javascripts/strophejs-1.0.1/tests/pubsub.js +++ /dev/null @@ -1,314 +0,0 @@ - - -Strophe.Test = { - BOSH_URL: "/xmpp-httpbind", - XMPP_DOMAIN: 'localhost', - PUBSUB_COMPONENT: "pubsub.localhost", - _node_name: "", //node name created in connectCallback function - connection: null, //connection object created in run function - - run: function() { - $(document).ready(function(){ - //Connect strophe, uses localhost to test - Strophe.Test.connection = new Strophe.Connection(Strophe.Test.BOSH_URL); - - //connect anonymously to run most tests - Strophe.Test.connection.connect(Strophe.Test.XMPP_DOMAIN, - null, - Strophe.Test.connectCallback); - - //set up the test client UI - $("#disconnect").click(function() { - Strophe.Test.connection.disconnect(); - }); - $("#run_tests").click(function() { - test("Anonymous connection test.", function() { - if(Strophe.Test.connection.connected) - { - ok( true, "all good"); - } - else - { - ok( false, "not connected anonymously"); - } - }); - - test("Create default node test.",function(){ - var iqid = Strophe.Test.connection.pubsub - .createNode(Strophe.Test.connection.jid, - Strophe.Test.PUBSUB_COMPONENT, - Strophe.Test._node_name, {}, - function(stanza) { - test("handled create node.", - function() { - var error = $(stanza).find("error"); - - if(error.length == 0) - { - ok(true, "returned"); - } - else - { - ok(false,"error creating node."); - } - }); - }); - ok(true,"sent create request. "+ iqid); - }); - - test("subscribe to a node",function() { - var iqid = Strophe.Test.connection.pubsub - .subscribe(Strophe.Test.connection.jid, - Strophe.Test.PUBSUB_COMPONENT, - Strophe.Test._node_name, - [], - function(stanza) { - test("items received", function() { - console.log(stanza); - if($(stanza).length > 0) - { - ok(true,"item received."); - } - else - { - ok(false,"no items."); - } - }); - }, - function(stanza) { - var error = $(stanza).find("error"); - - test("handled subscribe", - function() { - if(error.length == 0) - { - ok(true,"subscribed"); - } - else - { - console.log(error.get(0)); - ok(false, - "not subscribed"); - } - - }); - }); - - if(iqid) - ok(true, - "subscribed to " + Strophe.Test._node_name); - }); - - test("publish to a node",function() { - var iqid = Strophe.Test.connection.pubsub - .publish(Strophe.Test.connection.jid, - Strophe.Test.PUBSUB_COMPONENT, - Strophe.Test._node_name, - {test:'test'}, - function(stanza) { - var error = $(stanza).find("error"); - - test("handled published item", - function() { - if(error.length == 0) - { - ok(true,"got item"); - } - else - { - ok(false, - "no item"); - } - - }); - }); - - if(iqid) - ok(true, - "published to " + Strophe.Test._node_name); - - }); - - test("subscribe to a node with options",function() { - var keyword_elem = Strophe.xmlElement("field", - [["var", - "http://stanziq.com/search#keyword"], - ["type", - 'text-single'], - ["label", - "keyword to match"]]); - var value = Strophe.xmlElement("value",[]); - var text = Strophe.xmlTextNode("crazy"); - value.appendChild(text); - keyword_elem.appendChild(value); - - var iqid = Strophe.Test.connection.pubsub - .subscribe(Strophe.Test.connection.jid, - Strophe.Test.PUBSUB_COMPONENT, - Strophe.Test._node_name, - [keyword_elem], - function(stanza) {console.log(stanza);}, - function(stanza) { - - var error = $(stanza).find("error"); - - test("handled subscribe with options", - function() { - if(error.length == 0) - { - ok(true,"search subscribed"); - } - else - { - console.log(error.get(0)); - ok(false, - "search not subscribed"); - } - - }); - }); - - if(iqid) - ok(true, - "subscribed to search"); - }); - - test("unsubscribe to a node",function() { - var iqid = Strophe.Test.connection.pubsub - .unsubscribe(Strophe.Test.connection.jid, - Strophe.Test.PUBSUB_COMPONENT, - Strophe.Test._node_name, - function(stanza) { - var error = $(stanza).find("error"); - - test("handled unsubscribe", - function() { - if(error.length == 0) - { - ok(true,"unsubscribed"); - } - else - { - console.log(error.get(0)); - ok(false, - "unable to unsubscribed"); - } - }); - }); - - if(iqid) - ok(true, - "unsubscribed from search with no options."); - }); - - test("test items retrieval",function(){ - var itemid = Strophe.Test.connection.pubsub - .items(Strophe.Test.connection.jid, - Strophe.Test.PUBSUB_COMPONENT, - Strophe.Test._node_name, - function(stanza) { - ok(true,"item request successful."); - }, - function(stanza) { - ok(false,"failed to send request."); - }); - - if(itemid) - { - ok(true,"item request sent."); - } - }); - - test("test sendIQ interface.",function(){ - var sendiq_good = false; - //setup timeout for sendIQ for 3 seconds - setTimeout(function() { - test("Timeout check", function () { - ok(sendiq_good, "The iq didn't timeout."); - }); - }, 3000); - - //send a pubsub subscribe stanza - - var sub = $iq({from:Strophe.Test.connection.jid, - to:Strophe.Test.PUBSUB_COMPONENT, - type:'set'}) - .c('pubsub', { xmlns:Strophe.NS.PUBSUB }) - .c('subscribe', - {node:Strophe.Test._node_name, - jid:Strophe.Test.connection.jid}); - var stanza=sub.tree(); - //call sendIQ with several call backs - Strophe.Test.connection - .sendIQ(stanza, - function(stanza) { - test("iq sent",function() { - sendiq_good = true; - ok(true,"iq sent succesfully."); - }); - }, - function(stz) { - test("iq fail",function() { - if (stz) - sendiq_good = true; - console.log(stanza); - ok(true,"failed to send iq."); - }); - }); - }); - - test("test sendIQ failed.",function(){ - var sub = $iq({from:Strophe.Test.connection.jid, - to:Strophe.Test.PUBSUB_COMPONENT, - type:'get'}); - - //call sendIQ with several call backs - Strophe.Test.connection - .sendIQ(sub.tree(), - function(stanza) { - console.log(stanza); - test("iq sent",function() { - ok(false, - "iq sent succesfully when should have failed."); - }); - }, - function(stanza) { - test("iq fail",function() { - ok(true, - "success on failure test: failed to send iq."); - }); - }); - }); - }); - }); - }, - - connectCallback: function(status,cond) { - var error_message = null; - if(status == Strophe.Status.CONNECTED) - { - $('#run_tests').show(); - $('#disconnect').show(); - var bare_jid = Strophe.getBareJidFromJid(Strophe.Test.connection.jid).split("@")[0]; - Strophe.Test._node_name = "/home/"+Strophe.Test.XMPP_DOMAIN+"/"+bare_jid; - } - else if (status == Strophe.Status.DISCONNECTED || status == Strophe.Status.DICONNECTING) - { - $('#run_tests').hide(); - $('#disconnect').hide(); - } - else if ((status == 0) || (status == Strophe.Status.CONNFAIL)) - { - error_message = "Failed to connect to xmpp server."; - } - else if (status == Strophe.Status.AUTHFAIL) - { - error_message = "Failed to authenticate to xmpp server."; - } - if(error_message) - { - $('published_item').text(error_message); - - } - } -}; diff --git a/public/javascripts/strophejs-1.0.1/tests/strophe.html b/public/javascripts/strophejs-1.0.1/tests/strophe.html deleted file mode 100644 index 49934f5..0000000 --- a/public/javascripts/strophejs-1.0.1/tests/strophe.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - Strophe.js Tests - - -

    Strophe.js Tests

    -

    -

    -
      -
      - - diff --git a/public/javascripts/strophejs-1.0.1/tests/testrunner.js b/public/javascripts/strophejs-1.0.1/tests/testrunner.js deleted file mode 100644 index fd3abd5..0000000 --- a/public/javascripts/strophejs-1.0.1/tests/testrunner.js +++ /dev/null @@ -1,735 +0,0 @@ -/* - * QUnit - jQuery unit testrunner - * - * http://docs.jquery.com/QUnit - * - * Copyright (c) 2008 John Resig, Jörn Zaefferer - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * $Id$ - */ - -(function($) { - -// Tests for equality any JavaScript type and structure without unexpected results. -// Discussions and reference: http://philrathe.com/articles/equiv -// Test suites: http://philrathe.com/tests/equiv -// Author: Philippe Rathé -var equiv = function () { - - var innerEquiv; // the real equiv function - var callers = []; // stack to decide between skip/abort functions - - // Determine what is o. - function hoozit(o) { - if (typeof o === "string") { - return "string"; - - } else if (typeof o === "boolean") { - return "boolean"; - - } else if (typeof o === "number") { - - if (isNaN(o)) { - return "nan"; - } else { - return "number"; - } - - } else if (typeof o === "undefined") { - return "undefined"; - - // consider: typeof null === object - } else if (o === null) { - return "null"; - - // consider: typeof [] === object - } else if (o instanceof Array) { - return "array"; - - // consider: typeof new Date() === object - } else if (o instanceof Date) { - return "date"; - - // consider: /./ instanceof Object; - // /./ instanceof RegExp; - // typeof /./ === "function"; // => false in IE and Opera, - // true in FF and Safari - } else if (o instanceof RegExp) { - return "regexp"; - - } else if (typeof o === "object") { - return "object"; - - } else if (o instanceof Function) { - return "function"; - } - } - - // Call the o related callback with the given arguments. - function bindCallbacks(o, callbacks, args) { - var prop = hoozit(o); - if (prop) { - if (hoozit(callbacks[prop]) === "function") { - return callbacks[prop].apply(callbacks, args); - } else { - return callbacks[prop]; // or undefined - } - } - } - - var callbacks = function () { - - // for string, boolean, number and null - function useStrictEquality(b, a) { - return a === b; - } - - return { - "string": useStrictEquality, - "boolean": useStrictEquality, - "number": useStrictEquality, - "null": useStrictEquality, - "undefined": useStrictEquality, - - "nan": function (b) { - return isNaN(b); - }, - - "date": function (b, a) { - return hoozit(b) === "date" && a.valueOf() === b.valueOf(); - }, - - "regexp": function (b, a) { - return hoozit(b) === "regexp" && - a.source === b.source && // the regex itself - a.global === b.global && // and its modifers (gmi) ... - a.ignoreCase === b.ignoreCase && - a.multiline === b.multiline; - }, - - // - skip when the property is a method of an instance (OOP) - // - abort otherwise, - // initial === would have catch identical references anyway - "function": function () { - var caller = callers[callers.length - 1]; - return caller !== Object && - typeof caller !== "undefined"; - }, - - "array": function (b, a) { - var i; - var len; - - // b could be an object literal here - if ( ! (hoozit(b) === "array")) { - return false; - } - - len = a.length; - if (len !== b.length) { // safe and faster - return false; - } - for (i = 0; i < len; i++) { - if( ! innerEquiv(a[i], b[i])) { - return false; - } - } - return true; - }, - - "object": function (b, a) { - var i; - var eq = true; // unless we can proove it - var aProperties = [], bProperties = []; // collection of strings - - // comparing constructors is more strict than using instanceof - if ( a.constructor !== b.constructor) { - return false; - } - - // stack constructor before traversing properties - callers.push(a.constructor); - - for (i in a) { // be strict: don't ensures hasOwnProperty and go deep - - aProperties.push(i); // collect a's properties - - if ( ! innerEquiv(a[i], b[i])) { - eq = false; - } - } - - callers.pop(); // unstack, we are done - - for (i in b) { - bProperties.push(i); // collect b's properties - } - - // Ensures identical properties name - return eq && innerEquiv(aProperties.sort(), bProperties.sort()); - } - }; - }(); - - innerEquiv = function () { // can take multiple arguments - var args = Array.prototype.slice.apply(arguments); - if (args.length < 2) { - return true; // end transition - } - - return (function (a, b) { - if (a === b) { - return true; // catch the most you can - - } else if (typeof a !== typeof b || a === null || b === null || typeof a === "undefined" || typeof b === "undefined") { - return false; // don't lose time with error prone cases - - } else { - return bindCallbacks(a, callbacks, [b, a]); - } - - // apply transition with (1..n) arguments - })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1)); - }; - - return innerEquiv; -}(); // equiv - -var config = { - stats: { - all: 0, - bad: 0 - }, - queue: [], - // block until document ready - blocking: true, - //restrict modules/tests by get parameters - filters: location.search.length > 1 && $.map( location.search.slice(1).split('&'), decodeURIComponent ), - isLocal: !!(window.location.protocol == 'file:') -}; - -// public API as global methods -$.extend(window, { - test: test, - module: module, - expect: expect, - ok: ok, - equals: equals, - start: start, - stop: stop, - reset: reset, - isLocal: config.isLocal, - same: function(a, b, message) { - push(equiv(a, b), a, b, message); - }, - QUnit: { - equiv: equiv - }, - // legacy methods below - isSet: isSet, - isObj: isObj, - compare: function() { - throw "compare is deprecated - use same() instead"; - }, - compare2: function() { - throw "compare2 is deprecated - use same() instead"; - }, - serialArray: function() { - throw "serialArray is deprecated - use jsDump.parse() instead"; - }, - q: q, - t: t, - url: url, - triggerEvent: triggerEvent -}); - -$(window).load(function() { - $('#userAgent').html(navigator.userAgent); - var head = $('
      ').insertAfter("#userAgent"); - $('').attr("disabled", true).prependTo(head).click(function() { - $('li.pass')[this.checked ? 'hide' : 'show'](); - }); - runTest(); -}); - -function synchronize(callback) { - config.queue.push(callback); - if(!config.blocking) { - process(); - } -} - -function process() { - while(config.queue.length && !config.blocking) { - config.queue.shift()(); - } -} - -function stop(timeout) { - config.blocking = true; - if (timeout) - config.timeout = setTimeout(function() { - ok( false, "Test timed out" ); - start(); - }, timeout); -} -function start() { - // A slight delay, to avoid any current callbacks - setTimeout(function() { - if(config.timeout) - clearTimeout(config.timeout); - config.blocking = false; - process(); - }, 13); -} - -function validTest( name ) { - var filters = config.filters; - if( !filters ) - return true; - - var i = filters.length, - run = false; - while( i-- ){ - var filter = filters[i], - not = filter.charAt(0) == '!'; - if( not ) - filter = filter.slice(1); - if( name.indexOf(filter) != -1 ) - return !not; - if( not ) - run = true; - } - return run; -} - -function runTest() { - config.blocking = false; - var started = +new Date; - config.fixture = document.getElementById('main').innerHTML; - config.ajaxSettings = $.ajaxSettings; - synchronize(function() { - $('

      ').html(['Tests completed in ', - +new Date - started, ' milliseconds.
      ', - '', config.stats.bad, ' tests of ', config.stats.all, ' failed.

      '] - .join('')) - .appendTo("body"); - $("#banner").addClass(config.stats.bad ? "fail" : "pass"); - }); -} - -function test(name, callback) { - if(config.currentModule) - name = config.currentModule + " module: " + name; - var lifecycle = $.extend({ - setup: function() {}, - teardown: function() {} - }, config.moduleLifecycle); - - if ( !validTest(name) ) - return; - - synchronize(function() { - config.assertions = []; - config.expected = null; - try { - lifecycle.setup(); - callback(); - lifecycle.teardown(); - } catch(e) { - if( typeof console != "undefined" && console.error && console.warn ) { - console.error("Test " + name + " died, exception and test follows"); - console.error(e); - console.warn(callback.toString()); - } - config.assertions.push( { - result: false, - message: "Died on test #" + (config.assertions.length + 1) + ": " + e.message - }); - } - }); - synchronize(function() { - try { - reset(); - } catch(e) { - if( typeof console != "undefined" && console.error && console.warn ) { - console.error("reset() failed, following Test " + name + ", exception and reset fn follows"); - console.error(e); - console.warn(reset.toString()); - } - } - - if(config.expected && config.expected != config.assertions.length) { - config.assertions.push({ - result: false, - message: "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" - }); - } - - var good = 0, bad = 0; - var ol = $("
        ").hide(); - config.stats.all += config.assertions.length; - for ( var i = 0; i < config.assertions.length; i++ ) { - var assertion = config.assertions[i]; - $("
      1. ").addClass(assertion.result ? "pass" : "fail").text(assertion.message || "(no message)").appendTo(ol); - assertion.result ? good++ : bad++; - } - config.stats.bad += bad; - - var b = $("").html(name + " (" + bad + ", " + good + ", " + config.assertions.length + ")") - .click(function(){ - $(this).next().toggle(); - }) - .dblclick(function(event) { - var target = $(event.target).filter("strong").clone(); - if ( target.length ) { - target.children().remove(); - location.href = location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent($.trim(target.text())); - } - }); - - $("
      2. ").addClass(bad ? "fail" : "pass").append(b).append(ol).appendTo("#tests"); - - if(bad) { - $("#filter").attr("disabled", null); - } - }); -} - -// call on start of module test to prepend name to all tests -function module(name, lifecycle) { - config.currentModule = name; - config.moduleLifecycle = lifecycle; -} - -/** - * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. - */ -function expect(asserts) { - config.expected = asserts; -} - -/** - * Resets the test setup. Useful for tests that modify the DOM. - */ -function reset() { - $("#main").html( config.fixture ); - $.event.global = {}; - $.ajaxSettings = $.extend({}, config.ajaxSettings); -} - -/** - * Asserts true. - * @example ok( $("a").size() > 5, "There must be at least 5 anchors" ); - */ -function ok(a, msg) { - config.assertions.push({ - result: !!a, - message: msg - }); -} - -/** - * Asserts that two arrays are the same - */ -function isSet(a, b, msg) { - function serialArray( a ) { - var r = []; - - if ( a && a.length ) - for ( var i = 0; i < a.length; i++ ) { - var str = a[i].nodeName; - if ( str ) { - str = str.toLowerCase(); - if ( a[i].id ) - str += "#" + a[i].id; - } else - str = a[i]; - r.push( str ); - } - - return "[ " + r.join(", ") + " ]"; - } - var ret = true; - if ( a && b && a.length != undefined && a.length == b.length ) { - for ( var i = 0; i < a.length; i++ ) - if ( a[i] != b[i] ) - ret = false; - } else - ret = false; - config.assertions.push({ - result: ret, - message: !ret ? (msg + " expected: " + serialArray(b) + " result: " + serialArray(a)) : msg - }); -} - -/** - * Asserts that two objects are equivalent - */ -function isObj(a, b, msg) { - var ret = true; - - if ( a && b ) { - for ( var i in a ) - if ( a[i] != b[i] ) - ret = false; - - for ( i in b ) - if ( a[i] != b[i] ) - ret = false; - } else - ret = false; - - config.assertions.push({ - result: ret, - message: msg - }); -} - -/** - * Returns an array of elements with the given IDs, eg. - * @example q("main", "foo", "bar") - * @result [
        , , ] - */ -function q() { - var r = []; - for ( var i = 0; i < arguments.length; i++ ) - r.push( document.getElementById( arguments[i] ) ); - return r; -} - -/** - * Asserts that a select matches the given IDs - * @example t("Check for something", "//[a]", ["foo", "baar"]); - * @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baar' - */ -function t(a,b,c) { - var f = $(b); - var s = ""; - for ( var i = 0; i < f.length; i++ ) - s += (s && ",") + '"' + f[i].id + '"'; - isSet(f, q.apply(q,c), a + " (" + b + ")"); -} - -/** - * Add random number to url to stop IE from caching - * - * @example url("data/test.html") - * @result "data/test.html?10538358428943" - * - * @example url("data/test.php?foo=bar") - * @result "data/test.php?foo=bar&10538358345554" - */ -function url(value) { - return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random()*100000); -} - -/** - * Checks that the first two arguments are equal, with an optional message. - * Prints out both actual and expected values. - * - * Prefered to ok( actual == expected, message ) - * - * @example equals( $.format("Received {0} bytes.", 2), "Received 2 bytes." ); - * - * @param Object actual - * @param Object expected - * @param String message (optional) - */ -function equals(actual, expected, message) { - push(expected == actual, actual, expected, message); -} - -function push(result, actual, expected, message) { - message = message || (result ? "okay" : "failed"); - config.assertions.push({ - result: result, - message: result ? message + ": " + expected : message + ", expected: " + jsDump.parse(expected) + " result: " + jsDump.parse(actual) - }); -} - -/** - * Trigger an event on an element. - * - * @example triggerEvent( document.body, "click" ); - * - * @param DOMElement elem - * @param String type - */ -function triggerEvent( elem, type, event ) { - if ( $.browser.mozilla || $.browser.opera ) { - event = document.createEvent("MouseEvents"); - event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, - 0, 0, 0, 0, 0, false, false, false, false, 0, null); - elem.dispatchEvent( event ); - } else if ( $.browser.msie ) { - elem.fireEvent("on"+type); - } -} - -})(jQuery); - -/** - * jsDump - * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com - * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php) - * Date: 5/15/2008 - * @projectDescription Advanced and extensible data dumping for Javascript. - * @version 1.0.0 - * @author Ariel Flesler - * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} - */ -(function(){ - function quote( str ){ - return '"' + str.toString().replace(/"/g, '\\"') + '"'; - }; - function literal( o ){ - return o + ''; - }; - function join( pre, arr, post ){ - var s = jsDump.separator(), - base = jsDump.indent(); - inner = jsDump.indent(1); - if( arr.join ) - arr = arr.join( ',' + s + inner ); - if( !arr ) - return pre + post; - return [ pre, inner + arr, base + post ].join(s); - }; - function array( arr ){ - var i = arr.length, ret = Array(i); - this.up(); - while( i-- ) - ret[i] = this.parse( arr[i] ); - this.down(); - return join( '[', ret, ']' ); - }; - - var reName = /^function (\w+)/; - - var jsDump = window.jsDump = { - parse:function( obj, type ){//type is used mostly internally, you can fix a (custom)type in advance - var parser = this.parsers[ type || this.typeOf(obj) ]; - type = typeof parser; - - return type == 'function' ? parser.call( this, obj ) : - type == 'string' ? parser : - this.parsers.error; - }, - typeOf:function( obj ){ - var type = typeof obj, - f = 'function';//we'll use it 3 times, save it - return type != 'object' && type != f ? type : - !obj ? 'null' : - obj.exec ? 'regexp' :// some browsers (FF) consider regexps functions - obj.getHours ? 'date' : - obj.scrollBy ? 'window' : - obj.nodeName == '#document' ? 'document' : - obj.nodeName ? 'node' : - obj.item ? 'nodelist' : // Safari reports nodelists as functions - obj.callee ? 'arguments' : - obj.call || obj.constructor != Array && //an array would also fall on this hack - (obj+'').indexOf(f) != -1 ? f : //IE reports functions like alert, as objects - 'length' in obj ? 'array' : - type; - }, - separator:function(){ - return this.multiline ? this.HTML ? '
        ' : '\n' : this.HTML ? ' ' : ' '; - }, - indent:function( extra ){// extra can be a number, shortcut for increasing-calling-decreasing - if( !this.multiline ) - return ''; - var chr = this.indentChar; - if( this.HTML ) - chr = chr.replace(/\t/g,' ').replace(/ /g,' '); - return Array( this._depth_ + (extra||0) ).join(chr); - }, - up:function( a ){ - this._depth_ += a || 1; - }, - down:function( a ){ - this._depth_ -= a || 1; - }, - setParser:function( name, parser ){ - this.parsers[name] = parser; - }, - // The next 3 are exposed so you can use them - quote:quote, - literal:literal, - join:join, - // - _depth_: 1, - // This is the list of parsers, to modify them, use jsDump.setParser - parsers:{ - window: '[Window]', - document: '[Document]', - error:'[ERROR]', //when no parser is found, shouldn't happen - unknown: '[Unknown]', - 'null':'null', - undefined:'undefined', - 'function':function( fn ){ - var ret = 'function', - name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE - if( name ) - ret += ' ' + name; - ret += '('; - - ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join(''); - return join( ret, this.parse(fn,'functionCode'), '}' ); - }, - array: array, - nodelist: array, - arguments: array, - object:function( map ){ - var ret = [ ]; - this.up(); - for( var key in map ) - ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) ); - this.down(); - return join( '{', ret, '}' ); - }, - node:function( node ){ - var open = this.HTML ? '<' : '<', - close = this.HTML ? '>' : '>'; - - var tag = node.nodeName.toLowerCase(), - ret = open + tag; - - for( var a in this.DOMAttrs ){ - var val = node[this.DOMAttrs[a]]; - if( val ) - ret += ' ' + a + '=' + this.parse( val, 'attribute' ); - } - return ret + close + open + '/' + tag + close; - }, - functionArgs:function( fn ){//function calls it internally, it's the arguments part of the function - var l = fn.length; - if( !l ) return ''; - - var args = Array(l); - while( l-- ) - args[l] = String.fromCharCode(97+l);//97 is 'a' - return ' ' + args.join(', ') + ' '; - }, - key:quote, //object calls it internally, the key part of an item in a map - functionCode:'[code]', //function calls it internally, it's the content of the function - attribute:quote, //node calls it internally, it's an html attribute value - string:quote, - date:quote, - regexp:literal, //regex - number:literal, - 'boolean':literal - }, - DOMAttrs:{//attributes to dump from nodes, name=>realName - id:'id', - name:'name', - 'class':'className' - }, - HTML:false,//if true, entities are escaped ( <, >, \t, space and \n ) - indentChar:' ',//indentation unit - multiline:true //if true, items in a collection, are separated by a \n, else just a space. - }; - -})(); diff --git a/public/javascripts/strophejs-1.0.1/tests/tests.js b/public/javascripts/strophejs-1.0.1/tests/tests.js deleted file mode 100644 index 13045ec..0000000 --- a/public/javascripts/strophejs-1.0.1/tests/tests.js +++ /dev/null @@ -1,163 +0,0 @@ -$(document).ready(function () { - module("JIDs"); - - test("Normal JID", function () { - var jid = "darcy@pemberley.lit/library"; - equals(Strophe.getNodeFromJid(jid), "darcy", - "Node should be 'darcy'"); - equals(Strophe.getDomainFromJid(jid), "pemberley.lit", - "Domain should be 'pemberley.lit'"); - equals(Strophe.getResourceFromJid(jid), "library", - "Node should be 'library'"); - equals(Strophe.getBareJidFromJid(jid), - "darcy@pemberley.lit", - "Bare JID should be 'darcy@pemberley.lit'"); - }); - - test("Weird node (unescaped)", function () { - var jid = "darcy@netherfield.lit@pemberley.lit/library"; - equals(Strophe.getNodeFromJid(jid), "darcy", - "Node should be 'darcy'"); - equals(Strophe.getDomainFromJid(jid), - "netherfield.lit@pemberley.lit", - "Domain should be 'netherfield.lit@pemberley.lit'"); - equals(Strophe.getResourceFromJid(jid), "library", - "Resource should be 'library'"); - equals(Strophe.getBareJidFromJid(jid), - "darcy@netherfield.lit@pemberley.lit", - "Bare JID should be 'darcy@netherfield.lit@pemberley.lit'"); - }); - - test("Weird node (escaped)", function () { - var escapedNode = Strophe.escapeNode("darcy@netherfield.lit"); - var jid = escapedNode + "@pemberley.lit/library"; - equals(Strophe.getNodeFromJid(jid), "darcy\\40netherfield.lit", - "Node should be 'darcy\\40netherfield.lit'"); - equals(Strophe.getDomainFromJid(jid), - "pemberley.lit", - "Domain should be 'pemberley.lit'"); - equals(Strophe.getResourceFromJid(jid), "library", - "Resource should be 'library'"); - equals(Strophe.getBareJidFromJid(jid), - "darcy\\40netherfield.lit@pemberley.lit", - "Bare JID should be 'darcy\\40netherfield.lit@pemberley.lit'"); - }); - - test("Weird resource", function () { - var jid = "books@chat.pemberley.lit/darcy@pemberley.lit/library"; - equals(Strophe.getNodeFromJid(jid), "books", - "Node should be 'books'"); - equals(Strophe.getDomainFromJid(jid), "chat.pemberley.lit", - "Domain should be 'chat.pemberley.lit'"); - equals(Strophe.getResourceFromJid(jid), - "darcy@pemberley.lit/library", - "Resource should be 'darcy@pemberley.lit/library'"); - equals(Strophe.getBareJidFromJid(jid), - "books@chat.pemberley.lit", - "Bare JID should be 'books@chat.pemberley.lit'"); - }); - - module("Builder"); - - test("Correct namespace (#32)", function () { - var stanzas = [new Strophe.Builder("message", {foo: "asdf"}).tree(), - $build("iq", {}).tree(), - $pres().tree()]; - $.each(stanzas, function () { - equals($(this).attr('xmlns'), Strophe.NS.CLIENT, - "Namespace should be '" + Strophe.NS.CLIENT + "'"); - }); - }); - - test("send() accepts Builders (#27)", function () { - var stanza = $pres(); - var conn = new Strophe.Connection(""); - // fake connection callback to avoid errors - conn.connect_callback = function () {}; - - ok(conn._data.length === 0, "Output queue is clean"); - try { - conn.send(stanza); - } catch (e) {} - ok(conn._data.length === 1, "Output queue contains an element"); - }); - - test("send() does not accept strings", function () { - var stanza = ""; - var conn = new Strophe.Connection(""); - // fake connection callback to avoid errors - conn.connect_callback = function () {}; - expect(1); - try { - conn.send(stanza); - } catch (e) { - equals(e.name, "StropheError", "send() should throw exception"); - } - }); - - test("Builder with XML attribute escaping test", function () { - var text = ""; - var expected = ""; - var pres = $pres({to: text}); - equals(pres.toString(), expected, "< should be escaped"); - - text = "foo&bar"; - expected = ""; - pres = $pres({to: text}); - equals(pres.toString(), expected, "& should be escaped"); - }); - - module("XML"); - - test("XML escaping test", function () { - var text = "s & p"; - var textNode = Strophe.xmlTextNode(text); - equals(Strophe.getText(textNode), "s & p", "should be escaped"); - var text0 = "s < & > p"; - var textNode0 = Strophe.xmlTextNode(text0); - equals(Strophe.getText(textNode0), "s < & > p", "should be escaped"); - }); - - test("XML element creation", function () { - var elem = Strophe.xmlElement("message"); - equals(elem.tagName, "message", "Element name should be the same"); - }); - - module("Handler"); - - test("Full JID matching", function () { - var elem = $msg({from: 'darcy@pemberley.lit/library'}).tree(); - - var hand = new Strophe.Handler(null, null, null, null, null, - 'darcy@pemberley.lit/library'); - equals(hand.isMatch(elem), true, "Full JID should match"); - - hand = new Strophe.Handler(null, null, null, null, null, - 'darcy@pemberley.lit') - equals(hand.isMatch(elem), false, "Bare JID shouldn't match"); - }); - - test("Bare JID matching", function () { - var elem = $msg({from: 'darcy@pemberley.lit/library'}).tree(); - - var hand = new Strophe.Handler(null, null, null, null, null, - 'darcy@pemberley.lit/library', - {matchBare: true}); - equals(hand.isMatch(elem), true, "Full JID should match"); - - hand = new Strophe.Handler(null, null, null, null, null, - 'darcy@pemberley.lit', - {matchBare: true}); - equals(hand.isMatch(elem), true, "Bare JID should match"); - }); - - module("Misc"); - - test("Quoting strings", function () { - var input = '"beep \\40"'; - var conn = new Strophe.Connection(); - var output = conn._quote(input); - equals(output, "\"\\\"beep \\\\40\\\"\"", - "string should be quoted and escaped"); - }); -}); diff --git a/public/javascripts/strophejs-1.0.1/tests/testsuite.css b/public/javascripts/strophejs-1.0.1/tests/testsuite.css deleted file mode 100644 index dbfc43a..0000000 --- a/public/javascripts/strophejs-1.0.1/tests/testsuite.css +++ /dev/null @@ -1,120 +0,0 @@ -body, div, h1 { font-family: 'trebuchet ms', verdana, arial; margin: 0; padding: 0 } -body {font-size: 10pt; } -h1 { padding: 15px; font-size: large; background-color: #06b; color: white; } -h1 a { color: white; } -h2 { padding: 10px; background-color: #eee; color: black; margin: 0; font-size: small; font-weight: normal } - -.pass { color: green; } -.fail { color: red; } -p.result { margin-left: 1em; } - -#banner { height: 2em; border-bottom: 1px solid white; } -h2.pass { background-color: green; } -h2.fail { background-color: red; } - -div.testrunner-toolbar { background: #eee; border-top: 1px solid black; padding: 10px; } - -ol#tests > li > strong { cursor:pointer; } - -div#fx-tests h4 { - background: red; -} - -div#fx-tests h4.pass { - background: green; -} - -div#fx-tests div.box { - background: red url(data/cow.jpg) no-repeat; - overflow: hidden; - border: 2px solid #000; -} - -div#fx-tests div.overflow { - overflow: visible; -} - -div.inline { - display: inline; -} - -div.autoheight { - height: auto; -} - -div.autowidth { - width: auto; -} - -div.autoopacity { - opacity: auto; -} - -div.largewidth { - width: 100px; -} - -div.largeheight { - height: 100px; -} - -div.largeopacity { - filter: progid:DXImageTransform.Microsoft.Alpha(opacity=100); -} - -div.medwidth { - width: 50px; -} - -div.medheight { - height: 50px; -} - -div.medopacity { - opacity: 0.5; - filter: progid:DXImageTransform.Microsoft.Alpha(opacity=50); -} - -div.nowidth { - width: 0px; -} - -div.noheight { - height: 0px; -} - -div.noopacity { - opacity: 0; - filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0); -} - -div.hidden { - display: none; -} - -div#fx-tests div.widewidth { - background-repeat: repeat-x; -} - -div#fx-tests div.wideheight { - background-repeat: repeat-y; -} - -div#fx-tests div.widewidth.wideheight { - background-repeat: repeat; -} - -div#fx-tests div.noback { - background-image: none; -} - -div.chain, div.chain div { width: 100px; height: 20px; position: relative; float: left; } -div.chain div { position: absolute; top: 0px; left: 0px; } - -div.chain.test { background: red; } -div.chain.test div { background: green; } - -div.chain.out { background: green; } -div.chain.out div { background: red; display: none; } - -div#show-tests * { display: none; } diff --git a/public/javascripts/strophejs-1.0.1/tests/yuitests.html b/public/javascripts/strophejs-1.0.1/tests/yuitests.html deleted file mode 100644 index 478b1b4..0000000 --- a/public/javascripts/strophejs-1.0.1/tests/yuitests.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - Strophe Tests - - - - - - - - - - - -
        - - diff --git a/public/javascripts/strophejs-1.0.1/tests/yuitests.js b/public/javascripts/strophejs-1.0.1/tests/yuitests.js deleted file mode 100644 index 076d985..0000000 --- a/public/javascripts/strophejs-1.0.1/tests/yuitests.js +++ /dev/null @@ -1,26 +0,0 @@ -YUI().use("test", "console", function (Y) { - Y.namespace("strophe.test"); - var Assert = Y.Assert; - - Y.strophe.test.JIDTestCase = new Y.Test.Case({ - name: "JIDs", - - testNormalJid: function () { - var jid = "darcy@pemberley.lit/library"; - - Assert.areSame("darcy", Strophe.getNodeFromJid(jid)); - Assert.areSame("pemberley.lit", Strophe.getDomainFromJid(jid)); - Assert.areSame("library", Strophe.getResourceFromJid(jid)); - Assert.areSame("darcy@pemberley.lit", - Strophe.getBareJidFromJid(jid)); - } - }); - - Y.strophe.test.StropheSuite = new Y.Test.Suite("Strophe Suite"); - Y.strophe.test.StropheSuite.add(Y.strophe.test.JIDTestCase); - - new Y.Console({newestOnTop: false}).render('#console'); - - Y.Test.Runner.add(Y.strophe.test.StropheSuite); - Y.Test.Runner.run(); -}); diff --git a/public/javascripts/strophejs-1.1.3/LICENSE.txt b/public/javascripts/strophejs-1.1.3/LICENSE.txt new file mode 100644 index 0000000..06d6642 --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2006-2009 Collecta, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/public/javascripts/strophejs-1.1.3/README.txt b/public/javascripts/strophejs-1.1.3/README.txt new file mode 100644 index 0000000..ca73fe1 --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/README.txt @@ -0,0 +1,15 @@ +Strophe.js is a JavaScript library for speaking XMPP via BOSH (XEP 124 +and 206) and WebSockets (draft-ietf-xmpp-websocket-00). It is +licensed under the MIT license, except for the files sha1.js, base64.js +and md5.js, which are licensed as public domain and BSD (see these files +for details). + +It has been tested on Firefox, Firefox for Android, IE, Safari, Mobile Safari, +Chrome, Chrome for Android, Opera and the mobile Opera browser. + +The homepage for Strophe is http://strophe.im/strophejs + +The book Professional XMPP Programming with JavaScript and jQuery is +also available, which covers Strophe in detail in the context of web +applications. You can find more information at +http://professionalxmpp.com. diff --git a/public/javascripts/strophejs-1.1.3/contrib/discojs/README.txt b/public/javascripts/strophejs-1.1.3/contrib/discojs/README.txt new file mode 100644 index 0000000..78e1dbc --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/contrib/discojs/README.txt @@ -0,0 +1,42 @@ +Disco Dancing with XMPP + + There are many things one can do via XMPP. The list is + endlist. But one thing that some forget about is discovering + services a XMPP entity or server provides. In most cases a human or + user does not care about this information and should not care. But + you may have a website or web application that needs this + information in order to decide what options to show to your + users. You can do this very easily with JQuery, Strophe, and + Punjab. + + We start with Punjab or a BOSH connection manager. This is + needed so we can connect to a XMPP server. First, lets download + punjab. + + svn co https://code.stanziq.com/svn/punjab/trunk punjab + + After we have punjab go into the directory and install punjab. + + cd punjab + python setup.py install + + Then create a .tac file to configure Punjab. + + See punjab.tac + + Next, we will need Strophe. Lets download thelatest version from + svn too. + + cd /directory/where/you/configured/punjab/html + + svn co https://code.stanziq.com/svn/strophe/trunk/strophejs + + In your html directory you will then begin to create your disco browser. + + Version 1 we take the basic example and modify it to do disco. + + Version 2 we add anonymous login + + Version 3 we make it pretty + + Version 4 we add handlers for different services diff --git a/public/javascripts/strophejs-1.1.3/contrib/discojs/css/disco.css b/public/javascripts/strophejs-1.1.3/contrib/discojs/css/disco.css new file mode 100644 index 0000000..4ffdd97 --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/contrib/discojs/css/disco.css @@ -0,0 +1,16 @@ +#login .leftinput +{ + margin-bottom: .5em; +} + +#login input +{ + margin-bottom: 10px; +} + +#log { + width: 100%; + height: 200px; + overflow: auto; + + } diff --git a/public/javascripts/strophejs-1.1.3/contrib/discojs/index.html b/public/javascripts/strophejs-1.1.3/contrib/discojs/index.html new file mode 100644 index 0000000..e2ed869 --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/contrib/discojs/index.html @@ -0,0 +1,47 @@ + + + + XMPP Disco Dancing + + + + + + + + + + +
        +
        + + + + + +
        +
        +
        +
        +
        +
        +
        + + + diff --git a/public/javascripts/strophejs-1.1.3/contrib/discojs/punjab.tac b/public/javascripts/strophejs-1.1.3/contrib/discojs/punjab.tac new file mode 100644 index 0000000..7b2e8c6 --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/contrib/discojs/punjab.tac @@ -0,0 +1,18 @@ +# punjab tac file +from twisted.web import server, resource, static +from twisted.application import service, internet + +from punjab.httpb import Httpb, HttpbService + +root = static.File("./") # This needs to be the directory + # where you will have your html + # and javascript. + +b = resource.IResource(HttpbService(1)) # turn on debug with 1 +root.putChild('bosh', b) + + +site = server.Site(root) + +application = service.Application("punjab") +internet.TCPServer(5280, site).setServiceParent(application) diff --git a/public/javascripts/strophejs-1.1.3/contrib/discojs/scripts/basic.js b/public/javascripts/strophejs-1.1.3/contrib/discojs/scripts/basic.js new file mode 100644 index 0000000..4e01f08 --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/contrib/discojs/scripts/basic.js @@ -0,0 +1,102 @@ +var BOSH_SERVICE = 'http://localhost:5280/bosh'; + +var connection = null; +var browser = null; +var show_log = true; + +function log(msg) +{ + $('#log').append('
        ').append(document.createTextNode(msg)); +} + + +function rawInput(data) +{ + log('RECV: ' + data); +} + +function rawOutput(data) +{ + log('SENT: ' + data); +} + +function onConnect(status) +{ + if (status == Strophe.Status.CONNECTING) { + log('Strophe is connecting.'); + + } else if (status == Strophe.Status.CONNFAIL) { + log('Strophe failed to connect.'); + showConnect(); + } else if (status == Strophe.Status.DISCONNECTING) { + log('Strophe is disconnecting.'); + } else if (status == Strophe.Status.DISCONNECTED) { + log('Strophe is disconnected.'); + showConnect(); + + } else if (status == Strophe.Status.CONNECTED) { + log('Strophe is connected.'); + // Start up disco browser + browser.showBrowser(); + } +} + +function showConnect() +{ + var jid = $('#jid'); + var pass = $('#pass'); + var button = $('#connect').get(0); + + browser.closeBrowser(); + + $('label').show(); + jid.show(); + pass.show(); + $('#anon').show(); + button.value = 'connect'; + return false; +} + +function showDisconnect() +{ + var jid = $('#jid'); + var pass = $('#pass'); + var button = $('#connect').get(0); + + button.value = 'disconnect'; + pass.hide(); + jid.hide(); + $('label').hide(); + $('#anon').hide(); + return false; +} + +$(document).ready(function () { + connection = new Strophe.Connection(BOSH_SERVICE); + connection.rawInput = rawInput; + connection.rawOutput = rawOutput; + + browser = new Disco(); + + $("#log_container").bind('click', function () { + $("#log").toggle(); + } + ); + + $('#cred').bind('submit', function () { + var button = $('#connect').get(0); + var jid = $('#jid'); + var pass = $('#pass'); + + if (button.value == 'connect') { + showDisconnect(); + connection.connect(jid.get(0).value, + pass.get(0).value, + onConnect); + } else { + connection.disconnect(); + showConnect(); + } + return false; + }); +}); \ No newline at end of file diff --git a/public/javascripts/strophejs-1.1.3/contrib/discojs/scripts/disco.js b/public/javascripts/strophejs-1.1.3/contrib/discojs/scripts/disco.js new file mode 100644 index 0000000..a1d7ed5 --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/contrib/discojs/scripts/disco.js @@ -0,0 +1,60 @@ + +var NS_DISCO_INFO = 'http://jabber.org/protocol/disco#info'; +var NS_DISCO_ITEM = 'http://jabber.org/protocol/disco#items'; + + +// Disco stuff +Disco = function () { + // Class that does nothing +}; + +Disco.prototype = { + showBrowser: function() { + // Browser Display + var disco = $('#disco'); + var jid = $('#jid'); + var server = connection.jid.split('@')[1]; + + // display input box + disco.append("
        Server :
        "); + + // add handler for search form + $("#browse").bind('submit', function () { + this.startBrowse($("#server").get(0).value); + return false; + }); + + this.startBrowse(server); + }, + + closeBrowser: function() { + var disco = $('#disco'); + + disco.empty(); + }, + + startBrowse: function(server) { + // build iq request + var id = 'startBrowse'; + + var discoiq = $iq({'from':connection.jid+"/"+connection.resource, + 'to':server, + 'id':id, + 'type':'get'} + ) + .c('query', {'xmlns': NS_DISCO_INFO}); + + connection.addHandler(this._cbBrowse, null, 'iq', 'result', id); + connection.send(discoiq.tree()); + + }, + + _cbBrowse: function(e) { + var elem = $(e); // make this Element a JQuery Element + alert(e); + + return false; // return false to remove the handler + }, + +}; + diff --git a/public/javascripts/strophejs-1.1.3/doc/files/strophe-js.html b/public/javascripts/strophejs-1.1.3/doc/files/strophe-js.html new file mode 100644 index 0000000..0cb8afe --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/doc/files/strophe-js.html @@ -0,0 +1,241 @@ + + +strophe.js + + + + + + + + + +

        strophe.js

        A JavaScript library for XMPP BOSH/XMPP over Websocket.

        This is the JavaScript version of the Strophe library.  Since JavaScript had no facilities for persistent TCP connections, this library uses Bidirectional-streams Over Synchronous HTTP (BOSH) to emulate a persistent, stateful, two-way connection to an XMPP server.  More information on BOSH can be found in XEP 124.

        This version of Strophe also works with WebSockets.  For more information on XMPP-over WebSocket see this RFC draft: http://tools.ietf.org/html/draft-ietf-xmpp-websocket-00

        Summary
        strophe.jsA JavaScript library for XMPP BOSH/XMPP over Websocket.
        Functions
        $buildCreate a Strophe.Builder.
        $msgCreate a Strophe.Builder with a <message/> element as the root.
        $iqCreate a Strophe.Builder with an <iq/> element as the root.
        $presCreate a Strophe.Builder with a <presence/> element as the root.
        StropheAn object container for all Strophe library functions.
        Constants
        VERSIONThe version of the Strophe library.
        XMPP Namespace ConstantsCommon namespace constants from the XMPP RFCs and XEPs.
        XHTML_IM Namespacecontains allowed tags, tag attributes, and css properties.
        Connection Status ConstantsConnection status constants for use by the connection handler callback.
        Log Level ConstantsLogging level indicators.
        Functions
        addNamespaceThis function is used to extend the current namespaces in Strophe.NS.
        forEachChildMap a function over some or all child elements of a given element.
        isTagEqualCompare an element’s tag name with a string.
        xmlGeneratorGet the DOM document to generate elements.
        xmlElementCreate an XML DOM element.
        xmlescapeExcapes invalid xml characters.
        xmlTextNodeCreates an XML DOM text node.
        xmlHtmlNodeCreates an XML DOM html node.
        getTextGet the concatenation of all text children of an element.
        copyElementCopy an XML DOM element.
        createHtmlCopy an HTML DOM element into an XML DOM.
        escapeNodeEscape the node part (also called local part) of a JID.
        unescapeNodeUnescape a node part (also called local part) of a JID.
        getNodeFromJidGet the node portion of a JID String.
        getDomainFromJidGet the domain portion of a JID String.
        getResourceFromJidGet the resource portion of a JID String.
        getBareJidFromJidGet the bare JID from a JID String.
        logUser overrideable logging function.
        debugLog a message at the Strophe.LogLevel.DEBUG level.
        infoLog a message at the Strophe.LogLevel.INFO level.
        warnLog a message at the Strophe.LogLevel.WARN level.
        errorLog a message at the Strophe.LogLevel.ERROR level.
        fatalLog a message at the Strophe.LogLevel.FATAL level.
        serializeRender a DOM element and all descendants to a String.
        addConnectionPluginExtends the Strophe.Connection object with the given plugin.
        Strophe.BuilderXML DOM builder.
        Functions
        Strophe.BuilderCreate a Strophe.Builder object.
        treeReturn the DOM tree.
        toStringSerialize the DOM tree to a String.
        upMake the current parent element the new current element.
        attrsAdd or modify attributes of the current element.
        cAdd a child to the current element and make it the new current element.
        cnodeAdd a child to the current element and make it the new current element.
        tAdd a child text element.
        hReplace current element contents with the HTML passed in.
        Strophe.ConnectionXMPP Connection manager.
        Functions
        Strophe.ConnectionCreate and initialize a Strophe.Connection object.
        resetReset the connection.
        pausePause the request manager.
        resumeResume the request manager.
        getUniqueIdGenerate a unique ID for use in <iq/> elements.
        connectStarts the connection process.
        Variables
        authzidAuthorization identity.
        authcidAuthentication identity (User name).
        passAuthentication identity (User password).
        servtypeDigest MD5 compatibility.
        Functions
        attachAttach to an already created and authenticated BOSH session.
        xmlInputUser overrideable function that receives XML data coming into the connection.
        xmlOutputUser overrideable function that receives XML data sent to the connection.
        rawInputUser overrideable function that receives raw data coming into the connection.
        rawOutputUser overrideable function that receives raw data sent to the connection.
        sendSend a stanza.
        flushImmediately send any pending outgoing data.
        sendIQHelper function to send IQ stanzas.
        addTimedHandlerAdd a timed handler to the connection.
        deleteTimedHandlerDelete a timed handler for a connection.
        addHandlerAdd a stanza handler for the connection.
        deleteHandlerDelete a stanza handler for a connection.
        disconnectStart the graceful disconnection process.
        authenticateSet up authentication
        Strophe.SASLMechanismencapsulates SASL authentication mechanisms.
        Variables
        priorityDetermines which SASLMechanism is chosen for authentication (Higher is better).
        Functions
        testChecks if mechanism able to run.
        Constants
        SASL mechanismsAvailable authentication mechanisms
        Strophe.BoshPrivate helper class that handles BOSH Connections
        Files
        bosh.jsA JavaScript library to enable BOSH in Strophejs.
        Variables
        stripBOSH-Connections will have all stanzas wrapped in a <body> tag when passed to Strophe.Connection.xmlInput or Strophe.Connection.xmlOutput.
        Strophe.WebSocketPrivate helper class that handles WebSocket Connections
        Files
        websocket.jsA JavaScript library to enable XMPP over Websocket in Strophejs.
        + +

        Functions

        + +

        $build

        function $build(name,
        attrs)

        Create a Strophe.Builder.  This is an alias for ‘new Strophe.Builder(name, attrs)’.

        Parameters

        (String) nameThe root element name.
        (Object) attrsThe attributes for the root element in object notation.

        Returns

        A new Strophe.Builder object.

        + +

        $msg

        function $msg(attrs)

        Create a Strophe.Builder with a <message/> element as the root.

        Parmaeters

        (Object) attrsThe <message/> element attributes in object notation.

        Returns

        A new Strophe.Builder object.

        + +

        $iq

        function $iq(attrs)

        Create a Strophe.Builder with an <iq/> element as the root.

        Parameters

        (Object) attrsThe <iq/> element attributes in object notation.

        Returns

        A new Strophe.Builder object.

        + +

        $pres

        function $pres(attrs)

        Create a Strophe.Builder with a <presence/> element as the root.

        Parameters

        (Object) attrsThe <presence/> element attributes in object notation.

        Returns

        A new Strophe.Builder object.

        + +

        Strophe

        An object container for all Strophe library functions.

        This class is just a container for all the objects and constants used in the library.  It is not meant to be instantiated, but to provide a namespace for library objects, constants, and functions.

        Summary
        Constants
        VERSIONThe version of the Strophe library.
        XMPP Namespace ConstantsCommon namespace constants from the XMPP RFCs and XEPs.
        XHTML_IM Namespacecontains allowed tags, tag attributes, and css properties.
        Connection Status ConstantsConnection status constants for use by the connection handler callback.
        Log Level ConstantsLogging level indicators.
        Functions
        addNamespaceThis function is used to extend the current namespaces in Strophe.NS.
        forEachChildMap a function over some or all child elements of a given element.
        isTagEqualCompare an element’s tag name with a string.
        xmlGeneratorGet the DOM document to generate elements.
        xmlElementCreate an XML DOM element.
        xmlescapeExcapes invalid xml characters.
        xmlTextNodeCreates an XML DOM text node.
        xmlHtmlNodeCreates an XML DOM html node.
        getTextGet the concatenation of all text children of an element.
        copyElementCopy an XML DOM element.
        createHtmlCopy an HTML DOM element into an XML DOM.
        escapeNodeEscape the node part (also called local part) of a JID.
        unescapeNodeUnescape a node part (also called local part) of a JID.
        getNodeFromJidGet the node portion of a JID String.
        getDomainFromJidGet the domain portion of a JID String.
        getResourceFromJidGet the resource portion of a JID String.
        getBareJidFromJidGet the bare JID from a JID String.
        logUser overrideable logging function.
        debugLog a message at the Strophe.LogLevel.DEBUG level.
        infoLog a message at the Strophe.LogLevel.INFO level.
        warnLog a message at the Strophe.LogLevel.WARN level.
        errorLog a message at the Strophe.LogLevel.ERROR level.
        fatalLog a message at the Strophe.LogLevel.FATAL level.
        serializeRender a DOM element and all descendants to a String.
        addConnectionPluginExtends the Strophe.Connection object with the given plugin.
        + +

        Constants

        + +

        VERSION

        The version of the Strophe library.  Unreleased builds will have a version of head-HASH where HASH is a partial revision.

        + +

        XMPP Namespace Constants

        Common namespace constants from the XMPP RFCs and XEPs.

        NS.HTTPBINDHTTP BIND namespace from XEP 124.
        NS.BOSHBOSH namespace from XEP 206.
        NS.CLIENTMain XMPP client namespace.
        NS.AUTHLegacy authentication namespace.
        NS.ROSTERRoster operations namespace.
        NS.PROFILEProfile namespace.
        NS.DISCO_INFOService discovery info namespace from XEP 30.
        NS.DISCO_ITEMSService discovery items namespace from XEP 30.
        NS.MUCMulti-User Chat namespace from XEP 45.
        NS.SASLXMPP SASL namespace from RFC 3920.
        NS.STREAMXMPP Streams namespace from RFC 3920.
        NS.BINDXMPP Binding namespace from RFC 3920.
        NS.SESSIONXMPP Session namespace from RFC 3920.
        NS.XHTML_IMXHTML-IM namespace from XEP 71.
        NS.XHTMLXHTML body namespace from XEP 71.
        + +

        XHTML_IM Namespace

        contains allowed tags, tag attributes, and css properties.  Used in the createHtml function to filter incoming html into the allowed XHTML-IM subset.  See http://xmpp.org/extensions/xep-0071.html#profile-summary for the list of recommended allowed tags and their attributes.

        + +

        Connection Status Constants

        Connection status constants for use by the connection handler callback.

        Status.ERRORAn error has occurred
        Status.CONNECTINGThe connection is currently being made
        Status.CONNFAILThe connection attempt failed
        Status.AUTHENTICATINGThe connection is authenticating
        Status.AUTHFAILThe authentication attempt failed
        Status.CONNECTEDThe connection has succeeded
        Status.DISCONNECTEDThe connection has been terminated
        Status.DISCONNECTINGThe connection is currently being terminated
        Status.ATTACHEDThe connection has been attached
        + +

        Log Level Constants

        Logging level indicators.

        LogLevel.DEBUGDebug output
        LogLevel.INFOInformational output
        LogLevel.WARNWarnings
        LogLevel.ERRORErrors
        LogLevel.FATALFatal errors
        + +

        Functions

        + +

        addNamespace

        addNamespace: function (name,
        value)

        This function is used to extend the current namespaces in Strophe.NS.  It takes a key and a value with the key being the name of the new namespace, with its actual value.  For example: Strophe.addNamespace(‘PUBSUB’, “http://jabber.org/protocol/pubsub”);

        Parameters

        (String) nameThe name under which the namespace will be referenced under Strophe.NS
        (String) valueThe actual namespace.
        + +

        forEachChild

        forEachChild: function (elem,
        elemName,
        func)

        Map a function over some or all child elements of a given element.

        This is a small convenience function for mapping a function over some or all of the children of an element.  If elemName is null, all children will be passed to the function, otherwise only children whose tag names match elemName will be passed.

        Parameters

        (XMLElement) elemThe element to operate on.
        (String) elemNameThe child element tag name filter.
        (Function) funcThe function to apply to each child.  This function should take a single argument, a DOM element.
        + +

        isTagEqual

        isTagEqual: function (el,
        name)

        Compare an element’s tag name with a string.

        This function is case insensitive.

        Parameters

        (XMLElement) elA DOM element.
        (String) nameThe element name.

        Returns

        true if the element’s tag name matches el, and false otherwise.

        + +

        xmlGenerator

        xmlGenerator: function ()

        Get the DOM document to generate elements.

        Returns

        The currently used DOM document.

        + +

        xmlElement

        xmlElement: function (name)

        Create an XML DOM element.

        This function creates an XML DOM element correctly across all implementations.  Note that these are not HTML DOM elements, which aren’t appropriate for XMPP stanzas.

        Parameters

        (String) nameThe name for the element.
        (Array|Object) attrsAn optional array or object containing key/value pairs to use as element attributes.  The object should be in the format {‘key’: ‘value’} or {key: ‘value’}.  The array should have the format [[‘key1’, ‘value1’], [‘key2’, ‘value2’]].
        (String) textThe text child data for the element.

        Returns

        A new XML DOM element.

        + +

        xmlescape

        xmlescape: function(text)

        Excapes invalid xml characters.

        Parameters

        (String) texttext to escape.

        Returns

        Escaped text.

        + +

        xmlTextNode

        xmlTextNode: function (text)

        Creates an XML DOM text node.

        Provides a cross implementation version of document.createTextNode.

        Parameters

        (String) textThe content of the text node.

        Returns

        A new XML DOM text node.

        + +

        xmlHtmlNode

        xmlHtmlNode: function (html)

        Creates an XML DOM html node.

        Parameters

        (String) htmlThe content of the html node.

        Returns

        A new XML DOM text node.

        + +

        getText

        getText: function (elem)

        Get the concatenation of all text children of an element.

        Parameters

        (XMLElement) elemA DOM element.

        Returns

        A String with the concatenated text of all text element children.

        + +

        copyElement

        copyElement: function (elem)

        Copy an XML DOM element.

        This function copies a DOM element and all its descendants and returns the new copy.

        Parameters

        (XMLElement) elemA DOM element.

        Returns

        A new, copied DOM element tree.

        + +

        createHtml

        createHtml: function (elem)

        Copy an HTML DOM element into an XML DOM.

        This function copies a DOM element and all its descendants and returns the new copy.

        Parameters

        (HTMLElement) elemA DOM element.

        Returns

        A new, copied DOM element tree.

        + +

        escapeNode

        escapeNode: function (node)

        Escape the node part (also called local part) of a JID.

        Parameters

        (String) nodeA node (or local part).

        Returns

        An escaped node (or local part).

        + +

        unescapeNode

        unescapeNode: function (node)

        Unescape a node part (also called local part) of a JID.

        Parameters

        (String) nodeA node (or local part).

        Returns

        An unescaped node (or local part).

        + +

        getNodeFromJid

        getNodeFromJid: function (jid)

        Get the node portion of a JID String.

        Parameters

        (String) jidA JID.

        Returns

        A String containing the node.

        + +

        getDomainFromJid

        getDomainFromJid: function (jid)

        Get the domain portion of a JID String.

        Parameters

        (String) jidA JID.

        Returns

        A String containing the domain.

        + +

        getResourceFromJid

        getResourceFromJid: function (jid)

        Get the resource portion of a JID String.

        Parameters

        (String) jidA JID.

        Returns

        A String containing the resource.

        + +

        getBareJidFromJid

        getBareJidFromJid: function (jid)

        Get the bare JID from a JID String.

        Parameters

        (String) jidA JID.

        Returns

        A String containing the bare JID.

        + +

        log

        User overrideable logging function.

        This function is called whenever the Strophe library calls any of the logging functions.  The default implementation of this function does nothing.  If client code wishes to handle the logging messages, it should override this with

        Strophe.log = function (level, msg) {
        +  (user code here)
        +};

        Please note that data sent and received over the wire is logged via Strophe.Connection.rawInput() and Strophe.Connection.rawOutput().

        The different levels and their meanings are

        DEBUGMessages useful for debugging purposes.
        INFOInformational messages.  This is mostly information like ‘disconnect was called’ or ‘SASL auth succeeded’.
        WARNWarnings about potential problems.  This is mostly used to report transient connection errors like request timeouts.
        ERRORSome error occurred.
        FATALA non-recoverable fatal error occurred.

        Parameters

        (Integer) levelThe log level of the log message.  This will be one of the values in Strophe.LogLevel.
        (String) msgThe log message.
        + +

        debug

        debug: function(msg)

        Log a message at the Strophe.LogLevel.DEBUG level.

        Parameters

        (String) msgThe log message.
        + +

        info

        info: function (msg)

        Log a message at the Strophe.LogLevel.INFO level.

        Parameters

        (String) msgThe log message.
        + +

        warn

        warn: function (msg)

        Log a message at the Strophe.LogLevel.WARN level.

        Parameters

        (String) msgThe log message.
        + +

        error

        error: function (msg)

        Log a message at the Strophe.LogLevel.ERROR level.

        Parameters

        (String) msgThe log message.
        + +

        fatal

        fatal: function (msg)

        Log a message at the Strophe.LogLevel.FATAL level.

        Parameters

        (String) msgThe log message.
        + +

        serialize

        serialize: function (elem)

        Render a DOM element and all descendants to a String.

        Parameters

        (XMLElement) elemA DOM element.

        Returns

        The serialized element tree as a String.

        + +

        addConnectionPlugin

        addConnectionPlugin: function (name,
        ptype)

        Extends the Strophe.Connection object with the given plugin.

        Parameters

        (String) nameThe name of the extension.
        (Object) ptypeThe plugin’s prototype.
        + +

        Strophe.Builder

        XML DOM builder.

        This object provides an interface similar to JQuery but for building DOM element easily and rapidly.  All the functions except for toString() and tree() return the object, so calls can be chained.  Here’s an example using the $iq() builder helper.

        $iq({to: 'you', from: 'me', type: 'get', id: '1'})
        +    .c('query', {xmlns: 'strophe:example'})
        +    .c('example')
        +    .toString()

        The above generates this XML fragment

        <iq to='you' from='me' type='get' id='1'>
        +  <query xmlns='strophe:example'>
        +    <example/>
        +  </query>
        +</iq>

        The corresponding DOM manipulations to get a similar fragment would be a lot more tedious and probably involve several helper variables.

        Since adding children makes new operations operate on the child, up() is provided to traverse up the tree.  To add two children, do

        builder.c('child1', ...).up().c('child2', ...)

        The next operation on the Builder will be relative to the second child.

        Summary
        Functions
        Strophe.BuilderCreate a Strophe.Builder object.
        treeReturn the DOM tree.
        toStringSerialize the DOM tree to a String.
        upMake the current parent element the new current element.
        attrsAdd or modify attributes of the current element.
        cAdd a child to the current element and make it the new current element.
        cnodeAdd a child to the current element and make it the new current element.
        tAdd a child text element.
        hReplace current element contents with the HTML passed in.
        + +

        Functions

        + +

        Strophe.Builder

        Strophe.Builder = function (name,
        attrs)

        Create a Strophe.Builder object.

        The attributes should be passed in object notation.  For example

        var b = new Builder('message', {to: 'you', from: 'me'});

        or

        var b = new Builder('messsage', {'xml:lang': 'en'});

        Parameters

        (String) nameThe name of the root element.
        (Object) attrsThe attributes for the root element in object notation.

        Returns

        A new Strophe.Builder.

        + +

        tree

        tree: function ()

        Return the DOM tree.

        This function returns the current DOM tree as an element object.  This is suitable for passing to functions like Strophe.Connection.send().

        Returns

        The DOM tree as a element object.

        + +

        toString

        toString: function ()

        Serialize the DOM tree to a String.

        This function returns a string serialization of the current DOM tree.  It is often used internally to pass data to a Strophe.Request object.

        Returns

        The serialized DOM tree in a String.

        + +

        up

        up: function ()

        Make the current parent element the new current element.

        This function is often used after c() to traverse back up the tree.  For example, to add two children to the same element

        builder.c('child1', {}).up().c('child2', {});

        Returns

        The Stophe.Builder object.

        + +

        attrs

        attrs: function (moreattrs)

        Add or modify attributes of the current element.

        The attributes should be passed in object notation.  This function does not move the current element pointer.

        Parameters

        (Object) moreattrsThe attributes to add/modify in object notation.

        Returns

        The Strophe.Builder object.

        + +

        c

        c: function (name,
        attrs,
        text)

        Add a child to the current element and make it the new current element.

        This function moves the current element pointer to the child, unless text is provided.  If you need to add another child, it is necessary to use up() to go back to the parent in the tree.

        Parameters

        (String) nameThe name of the child.
        (Object) attrsThe attributes of the child in object notation.
        (String) textThe text to add to the child.

        Returns

        The Strophe.Builder object.

        + +

        cnode

        cnode: function (elem)

        Add a child to the current element and make it the new current element.

        This function is the same as c() except that instead of using a name and an attributes object to create the child it uses an existing DOM element object.

        Parameters

        (XMLElement) elemA DOM element.

        Returns

        The Strophe.Builder object.

        + +

        t

        t: function (text)

        Add a child text element.

        This does not make the child the new current element since there are no children of text elements.

        Parameters

        (String) textThe text data to append to the current element.

        Returns

        The Strophe.Builder object.

        + +

        h

        h: function (html)

        Replace current element contents with the HTML passed in.

        This does not make the child the new current element

        Parameters

        (String) htmlThe html to insert as contents of current element.

        Returns

        The Strophe.Builder object.

        + +

        Strophe.Connection

        XMPP Connection manager.

        This class is the main part of Strophe.  It manages a BOSH connection to an XMPP server and dispatches events to the user callbacks as data arrives.  It supports SASL PLAIN, SASL DIGEST-MD5, SASL SCRAM-SHA1 and legacy authentication.

        After creating a Strophe.Connection object, the user will typically call connect() with a user supplied callback to handle connection level events like authentication failure, disconnection, or connection complete.

        The user will also have several event handlers defined by using addHandler() and addTimedHandler().  These will allow the user code to respond to interesting stanzas or do something periodically with the connection.  These handlers will be active once authentication is finished.

        To send data to the connection, use send().

        Summary
        Functions
        Strophe.ConnectionCreate and initialize a Strophe.Connection object.
        resetReset the connection.
        pausePause the request manager.
        resumeResume the request manager.
        getUniqueIdGenerate a unique ID for use in <iq/> elements.
        connectStarts the connection process.
        Variables
        authzidAuthorization identity.
        authcidAuthentication identity (User name).
        passAuthentication identity (User password).
        servtypeDigest MD5 compatibility.
        Functions
        attachAttach to an already created and authenticated BOSH session.
        xmlInputUser overrideable function that receives XML data coming into the connection.
        xmlOutputUser overrideable function that receives XML data sent to the connection.
        rawInputUser overrideable function that receives raw data coming into the connection.
        rawOutputUser overrideable function that receives raw data sent to the connection.
        sendSend a stanza.
        flushImmediately send any pending outgoing data.
        sendIQHelper function to send IQ stanzas.
        addTimedHandlerAdd a timed handler to the connection.
        deleteTimedHandlerDelete a timed handler for a connection.
        addHandlerAdd a stanza handler for the connection.
        deleteHandlerDelete a stanza handler for a connection.
        disconnectStart the graceful disconnection process.
        authenticateSet up authentication
        + +

        Functions

        + +

        Strophe.Connection

        Strophe.Connection = function (service,
        options)

        Create and initialize a Strophe.Connection object.

        The transport-protocol for this connection will be chosen automatically based on the given service parameter.  URLs starting with “ws://” or “wss://” will use WebSockets, URLs starting with “http://”, “https://” or without a protocol will use BOSH.

        To make Strophe connect to the current host you can leave out the protocol and host part and just pass the path, e.g.

        var conn = new Strophe.Connection("/http-bind/");

        WebSocket options

        If you want to connect to the current host with a WebSocket connection you can tell Strophe to use WebSockets through a “protocol” attribute in the optional options parameter.  Valid values are “ws” for WebSocket and “wss” for Secure WebSocket.  So to connect to “wss://CURRENT_HOSTNAME/xmpp-websocket” you would call

        var conn = new Strophe.Connection("/xmpp-websocket/", {protocol: "wss"});

        Note that relative URLs NOT starting with a “/” will also include the path of the current site.

        Also because downgrading security is not permitted by browsers, when using relative URLs both BOSH and WebSocket connections will use their secure variants if the current connection to the site is also secure (https).

        BOSH options

        by adding “sync” to the options, you can control if requests will be made synchronously or not.  The default behaviour is asynchronous.  If you want to make requests synchronous, make “sync” evaluate to true:

        var conn = new Strophe.Connection("/http-bind/", {sync: true});

        You can also toggle this on an already established connection:

        conn.options.sync = true;

        Parameters

        (String) serviceThe BOSH or WebSocket service URL.
        (Object) optionsA hash of configuration options

        Returns

        A new Strophe.Connection object.

        + +

        reset

        reset: function ()

        Reset the connection.

        This function should be called after a connection is disconnected before that connection is reused.

        + +

        pause

        pause: function ()

        Pause the request manager.

        This will prevent Strophe from sending any more requests to the server.  This is very useful for temporarily pausing BOSH-Connections while a lot of send() calls are happening quickly.  This causes Strophe to send the data in a single request, saving many request trips.

        + +

        resume

        resume: function ()

        Resume the request manager.

        This resumes after pause() has been called.

        + +

        getUniqueId

        getUniqueId: function (suffix)

        Generate a unique ID for use in <iq/> elements.

        All <iq/> stanzas are required to have unique id attributes.  This function makes creating these easy.  Each connection instance has a counter which starts from zero, and the value of this counter plus a colon followed by the suffix becomes the unique id.  If no suffix is supplied, the counter is used as the unique id.

        Suffixes are used to make debugging easier when reading the stream data, and their use is recommended.  The counter resets to 0 for every new connection for the same reason.  For connections to the same server that authenticate the same way, all the ids should be the same, which makes it easy to see changes.  This is useful for automated testing as well.

        Parameters

        (String) suffixA optional suffix to append to the id.

        Returns

        A unique string to be used for the id attribute.

        + +

        connect

        connect: function (jid,
        pass,
        callback,
        wait,
        hold,
        route)

        Starts the connection process.

        As the connection process proceeds, the user supplied callback will be triggered multiple times with status updates.  The callback should take two arguments - the status code and the error condition.

        The status code will be one of the values in the Strophe.Status constants.  The error condition will be one of the conditions defined in RFC 3920 or the condition ‘strophe-parsererror’.

        The Parameters wait, hold and route are optional and only relevant for BOSH connections.  Please see XEP 124 for a more detailed explanation of the optional parameters.

        Parameters

        (String) jidThe user’s JID.  This may be a bare JID, or a full JID.  If a node is not supplied, SASL ANONYMOUS authentication will be attempted.
        (String) passThe user’s password.
        (Function) callbackThe connect callback function.
        (Integer) waitThe optional HTTPBIND wait value.  This is the time the server will wait before returning an empty result for a request.  The default setting of 60 seconds is recommended.
        (Integer) holdThe optional HTTPBIND hold value.  This is the number of connections the server will hold at one time.  This should almost always be set to 1 (the default).
        (String) routeThe optional route value.
        + +

        Variables

        + +

        authzid

        this.authzid

        Authorization identity.

        + +

        authcid

        this.authcid

        Authentication identity (User name).

        + +

        pass

        this.pass

        Authentication identity (User password).

        + +

        servtype

        this.servtype

        Digest MD5 compatibility.

        + +

        Functions

        + +

        attach

        attach: function (jid,
        sid,
        rid,
        callback,
        wait,
        hold,
        wind)

        Attach to an already created and authenticated BOSH session.

        This function is provided to allow Strophe to attach to BOSH sessions which have been created externally, perhaps by a Web application.  This is often used to support auto-login type features without putting user credentials into the page.

        Parameters

        (String) jidThe full JID that is bound by the session.
        (String) sidThe SID of the BOSH session.
        (String) ridThe current RID of the BOSH session.  This RID will be used by the next request.  (Function) callback The connect callback function.
        (Integer) waitThe optional HTTPBIND wait value.  This is the time the server will wait before returning an empty result for a request.  The default setting of 60 seconds is recommended.  Other settings will require tweaks to the Strophe.TIMEOUT value.
        (Integer) holdThe optional HTTPBIND hold value.  This is the number of connections the server will hold at one time.  This should almost always be set to 1 (the default).
        (Integer) windThe optional HTTBIND window value.  This is the allowed range of request ids that are valid.  The default is 5.
        + +

        xmlInput

        User overrideable function that receives XML data coming into the connection.

        The default function does nothing.  User code can override this with

        Strophe.Connection.xmlInput = function (elem) {
        +  (user code)
        +};

        Due to limitations of current Browsers’ XML-Parsers the opening and closing <stream> tag for WebSocket-Connoctions will be passed as selfclosing here.

        BOSH-Connections will have all stanzas wrapped in a <body> tag.  See Strophe.Bosh.strip if you want to strip this tag.

        Parameters

        (XMLElement) elemThe XML data received by the connection.
        + +

        xmlOutput

        User overrideable function that receives XML data sent to the connection.

        The default function does nothing.  User code can override this with

        Strophe.Connection.xmlOutput = function (elem) {
        +  (user code)
        +};

        Due to limitations of current Browsers’ XML-Parsers the opening and closing <stream> tag for WebSocket-Connoctions will be passed as selfclosing here.

        BOSH-Connections will have all stanzas wrapped in a <body> tag.  See Strophe.Bosh.strip if you want to strip this tag.

        Parameters

        (XMLElement) elemThe XMLdata sent by the connection.
        + +

        rawInput

        User overrideable function that receives raw data coming into the connection.

        The default function does nothing.  User code can override this with

        Strophe.Connection.rawInput = function (data) {
        +  (user code)
        +};

        Parameters

        (String) dataThe data received by the connection.
        + +

        rawOutput

        User overrideable function that receives raw data sent to the connection.

        The default function does nothing.  User code can override this with

        Strophe.Connection.rawOutput = function (data) {
        +  (user code)
        +};

        Parameters

        (String) dataThe data sent by the connection.
        + +

        send

        send: function (elem)

        Send a stanza.

        This function is called to push data onto the send queue to go out over the wire.  Whenever a request is sent to the BOSH server, all pending data is sent and the queue is flushed.

        Parameters

        (XMLElement | [XMLElement] | Strophe.Builder) elem - The stanza to send.

        + +

        flush

        flush: function ()

        Immediately send any pending outgoing data.

        Normally send() queues outgoing data until the next idle period (100ms), which optimizes network use in the common cases when several send()s are called in succession. flush() can be used to immediately send all pending data.

        + +

        sendIQ

        sendIQ: function(elem,
        callback,
        errback,
        timeout)

        Helper function to send IQ stanzas.

        Parameters

        (XMLElement) elemThe stanza to send.
        (Function) callbackThe callback function for a successful request.
        (Function) errbackThe callback function for a failed or timed out request.  On timeout, the stanza will be null.
        (Integer) timeoutThe time specified in milliseconds for a timeout to occur.

        Returns

        The id used to send the IQ.

        + +

        addTimedHandler

        addTimedHandler: function (period,
        handler)

        Add a timed handler to the connection.

        This function adds a timed handler.  The provided handler will be called every period milliseconds until it returns false, the connection is terminated, or the handler is removed.  Handlers that wish to continue being invoked should return true.

        Because of method binding it is necessary to save the result of this function if you wish to remove a handler with deleteTimedHandler().

        Note that user handlers are not active until authentication is successful.

        Parameters

        (Integer) periodThe period of the handler.
        (Function) handlerThe callback function.

        Returns

        A reference to the handler that can be used to remove it.

        + +

        deleteTimedHandler

        deleteTimedHandler: function (handRef)

        Delete a timed handler for a connection.

        This function removes a timed handler from the connection.  The handRef parameter is not the function passed to addTimedHandler(), but is the reference returned from addTimedHandler().

        Parameters

        (Strophe.TimedHandler) handRefThe handler reference.
        + +

        addHandler

        addHandler: function (handler,
        ns,
        name,
        type,
        id,
        from,
        options)

        Add a stanza handler for the connection.

        This function adds a stanza handler to the connection.  The handler callback will be called for any stanza that matches the parameters.  Note that if multiple parameters are supplied, they must all match for the handler to be invoked.

        The handler will receive the stanza that triggered it as its argument.  The handler should return true if it is to be invoked again; returning false will remove the handler after it returns.

        As a convenience, the ns parameters applies to the top level element and also any of its immediate children.  This is primarily to make matching /iq/query elements easy.

        The options argument contains handler matching flags that affect how matches are determined.  Currently the only flag is matchBare (a boolean).  When matchBare is true, the from parameter and the from attribute on the stanza will be matched as bare JIDs instead of full JIDs.  To use this, pass {matchBare: true} as the value of options.  The default value for matchBare is false.

        The return value should be saved if you wish to remove the handler with deleteHandler().

        Parameters

        (Function) handlerThe user callback.
        (String) nsThe namespace to match.
        (String) nameThe stanza name to match.
        (String) typeThe stanza type attribute to match.
        (String) idThe stanza id attribute to match.
        (String) fromThe stanza from attribute to match.
        (String) optionsThe handler options

        Returns

        A reference to the handler that can be used to remove it.

        + +

        deleteHandler

        deleteHandler: function (handRef)

        Delete a stanza handler for a connection.

        This function removes a stanza handler from the connection.  The handRef parameter is not the function passed to addHandler(), but is the reference returned from addHandler().

        Parameters

        (Strophe.Handler) handRefThe handler reference.
        + +

        disconnect

        disconnect: function (reason)

        Start the graceful disconnection process.

        This function starts the disconnection process.  This process starts by sending unavailable presence and sending BOSH body of type terminate.  A timeout handler makes sure that disconnection happens even if the BOSH server does not respond.

        The user supplied connection callback will be notified of the progress as this process happens.

        Parameters

        (String) reasonThe reason the disconnect is occuring.
        + +

        authenticate

        authenticate: function (matched)

        Set up authentication

        Contiunues the initial connection request by setting up authentication handlers and start the authentication process.

        SASL authentication will be attempted if available, otherwise the code will fall back to legacy authentication.

        + +

        Strophe.SASLMechanism

        encapsulates SASL authentication mechanisms.

        User code may override the priority for each mechanism or disable it completely.  See priority for information about changing priority and test for informatian on how to disable a mechanism.

        By default, all mechanisms are enabled and the priorities are

        SCRAM-SHA140
        DIGEST-MD530
        Plain20
        Summary
        Variables
        priorityDetermines which SASLMechanism is chosen for authentication (Higher is better).
        Functions
        testChecks if mechanism able to run.
        Constants
        SASL mechanismsAvailable authentication mechanisms
        + +

        Variables

        + +

        priority

        this.priority

        Determines which SASLMechanism is chosen for authentication (Higher is better).  Users may override this to prioritize mechanisms differently.

        In the default configuration the priorities are

        SCRAM-SHA140
        DIGEST-MD530
        Plain20

        Example: (This will cause Strophe to choose the mechanism that the server sent first)

        Strophe.SASLMD5.priority = Strophe.SASLSHA1.priority;

        See SASL mechanisms for a list of available mechanisms.

        + +

        Functions

        + +

        test

        Checks if mechanism able to run.  To disable a mechanism, make this return false;

        To disable plain authentication run

        Strophe.SASLPlain.test = function() {
        +  return false;
        +}

        See SASL mechanisms for a list of available mechanisms.

        Parameters

        (Strophe.Connection) connectionTarget Connection.

        Returns

        (Boolean) If mechanism was able to run.

        + +

        Constants

        + +

        SASL mechanisms

        Available authentication mechanisms

        Strophe.SASLAnonymousSASL Anonymous authentication.
        Strophe.SASLPlainSASL Plain authentication.
        Strophe.SASLMD5SASL Digest-MD5 authentication
        Strophe.SASLSHA1SASL SCRAM-SHA1 authentication
        + +

        Strophe.Bosh

        Private helper class that handles BOSH Connections

        The Strophe.Bosh class is used internally by Strophe.Connection to encapsulate BOSH sessions.  It is not meant to be used from user’s code.

        Summary
        Files
        bosh.jsA JavaScript library to enable BOSH in Strophejs.
        Variables
        stripBOSH-Connections will have all stanzas wrapped in a <body> tag when passed to Strophe.Connection.xmlInput or Strophe.Connection.xmlOutput.
        + +

        Files

        + +

        bosh.js

        A JavaScript library to enable BOSH in Strophejs.

        this library uses Bidirectional-streams Over Synchronous HTTP (BOSH) to emulate a persistent, stateful, two-way connection to an XMPP server.  More information on BOSH can be found in XEP 124.

        + +

        Variables

        + +

        strip

        strip: null

        BOSH-Connections will have all stanzas wrapped in a <body> tag when passed to Strophe.Connection.xmlInput or Strophe.Connection.xmlOutput.  To strip this tag, User code can set Strophe.Bosh.strip to “body”:

        Strophe.Bosh.prototype.strip = "body";

        This will enable stripping of the body tag in both Strophe.Connection.xmlInput and Strophe.Connection.xmlOutput.

        + +

        Strophe.WebSocket

        Private helper class that handles WebSocket Connections

        The Strophe.WebSocket class is used internally by Strophe.Connection to encapsulate WebSocket sessions.  It is not meant to be used from user’s code.

        Summary
        Files
        websocket.jsA JavaScript library to enable XMPP over Websocket in Strophejs.
        + +

        Files

        + +

        websocket.js

        A JavaScript library to enable XMPP over Websocket in Strophejs.

        This file implements XMPP over WebSockets for Strophejs.  If a Connection is established with a Websocket url (ws://...)  Strophe will use WebSockets.  For more information on XMPP-over WebSocket see this RFC draft: http://tools.ietf.org/html/draft-ietf-xmpp-websocket-00

        WebSocket support implemented by Andreas Guth (andrea.nosp@m.s.guth@rwth-aa.nosp@m.chen.de)

        + +
        + + + + + + + + + + +
        function $build(name,
        attrs)
        Create a Strophe.Builder.
        function $msg(attrs)
        Create a Strophe.Builder with a message/ element as the root.
        function $iq(attrs)
        Create a Strophe.Builder with an iq/ element as the root.
        function $pres(attrs)
        Create a Strophe.Builder with a presence/ element as the root.
        addNamespace: function (name,
        value)
        This function is used to extend the current namespaces in Strophe.NS.
        forEachChild: function (elem,
        elemName,
        func)
        Map a function over some or all child elements of a given element.
        isTagEqual: function (el,
        name)
        Compare an element’s tag name with a string.
        xmlGenerator: function ()
        Get the DOM document to generate elements.
        xmlElement: function (name)
        Create an XML DOM element.
        xmlescape: function(text)
        Excapes invalid xml characters.
        xmlTextNode: function (text)
        Creates an XML DOM text node.
        xmlHtmlNode: function (html)
        Creates an XML DOM html node.
        getText: function (elem)
        Get the concatenation of all text children of an element.
        copyElement: function (elem)
        Copy an XML DOM element.
        createHtml: function (elem)
        Copy an HTML DOM element into an XML DOM.
        escapeNode: function (node)
        Escape the node part (also called local part) of a JID.
        unescapeNode: function (node)
        Unescape a node part (also called local part) of a JID.
        getNodeFromJid: function (jid)
        Get the node portion of a JID String.
        getDomainFromJid: function (jid)
        Get the domain portion of a JID String.
        getResourceFromJid: function (jid)
        Get the resource portion of a JID String.
        getBareJidFromJid: function (jid)
        Get the bare JID from a JID String.
        debug: function(msg)
        Log a message at the Strophe.LogLevel.DEBUG level.
        info: function (msg)
        Log a message at the Strophe.LogLevel.INFO level.
        warn: function (msg)
        Log a message at the Strophe.LogLevel.WARN level.
        error: function (msg)
        Log a message at the Strophe.LogLevel.ERROR level.
        fatal: function (msg)
        Log a message at the Strophe.LogLevel.FATAL level.
        serialize: function (elem)
        Render a DOM element and all descendants to a String.
        addConnectionPlugin: function (name,
        ptype)
        Extends the Strophe.Connection object with the given plugin.
        Strophe.Builder = function (name,
        attrs)
        Create a Strophe.Builder object.
        tree: function ()
        Return the DOM tree.
        toString: function ()
        Serialize the DOM tree to a String.
        up: function ()
        Make the current parent element the new current element.
        attrs: function (moreattrs)
        Add or modify attributes of the current element.
        c: function (name,
        attrs,
        text)
        Add a child to the current element and make it the new current element.
        cnode: function (elem)
        Add a child to the current element and make it the new current element.
        t: function (text)
        Add a child text element.
        h: function (html)
        Replace current element contents with the HTML passed in.
        Strophe.Connection = function (service,
        options)
        Create and initialize a Strophe.Connection object.
        reset: function ()
        Reset the connection.
        pause: function ()
        Pause the request manager.
        resume: function ()
        Resume the request manager.
        getUniqueId: function (suffix)
        Generate a unique ID for use in iq/ elements.
        connect: function (jid,
        pass,
        callback,
        wait,
        hold,
        route)
        Starts the connection process.
        this.authzid
        Authorization identity.
        this.authcid
        Authentication identity (User name).
        this.pass
        Authentication identity (User password).
        this.servtype
        Digest MD5 compatibility.
        attach: function (jid,
        sid,
        rid,
        callback,
        wait,
        hold,
        wind)
        Attach to an already created and authenticated BOSH session.
        send: function (elem)
        Send a stanza.
        flush: function ()
        Immediately send any pending outgoing data.
        sendIQ: function(elem,
        callback,
        errback,
        timeout)
        Helper function to send IQ stanzas.
        addTimedHandler: function (period,
        handler)
        Add a timed handler to the connection.
        deleteTimedHandler: function (handRef)
        Delete a timed handler for a connection.
        addHandler: function (handler,
        ns,
        name,
        type,
        id,
        from,
        options)
        Add a stanza handler for the connection.
        deleteHandler: function (handRef)
        Delete a stanza handler for a connection.
        disconnect: function (reason)
        Start the graceful disconnection process.
        authenticate: function (matched)
        Set up authentication
        this.priority
        Determines which SASLMechanism is chosen for authentication (Higher is better).
        encapsulates SASL authentication mechanisms.
        strip: null
        BOSH-Connections will have all stanzas wrapped in a body tag when passed to Strophe.Connection.xmlInput or Strophe.Connection.xmlOutput.
        User overrideable function that receives XML data coming into the connection.
        User overrideable function that receives XML data sent to the connection.
        Checks if mechanism able to run.
        Available authentication mechanisms
        + + + + + + + + \ No newline at end of file diff --git a/public/javascripts/strophejs-1.1.3/doc/index.html b/public/javascripts/strophejs-1.1.3/doc/index.html new file mode 100644 index 0000000..a623238 --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/doc/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/javascripts/strophejs-1.1.3/doc/index/Classes.html b/public/javascripts/strophejs-1.1.3/doc/index/Classes.html new file mode 100644 index 0000000..5da88a1 --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/doc/index/Classes.html @@ -0,0 +1,33 @@ + + +Class Index + + + + + + + + + +
        Class Index
        $#! · 0-9 · A · B · C · D · E · F · G · H · I · J · K · L · M · N · O · P · Q · R · S · T · U · V · W · X · Y · Z
        S
         Strophe
         Strophe.Bosh
         Strophe.Builder
         Strophe.Connection
         Strophe.SASLMechanism
         Strophe.WebSocket
        + +
        An object container for all Strophe library functions.
        Private helper class that handles BOSH Connections
        XML DOM builder.
        XMPP Connection manager.
        encapsulates SASL authentication mechanisms.
        Private helper class that handles WebSocket Connections
        + +
        + + + + + + + + + + + + \ No newline at end of file diff --git a/public/javascripts/strophejs-1.1.3/doc/index/Constants.html b/public/javascripts/strophejs-1.1.3/doc/index/Constants.html new file mode 100644 index 0000000..1ed8d3f --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/doc/index/Constants.html @@ -0,0 +1,93 @@ + + +Constant Index + + + + + + + + + +
        Constant Index
        $#! · 0-9 · A · B · C · D · E · F · G · H · I · J · K · L · M · N · O · P · Q · R · S · T · U · V · W · X · Y · Z
        A
         ATTACHED, Strophe.Status
         AUTH, Strophe.NS
         AUTHENTICATING, Strophe.Status
         AUTHFAIL, Strophe.Status
        B
         BIND, Strophe.NS
         BOSH, Strophe.NS
        C
         CLIENT, Strophe.NS
         CONNECTED, Strophe.Status
         CONNECTING, Strophe.Status
         Connection Status Constants, Strophe
         CONNFAIL, Strophe.Status
        D
         DEBUG, Strophe.LogLevel
         DISCO_INFO, Strophe.NS
         DISCO_ITEMS, Strophe.NS
         DISCONNECTED, Strophe.Status
         DISCONNECTING, Strophe.Status
        E
         ERROR
        F
         FATAL, Strophe.LogLevel
        H
         HTTPBIND, Strophe.NS
        I
         INFO, Strophe.LogLevel
        L
         Log Level Constants, Strophe
        M
         MUC, Strophe.NS
        P
         PROFILE, Strophe.NS
        R
         ROSTER, Strophe.NS
        S
         SASL, Strophe.NS
         SASL mechanisms, Strophe.SASLMechanism
         SASLAnonymous, Strophe.SASLMechanism.Strophe
         SASLMD5, Strophe.SASLMechanism.Strophe
         SASLPlain, Strophe.SASLMechanism.Strophe
         SASLSHA1, Strophe.SASLMechanism.Strophe
         SESSION, Strophe.NS
         STREAM, Strophe.NS
        V
         VERSION, Strophe
        W
         WARN, Strophe.LogLevel
        X
         XHTML, Strophe.NS
         XHTML_IM, Strophe.NS
         XHTML_IM Namespace, Strophe
         XMPP Namespace Constants, Strophe
        + +
        The connection has been attached
        Legacy authentication namespace.
        The connection is authenticating
        The authentication attempt failed
        + + + +
        XMPP Binding namespace from RFC 3920.
        BOSH namespace from XEP 206.
        + + + +
        Main XMPP client namespace.
        The connection has succeeded
        The connection is currently being made
        Connection status constants for use by the connection handler callback.
        The connection attempt failed
        + + + +
        Debug output
        Service discovery info namespace from XEP 30.
        Service discovery items namespace from XEP 30.
        The connection has been terminated
        The connection is currently being terminated
        + + + +
        Errors
        An error has occurred
        + + + +
        Fatal errors
        + + + +
        HTTP BIND namespace from XEP 124.
        + + + +
        Informational output
        + + + +
        Logging level indicators.
        + + + +
        Multi-User Chat namespace from XEP 45.
        + + + +
        Profile namespace.
        + + + +
        Roster operations namespace.
        + + + +
        XMPP SASL namespace from RFC 3920.
        Available authentication mechanisms
        SASL Anonymous authentication.
        SASL Digest-MD5 authentication
        SASL Plain authentication.
        SASL SCRAM-SHA1 authentication
        XMPP Session namespace from RFC 3920.
        XMPP Streams namespace from RFC 3920.
        + + + +
        The version of the Strophe library.
        + + + +
        Warnings
        + + + +
        XHTML body namespace from XEP 71.
        XHTML-IM namespace from XEP 71.
        contains allowed tags, tag attributes, and css properties.
        Common namespace constants from the XMPP RFCs and XEPs.
        + +
        + + + + + + + + + + + + \ No newline at end of file diff --git a/public/javascripts/strophejs-1.1.3/doc/index/Files.html b/public/javascripts/strophejs-1.1.3/doc/index/Files.html new file mode 100644 index 0000000..4bdb405 --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/doc/index/Files.html @@ -0,0 +1,41 @@ + + +File Index + + + + + + + + + +
        File Index
        $#! · 0-9 · A · B · C · D · E · F · G · H · I · J · K · L · M · N · O · P · Q · R · S · T · U · V · W · X · Y · Z
        B
         bosh.js
        S
         strophe.js
        W
         websocket.js
        + +
        A JavaScript library to enable BOSH in Strophejs.
        + + + +
        A JavaScript library for XMPP BOSH/XMPP over Websocket.
        + + + +
        A JavaScript library to enable XMPP over Websocket in Strophejs.
        + +
        + + + + + + + + + + + + \ No newline at end of file diff --git a/public/javascripts/strophejs-1.1.3/doc/index/Functions.html b/public/javascripts/strophejs-1.1.3/doc/index/Functions.html new file mode 100644 index 0000000..1e57ac4 --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/doc/index/Functions.html @@ -0,0 +1,101 @@ + + +Function Index + + + + + + + + + +
        Function Index
        $#! · 0-9 · A · B · C · D · E · F · G · H · I · J · K · L · M · N · O · P · Q · R · S · T · U · V · W · X · Y · Z
        $#!
         $build
         $iq
         $msg
         $pres
        A
         addConnectionPlugin, Strophe
         addHandler, Strophe.Connection
         addNamespace, Strophe
         addTimedHandler, Strophe.Connection
         attach, Strophe.Connection
         attrs, Strophe.Builder
         authenticate, Strophe.Connection
        B
         Builder, Strophe.Builder.Strophe
        C
         c, Strophe.Builder
         cnode, Strophe.Builder
         connect, Strophe.Connection
         Connection, Strophe.Connection.Strophe
         copyElement, Strophe
         createHtml, Strophe
        D
         debug, Strophe
         deleteHandler, Strophe.Connection
         deleteTimedHandler, Strophe.Connection
         disconnect, Strophe.Connection
        E
         error, Strophe
         escapeNode, Strophe
        F
         fatal, Strophe
         flush, Strophe.Connection
         forEachChild, Strophe
        G
         getBareJidFromJid, Strophe
         getDomainFromJid, Strophe
         getNodeFromJid, Strophe
         getResourceFromJid, Strophe
         getText, Strophe
         getUniqueId, Strophe.Connection
        H
         h, Strophe.Builder
        I
         info, Strophe
         isTagEqual, Strophe
        L
         log, Strophe
        P
         pause, Strophe.Connection
        R
         rawInput, Strophe.Connection
         rawOutput, Strophe.Connection
         reset, Strophe.Connection
         resume, Strophe.Connection
        S
         send, Strophe.Connection
         sendIQ, Strophe.Connection
         serialize, Strophe
        T
         t, Strophe.Builder
         test, Strophe.SASLMechanism
         toString, Strophe.Builder
         tree, Strophe.Builder
        U
         unescapeNode, Strophe
         up, Strophe.Builder
        W
         warn, Strophe
        X
         xmlElement, Strophe
         xmlescape, Strophe
         xmlGenerator, Strophe
         xmlHtmlNode, Strophe
         xmlInput, Strophe.Connection
         xmlOutput, Strophe.Connection
         xmlTextNode, Strophe
        + +
        function $build(name,
        attrs)
        Create a Strophe.Builder.
        function $iq(attrs)
        Create a Strophe.Builder with an iq/ element as the root.
        function $msg(attrs)
        Create a Strophe.Builder with a message/ element as the root.
        function $pres(attrs)
        Create a Strophe.Builder with a presence/ element as the root.
        + + + +
        addConnectionPlugin: function (name,
        ptype)
        Extends the Strophe.Connection object with the given plugin.
        addHandler: function (handler,
        ns,
        name,
        type,
        id,
        from,
        options)
        Add a stanza handler for the connection.
        addNamespace: function (name,
        value)
        This function is used to extend the current namespaces in Strophe.NS.
        addTimedHandler: function (period,
        handler)
        Add a timed handler to the connection.
        attach: function (jid,
        sid,
        rid,
        callback,
        wait,
        hold,
        wind)
        Attach to an already created and authenticated BOSH session.
        attrs: function (moreattrs)
        Add or modify attributes of the current element.
        authenticate: function (matched)
        Set up authentication
        + + + +
        Strophe.Builder = function (name,
        attrs)
        Create a Strophe.Builder object.
        + + + +
        c: function (name,
        attrs,
        text)
        Add a child to the current element and make it the new current element.
        cnode: function (elem)
        Add a child to the current element and make it the new current element.
        connect: function (jid,
        pass,
        callback,
        wait,
        hold,
        route)
        Starts the connection process.
        Strophe.Connection = function (service,
        options)
        Create and initialize a Strophe.Connection object.
        copyElement: function (elem)
        Copy an XML DOM element.
        createHtml: function (elem)
        Copy an HTML DOM element into an XML DOM.
        + + + +
        debug: function(msg)
        Log a message at the Strophe.LogLevel.DEBUG level.
        deleteHandler: function (handRef)
        Delete a stanza handler for a connection.
        deleteTimedHandler: function (handRef)
        Delete a timed handler for a connection.
        disconnect: function (reason)
        Start the graceful disconnection process.
        + + + +
        error: function (msg)
        Log a message at the Strophe.LogLevel.ERROR level.
        escapeNode: function (node)
        Escape the node part (also called local part) of a JID.
        + + + +
        fatal: function (msg)
        Log a message at the Strophe.LogLevel.FATAL level.
        flush: function ()
        Immediately send any pending outgoing data.
        forEachChild: function (elem,
        elemName,
        func)
        Map a function over some or all child elements of a given element.
        + + + +
        getBareJidFromJid: function (jid)
        Get the bare JID from a JID String.
        getDomainFromJid: function (jid)
        Get the domain portion of a JID String.
        getNodeFromJid: function (jid)
        Get the node portion of a JID String.
        getResourceFromJid: function (jid)
        Get the resource portion of a JID String.
        getText: function (elem)
        Get the concatenation of all text children of an element.
        getUniqueId: function (suffix)
        Generate a unique ID for use in iq/ elements.
        + + + +
        h: function (html)
        Replace current element contents with the HTML passed in.
        + + + +
        info: function (msg)
        Log a message at the Strophe.LogLevel.INFO level.
        isTagEqual: function (el,
        name)
        Compare an element’s tag name with a string.
        + + + +
        User overrideable logging function.
        + + + +
        pause: function ()
        Pause the request manager.
        + + + +
        User overrideable function that receives raw data coming into the connection.
        User overrideable function that receives raw data sent to the connection.
        reset: function ()
        Reset the connection.
        resume: function ()
        Resume the request manager.
        + + + +
        send: function (elem)
        Send a stanza.
        sendIQ: function(elem,
        callback,
        errback,
        timeout)
        Helper function to send IQ stanzas.
        serialize: function (elem)
        Render a DOM element and all descendants to a String.
        + + + +
        t: function (text)
        Add a child text element.
        Checks if mechanism able to run.
        toString: function ()
        Serialize the DOM tree to a String.
        tree: function ()
        Return the DOM tree.
        + + + +
        unescapeNode: function (node)
        Unescape a node part (also called local part) of a JID.
        up: function ()
        Make the current parent element the new current element.
        + + + +
        warn: function (msg)
        Log a message at the Strophe.LogLevel.WARN level.
        + + + +
        xmlElement: function (name)
        Create an XML DOM element.
        xmlescape: function(text)
        Excapes invalid xml characters.
        xmlGenerator: function ()
        Get the DOM document to generate elements.
        xmlHtmlNode: function (html)
        Creates an XML DOM html node.
        User overrideable function that receives XML data coming into the connection.
        User overrideable function that receives XML data sent to the connection.
        xmlTextNode: function (text)
        Creates an XML DOM text node.
        + +
        + + + + + + + + + + + + \ No newline at end of file diff --git a/public/javascripts/strophejs-1.1.3/doc/index/General.html b/public/javascripts/strophejs-1.1.3/doc/index/General.html new file mode 100644 index 0000000..940e9a9 --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/doc/index/General.html @@ -0,0 +1,85 @@ + + +Index + + + + + + + + + +
        Index
        $#! · 0-9 · A · B · C · D · E · F · G · H · I · J · K · L · M · N · O · P · Q · R · S · T · U · V · W · X · Y · Z
        $#!
         $build
         $iq
         $msg
         $pres
        A
         addConnectionPlugin, Strophe
         addHandler, Strophe.Connection
         addNamespace, Strophe
         addTimedHandler, Strophe.Connection
         attach, Strophe.Connection
         ATTACHED, Strophe.Status
         attrs, Strophe.Builder
         AUTH, Strophe.NS
         authcid, Strophe.Connection
         authenticate, Strophe.Connection
         AUTHENTICATING, Strophe.Status
         AUTHFAIL, Strophe.Status
         authzid, Strophe.Connection
        B
         BIND, Strophe.NS
         BOSH, Strophe.NS
         bosh.js
         Builder, Strophe.Builder.Strophe
        C
         c, Strophe.Builder
         CLIENT, Strophe.NS
         cnode, Strophe.Builder
         connect, Strophe.Connection
         CONNECTED, Strophe.Status
         CONNECTING, Strophe.Status
         Connection, Strophe.Connection.Strophe
         Connection Status Constants, Strophe
         CONNFAIL, Strophe.Status
         Constants
         copyElement, Strophe
         createHtml, Strophe
        D
         debug, Strophe
         DEBUG, Strophe.LogLevel
         deleteHandler, Strophe.Connection
         deleteTimedHandler, Strophe.Connection
         DISCO_INFO, Strophe.NS
         DISCO_ITEMS, Strophe.NS
         disconnect, Strophe.Connection
         DISCONNECTED, Strophe.Status
         DISCONNECTING, Strophe.Status
        E
         error, Strophe
         ERROR
         escapeNode, Strophe
        F
         fatal, Strophe
         FATAL, Strophe.LogLevel
         Files
         flush, Strophe.Connection
         forEachChild, Strophe
         Functions
        G
         getBareJidFromJid, Strophe
         getDomainFromJid, Strophe
         getNodeFromJid, Strophe
         getResourceFromJid, Strophe
         getText, Strophe
         getUniqueId, Strophe.Connection
        H
         h, Strophe.Builder
         HTTPBIND, Strophe.NS
        I
         info, Strophe
         INFO, Strophe.LogLevel
         isTagEqual, Strophe
        L
         log, Strophe
         Log Level Constants, Strophe
        M
         MUC, Strophe.NS
        P
         pass, Strophe.Connection
         pause, Strophe.Connection
         priority, Strophe.SASLMechanism
         PROFILE, Strophe.NS
        R
         rawInput, Strophe.Connection
         rawOutput, Strophe.Connection
         reset, Strophe.Connection
         resume, Strophe.Connection
         ROSTER, Strophe.NS
        + +
        function $build(name,
        attrs)
        Create a Strophe.Builder.
        function $iq(attrs)
        Create a Strophe.Builder with an iq/ element as the root.
        function $msg(attrs)
        Create a Strophe.Builder with a message/ element as the root.
        function $pres(attrs)
        Create a Strophe.Builder with a presence/ element as the root.
        + + + +
        addConnectionPlugin: function (name,
        ptype)
        Extends the Strophe.Connection object with the given plugin.
        addHandler: function (handler,
        ns,
        name,
        type,
        id,
        from,
        options)
        Add a stanza handler for the connection.
        addNamespace: function (name,
        value)
        This function is used to extend the current namespaces in Strophe.NS.
        addTimedHandler: function (period,
        handler)
        Add a timed handler to the connection.
        attach: function (jid,
        sid,
        rid,
        callback,
        wait,
        hold,
        wind)
        Attach to an already created and authenticated BOSH session.
        The connection has been attached
        attrs: function (moreattrs)
        Add or modify attributes of the current element.
        Legacy authentication namespace.
        this.authcid
        Authentication identity (User name).
        authenticate: function (matched)
        Set up authentication
        The connection is authenticating
        The authentication attempt failed
        this.authzid
        Authorization identity.
        + + + +
        XMPP Binding namespace from RFC 3920.
        BOSH namespace from XEP 206.
        A JavaScript library to enable BOSH in Strophejs.
        Strophe.Builder = function (name,
        attrs)
        Create a Strophe.Builder object.
        + + + +
        c: function (name,
        attrs,
        text)
        Add a child to the current element and make it the new current element.
        Main XMPP client namespace.
        cnode: function (elem)
        Add a child to the current element and make it the new current element.
        connect: function (jid,
        pass,
        callback,
        wait,
        hold,
        route)
        Starts the connection process.
        The connection has succeeded
        The connection is currently being made
        Strophe.Connection = function (service,
        options)
        Create and initialize a Strophe.Connection object.
        Connection status constants for use by the connection handler callback.
        The connection attempt failed
        copyElement: function (elem)
        Copy an XML DOM element.
        createHtml: function (elem)
        Copy an HTML DOM element into an XML DOM.
        + + + +
        debug: function(msg)
        Log a message at the Strophe.LogLevel.DEBUG level.
        Debug output
        deleteHandler: function (handRef)
        Delete a stanza handler for a connection.
        deleteTimedHandler: function (handRef)
        Delete a timed handler for a connection.
        Service discovery info namespace from XEP 30.
        Service discovery items namespace from XEP 30.
        disconnect: function (reason)
        Start the graceful disconnection process.
        The connection has been terminated
        The connection is currently being terminated
        + + + +
        error: function (msg)
        Log a message at the Strophe.LogLevel.ERROR level.
        Errors
        An error has occurred
        escapeNode: function (node)
        Escape the node part (also called local part) of a JID.
        + + + +
        fatal: function (msg)
        Log a message at the Strophe.LogLevel.FATAL level.
        Fatal errors
        flush: function ()
        Immediately send any pending outgoing data.
        forEachChild: function (elem,
        elemName,
        func)
        Map a function over some or all child elements of a given element.
        + + + +
        getBareJidFromJid: function (jid)
        Get the bare JID from a JID String.
        getDomainFromJid: function (jid)
        Get the domain portion of a JID String.
        getNodeFromJid: function (jid)
        Get the node portion of a JID String.
        getResourceFromJid: function (jid)
        Get the resource portion of a JID String.
        getText: function (elem)
        Get the concatenation of all text children of an element.
        getUniqueId: function (suffix)
        Generate a unique ID for use in iq/ elements.
        + + + +
        h: function (html)
        Replace current element contents with the HTML passed in.
        HTTP BIND namespace from XEP 124.
        + + + +
        info: function (msg)
        Log a message at the Strophe.LogLevel.INFO level.
        Informational output
        isTagEqual: function (el,
        name)
        Compare an element’s tag name with a string.
        + + + +
        User overrideable logging function.
        Logging level indicators.
        + + + +
        Multi-User Chat namespace from XEP 45.
        + + + +
        this.pass
        Authentication identity (User password).
        pause: function ()
        Pause the request manager.
        this.priority
        Determines which SASLMechanism is chosen for authentication (Higher is better).
        Profile namespace.
        + + + +
        User overrideable function that receives raw data coming into the connection.
        User overrideable function that receives raw data sent to the connection.
        reset: function ()
        Reset the connection.
        resume: function ()
        Resume the request manager.
        Roster operations namespace.
        + +
        + + + + + + + + + + + + \ No newline at end of file diff --git a/public/javascripts/strophejs-1.1.3/doc/index/General2.html b/public/javascripts/strophejs-1.1.3/doc/index/General2.html new file mode 100644 index 0000000..8419699 --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/doc/index/General2.html @@ -0,0 +1,53 @@ + + +Index + + + + + + + + + +
        Index
        $#! · 0-9 · A · B · C · D · E · F · G · H · I · J · K · L · M · N · O · P · Q · R · S · T · U · V · W · X · Y · Z
        S
         SASL, Strophe.NS
         SASL mechanisms, Strophe.SASLMechanism
         SASLAnonymous, Strophe.SASLMechanism.Strophe
         SASLMD5, Strophe.SASLMechanism.Strophe
         SASLPlain, Strophe.SASLMechanism.Strophe
         SASLSHA1, Strophe.SASLMechanism.Strophe
         send, Strophe.Connection
         sendIQ, Strophe.Connection
         serialize, Strophe
         servtype, Strophe.Connection
         SESSION, Strophe.NS
         STREAM, Strophe.NS
         strip, Strophe.Bosh
         Strophe
         Strophe.Bosh
         Strophe.Builder
         Strophe.Connection
         strophe.js
         Strophe.SASLMechanism
         Strophe.WebSocket
        T
         t, Strophe.Builder
         test, Strophe.SASLMechanism
         toString, Strophe.Builder
         tree, Strophe.Builder
        U
         unescapeNode, Strophe
         up, Strophe.Builder
        V
         Variables
         VERSION, Strophe
        W
         warn, Strophe
         WARN, Strophe.LogLevel
         websocket.js
        X
         XHTML, Strophe.NS
         XHTML_IM, Strophe.NS
         XHTML_IM Namespace, Strophe
         xmlElement, Strophe
         xmlescape, Strophe
         xmlGenerator, Strophe
         xmlHtmlNode, Strophe
         xmlInput, Strophe.Connection
         xmlOutput, Strophe.Connection
         xmlTextNode, Strophe
         XMPP Namespace Constants, Strophe
        + +
        XMPP SASL namespace from RFC 3920.
        Available authentication mechanisms
        SASL Anonymous authentication.
        SASL Digest-MD5 authentication
        SASL Plain authentication.
        SASL SCRAM-SHA1 authentication
        send: function (elem)
        Send a stanza.
        sendIQ: function(elem,
        callback,
        errback,
        timeout)
        Helper function to send IQ stanzas.
        serialize: function (elem)
        Render a DOM element and all descendants to a String.
        this.servtype
        Digest MD5 compatibility.
        XMPP Session namespace from RFC 3920.
        XMPP Streams namespace from RFC 3920.
        strip: null
        BOSH-Connections will have all stanzas wrapped in a body tag when passed to Strophe.Connection.xmlInput or Strophe.Connection.xmlOutput.
        An object container for all Strophe library functions.
        Private helper class that handles BOSH Connections
        XML DOM builder.
        XMPP Connection manager.
        A JavaScript library for XMPP BOSH/XMPP over Websocket.
        encapsulates SASL authentication mechanisms.
        Private helper class that handles WebSocket Connections
        + + + +
        t: function (text)
        Add a child text element.
        Checks if mechanism able to run.
        toString: function ()
        Serialize the DOM tree to a String.
        tree: function ()
        Return the DOM tree.
        + + + +
        unescapeNode: function (node)
        Unescape a node part (also called local part) of a JID.
        up: function ()
        Make the current parent element the new current element.
        + + + +
        The version of the Strophe library.
        + + + +
        warn: function (msg)
        Log a message at the Strophe.LogLevel.WARN level.
        Warnings
        A JavaScript library to enable XMPP over Websocket in Strophejs.
        + + + +
        XHTML body namespace from XEP 71.
        XHTML-IM namespace from XEP 71.
        contains allowed tags, tag attributes, and css properties.
        xmlElement: function (name)
        Create an XML DOM element.
        xmlescape: function(text)
        Excapes invalid xml characters.
        xmlGenerator: function ()
        Get the DOM document to generate elements.
        xmlHtmlNode: function (html)
        Creates an XML DOM html node.
        User overrideable function that receives XML data coming into the connection.
        User overrideable function that receives XML data sent to the connection.
        xmlTextNode: function (text)
        Creates an XML DOM text node.
        Common namespace constants from the XMPP RFCs and XEPs.
        + +
        + + + + + + + + + + + + \ No newline at end of file diff --git a/public/javascripts/strophejs-1.1.3/doc/index/Variables.html b/public/javascripts/strophejs-1.1.3/doc/index/Variables.html new file mode 100644 index 0000000..ca4256c --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/doc/index/Variables.html @@ -0,0 +1,41 @@ + + +Variable Index + + + + + + + + + +
        Variable Index
        $#! · 0-9 · A · B · C · D · E · F · G · H · I · J · K · L · M · N · O · P · Q · R · S · T · U · V · W · X · Y · Z
        A
         authcid, Strophe.Connection
         authzid, Strophe.Connection
        P
         pass, Strophe.Connection
         priority, Strophe.SASLMechanism
        S
         servtype, Strophe.Connection
         strip, Strophe.Bosh
        + +
        this.authcid
        Authentication identity (User name).
        this.authzid
        Authorization identity.
        + + + +
        this.pass
        Authentication identity (User password).
        this.priority
        Determines which SASLMechanism is chosen for authentication (Higher is better).
        + + + +
        this.servtype
        Digest MD5 compatibility.
        strip: null
        BOSH-Connections will have all stanzas wrapped in a body tag when passed to Strophe.Connection.xmlInput or Strophe.Connection.xmlOutput.
        + +
        + + + + + + + + + + + + \ No newline at end of file diff --git a/public/javascripts/strophejs-1.1.3/doc/javascript/main.js b/public/javascripts/strophejs-1.1.3/doc/javascript/main.js new file mode 100644 index 0000000..3f42acd --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/doc/javascript/main.js @@ -0,0 +1,841 @@ +// This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure +// Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL) +// Refer to License.txt for the complete details + +// This file may be distributed with documentation files generated by Natural Docs. +// Such documentation is not covered by Natural Docs' copyright and licensing, +// and may have its own copyright and distribution terms as decided by its author. + + +// +// Browser Styles +// ____________________________________________________________________________ + +var agt=navigator.userAgent.toLowerCase(); +var browserType; +var browserVer; + +if (agt.indexOf("opera") != -1) + { + browserType = "Opera"; + + if (agt.indexOf("opera 7") != -1 || agt.indexOf("opera/7") != -1) + { browserVer = "Opera7"; } + else if (agt.indexOf("opera 8") != -1 || agt.indexOf("opera/8") != -1) + { browserVer = "Opera8"; } + else if (agt.indexOf("opera 9") != -1 || agt.indexOf("opera/9") != -1) + { browserVer = "Opera9"; } + } + +else if (agt.indexOf("applewebkit") != -1) + { + browserType = "Safari"; + + if (agt.indexOf("version/3") != -1) + { browserVer = "Safari3"; } + else if (agt.indexOf("safari/4") != -1) + { browserVer = "Safari2"; } + } + +else if (agt.indexOf("khtml") != -1) + { + browserType = "Konqueror"; + } + +else if (agt.indexOf("msie") != -1) + { + browserType = "IE"; + + if (agt.indexOf("msie 6") != -1) + { browserVer = "IE6"; } + else if (agt.indexOf("msie 7") != -1) + { browserVer = "IE7"; } + } + +else if (agt.indexOf("gecko") != -1) + { + browserType = "Firefox"; + + if (agt.indexOf("rv:1.7") != -1) + { browserVer = "Firefox1"; } + else if (agt.indexOf("rv:1.8)") != -1 || agt.indexOf("rv:1.8.0") != -1) + { browserVer = "Firefox15"; } + else if (agt.indexOf("rv:1.8.1") != -1) + { browserVer = "Firefox2"; } + } + + +// +// Support Functions +// ____________________________________________________________________________ + + +function GetXPosition(item) + { + var position = 0; + + if (item.offsetWidth != null) + { + while (item != document.body && item != null) + { + position += item.offsetLeft; + item = item.offsetParent; + }; + }; + + return position; + }; + + +function GetYPosition(item) + { + var position = 0; + + if (item.offsetWidth != null) + { + while (item != document.body && item != null) + { + position += item.offsetTop; + item = item.offsetParent; + }; + }; + + return position; + }; + + +function MoveToPosition(item, x, y) + { + // Opera 5 chokes on the px extension, so it can use the Microsoft one instead. + + if (item.style.left != null) + { + item.style.left = x + "px"; + item.style.top = y + "px"; + } + else if (item.style.pixelLeft != null) + { + item.style.pixelLeft = x; + item.style.pixelTop = y; + }; + }; + + +// +// Menu +// ____________________________________________________________________________ + + +function ToggleMenu(id) + { + if (!window.document.getElementById) + { return; }; + + var display = window.document.getElementById(id).style.display; + + if (display == "none") + { display = "block"; } + else + { display = "none"; } + + window.document.getElementById(id).style.display = display; + } + +function HideAllBut(ids, max) + { + if (document.getElementById) + { + ids.sort( function(a,b) { return a - b; } ); + var number = 1; + + while (number < max) + { + if (ids.length > 0 && number == ids[0]) + { ids.shift(); } + else + { + document.getElementById("MGroupContent" + number).style.display = "none"; + }; + + number++; + }; + }; + } + + +// +// Tooltips +// ____________________________________________________________________________ + + +var tooltipTimer = 0; + +function ShowTip(event, tooltipID, linkID) + { + if (tooltipTimer) + { clearTimeout(tooltipTimer); }; + + var docX = event.clientX + window.pageXOffset; + var docY = event.clientY + window.pageYOffset; + + var showCommand = "ReallyShowTip('" + tooltipID + "', '" + linkID + "', " + docX + ", " + docY + ")"; + + tooltipTimer = setTimeout(showCommand, 1000); + } + +function ReallyShowTip(tooltipID, linkID, docX, docY) + { + tooltipTimer = 0; + + var tooltip; + var link; + + if (document.getElementById) + { + tooltip = document.getElementById(tooltipID); + link = document.getElementById(linkID); + } +/* else if (document.all) + { + tooltip = eval("document.all['" + tooltipID + "']"); + link = eval("document.all['" + linkID + "']"); + } +*/ + if (tooltip) + { + var left = GetXPosition(link); + var top = GetYPosition(link); + top += link.offsetHeight; + + + // The fallback method is to use the mouse X and Y relative to the document. We use a separate if and test if its a number + // in case some browser snuck through the above if statement but didn't support everything. + + if (!isFinite(top) || top == 0) + { + left = docX; + top = docY; + } + + // Some spacing to get it out from under the cursor. + + top += 10; + + // Make sure the tooltip doesnt get smushed by being too close to the edge, or in some browsers, go off the edge of the + // page. We do it here because Konqueror does get offsetWidth right even if it doesnt get the positioning right. + + if (tooltip.offsetWidth != null) + { + var width = tooltip.offsetWidth; + var docWidth = document.body.clientWidth; + + if (left + width > docWidth) + { left = docWidth - width - 1; } + + // If there's a horizontal scroll bar we could go past zero because it's using the page width, not the window width. + if (left < 0) + { left = 0; }; + } + + MoveToPosition(tooltip, left, top); + tooltip.style.visibility = "visible"; + } + } + +function HideTip(tooltipID) + { + if (tooltipTimer) + { + clearTimeout(tooltipTimer); + tooltipTimer = 0; + } + + var tooltip; + + if (document.getElementById) + { tooltip = document.getElementById(tooltipID); } + else if (document.all) + { tooltip = eval("document.all['" + tooltipID + "']"); } + + if (tooltip) + { tooltip.style.visibility = "hidden"; } + } + + +// +// Blockquote fix for IE +// ____________________________________________________________________________ + + +function NDOnLoad() + { + if (browserVer == "IE6") + { + var scrollboxes = document.getElementsByTagName('blockquote'); + + if (scrollboxes.item(0)) + { + NDDoResize(); + window.onresize=NDOnResize; + }; + }; + }; + + +var resizeTimer = 0; + +function NDOnResize() + { + if (resizeTimer != 0) + { clearTimeout(resizeTimer); }; + + resizeTimer = setTimeout(NDDoResize, 250); + }; + + +function NDDoResize() + { + var scrollboxes = document.getElementsByTagName('blockquote'); + + var i; + var item; + + i = 0; + while (item = scrollboxes.item(i)) + { + item.style.width = 100; + i++; + }; + + i = 0; + while (item = scrollboxes.item(i)) + { + item.style.width = item.parentNode.offsetWidth; + i++; + }; + + clearTimeout(resizeTimer); + resizeTimer = 0; + } + + + +/* ________________________________________________________________________________________________________ + + Class: SearchPanel + ________________________________________________________________________________________________________ + + A class handling everything associated with the search panel. + + Parameters: + + name - The name of the global variable that will be storing this instance. Is needed to be able to set timeouts. + mode - The mode the search is going to work in. Pass CommandLineOption()>, so the + value will be something like "HTML" or "FramedHTML". + + ________________________________________________________________________________________________________ +*/ + + +function SearchPanel(name, mode, resultsPath) + { + if (!name || !mode || !resultsPath) + { alert("Incorrect parameters to SearchPanel."); }; + + + // Group: Variables + // ________________________________________________________________________ + + /* + var: name + The name of the global variable that will be storing this instance of the class. + */ + this.name = name; + + /* + var: mode + The mode the search is going to work in, such as "HTML" or "FramedHTML". + */ + this.mode = mode; + + /* + var: resultsPath + The relative path from the current HTML page to the results page directory. + */ + this.resultsPath = resultsPath; + + /* + var: keyTimeout + The timeout used between a keystroke and when a search is performed. + */ + this.keyTimeout = 0; + + /* + var: keyTimeoutLength + The length of in thousandths of a second. + */ + this.keyTimeoutLength = 500; + + /* + var: lastSearchValue + The last search string executed, or an empty string if none. + */ + this.lastSearchValue = ""; + + /* + var: lastResultsPage + The last results page. The value is only relevant if is set. + */ + this.lastResultsPage = ""; + + /* + var: deactivateTimeout + + The timeout used between when a control is deactivated and when the entire panel is deactivated. Is necessary + because a control may be deactivated in favor of another control in the same panel, in which case it should stay + active. + */ + this.deactivateTimout = 0; + + /* + var: deactivateTimeoutLength + The length of in thousandths of a second. + */ + this.deactivateTimeoutLength = 200; + + + + + // Group: DOM Elements + // ________________________________________________________________________ + + + // Function: DOMSearchField + this.DOMSearchField = function() + { return document.getElementById("MSearchField"); }; + + // Function: DOMSearchType + this.DOMSearchType = function() + { return document.getElementById("MSearchType"); }; + + // Function: DOMPopupSearchResults + this.DOMPopupSearchResults = function() + { return document.getElementById("MSearchResults"); }; + + // Function: DOMPopupSearchResultsWindow + this.DOMPopupSearchResultsWindow = function() + { return document.getElementById("MSearchResultsWindow"); }; + + // Function: DOMSearchPanel + this.DOMSearchPanel = function() + { return document.getElementById("MSearchPanel"); }; + + + + + // Group: Event Handlers + // ________________________________________________________________________ + + + /* + Function: OnSearchFieldFocus + Called when focus is added or removed from the search field. + */ + this.OnSearchFieldFocus = function(isActive) + { + this.Activate(isActive); + }; + + + /* + Function: OnSearchFieldChange + Called when the content of the search field is changed. + */ + this.OnSearchFieldChange = function() + { + if (this.keyTimeout) + { + clearTimeout(this.keyTimeout); + this.keyTimeout = 0; + }; + + var searchValue = this.DOMSearchField().value.replace(/ +/g, ""); + + if (searchValue != this.lastSearchValue) + { + if (searchValue != "") + { + this.keyTimeout = setTimeout(this.name + ".Search()", this.keyTimeoutLength); + } + else + { + if (this.mode == "HTML") + { this.DOMPopupSearchResultsWindow().style.display = "none"; }; + this.lastSearchValue = ""; + }; + }; + }; + + + /* + Function: OnSearchTypeFocus + Called when focus is added or removed from the search type. + */ + this.OnSearchTypeFocus = function(isActive) + { + this.Activate(isActive); + }; + + + /* + Function: OnSearchTypeChange + Called when the search type is changed. + */ + this.OnSearchTypeChange = function() + { + var searchValue = this.DOMSearchField().value.replace(/ +/g, ""); + + if (searchValue != "") + { + this.Search(); + }; + }; + + + + // Group: Action Functions + // ________________________________________________________________________ + + + /* + Function: CloseResultsWindow + Closes the results window. + */ + this.CloseResultsWindow = function() + { + this.DOMPopupSearchResultsWindow().style.display = "none"; + this.Activate(false, true); + }; + + + /* + Function: Search + Performs a search. + */ + this.Search = function() + { + this.keyTimeout = 0; + + var searchValue = this.DOMSearchField().value.replace(/^ +/, ""); + var searchTopic = this.DOMSearchType().value; + + var pageExtension = searchValue.substr(0,1); + + if (pageExtension.match(/^[a-z]/i)) + { pageExtension = pageExtension.toUpperCase(); } + else if (pageExtension.match(/^[0-9]/)) + { pageExtension = 'Numbers'; } + else + { pageExtension = "Symbols"; }; + + var resultsPage; + var resultsPageWithSearch; + var hasResultsPage; + + // indexSectionsWithContent is defined in searchdata.js + if (indexSectionsWithContent[searchTopic][pageExtension] == true) + { + resultsPage = this.resultsPath + '/' + searchTopic + pageExtension + '.html'; + resultsPageWithSearch = resultsPage+'?'+escape(searchValue); + hasResultsPage = true; + } + else + { + resultsPage = this.resultsPath + '/NoResults.html'; + resultsPageWithSearch = resultsPage; + hasResultsPage = false; + }; + + var resultsFrame; + if (this.mode == "HTML") + { resultsFrame = window.frames.MSearchResults; } + else if (this.mode == "FramedHTML") + { resultsFrame = window.top.frames['Content']; }; + + + if (resultsPage != this.lastResultsPage || + + // Bug in IE. If everything becomes hidden in a run, none of them will be able to be reshown in the next for some + // reason. It counts the right number of results, and you can even read the display as "block" after setting it, but it + // just doesn't work in IE 6 or IE 7. So if we're on the right page but the previous search had no results, reload the + // page anyway to get around the bug. + (browserType == "IE" && hasResultsPage && + (!resultsFrame.searchResults || resultsFrame.searchResults.lastMatchCount == 0)) ) + + { + resultsFrame.location.href = resultsPageWithSearch; + } + + // So if the results page is right and there's no IE bug, reperform the search on the existing page. We have to check if there + // are results because NoResults.html doesn't have any JavaScript, and it would be useless to do anything on that page even + // if it did. + else if (hasResultsPage) + { + // We need to check if this exists in case the frame is present but didn't finish loading. + if (resultsFrame.searchResults) + { resultsFrame.searchResults.Search(searchValue); } + + // Otherwise just reload instead of waiting. + else + { resultsFrame.location.href = resultsPageWithSearch; }; + }; + + + var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); + + if (this.mode == "HTML" && domPopupSearchResultsWindow.style.display != "block") + { + var domSearchType = this.DOMSearchType(); + + var left = GetXPosition(domSearchType); + var top = GetYPosition(domSearchType) + domSearchType.offsetHeight; + + MoveToPosition(domPopupSearchResultsWindow, left, top); + domPopupSearchResultsWindow.style.display = 'block'; + }; + + + this.lastSearchValue = searchValue; + this.lastResultsPage = resultsPage; + }; + + + + // Group: Activation Functions + // Functions that handle whether the entire panel is active or not. + // ________________________________________________________________________ + + + /* + Function: Activate + + Activates or deactivates the search panel, resetting things to their default values if necessary. You can call this on every + control's OnBlur() and it will handle not deactivating the entire panel when focus is just switching between them transparently. + + Parameters: + + isActive - Whether you're activating or deactivating the panel. + ignoreDeactivateDelay - Set if you're positive the action will deactivate the panel and thus want to skip the delay. + */ + this.Activate = function(isActive, ignoreDeactivateDelay) + { + // We want to ignore isActive being false while the results window is open. + if (isActive || (this.mode == "HTML" && this.DOMPopupSearchResultsWindow().style.display == "block")) + { + if (this.inactivateTimeout) + { + clearTimeout(this.inactivateTimeout); + this.inactivateTimeout = 0; + }; + + this.DOMSearchPanel().className = 'MSearchPanelActive'; + + var searchField = this.DOMSearchField(); + + if (searchField.value == 'Search') + { searchField.value = ""; } + } + else if (!ignoreDeactivateDelay) + { + this.inactivateTimeout = setTimeout(this.name + ".InactivateAfterTimeout()", this.inactivateTimeoutLength); + } + else + { + this.InactivateAfterTimeout(); + }; + }; + + + /* + Function: InactivateAfterTimeout + + Called by , which is set by . Inactivation occurs on a timeout because a control may + receive OnBlur() when focus is really transferring to another control in the search panel. In this case we don't want to + actually deactivate the panel because not only would that cause a visible flicker but it could also reset the search value. + So by doing it on a timeout instead, there's a short period where the second control's OnFocus() can cancel the deactivation. + */ + this.InactivateAfterTimeout = function() + { + this.inactivateTimeout = 0; + + this.DOMSearchPanel().className = 'MSearchPanelInactive'; + this.DOMSearchField().value = "Search"; + + this.lastSearchValue = ""; + this.lastResultsPage = ""; + }; + }; + + + + +/* ________________________________________________________________________________________________________ + + Class: SearchResults + _________________________________________________________________________________________________________ + + The class that handles everything on the search results page. + _________________________________________________________________________________________________________ +*/ + + +function SearchResults(name, mode) + { + /* + var: mode + The mode the search is going to work in, such as "HTML" or "FramedHTML". + */ + this.mode = mode; + + /* + var: lastMatchCount + The number of matches from the last run of . + */ + this.lastMatchCount = 0; + + + /* + Function: Toggle + Toggles the visibility of the passed element ID. + */ + this.Toggle = function(id) + { + if (this.mode == "FramedHTML") + { return; }; + + var parentElement = document.getElementById(id); + + var element = parentElement.firstChild; + + while (element && element != parentElement) + { + if (element.nodeName == 'DIV' && element.className == 'ISubIndex') + { + if (element.style.display == 'block') + { element.style.display = "none"; } + else + { element.style.display = 'block'; } + }; + + if (element.nodeName == 'DIV' && element.hasChildNodes()) + { element = element.firstChild; } + else if (element.nextSibling) + { element = element.nextSibling; } + else + { + do + { + element = element.parentNode; + } + while (element && element != parentElement && !element.nextSibling); + + if (element && element != parentElement) + { element = element.nextSibling; }; + }; + }; + }; + + + /* + Function: Search + + Searches for the passed string. If there is no parameter, it takes it from the URL query. + + Always returns true, since other documents may try to call it and that may or may not be possible. + */ + this.Search = function(search) + { + if (!search) + { + search = window.location.search; + search = search.substring(1); // Remove the leading ? + search = unescape(search); + }; + + search = search.replace(/^ +/, ""); + search = search.replace(/ +$/, ""); + search = search.toLowerCase(); + + if (search.match(/[^a-z0-9]/)) // Just a little speedup so it doesn't have to go through the below unnecessarily. + { + search = search.replace(/\_/g, "_und"); + search = search.replace(/\ +/gi, "_spc"); + search = search.replace(/\~/g, "_til"); + search = search.replace(/\!/g, "_exc"); + search = search.replace(/\@/g, "_att"); + search = search.replace(/\#/g, "_num"); + search = search.replace(/\$/g, "_dol"); + search = search.replace(/\%/g, "_pct"); + search = search.replace(/\^/g, "_car"); + search = search.replace(/\&/g, "_amp"); + search = search.replace(/\*/g, "_ast"); + search = search.replace(/\(/g, "_lpa"); + search = search.replace(/\)/g, "_rpa"); + search = search.replace(/\-/g, "_min"); + search = search.replace(/\+/g, "_plu"); + search = search.replace(/\=/g, "_equ"); + search = search.replace(/\{/g, "_lbc"); + search = search.replace(/\}/g, "_rbc"); + search = search.replace(/\[/g, "_lbk"); + search = search.replace(/\]/g, "_rbk"); + search = search.replace(/\:/g, "_col"); + search = search.replace(/\;/g, "_sco"); + search = search.replace(/\"/g, "_quo"); + search = search.replace(/\'/g, "_apo"); + search = search.replace(/\/g, "_ran"); + search = search.replace(/\,/g, "_com"); + search = search.replace(/\./g, "_per"); + search = search.replace(/\?/g, "_que"); + search = search.replace(/\//g, "_sla"); + search = search.replace(/[^a-z0-9\_]i/gi, "_zzz"); + }; + + var resultRows = document.getElementsByTagName("div"); + var matches = 0; + + var i = 0; + while (i < resultRows.length) + { + var row = resultRows.item(i); + + if (row.className == "SRResult") + { + var rowMatchName = row.id.toLowerCase(); + rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); + + if (search.length <= rowMatchName.length && rowMatchName.substr(0, search.length) == search) + { + row.style.display = "block"; + matches++; + } + else + { row.style.display = "none"; }; + }; + + i++; + }; + + document.getElementById("Searching").style.display="none"; + + if (matches == 0) + { document.getElementById("NoMatches").style.display="block"; } + else + { document.getElementById("NoMatches").style.display="none"; } + + this.lastMatchCount = matches; + + return true; + }; + }; + diff --git a/public/javascripts/strophejs-1.1.3/doc/javascript/prettify.js b/public/javascripts/strophejs-1.1.3/doc/javascript/prettify.js new file mode 100644 index 0000000..fda4bf1 --- /dev/null +++ b/public/javascripts/strophejs-1.1.3/doc/javascript/prettify.js @@ -0,0 +1,1526 @@ + +// This code comes from the December 2009 release of Google Prettify, which is Copyright © 2006 Google Inc. +// Minor modifications are marked with "ND Change" comments. +// As part of Natural Docs, this code is licensed under version 3 of the GNU Affero General Public License (AGPL.) +// However, it may also be obtained separately under version 2.0 of the Apache License. +// Refer to License.txt for the complete details + + +// Main code +// ____________________________________________________________________________ + +// Copyright (C) 2006 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +/** + * @fileoverview + * some functions for browser-side pretty printing of code contained in html. + *

        + * + * For a fairly comprehensive set of languages see the + * README + * file that came with this source. At a minimum, the lexer should work on a + * number of languages including C and friends, Java, Python, Bash, SQL, HTML, + * XML, CSS, Javascript, and Makefiles. It works passably on Ruby, PHP and Awk + * and a subset of Perl, but, because of commenting conventions, doesn't work on + * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class. + *

        + * Usage:

          + *
        1. include this source file in an html page via + * {@code } + *
        2. define style rules. See the example page for examples. + *
        3. mark the {@code
          } and {@code } tags in your source with
          + *    {@code class=prettyprint.}
          + *    You can also use the (html deprecated) {@code } tag, but the pretty
          + *    printer needs to do more substantial DOM manipulations to support that, so
          + *    some css styles may not be preserved.
          + * </ol>
          + * That's it.  I wanted to keep the API as simple as possible, so there's no
          + * need to specify which language the code is in, but if you wish, you can add
          + * another class to the {@code <pre>} or {@code <code>} element to specify the
          + * language, as in {@code <pre class="prettyprint lang-java">}.  Any class that
          + * starts with "lang-" followed by a file extension, specifies the file type.
          + * See the "lang-*.js" files in this directory for code that implements
          + * per-language file handlers.
          + * <p>
          + * Change log:<br>
          + * cbeust, 2006/08/22
          + * <blockquote>
          + *   Java annotations (start with "@") are now captured as literals ("lit")
          + * </blockquote>
          + * @requires console
          + * @overrides window
          + */
          +
          +// JSLint declarations
          +/*global console, document, navigator, setTimeout, window */
          +
          +/**
          + * Split {@code prettyPrint} into multiple timeouts so as not to interfere with
          + * UI events.
          + * If set to {@code false}, {@code prettyPrint()} is synchronous.
          + */
          +window['PR_SHOULD_USE_CONTINUATION'] = true;
          +
          +/** the number of characters between tab columns */
          +window['PR_TAB_WIDTH'] = 8;
          +
          +/** Walks the DOM returning a properly escaped version of innerHTML.
          +  * @param {Node} node
          +  * @param {Array.<string>} out output buffer that receives chunks of HTML.
          +  */
          +window['PR_normalizedHtml']
          +
          +/** Contains functions for creating and registering new language handlers.
          +  * @type {Object}
          +  */
          +  = window['PR']
          +
          +/** Pretty print a chunk of code.
          +  *
          +  * @param {string} sourceCodeHtml code as html
          +  * @return {string} code as html, but prettier
          +  */
          +  = window['prettyPrintOne']
          +/** Find all the {@code <pre>} and {@code <code>} tags in the DOM with
          +  * {@code class=prettyprint} and prettify them.
          +  * @param {Function?} opt_whenDone if specified, called when the last entry
          +  *     has been finished.
          +  */
          +  = window['prettyPrint'] = void 0;
          +
          +/** browser detection. @extern @returns false if not IE, otherwise the major version. */
          +window['_pr_isIE6'] = function () {
          +  var ieVersion = navigator && navigator.userAgent &&
          +      navigator.userAgent.match(/\bMSIE ([678])\./);
          +  ieVersion = ieVersion ? +ieVersion[1] : false;
          +  window['_pr_isIE6'] = function () { return ieVersion; };
          +  return ieVersion;
          +};
          +
          +
          +(function () {
          +  // Keyword lists for various languages.
          +  var FLOW_CONTROL_KEYWORDS =
          +      "break continue do else for if return while ";
          +  var C_KEYWORDS = FLOW_CONTROL_KEYWORDS + "auto case char const default " +
          +      "double enum extern float goto int long register short signed sizeof " +
          +      "static struct switch typedef union unsigned void volatile ";
          +  var COMMON_KEYWORDS = C_KEYWORDS + "catch class delete false import " +
          +      "new operator private protected public this throw true try typeof ";
          +  var CPP_KEYWORDS = COMMON_KEYWORDS + "alignof align_union asm axiom bool " +
          +      "concept concept_map const_cast constexpr decltype " +
          +      "dynamic_cast explicit export friend inline late_check " +
          +      "mutable namespace nullptr reinterpret_cast static_assert static_cast " +
          +      "template typeid typename using virtual wchar_t where ";
          +  var JAVA_KEYWORDS = COMMON_KEYWORDS +
          +      "abstract boolean byte extends final finally implements import " +
          +      "instanceof null native package strictfp super synchronized throws " +
          +      "transient ";
          +  var CSHARP_KEYWORDS = JAVA_KEYWORDS +
          +      "as base by checked decimal delegate descending event " +
          +      "fixed foreach from group implicit in interface internal into is lock " +
          +      "object out override orderby params partial readonly ref sbyte sealed " +
          +      "stackalloc string select uint ulong unchecked unsafe ushort var ";
          +  var JSCRIPT_KEYWORDS = COMMON_KEYWORDS +
          +      "debugger eval export function get null set undefined var with " +
          +      "Infinity NaN ";
          +  var PERL_KEYWORDS = "caller delete die do dump elsif eval exit foreach for " +
          +      "goto if import last local my next no our print package redo require " +
          +      "sub undef unless until use wantarray while BEGIN END ";
          +  var PYTHON_KEYWORDS = FLOW_CONTROL_KEYWORDS + "and as assert class def del " +
          +      "elif except exec finally from global import in is lambda " +
          +      "nonlocal not or pass print raise try with yield " +
          +      "False True None ";
          +  var RUBY_KEYWORDS = FLOW_CONTROL_KEYWORDS + "alias and begin case class def" +
          +      " defined elsif end ensure false in module next nil not or redo rescue " +
          +      "retry self super then true undef unless until when yield BEGIN END ";
          +  var SH_KEYWORDS = FLOW_CONTROL_KEYWORDS + "case done elif esac eval fi " +
          +      "function in local set then until ";
          +  var ALL_KEYWORDS = (
          +      CPP_KEYWORDS + CSHARP_KEYWORDS + JSCRIPT_KEYWORDS + PERL_KEYWORDS +
          +      PYTHON_KEYWORDS + RUBY_KEYWORDS + SH_KEYWORDS);
          +
          +  // token style names.  correspond to css classes
          +  /** token style for a string literal */
          +  var PR_STRING = 'str';
          +  /** token style for a keyword */
          +  var PR_KEYWORD = 'kwd';
          +  /** token style for a comment */
          +  var PR_COMMENT = 'com';
          +  /** token style for a type */
          +  var PR_TYPE = 'typ';
          +  /** token style for a literal value.  e.g. 1, null, true. */
          +  var PR_LITERAL = 'lit';
          +  /** token style for a punctuation string. */
          +  var PR_PUNCTUATION = 'pun';
          +  /** token style for a punctuation string. */
          +  var PR_PLAIN = 'pln';
          +
          +  /** token style for an sgml tag. */
          +  var PR_TAG = 'tag';
          +  /** token style for a markup declaration such as a DOCTYPE. */
          +  var PR_DECLARATION = 'dec';
          +  /** token style for embedded source. */
          +  var PR_SOURCE = 'src';
          +  /** token style for an sgml attribute name. */
          +  var PR_ATTRIB_NAME = 'atn';
          +  /** token style for an sgml attribute value. */
          +  var PR_ATTRIB_VALUE = 'atv';
          +
          +  /**
          +   * A class that indicates a section of markup that is not code, e.g. to allow
          +   * embedding of line numbers within code listings.
          +   */
          +  var PR_NOCODE = 'nocode';
          +
          +  /** A set of tokens that can precede a regular expression literal in
          +    * javascript.
          +    * http://www.mozilla.org/js/language/js20/rationale/syntax.html has the full
          +    * list, but I've removed ones that might be problematic when seen in
          +    * languages that don't support regular expression literals.
          +    *
          +    * <p>Specifically, I've removed any keywords that can't precede a regexp
          +    * literal in a syntactically legal javascript program, and I've removed the
          +    * "in" keyword since it's not a keyword in many languages, and might be used
          +    * as a count of inches.
          +    *
          +    * <p>The link a above does not accurately describe EcmaScript rules since
          +    * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works
          +    * very well in practice.
          +    *
          +    * @private
          +    */
          +  var REGEXP_PRECEDER_PATTERN = function () {
          +      var preceders = [
          +          "!", "!=", "!==", "#", "%", "%=", "&", "&&", "&&=",
          +          "&=", "(", "*", "*=", /* "+", */ "+=", ",", /* "-", */ "-=",
          +          "->", /*".", "..", "...", handled below */ "/", "/=", ":", "::", ";",
          +          "<", "<<", "<<=", "<=", "=", "==", "===", ">",
          +          ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[",
          +          "^", "^=", "^^", "^^=", "{", "|", "|=", "||",
          +          "||=", "~" /* handles =~ and !~ */,
          +          "break", "case", "continue", "delete",
          +          "do", "else", "finally", "instanceof",
          +          "return", "throw", "try", "typeof"
          +          ];
          +      var pattern = '(?:^^|[+-]';
          +      for (var i = 0; i < preceders.length; ++i) {
          +        pattern += '|' + preceders[i].replace(/([^=<>:&a-z])/g, '\\$1');
          +      }
          +      pattern += ')\\s*';  // matches at end, and matches empty string
          +      return pattern;
          +      // CAVEAT: this does not properly handle the case where a regular
          +      // expression immediately follows another since a regular expression may
          +      // have flags for case-sensitivity and the like.  Having regexp tokens
          +      // adjacent is not valid in any language I'm aware of, so I'm punting.
          +      // TODO: maybe style special characters inside a regexp as punctuation.
          +    }();
          +
          +  // Define regexps here so that the interpreter doesn't have to create an
          +  // object each time the function containing them is called.
          +  // The language spec requires a new object created even if you don't access
          +  // the $1 members.
          +  var pr_amp = /&/g;
          +  var pr_lt = /</g;
          +  var pr_gt = />/g;
          +  var pr_quot = /\"/g;
          +  /** like textToHtml but escapes double quotes to be attribute safe. */
          +  function attribToHtml(str) {
          +    return str.replace(pr_amp, '&amp;')
          +        .replace(pr_lt, '&lt;')
          +        .replace(pr_gt, '&gt;')
          +        .replace(pr_quot, '&quot;');
          +  }
          +
          +  /** escapest html special characters to html. */
          +  function textToHtml(str) {
          +    return str.replace(pr_amp, '&amp;')
          +        .replace(pr_lt, '&lt;')
          +        .replace(pr_gt, '&gt;');
          +  }
          +
          +
          +  var pr_ltEnt = /&lt;/g;
          +  var pr_gtEnt = /&gt;/g;
          +  var pr_aposEnt = /&apos;/g;
          +  var pr_quotEnt = /&quot;/g;
          +  var pr_ampEnt = /&amp;/g;
          +  var pr_nbspEnt = /&nbsp;/g;
          +  /** unescapes html to plain text. */
          +  function htmlToText(html) {
          +    var pos = html.indexOf('&');
          +    if (pos < 0) { return html; }
          +    // Handle numeric entities specially.  We can't use functional substitution
          +    // since that doesn't work in older versions of Safari.
          +    // These should be rare since most browsers convert them to normal chars.
          +    for (--pos; (pos = html.indexOf('&#', pos + 1)) >= 0;) {
          +      var end = html.indexOf(';', pos);
          +      if (end >= 0) {
          +        var num = html.substring(pos + 3, end);
          +        var radix = 10;
          +        if (num && num.charAt(0) === 'x') {
          +          num = num.substring(1);
          +          radix = 16;
          +        }
          +        var codePoint = parseInt(num, radix);
          +        if (!isNaN(codePoint)) {
          +          html = (html.substring(0, pos) + String.fromCharCode(codePoint) +
          +                  html.substring(end + 1));
          +        }
          +      }
          +    }
          +
          +    return html.replace(pr_ltEnt, '<')
          +        .replace(pr_gtEnt, '>')
          +        .replace(pr_aposEnt, "'")
          +        .replace(pr_quotEnt, '"')
          +        .replace(pr_nbspEnt, ' ')
          +        .replace(pr_ampEnt, '&');
          +  }
          +
          +  /** is the given node's innerHTML normally unescaped? */
          +  function isRawContent(node) {
          +    return 'XMP' === node.tagName;
          +  }
          +
          +  var newlineRe = /[\r\n]/g;
          +  /**
          +   * Are newlines and adjacent spaces significant in the given node's innerHTML?
          +   */
          +  function isPreformatted(node, content) {
          +    // PRE means preformatted, and is a very common case, so don't create
          +    // unnecessary computed style objects.
          +    if ('PRE' === node.tagName) { return true; }
          +    if (!newlineRe.test(content)) { return true; }  // Don't care
          +    var whitespace = '';
          +    // For disconnected nodes, IE has no currentStyle.
          +    if (node.currentStyle) {
          +      whitespace = node.currentStyle.whiteSpace;
          +    } else if (window.getComputedStyle) {
          +      // Firefox makes a best guess if node is disconnected whereas Safari
          +      // returns the empty string.
          +      whitespace = window.getComputedStyle(node, null).whiteSpace;
          +    }
          +    return !whitespace || whitespace === 'pre';
          +  }
          +
          +  function normalizedHtml(node, out) {
          +    switch (node.nodeType) {
          +      case 1:  // an element
          +        var name = node.tagName.toLowerCase();
          +        out.push('<', name);
          +        for (var i = 0; i < node.attributes.length; ++i) {
          +          var attr = node.attributes[i];
          +          if (!attr.specified) { continue; }
          +          out.push(' ');
          +          normalizedHtml(attr, out);
          +        }
          +        out.push('>');
          +        for (var child = node.firstChild; child; child = child.nextSibling) {
          +          normalizedHtml(child, out);
          +        }
          +        if (node.firstChild || !/^(?:br|link|img)$/.test(name)) {
          +          out.push('<\/', name, '>');
          +        }
          +        break;
          +      case 2: // an attribute
          +        out.push(node.name.toLowerCase(), '="', attribToHtml(node.value), '"');
          +        break;
          +      case 3: case 4: // text
          +        out.push(textToHtml(node.nodeValue));
          +        break;
          +    }
          +  }
          +
          +  /**
          +   * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally
          +   * matches the union o the sets o strings matched d by the input RegExp.
          +   * Since it matches globally, if the input strings have a start-of-input
          +   * anchor (/^.../), it is ignored for the purposes of unioning.
          +   * @param {Array.<RegExp>} regexs non multiline, non-global regexs.
          +   * @return {RegExp} a global regex.
          +   */
          +  function combinePrefixPatterns(regexs) {
          +    var capturedGroupIndex = 0;
          +
          +    var needToFoldCase = false;
          +    var ignoreCase = false;
          +    for (var i = 0, n = regexs.length; i < n; ++i) {
          +      var regex = regexs[i];
          +      if (regex.ignoreCase) {
          +        ignoreCase = true;
          +      } else if (/[a-z]/i.test(regex.source.replace(
          +                     /\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi, ''))) {
          +        needToFoldCase = true;
          +        ignoreCase = false;
          +        break;
          +      }
          +    }
          +
          +    function decodeEscape(charsetPart) {
          +      if (charsetPart.charAt(0) !== '\\') { return charsetPart.charCodeAt(0); }
          +      switch (charsetPart.charAt(1)) {
          +        case 'b': return 8;
          +        case 't': return 9;
          +        case 'n': return 0xa;
          +        case 'v': return 0xb;
          +        case 'f': return 0xc;
          +        case 'r': return 0xd;
          +        case 'u': case 'x':
          +          return parseInt(charsetPart.substring(2), 16)
          +              || charsetPart.charCodeAt(1);
          +        case '0': case '1': case '2': case '3': case '4':
          +        case '5': case '6': case '7':
          +          return parseInt(charsetPart.substring(1), 8);
          +        default: return charsetPart.charCodeAt(1);
          +      }
          +    }
          +
          +    function encodeEscape(charCode) {
          +      if (charCode < 0x20) {
          +        return (charCode < 0x10 ? '\\x0' : '\\x') + charCode.toString(16);
          +      }
          +      var ch = String.fromCharCode(charCode);
          +      if (ch === '\\' || ch === '-' || ch === '[' || ch === ']') {
          +        ch = '\\' + ch;
          +      }
          +      return ch;
          +    }
          +
          +    function caseFoldCharset(charSet) {
          +      var charsetParts = charSet.substring(1, charSet.length - 1).match(
          +          new RegExp(
          +              '\\\\u[0-9A-Fa-f]{4}'
          +              + '|\\\\x[0-9A-Fa-f]{2}'
          +              + '|\\\\[0-3][0-7]{0,2}'
          +              + '|\\\\[0-7]{1,2}'
          +              + '|\\\\[\\s\\S]'
          +              + '|-'
          +              + '|[^-\\\\]',
          +              'g'));
          +      var groups = [];
          +      var ranges = [];
          +      var inverse = charsetParts[0] === '^';
          +      for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {
          +        var p = charsetParts[i];
          +        switch (p) {
          +          case '\\B': case '\\b':
          +          case '\\D': case '\\d':
          +          case '\\S': case '\\s':
          +          case '\\W': case '\\w':
          +            groups.push(p);
          +            continue;
          +        }
          +        var start = decodeEscape(p);
          +        var end;
          +        if (i + 2 < n && '-' === charsetParts[i + 1]) {
          +          end = decodeEscape(charsetParts[i + 2]);
          +          i += 2;
          +        } else {
          +          end = start;
          +        }
          +        ranges.push([start, end]);
          +        // If the range might intersect letters, then expand it.
          +        if (!(end < 65 || start > 122)) {
          +          if (!(end < 65 || start > 90)) {
          +            ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);
          +          }
          +          if (!(end < 97 || start > 122)) {
          +            ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);
          +          }
          +        }
          +      }
          +
          +      // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]
          +      // -> [[1, 12], [14, 14], [16, 17]]
          +      ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1]  - a[1]); });
          +      var consolidatedRanges = [];
          +      var lastRange = [NaN, NaN];
          +      for (var i = 0; i < ranges.length; ++i) {
          +        var range = ranges[i];
          +        if (range[0] <= lastRange[1] + 1) {
          +          lastRange[1] = Math.max(lastRange[1], range[1]);
          +        } else {
          +          consolidatedRanges.push(lastRange = range);
          +        }
          +      }
          +
          +      var out = ['['];
          +      if (inverse) { out.push('^'); }
          +      out.push.apply(out, groups);
          +      for (var i = 0; i < consolidatedRanges.length; ++i) {
          +        var range = consolidatedRanges[i];
          +        out.push(encodeEscape(range[0]));
          +        if (range[1] > range[0]) {
          +          if (range[1] + 1 > range[0]) { out.push('-'); }
          +          out.push(encodeEscape(range[1]));
          +        }
          +      }
          +      out.push(']');
          +      return out.join('');
          +    }
          +
          +    function allowAnywhereFoldCaseAndRenumberGroups(regex) {
          +      // Split into character sets, escape sequences, punctuation strings
          +      // like ('(', '(?:', ')', '^'), and runs of characters that do not
          +      // include any of the above.
          +      var parts = regex.source.match(
          +          new RegExp(
          +              '(?:'
          +              + '\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]'  // a character set
          +              + '|\\\\u[A-Fa-f0-9]{4}'  // a unicode escape
          +              + '|\\\\x[A-Fa-f0-9]{2}'  // a hex escape
          +              + '|\\\\[0-9]+'  // a back-reference or octal escape
          +              + '|\\\\[^ux0-9]'  // other escape sequence
          +              + '|\\(\\?[:!=]'  // start of a non-capturing group
          +              + '|[\\(\\)\\^]'  // start/emd of a group, or line start
          +              + '|[^\\x5B\\x5C\\(\\)\\^]+'  // run of other characters
          +              + ')',
          +              'g'));
          +      var n = parts.length;
          +
          +      // Maps captured group numbers to the number they will occupy in
          +      // the output or to -1 if that has not been determined, or to
          +      // undefined if they need not be capturing in the output.
          +      var capturedGroups = [];
          +
          +      // Walk over and identify back references to build the capturedGroups
          +      // mapping.
          +      for (var i = 0, groupIndex = 0; i < n; ++i) {
          +        var p = parts[i];
          +        if (p === '(') {
          +          // groups are 1-indexed, so max group index is count of '('
          +          ++groupIndex;
          +        } else if ('\\' === p.charAt(0)) {
          +          var decimalValue = +p.substring(1);
          +          if (decimalValue && decimalValue <= groupIndex) {
          +            capturedGroups[decimalValue] = -1;
          +          }
          +        }
          +      }
          +
          +      // Renumber groups and reduce capturing groups to non-capturing groups
          +      // where possible.
          +      for (var i = 1; i < capturedGroups.length; ++i) {
          +        if (-1 === capturedGroups[i]) {
          +          capturedGroups[i] = ++capturedGroupIndex;
          +        }
          +      }
          +      for (var i = 0, groupIndex = 0; i < n; ++i) {
          +        var p = parts[i];
          +        if (p === '(') {
          +          ++groupIndex;
          +          if (capturedGroups[groupIndex] === undefined) {
          +            parts[i] = '(?:';
          +          }
          +        } else if ('\\' === p.charAt(0)) {
          +          var decimalValue = +p.substring(1);
          +          if (decimalValue && decimalValue <= groupIndex) {
          +            parts[i] = '\\' + capturedGroups[groupIndex];
          +          }
          +        }
          +      }
          +
          +      // Remove any prefix anchors so that the output will match anywhere.
          +      // ^^ really does mean an anchored match though.
          +      for (var i = 0, groupIndex = 0; i < n; ++i) {
          +        if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; }
          +      }
          +
          +      // Expand letters to groupts to handle mixing of case-sensitive and
          +      // case-insensitive patterns if necessary.
          +      if (regex.ignoreCase && needToFoldCase) {
          +        for (var i = 0; i < n; ++i) {
          +          var p = parts[i];
          +          var ch0 = p.charAt(0);
          +          if (p.length >= 2 && ch0 === '[') {
          +            parts[i] = caseFoldCharset(p);
          +          } else if (ch0 !== '\\') {
          +            // TODO: handle letters in numeric escapes.
          +            parts[i] = p.replace(
          +                /[a-zA-Z]/g,
          +                function (ch) {
          +                  var cc = ch.charCodeAt(0);
          +                  return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']';
          +                });
          +          }
          +        }
          +      }
          +
          +      return parts.join('');
          +    }
          +
          +    var rewritten = [];
          +    for (var i = 0, n = regexs.length; i < n; ++i) {
          +      var regex = regexs[i];
          +      if (regex.global || regex.multiline) { throw new Error('' + regex); }
          +      rewritten.push(
          +          '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')');
          +    }
          +
          +    return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g');
          +  }
          +
          +  var PR_innerHtmlWorks = null;
          +  function getInnerHtml(node) {
          +    // inner html is hopelessly broken in Safari 2.0.4 when the content is
          +    // an html description of well formed XML and the containing tag is a PRE
          +    // tag, so we detect that case and emulate innerHTML.
          +    if (null === PR_innerHtmlWorks) {
          +      var testNode = document.createElement('PRE');
          +      testNode.appendChild(
          +          document.createTextNode('<!DOCTYPE foo PUBLIC "foo bar">\n<foo />'));
          +      PR_innerHtmlWorks = !/</.test(testNode.innerHTML);
          +    }
          +
          +    if (PR_innerHtmlWorks) {
          +      var content = node.innerHTML;
          +      // XMP tags contain unescaped entities so require special handling.
          +      if (isRawContent(node)) {
          +        content = textToHtml(content);
          +      } else if (!isPreformatted(node, content)) {
          +        content = content.replace(/(<br\s*\/?>)[\r\n]+/g, '$1')
          +            .replace(/(?:[\r\n]+[ \t]*)+/g, ' ');
          +      }
          +      return content;
          +    }
          +
          +    var out = [];
          +    for (var child = node.firstChild; child; child = child.nextSibling) {
          +      normalizedHtml(child, out);
          +    }
          +    return out.join('');
          +  }
          +
          +  /** returns a function that expand tabs to spaces.  This function can be fed
          +    * successive chunks of text, and will maintain its own internal state to
          +    * keep track of how tabs are expanded.
          +    * @return {function (string) : string} a function that takes
          +    *   plain text and return the text with tabs expanded.
          +    * @private
          +    */
          +  function makeTabExpander(tabWidth) {
          +    var SPACES = '                ';
          +    var charInLine = 0;
          +
          +    return function (plainText) {
          +      // walk over each character looking for tabs and newlines.
          +      // On tabs, expand them.  On newlines, reset charInLine.
          +      // Otherwise increment charInLine
          +      var out = null;
          +      var pos = 0;
          +      for (var i = 0, n = plainText.length; i < n; ++i) {
          +        var ch = plainText.charAt(i);
          +
          +        switch (ch) {
          +          case '\t':
          +            if (!out) { out = []; }
          +            out.push(plainText.substring(pos, i));
          +            // calculate how much space we need in front of this part
          +            // nSpaces is the amount of padding -- the number of spaces needed
          +            // to move us to the next column, where columns occur at factors of
          +            // tabWidth.
          +            var nSpaces = tabWidth - (charInLine % tabWidth);
          +            charInLine += nSpaces;
          +            for (; nSpaces >= 0; nSpaces -= SPACES.length) {
          +              out.push(SPACES.substring(0, nSpaces));
          +            }
          +            pos = i + 1;
          +            break;
          +          case '\n':
          +            charInLine = 0;
          +            break;
          +          default:
          +            ++charInLine;
          +        }
          +      }
          +      if (!out) { return plainText; }
          +      out.push(plainText.substring(pos));
          +      return out.join('');
          +    };
          +  }
          +
          +  var pr_chunkPattern = new RegExp(
          +      '[^<]+'  // A run of characters other than '<'
          +      + '|<\!--[\\s\\S]*?--\>'  // an HTML comment
          +      + '|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>'  // a CDATA section
          +      // a probable tag that should not be highlighted
          +      + '|<\/?[a-zA-Z](?:[^>\"\']|\'[^\']*\'|\"[^\"]*\")*>'
          +      + '|<',  // A '<' that does not begin a larger chunk
          +      'g');
          +  var pr_commentPrefix = /^<\!--/;
          +  var pr_cdataPrefix = /^<!\[CDATA\[/;
          +  var pr_brPrefix = /^<br\b/i;
          +  var pr_tagNameRe = /^<(\/?)([a-zA-Z][a-zA-Z0-9]*)/;
          +
          +  /** split markup into chunks of html tags (style null) and
          +    * plain text (style {@link #PR_PLAIN}), converting tags which are
          +    * significant for tokenization (<br>) into their textual equivalent.
          +    *
          +    * @param {string} s html where whitespace is considered significant.
          +    * @return {Object} source code and extracted tags.
          +    * @private
          +    */
          +  function extractTags(s) {
          +    // since the pattern has the 'g' modifier and defines no capturing groups,
          +    // this will return a list of all chunks which we then classify and wrap as
          +    // PR_Tokens
          +    var matches = s.match(pr_chunkPattern);
          +    var sourceBuf = [];
          +    var sourceBufLen = 0;
          +    var extractedTags = [];
          +    if (matches) {
          +      for (var i = 0, n = matches.length; i < n; ++i) {
          +        var match = matches[i];
          +        if (match.length > 1 && match.charAt(0) === '<') {
          +          if (pr_commentPrefix.test(match)) { continue; }
          +          if (pr_cdataPrefix.test(match)) {
          +            // strip CDATA prefix and suffix.  Don't unescape since it's CDATA
          +            sourceBuf.push(match.substring(9, match.length - 3));
          +            sourceBufLen += match.length - 12;
          +          } else if (pr_brPrefix.test(match)) {
          +            // <br> tags are lexically significant so convert them to text.
          +            // This is undone later.
          +            sourceBuf.push('\n');
          +            ++sourceBufLen;
          +          } else {
          +            if (match.indexOf(PR_NOCODE) >= 0 && isNoCodeTag(match)) {
          +              // A <span class="nocode"> will start a section that should be
          +              // ignored.  Continue walking the list until we see a matching end
          +              // tag.
          +              var name = match.match(pr_tagNameRe)[2];
          +              var depth = 1;
          +              var j;
          +              end_tag_loop:
          +              for (j = i + 1; j < n; ++j) {
          +                var name2 = matches[j].match(pr_tagNameRe);
          +                if (name2 && name2[2] === name) {
          +                  if (name2[1] === '/') {
          +                    if (--depth === 0) { break end_tag_loop; }
          +                  } else {
          +                    ++depth;
          +                  }
          +                }
          +              }
          +              if (j < n) {
          +                extractedTags.push(
          +                    sourceBufLen, matches.slice(i, j + 1).join(''));
          +                i = j;
          +              } else {  // Ignore unclosed sections.
          +                extractedTags.push(sourceBufLen, match);
          +              }
          +            } else {
          +              extractedTags.push(sourceBufLen, match);
          +            }
          +          }
          +        } else {
          +          var literalText = htmlToText(match);
          +          sourceBuf.push(literalText);
          +          sourceBufLen += literalText.length;
          +        }
          +      }
          +    }
          +    return { source: sourceBuf.join(''), tags: extractedTags };
          +  }
          +
          +  /** True if the given tag contains a class attribute with the nocode class. */
          +  function isNoCodeTag(tag) {
          +    return !!tag
          +        // First canonicalize the representation of attributes
          +        .replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g,
          +                 ' $1="$2$3$4"')
          +        // Then look for the attribute we want.
          +        .match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/);
          +  }
          +
          +  /**
          +   * Apply the given language handler to sourceCode and add the resulting
          +   * decorations to out.
          +   * @param {number} basePos the index of sourceCode within the chunk of source
          +   *    whose decorations are already present on out.
          +   */
          +  function appendDecorations(basePos, sourceCode, langHandler, out) {
          +    if (!sourceCode) { return; }
          +    var job = {
          +      source: sourceCode,
          +      basePos: basePos
          +    };
          +    langHandler(job);
          +    out.push.apply(out, job.decorations);
          +  }
          +
          +  /** Given triples of [style, pattern, context] returns a lexing function,
          +    * The lexing function interprets the patterns to find token boundaries and
          +    * returns a decoration list of the form
          +    * [index_0, style_0, index_1, style_1, ..., index_n, style_n]
          +    * where index_n is an index into the sourceCode, and style_n is a style
          +    * constant like PR_PLAIN.  index_n-1 <= index_n, and style_n-1 applies to
          +    * all characters in sourceCode[index_n-1:index_n].
          +    *
          +    * The stylePatterns is a list whose elements have the form
          +    * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].
          +    *
          +    * Style is a style constant like PR_PLAIN, or can be a string of the
          +    * form 'lang-FOO', where FOO is a language extension describing the
          +    * language of the portion of the token in $1 after pattern executes.
          +    * E.g., if style is 'lang-lisp', and group 1 contains the text
          +    * '(hello (world))', then that portion of the token will be passed to the
          +    * registered lisp handler for formatting.
          +    * The text before and after group 1 will be restyled using this decorator
          +    * so decorators should take care that this doesn't result in infinite
          +    * recursion.  For example, the HTML lexer rule for SCRIPT elements looks
          +    * something like ['lang-js', /<[s]cript>(.+?)<\/script>/].  This may match
          +    * '<script>foo()<\/script>', which would cause the current decorator to
          +    * be called with '<script>' which would not match the same rule since
          +    * group 1 must not be empty, so it would be instead styled as PR_TAG by
          +    * the generic tag rule.  The handler registered for the 'js' extension would
          +    * then be called with 'foo()', and finally, the current decorator would
          +    * be called with '<\/script>' which would not match the original rule and
          +    * so the generic tag rule would identify it as a tag.
          +    *
          +    * Pattern must only match prefixes, and if it matches a prefix, then that
          +    * match is considered a token with the same style.
          +    *
          +    * Context is applied to the last non-whitespace, non-comment token
          +    * recognized.
          +    *
          +    * Shortcut is an optional string of characters, any of which, if the first
          +    * character, gurantee that this pattern and only this pattern matches.
          +    *
          +    * @param {Array} shortcutStylePatterns patterns that always start with
          +    *   a known character.  Must have a shortcut string.
          +    * @param {Array} fallthroughStylePatterns patterns that will be tried in
          +    *   order if the shortcut ones fail.  May have shortcuts.
          +    *
          +    * @return {function (Object)} a
          +    *   function that takes source code and returns a list of decorations.
          +    */
          +  function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) {
          +    var shortcuts = {};
          +    var tokenizer;
          +    (function () {
          +      var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);
          +      var allRegexs = [];
          +      var regexKeys = {};
          +      for (var i = 0, n = allPatterns.length; i < n; ++i) {
          +        var patternParts = allPatterns[i];
          +        var shortcutChars = patternParts[3];
          +        if (shortcutChars) {
          +          for (var c = shortcutChars.length; --c >= 0;) {
          +            shortcuts[shortcutChars.charAt(c)] = patternParts;
          +          }
          +        }
          +        var regex = patternParts[1];
          +        var k = '' + regex;
          +        if (!regexKeys.hasOwnProperty(k)) {
          +          allRegexs.push(regex);
          +          regexKeys[k] = null;
          +        }
          +      }
          +      allRegexs.push(/[\0-\uffff]/);
          +      tokenizer = combinePrefixPatterns(allRegexs);
          +    })();
          +
          +    var nPatterns = fallthroughStylePatterns.length;
          +    var notWs = /\S/;
          +
          +    /**
          +     * Lexes job.source and produces an output array job.decorations of style
          +     * classes preceded by the position at which they start in job.source in
          +     * order.
          +     *
          +     * @param {Object} job an object like {@code
          +     *    source: {string} sourceText plain text,
          +     *    basePos: {int} position of job.source in the larger chunk of
          +     *        sourceCode.
          +     * }
          +     */
          +    var decorate = function (job) {
          +      var sourceCode = job.source, basePos = job.basePos;
          +      /** Even entries are positions in source in ascending order.  Odd enties
          +        * are style markers (e.g., PR_COMMENT) that run from that position until
          +        * the end.
          +        * @type {Array.<number|string>}
          +        */
          +      var decorations = [basePos, PR_PLAIN];
          +      var pos = 0;  // index into sourceCode
          +      var tokens = sourceCode.match(tokenizer) || [];
          +      var styleCache = {};
          +
          +      for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) {
          +        var token = tokens[ti];
          +        var style = styleCache[token];
          +        var match = void 0;
          +
          +        var isEmbedded;
          +        if (typeof style === 'string') {
          +          isEmbedded = false;
          +        } else {
          +          var patternParts = shortcuts[token.charAt(0)];
          +          if (patternParts) {
          +            match = token.match(patternParts[1]);
          +            style = patternParts[0];
          +          } else {
          +            for (var i = 0; i < nPatterns; ++i) {
          +              patternParts = fallthroughStylePatterns[i];
          +              match = token.match(patternParts[1]);
          +              if (match) {
          +                style = patternParts[0];
          +                break;
          +              }
          +            }
          +
          +            if (!match) {  // make sure that we make progress
          +              style = PR_PLAIN;
          +            }
          +          }
          +
          +          isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5);
          +          if (isEmbedded && !(match && typeof match[1] === 'string')) {
          +            isEmbedded = false;
          +            style = PR_SOURCE;
          +          }
          +
          +          if (!isEmbedded) { styleCache[token] = style; }
          +        }
          +
          +        var tokenStart = pos;
          +        pos += token.length;
          +
          +        if (!isEmbedded) {
          +          decorations.push(basePos + tokenStart, style);
          +        } else {  // Treat group 1 as an embedded block of source code.
          +          var embeddedSource = match[1];
          +          var embeddedSourceStart = token.indexOf(embeddedSource);
          +          var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length;
          +          if (match[2]) {
          +            // If embeddedSource can be blank, then it would match at the
          +            // beginning which would cause us to infinitely recurse on the
          +            // entire token, so we catch the right context in match[2].
          +            embeddedSourceEnd = token.length - match[2].length;
          +            embeddedSourceStart = embeddedSourceEnd - embeddedSource.length;
          +          }
          +          var lang = style.substring(5);
          +          // Decorate the left of the embedded source
          +          appendDecorations(
          +              basePos + tokenStart,
          +              token.substring(0, embeddedSourceStart),
          +              decorate, decorations);
          +          // Decorate the embedded source
          +          appendDecorations(
          +              basePos + tokenStart + embeddedSourceStart,
          +              embeddedSource,
          +              langHandlerForExtension(lang, embeddedSource),
          +              decorations);
          +          // Decorate the right of the embedded section
          +          appendDecorations(
          +              basePos + tokenStart + embeddedSourceEnd,
          +              token.substring(embeddedSourceEnd),
          +              decorate, decorations);
          +        }
          +      }
          +      job.decorations = decorations;
          +    };
          +    return decorate;
          +  }
          +
          +  /** returns a function that produces a list of decorations from source text.
          +    *
          +    * This code treats ", ', and ` as string delimiters, and \ as a string
          +    * escape.  It does not recognize perl's qq() style strings.
          +    * It has no special handling for double delimiter escapes as in basic, or
          +    * the tripled delimiters used in python, but should work on those regardless
          +    * although in those cases a single string literal may be broken up into
          +    * multiple adjacent string literals.
          +    *
          +    * It recognizes C, C++, and shell style comments.
          +    *
          +    * @param {Object} options a set of optional parameters.
          +    * @return {function (Object)} a function that examines the source code
          +    *     in the input job and builds the decoration list.
          +    */
          +  function sourceDecorator(options) {
          +    var shortcutStylePatterns = [], fallthroughStylePatterns = [];
          +    if (options['tripleQuotedStrings']) {
          +      // '''multi-line-string''', 'single-line-string', and double-quoted
          +      shortcutStylePatterns.push(
          +          [PR_STRING,  /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
          +           null, '\'"']);
          +    } else if (options['multiLineStrings']) {
          +      // 'multi-line-string', "multi-line-string"
          +      shortcutStylePatterns.push(
          +          [PR_STRING,  /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,
          +           null, '\'"`']);
          +    } else {
          +      // 'single-line-string', "single-line-string"
          +      shortcutStylePatterns.push(
          +          [PR_STRING,
          +           /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,
          +           null, '"\'']);
          +    }
          +    if (options['verbatimStrings']) {
          +      // verbatim-string-literal production from the C# grammar.  See issue 93.
          +      fallthroughStylePatterns.push(
          +          [PR_STRING, /^@\"(?:[^\"]|\"\")*(?:\"|$)/, null]);
          +    }
          +    if (options['hashComments']) {
          +      if (options['cStyleComments']) {
          +        // Stop C preprocessor declarations at an unclosed open comment
          +        shortcutStylePatterns.push(
          +            [PR_COMMENT, /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,
          +             null, '#']);
          +        fallthroughStylePatterns.push(
          +            [PR_STRING,
          +             /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,
          +             null]);
          +      } else {
          +        shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']);
          +      }
          +    }
          +    if (options['cStyleComments']) {
          +      fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]);
          +      fallthroughStylePatterns.push(
          +          [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]);
          +    }
          +    if (options['regexLiterals']) {
          +      var REGEX_LITERAL = (
          +          // A regular expression literal starts with a slash that is
          +          // not followed by * or / so that it is not confused with
          +          // comments.
          +          '/(?=[^/*])'
          +          // and then contains any number of raw characters,
          +          + '(?:[^/\\x5B\\x5C]'
          +          // escape sequences (\x5C),
          +          +    '|\\x5C[\\s\\S]'
          +          // or non-nesting character sets (\x5B\x5D);
          +          +    '|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+'
          +          // finally closed by a /.
          +          + '/');
          +      fallthroughStylePatterns.push(
          +          ['lang-regex',
          +           new RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')')
          +           ]);
          +    }
          +
          +    var keywords = options['keywords'].replace(/^\s+|\s+$/g, '');
          +    if (keywords.length) {
          +      fallthroughStylePatterns.push(
          +          [PR_KEYWORD,
          +           new RegExp('^(?:' + keywords.replace(/\s+/g, '|') + ')\\b'), null]);
          +    }
          +
          +    shortcutStylePatterns.push([PR_PLAIN,       /^\s+/, null, ' \r\n\t\xA0']);
          +    fallthroughStylePatterns.push(
          +        // TODO(mikesamuel): recognize non-latin letters and numerals in idents
          +        [PR_LITERAL,     /^@[a-z_$][a-z_$@0-9]*/i, null],
          +        [PR_TYPE,        /^@?[A-Z]+[a-z][A-Za-z_$@0-9]*/, null],
          +        [PR_PLAIN,       /^[a-z_$][a-z_$@0-9]*/i, null],
          +        [PR_LITERAL,
          +         new RegExp(
          +             '^(?:'
          +             // A hex number
          +             + '0x[a-f0-9]+'
          +             // or an octal or decimal number,
          +             + '|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)'
          +             // possibly in scientific notation
          +             + '(?:e[+\\-]?\\d+)?'
          +             + ')'
          +             // with an optional modifier like UL for unsigned long
          +             + '[a-z]*', 'i'),
          +         null, '0123456789'],
          +        [PR_PUNCTUATION, /^.[^\s\w\.$@\'\"\`\/\#]*/, null]);
          +
          +    return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns);
          +  }
          +
          +  var decorateSource = sourceDecorator({
          +        'keywords': ALL_KEYWORDS,
          +        'hashComments': true,
          +        'cStyleComments': true,
          +        'multiLineStrings': true,
          +        'regexLiterals': true
          +      });
          +
          +  /** Breaks {@code job.source} around style boundaries in
          +    * {@code job.decorations} while re-interleaving {@code job.extractedTags},
          +    * and leaves the result in {@code job.prettyPrintedHtml}.
          +    * @param {Object} job like {
          +    *    source: {string} source as plain text,
          +    *    extractedTags: {Array.<number|string>} extractedTags chunks of raw
          +    *                   html preceded by their position in {@code job.source}
          +    *                   in order
          +    *    decorations: {Array.<number|string} an array of style classes preceded
          +    *                 by the position at which they start in job.source in order
          +    * }
          +    * @private
          +    */
          +  function recombineTagsAndDecorations(job) {
          +    var sourceText = job.source;
          +    var extractedTags = job.extractedTags;
          +    var decorations = job.decorations;
          +
          +    var html = [];
          +    // index past the last char in sourceText written to html
          +    var outputIdx = 0;
          +
          +    var openDecoration = null;
          +    var currentDecoration = null;
          +    var tagPos = 0;  // index into extractedTags
          +    var decPos = 0;  // index into decorations
          +    var tabExpander = makeTabExpander(window['PR_TAB_WIDTH']);
          +
          +    var adjacentSpaceRe = /([\r\n ]) /g;
          +    var startOrSpaceRe = /(^| ) /gm;
          +    var newlineRe = /\r\n?|\n/g;
          +    var trailingSpaceRe = /[ \r\n]$/;
          +    var lastWasSpace = true;  // the last text chunk emitted ended with a space.
          +
          +    // A helper function that is responsible for opening sections of decoration
          +    // and outputing properly escaped chunks of source
          +    function emitTextUpTo(sourceIdx) {
          +      if (sourceIdx > outputIdx) {
          +        if (openDecoration && openDecoration !== currentDecoration) {
          +          // Close the current decoration
          +          html.push('</span>');
          +          openDecoration = null;
          +        }
          +        if (!openDecoration && currentDecoration) {
          +          openDecoration = currentDecoration;
          +          html.push('<span class="', openDecoration, '">');
          +        }
          +        // This interacts badly with some wikis which introduces paragraph tags
          +        // into pre blocks for some strange reason.
          +        // It's necessary for IE though which seems to lose the preformattedness
          +        // of <pre> tags when their innerHTML is assigned.
          +        // http://stud3.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
          +        // and it serves to undo the conversion of <br>s to newlines done in
          +        // chunkify.
          +        var htmlChunk = textToHtml(
          +            tabExpander(sourceText.substring(outputIdx, sourceIdx)))
          +            .replace(lastWasSpace
          +                     ? startOrSpaceRe
          +                     : adjacentSpaceRe, '$1&nbsp;');
          +        // Keep track of whether we need to escape space at the beginning of the
          +        // next chunk.
          +        lastWasSpace = trailingSpaceRe.test(htmlChunk);
          +        // IE collapses multiple adjacient <br>s into 1 line break.
          +        // Prefix every <br> with '&nbsp;' can prevent such IE's behavior.
          +        var lineBreakHtml = window['_pr_isIE6']() ? '&nbsp;<br />' : '<br />';
          +        html.push(htmlChunk.replace(newlineRe, lineBreakHtml));
          +        outputIdx = sourceIdx;
          +      }
          +    }
          +
          +    while (true) {
          +      // Determine if we're going to consume a tag this time around.  Otherwise
          +      // we consume a decoration or exit.
          +      var outputTag;
          +      if (tagPos < extractedTags.length) {
          +        if (decPos < decorations.length) {
          +          // Pick one giving preference to extractedTags since we shouldn't open
          +          // a new style that we're going to have to immediately close in order
          +          // to output a tag.
          +          outputTag = extractedTags[tagPos] <= decorations[decPos];
          +        } else {
          +          outputTag = true;
          +        }
          +      } else {
          +        outputTag = false;
          +      }
          +      // Consume either a decoration or a tag or exit.
          +      if (outputTag) {
          +        emitTextUpTo(extractedTags[tagPos]);
          +        if (openDecoration) {
          +          // Close the current decoration
          +          html.push('</span>');
          +          openDecoration = null;
          +        }
          +        html.push(extractedTags[tagPos + 1]);
          +        tagPos += 2;
          +      } else if (decPos < decorations.length) {
          +        emitTextUpTo(decorations[decPos]);
          +        currentDecoration = decorations[decPos + 1];
          +        decPos += 2;
          +      } else {
          +        break;
          +      }
          +    }
          +    emitTextUpTo(sourceText.length);
          +    if (openDecoration) {
          +      html.push('</span>');
          +    }
          +    job.prettyPrintedHtml = html.join('');
          +  }
          +
          +  /** Maps language-specific file extensions to handlers. */
          +  var langHandlerRegistry = {};
          +  /** Register a language handler for the given file extensions.
          +    * @param {function (Object)} handler a function from source code to a list
          +    *      of decorations.  Takes a single argument job which describes the
          +    *      state of the computation.   The single parameter has the form
          +    *      {@code {
          +    *        source: {string} as plain text.
          +    *        decorations: {Array.<number|string>} an array of style classes
          +    *                     preceded by the position at which they start in
          +    *                     job.source in order.
          +    *                     The language handler should assigned this field.
          +    *        basePos: {int} the position of source in the larger source chunk.
          +    *                 All positions in the output decorations array are relative
          +    *                 to the larger source chunk.
          +    *      } }
          +    * @param {Array.<string>} fileExtensions
          +    */
          +  function registerLangHandler(handler, fileExtensions) {
          +    for (var i = fileExtensions.length; --i >= 0;) {
          +      var ext = fileExtensions[i];
          +      if (!langHandlerRegistry.hasOwnProperty(ext)) {
          +        langHandlerRegistry[ext] = handler;
          +      } else if ('console' in window) {
          +        console.warn('cannot override language handler %s', ext);
          +      }
          +    }
          +  }
          +  function langHandlerForExtension(extension, source) {
          +    if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) {
          +      // Treat it as markup if the first non whitespace character is a < and
          +      // the last non-whitespace character is a >.
          +      extension = /^\s*</.test(source)
          +          ? 'default-markup'
          +          : 'default-code';
          +    }
          +    return langHandlerRegistry[extension];
          +  }
          +  registerLangHandler(decorateSource, ['default-code']);
          +  registerLangHandler(
          +      createSimpleLexer(
          +          [],
          +          [
          +           [PR_PLAIN,       /^[^<?]+/],
          +           [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/],
          +           [PR_COMMENT,     /^<\!--[\s\S]*?(?:-\->|$)/],
          +           // Unescaped content in an unknown language
          +           ['lang-',        /^<\?([\s\S]+?)(?:\?>|$)/],
          +           ['lang-',        /^<%([\s\S]+?)(?:%>|$)/],
          +           [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/],
          +           ['lang-',        /^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],
          +           // Unescaped content in javascript.  (Or possibly vbscript).
          +           ['lang-js',      /^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],
          +           // Contains unescaped stylesheet content
          +           ['lang-css',     /^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],
          +           ['lang-in.tag',  /^(<\/?[a-z][^<>]*>)/i]
          +          ]),
          +      ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']);
          +  registerLangHandler(
          +      createSimpleLexer(
          +          [
          +           [PR_PLAIN,        /^[\s]+/, null, ' \t\r\n'],
          +           [PR_ATTRIB_VALUE, /^(?:\"[^\"]*\"?|\'[^\']*\'?)/, null, '\"\'']
          +           ],
          +          [
          +           [PR_TAG,          /^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],
          +           [PR_ATTRIB_NAME,  /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],
          +           ['lang-uq.val',   /^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],
          +           [PR_PUNCTUATION,  /^[=<>\/]+/],
          +           ['lang-js',       /^on\w+\s*=\s*\"([^\"]+)\"/i],
          +           ['lang-js',       /^on\w+\s*=\s*\'([^\']+)\'/i],
          +           ['lang-js',       /^on\w+\s*=\s*([^\"\'>\s]+)/i],
          +           ['lang-css',      /^style\s*=\s*\"([^\"]+)\"/i],
          +           ['lang-css',      /^style\s*=\s*\'([^\']+)\'/i],
          +           ['lang-css',      /^style\s*=\s*([^\"\'>\s]+)/i]
          +           ]),
          +      ['in.tag']);
          +  registerLangHandler(
          +      createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\s\S]+/]]), ['uq.val']);
          +  registerLangHandler(sourceDecorator({
          +          'keywords': CPP_KEYWORDS,
          +          'hashComments': true,
          +          'cStyleComments': true
          +        }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']);
          +  registerLangHandler(sourceDecorator({
          +          'keywords': 'null true false'
          +        }), ['json']);
          +  registerLangHandler(sourceDecorator({
          +          'keywords': CSHARP_KEYWORDS,
          +          'hashComments': true,
          +          'cStyleComments': true,
          +          'verbatimStrings': true
          +        }), ['cs']);
          +  registerLangHandler(sourceDecorator({
          +          'keywords': JAVA_KEYWORDS,
          +          'cStyleComments': true
          +        }), ['java']);
          +  registerLangHandler(sourceDecorator({
          +          'keywords': SH_KEYWORDS,
          +          'hashComments': true,
          +          'multiLineStrings': true
          +        }), ['bsh', 'csh', 'sh']);
          +  registerLangHandler(sourceDecorator({
          +          'keywords': PYTHON_KEYWORDS,
          +          'hashComments': true,
          +          'multiLineStrings': true,
          +          'tripleQuotedStrings': true
          +        }), ['cv', 'py']);
          +  registerLangHandler(sourceDecorator({
          +          'keywords': PERL_KEYWORDS,
          +          'hashComments': true,
          +          'multiLineStrings': true,
          +          'regexLiterals': true
          +        }), ['perl', 'pl', 'pm']);
          +  registerLangHandler(sourceDecorator({
          +          'keywords': RUBY_KEYWORDS,
          +          'hashComments': true,
          +          'multiLineStrings': true,
          +          'regexLiterals': true
          +        }), ['rb']);
          +  registerLangHandler(sourceDecorator({
          +          'keywords': JSCRIPT_KEYWORDS,
          +          'cStyleComments': true,
          +          'regexLiterals': true
          +        }), ['js']);
          +  registerLangHandler(
          +      createSimpleLexer([], [[PR_STRING, /^[\s\S]+/]]), ['regex']);
          +
          +  function applyDecorator(job) {
          +    var sourceCodeHtml = job.sourceCodeHtml;
          +    var opt_langExtension = job.langExtension;
          +
          +    // Prepopulate output in case processing fails with an exception.
          +    job.prettyPrintedHtml = sourceCodeHtml;
          +
          +    try {
          +      // Extract tags, and convert the source code to plain text.
          +      var sourceAndExtractedTags = extractTags(sourceCodeHtml);
          +      /** Plain text. @type {string} */
          +      var source = sourceAndExtractedTags.source;
          +      job.source = source;
          +      job.basePos = 0;
          +
          +      /** Even entries are positions in source in ascending order.  Odd entries
          +        * are tags that were extracted at that position.
          +        * @type {Array.<number|string>}
          +        */
          +      job.extractedTags = sourceAndExtractedTags.tags;
          +
          +      // Apply the appropriate language handler
          +      langHandlerForExtension(opt_langExtension, source)(job);
          +      // Integrate the decorations and tags back into the source code to produce
          +      // a decorated html string which is left in job.prettyPrintedHtml.
          +      recombineTagsAndDecorations(job);
          +    } catch (e) {
          +      if ('console' in window) {
          +        console.log(e);
          +        console.trace();
          +      }
          +    }
          +  }
          +
          +  function prettyPrintOne(sourceCodeHtml, opt_langExtension) {
          +    var job = {
          +      sourceCodeHtml: sourceCodeHtml,
          +      langExtension: opt_langExtension
          +    };
          +    applyDecorator(job);
          +    return job.prettyPrintedHtml;
          +  }
          +
          +  function prettyPrint(opt_whenDone) {
          +    var isIE678 = window['_pr_isIE6']();
          +    var ieNewline = isIE678 === 6 ? '\r\n' : '\r';
          +    // See bug 71 and http://stackoverflow.com/questions/136443/why-doesnt-ie7-
          +
          +    // fetch a list of nodes to rewrite
          +    var codeSegments = [
          +        document.getElementsByTagName('pre'),
          +        document.getElementsByTagName('code'),
          +        document.getElementsByTagName('td'),  /* ND Change: Add tables to support prototypes. */
          +        document.getElementsByTagName('xmp') ];
          +    var elements = [];
          +    for (var i = 0; i < codeSegments.length; ++i) {
          +      for (var j = 0, n = codeSegments[i].length; j < n; ++j) {
          +        elements.push(codeSegments[i][j]);
          +      }
          +    }
          +    codeSegments = null;
          +
          +    var clock = Date;
          +    if (!clock['now']) {
          +      clock = { 'now': function () { return (new Date).getTime(); } };
          +    }
          +
          +    // The loop is broken into a series of continuations to make sure that we
          +    // don't make the browser unresponsive when rewriting a large page.
          +    var k = 0;
          +    var prettyPrintingJob;
          +
          +    function doWork() {
          +      var endTime = (window['PR_SHOULD_USE_CONTINUATION'] ?
          +                     clock.now() + 250 /* ms */ :
          +                     Infinity);
          +      for (; k < elements.length && clock.now() < endTime; k++) {
          +        var cs = elements[k];
          +        if (cs.className && cs.className.indexOf('prettyprint') >= 0) {
          +          // If the classes includes a language extensions, use it.
          +          // Language extensions can be specified like
          +          //     <pre class="prettyprint lang-cpp">
          +          // the language extension "cpp" is used to find a language handler as
          +          // passed to PR_registerLangHandler.
          +          var langExtension = cs.className.match(/\blang-(\w+)\b/);
          +          if (langExtension) { langExtension = langExtension[1]; }
          +
          +          // make sure this is not nested in an already prettified element
          +          var nested = false;
          +          for (var p = cs.parentNode; p; p = p.parentNode) {
          +            if ((p.tagName === 'pre' || p.tagName === 'code' ||
          +                 p.tagName === 'xmp' || p.tagName === 'td') &&  /* ND Change: Add tables to support prototypes */
          +                p.className && p.className.indexOf('prettyprint') >= 0) {
          +              nested = true;
          +              break;
          +            }
          +          }
          +          if (!nested) {
          +            // fetch the content as a snippet of properly escaped HTML.
          +            // Firefox adds newlines at the end.
          +            var content = getInnerHtml(cs);
          +            content = content.replace(/(?:\r\n?|\n)$/, '');
          +
          +	  		/* ND Change: we need to preserve &nbsp;s so change them to a special character instead of a space. */
          +			content = content.replace(/&nbsp;/g, '\x11');
          +
          +            // do the pretty printing
          +            prettyPrintingJob = {
          +              sourceCodeHtml: content,
          +              langExtension: langExtension,
          +              sourceNode: cs
          +            };
          +            applyDecorator(prettyPrintingJob);
          +            replaceWithPrettyPrintedHtml();
          +          }
          +        }
          +      }
          +      if (k < elements.length) {
          +        // finish up in a continuation
          +        setTimeout(doWork, 250);
          +      } else if (opt_whenDone) {
          +        opt_whenDone();
          +      }
          +    }
          +
          +    function replaceWithPrettyPrintedHtml() {
          +      var newContent = prettyPrintingJob.prettyPrintedHtml;
          +      if (!newContent) { return; }
          +
          +      /* ND Change: Restore the preserved &nbsp;s.  */
          +	  newContent = newContent.replace(/\x11/g, '&nbsp;');
          +
          +      var cs = prettyPrintingJob.sourceNode;
          +
          +      // push the prettified html back into the tag.
          +      if (!isRawContent(cs)) {
          +        // just replace the old html with the new
          +        cs.innerHTML = newContent;
          +      } else {
          +        // we need to change the tag to a <pre> since <xmp>s do not allow
          +        // embedded tags such as the span tags used to attach styles to
          +        // sections of source code.
          +        var pre = document.createElement('PRE');
          +        for (var i = 0; i < cs.attributes.length; ++i) {
          +          var a = cs.attributes[i];
          +          if (a.specified) {
          +            var aname = a.name.toLowerCase();
          +            if (aname === 'class') {
          +              pre.className = a.value;  // For IE 6
          +            } else {
          +              pre.setAttribute(a.name, a.value);
          +            }
          +          }
          +        }
          +        pre.innerHTML = newContent;
          +
          +        // remove the old
          +        cs.parentNode.replaceChild(pre, cs);
          +        cs = pre;
          +      }
          +
          +      // Replace <br>s with line-feeds so that copying and pasting works
          +      // on IE 6.
          +      // Doing this on other browsers breaks lots of stuff since \r\n is
          +      // treated as two newlines on Firefox, and doing this also slows
          +      // down rendering.
          +      if (isIE678 && cs.tagName === 'PRE') {
          +        var lineBreaks = cs.getElementsByTagName('br');
          +        for (var j = lineBreaks.length; --j >= 0;) {
          +          var lineBreak = lineBreaks[j];
          +          lineBreak.parentNode.replaceChild(
          +              document.createTextNode(ieNewline), lineBreak);
          +        }
          +      }
          +    }
          +
          +    doWork();
          +  }
          +
          +  window['PR_normalizedHtml'] = normalizedHtml;
          +  window['prettyPrintOne'] = prettyPrintOne;
          +  window['prettyPrint'] = prettyPrint;
          +  window['PR'] = {
          +        'combinePrefixPatterns': combinePrefixPatterns,
          +        'createSimpleLexer': createSimpleLexer,
          +        'registerLangHandler': registerLangHandler,
          +        'sourceDecorator': sourceDecorator,
          +        'PR_ATTRIB_NAME': PR_ATTRIB_NAME,
          +        'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,
          +        'PR_COMMENT': PR_COMMENT,
          +        'PR_DECLARATION': PR_DECLARATION,
          +        'PR_KEYWORD': PR_KEYWORD,
          +        'PR_LITERAL': PR_LITERAL,
          +        'PR_NOCODE': PR_NOCODE,
          +        'PR_PLAIN': PR_PLAIN,
          +        'PR_PUNCTUATION': PR_PUNCTUATION,
          +        'PR_SOURCE': PR_SOURCE,
          +        'PR_STRING': PR_STRING,
          +        'PR_TAG': PR_TAG,
          +        'PR_TYPE': PR_TYPE
          +      };
          +})();
          +
          +
          +// ____________________________________________________________________________
          +
          +
          +
          +// Lua extension
          +
          +PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[\t\n\r \xA0]+/,null,'	\n\r \xa0'],[PR.PR_STRING,/^(?:\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)|\'(?:[^\'\\]|\\[\s\S])*(?:\'|$))/,null,'\"\'']],[[PR.PR_COMMENT,/^--(?:\[(=*)\[[\s\S]*?(?:\]\1\]|$)|[^\r\n]*)/],[PR.PR_STRING,/^\[(=*)\[[\s\S]*?(?:\]\1\]|$)/],[PR.PR_KEYWORD,/^(?:and|break|do|else|elseif|end|false|for|function|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,null],[PR.PR_LITERAL,/^[+-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],[PR.PR_PLAIN,/^[a-z_]\w*/i],[PR.PR_PUNCTUATION,/^[^\w\t\n\r \xA0][^\w\t\n\r \xA0\"\'\-\+=]*/]]),['lua'])
          +
          +
          +// Haskell extension
          +
          +PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[\t\n\x0B\x0C\r ]+/,null,'	\n\r '],[PR.PR_STRING,/^\"(?:[^\"\\\n\x0C\r]|\\[\s\S])*(?:\"|$)/,null,'\"'],[PR.PR_STRING,/^\'(?:[^\'\\\n\x0C\r]|\\[^&])\'?/,null,'\''],[PR.PR_LITERAL,/^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+\-]?\d+)?)/i,null,'0123456789']],[[PR.PR_COMMENT,/^(?:(?:--+(?:[^\r\n\x0C]*)?)|(?:\{-(?:[^-]|-+[^-\}])*-\}))/],[PR.PR_KEYWORD,/^(?:case|class|data|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|module|newtype|of|then|type|where|_)(?=[^a-zA-Z0-9\']|$)/,null],[PR.PR_PLAIN,/^(?:[A-Z][\w\']*\.)*[a-zA-Z][\w\']*/],[PR.PR_PUNCTUATION,/^[^\t\n\x0B\x0C\r a-zA-Z0-9\'\"]+/]]),['hs'])
          +
          +
          +// ML extension
          +
          +PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[\t\n\r \xA0]+/,null,'	\n\r \xa0'],[PR.PR_COMMENT,/^#(?:if[\t\n\r \xA0]+(?:[a-z_$][\w\']*|``[^\r\n\t`]*(?:``|$))|else|endif|light)/i,null,'#'],[PR.PR_STRING,/^(?:\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)|\'(?:[^\'\\]|\\[\s\S])*(?:\'|$))/,null,'\"\'']],[[PR.PR_COMMENT,/^(?:\/\/[^\r\n]*|\(\*[\s\S]*?\*\))/],[PR.PR_KEYWORD,/^(?:abstract|and|as|assert|begin|class|default|delegate|do|done|downcast|downto|elif|else|end|exception|extern|false|finally|for|fun|function|if|in|inherit|inline|interface|internal|lazy|let|match|member|module|mutable|namespace|new|null|of|open|or|override|private|public|rec|return|static|struct|then|to|true|try|type|upcast|use|val|void|when|while|with|yield|asr|land|lor|lsl|lsr|lxor|mod|sig|atomic|break|checked|component|const|constraint|constructor|continue|eager|event|external|fixed|functor|global|include|method|mixin|object|parallel|process|protected|pure|sealed|trait|virtual|volatile)\b/],[PR.PR_LITERAL,/^[+\-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],[PR.PR_PLAIN,/^(?:[a-z_]\w*[!?#]?|``[^\r\n\t`]*(?:``|$))/i],[PR.PR_PUNCTUATION,/^[^\t\n\r \xA0\"\'\w]+/]]),['fs','ml'])
          +
          +
          +// SQL extension
          +
          +PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[\t\n\r \xA0]+/,null,'	\n\r \xa0'],[PR.PR_STRING,/^(?:"(?:[^\"\\]|\\.)*"|'(?:[^\'\\]|\\.)*')/,null,'\"\'']],[[PR.PR_COMMENT,/^(?:--[^\r\n]*|\/\*[\s\S]*?(?:\*\/|$))/],[PR.PR_KEYWORD,/^(?:ADD|ALL|ALTER|AND|ANY|AS|ASC|AUTHORIZATION|BACKUP|BEGIN|BETWEEN|BREAK|BROWSE|BULK|BY|CASCADE|CASE|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMN|COMMIT|COMPUTE|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATABASE|DBCC|DEALLOCATE|DECLARE|DEFAULT|DELETE|DENY|DESC|DISK|DISTINCT|DISTRIBUTED|DOUBLE|DROP|DUMMY|DUMP|ELSE|END|ERRLVL|ESCAPE|EXCEPT|EXEC|EXECUTE|EXISTS|EXIT|FETCH|FILE|FILLFACTOR|FOR|FOREIGN|FREETEXT|FREETEXTTABLE|FROM|FULL|FUNCTION|GOTO|GRANT|GROUP|HAVING|HOLDLOCK|IDENTITY|IDENTITYCOL|IDENTITY_INSERT|IF|IN|INDEX|INNER|INSERT|INTERSECT|INTO|IS|JOIN|KEY|KILL|LEFT|LIKE|LINENO|LOAD|NATIONAL|NOCHECK|NONCLUSTERED|NOT|NULL|NULLIF|OF|OFF|OFFSETS|ON|OPEN|OPENDATASOURCE|OPENQUERY|OPENROWSET|OPENXML|OPTION|OR|ORDER|OUTER|OVER|PERCENT|PLAN|PRECISION|PRIMARY|PRINT|PROC|PROCEDURE|PUBLIC|RAISERROR|READ|READTEXT|RECONFIGURE|REFERENCES|REPLICATION|RESTORE|RESTRICT|RETURN|REVOKE|RIGHT|ROLLBACK|ROWCOUNT|ROWGUIDCOL|RULE|SAVE|SCHEMA|SELECT|SESSION_USER|SET|SETUSER|SHUTDOWN|SOME|STATISTICS|SYSTEM_USER|TABLE|TEXTSIZE|THEN|TO|TOP|TRAN|TRANSACTION|TRIGGER|TRUNCATE|TSEQUAL|UNION|UNIQUE|UPDATE|UPDATETEXT|USE|USER|VALUES|VARYING|VIEW|WAITFOR|WHEN|WHERE|WHILE|WITH|WRITETEXT)(?=[^\w-]|$)/i,null],[PR.PR_LITERAL,/^[+-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],[PR.PR_PLAIN,/^[a-z_][\w-]*/i],[PR.PR_PUNCTUATION,/^[^\w\t\n\r \xA0\"\'][^\w\t\n\r \xA0+\-\"\']*/]]),['sql'])
          +
          +
          +// VB extension
          +
          +PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[\t\n\r \xA0\u2028\u2029]+/,null,'	\n\r \xa0\u2028\u2029'],[PR.PR_STRING,/^(?:[\"\u201C\u201D](?:[^\"\u201C\u201D]|[\"\u201C\u201D]{2})(?:[\"\u201C\u201D]c|$)|[\"\u201C\u201D](?:[^\"\u201C\u201D]|[\"\u201C\u201D]{2})*(?:[\"\u201C\u201D]|$))/i,null,'\"\u201c\u201d'],[PR.PR_COMMENT,/^[\'\u2018\u2019][^\r\n\u2028\u2029]*/,null,'\'\u2018\u2019']],[[PR.PR_KEYWORD,/^(?:AddHandler|AddressOf|Alias|And|AndAlso|Ansi|As|Assembly|Auto|Boolean|ByRef|Byte|ByVal|Call|Case|Catch|CBool|CByte|CChar|CDate|CDbl|CDec|Char|CInt|Class|CLng|CObj|Const|CShort|CSng|CStr|CType|Date|Decimal|Declare|Default|Delegate|Dim|DirectCast|Do|Double|Each|Else|ElseIf|End|EndIf|Enum|Erase|Error|Event|Exit|Finally|For|Friend|Function|Get|GetType|GoSub|GoTo|Handles|If|Implements|Imports|In|Inherits|Integer|Interface|Is|Let|Lib|Like|Long|Loop|Me|Mod|Module|MustInherit|MustOverride|MyBase|MyClass|Namespace|New|Next|Not|NotInheritable|NotOverridable|Object|On|Option|Optional|Or|OrElse|Overloads|Overridable|Overrides|ParamArray|Preserve|Private|Property|Protected|Public|RaiseEvent|ReadOnly|ReDim|RemoveHandler|Resume|Return|Select|Set|Shadows|Shared|Short|Single|Static|Step|Stop|String|Structure|Sub|SyncLock|Then|Throw|To|Try|TypeOf|Unicode|Until|Variant|Wend|When|While|With|WithEvents|WriteOnly|Xor|EndIf|GoSub|Let|Variant|Wend)\b/i,null],[PR.PR_COMMENT,/^REM[^\r\n\u2028\u2029]*/i],[PR.PR_LITERAL,/^(?:True\b|False\b|Nothing\b|\d+(?:E[+\-]?\d+[FRD]?|[FRDSIL])?|(?:&H[0-9A-F]+|&O[0-7]+)[SIL]?|\d*\.\d+(?:E[+\-]?\d+)?[FRD]?|#\s+(?:\d+[\-\/]\d+[\-\/]\d+(?:\s+\d+:\d+(?::\d+)?(\s*(?:AM|PM))?)?|\d+:\d+(?::\d+)?(\s*(?:AM|PM))?)\s+#)/i],[PR.PR_PLAIN,/^(?:(?:[a-z]|_\w)\w*|\[(?:[a-z]|_\w)\w*\])/i],[PR.PR_PUNCTUATION,/^[^\w\t\n\r \"\'\[\]\xA0\u2018\u2019\u201C\u201D\u2028\u2029]+/],[PR.PR_PUNCTUATION,/^(?:\[|\])/]]),['vb','vbs'])
          diff --git a/public/javascripts/strophejs-1.1.3/doc/javascript/searchdata.js b/public/javascripts/strophejs-1.1.3/doc/javascript/searchdata.js
          new file mode 100644
          index 0000000..4552c6a
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/javascript/searchdata.js
          @@ -0,0 +1,182 @@
          +var indexSectionsWithContent = {
          +   "Files": {
          +      "Symbols": false,
          +      "Numbers": false,
          +      "A": false,
          +      "B": true,
          +      "C": false,
          +      "D": false,
          +      "E": false,
          +      "F": false,
          +      "G": false,
          +      "H": false,
          +      "I": false,
          +      "J": false,
          +      "K": false,
          +      "L": false,
          +      "M": false,
          +      "N": false,
          +      "O": false,
          +      "P": false,
          +      "Q": false,
          +      "R": false,
          +      "S": true,
          +      "T": false,
          +      "U": false,
          +      "V": false,
          +      "W": true,
          +      "X": false,
          +      "Y": false,
          +      "Z": false
          +      },
          +   "Functions": {
          +      "Symbols": true,
          +      "Numbers": false,
          +      "A": true,
          +      "B": true,
          +      "C": true,
          +      "D": true,
          +      "E": true,
          +      "F": true,
          +      "G": true,
          +      "H": true,
          +      "I": true,
          +      "J": false,
          +      "K": false,
          +      "L": true,
          +      "M": false,
          +      "N": false,
          +      "O": false,
          +      "P": true,
          +      "Q": false,
          +      "R": true,
          +      "S": true,
          +      "T": true,
          +      "U": true,
          +      "V": false,
          +      "W": true,
          +      "X": true,
          +      "Y": false,
          +      "Z": false
          +      },
          +   "General": {
          +      "Symbols": true,
          +      "Numbers": false,
          +      "A": true,
          +      "B": true,
          +      "C": true,
          +      "D": true,
          +      "E": true,
          +      "F": true,
          +      "G": true,
          +      "H": true,
          +      "I": true,
          +      "J": false,
          +      "K": false,
          +      "L": true,
          +      "M": true,
          +      "N": false,
          +      "O": false,
          +      "P": true,
          +      "Q": false,
          +      "R": true,
          +      "S": true,
          +      "T": true,
          +      "U": true,
          +      "V": true,
          +      "W": true,
          +      "X": true,
          +      "Y": false,
          +      "Z": false
          +      },
          +   "Classes": {
          +      "Symbols": false,
          +      "Numbers": false,
          +      "A": false,
          +      "B": false,
          +      "C": false,
          +      "D": false,
          +      "E": false,
          +      "F": false,
          +      "G": false,
          +      "H": false,
          +      "I": false,
          +      "J": false,
          +      "K": false,
          +      "L": false,
          +      "M": false,
          +      "N": false,
          +      "O": false,
          +      "P": false,
          +      "Q": false,
          +      "R": false,
          +      "S": true,
          +      "T": false,
          +      "U": false,
          +      "V": false,
          +      "W": false,
          +      "X": false,
          +      "Y": false,
          +      "Z": false
          +      },
          +   "Variables": {
          +      "Symbols": false,
          +      "Numbers": false,
          +      "A": true,
          +      "B": false,
          +      "C": false,
          +      "D": false,
          +      "E": false,
          +      "F": false,
          +      "G": false,
          +      "H": false,
          +      "I": false,
          +      "J": false,
          +      "K": false,
          +      "L": false,
          +      "M": false,
          +      "N": false,
          +      "O": false,
          +      "P": true,
          +      "Q": false,
          +      "R": false,
          +      "S": true,
          +      "T": false,
          +      "U": false,
          +      "V": false,
          +      "W": false,
          +      "X": false,
          +      "Y": false,
          +      "Z": false
          +      },
          +   "Constants": {
          +      "Symbols": false,
          +      "Numbers": false,
          +      "A": true,
          +      "B": true,
          +      "C": true,
          +      "D": true,
          +      "E": true,
          +      "F": true,
          +      "G": false,
          +      "H": true,
          +      "I": true,
          +      "J": false,
          +      "K": false,
          +      "L": true,
          +      "M": true,
          +      "N": false,
          +      "O": false,
          +      "P": true,
          +      "Q": false,
          +      "R": true,
          +      "S": true,
          +      "T": false,
          +      "U": false,
          +      "V": true,
          +      "W": true,
          +      "X": true,
          +      "Y": false,
          +      "Z": false
          +      }
          +   }
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ClassesS.html b/public/javascripts/strophejs-1.1.3/doc/search/ClassesS.html
          new file mode 100644
          index 0000000..82adaae
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ClassesS.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_Strophe><div class=IEntry><a href="../files/strophe-js.html#Strophe" target=_parent class=ISymbol>Strophe</a></div></div><div class=SRResult id=SR_Strophe_perBosh><div class=IEntry><a href="../files/strophe-js.html#Strophe.Bosh" target=_parent class=ISymbol>Strophe.Bosh</a></div></div><div class=SRResult id=SR_Strophe_perBuilder><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder" target=_parent class=ISymbol>Strophe.<wbr>Builder</a></div></div><div class=SRResult id=SR_Strophe_perConnection><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection" target=_parent class=ISymbol>Strophe.<wbr>Connection</a></div></div><div class=SRResult id=SR_Strophe_perSASLMechanism><div class=IEntry><a href="../files/strophe-js.html#Strophe.SASLMechanism" target=_parent class=ISymbol>Strophe.<wbr>SASLMechanism</a></div></div><div class=SRResult id=SR_Strophe_perWebSocket><div class=IEntry><a href="../files/strophe-js.html#Strophe.WebSocket" target=_parent class=ISymbol>Strophe.<wbr>WebSocket</a></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ConstantsA.html b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsA.html
          new file mode 100644
          index 0000000..c0e5326
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsA.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_ATTACHED><div class=IEntry><a href="../files/strophe-js.html#Strophe.Status.ATTACHED" target=_parent class=ISymbol>ATTACHED</a>, <span class=IParent>Strophe.<wbr>Status</span></div></div><div class=SRResult id=SR_AUTH><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.AUTH" target=_parent class=ISymbol>AUTH</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_AUTHENTICATING><div class=IEntry><a href="../files/strophe-js.html#Strophe.Status.AUTHENTICATING" target=_parent class=ISymbol>AUTHENTICATING</a>, <span class=IParent>Strophe.<wbr>Status</span></div></div><div class=SRResult id=SR_AUTHFAIL><div class=IEntry><a href="../files/strophe-js.html#Strophe.Status.AUTHFAIL" target=_parent class=ISymbol>AUTHFAIL</a>, <span class=IParent>Strophe.<wbr>Status</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ConstantsB.html b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsB.html
          new file mode 100644
          index 0000000..c9c8ff8
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsB.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_BIND><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.BIND" target=_parent class=ISymbol>BIND</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_BOSH><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.BOSH" target=_parent class=ISymbol>BOSH</a>, <span class=IParent>Strophe.NS</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ConstantsC.html b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsC.html
          new file mode 100644
          index 0000000..b9221c5
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsC.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_CLIENT><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.CLIENT" target=_parent class=ISymbol>CLIENT</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_CONNECTED><div class=IEntry><a href="../files/strophe-js.html#Strophe.Status.CONNECTED" target=_parent class=ISymbol>CONNECTED</a>, <span class=IParent>Strophe.<wbr>Status</span></div></div><div class=SRResult id=SR_CONNECTING><div class=IEntry><a href="../files/strophe-js.html#Strophe.Status.CONNECTING" target=_parent class=ISymbol>CONNECTING</a>, <span class=IParent>Strophe.<wbr>Status</span></div></div><div class=SRResult id=SR_Connection_spcStatus_spcConstants><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection_Status_Constants" target=_parent class=ISymbol>Connection Status Constants</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_CONNFAIL><div class=IEntry><a href="../files/strophe-js.html#Strophe.Status.CONNFAIL" target=_parent class=ISymbol>CONNFAIL</a>, <span class=IParent>Strophe.<wbr>Status</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ConstantsD.html b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsD.html
          new file mode 100644
          index 0000000..23e7e18
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsD.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_DEBUG><div class=IEntry><a href="../files/strophe-js.html#Strophe.LogLevel.DEBUG" target=_parent class=ISymbol>DEBUG</a>, <span class=IParent>Strophe.<wbr>LogLevel</span></div></div><div class=SRResult id=SR_DISCO_undINFO><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.DISCO_INFO" target=_parent class=ISymbol>DISCO_INFO</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_DISCO_undITEMS><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.DISCO_ITEMS" target=_parent class=ISymbol>DISCO_ITEMS</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_DISCONNECTED><div class=IEntry><a href="../files/strophe-js.html#Strophe.Status.DISCONNECTED" target=_parent class=ISymbol>DISCONNECTED</a>, <span class=IParent>Strophe.<wbr>Status</span></div></div><div class=SRResult id=SR_DISCONNECTING><div class=IEntry><a href="../files/strophe-js.html#Strophe.Status.DISCONNECTING" target=_parent class=ISymbol>DISCONNECTING</a>, <span class=IParent>Strophe.<wbr>Status</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ConstantsE.html b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsE.html
          new file mode 100644
          index 0000000..a6a034a
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsE.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_ERROR><div class=IEntry><a href="javascript:searchResults.Toggle('SR_ERROR')" class=ISymbol>ERROR</a><div class=ISubIndex><a href="../files/strophe-js.html#Strophe.LogLevel.ERROR" target=_parent class=IParent>Strophe.<wbr>LogLevel</a><a href="../files/strophe-js.html#Strophe.Status.ERROR" target=_parent class=IParent>Strophe.<wbr>Status</a></div></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ConstantsF.html b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsF.html
          new file mode 100644
          index 0000000..e08ad31
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsF.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_FATAL><div class=IEntry><a href="../files/strophe-js.html#Strophe.LogLevel.FATAL" target=_parent class=ISymbol>FATAL</a>, <span class=IParent>Strophe.<wbr>LogLevel</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ConstantsH.html b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsH.html
          new file mode 100644
          index 0000000..2c86680
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsH.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_HTTPBIND><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.HTTPBIND" target=_parent class=ISymbol>HTTPBIND</a>, <span class=IParent>Strophe.NS</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ConstantsI.html b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsI.html
          new file mode 100644
          index 0000000..713c8a5
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsI.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_INFO><div class=IEntry><a href="../files/strophe-js.html#Strophe.LogLevel.INFO" target=_parent class=ISymbol>INFO</a>, <span class=IParent>Strophe.<wbr>LogLevel</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ConstantsL.html b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsL.html
          new file mode 100644
          index 0000000..ad4744d
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsL.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_Log_spcLevel_spcConstants><div class=IEntry><a href="../files/strophe-js.html#Strophe.Log_Level_Constants" target=_parent class=ISymbol>Log Level Constants</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ConstantsM.html b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsM.html
          new file mode 100644
          index 0000000..5026eb9
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsM.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_MUC><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.MUC" target=_parent class=ISymbol>MUC</a>, <span class=IParent>Strophe.NS</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ConstantsP.html b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsP.html
          new file mode 100644
          index 0000000..143e33f
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsP.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_PROFILE><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.PROFILE" target=_parent class=ISymbol>PROFILE</a>, <span class=IParent>Strophe.NS</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ConstantsR.html b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsR.html
          new file mode 100644
          index 0000000..d606cc7
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsR.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_ROSTER><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.ROSTER" target=_parent class=ISymbol>ROSTER</a>, <span class=IParent>Strophe.NS</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ConstantsS.html b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsS.html
          new file mode 100644
          index 0000000..515a22b
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsS.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_SASL><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.SASL" target=_parent class=ISymbol>SASL</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_SASL_spcmechanisms><div class=IEntry><a href="../files/strophe-js.html#Strophe.SASLMechanism.SASL_mechanisms" target=_parent class=ISymbol>SASL mechanisms</a>, <span class=IParent>Strophe.<wbr>SASLMechanism</span></div></div><div class=SRResult id=SR_SASLAnonymous><div class=IEntry><a href="../files/strophe-js.html#Strophe.SASLMechanism.Strophe.SASLAnonymous" target=_parent class=ISymbol>SASLAnonymous</a>, <span class=IParent>Strophe.<wbr>SASLMechanism.<wbr>Strophe</span></div></div><div class=SRResult id=SR_SASLMD5><div class=IEntry><a href="../files/strophe-js.html#Strophe.SASLMechanism.Strophe.SASLMD5" target=_parent class=ISymbol>SASLMD5</a>, <span class=IParent>Strophe.<wbr>SASLMechanism.<wbr>Strophe</span></div></div><div class=SRResult id=SR_SASLPlain><div class=IEntry><a href="../files/strophe-js.html#Strophe.SASLMechanism.Strophe.SASLPlain" target=_parent class=ISymbol>SASLPlain</a>, <span class=IParent>Strophe.<wbr>SASLMechanism.<wbr>Strophe</span></div></div><div class=SRResult id=SR_SASLSHA1><div class=IEntry><a href="../files/strophe-js.html#Strophe.SASLMechanism.Strophe.SASLSHA1" target=_parent class=ISymbol>SASLSHA1</a>, <span class=IParent>Strophe.<wbr>SASLMechanism.<wbr>Strophe</span></div></div><div class=SRResult id=SR_SESSION><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.SESSION" target=_parent class=ISymbol>SESSION</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_STREAM><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.STREAM" target=_parent class=ISymbol>STREAM</a>, <span class=IParent>Strophe.NS</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ConstantsV.html b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsV.html
          new file mode 100644
          index 0000000..0f16c4c
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsV.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_VERSION><div class=IEntry><a href="../files/strophe-js.html#Strophe.VERSION" target=_parent class=ISymbol>VERSION</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ConstantsW.html b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsW.html
          new file mode 100644
          index 0000000..1a540dd
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsW.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_WARN><div class=IEntry><a href="../files/strophe-js.html#Strophe.LogLevel.WARN" target=_parent class=ISymbol>WARN</a>, <span class=IParent>Strophe.<wbr>LogLevel</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/ConstantsX.html b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsX.html
          new file mode 100644
          index 0000000..2fd7add
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/ConstantsX.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_XHTML><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.XHTML" target=_parent class=ISymbol>XHTML</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_XHTML_undIM><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.XHTML_IM" target=_parent class=ISymbol>XHTML_IM</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_XHTML_undIM_spcNamespace><div class=IEntry><a href="../files/strophe-js.html#Strophe.XHTML_IM_Namespace" target=_parent class=ISymbol>XHTML_IM Namespace</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_XMPP_spcNamespace_spcConstants><div class=IEntry><a href="../files/strophe-js.html#Strophe.XMPP_Namespace_Constants" target=_parent class=ISymbol>XMPP Namespace Constants</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FilesB.html b/public/javascripts/strophejs-1.1.3/doc/search/FilesB.html
          new file mode 100644
          index 0000000..af73756
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FilesB.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_bosh_perjs><div class=IEntry><a href="../files/strophe-js.html#bosh.js" target=_parent class=ISymbol>bosh.js</a></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FilesS.html b/public/javascripts/strophejs-1.1.3/doc/search/FilesS.html
          new file mode 100644
          index 0000000..3baeda4
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FilesS.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_strophe_perjs><div class=IEntry><a href="../files/strophe-js.html#strophe.js" target=_parent class=ISymbol>strophe.js</a></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FilesW.html b/public/javascripts/strophejs-1.1.3/doc/search/FilesW.html
          new file mode 100644
          index 0000000..d1540cc
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FilesW.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_websocket_perjs><div class=IEntry><a href="../files/strophe-js.html#websocket.js" target=_parent class=ISymbol>websocket.js</a></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsA.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsA.html
          new file mode 100644
          index 0000000..02599ac
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsA.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_addConnectionPlugin><div class=IEntry><a href="../files/strophe-js.html#Strophe.addConnectionPlugin" target=_parent class=ISymbol>addConnectionPlugin</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_addHandler><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.addHandler" target=_parent class=ISymbol>addHandler</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_addNamespace><div class=IEntry><a href="../files/strophe-js.html#Strophe.addNamespace" target=_parent class=ISymbol>addNamespace</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_addTimedHandler><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.addTimedHandler" target=_parent class=ISymbol>addTimedHandler</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_attach><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.attach" target=_parent class=ISymbol>attach</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_attrs><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.attrs" target=_parent class=ISymbol>attrs</a>, <span class=IParent>Strophe.<wbr>Builder</span></div></div><div class=SRResult id=SR_authenticate><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.authenticate" target=_parent class=ISymbol>authenticate</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsB.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsB.html
          new file mode 100644
          index 0000000..a408215
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsB.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_Builder><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.Strophe.Builder" target=_parent class=ISymbol>Builder</a>, <span class=IParent>Strophe.<wbr>Builder.<wbr>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsC.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsC.html
          new file mode 100644
          index 0000000..54bedc5
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsC.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_c><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.c" target=_parent class=ISymbol>c</a>, <span class=IParent>Strophe.<wbr>Builder</span></div></div><div class=SRResult id=SR_cnode><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.cnode" target=_parent class=ISymbol>cnode</a>, <span class=IParent>Strophe.<wbr>Builder</span></div></div><div class=SRResult id=SR_connect><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.connect" target=_parent class=ISymbol>connect</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_Connection><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.Strophe.Connection" target=_parent class=ISymbol>Connection</a>, <span class=IParent>Strophe.<wbr>Connection.<wbr>Strophe</span></div></div><div class=SRResult id=SR_copyElement><div class=IEntry><a href="../files/strophe-js.html#Strophe.copyElement" target=_parent class=ISymbol>copyElement</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_createHtml><div class=IEntry><a href="../files/strophe-js.html#Strophe.createHtml" target=_parent class=ISymbol>createHtml</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsD.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsD.html
          new file mode 100644
          index 0000000..e6491d7
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsD.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_debug><div class=IEntry><a href="../files/strophe-js.html#Strophe.debug" target=_parent class=ISymbol>debug</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_deleteHandler><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.deleteHandler" target=_parent class=ISymbol>deleteHandler</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_deleteTimedHandler><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.deleteTimedHandler" target=_parent class=ISymbol>deleteTimedHandler</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_disconnect><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.disconnect" target=_parent class=ISymbol>disconnect</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsE.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsE.html
          new file mode 100644
          index 0000000..fdf1958
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsE.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_error><div class=IEntry><a href="../files/strophe-js.html#Strophe.error" target=_parent class=ISymbol>error</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_escapeNode><div class=IEntry><a href="../files/strophe-js.html#Strophe.escapeNode" target=_parent class=ISymbol>escapeNode</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsF.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsF.html
          new file mode 100644
          index 0000000..e7c135e
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsF.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_fatal><div class=IEntry><a href="../files/strophe-js.html#Strophe.fatal" target=_parent class=ISymbol>fatal</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_flush><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.flush" target=_parent class=ISymbol>flush</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_forEachChild><div class=IEntry><a href="../files/strophe-js.html#Strophe.forEachChild" target=_parent class=ISymbol>forEachChild</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsG.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsG.html
          new file mode 100644
          index 0000000..cbbfe4e
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsG.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_getBareJidFromJid><div class=IEntry><a href="../files/strophe-js.html#Strophe.getBareJidFromJid" target=_parent class=ISymbol>getBareJidFromJid</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_getDomainFromJid><div class=IEntry><a href="../files/strophe-js.html#Strophe.getDomainFromJid" target=_parent class=ISymbol>getDomainFromJid</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_getNodeFromJid><div class=IEntry><a href="../files/strophe-js.html#Strophe.getNodeFromJid" target=_parent class=ISymbol>getNodeFromJid</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_getResourceFromJid><div class=IEntry><a href="../files/strophe-js.html#Strophe.getResourceFromJid" target=_parent class=ISymbol>getResourceFromJid</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_getText><div class=IEntry><a href="../files/strophe-js.html#Strophe.getText" target=_parent class=ISymbol>getText</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_getUniqueId><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.getUniqueId" target=_parent class=ISymbol>getUniqueId</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsH.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsH.html
          new file mode 100644
          index 0000000..579a279
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsH.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_h><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.h" target=_parent class=ISymbol>h</a>, <span class=IParent>Strophe.<wbr>Builder</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsI.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsI.html
          new file mode 100644
          index 0000000..1528a85
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsI.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_info><div class=IEntry><a href="../files/strophe-js.html#Strophe.info" target=_parent class=ISymbol>info</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_isTagEqual><div class=IEntry><a href="../files/strophe-js.html#Strophe.isTagEqual" target=_parent class=ISymbol>isTagEqual</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsL.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsL.html
          new file mode 100644
          index 0000000..9f24803
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsL.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_log><div class=IEntry><a href="../files/strophe-js.html#Strophe.log" target=_parent class=ISymbol>log</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsP.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsP.html
          new file mode 100644
          index 0000000..2394eaa
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsP.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_pause><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.pause" target=_parent class=ISymbol>pause</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsR.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsR.html
          new file mode 100644
          index 0000000..aeae938
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsR.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_rawInput><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.rawInput" target=_parent class=ISymbol>rawInput</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_rawOutput><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.rawOutput" target=_parent class=ISymbol>rawOutput</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_reset><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.reset" target=_parent class=ISymbol>reset</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_resume><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.resume" target=_parent class=ISymbol>resume</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsS.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsS.html
          new file mode 100644
          index 0000000..faec572
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsS.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_send><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.send" target=_parent class=ISymbol>send</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_sendIQ><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.sendIQ" target=_parent class=ISymbol>sendIQ</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_serialize><div class=IEntry><a href="../files/strophe-js.html#Strophe.serialize" target=_parent class=ISymbol>serialize</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsSymbols.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsSymbols.html
          new file mode 100644
          index 0000000..7fcabeb
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsSymbols.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR__dolbuild><div class=IEntry><a href="../files/strophe-js.html#$build" target=_parent class=ISymbol>$build</a></div></div><div class=SRResult id=SR__doliq><div class=IEntry><a href="../files/strophe-js.html#$iq" target=_parent class=ISymbol>$iq</a></div></div><div class=SRResult id=SR__dolmsg><div class=IEntry><a href="../files/strophe-js.html#$msg" target=_parent class=ISymbol>$msg</a></div></div><div class=SRResult id=SR__dolpres><div class=IEntry><a href="../files/strophe-js.html#$pres" target=_parent class=ISymbol>$pres</a></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsT.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsT.html
          new file mode 100644
          index 0000000..9d47c02
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsT.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_t><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.t" target=_parent class=ISymbol>t</a>, <span class=IParent>Strophe.<wbr>Builder</span></div></div><div class=SRResult id=SR_test><div class=IEntry><a href="../files/strophe-js.html#Strophe.SASLMechanism.test" target=_parent class=ISymbol>test</a>, <span class=IParent>Strophe.<wbr>SASLMechanism</span></div></div><div class=SRResult id=SR_toString><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.toString" target=_parent class=ISymbol>toString</a>, <span class=IParent>Strophe.<wbr>Builder</span></div></div><div class=SRResult id=SR_tree><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.tree" target=_parent class=ISymbol>tree</a>, <span class=IParent>Strophe.<wbr>Builder</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsU.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsU.html
          new file mode 100644
          index 0000000..65915d7
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsU.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_unescapeNode><div class=IEntry><a href="../files/strophe-js.html#Strophe.unescapeNode" target=_parent class=ISymbol>unescapeNode</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_up><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.up" target=_parent class=ISymbol>up</a>, <span class=IParent>Strophe.<wbr>Builder</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsW.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsW.html
          new file mode 100644
          index 0000000..89f5a58
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsW.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_warn><div class=IEntry><a href="../files/strophe-js.html#Strophe.warn" target=_parent class=ISymbol>warn</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/FunctionsX.html b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsX.html
          new file mode 100644
          index 0000000..bb81d4d
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/FunctionsX.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_xmlElement><div class=IEntry><a href="../files/strophe-js.html#Strophe.xmlElement" target=_parent class=ISymbol>xmlElement</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_xmlescape><div class=IEntry><a href="../files/strophe-js.html#Strophe.xmlescape" target=_parent class=ISymbol>xmlescape</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_xmlGenerator><div class=IEntry><a href="../files/strophe-js.html#Strophe.xmlGenerator" target=_parent class=ISymbol>xmlGenerator</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_xmlHtmlNode><div class=IEntry><a href="../files/strophe-js.html#Strophe.xmlHtmlNode" target=_parent class=ISymbol>xmlHtmlNode</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_xmlInput><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.xmlInput" target=_parent class=ISymbol>xmlInput</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_xmlOutput><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.xmlOutput" target=_parent class=ISymbol>xmlOutput</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_xmlTextNode><div class=IEntry><a href="../files/strophe-js.html#Strophe.xmlTextNode" target=_parent class=ISymbol>xmlTextNode</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralA.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralA.html
          new file mode 100644
          index 0000000..3be90cb
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralA.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_addConnectionPlugin><div class=IEntry><a href="../files/strophe-js.html#Strophe.addConnectionPlugin" target=_parent class=ISymbol>addConnectionPlugin</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_addHandler><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.addHandler" target=_parent class=ISymbol>addHandler</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_addNamespace><div class=IEntry><a href="../files/strophe-js.html#Strophe.addNamespace" target=_parent class=ISymbol>addNamespace</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_addTimedHandler><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.addTimedHandler" target=_parent class=ISymbol>addTimedHandler</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_attach><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.attach" target=_parent class=ISymbol>attach</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_ATTACHED><div class=IEntry><a href="../files/strophe-js.html#Strophe.Status.ATTACHED" target=_parent class=ISymbol>ATTACHED</a>, <span class=IParent>Strophe.<wbr>Status</span></div></div><div class=SRResult id=SR_attrs><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.attrs" target=_parent class=ISymbol>attrs</a>, <span class=IParent>Strophe.<wbr>Builder</span></div></div><div class=SRResult id=SR_AUTH><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.AUTH" target=_parent class=ISymbol>AUTH</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_authcid><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.authcid" target=_parent class=ISymbol>authcid</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_authenticate><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.authenticate" target=_parent class=ISymbol>authenticate</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_AUTHENTICATING><div class=IEntry><a href="../files/strophe-js.html#Strophe.Status.AUTHENTICATING" target=_parent class=ISymbol>AUTHENTICATING</a>, <span class=IParent>Strophe.<wbr>Status</span></div></div><div class=SRResult id=SR_AUTHFAIL><div class=IEntry><a href="../files/strophe-js.html#Strophe.Status.AUTHFAIL" target=_parent class=ISymbol>AUTHFAIL</a>, <span class=IParent>Strophe.<wbr>Status</span></div></div><div class=SRResult id=SR_authzid><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.authzid" target=_parent class=ISymbol>authzid</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralB.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralB.html
          new file mode 100644
          index 0000000..a6d68ae
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralB.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_BIND><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.BIND" target=_parent class=ISymbol>BIND</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_BOSH><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.BOSH" target=_parent class=ISymbol>BOSH</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_bosh_perjs><div class=IEntry><a href="../files/strophe-js.html#bosh.js" target=_parent class=ISymbol>bosh.js</a></div></div><div class=SRResult id=SR_Builder><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.Strophe.Builder" target=_parent class=ISymbol>Builder</a>, <span class=IParent>Strophe.<wbr>Builder.<wbr>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralC.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralC.html
          new file mode 100644
          index 0000000..c32a668
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralC.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_c><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.c" target=_parent class=ISymbol>c</a>, <span class=IParent>Strophe.<wbr>Builder</span></div></div><div class=SRResult id=SR_CLIENT><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.CLIENT" target=_parent class=ISymbol>CLIENT</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_cnode><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.cnode" target=_parent class=ISymbol>cnode</a>, <span class=IParent>Strophe.<wbr>Builder</span></div></div><div class=SRResult id=SR_connect><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.connect" target=_parent class=ISymbol>connect</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_CONNECTED><div class=IEntry><a href="../files/strophe-js.html#Strophe.Status.CONNECTED" target=_parent class=ISymbol>CONNECTED</a>, <span class=IParent>Strophe.<wbr>Status</span></div></div><div class=SRResult id=SR_CONNECTING><div class=IEntry><a href="../files/strophe-js.html#Strophe.Status.CONNECTING" target=_parent class=ISymbol>CONNECTING</a>, <span class=IParent>Strophe.<wbr>Status</span></div></div><div class=SRResult id=SR_Connection><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.Strophe.Connection" target=_parent class=ISymbol>Connection</a>, <span class=IParent>Strophe.<wbr>Connection.<wbr>Strophe</span></div></div><div class=SRResult id=SR_Connection_spcStatus_spcConstants><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection_Status_Constants" target=_parent class=ISymbol>Connection Status Constants</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_CONNFAIL><div class=IEntry><a href="../files/strophe-js.html#Strophe.Status.CONNFAIL" target=_parent class=ISymbol>CONNFAIL</a>, <span class=IParent>Strophe.<wbr>Status</span></div></div><div class=SRResult id=SR_Constants><div class=IEntry><a href="javascript:searchResults.Toggle('SR_Constants')" class=ISymbol>Constants</a><div class=ISubIndex><a href="../files/strophe-js.html#Strophe.Constants" target=_parent class=IParent>Strophe</a><a href="../files/strophe-js.html#Strophe.SASLMechanism.Constants" target=_parent class=IParent>Strophe.<wbr>SASLMechanism</a></div></div></div><div class=SRResult id=SR_copyElement><div class=IEntry><a href="../files/strophe-js.html#Strophe.copyElement" target=_parent class=ISymbol>copyElement</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_createHtml><div class=IEntry><a href="../files/strophe-js.html#Strophe.createHtml" target=_parent class=ISymbol>createHtml</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralD.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralD.html
          new file mode 100644
          index 0000000..b92e457
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralD.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_debug><div class=IEntry><a href="../files/strophe-js.html#Strophe.debug" target=_parent class=ISymbol>debug</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR2_DEBUG><div class=IEntry><a href="../files/strophe-js.html#Strophe.LogLevel.DEBUG" target=_parent class=ISymbol>DEBUG</a>, <span class=IParent>Strophe.<wbr>LogLevel</span></div></div><div class=SRResult id=SR_deleteHandler><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.deleteHandler" target=_parent class=ISymbol>deleteHandler</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_deleteTimedHandler><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.deleteTimedHandler" target=_parent class=ISymbol>deleteTimedHandler</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_DISCO_undINFO><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.DISCO_INFO" target=_parent class=ISymbol>DISCO_INFO</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_DISCO_undITEMS><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.DISCO_ITEMS" target=_parent class=ISymbol>DISCO_ITEMS</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_disconnect><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.disconnect" target=_parent class=ISymbol>disconnect</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_DISCONNECTED><div class=IEntry><a href="../files/strophe-js.html#Strophe.Status.DISCONNECTED" target=_parent class=ISymbol>DISCONNECTED</a>, <span class=IParent>Strophe.<wbr>Status</span></div></div><div class=SRResult id=SR_DISCONNECTING><div class=IEntry><a href="../files/strophe-js.html#Strophe.Status.DISCONNECTING" target=_parent class=ISymbol>DISCONNECTING</a>, <span class=IParent>Strophe.<wbr>Status</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralE.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralE.html
          new file mode 100644
          index 0000000..fd7e969
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralE.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_error><div class=IEntry><a href="../files/strophe-js.html#Strophe.error" target=_parent class=ISymbol>error</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR2_ERROR><div class=IEntry><a href="javascript:searchResults.Toggle('SR2_ERROR')" class=ISymbol>ERROR</a><div class=ISubIndex><a href="../files/strophe-js.html#Strophe.LogLevel.ERROR" target=_parent class=IParent>Strophe.<wbr>LogLevel</a><a href="../files/strophe-js.html#Strophe.Status.ERROR" target=_parent class=IParent>Strophe.<wbr>Status</a></div></div></div><div class=SRResult id=SR_escapeNode><div class=IEntry><a href="../files/strophe-js.html#Strophe.escapeNode" target=_parent class=ISymbol>escapeNode</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralF.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralF.html
          new file mode 100644
          index 0000000..94526b1
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralF.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_fatal><div class=IEntry><a href="../files/strophe-js.html#Strophe.fatal" target=_parent class=ISymbol>fatal</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR2_FATAL><div class=IEntry><a href="../files/strophe-js.html#Strophe.LogLevel.FATAL" target=_parent class=ISymbol>FATAL</a>, <span class=IParent>Strophe.<wbr>LogLevel</span></div></div><div class=SRResult id=SR_Files><div class=IEntry><a href="javascript:searchResults.Toggle('SR_Files')" class=ISymbol>Files</a><div class=ISubIndex><a href="../files/strophe-js.html#Strophe.Bosh.Files" target=_parent class=IParent>Strophe.Bosh</a><a href="../files/strophe-js.html#Strophe.WebSocket.Files" target=_parent class=IParent>Strophe.<wbr>WebSocket</a></div></div></div><div class=SRResult id=SR_flush><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.flush" target=_parent class=ISymbol>flush</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_forEachChild><div class=IEntry><a href="../files/strophe-js.html#Strophe.forEachChild" target=_parent class=ISymbol>forEachChild</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_Functions><div class=IEntry><a href="javascript:searchResults.Toggle('SR_Functions')" class=ISymbol>Functions</a><div class=ISubIndex><a href="../files/strophe-js.html#Functions" target=_parent class=IParent>Global</a><a href="../files/strophe-js.html#Strophe.Functions" target=_parent class=IParent>Strophe</a><a href="../files/strophe-js.html#Strophe.Builder.Functions" target=_parent class=IParent>Strophe.<wbr>Builder</a><a href="../files/strophe-js.html#Strophe.Connection.Functions" target=_parent class=IParent>Strophe.<wbr>Connection</a><a href="../files/strophe-js.html#Strophe.SASLMechanism.Functions" target=_parent class=IParent>Strophe.<wbr>SASLMechanism</a></div></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralG.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralG.html
          new file mode 100644
          index 0000000..cbbfe4e
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralG.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_getBareJidFromJid><div class=IEntry><a href="../files/strophe-js.html#Strophe.getBareJidFromJid" target=_parent class=ISymbol>getBareJidFromJid</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_getDomainFromJid><div class=IEntry><a href="../files/strophe-js.html#Strophe.getDomainFromJid" target=_parent class=ISymbol>getDomainFromJid</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_getNodeFromJid><div class=IEntry><a href="../files/strophe-js.html#Strophe.getNodeFromJid" target=_parent class=ISymbol>getNodeFromJid</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_getResourceFromJid><div class=IEntry><a href="../files/strophe-js.html#Strophe.getResourceFromJid" target=_parent class=ISymbol>getResourceFromJid</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_getText><div class=IEntry><a href="../files/strophe-js.html#Strophe.getText" target=_parent class=ISymbol>getText</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_getUniqueId><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.getUniqueId" target=_parent class=ISymbol>getUniqueId</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralH.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralH.html
          new file mode 100644
          index 0000000..5647903
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralH.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_h><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.h" target=_parent class=ISymbol>h</a>, <span class=IParent>Strophe.<wbr>Builder</span></div></div><div class=SRResult id=SR_HTTPBIND><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.HTTPBIND" target=_parent class=ISymbol>HTTPBIND</a>, <span class=IParent>Strophe.NS</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralI.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralI.html
          new file mode 100644
          index 0000000..e6b7838
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralI.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_info><div class=IEntry><a href="../files/strophe-js.html#Strophe.info" target=_parent class=ISymbol>info</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR2_INFO><div class=IEntry><a href="../files/strophe-js.html#Strophe.LogLevel.INFO" target=_parent class=ISymbol>INFO</a>, <span class=IParent>Strophe.<wbr>LogLevel</span></div></div><div class=SRResult id=SR_isTagEqual><div class=IEntry><a href="../files/strophe-js.html#Strophe.isTagEqual" target=_parent class=ISymbol>isTagEqual</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralL.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralL.html
          new file mode 100644
          index 0000000..0e4c5e2
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralL.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_log><div class=IEntry><a href="../files/strophe-js.html#Strophe.log" target=_parent class=ISymbol>log</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_Log_spcLevel_spcConstants><div class=IEntry><a href="../files/strophe-js.html#Strophe.Log_Level_Constants" target=_parent class=ISymbol>Log Level Constants</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralM.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralM.html
          new file mode 100644
          index 0000000..5026eb9
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralM.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_MUC><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.MUC" target=_parent class=ISymbol>MUC</a>, <span class=IParent>Strophe.NS</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralP.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralP.html
          new file mode 100644
          index 0000000..b29e005
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralP.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_pass><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.pass" target=_parent class=ISymbol>pass</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_pause><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.pause" target=_parent class=ISymbol>pause</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_priority><div class=IEntry><a href="../files/strophe-js.html#Strophe.SASLMechanism.priority" target=_parent class=ISymbol>priority</a>, <span class=IParent>Strophe.<wbr>SASLMechanism</span></div></div><div class=SRResult id=SR_PROFILE><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.PROFILE" target=_parent class=ISymbol>PROFILE</a>, <span class=IParent>Strophe.NS</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralR.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralR.html
          new file mode 100644
          index 0000000..c4c5e8f
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralR.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_rawInput><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.rawInput" target=_parent class=ISymbol>rawInput</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_rawOutput><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.rawOutput" target=_parent class=ISymbol>rawOutput</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_reset><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.reset" target=_parent class=ISymbol>reset</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_resume><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.resume" target=_parent class=ISymbol>resume</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_ROSTER><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.ROSTER" target=_parent class=ISymbol>ROSTER</a>, <span class=IParent>Strophe.NS</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralS.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralS.html
          new file mode 100644
          index 0000000..b5214ff
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralS.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_SASL><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.SASL" target=_parent class=ISymbol>SASL</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_SASL_spcmechanisms><div class=IEntry><a href="../files/strophe-js.html#Strophe.SASLMechanism.SASL_mechanisms" target=_parent class=ISymbol>SASL mechanisms</a>, <span class=IParent>Strophe.<wbr>SASLMechanism</span></div></div><div class=SRResult id=SR_SASLAnonymous><div class=IEntry><a href="../files/strophe-js.html#Strophe.SASLMechanism.Strophe.SASLAnonymous" target=_parent class=ISymbol>SASLAnonymous</a>, <span class=IParent>Strophe.<wbr>SASLMechanism.<wbr>Strophe</span></div></div><div class=SRResult id=SR_SASLMD5><div class=IEntry><a href="../files/strophe-js.html#Strophe.SASLMechanism.Strophe.SASLMD5" target=_parent class=ISymbol>SASLMD5</a>, <span class=IParent>Strophe.<wbr>SASLMechanism.<wbr>Strophe</span></div></div><div class=SRResult id=SR_SASLPlain><div class=IEntry><a href="../files/strophe-js.html#Strophe.SASLMechanism.Strophe.SASLPlain" target=_parent class=ISymbol>SASLPlain</a>, <span class=IParent>Strophe.<wbr>SASLMechanism.<wbr>Strophe</span></div></div><div class=SRResult id=SR_SASLSHA1><div class=IEntry><a href="../files/strophe-js.html#Strophe.SASLMechanism.Strophe.SASLSHA1" target=_parent class=ISymbol>SASLSHA1</a>, <span class=IParent>Strophe.<wbr>SASLMechanism.<wbr>Strophe</span></div></div><div class=SRResult id=SR_send><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.send" target=_parent class=ISymbol>send</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_sendIQ><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.sendIQ" target=_parent class=ISymbol>sendIQ</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_serialize><div class=IEntry><a href="../files/strophe-js.html#Strophe.serialize" target=_parent class=ISymbol>serialize</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_servtype><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.servtype" target=_parent class=ISymbol>servtype</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_SESSION><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.SESSION" target=_parent class=ISymbol>SESSION</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_STREAM><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.STREAM" target=_parent class=ISymbol>STREAM</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_strip><div class=IEntry><a href="../files/strophe-js.html#Strophe.Bosh.strip" target=_parent class=ISymbol>strip</a>, <span class=IParent>Strophe.Bosh</span></div></div><div class=SRResult id=SR_Strophe><div class=IEntry><a href="../files/strophe-js.html#Strophe" target=_parent class=ISymbol>Strophe</a></div></div><div class=SRResult id=SR_Strophe_perBosh><div class=IEntry><a href="../files/strophe-js.html#Strophe.Bosh" target=_parent class=ISymbol>Strophe.Bosh</a></div></div><div class=SRResult id=SR_Strophe_perBuilder><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder" target=_parent class=ISymbol>Strophe.<wbr>Builder</a></div></div><div class=SRResult id=SR_Strophe_perConnection><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection" target=_parent class=ISymbol>Strophe.<wbr>Connection</a></div></div><div class=SRResult id=SR_strophe_perjs><div class=IEntry><a href="../files/strophe-js.html#strophe.js" target=_parent class=ISymbol>strophe.js</a></div></div><div class=SRResult id=SR_Strophe_perSASLMechanism><div class=IEntry><a href="../files/strophe-js.html#Strophe.SASLMechanism" target=_parent class=ISymbol>Strophe.<wbr>SASLMechanism</a></div></div><div class=SRResult id=SR_Strophe_perWebSocket><div class=IEntry><a href="../files/strophe-js.html#Strophe.WebSocket" target=_parent class=ISymbol>Strophe.<wbr>WebSocket</a></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralSymbols.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralSymbols.html
          new file mode 100644
          index 0000000..7fcabeb
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralSymbols.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR__dolbuild><div class=IEntry><a href="../files/strophe-js.html#$build" target=_parent class=ISymbol>$build</a></div></div><div class=SRResult id=SR__doliq><div class=IEntry><a href="../files/strophe-js.html#$iq" target=_parent class=ISymbol>$iq</a></div></div><div class=SRResult id=SR__dolmsg><div class=IEntry><a href="../files/strophe-js.html#$msg" target=_parent class=ISymbol>$msg</a></div></div><div class=SRResult id=SR__dolpres><div class=IEntry><a href="../files/strophe-js.html#$pres" target=_parent class=ISymbol>$pres</a></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralT.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralT.html
          new file mode 100644
          index 0000000..9d47c02
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralT.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_t><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.t" target=_parent class=ISymbol>t</a>, <span class=IParent>Strophe.<wbr>Builder</span></div></div><div class=SRResult id=SR_test><div class=IEntry><a href="../files/strophe-js.html#Strophe.SASLMechanism.test" target=_parent class=ISymbol>test</a>, <span class=IParent>Strophe.<wbr>SASLMechanism</span></div></div><div class=SRResult id=SR_toString><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.toString" target=_parent class=ISymbol>toString</a>, <span class=IParent>Strophe.<wbr>Builder</span></div></div><div class=SRResult id=SR_tree><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.tree" target=_parent class=ISymbol>tree</a>, <span class=IParent>Strophe.<wbr>Builder</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralU.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralU.html
          new file mode 100644
          index 0000000..65915d7
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralU.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_unescapeNode><div class=IEntry><a href="../files/strophe-js.html#Strophe.unescapeNode" target=_parent class=ISymbol>unescapeNode</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_up><div class=IEntry><a href="../files/strophe-js.html#Strophe.Builder.up" target=_parent class=ISymbol>up</a>, <span class=IParent>Strophe.<wbr>Builder</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralV.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralV.html
          new file mode 100644
          index 0000000..f97b686
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralV.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_Variables><div class=IEntry><a href="javascript:searchResults.Toggle('SR_Variables')" class=ISymbol>Variables</a><div class=ISubIndex><a href="../files/strophe-js.html#Strophe.Bosh.Variables" target=_parent class=IParent>Strophe.Bosh</a><a href="../files/strophe-js.html#Strophe.Connection.Variables" target=_parent class=IParent>Strophe.<wbr>Connection</a><a href="../files/strophe-js.html#Strophe.SASLMechanism.Variables" target=_parent class=IParent>Strophe.<wbr>SASLMechanism</a></div></div></div><div class=SRResult id=SR_VERSION><div class=IEntry><a href="../files/strophe-js.html#Strophe.VERSION" target=_parent class=ISymbol>VERSION</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralW.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralW.html
          new file mode 100644
          index 0000000..1765003
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralW.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_warn><div class=IEntry><a href="../files/strophe-js.html#Strophe.warn" target=_parent class=ISymbol>warn</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR2_WARN><div class=IEntry><a href="../files/strophe-js.html#Strophe.LogLevel.WARN" target=_parent class=ISymbol>WARN</a>, <span class=IParent>Strophe.<wbr>LogLevel</span></div></div><div class=SRResult id=SR_websocket_perjs><div class=IEntry><a href="../files/strophe-js.html#websocket.js" target=_parent class=ISymbol>websocket.js</a></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/GeneralX.html b/public/javascripts/strophejs-1.1.3/doc/search/GeneralX.html
          new file mode 100644
          index 0000000..b554996
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/GeneralX.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_XHTML><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.XHTML" target=_parent class=ISymbol>XHTML</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_XHTML_undIM><div class=IEntry><a href="../files/strophe-js.html#Strophe.NS.XHTML_IM" target=_parent class=ISymbol>XHTML_IM</a>, <span class=IParent>Strophe.NS</span></div></div><div class=SRResult id=SR_XHTML_undIM_spcNamespace><div class=IEntry><a href="../files/strophe-js.html#Strophe.XHTML_IM_Namespace" target=_parent class=ISymbol>XHTML_IM Namespace</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_xmlElement><div class=IEntry><a href="../files/strophe-js.html#Strophe.xmlElement" target=_parent class=ISymbol>xmlElement</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_xmlescape><div class=IEntry><a href="../files/strophe-js.html#Strophe.xmlescape" target=_parent class=ISymbol>xmlescape</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_xmlGenerator><div class=IEntry><a href="../files/strophe-js.html#Strophe.xmlGenerator" target=_parent class=ISymbol>xmlGenerator</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_xmlHtmlNode><div class=IEntry><a href="../files/strophe-js.html#Strophe.xmlHtmlNode" target=_parent class=ISymbol>xmlHtmlNode</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_xmlInput><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.xmlInput" target=_parent class=ISymbol>xmlInput</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_xmlOutput><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.xmlOutput" target=_parent class=ISymbol>xmlOutput</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_xmlTextNode><div class=IEntry><a href="../files/strophe-js.html#Strophe.xmlTextNode" target=_parent class=ISymbol>xmlTextNode</a>, <span class=IParent>Strophe</span></div></div><div class=SRResult id=SR_XMPP_spcNamespace_spcConstants><div class=IEntry><a href="../files/strophe-js.html#Strophe.XMPP_Namespace_Constants" target=_parent class=ISymbol>XMPP Namespace Constants</a>, <span class=IParent>Strophe</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/NoResults.html b/public/javascripts/strophejs-1.1.3/doc/search/NoResults.html
          new file mode 100644
          index 0000000..8c72496
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/NoResults.html
          @@ -0,0 +1,15 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=NoMatches>No Matches</div></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/VariablesA.html b/public/javascripts/strophejs-1.1.3/doc/search/VariablesA.html
          new file mode 100644
          index 0000000..510f1af
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/VariablesA.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_authcid><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.authcid" target=_parent class=ISymbol>authcid</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_authzid><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.authzid" target=_parent class=ISymbol>authzid</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/VariablesP.html b/public/javascripts/strophejs-1.1.3/doc/search/VariablesP.html
          new file mode 100644
          index 0000000..ef0b0e2
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/VariablesP.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_pass><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.pass" target=_parent class=ISymbol>pass</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_priority><div class=IEntry><a href="../files/strophe-js.html#Strophe.SASLMechanism.priority" target=_parent class=ISymbol>priority</a>, <span class=IParent>Strophe.<wbr>SASLMechanism</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/search/VariablesS.html b/public/javascripts/strophejs-1.1.3/doc/search/VariablesS.html
          new file mode 100644
          index 0000000..f700656
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/search/VariablesS.html
          @@ -0,0 +1,20 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
          +
          +<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" href="../styles/main.css"><script language=JavaScript src="../javascript/main.js"></script></head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()"><script language=JavaScript><!--
          +if (browserType) {document.write("<div class=" + browserType + ">");if (browserVer) {document.write("<div class=" + browserVer + ">"); }}// --></script>
          +
          +<!--  Generated by Natural Docs, version 1.52 -->
          +<!--  http://www.naturaldocs.org  -->
          +
          +<!-- saved from url=(0026)http://www.naturaldocs.org -->
          +
          +
          +
          +
          +<div id=Index><div class=SRStatus id=Loading>Loading...</div><table border=0 cellspacing=0 cellpadding=0><div class=SRResult id=SR_servtype><div class=IEntry><a href="../files/strophe-js.html#Strophe.Connection.servtype" target=_parent class=ISymbol>servtype</a>, <span class=IParent>Strophe.<wbr>Connection</span></div></div><div class=SRResult id=SR_strip><div class=IEntry><a href="../files/strophe-js.html#Strophe.Bosh.strip" target=_parent class=ISymbol>strip</a>, <span class=IParent>Strophe.Bosh</span></div></div></table><div class=SRStatus id=Searching>Searching...</div><div class=SRStatus id=NoMatches>No Matches</div><script type="text/javascript"><!--
          +document.getElementById("Loading").style.display="none";
          +document.getElementById("NoMatches").style.display="none";
          +var searchResults = new SearchResults("searchResults", "HTML");
          +searchResults.Search();
          +--></script></div><script language=JavaScript><!--
          +if (browserType) {if (browserVer) {document.write("</div>"); }document.write("</div>");}// --></script></body></html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/doc/styles/main.css b/public/javascripts/strophejs-1.1.3/doc/styles/main.css
          new file mode 100644
          index 0000000..511703f
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/doc/styles/main.css
          @@ -0,0 +1,828 @@
          +/*
          +   IMPORTANT: If you're editing this file in the output directory of one of
          +   your projects, your changes will be overwritten the next time you run
          +   Natural Docs.  Instead, copy this file to your project directory, make your
          +   changes, and you can use it with -s.  Even better would be to make a CSS
          +   file in your project directory with only your changes, which you can then
          +   use with -s [original style] [your changes].
          +
          +   On the other hand, if you're editing this file in the Natural Docs styles
          +   directory, the changes will automatically be applied to all your projects
          +   that use this style the next time Natural Docs is run on them.
          +
          +   This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure.
          +   Natural Docs is licensed under version 3 of the GNU Affero General Public
          +   License (AGPL).  Refer to License.txt for the complete details.
          +
          +   This file may be distributed with documentation files generated by Natural Docs.
          +   Such documentation is not covered by Natural Docs' copyright and licensing,
          +   and may have its own copyright and distribution terms as decided by its author.
          +*/
          +
          +body {
          +    font: 10pt Verdana, Arial, sans-serif;
          +    color: #000000;
          +    margin: 0; padding: 0;
          +    }
          +
          +.ContentPage,
          +.IndexPage,
          +.FramedMenuPage {
          +    background-color: #E8E8E8;
          +    }
          +.FramedContentPage,
          +.FramedIndexPage,
          +.FramedSearchResultsPage,
          +.PopupSearchResultsPage {
          +    background-color: #FFFFFF;
          +    }
          +
          +
          +a:link,
          +a:visited { color: #900000; text-decoration: none }
          +a:hover { color: #900000; text-decoration: underline }
          +a:active { color: #FF0000; text-decoration: underline }
          +
          +td {
          +    vertical-align: top }
          +
          +img { border: 0;  }
          +
          +
          +/*
          +    Comment out this line to use web-style paragraphs (blank line between
          +    paragraphs, no indent) instead of print-style paragraphs (no blank line,
          +    indented.)
          +*/
          +p {
          +    text-indent: 5ex; margin: 0 }
          +
          +
          +/*  Opera doesn't break with just wbr, but will if you add this.  */
          +.Opera wbr:after {
          +	content: "\00200B";
          +	}
          +
          +
          +/*  Blockquotes are used as containers for things that may need to scroll.  */
          +blockquote {
          +    padding: 0;
          +    margin: 0;
          +    overflow: auto;
          +    }
          +
          +
          +.Firefox1 blockquote {
          +    padding-bottom: .5em;
          +    }
          +
          +/*  Turn off scrolling when printing.  */
          +@media print {
          +    blockquote {
          +        overflow: visible;
          +        }
          +    .IE blockquote {
          +        width: auto;
          +        }
          +    }
          +
          +
          +
          +#Menu {
          +    font-size: 9pt;
          +    padding: 10px 0 0 0;
          +    }
          +.ContentPage #Menu,
          +.IndexPage #Menu {
          +    position: absolute;
          +    top: 0;
          +    left: 0;
          +    width: 31ex;
          +    overflow: hidden;
          +    }
          +.ContentPage .Firefox #Menu,
          +.IndexPage .Firefox #Menu {
          +    width: 27ex;
          +    }
          +
          +
          +    .MTitle {
          +        font-size: 16pt; font-weight: bold; font-variant: small-caps;
          +        text-align: center;
          +        padding: 5px 10px 15px 10px;
          +        border-bottom: 1px dotted #000000;
          +        margin-bottom: 15px }
          +
          +    .MSubTitle {
          +        font-size: 9pt; font-weight: normal; font-variant: normal;
          +        margin-top: 1ex; margin-bottom: 5px }
          +
          +
          +    .MEntry a:link,
          +    .MEntry a:hover,
          +    .MEntry a:visited { color: #606060; margin-right: 0 }
          +    .MEntry a:active { color: #A00000; margin-right: 0 }
          +
          +
          +    .MGroup {
          +        font-variant: small-caps; font-weight: bold;
          +        margin: 1em 0 1em 10px;
          +        }
          +
          +    .MGroupContent {
          +        font-variant: normal; font-weight: normal }
          +
          +    .MGroup a:link,
          +    .MGroup a:hover,
          +    .MGroup a:visited { color: #545454; margin-right: 10px }
          +    .MGroup a:active { color: #A00000; margin-right: 10px }
          +
          +
          +    .MFile,
          +    .MText,
          +    .MLink,
          +    .MIndex {
          +        padding: 1px 17px 2px 10px;
          +        margin: .25em 0 .25em 0;
          +        }
          +
          +    .MText {
          +        font-size: 8pt; font-style: italic }
          +
          +    .MLink {
          +        font-style: italic }
          +
          +    #MSelected {
          +        color: #000000; background-color: #FFFFFF;
          +        /*  Replace padding with border.  */
          +        padding: 0 10px 0 10px;
          +        border-width: 1px 2px 2px 0; border-style: solid; border-color: #000000;
          +        margin-right: 5px;
          +        }
          +
          +    /*  Close off the left side when its in a group.  */
          +    .MGroup #MSelected {
          +        padding-left: 9px; border-left-width: 1px }
          +
          +    /*  A treat for Mozilla users.  Blatantly non-standard.  Will be replaced with CSS 3 attributes when finalized/supported.  */
          +    .Firefox #MSelected {
          +        -moz-border-radius-topright: 10px;
          +        -moz-border-radius-bottomright: 10px }
          +    .Firefox .MGroup #MSelected {
          +        -moz-border-radius-topleft: 10px;
          +        -moz-border-radius-bottomleft: 10px }
          +
          +
          +    #MSearchPanel {
          +        padding: 0px 6px;
          +        margin: .25em 0;
          +        }
          +
          +
          +    #MSearchField {
          +        font: italic 9pt Verdana, sans-serif;
          +        color: #606060;
          +        background-color: #E8E8E8;
          +        border: none;
          +        padding: 2px 4px;
          +        width: 100%;
          +        }
          +    /* Only Opera gets it right. */
          +    .Firefox #MSearchField,
          +    .IE #MSearchField,
          +    .Safari #MSearchField {
          +        width: 94%;
          +        }
          +    .Opera9 #MSearchField,
          +    .Konqueror #MSearchField {
          +        width: 97%;
          +        }
          +    .FramedMenuPage .Firefox #MSearchField,
          +    .FramedMenuPage .Safari #MSearchField,
          +    .FramedMenuPage .Konqueror #MSearchField {
          +        width: 98%;
          +        }
          +
          +    /* Firefox doesn't do this right in frames without #MSearchPanel added on.
          +        It's presence doesn't hurt anything other browsers. */
          +    #MSearchPanel.MSearchPanelInactive:hover #MSearchField {
          +        background-color: #FFFFFF;
          +        border: 1px solid #C0C0C0;
          +        padding: 1px 3px;
          +        }
          +    .MSearchPanelActive #MSearchField {
          +        background-color: #FFFFFF;
          +        border: 1px solid #C0C0C0;
          +        font-style: normal;
          +        padding: 1px 3px;
          +        }
          +
          +    #MSearchType {
          +        visibility: hidden;
          +        font: 8pt Verdana, sans-serif;
          +        width: 98%;
          +        padding: 0;
          +        border: 1px solid #C0C0C0;
          +        }
          +    .MSearchPanelActive #MSearchType,
          +    /*  As mentioned above, Firefox doesn't do this right in frames without #MSearchPanel added on. */
          +    #MSearchPanel.MSearchPanelInactive:hover #MSearchType,
          +    #MSearchType:focus {
          +        visibility: visible;
          +        color: #606060;
          +        }
          +    #MSearchType option#MSearchEverything {
          +        font-weight: bold;
          +        }
          +
          +    .Opera8 .MSearchPanelInactive:hover,
          +    .Opera8 .MSearchPanelActive {
          +        margin-left: -1px;
          +        }
          +
          +
          +    iframe#MSearchResults {
          +        width: 60ex;
          +        height: 15em;
          +        }
          +    #MSearchResultsWindow {
          +        display: none;
          +        position: absolute;
          +        left: 0; top: 0;
          +        border: 1px solid #000000;
          +        background-color: #E8E8E8;
          +        }
          +    #MSearchResultsWindowClose {
          +        font-weight: bold;
          +        font-size: 8pt;
          +        display: block;
          +        padding: 2px 5px;
          +        }
          +    #MSearchResultsWindowClose:link,
          +    #MSearchResultsWindowClose:visited {
          +        color: #000000;
          +        text-decoration: none;
          +        }
          +    #MSearchResultsWindowClose:active,
          +    #MSearchResultsWindowClose:hover {
          +        color: #800000;
          +        text-decoration: none;
          +        background-color: #F4F4F4;
          +        }
          +
          +
          +
          +
          +#Content {
          +    padding-bottom: 15px;
          +    }
          +
          +.ContentPage #Content {
          +    border-width: 0 0 1px 1px;
          +    border-style: solid;
          +    border-color: #000000;
          +    background-color: #FFFFFF;
          +    font-size: 9pt;  /* To make 31ex match the menu's 31ex. */
          +    margin-left: 31ex;
          +    }
          +.ContentPage .Firefox #Content {
          +    margin-left: 27ex;
          +    }
          +
          +
          +
          +    .CTopic {
          +        font-size: 10pt;
          +        margin-bottom: 3em;
          +        }
          +
          +
          +    .CTitle {
          +        font-size: 12pt; font-weight: bold;
          +        border-width: 0 0 1px 0; border-style: solid; border-color: #A0A0A0;
          +        margin: 0 15px .5em 15px }
          +
          +    .CGroup .CTitle {
          +        font-size: 16pt; font-variant: small-caps;
          +        padding-left: 15px; padding-right: 15px;
          +        border-width: 0 0 2px 0; border-color: #000000;
          +        margin-left: 0; margin-right: 0 }
          +
          +    .CClass .CTitle,
          +    .CInterface .CTitle,
          +    .CDatabase .CTitle,
          +    .CDatabaseTable .CTitle,
          +    .CSection .CTitle {
          +        font-size: 18pt;
          +        color: #FFFFFF; background-color: #A0A0A0;
          +        padding: 10px 15px 10px 15px;
          +        border-width: 2px 0; border-color: #000000;
          +        margin-left: 0; margin-right: 0 }
          +
          +    #MainTopic .CTitle {
          +        font-size: 20pt;
          +        color: #FFFFFF; background-color: #7070C0;
          +        padding: 10px 15px 10px 15px;
          +        border-width: 0 0 3px 0; border-color: #000000;
          +        margin-left: 0; margin-right: 0 }
          +
          +    .CBody {
          +        margin-left: 15px; margin-right: 15px }
          +
          +
          +    .CToolTip {
          +        position: absolute; visibility: hidden;
          +        left: 0; top: 0;
          +        background-color: #FFFFE0;
          +        padding: 5px;
          +        border-width: 1px 2px 2px 1px; border-style: solid; border-color: #000000;
          +        font-size: 8pt;
          +        }
          +
          +    .Opera .CToolTip {
          +        max-width: 98%;
          +        }
          +
          +    /*  Scrollbars would be useless.  */
          +    .CToolTip blockquote {
          +        overflow: hidden;
          +        }
          +    .IE6 .CToolTip blockquote {
          +        overflow: visible;
          +        }
          +
          +    .CHeading {
          +        font-weight: bold; font-size: 10pt;
          +        margin: 1.5em 0 .5em 0;
          +        }
          +
          +    .CBody pre {
          +        font: 10pt "Courier New", Courier, monospace;
          +	    background-color: #FCFCFC;
          +	    margin: 1em 35px;
          +	    padding: 10px 15px 10px 10px;
          +	    border-color: #E0E0E0 #E0E0E0 #E0E0E0 #E4E4E4;
          +	    border-width: 1px 1px 1px 6px;
          +	    border-style: dashed dashed dashed solid;
          +        }
          +
          +    .CBody ul {
          +        /*  I don't know why CBody's margin doesn't apply, but it's consistent across browsers so whatever.
          +             Reapply it here as padding.  */
          +        padding-left: 15px; padding-right: 15px;
          +        margin: .5em 5ex .5em 5ex;
          +        }
          +
          +    .CDescriptionList {
          +        margin: .5em 5ex 0 5ex }
          +
          +        .CDLEntry {
          +            font: 10pt "Courier New", Courier, monospace; color: #808080;
          +            padding-bottom: .25em;
          +            white-space: nowrap }
          +
          +        .CDLDescription {
          +            font-size: 10pt;  /*  For browsers that don't inherit correctly, like Opera 5.  */
          +            padding-bottom: .5em; padding-left: 5ex }
          +
          +
          +    .CTopic img {
          +        text-align: center;
          +        display: block;
          +        margin: 1em auto;
          +        }
          +    .CImageCaption {
          +        font-variant: small-caps;
          +        font-size: 8pt;
          +        color: #808080;
          +        text-align: center;
          +        position: relative;
          +        top: 1em;
          +        }
          +
          +    .CImageLink {
          +        color: #808080;
          +        font-style: italic;
          +        }
          +    a.CImageLink:link,
          +    a.CImageLink:visited,
          +    a.CImageLink:hover { color: #808080 }
          +
          +
          +
          +
          +
          +.Prototype {
          +    font: 10pt "Courier New", Courier, monospace;
          +    padding: 5px 3ex;
          +    border-width: 1px; border-style: solid;
          +    margin: 0 5ex 1.5em 5ex;
          +    }
          +
          +    .Prototype td {
          +        font-size: 10pt;
          +        }
          +
          +    .PDefaultValue,
          +    .PDefaultValuePrefix,
          +    .PTypePrefix {
          +        color: #8F8F8F;
          +        }
          +    .PTypePrefix {
          +        text-align: right;
          +        }
          +    .PAfterParameters {
          +        vertical-align: bottom;
          +        }
          +
          +    .IE .Prototype table {
          +        padding: 0;
          +        }
          +
          +    .CFunction .Prototype {
          +        background-color: #F4F4F4; border-color: #D0D0D0 }
          +    .CProperty .Prototype {
          +        background-color: #F4F4FF; border-color: #C0C0E8 }
          +    .CVariable .Prototype {
          +        background-color: #FFFFF0; border-color: #E0E0A0 }
          +
          +    .CClass .Prototype {
          +        border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0;
          +        background-color: #F4F4F4;
          +        }
          +    .CInterface .Prototype {
          +        border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0D0;
          +        background-color: #F4F4FF;
          +        }
          +
          +    .CDatabaseIndex .Prototype,
          +    .CConstant .Prototype {
          +        background-color: #D0D0D0; border-color: #000000 }
          +    .CType .Prototype,
          +    .CEnumeration .Prototype {
          +        background-color: #FAF0F0; border-color: #E0B0B0;
          +        }
          +    .CDatabaseTrigger .Prototype,
          +    .CEvent .Prototype,
          +    .CDelegate .Prototype {
          +        background-color: #F0FCF0; border-color: #B8E4B8 }
          +
          +    .CToolTip .Prototype {
          +        margin: 0 0 .5em 0;
          +        white-space: nowrap;
          +        }
          +
          +
          +
          +
          +
          +.Summary {
          +    margin: 1.5em 5ex 0 5ex }
          +
          +    .STitle {
          +        font-size: 12pt; font-weight: bold;
          +        margin-bottom: .5em }
          +
          +
          +    .SBorder {
          +        background-color: #FFFFF0;
          +        padding: 15px;
          +        border: 1px solid #C0C060 }
          +
          +    /* In a frame IE 6 will make them too long unless you set the width to 100%.  Without frames it will be correct without a width
          +        or slightly too long (but not enough to scroll) with a width.  This arbitrary weirdness simply astounds me.  IE 7 has the same
          +        problem with frames, haven't tested it without.  */
          +    .FramedContentPage .IE .SBorder {
          +        width: 100% }
          +
          +    /*  A treat for Mozilla users.  Blatantly non-standard.  Will be replaced with CSS 3 attributes when finalized/supported.  */
          +    .Firefox .SBorder {
          +        -moz-border-radius: 20px }
          +
          +
          +    .STable {
          +        font-size: 9pt; width: 100% }
          +
          +    .SEntry {
          +        width: 30% }
          +    .SDescription {
          +        width: 70% }
          +
          +
          +    .SMarked {
          +        background-color: #F8F8D8 }
          +
          +    .SDescription { padding-left: 2ex }
          +    .SIndent1 .SEntry { padding-left: 1.5ex }   .SIndent1 .SDescription { padding-left: 3.5ex }
          +    .SIndent2 .SEntry { padding-left: 3.0ex }   .SIndent2 .SDescription { padding-left: 5.0ex }
          +    .SIndent3 .SEntry { padding-left: 4.5ex }   .SIndent3 .SDescription { padding-left: 6.5ex }
          +    .SIndent4 .SEntry { padding-left: 6.0ex }   .SIndent4 .SDescription { padding-left: 8.0ex }
          +    .SIndent5 .SEntry { padding-left: 7.5ex }   .SIndent5 .SDescription { padding-left: 9.5ex }
          +
          +    .SDescription a { color: #800000}
          +    .SDescription a:active { color: #A00000 }
          +
          +    .SGroup td {
          +        padding-top: .5em; padding-bottom: .25em }
          +
          +    .SGroup .SEntry {
          +        font-weight: bold; font-variant: small-caps }
          +
          +    .SGroup .SEntry a { color: #800000 }
          +    .SGroup .SEntry a:active { color: #F00000 }
          +
          +
          +    .SMain td,
          +    .SClass td,
          +    .SDatabase td,
          +    .SDatabaseTable td,
          +    .SSection td {
          +        font-size: 10pt;
          +        padding-bottom: .25em }
          +
          +    .SClass td,
          +    .SDatabase td,
          +    .SDatabaseTable td,
          +    .SSection td {
          +        padding-top: 1em }
          +
          +    .SMain .SEntry,
          +    .SClass .SEntry,
          +    .SDatabase .SEntry,
          +    .SDatabaseTable .SEntry,
          +    .SSection .SEntry {
          +        font-weight: bold;
          +        }
          +
          +    .SMain .SEntry a,
          +    .SClass .SEntry a,
          +    .SDatabase .SEntry a,
          +    .SDatabaseTable .SEntry a,
          +    .SSection .SEntry a { color: #000000 }
          +
          +    .SMain .SEntry a:active,
          +    .SClass .SEntry a:active,
          +    .SDatabase .SEntry a:active,
          +    .SDatabaseTable .SEntry a:active,
          +    .SSection .SEntry a:active { color: #A00000 }
          +
          +
          +
          +
          +
          +.ClassHierarchy {
          +    margin: 0 15px 1em 15px }
          +
          +    .CHEntry {
          +        border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0;
          +        margin-bottom: 3px;
          +        padding: 2px 2ex;
          +        font-size: 10pt;
          +        background-color: #F4F4F4; color: #606060;
          +        }
          +
          +    .Firefox .CHEntry {
          +        -moz-border-radius: 4px;
          +        }
          +
          +    .CHCurrent .CHEntry {
          +        font-weight: bold;
          +        border-color: #000000;
          +        color: #000000;
          +        }
          +
          +    .CHChildNote .CHEntry {
          +        font-style: italic;
          +        font-size: 8pt;
          +        }
          +
          +    .CHIndent {
          +        margin-left: 3ex;
          +        }
          +
          +    .CHEntry a:link,
          +    .CHEntry a:visited,
          +    .CHEntry a:hover {
          +        color: #606060;
          +        }
          +    .CHEntry a:active {
          +        color: #800000;
          +        }
          +
          +
          +
          +
          +
          +#Index {
          +    background-color: #FFFFFF;
          +    }
          +
          +/*  As opposed to .PopupSearchResultsPage #Index  */
          +.IndexPage #Index,
          +.FramedIndexPage #Index,
          +.FramedSearchResultsPage #Index {
          +    padding: 15px;
          +    }
          +
          +.IndexPage #Index {
          +    border-width: 0 0 1px 1px;
          +    border-style: solid;
          +    border-color: #000000;
          +    font-size: 9pt;  /* To make 27ex match the menu's 27ex. */
          +    margin-left: 27ex;
          +    }
          +
          +
          +    .IPageTitle {
          +        font-size: 20pt; font-weight: bold;
          +        color: #FFFFFF; background-color: #7070C0;
          +        padding: 10px 15px 10px 15px;
          +        border-width: 0 0 3px 0; border-color: #000000; border-style: solid;
          +        margin: -15px -15px 0 -15px }
          +
          +    .FramedSearchResultsPage .IPageTitle {
          +        margin-bottom: 15px;
          +        }
          +
          +    .INavigationBar {
          +        font-size: 10pt;
          +        text-align: center;
          +        background-color: #FFFFF0;
          +        padding: 5px;
          +        border-bottom: solid 1px black;
          +        margin: 0 -15px 15px -15px;
          +        }
          +
          +    .INavigationBar a {
          +        font-weight: bold }
          +
          +    .IHeading {
          +        font-size: 16pt; font-weight: bold;
          +        padding: 2.5em 0 .5em 0;
          +        text-align: center;
          +        width: 3.5ex;
          +        }
          +    #IFirstHeading {
          +        padding-top: 0;
          +        }
          +
          +    .IEntry {
          +        font-size: 10pt;
          +        padding-left: 1ex;
          +        }
          +    .PopupSearchResultsPage .IEntry {
          +        font-size: 8pt;
          +        padding: 1px 5px;
          +        }
          +    .PopupSearchResultsPage .Opera9 .IEntry,
          +    .FramedSearchResultsPage .Opera9 .IEntry {
          +        text-align: left;
          +        }
          +    .FramedSearchResultsPage .IEntry {
          +        padding: 0;
          +        }
          +
          +    .ISubIndex {
          +        padding-left: 3ex; padding-bottom: .5em }
          +    .PopupSearchResultsPage .ISubIndex {
          +        display: none;
          +        }
          +
          +    /*  While it may cause some entries to look like links when they aren't, I found it's much easier to read the
          +         index if everything's the same color.  */
          +    .ISymbol {
          +        font-weight: bold; color: #900000  }
          +
          +    .IndexPage .ISymbolPrefix,
          +    .FramedIndexPage .ISymbolPrefix {
          +        font-size: 10pt;
          +        text-align: right;
          +        color: #C47C7C;
          +        background-color: #F8F8F8;
          +        border-right: 3px solid #E0E0E0;
          +        border-left: 1px solid #E0E0E0;
          +        padding: 0 1px 0 2px;
          +        }
          +    .PopupSearchResultsPage .ISymbolPrefix,
          +    .FramedSearchResultsPage .ISymbolPrefix {
          +        color: #900000;
          +        }
          +    .PopupSearchResultsPage .ISymbolPrefix {
          +        font-size: 8pt;
          +        }
          +
          +    .IndexPage #IFirstSymbolPrefix,
          +    .FramedIndexPage #IFirstSymbolPrefix {
          +        border-top: 1px solid #E0E0E0;
          +        }
          +    .IndexPage #ILastSymbolPrefix,
          +    .FramedIndexPage #ILastSymbolPrefix {
          +        border-bottom: 1px solid #E0E0E0;
          +        }
          +    .IndexPage #IOnlySymbolPrefix,
          +    .FramedIndexPage #IOnlySymbolPrefix {
          +        border-top: 1px solid #E0E0E0;
          +        border-bottom: 1px solid #E0E0E0;
          +        }
          +
          +    a.IParent,
          +    a.IFile {
          +        display: block;
          +        }
          +
          +    .PopupSearchResultsPage .SRStatus {
          +        padding: 2px 5px;
          +        font-size: 8pt;
          +        font-style: italic;
          +        }
          +    .FramedSearchResultsPage .SRStatus {
          +        font-size: 10pt;
          +        font-style: italic;
          +        }
          +
          +    .SRResult {
          +        display: none;
          +        }
          +
          +
          +
          +#Footer {
          +    font-size: 8pt;
          +    color: #989898;
          +    text-align: right;
          +    }
          +
          +#Footer p {
          +    text-indent: 0;
          +    margin-bottom: .5em;
          +    }
          +
          +.ContentPage #Footer,
          +.IndexPage #Footer {
          +    text-align: right;
          +    margin: 2px;
          +    }
          +
          +.FramedMenuPage #Footer {
          +    text-align: center;
          +    margin: 5em 10px 10px 10px;
          +    padding-top: 1em;
          +    border-top: 1px solid #C8C8C8;
          +    }
          +
          +    #Footer a:link,
          +    #Footer a:hover,
          +    #Footer a:visited { color: #989898 }
          +    #Footer a:active { color: #A00000 }
          +
          +
          +
          +.prettyprint .kwd { color: #800000; }  /* keywords */
          +
          +    .prettyprint.PDefaultValue .kwd,
          +    .prettyprint.PDefaultValuePrefix .kwd,
          +    .prettyprint.PTypePrefix .kwd {
          +        color: #C88F8F;
          +        }
          +
          +.prettyprint .com { color: #008000; }  /* comments */
          +
          +    .prettyprint.PDefaultValue .com,
          +    .prettyprint.PDefaultValuePrefix .com,
          +    .prettyprint.PTypePrefix .com {
          +        color: #8FC88F;
          +        }
          +
          +.prettyprint .str { color: #0000B0; }  /* strings */
          +.prettyprint .lit { color: #0000B0; }  /* literals */
          +
          +    .prettyprint.PDefaultValue .str,
          +    .prettyprint.PDefaultValuePrefix .str,
          +    .prettyprint.PTypePrefix .str,
          +    .prettyprint.PDefaultValue .lit,
          +    .prettyprint.PDefaultValuePrefix .lit,
          +    .prettyprint.PTypePrefix .lit {
          +        color: #8F8FC0;
          +        }
          +
          +.prettyprint .typ { color: #000000; }  /* types */
          +.prettyprint .pun { color: #000000; }  /* punctuation */
          +.prettyprint .pln { color: #000000; }  /* punctuation */
          +
          +    .prettyprint.PDefaultValue .typ,
          +    .prettyprint.PDefaultValuePrefix .typ,
          +    .prettyprint.PTypePrefix .typ,
          +    .prettyprint.PDefaultValue .pun,
          +    .prettyprint.PDefaultValuePrefix .pun,
          +    .prettyprint.PTypePrefix .pun,
          +    .prettyprint.PDefaultValue .pln,
          +    .prettyprint.PDefaultValuePrefix .pln,
          +    .prettyprint.PTypePrefix .pln {
          +        color: #8F8F8F;
          +        }
          +
          +.prettyprint .tag { color: #008; }
          +.prettyprint .atn { color: #606; }
          +.prettyprint .atv { color: #080; }
          +.prettyprint .dec { color: #606; }
          +
          diff --git a/public/javascripts/strophejs-1.1.3/examples/attach/README b/public/javascripts/strophejs-1.1.3/examples/attach/README
          new file mode 100644
          index 0000000..3b190aa
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/attach/README
          @@ -0,0 +1,37 @@
          +This is an example of Strophe attaching to a pre-existing BOSH session
          +that is created externally.  This example requires a bit more than
          +HTML and JavaScript.  Specifically it contains a very simple Web
          +application written in Django which creates a BOSH session before
          +rendering the page.
          +
          +Requirements:
          +
          +* Django 1.0 (http://www.djangoproject.com)
          +* Twisted 8.1.x (http://twistedmatrix.com)
          +* Punjab 0.3 (http://code.stanziq.com/punjab)
          +
          +Note that Twisted and Punjab are only used for small functions related
          +to JID and BOSH parsing.
          +
          +How It Works:
          +
          +The Django app contains one view which is tied to the root URL.  This
          +view uses the BOSHClient class to start a BOSH session using the
          +settings from settings.py.
          +
          +Once the connection is established, Django passes the JID, SID, and
          +RID for the BOSH session into the template engine and renders the
          +page.
          +
          +The template assigns the JID, SID, and RID to global vars like so:
          +
          +    var BOSH_JID = {{ jid }};
          +    var BOSH_SID = {{ sid }};
          +    var BOSH_RID = {{ rid }};
          +
          +The connection is attached to Strophe by calling
          +Strophe.Connection.attach() with this data and a connection callback
          +handler.
          +
          +To show that the session is attached and works, a disco info ping is
          +done to jabber.org.
          diff --git a/public/javascripts/strophejs-1.1.3/examples/attach/__init__.py b/public/javascripts/strophejs-1.1.3/examples/attach/__init__.py
          new file mode 100644
          index 0000000..e69de29
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/attach/__init__.py
          diff --git a/public/javascripts/strophejs-1.1.3/examples/attach/attacher/__init__.py b/public/javascripts/strophejs-1.1.3/examples/attach/attacher/__init__.py
          new file mode 100644
          index 0000000..e69de29
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/attach/attacher/__init__.py
          diff --git a/public/javascripts/strophejs-1.1.3/examples/attach/attacher/views.py b/public/javascripts/strophejs-1.1.3/examples/attach/attacher/views.py
          new file mode 100644
          index 0000000..c495cab
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/attach/attacher/views.py
          @@ -0,0 +1,18 @@
          +from django.http import HttpResponse
          +from django.template import Context, loader
          +
          +from attach.settings import BOSH_SERVICE, JABBERID, PASSWORD
          +from attach.boshclient import BOSHClient
          +
          +def index(request):
          +    bc = BOSHClient(JABBERID, PASSWORD, BOSH_SERVICE)
          +    bc.startSessionAndAuth()
          +
          +    t = loader.get_template("attacher/index.html")
          +    c = Context({
          +	    'jid': bc.jabberid.full(),
          +	    'sid': bc.sid,
          +	    'rid': bc.rid,
          +    })
          +
          +    return HttpResponse(t.render(c))
          diff --git a/public/javascripts/strophejs-1.1.3/examples/attach/boshclient.py b/public/javascripts/strophejs-1.1.3/examples/attach/boshclient.py
          new file mode 100644
          index 0000000..e6fe969
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/attach/boshclient.py
          @@ -0,0 +1,158 @@
          +import sys, os
          +import httplib, urllib
          +import random, binascii
          +from urlparse import urlparse
          +
          +from punjab.httpb import HttpbParse
          +
          +from twisted.words.xish import domish
          +from twisted.words.protocols.jabber import jid
          +
          +TLS_XMLNS = 'urn:ietf:params:xml:ns:xmpp-tls'
          +SASL_XMLNS = 'urn:ietf:params:xml:ns:xmpp-sasl'
          +BIND_XMLNS = 'urn:ietf:params:xml:ns:xmpp-bind'
          +SESSION_XMLNS = 'urn:ietf:params:xml:ns:xmpp-session'
          +
          +
          +class BOSHClient:
          +    def __init__(self, jabberid, password, bosh_service):
          +        self.rid = random.randint(0, 10000000)
          +        self.jabberid = jid.internJID(jabberid)
          +        self.password = password
          +
          +        self.authid = None
          +        self.sid = None
          +        self.logged_in = False
          +        self.headers = {"Content-type": "text/xml",
          +                        "Accept": "text/xml"}
          +
          +	self.bosh_service = urlparse(bosh_service)
          +        
          +    def buildBody(self, child=None):
          +        """Build a BOSH body.
          +        """
          +        
          +        body = domish.Element(("http://jabber.org/protocol/httpbind", "body"))
          +        body['content'] = 'text/xml; charset=utf-8'
          +        self.rid = self.rid + 1
          +        body['rid'] = str(self.rid)
          +        body['sid'] = str(self.sid)
          +        body['xml:lang'] = 'en'
          +     
          +        if child is not None:
          +            body.addChild(child)
          +
          +        return body
          +        
          +    def sendBody(self, body):
          +        """Send the body.
          +        """
          +
          +        parser = HttpbParse(True)
          +
          +        # start new session
          +        conn = httplib.HTTPConnection(self.bosh_service.netloc)
          +        conn.request("POST", self.bosh_service.path, 
          +		     body.toXml(), self.headers)
          +
          +        response = conn.getresponse()
          +	data = ''
          +        if response.status == 200:
          +            data = response.read()
          +        conn.close()
          +
          +        return parser.parse(data)
          +
          +    def startSessionAndAuth(self, hold='1', wait='70'):
          +        # Create a session
          +        # create body
          +        body = domish.Element(("http://jabber.org/protocol/httpbind", "body"))
          +
          +        body['content'] = 'text/xml; charset=utf-8'
          +        body['hold'] = hold
          +        body['rid'] = str(self.rid)
          +        body['to'] = self.jabberid.host
          +        body['wait'] = wait
          +        body['window'] = '5'
          +        body['xml:lang'] = 'en'
          +
          +
          +        retb, elems = self.sendBody(body)
          +        if type(retb) != str and retb.hasAttribute('authid') and \
          +		retb.hasAttribute('sid'):
          +            self.authid = retb['authid']
          +            self.sid = retb['sid']
          +
          +            # go ahead and auth
          +            auth = domish.Element((SASL_XMLNS, 'auth'))
          +            auth['mechanism'] = 'PLAIN'
          +            
          +            # TODO: add authzid
          +            if auth['mechanism'] == 'PLAIN':
          +                auth_str = ""
          +                auth_str += "\000"
          +                auth_str += self.jabberid.user.encode('utf-8')
          +                auth_str += "\000"
          +                try:
          +                    auth_str += self.password.encode('utf-8').strip()
          +                except UnicodeDecodeError:
          +                    auth_str += self.password.decode('latin1') \
          +		        .encode('utf-8').strip()
          +                        
          +                auth.addContent(binascii.b2a_base64(auth_str))
          +                
          +                retb, elems = self.sendBody(self.buildBody(auth))
          +                if len(elems) == 0:
          +		    # poll for data
          +                    retb, elems = self.sendBody(self.buildBody())
          +
          +                if len(elems) > 0:
          +                    if elems[0].name == 'success':
          +                        retb, elems = self.sendBody(self.buildBody())
          +                        
          +                        has_bind = False
          +                        for child in elems[0].children:
          +                            if child.name == 'bind':
          +                                has_bind = True
          +                                break
          +
          +                        if has_bind:
          +                            iq = domish.Element(('jabber:client', 'iq'))
          +                            iq['type'] = 'set'
          +                            iq.addUniqueId()
          +                            iq.addElement('bind')
          +                            iq.bind['xmlns'] = BIND_XMLNS
          +                            if self.jabberid.resource:
          +				iq.bind.addElement('resource')
          +				iq.bind.resource.addContent(
          +				    self.jabberid.resource)
          +
          +                            retb, elems = self.sendBody(self.buildBody(iq))
          +                            if type(retb) != str and retb.name == 'body':
          +                                # send session
          +                                iq = domish.Element(('jabber:client', 'iq'))
          +                                iq['type'] = 'set'
          +                                iq.addUniqueId()
          +                                iq.addElement('session')
          +                                iq.session['xmlns'] = SESSION_XMLNS
          +
          +                                retb, elems = self.sendBody(self.buildBody(iq))
          +
          +				# did not bind, TODO - add a retry?
          +                                if type(retb) != str and retb.name == 'body':
          +                                    self.logged_in = True
          +				    # bump up the rid, punjab already 
          +				    # received self.rid
          +                                    self.rid += 1
          +
          +
          +if __name__ == '__main__':
          +    USERNAME = sys.argv[1]
          +    PASSWORD = sys.argv[2]
          +    SERVICE = sys.argv[3]
          +
          +    c = BOSHClient(USERNAME, PASSWORD, SERVICE)
          +    c.startSessionAndAuth()
          +
          +    print c.logged_in
          +    
          diff --git a/public/javascripts/strophejs-1.1.3/examples/attach/manage.py b/public/javascripts/strophejs-1.1.3/examples/attach/manage.py
          new file mode 100644
          index 0000000..5e78ea9
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/attach/manage.py
          @@ -0,0 +1,11 @@
          +#!/usr/bin/env python
          +from django.core.management import execute_manager
          +try:
          +    import settings # Assumed to be in the same directory.
          +except ImportError:
          +    import sys
          +    sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
          +    sys.exit(1)
          +
          +if __name__ == "__main__":
          +    execute_manager(settings)
          diff --git a/public/javascripts/strophejs-1.1.3/examples/attach/settings.py b/public/javascripts/strophejs-1.1.3/examples/attach/settings.py
          new file mode 100644
          index 0000000..419ec36
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/attach/settings.py
          @@ -0,0 +1,85 @@
          +# Django settings for attach project.
          +
          +DEBUG = True
          +TEMPLATE_DEBUG = DEBUG
          +
          +ADMINS = (
          +    ('Some Body', 'romeo@example.com'),
          +)
          +
          +MANAGERS = ADMINS
          +
          +DATABASE_ENGINE = 'sqlite3'           # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
          +DATABASE_NAME = '/path/to/attach.db'             # Or path to database file if using sqlite3.
          +DATABASE_USER = ''             # Not used with sqlite3.
          +DATABASE_PASSWORD = ''         # Not used with sqlite3.
          +DATABASE_HOST = ''             # Set to empty string for localhost. Not used with sqlite3.
          +DATABASE_PORT = ''             # Set to empty string for default. Not used with sqlite3.
          +
          +# Local time zone for this installation. Choices can be found here:
          +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
          +# although not all choices may be available on all operating systems.
          +# If running in a Windows environment this must be set to the same as your
          +# system time zone.
          +TIME_ZONE = 'America/Denver'
          +
          +# Language code for this installation. All choices can be found here:
          +# http://www.i18nguy.com/unicode/language-identifiers.html
          +LANGUAGE_CODE = 'en-us'
          +
          +SITE_ID = 1
          +
          +# If you set this to False, Django will make some optimizations so as not
          +# to load the internationalization machinery.
          +USE_I18N = True
          +
          +# Absolute path to the directory that holds media.
          +# Example: "/home/media/media.lawrence.com/"
          +MEDIA_ROOT = ''
          +
          +# URL that handles the media served from MEDIA_ROOT. Make sure to use a
          +# trailing slash if there is a path component (optional in other cases).
          +# Examples: "http://media.lawrence.com", "http://example.com/media/"
          +MEDIA_URL = ''
          +
          +# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
          +# trailing slash.
          +# Examples: "http://foo.com/media/", "/media/".
          +ADMIN_MEDIA_PREFIX = '/media/'
          +
          +# Make this unique, and don't share it with anybody.
          +SECRET_KEY = 'asdf'
          +
          +# List of callables that know how to import templates from various sources.
          +TEMPLATE_LOADERS = (
          +    'django.template.loaders.filesystem.load_template_source',
          +    'django.template.loaders.app_directories.load_template_source',
          +#     'django.template.loaders.eggs.load_template_source',
          +)
          +
          +MIDDLEWARE_CLASSES = (
          +    'django.middleware.common.CommonMiddleware',
          +    'django.contrib.sessions.middleware.SessionMiddleware',
          +    'django.contrib.auth.middleware.AuthenticationMiddleware',
          +)
          +
          +ROOT_URLCONF = 'attach.urls'
          +
          +TEMPLATE_DIRS = (
          +    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
          +    # Always use forward slashes, even on Windows.
          +    # Don't forget to use absolute paths, not relative paths.
          +    '/path/to/attach/templates',
          +)
          +
          +INSTALLED_APPS = (
          +    'django.contrib.auth',
          +    'django.contrib.contenttypes',
          +    'django.contrib.sessions',
          +    'django.contrib.sites',
          +    'attach.attacher',
          +)
          +
          +BOSH_SERVICE = 'http://example.com/xmpp-httpbind'
          +JABBERID = 'romeo@example.com/bosh'
          +PASSWORD = 'juliet.is.hawt'
          diff --git a/public/javascripts/strophejs-1.1.3/examples/attach/templates/attacher/index.html b/public/javascripts/strophejs-1.1.3/examples/attach/templates/attacher/index.html
          new file mode 100644
          index 0000000..14a7590
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/attach/templates/attacher/index.html
          @@ -0,0 +1,88 @@
          +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
          +<html xmlns='http://www.w3.org/1999/xhtml'>
          +  <head>
          +    <title>Strophe Attach Example</title>
          +    <script language='javascript'
          +	    type='text/javascript'
          +	    src='http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js'></script>
          +    <script language='javascript'
          +	    type='text/javascript'
          +	    src='http://code.stanziq.com/svn/strophe/trunk/strophejs/b64.js'></script>
          +    <script language='javascript'
          +	    type='text/javascript'
          +	    src='http://code.stanziq.com/svn/strophe/trunk/strophejs/md5.js'></script>
          +    <script language='javascript'
          +	    type='text/javascript'
          +	    src='http://code.stanziq.com/svn/strophe/trunk/strophejs/sha1.js'></script>
          +    <script language='javascript'
          +	    type='text/javascript'
          +	    src='http://code.stanziq.com/svn/strophe/trunk/strophejs/strophe.js'></script>
          +    <script language='javascript'
          +	    type='text/javascript'>
          +      <!--
          +	  var ATTACH_SID = "{{ sid }}";
          +	  var ATTACH_RID = "{{ rid }}";
          +	  var ATTACH_JID = "{{ jid }}";
          +	  var BOSH_SERVICE = '/xmpp-httpbind';
          +	  var connection = null;
          +	  var startTime = null;
          +
          +          function log(msg)
          +	  {
          +	      $('#log').append('<div></div>').append(
          +	          document.createTextNode(msg));
          +	  }
          +
          +	  function onConnect(status) 
          +	  {
          +	      if (status == Strophe.Status.DISCONNECTED)
          +	          log('Disconnected.');
          +	  }
          +
          +          function onResult(iq) {
          +	      var elapsed = (new Date()) - startTime;
          +	      log('Response from jabber.org took ' + elapsed + 'ms.');
          +          }
          +	  
          +	  $(document).ready(function () {
          +	      // create the connection and attach it
          +	      connection = new Strophe.Connection(BOSH_SERVICE);
          +	      connection.rawInput = function (data) { 
          +	          log('RECV: ' + data); 
          +	      };
          +	      connection.rawOutput = function (data) { 
          +	          log('SENT: ' + data); 
          +	      };
          +	      // uncomment for extra debugging
          +	      // Strophe.log = function (lvl, msg) { log(msg); };
          +	      connection.attach(ATTACH_JID, ATTACH_SID, ATTACH_RID,
          +	                        onConnect);
          +
          +              // set up handler
          +	      connection.addHandler(onResult, null, 'iq', 
          +	                            'result', 'disco-1', null);
          +
          +              log('Strophe is attached.');
          +				
          +	      // send disco#info to jabber.org
          +	      var iq = $iq({to: 'jabber.org',
          +	                    type: 'get',
          +			    id: 'disco-1'})
          +                  .c('query', {xmlns: Strophe.NS.DISCO_INFO})
          +		  .tree()
          +
          +              startTime = new Date();
          +              connection.send(iq);
          +          });
          +      // -->
          +    </script>
          +  </head>
          +  <body>
          +    <h1>Strophe Attach Example</h1>
          +    <p>This example shows how to attach to an existing BOSH session with
          +    Strophe.</p>
          +    <h2>Log</h2>
          +    <div id='log'>
          +    </div>
          +  </body>
          +</html>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/examples/attach/urls.py b/public/javascripts/strophejs-1.1.3/examples/attach/urls.py
          new file mode 100644
          index 0000000..387eb08
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/attach/urls.py
          @@ -0,0 +1,19 @@
          +from django.conf.urls.defaults import *
          +
          +# Uncomment the next two lines to enable the admin:
          +# from django.contrib import admin
          +# admin.autodiscover()
          +
          +urlpatterns = patterns('',
          +    # Example:
          +    # (r'^attach/', include('attach.foo.urls')),
          +
          +    # Uncomment the admin/doc line below and add 'django.contrib.admindocs' 
          +    # to INSTALLED_APPS to enable admin documentation:
          +    # (r'^admin/doc/', include('django.contrib.admindocs.urls')),
          +
          +    # Uncomment the next line to enable the admin:
          +    # (r'^admin/(.*)', admin.site.root),
          +
          +    (r'^$', 'attach.attacher.views.index'),
          +)
          diff --git a/public/javascripts/strophejs-1.1.3/examples/basic.html b/public/javascripts/strophejs-1.1.3/examples/basic.html
          new file mode 100644
          index 0000000..0a9fa89
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/basic.html
          @@ -0,0 +1,22 @@
          +<!DOCTYPE html>
          +<html>
          +  <head>
          +    <title>Strophe.js Basic Example</title>
          +    <script src='http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js'></script>
          +    <script src='../strophe.js'></script>
          +    <script src='basic.js'></script>
          +  </head>
          +  <body>
          +    <div id='login' style='text-align: center'>
          +      <form name='cred'>
          +        <label for='jid'>JID:</label>
          +        <input type='text' id='jid'>
          +        <label for='pass'>Password:</label>
          +        <input type='password' id='pass'>
          +        <input type='button' id='connect' value='connect'>
          +      </form>
          +    </div>
          +    <hr>
          +    <div id='log'></div>
          +  </body>
          +</html>
          diff --git a/public/javascripts/strophejs-1.1.3/examples/basic.js b/public/javascripts/strophejs-1.1.3/examples/basic.js
          new file mode 100644
          index 0000000..a128e3d
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/basic.js
          @@ -0,0 +1,55 @@
          +var BOSH_SERVICE = 'http://bosh.metajack.im:5280/xmpp-httpbind'
          +var connection = null;
          +
          +function log(msg) 
          +{
          +    $('#log').append('<div></div>').append(document.createTextNode(msg));
          +}
          +
          +function rawInput(data)
          +{
          +    log('RECV: ' + data);
          +}
          +
          +function rawOutput(data)
          +{
          +    log('SENT: ' + data);
          +}
          +
          +function onConnect(status)
          +{
          +    if (status == Strophe.Status.CONNECTING) {
          +	log('Strophe is connecting.');
          +    } else if (status == Strophe.Status.CONNFAIL) {
          +	log('Strophe failed to connect.');
          +	$('#connect').get(0).value = 'connect';
          +    } else if (status == Strophe.Status.DISCONNECTING) {
          +	log('Strophe is disconnecting.');
          +    } else if (status == Strophe.Status.DISCONNECTED) {
          +	log('Strophe is disconnected.');
          +	$('#connect').get(0).value = 'connect';
          +    } else if (status == Strophe.Status.CONNECTED) {
          +	log('Strophe is connected.');
          +	connection.disconnect();
          +    }
          +}
          +
          +$(document).ready(function () {
          +    connection = new Strophe.Connection(BOSH_SERVICE);
          +    connection.rawInput = rawInput;
          +    connection.rawOutput = rawOutput;
          +
          +    $('#connect').bind('click', function () {
          +	var button = $('#connect').get(0);
          +	if (button.value == 'connect') {
          +	    button.value = 'disconnect';
          +
          +	    connection.connect($('#jid').get(0).value,
          +			       $('#pass').get(0).value,
          +			       onConnect);
          +	} else {
          +	    button.value = 'connect';
          +	    connection.disconnect();
          +	}
          +    });
          +});
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/examples/crossdomain.html b/public/javascripts/strophejs-1.1.3/examples/crossdomain.html
          new file mode 100644
          index 0000000..4de9a93
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/crossdomain.html
          @@ -0,0 +1,32 @@
          +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
          +<html xmlns="http://www.w3.org/1999/xhtml">
          +<head>
          +  <title>Strophe.js Basic Cross-Domain Example</title>
          +
          +  <script type='text/javascript'
          +	  src='http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js'></script>
          +  <script type='text/javascript'
          +          src='http://flxhr.flensed.com/code/build/flXHR.js'></script>
          +
          +  <script type='text/javascript'
          +	  src='../strophe.js'></script>
          +  <script type='text/javascript'
          +          src='../plugins/strophe.flxhr.js'></script>
          +
          +  <script type='text/javascript'
          +	  src='crossdomain.js'></script>
          +</head>
          +<body>
          +  <div id='login' style='text-align: center'>
          +    <form name='cred'>
          +      <label for='jid'>JID:</label>
          +      <input type='text' id='jid' />
          +      <label for='pass'>Password:</label>
          +      <input type='password' id='pass' />
          +      <input type='button' id='connect' value='connect' />
          +    </form>
          +  </div>
          +  <hr />
          +  <div id='log'></div>
          +</body>
          +</html>
          diff --git a/public/javascripts/strophejs-1.1.3/examples/crossdomain.js b/public/javascripts/strophejs-1.1.3/examples/crossdomain.js
          new file mode 100644
          index 0000000..9501f91
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/crossdomain.js
          @@ -0,0 +1,62 @@
          +// The BOSH_SERVICE here doesn't need to be on the same domain/port, but
          +// it must have a /crossdomain.xml policy file that allows access from
          +// wherever crossdomain.html lives.
          +//
          +// Most BOSH connection managers can serve static html files, so you should
          +// be able to configure them to serve a /crossdomain.xml file to allow
          +// access.
          +var BOSH_SERVICE = 'http://bosh.metajack.im:5280/xmpp-httpbind'
          +var connection = null;
          +
          +function log(msg) 
          +{
          +    $('#log').append('<div></div>').append(document.createTextNode(msg));
          +}
          +
          +function rawInput(data)
          +{
          +    log('RECV: ' + data);
          +}
          +
          +function rawOutput(data)
          +{
          +    log('SENT: ' + data);
          +}
          +
          +function onConnect(status)
          +{
          +    if (status == Strophe.Status.CONNECTING) {
          +	log('Strophe is connecting.');
          +    } else if (status == Strophe.Status.CONNFAIL) {
          +	log('Strophe failed to connect.');
          +	$('#connect').get(0).value = 'connect';
          +    } else if (status == Strophe.Status.DISCONNECTING) {
          +	log('Strophe is disconnecting.');
          +    } else if (status == Strophe.Status.DISCONNECTED) {
          +	log('Strophe is disconnected.');
          +	$('#connect').get(0).value = 'connect';
          +    } else if (status == Strophe.Status.CONNECTED) {
          +	log('Strophe is connected.');
          +	connection.disconnect();
          +    }
          +}
          +
          +$(document).ready(function () {
          +    connection = new Strophe.Connection(BOSH_SERVICE);
          +    connection.rawInput = rawInput;
          +    connection.rawOutput = rawOutput;
          +
          +    $('#connect').bind('click', function () {
          +	var button = $('#connect').get(0);
          +	if (button.value == 'connect') {
          +	    button.value = 'disconnect';
          +
          +	    connection.connect($('#jid').get(0).value,
          +			       $('#pass').get(0).value,
          +			       onConnect);
          +	} else {
          +	    button.value = 'connect';
          +	    connection.disconnect();
          +	}
          +    });
          +});
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/examples/crossdomain.xml b/public/javascripts/strophejs-1.1.3/examples/crossdomain.xml
          new file mode 100644
          index 0000000..3dce209
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/crossdomain.xml
          @@ -0,0 +1,12 @@
          +<?xml version="1.0"?>
          +<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
          +<cross-domain-policy>
          +  <!-- 
          +       Cross domain policy file for allow everything.  If you need more
          +       information on these, please see:
          +       http://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html
          +  -->
          +  <site-control permitted-cross-domain-policies="all"/>
          +  <allow-access-from domain="*" />
          +  <allow-http-request-headers-from domain="*" headers="*" />
          +</cross-domain-policy>
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/examples/echobot.html b/public/javascripts/strophejs-1.1.3/examples/echobot.html
          new file mode 100644
          index 0000000..07f97f5
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/echobot.html
          @@ -0,0 +1,25 @@
          +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
          +<html xmlns="http://www.w3.org/1999/xhtml">
          +<head>
          +  <title>Strophe.js Echobot Example</title>
          +  <script type='text/javascript'
          +	  src='http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js'></script>
          +  <script type='text/javascript'
          +	  src='../strophe.js'></script>
          +  <script type='text/javascript'
          +	  src='echobot.js'></script>
          +</head>
          +<body>
          +  <div id='login' style='text-align: center'>
          +    <form name='cred'>
          +      <label for='jid'>JID:</label>
          +      <input type='text' id='jid' />
          +      <label for='pass'>Password:</label>
          +      <input type='password' id='pass' />
          +      <input type='button' id='connect' value='connect' />
          +    </form>
          +  </div>
          +  <hr />
          +  <div id='log'></div>
          +</body>
          +</html>
          diff --git a/public/javascripts/strophejs-1.1.3/examples/echobot.js b/public/javascripts/strophejs-1.1.3/examples/echobot.js
          new file mode 100644
          index 0000000..a1017b2
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/echobot.js
          @@ -0,0 +1,79 @@
          +var BOSH_SERVICE = '/xmpp-httpbind';
          +var connection = null;
          +
          +function log(msg) 
          +{
          +    $('#log').append('<div></div>').append(document.createTextNode(msg));
          +}
          +
          +function onConnect(status)
          +{
          +    if (status == Strophe.Status.CONNECTING) {
          +	log('Strophe is connecting.');
          +    } else if (status == Strophe.Status.CONNFAIL) {
          +	log('Strophe failed to connect.');
          +	$('#connect').get(0).value = 'connect';
          +    } else if (status == Strophe.Status.DISCONNECTING) {
          +	log('Strophe is disconnecting.');
          +    } else if (status == Strophe.Status.DISCONNECTED) {
          +	log('Strophe is disconnected.');
          +	$('#connect').get(0).value = 'connect';
          +    } else if (status == Strophe.Status.CONNECTED) {
          +	log('Strophe is connected.');
          +	log('ECHOBOT: Send a message to ' + connection.jid + 
          +	    ' to talk to me.');
          +
          +	connection.addHandler(onMessage, null, 'message', null, null,  null); 
          +	connection.send($pres().tree());
          +    }
          +}
          +
          +function onMessage(msg) {
          +    var to = msg.getAttribute('to');
          +    var from = msg.getAttribute('from');
          +    var type = msg.getAttribute('type');
          +    var elems = msg.getElementsByTagName('body');
          +
          +    if (type == "chat" && elems.length > 0) {
          +	var body = elems[0];
          +
          +	log('ECHOBOT: I got a message from ' + from + ': ' + 
          +	    Strophe.getText(body));
          +    
          +	var reply = $msg({to: from, from: to, type: 'chat'})
          +            .cnode(Strophe.copyElement(body));
          +	connection.send(reply.tree());
          +
          +	log('ECHOBOT: I sent ' + from + ': ' + Strophe.getText(body));
          +    }
          +
          +    // we must return true to keep the handler alive.  
          +    // returning false would remove it after it finishes.
          +    return true;
          +}
          +
          +$(document).ready(function () {
          +    connection = new Strophe.Connection(BOSH_SERVICE);
          +
          +    // Uncomment the following lines to spy on the wire traffic.
          +    //connection.rawInput = function (data) { log('RECV: ' + data); };
          +    //connection.rawOutput = function (data) { log('SEND: ' + data); };
          +
          +    // Uncomment the following line to see all the debug output.
          +    //Strophe.log = function (level, msg) { log('LOG: ' + msg); };
          +
          +
          +    $('#connect').bind('click', function () {
          +	var button = $('#connect').get(0);
          +	if (button.value == 'connect') {
          +	    button.value = 'disconnect';
          +
          +	    connection.connect($('#jid').get(0).value,
          +			       $('#pass').get(0).value,
          +			       onConnect);
          +	} else {
          +	    button.value = 'connect';
          +	    connection.disconnect();
          +	}
          +    });
          +});
          diff --git a/public/javascripts/strophejs-1.1.3/examples/prebind.html b/public/javascripts/strophejs-1.1.3/examples/prebind.html
          new file mode 100644
          index 0000000..b9d4a34
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/prebind.html
          @@ -0,0 +1,39 @@
          +<!DOCTYPE html>
          +<html>
          +  <!--
          +     http-pre-bind example
          +
          +     This example works with mod_http_pre_bind found here:
          +     http://github.com/thepug/Mod-Http-Pre-Bind
          +     
          +     It expects both /xmpp-httpbind to be proxied and /http-pre-bind
          +     
          +     If you want to test this out without setting it up, you can use Collecta's
          +     at http://www.collecta.com/xmpp-httpbind and 
          +     http://www.collecta.com/http-pre-bind
          +     Use a JID of 'guest.collecta.com' to test.
          +    -->
          +
          +  <head>
          +    <title>Strophe.js Pre-Bind Example</title>
          +    <script src='http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js'></script>
          +    <script src='../strophe.js'></script>
          +    <script src='prebind.js'></script>
          +  </head>
          +
          +  <body>
          +    <div id='login' style='text-align: center'>
          +      <form name='cred'>
          +        <label for='jid'>JID:</label>
          +        <input type='text' id='jid'>
          +        <label for='pass'>Password:</label>
          +        <input type='password' id='pass'>
          +        <input type='button' id='connect' value='connect'>
          +      </form>
          +    </div>
          +
          +    <hr>
          +
          +    <div id='log'></div>
          +  </body>
          +</html>
          diff --git a/public/javascripts/strophejs-1.1.3/examples/prebind.js b/public/javascripts/strophejs-1.1.3/examples/prebind.js
          new file mode 100644
          index 0000000..009ac7d
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/prebind.js
          @@ -0,0 +1,103 @@
          +// http-pre-bind example
          +// This example works with mod_http_pre_bind found here:
          +// http://github.com/thepug/Mod-Http-Pre-Bind
          +// 
          +// It expects both /xmpp-httpbind to be proxied and /http-pre-bind
          +//
          +// If you want to test this out without setting it up, you can use Collecta's
          +// at http://www.collecta.com/xmpp-httpbind and 
          +// http://www.collecta.com/http-pre-bind
          +// Use a JID of 'guest.collecta.com' to test.
          +
          +var BOSH_SERVICE = '/xmpp-httpbind';
          +var PREBIND_SERVICE = '/http-pre-bind';
          +var connection = null;
          +
          +function log(msg) 
          +{
          +    $('#log').append('<div></div>').append(document.createTextNode(msg));
          +}
          +
          +function rawInput(data)
          +{
          +    log('RECV: ' + data);
          +}
          +
          +function rawOutput(data)
          +{
          +    log('SENT: ' + data);
          +}
          +
          +function onConnect(status)
          +{
          +    if (status === Strophe.Status.CONNECTING) {
          +	log('Strophe is connecting.');
          +    } else if (status === Strophe.Status.CONNFAIL) {
          +	log('Strophe failed to connect.');
          +	$('#connect').get(0).value = 'connect';
          +    } else if (status === Strophe.Status.DISCONNECTING) {
          +	log('Strophe is disconnecting.');
          +    } else if (status === Strophe.Status.DISCONNECTED) {
          +	log('Strophe is disconnected.');
          +	$('#connect').get(0).value = 'connect';
          +    } else if (status === Strophe.Status.CONNECTED) {
          +	log('Strophe is connected.');
          +	connection.disconnect();
          +    } else if (status === Strophe.Status.ATTACHED) {
          +        log('Strophe is attached.');
          +        connection.disconnect();
          +    }
          +}
          +
          +function normal_connect() {
          +    log('Prebind failed. Connecting normally...');
          +
          +    connection = new Strophe.Connection(BOSH_SERVICE);
          +    connection.rawInput = rawInput;
          +    connection.rawOutput = rawOutput;
          +
          +    connection.connect($('#jid').val(), $('#pass').val(), onConnect);
          +}
          +
          +function attach(data) {
          +    log('Prebind succeeded. Attaching...');
          +
          +    connection = new Strophe.Connection(BOSH_SERVICE);
          +    connection.rawInput = rawInput;
          +    connection.rawOutput = rawOutput;
          +    
          +    var $body = $(data.documentElement);
          +    connection.attach($body.find('jid').text(), 
          +                      $body.attr('sid'), 
          +                      parseInt($body.attr('rid'), 10) + 1, 
          +                      onConnect);
          +}
          +
          +$(document).ready(function () {
          +    $('#connect').bind('click', function () {
          +	var button = $('#connect').get(0);
          +	if (button.value == 'connect') {
          +	    button.value = 'disconnect';
          +
          +            // attempt prebind
          +            $.ajax({
          +                type: 'POST',
          +                url: PREBIND_SERVICE,
          +                contentType: 'text/xml',
          +                processData: false,
          +                data: $build('body', {
          +                    to: Strophe.getDomainFromJid($('#jid').val()),
          +                    rid: '' + Math.floor(Math.random() * 4294967295),
          +                    wait: '60',
          +                    hold: '1'}).toString(),
          +                dataType: 'xml',
          +                error: normal_connect,
          +                success: attach});
          +	} else {
          +	    button.value = 'connect';
          +	    if (connection) {
          +                connection.disconnect();
          +            }
          +	}
          +    });
          +});
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/examples/strophe.js b/public/javascripts/strophejs-1.1.3/examples/strophe.js
          new file mode 100644
          index 0000000..f1d50ae
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/examples/strophe.js
          @@ -0,0 +1,5139 @@
          +// This code was written by Tyler Akins and has been placed in the
          +// public domain.  It would be nice if you left this header intact.
          +// Base64 code from Tyler Akins -- http://rumkin.com
          +
          +var Base64 = (function () {
          +    var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
          +
          +    var obj = {
          +        /**
          +         * Encodes a string in base64
          +         * @param {String} input The string to encode in base64.
          +         */
          +        encode: function (input) {
          +            var output = "";
          +            var chr1, chr2, chr3;
          +            var enc1, enc2, enc3, enc4;
          +            var i = 0;
          +
          +            do {
          +                chr1 = input.charCodeAt(i++);
          +                chr2 = input.charCodeAt(i++);
          +                chr3 = input.charCodeAt(i++);
          +
          +                enc1 = chr1 >> 2;
          +                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
          +                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
          +                enc4 = chr3 & 63;
          +
          +                if (isNaN(chr2)) {
          +                    enc3 = enc4 = 64;
          +                } else if (isNaN(chr3)) {
          +                    enc4 = 64;
          +                }
          +
          +                output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) +
          +                    keyStr.charAt(enc3) + keyStr.charAt(enc4);
          +            } while (i < input.length);
          +
          +            return output;
          +        },
          +
          +        /**
          +         * Decodes a base64 string.
          +         * @param {String} input The string to decode.
          +         */
          +        decode: function (input) {
          +            var output = "";
          +            var chr1, chr2, chr3;
          +            var enc1, enc2, enc3, enc4;
          +            var i = 0;
          +
          +            // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
          +            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
          +
          +            do {
          +                enc1 = keyStr.indexOf(input.charAt(i++));
          +                enc2 = keyStr.indexOf(input.charAt(i++));
          +                enc3 = keyStr.indexOf(input.charAt(i++));
          +                enc4 = keyStr.indexOf(input.charAt(i++));
          +
          +                chr1 = (enc1 << 2) | (enc2 >> 4);
          +                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
          +                chr3 = ((enc3 & 3) << 6) | enc4;
          +
          +                output = output + String.fromCharCode(chr1);
          +
          +                if (enc3 != 64) {
          +                    output = output + String.fromCharCode(chr2);
          +                }
          +                if (enc4 != 64) {
          +                    output = output + String.fromCharCode(chr3);
          +                }
          +            } while (i < input.length);
          +
          +            return output;
          +        }
          +    };
          +
          +    return obj;
          +})();
          +
          +/*
          + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
          + * in FIPS PUB 180-1
          + * Version 2.1a Copyright Paul Johnston 2000 - 2002.
          + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
          + * Distributed under the BSD License
          + * See http://pajhome.org.uk/crypt/md5 for details.
          + */
          +
          +/* Some functions and variables have been stripped for use with Strophe */
          +
          +/*
          + * These are the functions you'll usually want to call
          + * They take string arguments and return either hex or base-64 encoded strings
          + */
          +function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * 8));}
          +function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * 8));}
          +function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
          +function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}
          +
          +/*
          + * Calculate the SHA-1 of an array of big-endian words, and a bit length
          + */
          +function core_sha1(x, len)
          +{
          +  /* append padding */
          +  x[len >> 5] |= 0x80 << (24 - len % 32);
          +  x[((len + 64 >> 9) << 4) + 15] = len;
          +
          +  var w = new Array(80);
          +  var a =  1732584193;
          +  var b = -271733879;
          +  var c = -1732584194;
          +  var d =  271733878;
          +  var e = -1009589776;
          +
          +  var i, j, t, olda, oldb, oldc, oldd, olde;
          +  for (i = 0; i < x.length; i += 16)
          +  {
          +    olda = a;
          +    oldb = b;
          +    oldc = c;
          +    oldd = d;
          +    olde = e;
          +
          +    for (j = 0; j < 80; j++)
          +    {
          +      if (j < 16) { w[j] = x[i + j]; }
          +      else { w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); }
          +      t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
          +                       safe_add(safe_add(e, w[j]), sha1_kt(j)));
          +      e = d;
          +      d = c;
          +      c = rol(b, 30);
          +      b = a;
          +      a = t;
          +    }
          +
          +    a = safe_add(a, olda);
          +    b = safe_add(b, oldb);
          +    c = safe_add(c, oldc);
          +    d = safe_add(d, oldd);
          +    e = safe_add(e, olde);
          +  }
          +  return [a, b, c, d, e];
          +}
          +
          +/*
          + * Perform the appropriate triplet combination function for the current
          + * iteration
          + */
          +function sha1_ft(t, b, c, d)
          +{
          +  if (t < 20) { return (b & c) | ((~b) & d); }
          +  if (t < 40) { return b ^ c ^ d; }
          +  if (t < 60) { return (b & c) | (b & d) | (c & d); }
          +  return b ^ c ^ d;
          +}
          +
          +/*
          + * Determine the appropriate additive constant for the current iteration
          + */
          +function sha1_kt(t)
          +{
          +  return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 :
          +         (t < 60) ? -1894007588 : -899497514;
          +}
          +
          +/*
          + * Calculate the HMAC-SHA1 of a key and some data
          + */
          +function core_hmac_sha1(key, data)
          +{
          +  var bkey = str2binb(key);
          +  if (bkey.length > 16) { bkey = core_sha1(bkey, key.length * 8); }
          +
          +  var ipad = new Array(16), opad = new Array(16);
          +  for (var i = 0; i < 16; i++)
          +  {
          +    ipad[i] = bkey[i] ^ 0x36363636;
          +    opad[i] = bkey[i] ^ 0x5C5C5C5C;
          +  }
          +
          +  var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * 8);
          +  return core_sha1(opad.concat(hash), 512 + 160);
          +}
          +
          +/*
          + * Add integers, wrapping at 2^32. This uses 16-bit operations internally
          + * to work around bugs in some JS interpreters.
          + */
          +function safe_add(x, y)
          +{
          +  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
          +  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
          +  return (msw << 16) | (lsw & 0xFFFF);
          +}
          +
          +/*
          + * Bitwise rotate a 32-bit number to the left.
          + */
          +function rol(num, cnt)
          +{
          +  return (num << cnt) | (num >>> (32 - cnt));
          +}
          +
          +/*
          + * Convert an 8-bit or 16-bit string to an array of big-endian words
          + * In 8-bit function, characters >255 have their hi-byte silently ignored.
          + */
          +function str2binb(str)
          +{
          +  var bin = [];
          +  var mask = 255;
          +  for (var i = 0; i < str.length * 8; i += 8)
          +  {
          +    bin[i>>5] |= (str.charCodeAt(i / 8) & mask) << (24 - i%32);
          +  }
          +  return bin;
          +}
          +
          +/*
          + * Convert an array of big-endian words to a string
          + */
          +function binb2str(bin)
          +{
          +  var str = "";
          +  var mask = 255;
          +  for (var i = 0; i < bin.length * 32; i += 8)
          +  {
          +    str += String.fromCharCode((bin[i>>5] >>> (24 - i%32)) & mask);
          +  }
          +  return str;
          +}
          +
          +/*
          + * Convert an array of big-endian words to a base-64 string
          + */
          +function binb2b64(binarray)
          +{
          +  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
          +  var str = "";
          +  var triplet, j;
          +  for (var i = 0; i < binarray.length * 4; i += 3)
          +  {
          +    triplet = (((binarray[i   >> 2] >> 8 * (3 -  i   %4)) & 0xFF) << 16) |
          +              (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) |
          +               ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
          +    for (j = 0; j < 4; j++)
          +    {
          +      if (i * 8 + j * 6 > binarray.length * 32) { str += "="; }
          +      else { str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); }
          +    }
          +  }
          +  return str;
          +}
          +
          +/*
          + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
          + * Digest Algorithm, as defined in RFC 1321.
          + * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
          + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
          + * Distributed under the BSD License
          + * See http://pajhome.org.uk/crypt/md5 for more info.
          + */
          +
          +/*
          + * Everything that isn't used by Strophe has been stripped here!
          + */
          +
          +var MD5 = (function () {
          +    /*
          +     * Add integers, wrapping at 2^32. This uses 16-bit operations internally
          +     * to work around bugs in some JS interpreters.
          +     */
          +    var safe_add = function (x, y) {
          +        var lsw = (x & 0xFFFF) + (y & 0xFFFF);
          +        var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
          +        return (msw << 16) | (lsw & 0xFFFF);
          +    };
          +
          +    /*
          +     * Bitwise rotate a 32-bit number to the left.
          +     */
          +    var bit_rol = function (num, cnt) {
          +        return (num << cnt) | (num >>> (32 - cnt));
          +    };
          +
          +    /*
          +     * Convert a string to an array of little-endian words
          +     */
          +    var str2binl = function (str) {
          +        var bin = [];
          +        for(var i = 0; i < str.length * 8; i += 8)
          +        {
          +            bin[i>>5] |= (str.charCodeAt(i / 8) & 255) << (i%32);
          +        }
          +        return bin;
          +    };
          +
          +    /*
          +     * Convert an array of little-endian words to a string
          +     */
          +    var binl2str = function (bin) {
          +        var str = "";
          +        for(var i = 0; i < bin.length * 32; i += 8)
          +        {
          +            str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & 255);
          +        }
          +        return str;
          +    };
          +
          +    /*
          +     * Convert an array of little-endian words to a hex string.
          +     */
          +    var binl2hex = function (binarray) {
          +        var hex_tab = "0123456789abcdef";
          +        var str = "";
          +        for(var i = 0; i < binarray.length * 4; i++)
          +        {
          +            str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
          +                hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
          +        }
          +        return str;
          +    };
          +
          +    /*
          +     * These functions implement the four basic operations the algorithm uses.
          +     */
          +    var md5_cmn = function (q, a, b, x, s, t) {
          +        return safe_add(bit_rol(safe_add(safe_add(a, q),safe_add(x, t)), s),b);
          +    };
          +
          +    var md5_ff = function (a, b, c, d, x, s, t) {
          +        return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
          +    };
          +
          +    var md5_gg = function (a, b, c, d, x, s, t) {
          +        return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
          +    };
          +
          +    var md5_hh = function (a, b, c, d, x, s, t) {
          +        return md5_cmn(b ^ c ^ d, a, b, x, s, t);
          +    };
          +
          +    var md5_ii = function (a, b, c, d, x, s, t) {
          +        return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
          +    };
          +
          +    /*
          +     * Calculate the MD5 of an array of little-endian words, and a bit length
          +     */
          +    var core_md5 = function (x, len) {
          +        /* append padding */
          +        x[len >> 5] |= 0x80 << ((len) % 32);
          +        x[(((len + 64) >>> 9) << 4) + 14] = len;
          +
          +        var a =  1732584193;
          +        var b = -271733879;
          +        var c = -1732584194;
          +        var d =  271733878;
          +
          +        var olda, oldb, oldc, oldd;
          +        for (var i = 0; i < x.length; i += 16)
          +        {
          +            olda = a;
          +            oldb = b;
          +            oldc = c;
          +            oldd = d;
          +
          +            a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
          +            d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
          +            c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
          +            b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
          +            a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
          +            d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
          +            c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
          +            b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
          +            a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
          +            d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
          +            c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
          +            b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
          +            a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
          +            d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
          +            c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
          +            b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);
          +
          +            a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
          +            d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
          +            c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
          +            b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
          +            a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
          +            d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
          +            c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
          +            b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
          +            a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
          +            d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
          +            c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
          +            b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
          +            a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
          +            d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
          +            c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
          +            b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
          +
          +            a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
          +            d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
          +            c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
          +            b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
          +            a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
          +            d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
          +            c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
          +            b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
          +            a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
          +            d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
          +            c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
          +            b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
          +            a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
          +            d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
          +            c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
          +            b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
          +
          +            a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
          +            d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
          +            c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
          +            b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
          +            a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
          +            d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
          +            c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
          +            b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
          +            a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
          +            d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
          +            c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
          +            b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
          +            a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
          +            d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
          +            c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
          +            b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
          +
          +            a = safe_add(a, olda);
          +            b = safe_add(b, oldb);
          +            c = safe_add(c, oldc);
          +            d = safe_add(d, oldd);
          +        }
          +        return [a, b, c, d];
          +    };
          +
          +
          +    var obj = {
          +        /*
          +         * These are the functions you'll usually want to call.
          +         * They take string arguments and return either hex or base-64 encoded
          +         * strings.
          +         */
          +        hexdigest: function (s) {
          +            return binl2hex(core_md5(str2binl(s), s.length * 8));
          +        },
          +
          +        hash: function (s) {
          +            return binl2str(core_md5(str2binl(s), s.length * 8));
          +        }
          +    };
          +
          +    return obj;
          +})();
          +
          +/*
          +    This program is distributed under the terms of the MIT license.
          +    Please see the LICENSE file for details.
          +
          +    Copyright 2006-2008, OGG, LLC
          +*/
          +
          +/* jshint undef: true, unused: true:, noarg: true, latedef: true */
          +/*global document, window, setTimeout, clearTimeout, console,
          +    ActiveXObject, Base64, MD5, DOMParser */
          +// from sha1.js
          +/*global core_hmac_sha1, binb2str, str_hmac_sha1, str_sha1, b64_hmac_sha1*/
          +
          +/** File: strophe.js
          + *  A JavaScript library for XMPP BOSH/XMPP over Websocket.
          + *
          + *  This is the JavaScript version of the Strophe library.  Since JavaScript
          + *  had no facilities for persistent TCP connections, this library uses
          + *  Bidirectional-streams Over Synchronous HTTP (BOSH) to emulate
          + *  a persistent, stateful, two-way connection to an XMPP server.  More
          + *  information on BOSH can be found in XEP 124.
          + *
          + *  This version of Strophe also works with WebSockets.
          + *  For more information on XMPP-over WebSocket see this RFC draft:
          + *  http://tools.ietf.org/html/draft-ietf-xmpp-websocket-00
          + */
          +
          +/** PrivateFunction: Function.prototype.bind
          + *  Bind a function to an instance.
          + *
          + *  This Function object extension method creates a bound method similar
          + *  to those in Python.  This means that the 'this' object will point
          + *  to the instance you want.  See
          + *  <a href='https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind'>MDC's bind() documentation</a> and
          + *  <a href='http://benjamin.smedbergs.us/blog/2007-01-03/bound-functions-and-function-imports-in-javascript/'>Bound Functions and Function Imports in JavaScript</a>
          + *  for a complete explanation.
          + *
          + *  This extension already exists in some browsers (namely, Firefox 3), but
          + *  we provide it to support those that don't.
          + *
          + *  Parameters:
          + *    (Object) obj - The object that will become 'this' in the bound function.
          + *    (Object) argN - An option argument that will be prepended to the
          + *      arguments given for the function call
          + *
          + *  Returns:
          + *    The bound function.
          + */
          +if (!Function.prototype.bind) {
          +    Function.prototype.bind = function (obj /*, arg1, arg2, ... */)
          +    {
          +        var func = this;
          +        var _slice = Array.prototype.slice;
          +        var _concat = Array.prototype.concat;
          +        var _args = _slice.call(arguments, 1);
          +
          +        return function () {
          +            return func.apply(obj ? obj : this,
          +                              _concat.call(_args,
          +                                           _slice.call(arguments, 0)));
          +        };
          +    };
          +}
          +
          +/** PrivateFunction: Array.prototype.indexOf
          + *  Return the index of an object in an array.
          + *
          + *  This function is not supplied by some JavaScript implementations, so
          + *  we provide it if it is missing.  This code is from:
          + *  http://developer.mozilla.org/En/Core_JavaScript_1.5_Reference:Objects:Array:indexOf
          + *
          + *  Parameters:
          + *    (Object) elt - The object to look for.
          + *    (Integer) from - The index from which to start looking. (optional).
          + *
          + *  Returns:
          + *    The index of elt in the array or -1 if not found.
          + */
          +if (!Array.prototype.indexOf)
          +{
          +    Array.prototype.indexOf = function(elt /*, from*/)
          +    {
          +        var len = this.length;
          +
          +        var from = Number(arguments[1]) || 0;
          +        from = (from < 0) ? Math.ceil(from) : Math.floor(from);
          +        if (from < 0) {
          +            from += len;
          +        }
          +
          +        for (; from < len; from++) {
          +            if (from in this && this[from] === elt) {
          +                return from;
          +            }
          +        }
          +
          +        return -1;
          +    };
          +}
          +
          +/* All of the Strophe globals are defined in this special function below so
          + * that references to the globals become closures.  This will ensure that
          + * on page reload, these references will still be available to callbacks
          + * that are still executing.
          + */
          +
          +(function (callback) {
          +var Strophe;
          +
          +/** Function: $build
          + *  Create a Strophe.Builder.
          + *  This is an alias for 'new Strophe.Builder(name, attrs)'.
          + *
          + *  Parameters:
          + *    (String) name - The root element name.
          + *    (Object) attrs - The attributes for the root element in object notation.
          + *
          + *  Returns:
          + *    A new Strophe.Builder object.
          + */
          +function $build(name, attrs) { return new Strophe.Builder(name, attrs); }
          +/** Function: $msg
          + *  Create a Strophe.Builder with a <message/> element as the root.
          + *
          + *  Parmaeters:
          + *    (Object) attrs - The <message/> element attributes in object notation.
          + *
          + *  Returns:
          + *    A new Strophe.Builder object.
          + */
          +function $msg(attrs) { return new Strophe.Builder("message", attrs); }
          +/** Function: $iq
          + *  Create a Strophe.Builder with an <iq/> element as the root.
          + *
          + *  Parameters:
          + *    (Object) attrs - The <iq/> element attributes in object notation.
          + *
          + *  Returns:
          + *    A new Strophe.Builder object.
          + */
          +function $iq(attrs) { return new Strophe.Builder("iq", attrs); }
          +/** Function: $pres
          + *  Create a Strophe.Builder with a <presence/> element as the root.
          + *
          + *  Parameters:
          + *    (Object) attrs - The <presence/> element attributes in object notation.
          + *
          + *  Returns:
          + *    A new Strophe.Builder object.
          + */
          +function $pres(attrs) { return new Strophe.Builder("presence", attrs); }
          +
          +/** Class: Strophe
          + *  An object container for all Strophe library functions.
          + *
          + *  This class is just a container for all the objects and constants
          + *  used in the library.  It is not meant to be instantiated, but to
          + *  provide a namespace for library objects, constants, and functions.
          + */
          +Strophe = {
          +    /** Constant: VERSION
          +     *  The version of the Strophe library. Unreleased builds will have
          +     *  a version of head-HASH where HASH is a partial revision.
          +     */
          +    VERSION: "1.1.3",
          +
          +    /** Constants: XMPP Namespace Constants
          +     *  Common namespace constants from the XMPP RFCs and XEPs.
          +     *
          +     *  NS.HTTPBIND - HTTP BIND namespace from XEP 124.
          +     *  NS.BOSH - BOSH namespace from XEP 206.
          +     *  NS.CLIENT - Main XMPP client namespace.
          +     *  NS.AUTH - Legacy authentication namespace.
          +     *  NS.ROSTER - Roster operations namespace.
          +     *  NS.PROFILE - Profile namespace.
          +     *  NS.DISCO_INFO - Service discovery info namespace from XEP 30.
          +     *  NS.DISCO_ITEMS - Service discovery items namespace from XEP 30.
          +     *  NS.MUC - Multi-User Chat namespace from XEP 45.
          +     *  NS.SASL - XMPP SASL namespace from RFC 3920.
          +     *  NS.STREAM - XMPP Streams namespace from RFC 3920.
          +     *  NS.BIND - XMPP Binding namespace from RFC 3920.
          +     *  NS.SESSION - XMPP Session namespace from RFC 3920.
          +     *  NS.XHTML_IM - XHTML-IM namespace from XEP 71.
          +     *  NS.XHTML - XHTML body namespace from XEP 71.
          +     */
          +    NS: {
          +        HTTPBIND: "http://jabber.org/protocol/httpbind",
          +        BOSH: "urn:xmpp:xbosh",
          +        CLIENT: "jabber:client",
          +        AUTH: "jabber:iq:auth",
          +        ROSTER: "jabber:iq:roster",
          +        PROFILE: "jabber:iq:profile",
          +        DISCO_INFO: "http://jabber.org/protocol/disco#info",
          +        DISCO_ITEMS: "http://jabber.org/protocol/disco#items",
          +        MUC: "http://jabber.org/protocol/muc",
          +        SASL: "urn:ietf:params:xml:ns:xmpp-sasl",
          +        STREAM: "http://etherx.jabber.org/streams",
          +        BIND: "urn:ietf:params:xml:ns:xmpp-bind",
          +        SESSION: "urn:ietf:params:xml:ns:xmpp-session",
          +        VERSION: "jabber:iq:version",
          +        STANZAS: "urn:ietf:params:xml:ns:xmpp-stanzas",
          +        XHTML_IM: "http://jabber.org/protocol/xhtml-im",
          +        XHTML: "http://www.w3.org/1999/xhtml"
          +    },
          +
          +
          +    /** Constants: XHTML_IM Namespace
          +     *  contains allowed tags, tag attributes, and css properties.
          +     *  Used in the createHtml function to filter incoming html into the allowed XHTML-IM subset.
          +     *  See http://xmpp.org/extensions/xep-0071.html#profile-summary for the list of recommended
          +     *  allowed tags and their attributes.
          +     */
          +    XHTML: {
          +                tags: ['a','blockquote','br','cite','em','img','li','ol','p','span','strong','ul','body'],
          +                attributes: {
          +                        'a':          ['href'],
          +                        'blockquote': ['style'],
          +                        'br':         [],
          +                        'cite':       ['style'],
          +                        'em':         [],
          +                        'img':        ['src', 'alt', 'style', 'height', 'width'],
          +                        'li':         ['style'],
          +                        'ol':         ['style'],
          +                        'p':          ['style'],
          +                        'span':       ['style'],
          +                        'strong':     [],
          +                        'ul':         ['style'],
          +                        'body':       []
          +                },
          +                css: ['background-color','color','font-family','font-size','font-style','font-weight','margin-left','margin-right','text-align','text-decoration'],
          +                validTag: function(tag)
          +                {
          +                        for(var i = 0; i < Strophe.XHTML.tags.length; i++) {
          +                                if(tag == Strophe.XHTML.tags[i]) {
          +                                        return true;
          +                                }
          +                        }
          +                        return false;
          +                },
          +                validAttribute: function(tag, attribute)
          +                {
          +                        if(typeof Strophe.XHTML.attributes[tag] !== 'undefined' && Strophe.XHTML.attributes[tag].length > 0) {
          +                                for(var i = 0; i < Strophe.XHTML.attributes[tag].length; i++) {
          +                                        if(attribute == Strophe.XHTML.attributes[tag][i]) {
          +                                                return true;
          +                                        }
          +                                }
          +                        }
          +                        return false;
          +                },
          +                validCSS: function(style)
          +                {
          +                        for(var i = 0; i < Strophe.XHTML.css.length; i++) {
          +                                if(style == Strophe.XHTML.css[i]) {
          +                                        return true;
          +                                }
          +                        }
          +                        return false;
          +                }
          +    },
          +
          +    /** Constants: Connection Status Constants
          +     *  Connection status constants for use by the connection handler
          +     *  callback.
          +     *
          +     *  Status.ERROR - An error has occurred
          +     *  Status.CONNECTING - The connection is currently being made
          +     *  Status.CONNFAIL - The connection attempt failed
          +     *  Status.AUTHENTICATING - The connection is authenticating
          +     *  Status.AUTHFAIL - The authentication attempt failed
          +     *  Status.CONNECTED - The connection has succeeded
          +     *  Status.DISCONNECTED - The connection has been terminated
          +     *  Status.DISCONNECTING - The connection is currently being terminated
          +     *  Status.ATTACHED - The connection has been attached
          +     */
          +    Status: {
          +        ERROR: 0,
          +        CONNECTING: 1,
          +        CONNFAIL: 2,
          +        AUTHENTICATING: 3,
          +        AUTHFAIL: 4,
          +        CONNECTED: 5,
          +        DISCONNECTED: 6,
          +        DISCONNECTING: 7,
          +        ATTACHED: 8
          +    },
          +
          +    /** Constants: Log Level Constants
          +     *  Logging level indicators.
          +     *
          +     *  LogLevel.DEBUG - Debug output
          +     *  LogLevel.INFO - Informational output
          +     *  LogLevel.WARN - Warnings
          +     *  LogLevel.ERROR - Errors
          +     *  LogLevel.FATAL - Fatal errors
          +     */
          +    LogLevel: {
          +        DEBUG: 0,
          +        INFO: 1,
          +        WARN: 2,
          +        ERROR: 3,
          +        FATAL: 4
          +    },
          +
          +    /** PrivateConstants: DOM Element Type Constants
          +     *  DOM element types.
          +     *
          +     *  ElementType.NORMAL - Normal element.
          +     *  ElementType.TEXT - Text data element.
          +     *  ElementType.FRAGMENT - XHTML fragment element.
          +     */
          +    ElementType: {
          +        NORMAL: 1,
          +        TEXT: 3,
          +        CDATA: 4,
          +        FRAGMENT: 11
          +    },
          +
          +    /** PrivateConstants: Timeout Values
          +     *  Timeout values for error states.  These values are in seconds.
          +     *  These should not be changed unless you know exactly what you are
          +     *  doing.
          +     *
          +     *  TIMEOUT - Timeout multiplier. A waiting request will be considered
          +     *      failed after Math.floor(TIMEOUT * wait) seconds have elapsed.
          +     *      This defaults to 1.1, and with default wait, 66 seconds.
          +     *  SECONDARY_TIMEOUT - Secondary timeout multiplier. In cases where
          +     *      Strophe can detect early failure, it will consider the request
          +     *      failed if it doesn't return after
          +     *      Math.floor(SECONDARY_TIMEOUT * wait) seconds have elapsed.
          +     *      This defaults to 0.1, and with default wait, 6 seconds.
          +     */
          +    TIMEOUT: 1.1,
          +    SECONDARY_TIMEOUT: 0.1,
          +
          +    /** Function: addNamespace
          +     *  This function is used to extend the current namespaces in
          +     *  Strophe.NS.  It takes a key and a value with the key being the
          +     *  name of the new namespace, with its actual value.
          +     *  For example:
          +     *  Strophe.addNamespace('PUBSUB', "http://jabber.org/protocol/pubsub");
          +     *
          +     *  Parameters:
          +     *    (String) name - The name under which the namespace will be
          +     *      referenced under Strophe.NS
          +     *    (String) value - The actual namespace.
          +     */
          +    addNamespace: function (name, value)
          +    {
          +      Strophe.NS[name] = value;
          +    },
          +
          +    /** Function: forEachChild
          +     *  Map a function over some or all child elements of a given element.
          +     *
          +     *  This is a small convenience function for mapping a function over
          +     *  some or all of the children of an element.  If elemName is null, all
          +     *  children will be passed to the function, otherwise only children
          +     *  whose tag names match elemName will be passed.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The element to operate on.
          +     *    (String) elemName - The child element tag name filter.
          +     *    (Function) func - The function to apply to each child.  This
          +     *      function should take a single argument, a DOM element.
          +     */
          +    forEachChild: function (elem, elemName, func)
          +    {
          +        var i, childNode;
          +
          +        for (i = 0; i < elem.childNodes.length; i++) {
          +            childNode = elem.childNodes[i];
          +            if (childNode.nodeType == Strophe.ElementType.NORMAL &&
          +                (!elemName || this.isTagEqual(childNode, elemName))) {
          +                func(childNode);
          +            }
          +        }
          +    },
          +
          +    /** Function: isTagEqual
          +     *  Compare an element's tag name with a string.
          +     *
          +     *  This function is case insensitive.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) el - A DOM element.
          +     *    (String) name - The element name.
          +     *
          +     *  Returns:
          +     *    true if the element's tag name matches _el_, and false
          +     *    otherwise.
          +     */
          +    isTagEqual: function (el, name)
          +    {
          +        return el.tagName.toLowerCase() == name.toLowerCase();
          +    },
          +
          +    /** PrivateVariable: _xmlGenerator
          +     *  _Private_ variable that caches a DOM document to
          +     *  generate elements.
          +     */
          +    _xmlGenerator: null,
          +
          +    /** PrivateFunction: _makeGenerator
          +     *  _Private_ function that creates a dummy XML DOM document to serve as
          +     *  an element and text node generator.
          +     */
          +    _makeGenerator: function () {
          +        var doc;
          +
          +        // IE9 does implement createDocument(); however, using it will cause the browser to leak memory on page unload.
          +        // Here, we test for presence of createDocument() plus IE's proprietary documentMode attribute, which would be
          +                // less than 10 in the case of IE9 and below.
          +        if (document.implementation.createDocument === undefined ||
          +                        document.implementation.createDocument && document.documentMode && document.documentMode < 10) {
          +            doc = this._getIEXmlDom();
          +            doc.appendChild(doc.createElement('strophe'));
          +        } else {
          +            doc = document.implementation
          +                .createDocument('jabber:client', 'strophe', null);
          +        }
          +
          +        return doc;
          +    },
          +
          +    /** Function: xmlGenerator
          +     *  Get the DOM document to generate elements.
          +     *
          +     *  Returns:
          +     *    The currently used DOM document.
          +     */
          +    xmlGenerator: function () {
          +        if (!Strophe._xmlGenerator) {
          +            Strophe._xmlGenerator = Strophe._makeGenerator();
          +        }
          +        return Strophe._xmlGenerator;
          +    },
          +
          +    /** PrivateFunction: _getIEXmlDom
          +     *  Gets IE xml doc object
          +     *
          +     *  Returns:
          +     *    A Microsoft XML DOM Object
          +     *  See Also:
          +     *    http://msdn.microsoft.com/en-us/library/ms757837%28VS.85%29.aspx
          +     */
          +    _getIEXmlDom : function() {
          +        var doc = null;
          +        var docStrings = [
          +            "Msxml2.DOMDocument.6.0",
          +            "Msxml2.DOMDocument.5.0",
          +            "Msxml2.DOMDocument.4.0",
          +            "MSXML2.DOMDocument.3.0",
          +            "MSXML2.DOMDocument",
          +            "MSXML.DOMDocument",
          +            "Microsoft.XMLDOM"
          +        ];
          +
          +        for (var d = 0; d < docStrings.length; d++) {
          +            if (doc === null) {
          +                try {
          +                    doc = new ActiveXObject(docStrings[d]);
          +                } catch (e) {
          +                    doc = null;
          +                }
          +            } else {
          +                break;
          +            }
          +        }
          +
          +        return doc;
          +    },
          +
          +    /** Function: xmlElement
          +     *  Create an XML DOM element.
          +     *
          +     *  This function creates an XML DOM element correctly across all
          +     *  implementations. Note that these are not HTML DOM elements, which
          +     *  aren't appropriate for XMPP stanzas.
          +     *
          +     *  Parameters:
          +     *    (String) name - The name for the element.
          +     *    (Array|Object) attrs - An optional array or object containing
          +     *      key/value pairs to use as element attributes. The object should
          +     *      be in the format {'key': 'value'} or {key: 'value'}. The array
          +     *      should have the format [['key1', 'value1'], ['key2', 'value2']].
          +     *    (String) text - The text child data for the element.
          +     *
          +     *  Returns:
          +     *    A new XML DOM element.
          +     */
          +    xmlElement: function (name)
          +    {
          +        if (!name) { return null; }
          +
          +        var node = Strophe.xmlGenerator().createElement(name);
          +
          +        // FIXME: this should throw errors if args are the wrong type or
          +        // there are more than two optional args
          +        var a, i, k;
          +        for (a = 1; a < arguments.length; a++) {
          +            if (!arguments[a]) { continue; }
          +            if (typeof(arguments[a]) == "string" ||
          +                typeof(arguments[a]) == "number") {
          +                node.appendChild(Strophe.xmlTextNode(arguments[a]));
          +            } else if (typeof(arguments[a]) == "object" &&
          +                       typeof(arguments[a].sort) == "function") {
          +                for (i = 0; i < arguments[a].length; i++) {
          +                    if (typeof(arguments[a][i]) == "object" &&
          +                        typeof(arguments[a][i].sort) == "function") {
          +                        node.setAttribute(arguments[a][i][0],
          +                                          arguments[a][i][1]);
          +                    }
          +                }
          +            } else if (typeof(arguments[a]) == "object") {
          +                for (k in arguments[a]) {
          +                    if (arguments[a].hasOwnProperty(k)) {
          +                        node.setAttribute(k, arguments[a][k]);
          +                    }
          +                }
          +            }
          +        }
          +
          +        return node;
          +    },
          +
          +    /*  Function: xmlescape
          +     *  Excapes invalid xml characters.
          +     *
          +     *  Parameters:
          +     *     (String) text - text to escape.
          +     *
          +     *  Returns:
          +     *      Escaped text.
          +     */
          +    xmlescape: function(text)
          +    {
          +        text = text.replace(/\&/g, "&amp;");
          +        text = text.replace(/</g,  "&lt;");
          +        text = text.replace(/>/g,  "&gt;");
          +        text = text.replace(/'/g,  "&apos;");
          +        text = text.replace(/"/g,  "&quot;");
          +        return text;
          +    },
          +
          +    /** Function: xmlTextNode
          +     *  Creates an XML DOM text node.
          +     *
          +     *  Provides a cross implementation version of document.createTextNode.
          +     *
          +     *  Parameters:
          +     *    (String) text - The content of the text node.
          +     *
          +     *  Returns:
          +     *    A new XML DOM text node.
          +     */
          +    xmlTextNode: function (text)
          +    {
          +        return Strophe.xmlGenerator().createTextNode(text);
          +    },
          +
          +    /** Function: xmlHtmlNode
          +     *  Creates an XML DOM html node.
          +     *
          +     *  Parameters:
          +     *    (String) html - The content of the html node.
          +     *
          +     *  Returns:
          +     *    A new XML DOM text node.
          +     */
          +    xmlHtmlNode: function (html)
          +    {
          +        var node;
          +        //ensure text is escaped
          +        if (window.DOMParser) {
          +            var parser = new DOMParser();
          +            node = parser.parseFromString(html, "text/xml");
          +        } else {
          +            node = new ActiveXObject("Microsoft.XMLDOM");
          +            node.async="false";
          +            node.loadXML(html);
          +        }
          +        return node;
          +    },
          +
          +    /** Function: getText
          +     *  Get the concatenation of all text children of an element.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - A DOM element.
          +     *
          +     *  Returns:
          +     *    A String with the concatenated text of all text element children.
          +     */
          +    getText: function (elem)
          +    {
          +        if (!elem) { return null; }
          +
          +        var str = "";
          +        if (elem.childNodes.length === 0 && elem.nodeType ==
          +            Strophe.ElementType.TEXT) {
          +            str += elem.nodeValue;
          +        }
          +
          +        for (var i = 0; i < elem.childNodes.length; i++) {
          +            if (elem.childNodes[i].nodeType == Strophe.ElementType.TEXT) {
          +                str += elem.childNodes[i].nodeValue;
          +            }
          +        }
          +
          +        return Strophe.xmlescape(str);
          +    },
          +
          +    /** Function: copyElement
          +     *  Copy an XML DOM element.
          +     *
          +     *  This function copies a DOM element and all its descendants and returns
          +     *  the new copy.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - A DOM element.
          +     *
          +     *  Returns:
          +     *    A new, copied DOM element tree.
          +     */
          +    copyElement: function (elem)
          +    {
          +        var i, el;
          +        if (elem.nodeType == Strophe.ElementType.NORMAL) {
          +            el = Strophe.xmlElement(elem.tagName);
          +
          +            for (i = 0; i < elem.attributes.length; i++) {
          +                el.setAttribute(elem.attributes[i].nodeName.toLowerCase(),
          +                                elem.attributes[i].value);
          +            }
          +
          +            for (i = 0; i < elem.childNodes.length; i++) {
          +                el.appendChild(Strophe.copyElement(elem.childNodes[i]));
          +            }
          +        } else if (elem.nodeType == Strophe.ElementType.TEXT) {
          +            el = Strophe.xmlGenerator().createTextNode(elem.nodeValue);
          +        }
          +
          +        return el;
          +    },
          +
          +
          +    /** Function: createHtml
          +     *  Copy an HTML DOM element into an XML DOM.
          +     *
          +     *  This function copies a DOM element and all its descendants and returns
          +     *  the new copy.
          +     *
          +     *  Parameters:
          +     *    (HTMLElement) elem - A DOM element.
          +     *
          +     *  Returns:
          +     *    A new, copied DOM element tree.
          +     */
          +    createHtml: function (elem)
          +    {
          +        var i, el, j, tag, attribute, value, css, cssAttrs, attr, cssName, cssValue;
          +        if (elem.nodeType == Strophe.ElementType.NORMAL) {
          +            tag = elem.nodeName.toLowerCase();
          +            if(Strophe.XHTML.validTag(tag)) {
          +                try {
          +                    el = Strophe.xmlElement(tag);
          +                    for(i = 0; i < Strophe.XHTML.attributes[tag].length; i++) {
          +                        attribute = Strophe.XHTML.attributes[tag][i];
          +                        value = elem.getAttribute(attribute);
          +                        if(typeof value == 'undefined' || value === null || value === '' || value === false || value === 0) {
          +                            continue;
          +                        }
          +                        if(attribute == 'style' && typeof value == 'object') {
          +                            if(typeof value.cssText != 'undefined') {
          +                                value = value.cssText; // we're dealing with IE, need to get CSS out
          +                            }
          +                        }
          +                        // filter out invalid css styles
          +                        if(attribute == 'style') {
          +                            css = [];
          +                            cssAttrs = value.split(';');
          +                            for(j = 0; j < cssAttrs.length; j++) {
          +                                attr = cssAttrs[j].split(':');
          +                                cssName = attr[0].replace(/^\s*/, "").replace(/\s*$/, "").toLowerCase();
          +                                if(Strophe.XHTML.validCSS(cssName)) {
          +                                    cssValue = attr[1].replace(/^\s*/, "").replace(/\s*$/, "");
          +                                    css.push(cssName + ': ' + cssValue);
          +                                }
          +                            }
          +                            if(css.length > 0) {
          +                                value = css.join('; ');
          +                                el.setAttribute(attribute, value);
          +                            }
          +                        } else {
          +                            el.setAttribute(attribute, value);
          +                        }
          +                    }
          +
          +                    for (i = 0; i < elem.childNodes.length; i++) {
          +                        el.appendChild(Strophe.createHtml(elem.childNodes[i]));
          +                    }
          +                } catch(e) { // invalid elements
          +                  el = Strophe.xmlTextNode('');
          +                }
          +            } else {
          +                el = Strophe.xmlGenerator().createDocumentFragment();
          +                for (i = 0; i < elem.childNodes.length; i++) {
          +                    el.appendChild(Strophe.createHtml(elem.childNodes[i]));
          +                }
          +            }
          +        } else if (elem.nodeType == Strophe.ElementType.FRAGMENT) {
          +            el = Strophe.xmlGenerator().createDocumentFragment();
          +            for (i = 0; i < elem.childNodes.length; i++) {
          +                el.appendChild(Strophe.createHtml(elem.childNodes[i]));
          +            }
          +        } else if (elem.nodeType == Strophe.ElementType.TEXT) {
          +            el = Strophe.xmlTextNode(elem.nodeValue);
          +        }
          +
          +        return el;
          +    },
          +
          +    /** Function: escapeNode
          +     *  Escape the node part (also called local part) of a JID.
          +     *
          +     *  Parameters:
          +     *    (String) node - A node (or local part).
          +     *
          +     *  Returns:
          +     *    An escaped node (or local part).
          +     */
          +    escapeNode: function (node)
          +    {
          +        return node.replace(/^\s+|\s+$/g, '')
          +            .replace(/\\/g,  "\\5c")
          +            .replace(/ /g,   "\\20")
          +            .replace(/\"/g,  "\\22")
          +            .replace(/\&/g,  "\\26")
          +            .replace(/\'/g,  "\\27")
          +            .replace(/\//g,  "\\2f")
          +            .replace(/:/g,   "\\3a")
          +            .replace(/</g,   "\\3c")
          +            .replace(/>/g,   "\\3e")
          +            .replace(/@/g,   "\\40");
          +    },
          +
          +    /** Function: unescapeNode
          +     *  Unescape a node part (also called local part) of a JID.
          +     *
          +     *  Parameters:
          +     *    (String) node - A node (or local part).
          +     *
          +     *  Returns:
          +     *    An unescaped node (or local part).
          +     */
          +    unescapeNode: function (node)
          +    {
          +        return node.replace(/\\20/g, " ")
          +            .replace(/\\22/g, '"')
          +            .replace(/\\26/g, "&")
          +            .replace(/\\27/g, "'")
          +            .replace(/\\2f/g, "/")
          +            .replace(/\\3a/g, ":")
          +            .replace(/\\3c/g, "<")
          +            .replace(/\\3e/g, ">")
          +            .replace(/\\40/g, "@")
          +            .replace(/\\5c/g, "\\");
          +    },
          +
          +    /** Function: getNodeFromJid
          +     *  Get the node portion of a JID String.
          +     *
          +     *  Parameters:
          +     *    (String) jid - A JID.
          +     *
          +     *  Returns:
          +     *    A String containing the node.
          +     */
          +    getNodeFromJid: function (jid)
          +    {
          +        if (jid.indexOf("@") < 0) { return null; }
          +        return jid.split("@")[0];
          +    },
          +
          +    /** Function: getDomainFromJid
          +     *  Get the domain portion of a JID String.
          +     *
          +     *  Parameters:
          +     *    (String) jid - A JID.
          +     *
          +     *  Returns:
          +     *    A String containing the domain.
          +     */
          +    getDomainFromJid: function (jid)
          +    {
          +        var bare = Strophe.getBareJidFromJid(jid);
          +        if (bare.indexOf("@") < 0) {
          +            return bare;
          +        } else {
          +            var parts = bare.split("@");
          +            parts.splice(0, 1);
          +            return parts.join('@');
          +        }
          +    },
          +
          +    /** Function: getResourceFromJid
          +     *  Get the resource portion of a JID String.
          +     *
          +     *  Parameters:
          +     *    (String) jid - A JID.
          +     *
          +     *  Returns:
          +     *    A String containing the resource.
          +     */
          +    getResourceFromJid: function (jid)
          +    {
          +        var s = jid.split("/");
          +        if (s.length < 2) { return null; }
          +        s.splice(0, 1);
          +        return s.join('/');
          +    },
          +
          +    /** Function: getBareJidFromJid
          +     *  Get the bare JID from a JID String.
          +     *
          +     *  Parameters:
          +     *    (String) jid - A JID.
          +     *
          +     *  Returns:
          +     *    A String containing the bare JID.
          +     */
          +    getBareJidFromJid: function (jid)
          +    {
          +        return jid ? jid.split("/")[0] : null;
          +    },
          +
          +    /** Function: log
          +     *  User overrideable logging function.
          +     *
          +     *  This function is called whenever the Strophe library calls any
          +     *  of the logging functions.  The default implementation of this
          +     *  function does nothing.  If client code wishes to handle the logging
          +     *  messages, it should override this with
          +     *  > Strophe.log = function (level, msg) {
          +     *  >   (user code here)
          +     *  > };
          +     *
          +     *  Please note that data sent and received over the wire is logged
          +     *  via Strophe.Connection.rawInput() and Strophe.Connection.rawOutput().
          +     *
          +     *  The different levels and their meanings are
          +     *
          +     *    DEBUG - Messages useful for debugging purposes.
          +     *    INFO - Informational messages.  This is mostly information like
          +     *      'disconnect was called' or 'SASL auth succeeded'.
          +     *    WARN - Warnings about potential problems.  This is mostly used
          +     *      to report transient connection errors like request timeouts.
          +     *    ERROR - Some error occurred.
          +     *    FATAL - A non-recoverable fatal error occurred.
          +     *
          +     *  Parameters:
          +     *    (Integer) level - The log level of the log message.  This will
          +     *      be one of the values in Strophe.LogLevel.
          +     *    (String) msg - The log message.
          +     */
          +    /* jshint ignore:start */
          +    log: function (level, msg)
          +    {
          +        return;
          +    },
          +    /* jshint ignore:end */
          +
          +    /** Function: debug
          +     *  Log a message at the Strophe.LogLevel.DEBUG level.
          +     *
          +     *  Parameters:
          +     *    (String) msg - The log message.
          +     */
          +    debug: function(msg)
          +    {
          +        this.log(this.LogLevel.DEBUG, msg);
          +    },
          +
          +    /** Function: info
          +     *  Log a message at the Strophe.LogLevel.INFO level.
          +     *
          +     *  Parameters:
          +     *    (String) msg - The log message.
          +     */
          +    info: function (msg)
          +    {
          +        this.log(this.LogLevel.INFO, msg);
          +    },
          +
          +    /** Function: warn
          +     *  Log a message at the Strophe.LogLevel.WARN level.
          +     *
          +     *  Parameters:
          +     *    (String) msg - The log message.
          +     */
          +    warn: function (msg)
          +    {
          +        this.log(this.LogLevel.WARN, msg);
          +    },
          +
          +    /** Function: error
          +     *  Log a message at the Strophe.LogLevel.ERROR level.
          +     *
          +     *  Parameters:
          +     *    (String) msg - The log message.
          +     */
          +    error: function (msg)
          +    {
          +        this.log(this.LogLevel.ERROR, msg);
          +    },
          +
          +    /** Function: fatal
          +     *  Log a message at the Strophe.LogLevel.FATAL level.
          +     *
          +     *  Parameters:
          +     *    (String) msg - The log message.
          +     */
          +    fatal: function (msg)
          +    {
          +        this.log(this.LogLevel.FATAL, msg);
          +    },
          +
          +    /** Function: serialize
          +     *  Render a DOM element and all descendants to a String.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - A DOM element.
          +     *
          +     *  Returns:
          +     *    The serialized element tree as a String.
          +     */
          +    serialize: function (elem)
          +    {
          +        var result;
          +
          +        if (!elem) { return null; }
          +
          +        if (typeof(elem.tree) === "function") {
          +            elem = elem.tree();
          +        }
          +
          +        var nodeName = elem.nodeName;
          +        var i, child;
          +
          +        if (elem.getAttribute("_realname")) {
          +            nodeName = elem.getAttribute("_realname");
          +        }
          +
          +        result = "<" + nodeName;
          +        for (i = 0; i < elem.attributes.length; i++) {
          +               if(elem.attributes[i].nodeName != "_realname") {
          +                 result += " " + elem.attributes[i].nodeName.toLowerCase() +
          +                "='" + elem.attributes[i].value
          +                    .replace(/&/g, "&amp;")
          +                       .replace(/\'/g, "&apos;")
          +                       .replace(/>/g, "&gt;")
          +                       .replace(/</g, "&lt;") + "'";
          +               }
          +        }
          +
          +        if (elem.childNodes.length > 0) {
          +            result += ">";
          +            for (i = 0; i < elem.childNodes.length; i++) {
          +                child = elem.childNodes[i];
          +                switch( child.nodeType ){
          +                  case Strophe.ElementType.NORMAL:
          +                    // normal element, so recurse
          +                    result += Strophe.serialize(child);
          +                    break;
          +                  case Strophe.ElementType.TEXT:
          +                    // text element to escape values
          +                    result += Strophe.xmlescape(child.nodeValue);
          +                    break;
          +                  case Strophe.ElementType.CDATA:
          +                    // cdata section so don't escape values
          +                    result += "<![CDATA["+child.nodeValue+"]]>";
          +                }
          +            }
          +            result += "</" + nodeName + ">";
          +        } else {
          +            result += "/>";
          +        }
          +
          +        return result;
          +    },
          +
          +    /** PrivateVariable: _requestId
          +     *  _Private_ variable that keeps track of the request ids for
          +     *  connections.
          +     */
          +    _requestId: 0,
          +
          +    /** PrivateVariable: Strophe.connectionPlugins
          +     *  _Private_ variable Used to store plugin names that need
          +     *  initialization on Strophe.Connection construction.
          +     */
          +    _connectionPlugins: {},
          +
          +    /** Function: addConnectionPlugin
          +     *  Extends the Strophe.Connection object with the given plugin.
          +     *
          +     *  Parameters:
          +     *    (String) name - The name of the extension.
          +     *    (Object) ptype - The plugin's prototype.
          +     */
          +    addConnectionPlugin: function (name, ptype)
          +    {
          +        Strophe._connectionPlugins[name] = ptype;
          +    }
          +};
          +
          +/** Class: Strophe.Builder
          + *  XML DOM builder.
          + *
          + *  This object provides an interface similar to JQuery but for building
          + *  DOM element easily and rapidly.  All the functions except for toString()
          + *  and tree() return the object, so calls can be chained.  Here's an
          + *  example using the $iq() builder helper.
          + *  > $iq({to: 'you', from: 'me', type: 'get', id: '1'})
          + *  >     .c('query', {xmlns: 'strophe:example'})
          + *  >     .c('example')
          + *  >     .toString()
          + *  The above generates this XML fragment
          + *  > <iq to='you' from='me' type='get' id='1'>
          + *  >   <query xmlns='strophe:example'>
          + *  >     <example/>
          + *  >   </query>
          + *  > </iq>
          + *  The corresponding DOM manipulations to get a similar fragment would be
          + *  a lot more tedious and probably involve several helper variables.
          + *
          + *  Since adding children makes new operations operate on the child, up()
          + *  is provided to traverse up the tree.  To add two children, do
          + *  > builder.c('child1', ...).up().c('child2', ...)
          + *  The next operation on the Builder will be relative to the second child.
          + */
          +
          +/** Constructor: Strophe.Builder
          + *  Create a Strophe.Builder object.
          + *
          + *  The attributes should be passed in object notation.  For example
          + *  > var b = new Builder('message', {to: 'you', from: 'me'});
          + *  or
          + *  > var b = new Builder('messsage', {'xml:lang': 'en'});
          + *
          + *  Parameters:
          + *    (String) name - The name of the root element.
          + *    (Object) attrs - The attributes for the root element in object notation.
          + *
          + *  Returns:
          + *    A new Strophe.Builder.
          + */
          +Strophe.Builder = function (name, attrs)
          +{
          +    // Set correct namespace for jabber:client elements
          +    if (name == "presence" || name == "message" || name == "iq") {
          +        if (attrs && !attrs.xmlns) {
          +            attrs.xmlns = Strophe.NS.CLIENT;
          +        } else if (!attrs) {
          +            attrs = {xmlns: Strophe.NS.CLIENT};
          +        }
          +    }
          +
          +    // Holds the tree being built.
          +    this.nodeTree = Strophe.xmlElement(name, attrs);
          +
          +    // Points to the current operation node.
          +    this.node = this.nodeTree;
          +};
          +
          +Strophe.Builder.prototype = {
          +    /** Function: tree
          +     *  Return the DOM tree.
          +     *
          +     *  This function returns the current DOM tree as an element object.  This
          +     *  is suitable for passing to functions like Strophe.Connection.send().
          +     *
          +     *  Returns:
          +     *    The DOM tree as a element object.
          +     */
          +    tree: function ()
          +    {
          +        return this.nodeTree;
          +    },
          +
          +    /** Function: toString
          +     *  Serialize the DOM tree to a String.
          +     *
          +     *  This function returns a string serialization of the current DOM
          +     *  tree.  It is often used internally to pass data to a
          +     *  Strophe.Request object.
          +     *
          +     *  Returns:
          +     *    The serialized DOM tree in a String.
          +     */
          +    toString: function ()
          +    {
          +        return Strophe.serialize(this.nodeTree);
          +    },
          +
          +    /** Function: up
          +     *  Make the current parent element the new current element.
          +     *
          +     *  This function is often used after c() to traverse back up the tree.
          +     *  For example, to add two children to the same element
          +     *  > builder.c('child1', {}).up().c('child2', {});
          +     *
          +     *  Returns:
          +     *    The Stophe.Builder object.
          +     */
          +    up: function ()
          +    {
          +        this.node = this.node.parentNode;
          +        return this;
          +    },
          +
          +    /** Function: attrs
          +     *  Add or modify attributes of the current element.
          +     *
          +     *  The attributes should be passed in object notation.  This function
          +     *  does not move the current element pointer.
          +     *
          +     *  Parameters:
          +     *    (Object) moreattrs - The attributes to add/modify in object notation.
          +     *
          +     *  Returns:
          +     *    The Strophe.Builder object.
          +     */
          +    attrs: function (moreattrs)
          +    {
          +        for (var k in moreattrs) {
          +            if (moreattrs.hasOwnProperty(k)) {
          +                this.node.setAttribute(k, moreattrs[k]);
          +            }
          +        }
          +        return this;
          +    },
          +
          +    /** Function: c
          +     *  Add a child to the current element and make it the new current
          +     *  element.
          +     *
          +     *  This function moves the current element pointer to the child,
          +     *  unless text is provided.  If you need to add another child, it
          +     *  is necessary to use up() to go back to the parent in the tree.
          +     *
          +     *  Parameters:
          +     *    (String) name - The name of the child.
          +     *    (Object) attrs - The attributes of the child in object notation.
          +     *    (String) text - The text to add to the child.
          +     *
          +     *  Returns:
          +     *    The Strophe.Builder object.
          +     */
          +    c: function (name, attrs, text)
          +    {
          +        var child = Strophe.xmlElement(name, attrs, text);
          +        this.node.appendChild(child);
          +        if (!text) {
          +            this.node = child;
          +        }
          +        return this;
          +    },
          +
          +    /** Function: cnode
          +     *  Add a child to the current element and make it the new current
          +     *  element.
          +     *
          +     *  This function is the same as c() except that instead of using a
          +     *  name and an attributes object to create the child it uses an
          +     *  existing DOM element object.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - A DOM element.
          +     *
          +     *  Returns:
          +     *    The Strophe.Builder object.
          +     */
          +    cnode: function (elem)
          +    {
          +        var impNode;
          +        var xmlGen = Strophe.xmlGenerator();
          +        try {
          +            impNode = (xmlGen.importNode !== undefined);
          +        }
          +        catch (e) {
          +            impNode = false;
          +        }
          +        var newElem = impNode ?
          +                      xmlGen.importNode(elem, true) :
          +                      Strophe.copyElement(elem);
          +        this.node.appendChild(newElem);
          +        this.node = newElem;
          +        return this;
          +    },
          +
          +    /** Function: t
          +     *  Add a child text element.
          +     *
          +     *  This *does not* make the child the new current element since there
          +     *  are no children of text elements.
          +     *
          +     *  Parameters:
          +     *    (String) text - The text data to append to the current element.
          +     *
          +     *  Returns:
          +     *    The Strophe.Builder object.
          +     */
          +    t: function (text)
          +    {
          +        var child = Strophe.xmlTextNode(text);
          +        this.node.appendChild(child);
          +        return this;
          +    },
          +
          +    /** Function: h
          +     *  Replace current element contents with the HTML passed in.
          +     *
          +     *  This *does not* make the child the new current element
          +     *
          +     *  Parameters:
          +     *    (String) html - The html to insert as contents of current element.
          +     *
          +     *  Returns:
          +     *    The Strophe.Builder object.
          +     */
          +    h: function (html)
          +    {
          +        var fragment = document.createElement('body');
          +
          +        // force the browser to try and fix any invalid HTML tags
          +        fragment.innerHTML = html;
          +
          +        // copy cleaned html into an xml dom
          +        var xhtml = Strophe.createHtml(fragment);
          +
          +        while(xhtml.childNodes.length > 0) {
          +            this.node.appendChild(xhtml.childNodes[0]);
          +        }
          +        return this;
          +    }
          +};
          +
          +/** PrivateClass: Strophe.Handler
          + *  _Private_ helper class for managing stanza handlers.
          + *
          + *  A Strophe.Handler encapsulates a user provided callback function to be
          + *  executed when matching stanzas are received by the connection.
          + *  Handlers can be either one-off or persistant depending on their
          + *  return value. Returning true will cause a Handler to remain active, and
          + *  returning false will remove the Handler.
          + *
          + *  Users will not use Strophe.Handler objects directly, but instead they
          + *  will use Strophe.Connection.addHandler() and
          + *  Strophe.Connection.deleteHandler().
          + */
          +
          +/** PrivateConstructor: Strophe.Handler
          + *  Create and initialize a new Strophe.Handler.
          + *
          + *  Parameters:
          + *    (Function) handler - A function to be executed when the handler is run.
          + *    (String) ns - The namespace to match.
          + *    (String) name - The element name to match.
          + *    (String) type - The element type to match.
          + *    (String) id - The element id attribute to match.
          + *    (String) from - The element from attribute to match.
          + *    (Object) options - Handler options
          + *
          + *  Returns:
          + *    A new Strophe.Handler object.
          + */
          +Strophe.Handler = function (handler, ns, name, type, id, from, options)
          +{
          +    this.handler = handler;
          +    this.ns = ns;
          +    this.name = name;
          +    this.type = type;
          +    this.id = id;
          +    this.options = options || {matchBare: false};
          +
          +    // default matchBare to false if undefined
          +    if (!this.options.matchBare) {
          +        this.options.matchBare = false;
          +    }
          +
          +    if (this.options.matchBare) {
          +        this.from = from ? Strophe.getBareJidFromJid(from) : null;
          +    } else {
          +        this.from = from;
          +    }
          +
          +    // whether the handler is a user handler or a system handler
          +    this.user = true;
          +};
          +
          +Strophe.Handler.prototype = {
          +    /** PrivateFunction: isMatch
          +     *  Tests if a stanza matches the Strophe.Handler.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The XML element to test.
          +     *
          +     *  Returns:
          +     *    true if the stanza matches and false otherwise.
          +     */
          +    isMatch: function (elem)
          +    {
          +        var nsMatch;
          +        var from = null;
          +
          +        if (this.options.matchBare) {
          +            from = Strophe.getBareJidFromJid(elem.getAttribute('from'));
          +        } else {
          +            from = elem.getAttribute('from');
          +        }
          +
          +        nsMatch = false;
          +        if (!this.ns) {
          +            nsMatch = true;
          +        } else {
          +            var that = this;
          +            Strophe.forEachChild(elem, null, function (elem) {
          +                if (elem.getAttribute("xmlns") == that.ns) {
          +                    nsMatch = true;
          +                }
          +            });
          +
          +            nsMatch = nsMatch || elem.getAttribute("xmlns") == this.ns;
          +        }
          +
          +        if (nsMatch &&
          +            (!this.name || Strophe.isTagEqual(elem, this.name)) &&
          +            (!this.type || elem.getAttribute("type") == this.type) &&
          +            (!this.id || elem.getAttribute("id") == this.id) &&
          +            (!this.from || from == this.from)) {
          +                return true;
          +        }
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: run
          +     *  Run the callback on a matching stanza.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The DOM element that triggered the
          +     *      Strophe.Handler.
          +     *
          +     *  Returns:
          +     *    A boolean indicating if the handler should remain active.
          +     */
          +    run: function (elem)
          +    {
          +        var result = null;
          +        try {
          +            result = this.handler(elem);
          +        } catch (e) {
          +            if (e.sourceURL) {
          +                Strophe.fatal("error: " + this.handler +
          +                              " " + e.sourceURL + ":" +
          +                              e.line + " - " + e.name + ": " + e.message);
          +            } else if (e.fileName) {
          +                if (typeof(console) != "undefined") {
          +                    console.trace();
          +                    console.error(this.handler, " - error - ", e, e.message);
          +                }
          +                Strophe.fatal("error: " + this.handler + " " +
          +                              e.fileName + ":" + e.lineNumber + " - " +
          +                              e.name + ": " + e.message);
          +            } else {
          +                Strophe.fatal("error: " + e.message + "\n" + e.stack);
          +            }
          +
          +            throw e;
          +        }
          +
          +        return result;
          +    },
          +
          +    /** PrivateFunction: toString
          +     *  Get a String representation of the Strophe.Handler object.
          +     *
          +     *  Returns:
          +     *    A String.
          +     */
          +    toString: function ()
          +    {
          +        return "{Handler: " + this.handler + "(" + this.name + "," +
          +            this.id + "," + this.ns + ")}";
          +    }
          +};
          +
          +/** PrivateClass: Strophe.TimedHandler
          + *  _Private_ helper class for managing timed handlers.
          + *
          + *  A Strophe.TimedHandler encapsulates a user provided callback that
          + *  should be called after a certain period of time or at regular
          + *  intervals.  The return value of the callback determines whether the
          + *  Strophe.TimedHandler will continue to fire.
          + *
          + *  Users will not use Strophe.TimedHandler objects directly, but instead
          + *  they will use Strophe.Connection.addTimedHandler() and
          + *  Strophe.Connection.deleteTimedHandler().
          + */
          +
          +/** PrivateConstructor: Strophe.TimedHandler
          + *  Create and initialize a new Strophe.TimedHandler object.
          + *
          + *  Parameters:
          + *    (Integer) period - The number of milliseconds to wait before the
          + *      handler is called.
          + *    (Function) handler - The callback to run when the handler fires.  This
          + *      function should take no arguments.
          + *
          + *  Returns:
          + *    A new Strophe.TimedHandler object.
          + */
          +Strophe.TimedHandler = function (period, handler)
          +{
          +    this.period = period;
          +    this.handler = handler;
          +
          +    this.lastCalled = new Date().getTime();
          +    this.user = true;
          +};
          +
          +Strophe.TimedHandler.prototype = {
          +    /** PrivateFunction: run
          +     *  Run the callback for the Strophe.TimedHandler.
          +     *
          +     *  Returns:
          +     *    true if the Strophe.TimedHandler should be called again, and false
          +     *      otherwise.
          +     */
          +    run: function ()
          +    {
          +        this.lastCalled = new Date().getTime();
          +        return this.handler();
          +    },
          +
          +    /** PrivateFunction: reset
          +     *  Reset the last called time for the Strophe.TimedHandler.
          +     */
          +    reset: function ()
          +    {
          +        this.lastCalled = new Date().getTime();
          +    },
          +
          +    /** PrivateFunction: toString
          +     *  Get a string representation of the Strophe.TimedHandler object.
          +     *
          +     *  Returns:
          +     *    The string representation.
          +     */
          +    toString: function ()
          +    {
          +        return "{TimedHandler: " + this.handler + "(" + this.period +")}";
          +    }
          +};
          +
          +/** Class: Strophe.Connection
          + *  XMPP Connection manager.
          + *
          + *  This class is the main part of Strophe.  It manages a BOSH connection
          + *  to an XMPP server and dispatches events to the user callbacks as
          + *  data arrives.  It supports SASL PLAIN, SASL DIGEST-MD5, SASL SCRAM-SHA1
          + *  and legacy authentication.
          + *
          + *  After creating a Strophe.Connection object, the user will typically
          + *  call connect() with a user supplied callback to handle connection level
          + *  events like authentication failure, disconnection, or connection
          + *  complete.
          + *
          + *  The user will also have several event handlers defined by using
          + *  addHandler() and addTimedHandler().  These will allow the user code to
          + *  respond to interesting stanzas or do something periodically with the
          + *  connection.  These handlers will be active once authentication is
          + *  finished.
          + *
          + *  To send data to the connection, use send().
          + */
          +
          +/** Constructor: Strophe.Connection
          + *  Create and initialize a Strophe.Connection object.
          + *
          + *  The transport-protocol for this connection will be chosen automatically
          + *  based on the given service parameter. URLs starting with "ws://" or
          + *  "wss://" will use WebSockets, URLs starting with "http://", "https://"
          + *  or without a protocol will use BOSH.
          + *
          + *  To make Strophe connect to the current host you can leave out the protocol
          + *  and host part and just pass the path, e.g.
          + *
          + *  > var conn = new Strophe.Connection("/http-bind/");
          + *
          + *  WebSocket options:
          + *
          + *  If you want to connect to the current host with a WebSocket connection you
          + *  can tell Strophe to use WebSockets through a "protocol" attribute in the
          + *  optional options parameter. Valid values are "ws" for WebSocket and "wss"
          + *  for Secure WebSocket.
          + *  So to connect to "wss://CURRENT_HOSTNAME/xmpp-websocket" you would call
          + *
          + *  > var conn = new Strophe.Connection("/xmpp-websocket/", {protocol: "wss"});
          + *
          + *  Note that relative URLs _NOT_ starting with a "/" will also include the path
          + *  of the current site.
          + *
          + *  Also because downgrading security is not permitted by browsers, when using
          + *  relative URLs both BOSH and WebSocket connections will use their secure
          + *  variants if the current connection to the site is also secure (https).
          + *
          + *  BOSH options:
          + *
          + *  by adding "sync" to the options, you can control if requests will
          + *  be made synchronously or not. The default behaviour is asynchronous.
          + *  If you want to make requests synchronous, make "sync" evaluate to true:
          + *  > var conn = new Strophe.Connection("/http-bind/", {sync: true});
          + *  You can also toggle this on an already established connection:
          + *  > conn.options.sync = true;
          + *
          + *
          + *  Parameters:
          + *    (String) service - The BOSH or WebSocket service URL.
          + *    (Object) options - A hash of configuration options
          + *
          + *  Returns:
          + *    A new Strophe.Connection object.
          + */
          +Strophe.Connection = function (service, options)
          +{
          +    // The service URL
          +    this.service = service;
          +
          +    // Configuration options
          +    this.options = options || {};
          +    var proto = this.options.protocol || "";
          +
          +    // Select protocal based on service or options
          +    if (service.indexOf("ws:") === 0 || service.indexOf("wss:") === 0 ||
          +            proto.indexOf("ws") === 0) {
          +        this._proto = new Strophe.Websocket(this);
          +    } else {
          +        this._proto = new Strophe.Bosh(this);
          +    }
          +    /* The connected JID. */
          +    this.jid = "";
          +    /* the JIDs domain */
          +    this.domain = null;
          +    /* stream:features */
          +    this.features = null;
          +
          +    // SASL
          +    this._sasl_data = {};
          +    this.do_session = false;
          +    this.do_bind = false;
          +
          +    // handler lists
          +    this.timedHandlers = [];
          +    this.handlers = [];
          +    this.removeTimeds = [];
          +    this.removeHandlers = [];
          +    this.addTimeds = [];
          +    this.addHandlers = [];
          +
          +    this._authentication = {};
          +    this._idleTimeout = null;
          +    this._disconnectTimeout = null;
          +
          +    this.do_authentication = true;
          +    this.authenticated = false;
          +    this.disconnecting = false;
          +    this.connected = false;
          +
          +    this.errors = 0;
          +
          +    this.paused = false;
          +
          +    this._data = [];
          +    this._uniqueId = 0;
          +
          +    this._sasl_success_handler = null;
          +    this._sasl_failure_handler = null;
          +    this._sasl_challenge_handler = null;
          +
          +    // Max retries before disconnecting
          +    this.maxRetries = 5;
          +
          +    // setup onIdle callback every 1/10th of a second
          +    this._idleTimeout = setTimeout(this._onIdle.bind(this), 100);
          +
          +    // initialize plugins
          +    for (var k in Strophe._connectionPlugins) {
          +        if (Strophe._connectionPlugins.hasOwnProperty(k)) {
          +            var ptype = Strophe._connectionPlugins[k];
          +            // jslint complaints about the below line, but this is fine
          +            var F = function () {}; // jshint ignore:line
          +            F.prototype = ptype;
          +            this[k] = new F();
          +            this[k].init(this);
          +        }
          +    }
          +};
          +
          +Strophe.Connection.prototype = {
          +    /** Function: reset
          +     *  Reset the connection.
          +     *
          +     *  This function should be called after a connection is disconnected
          +     *  before that connection is reused.
          +     */
          +    reset: function ()
          +    {
          +        this._proto._reset();
          +
          +        // SASL
          +        this.do_session = false;
          +        this.do_bind = false;
          +
          +        // handler lists
          +        this.timedHandlers = [];
          +        this.handlers = [];
          +        this.removeTimeds = [];
          +        this.removeHandlers = [];
          +        this.addTimeds = [];
          +        this.addHandlers = [];
          +        this._authentication = {};
          +
          +        this.authenticated = false;
          +        this.disconnecting = false;
          +        this.connected = false;
          +
          +        this.errors = 0;
          +
          +        this._requests = [];
          +        this._uniqueId = 0;
          +    },
          +
          +    /** Function: pause
          +     *  Pause the request manager.
          +     *
          +     *  This will prevent Strophe from sending any more requests to the
          +     *  server.  This is very useful for temporarily pausing
          +     *  BOSH-Connections while a lot of send() calls are happening quickly.
          +     *  This causes Strophe to send the data in a single request, saving
          +     *  many request trips.
          +     */
          +    pause: function ()
          +    {
          +        this.paused = true;
          +    },
          +
          +    /** Function: resume
          +     *  Resume the request manager.
          +     *
          +     *  This resumes after pause() has been called.
          +     */
          +    resume: function ()
          +    {
          +        this.paused = false;
          +    },
          +
          +    /** Function: getUniqueId
          +     *  Generate a unique ID for use in <iq/> elements.
          +     *
          +     *  All <iq/> stanzas are required to have unique id attributes.  This
          +     *  function makes creating these easy.  Each connection instance has
          +     *  a counter which starts from zero, and the value of this counter
          +     *  plus a colon followed by the suffix becomes the unique id. If no
          +     *  suffix is supplied, the counter is used as the unique id.
          +     *
          +     *  Suffixes are used to make debugging easier when reading the stream
          +     *  data, and their use is recommended.  The counter resets to 0 for
          +     *  every new connection for the same reason.  For connections to the
          +     *  same server that authenticate the same way, all the ids should be
          +     *  the same, which makes it easy to see changes.  This is useful for
          +     *  automated testing as well.
          +     *
          +     *  Parameters:
          +     *    (String) suffix - A optional suffix to append to the id.
          +     *
          +     *  Returns:
          +     *    A unique string to be used for the id attribute.
          +     */
          +    getUniqueId: function (suffix)
          +    {
          +        if (typeof(suffix) == "string" || typeof(suffix) == "number") {
          +            return ++this._uniqueId + ":" + suffix;
          +        } else {
          +            return ++this._uniqueId + "";
          +        }
          +    },
          +
          +    /** Function: connect
          +     *  Starts the connection process.
          +     *
          +     *  As the connection process proceeds, the user supplied callback will
          +     *  be triggered multiple times with status updates.  The callback
          +     *  should take two arguments - the status code and the error condition.
          +     *
          +     *  The status code will be one of the values in the Strophe.Status
          +     *  constants.  The error condition will be one of the conditions
          +     *  defined in RFC 3920 or the condition 'strophe-parsererror'.
          +     *
          +     *  The Parameters _wait_, _hold_ and _route_ are optional and only relevant
          +     *  for BOSH connections. Please see XEP 124 for a more detailed explanation
          +     *  of the optional parameters.
          +     *
          +     *  Parameters:
          +     *    (String) jid - The user's JID.  This may be a bare JID,
          +     *      or a full JID.  If a node is not supplied, SASL ANONYMOUS
          +     *      authentication will be attempted.
          +     *    (String) pass - The user's password.
          +     *    (Function) callback - The connect callback function.
          +     *    (Integer) wait - The optional HTTPBIND wait value.  This is the
          +     *      time the server will wait before returning an empty result for
          +     *      a request.  The default setting of 60 seconds is recommended.
          +     *    (Integer) hold - The optional HTTPBIND hold value.  This is the
          +     *      number of connections the server will hold at one time.  This
          +     *      should almost always be set to 1 (the default).
          +     *    (String) route - The optional route value.
          +     */
          +    connect: function (jid, pass, callback, wait, hold, route)
          +    {
          +        this.jid = jid;
          +        /** Variable: authzid
          +         *  Authorization identity.
          +         */
          +        this.authzid = Strophe.getBareJidFromJid(this.jid);
          +        /** Variable: authcid
          +         *  Authentication identity (User name).
          +         */
          +        this.authcid = Strophe.getNodeFromJid(this.jid);
          +        /** Variable: pass
          +         *  Authentication identity (User password).
          +         */
          +        this.pass = pass;
          +        /** Variable: servtype
          +         *  Digest MD5 compatibility.
          +         */
          +        this.servtype = "xmpp";
          +        this.connect_callback = callback;
          +        this.disconnecting = false;
          +        this.connected = false;
          +        this.authenticated = false;
          +        this.errors = 0;
          +
          +        // parse jid for domain
          +        this.domain = Strophe.getDomainFromJid(this.jid);
          +
          +        this._changeConnectStatus(Strophe.Status.CONNECTING, null);
          +
          +        this._proto._connect(wait, hold, route);
          +    },
          +
          +    /** Function: attach
          +     *  Attach to an already created and authenticated BOSH session.
          +     *
          +     *  This function is provided to allow Strophe to attach to BOSH
          +     *  sessions which have been created externally, perhaps by a Web
          +     *  application.  This is often used to support auto-login type features
          +     *  without putting user credentials into the page.
          +     *
          +     *  Parameters:
          +     *    (String) jid - The full JID that is bound by the session.
          +     *    (String) sid - The SID of the BOSH session.
          +     *    (String) rid - The current RID of the BOSH session.  This RID
          +     *      will be used by the next request.
          +     *    (Function) callback The connect callback function.
          +     *    (Integer) wait - The optional HTTPBIND wait value.  This is the
          +     *      time the server will wait before returning an empty result for
          +     *      a request.  The default setting of 60 seconds is recommended.
          +     *      Other settings will require tweaks to the Strophe.TIMEOUT value.
          +     *    (Integer) hold - The optional HTTPBIND hold value.  This is the
          +     *      number of connections the server will hold at one time.  This
          +     *      should almost always be set to 1 (the default).
          +     *    (Integer) wind - The optional HTTBIND window value.  This is the
          +     *      allowed range of request ids that are valid.  The default is 5.
          +     */
          +    attach: function (jid, sid, rid, callback, wait, hold, wind)
          +    {
          +        this._proto._attach(jid, sid, rid, callback, wait, hold, wind);
          +    },
          +
          +    /** Function: xmlInput
          +     *  User overrideable function that receives XML data coming into the
          +     *  connection.
          +     *
          +     *  The default function does nothing.  User code can override this with
          +     *  > Strophe.Connection.xmlInput = function (elem) {
          +     *  >   (user code)
          +     *  > };
          +     *
          +     *  Due to limitations of current Browsers' XML-Parsers the opening and closing
          +     *  <stream> tag for WebSocket-Connoctions will be passed as selfclosing here.
          +     *
          +     *  BOSH-Connections will have all stanzas wrapped in a <body> tag. See
          +     *  <Strophe.Bosh.strip> if you want to strip this tag.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The XML data received by the connection.
          +     */
          +    /* jshint unused:false */
          +    xmlInput: function (elem)
          +    {
          +        return;
          +    },
          +    /* jshint unused:true */
          +
          +    /** Function: xmlOutput
          +     *  User overrideable function that receives XML data sent to the
          +     *  connection.
          +     *
          +     *  The default function does nothing.  User code can override this with
          +     *  > Strophe.Connection.xmlOutput = function (elem) {
          +     *  >   (user code)
          +     *  > };
          +     *
          +     *  Due to limitations of current Browsers' XML-Parsers the opening and closing
          +     *  <stream> tag for WebSocket-Connoctions will be passed as selfclosing here.
          +     *
          +     *  BOSH-Connections will have all stanzas wrapped in a <body> tag. See
          +     *  <Strophe.Bosh.strip> if you want to strip this tag.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The XMLdata sent by the connection.
          +     */
          +    /* jshint unused:false */
          +    xmlOutput: function (elem)
          +    {
          +        return;
          +    },
          +    /* jshint unused:true */
          +
          +    /** Function: rawInput
          +     *  User overrideable function that receives raw data coming into the
          +     *  connection.
          +     *
          +     *  The default function does nothing.  User code can override this with
          +     *  > Strophe.Connection.rawInput = function (data) {
          +     *  >   (user code)
          +     *  > };
          +     *
          +     *  Parameters:
          +     *    (String) data - The data received by the connection.
          +     */
          +    /* jshint unused:false */
          +    rawInput: function (data)
          +    {
          +        return;
          +    },
          +    /* jshint unused:true */
          +
          +    /** Function: rawOutput
          +     *  User overrideable function that receives raw data sent to the
          +     *  connection.
          +     *
          +     *  The default function does nothing.  User code can override this with
          +     *  > Strophe.Connection.rawOutput = function (data) {
          +     *  >   (user code)
          +     *  > };
          +     *
          +     *  Parameters:
          +     *    (String) data - The data sent by the connection.
          +     */
          +    /* jshint unused:false */
          +    rawOutput: function (data)
          +    {
          +        return;
          +    },
          +    /* jshint unused:true */
          +
          +    /** Function: send
          +     *  Send a stanza.
          +     *
          +     *  This function is called to push data onto the send queue to
          +     *  go out over the wire.  Whenever a request is sent to the BOSH
          +     *  server, all pending data is sent and the queue is flushed.
          +     *
          +     *  Parameters:
          +     *    (XMLElement |
          +     *     [XMLElement] |
          +     *     Strophe.Builder) elem - The stanza to send.
          +     */
          +    send: function (elem)
          +    {
          +        if (elem === null) { return ; }
          +        if (typeof(elem.sort) === "function") {
          +            for (var i = 0; i < elem.length; i++) {
          +                this._queueData(elem[i]);
          +            }
          +        } else if (typeof(elem.tree) === "function") {
          +            this._queueData(elem.tree());
          +        } else {
          +            this._queueData(elem);
          +        }
          +
          +        this._proto._send();
          +    },
          +
          +    /** Function: flush
          +     *  Immediately send any pending outgoing data.
          +     *
          +     *  Normally send() queues outgoing data until the next idle period
          +     *  (100ms), which optimizes network use in the common cases when
          +     *  several send()s are called in succession. flush() can be used to
          +     *  immediately send all pending data.
          +     */
          +    flush: function ()
          +    {
          +        // cancel the pending idle period and run the idle function
          +        // immediately
          +        clearTimeout(this._idleTimeout);
          +        this._onIdle();
          +    },
          +
          +    /** Function: sendIQ
          +     *  Helper function to send IQ stanzas.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The stanza to send.
          +     *    (Function) callback - The callback function for a successful request.
          +     *    (Function) errback - The callback function for a failed or timed
          +     *      out request.  On timeout, the stanza will be null.
          +     *    (Integer) timeout - The time specified in milliseconds for a
          +     *      timeout to occur.
          +     *
          +     *  Returns:
          +     *    The id used to send the IQ.
          +    */
          +    sendIQ: function(elem, callback, errback, timeout) {
          +        var timeoutHandler = null;
          +        var that = this;
          +
          +        if (typeof(elem.tree) === "function") {
          +            elem = elem.tree();
          +        }
          +        var id = elem.getAttribute('id');
          +
          +        // inject id if not found
          +        if (!id) {
          +            id = this.getUniqueId("sendIQ");
          +            elem.setAttribute("id", id);
          +        }
          +
          +        var handler = this.addHandler(function (stanza) {
          +            // remove timeout handler if there is one
          +            if (timeoutHandler) {
          +                that.deleteTimedHandler(timeoutHandler);
          +            }
          +
          +            var iqtype = stanza.getAttribute('type');
          +            if (iqtype == 'result') {
          +                if (callback) {
          +                    callback(stanza);
          +                }
          +            } else if (iqtype == 'error') {
          +                if (errback) {
          +                    errback(stanza);
          +                }
          +            } else {
          +                throw {
          +                    name: "StropheError",
          +            message: "Got bad IQ type of " + iqtype
          +                };
          +            }
          +        }, null, 'iq', null, id);
          +
          +        // if timeout specified, setup timeout handler.
          +        if (timeout) {
          +            timeoutHandler = this.addTimedHandler(timeout, function () {
          +                // get rid of normal handler
          +                that.deleteHandler(handler);
          +
          +                // call errback on timeout with null stanza
          +                if (errback) {
          +                    errback(null);
          +                }
          +                return false;
          +            });
          +        }
          +
          +        this.send(elem);
          +
          +        return id;
          +    },
          +
          +    /** PrivateFunction: _queueData
          +     *  Queue outgoing data for later sending.  Also ensures that the data
          +     *  is a DOMElement.
          +     */
          +    _queueData: function (element) {
          +        if (element === null ||
          +            !element.tagName ||
          +            !element.childNodes) {
          +            throw {
          +                name: "StropheError",
          +                message: "Cannot queue non-DOMElement."
          +            };
          +        }
          +
          +        this._data.push(element);
          +    },
          +
          +    /** PrivateFunction: _sendRestart
          +     *  Send an xmpp:restart stanza.
          +     */
          +    _sendRestart: function ()
          +    {
          +        this._data.push("restart");
          +
          +        this._proto._sendRestart();
          +
          +        this._idleTimeout = setTimeout(this._onIdle.bind(this), 100);
          +    },
          +
          +    /** Function: addTimedHandler
          +     *  Add a timed handler to the connection.
          +     *
          +     *  This function adds a timed handler.  The provided handler will
          +     *  be called every period milliseconds until it returns false,
          +     *  the connection is terminated, or the handler is removed.  Handlers
          +     *  that wish to continue being invoked should return true.
          +     *
          +     *  Because of method binding it is necessary to save the result of
          +     *  this function if you wish to remove a handler with
          +     *  deleteTimedHandler().
          +     *
          +     *  Note that user handlers are not active until authentication is
          +     *  successful.
          +     *
          +     *  Parameters:
          +     *    (Integer) period - The period of the handler.
          +     *    (Function) handler - The callback function.
          +     *
          +     *  Returns:
          +     *    A reference to the handler that can be used to remove it.
          +     */
          +    addTimedHandler: function (period, handler)
          +    {
          +        var thand = new Strophe.TimedHandler(period, handler);
          +        this.addTimeds.push(thand);
          +        return thand;
          +    },
          +
          +    /** Function: deleteTimedHandler
          +     *  Delete a timed handler for a connection.
          +     *
          +     *  This function removes a timed handler from the connection.  The
          +     *  handRef parameter is *not* the function passed to addTimedHandler(),
          +     *  but is the reference returned from addTimedHandler().
          +     *
          +     *  Parameters:
          +     *    (Strophe.TimedHandler) handRef - The handler reference.
          +     */
          +    deleteTimedHandler: function (handRef)
          +    {
          +        // this must be done in the Idle loop so that we don't change
          +        // the handlers during iteration
          +        this.removeTimeds.push(handRef);
          +    },
          +
          +    /** Function: addHandler
          +     *  Add a stanza handler for the connection.
          +     *
          +     *  This function adds a stanza handler to the connection.  The
          +     *  handler callback will be called for any stanza that matches
          +     *  the parameters.  Note that if multiple parameters are supplied,
          +     *  they must all match for the handler to be invoked.
          +     *
          +     *  The handler will receive the stanza that triggered it as its argument.
          +     *  The handler should return true if it is to be invoked again;
          +     *  returning false will remove the handler after it returns.
          +     *
          +     *  As a convenience, the ns parameters applies to the top level element
          +     *  and also any of its immediate children.  This is primarily to make
          +     *  matching /iq/query elements easy.
          +     *
          +     *  The options argument contains handler matching flags that affect how
          +     *  matches are determined. Currently the only flag is matchBare (a
          +     *  boolean). When matchBare is true, the from parameter and the from
          +     *  attribute on the stanza will be matched as bare JIDs instead of
          +     *  full JIDs. To use this, pass {matchBare: true} as the value of
          +     *  options. The default value for matchBare is false.
          +     *
          +     *  The return value should be saved if you wish to remove the handler
          +     *  with deleteHandler().
          +     *
          +     *  Parameters:
          +     *    (Function) handler - The user callback.
          +     *    (String) ns - The namespace to match.
          +     *    (String) name - The stanza name to match.
          +     *    (String) type - The stanza type attribute to match.
          +     *    (String) id - The stanza id attribute to match.
          +     *    (String) from - The stanza from attribute to match.
          +     *    (String) options - The handler options
          +     *
          +     *  Returns:
          +     *    A reference to the handler that can be used to remove it.
          +     */
          +    addHandler: function (handler, ns, name, type, id, from, options)
          +    {
          +        var hand = new Strophe.Handler(handler, ns, name, type, id, from, options);
          +        this.addHandlers.push(hand);
          +        return hand;
          +    },
          +
          +    /** Function: deleteHandler
          +     *  Delete a stanza handler for a connection.
          +     *
          +     *  This function removes a stanza handler from the connection.  The
          +     *  handRef parameter is *not* the function passed to addHandler(),
          +     *  but is the reference returned from addHandler().
          +     *
          +     *  Parameters:
          +     *    (Strophe.Handler) handRef - The handler reference.
          +     */
          +    deleteHandler: function (handRef)
          +    {
          +        // this must be done in the Idle loop so that we don't change
          +        // the handlers during iteration
          +        this.removeHandlers.push(handRef);
          +    },
          +
          +    /** Function: disconnect
          +     *  Start the graceful disconnection process.
          +     *
          +     *  This function starts the disconnection process.  This process starts
          +     *  by sending unavailable presence and sending BOSH body of type
          +     *  terminate.  A timeout handler makes sure that disconnection happens
          +     *  even if the BOSH server does not respond.
          +     *
          +     *  The user supplied connection callback will be notified of the
          +     *  progress as this process happens.
          +     *
          +     *  Parameters:
          +     *    (String) reason - The reason the disconnect is occuring.
          +     */
          +    disconnect: function (reason)
          +    {
          +        this._changeConnectStatus(Strophe.Status.DISCONNECTING, reason);
          +
          +        Strophe.info("Disconnect was called because: " + reason);
          +        if (this.connected) {
          +            var pres = false;
          +            this.disconnecting = true;
          +            if (this.authenticated) {
          +                pres = $pres({
          +                    xmlns: Strophe.NS.CLIENT,
          +                    type: 'unavailable'
          +                });
          +            }
          +            // setup timeout handler
          +            this._disconnectTimeout = this._addSysTimedHandler(
          +                3000, this._onDisconnectTimeout.bind(this));
          +            this._proto._disconnect(pres);
          +        }
          +    },
          +
          +    /** PrivateFunction: _changeConnectStatus
          +     *  _Private_ helper function that makes sure plugins and the user's
          +     *  callback are notified of connection status changes.
          +     *
          +     *  Parameters:
          +     *    (Integer) status - the new connection status, one of the values
          +     *      in Strophe.Status
          +     *    (String) condition - the error condition or null
          +     */
          +    _changeConnectStatus: function (status, condition)
          +    {
          +        // notify all plugins listening for status changes
          +        for (var k in Strophe._connectionPlugins) {
          +            if (Strophe._connectionPlugins.hasOwnProperty(k)) {
          +                var plugin = this[k];
          +                if (plugin.statusChanged) {
          +                    try {
          +                        plugin.statusChanged(status, condition);
          +                    } catch (err) {
          +                        Strophe.error("" + k + " plugin caused an exception " +
          +                                      "changing status: " + err);
          +                    }
          +                }
          +            }
          +        }
          +
          +        // notify the user's callback
          +        if (this.connect_callback) {
          +            try {
          +                this.connect_callback(status, condition);
          +            } catch (e) {
          +                Strophe.error("User connection callback caused an " +
          +                              "exception: " + e);
          +            }
          +        }
          +    },
          +
          +    /** PrivateFunction: _doDisconnect
          +     *  _Private_ function to disconnect.
          +     *
          +     *  This is the last piece of the disconnection logic.  This resets the
          +     *  connection and alerts the user's connection callback.
          +     */
          +    _doDisconnect: function ()
          +    {
          +        // Cancel Disconnect Timeout
          +        if (this._disconnectTimeout !== null) {
          +            this.deleteTimedHandler(this._disconnectTimeout);
          +            this._disconnectTimeout = null;
          +        }
          +
          +        Strophe.info("_doDisconnect was called");
          +        this._proto._doDisconnect();
          +
          +        this.authenticated = false;
          +        this.disconnecting = false;
          +
          +        // delete handlers
          +        this.handlers = [];
          +        this.timedHandlers = [];
          +        this.removeTimeds = [];
          +        this.removeHandlers = [];
          +        this.addTimeds = [];
          +        this.addHandlers = [];
          +
          +        // tell the parent we disconnected
          +        this._changeConnectStatus(Strophe.Status.DISCONNECTED, null);
          +        this.connected = false;
          +    },
          +
          +    /** PrivateFunction: _dataRecv
          +     *  _Private_ handler to processes incoming data from the the connection.
          +     *
          +     *  Except for _connect_cb handling the initial connection request,
          +     *  this function handles the incoming data for all requests.  This
          +     *  function also fires stanza handlers that match each incoming
          +     *  stanza.
          +     *
          +     *  Parameters:
          +     *    (Strophe.Request) req - The request that has data ready.
          +     *    (string) req - The stanza a raw string (optiona).
          +     */
          +    _dataRecv: function (req, raw)
          +    {
          +        Strophe.info("_dataRecv called");
          +        var elem = this._proto._reqToData(req);
          +        if (elem === null) { return; }
          +
          +        if (this.xmlInput !== Strophe.Connection.prototype.xmlInput) {
          +            if (elem.nodeName === this._proto.strip && elem.childNodes.length) {
          +                this.xmlInput(elem.childNodes[0]);
          +            } else {
          +                this.xmlInput(elem);
          +            }
          +        }
          +        if (this.rawInput !== Strophe.Connection.prototype.rawInput) {
          +            if (raw) {
          +                this.rawInput(raw);
          +            } else {
          +                this.rawInput(Strophe.serialize(elem));
          +            }
          +        }
          +
          +        // remove handlers scheduled for deletion
          +        var i, hand;
          +        while (this.removeHandlers.length > 0) {
          +            hand = this.removeHandlers.pop();
          +            i = this.handlers.indexOf(hand);
          +            if (i >= 0) {
          +                this.handlers.splice(i, 1);
          +            }
          +        }
          +
          +        // add handlers scheduled for addition
          +        while (this.addHandlers.length > 0) {
          +            this.handlers.push(this.addHandlers.pop());
          +        }
          +
          +        // handle graceful disconnect
          +        if (this.disconnecting && this._proto._emptyQueue()) {
          +            this._doDisconnect();
          +            return;
          +        }
          +
          +        var typ = elem.getAttribute("type");
          +        var cond, conflict;
          +        if (typ !== null && typ == "terminate") {
          +            // Don't process stanzas that come in after disconnect
          +            if (this.disconnecting) {
          +                return;
          +            }
          +
          +            // an error occurred
          +            cond = elem.getAttribute("condition");
          +            conflict = elem.getElementsByTagName("conflict");
          +            if (cond !== null) {
          +                if (cond == "remote-stream-error" && conflict.length > 0) {
          +                    cond = "conflict";
          +                }
          +                this._changeConnectStatus(Strophe.Status.CONNFAIL, cond);
          +            } else {
          +                this._changeConnectStatus(Strophe.Status.CONNFAIL, "unknown");
          +            }
          +            this.disconnect('unknown stream-error');
          +            return;
          +        }
          +
          +        // send each incoming stanza through the handler chain
          +        var that = this;
          +        Strophe.forEachChild(elem, null, function (child) {
          +            var i, newList;
          +            // process handlers
          +            newList = that.handlers;
          +            that.handlers = [];
          +            for (i = 0; i < newList.length; i++) {
          +                var hand = newList[i];
          +                // encapsulate 'handler.run' not to lose the whole handler list if
          +                // one of the handlers throws an exception
          +                try {
          +                    if (hand.isMatch(child) &&
          +                        (that.authenticated || !hand.user)) {
          +                        if (hand.run(child)) {
          +                            that.handlers.push(hand);
          +                        }
          +                    } else {
          +                        that.handlers.push(hand);
          +                    }
          +                } catch(e) {
          +                    // if the handler throws an exception, we consider it as false
          +                    Strophe.warn('Removing Strophe handlers due to uncaught exception: ' + e.message);
          +                }
          +            }
          +        });
          +    },
          +
          +
          +    /** Attribute: mechanisms
          +     *  SASL Mechanisms available for Conncection.
          +     */
          +    mechanisms: {},
          +
          +    /** PrivateFunction: _connect_cb
          +     *  _Private_ handler for initial connection request.
          +     *
          +     *  This handler is used to process the initial connection request
          +     *  response from the BOSH server. It is used to set up authentication
          +     *  handlers and start the authentication process.
          +     *
          +     *  SASL authentication will be attempted if available, otherwise
          +     *  the code will fall back to legacy authentication.
          +     *
          +     *  Parameters:
          +     *    (Strophe.Request) req - The current request.
          +     *    (Function) _callback - low level (xmpp) connect callback function.
          +     *      Useful for plugins with their own xmpp connect callback (when their)
          +     *      want to do something special).
          +     */
          +    _connect_cb: function (req, _callback, raw)
          +    {
          +        Strophe.info("_connect_cb was called");
          +
          +        this.connected = true;
          +
          +        var bodyWrap = this._proto._reqToData(req);
          +        if (!bodyWrap) { return; }
          +
          +        if (this.xmlInput !== Strophe.Connection.prototype.xmlInput) {
          +            if (bodyWrap.nodeName === this._proto.strip && bodyWrap.childNodes.length) {
          +                this.xmlInput(bodyWrap.childNodes[0]);
          +            } else {
          +                this.xmlInput(bodyWrap);
          +            }
          +        }
          +        if (this.rawInput !== Strophe.Connection.prototype.rawInput) {
          +            if (raw) {
          +                this.rawInput(raw);
          +            } else {
          +                this.rawInput(Strophe.serialize(bodyWrap));
          +            }
          +        }
          +
          +        var conncheck = this._proto._connect_cb(bodyWrap);
          +        if (conncheck === Strophe.Status.CONNFAIL) {
          +            return;
          +        }
          +
          +        this._authentication.sasl_scram_sha1 = false;
          +        this._authentication.sasl_plain = false;
          +        this._authentication.sasl_digest_md5 = false;
          +        this._authentication.sasl_anonymous = false;
          +
          +        this._authentication.legacy_auth = false;
          +
          +        // Check for the stream:features tag
          +        var hasFeatures = bodyWrap.getElementsByTagName("stream:features").length > 0;
          +        if (!hasFeatures) {
          +            hasFeatures = bodyWrap.getElementsByTagName("features").length > 0;
          +        }
          +        var mechanisms = bodyWrap.getElementsByTagName("mechanism");
          +        var matched = [];
          +        var i, mech, found_authentication = false;
          +        if (!hasFeatures) {
          +            this._proto._no_auth_received(_callback);
          +            return;
          +        }
          +        if (mechanisms.length > 0) {
          +            for (i = 0; i < mechanisms.length; i++) {
          +                mech = Strophe.getText(mechanisms[i]);
          +                if (this.mechanisms[mech]) matched.push(this.mechanisms[mech]);
          +            }
          +        }
          +        this._authentication.legacy_auth =
          +            bodyWrap.getElementsByTagName("auth").length > 0;
          +        found_authentication = this._authentication.legacy_auth ||
          +            matched.length > 0;
          +        if (!found_authentication) {
          +            this._proto._no_auth_received(_callback);
          +            return;
          +        }
          +        if (this.do_authentication !== false)
          +            this.authenticate(matched);
          +    },
          +
          +    /** Function: authenticate
          +     * Set up authentication
          +     *
          +     *  Contiunues the initial connection request by setting up authentication
          +     *  handlers and start the authentication process.
          +     *
          +     *  SASL authentication will be attempted if available, otherwise
          +     *  the code will fall back to legacy authentication.
          +     *
          +     */
          +    authenticate: function (matched)
          +    {
          +      var i;
          +      // Sorting matched mechanisms according to priority.
          +      for (i = 0; i < matched.length - 1; ++i) {
          +        var higher = i;
          +        for (var j = i + 1; j < matched.length; ++j) {
          +          if (matched[j].prototype.priority > matched[higher].prototype.priority) {
          +            higher = j;
          +          }
          +        }
          +        if (higher != i) {
          +          var swap = matched[i];
          +          matched[i] = matched[higher];
          +          matched[higher] = swap;
          +        }
          +      }
          +
          +      // run each mechanism
          +      var mechanism_found = false;
          +      for (i = 0; i < matched.length; ++i) {
          +        if (!matched[i].test(this)) continue;
          +
          +        this._sasl_success_handler = this._addSysHandler(
          +          this._sasl_success_cb.bind(this), null,
          +          "success", null, null);
          +        this._sasl_failure_handler = this._addSysHandler(
          +          this._sasl_failure_cb.bind(this), null,
          +          "failure", null, null);
          +        this._sasl_challenge_handler = this._addSysHandler(
          +          this._sasl_challenge_cb.bind(this), null,
          +          "challenge", null, null);
          +
          +        this._sasl_mechanism = new matched[i]();
          +        this._sasl_mechanism.onStart(this);
          +
          +        var request_auth_exchange = $build("auth", {
          +          xmlns: Strophe.NS.SASL,
          +          mechanism: this._sasl_mechanism.name
          +        });
          +
          +        if (this._sasl_mechanism.isClientFirst) {
          +          var response = this._sasl_mechanism.onChallenge(this, null);
          +          request_auth_exchange.t(Base64.encode(response));
          +        }
          +
          +        this.send(request_auth_exchange.tree());
          +
          +        mechanism_found = true;
          +        break;
          +      }
          +
          +      if (!mechanism_found) {
          +        // if none of the mechanism worked
          +        if (Strophe.getNodeFromJid(this.jid) === null) {
          +            // we don't have a node, which is required for non-anonymous
          +            // client connections
          +            this._changeConnectStatus(Strophe.Status.CONNFAIL,
          +                                      'x-strophe-bad-non-anon-jid');
          +            this.disconnect('x-strophe-bad-non-anon-jid');
          +        } else {
          +          // fall back to legacy authentication
          +          this._changeConnectStatus(Strophe.Status.AUTHENTICATING, null);
          +          this._addSysHandler(this._auth1_cb.bind(this), null, null,
          +                              null, "_auth_1");
          +
          +          this.send($iq({
          +            type: "get",
          +            to: this.domain,
          +            id: "_auth_1"
          +          }).c("query", {
          +            xmlns: Strophe.NS.AUTH
          +          }).c("username", {}).t(Strophe.getNodeFromJid(this.jid)).tree());
          +        }
          +      }
          +
          +    },
          +
          +    _sasl_challenge_cb: function(elem) {
          +      var challenge = Base64.decode(Strophe.getText(elem));
          +      var response = this._sasl_mechanism.onChallenge(this, challenge);
          +
          +      var stanza = $build('response', {
          +          xmlns: Strophe.NS.SASL
          +      });
          +      if (response !== "") {
          +        stanza.t(Base64.encode(response));
          +      }
          +      this.send(stanza.tree());
          +
          +      return true;
          +    },
          +
          +    /** PrivateFunction: _auth1_cb
          +     *  _Private_ handler for legacy authentication.
          +     *
          +     *  This handler is called in response to the initial <iq type='get'/>
          +     *  for legacy authentication.  It builds an authentication <iq/> and
          +     *  sends it, creating a handler (calling back to _auth2_cb()) to
          +     *  handle the result
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The stanza that triggered the callback.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    /* jshint unused:false */
          +    _auth1_cb: function (elem)
          +    {
          +        // build plaintext auth iq
          +        var iq = $iq({type: "set", id: "_auth_2"})
          +            .c('query', {xmlns: Strophe.NS.AUTH})
          +            .c('username', {}).t(Strophe.getNodeFromJid(this.jid))
          +            .up()
          +            .c('password').t(this.pass);
          +
          +        if (!Strophe.getResourceFromJid(this.jid)) {
          +            // since the user has not supplied a resource, we pick
          +            // a default one here.  unlike other auth methods, the server
          +            // cannot do this for us.
          +            this.jid = Strophe.getBareJidFromJid(this.jid) + '/strophe';
          +        }
          +        iq.up().c('resource', {}).t(Strophe.getResourceFromJid(this.jid));
          +
          +        this._addSysHandler(this._auth2_cb.bind(this), null,
          +                            null, null, "_auth_2");
          +
          +        this.send(iq.tree());
          +
          +        return false;
          +    },
          +    /* jshint unused:true */
          +
          +    /** PrivateFunction: _sasl_success_cb
          +     *  _Private_ handler for succesful SASL authentication.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The matching stanza.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _sasl_success_cb: function (elem)
          +    {
          +        if (this._sasl_data["server-signature"]) {
          +            var serverSignature;
          +            var success = Base64.decode(Strophe.getText(elem));
          +            var attribMatch = /([a-z]+)=([^,]+)(,|$)/;
          +            var matches = success.match(attribMatch);
          +            if (matches[1] == "v") {
          +                serverSignature = matches[2];
          +            }
          +
          +            if (serverSignature != this._sasl_data["server-signature"]) {
          +              // remove old handlers
          +              this.deleteHandler(this._sasl_failure_handler);
          +              this._sasl_failure_handler = null;
          +              if (this._sasl_challenge_handler) {
          +                this.deleteHandler(this._sasl_challenge_handler);
          +                this._sasl_challenge_handler = null;
          +              }
          +
          +              this._sasl_data = {};
          +              return this._sasl_failure_cb(null);
          +            }
          +        }
          +
          +        Strophe.info("SASL authentication succeeded.");
          +
          +        if(this._sasl_mechanism)
          +          this._sasl_mechanism.onSuccess();
          +
          +        // remove old handlers
          +        this.deleteHandler(this._sasl_failure_handler);
          +        this._sasl_failure_handler = null;
          +        if (this._sasl_challenge_handler) {
          +            this.deleteHandler(this._sasl_challenge_handler);
          +            this._sasl_challenge_handler = null;
          +        }
          +
          +        this._addSysHandler(this._sasl_auth1_cb.bind(this), null,
          +                            "stream:features", null, null);
          +
          +        // we must send an xmpp:restart now
          +        this._sendRestart();
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: _sasl_auth1_cb
          +     *  _Private_ handler to start stream binding.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The matching stanza.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _sasl_auth1_cb: function (elem)
          +    {
          +        // save stream:features for future usage
          +        this.features = elem;
          +
          +        var i, child;
          +
          +        for (i = 0; i < elem.childNodes.length; i++) {
          +            child = elem.childNodes[i];
          +            if (child.nodeName == 'bind') {
          +                this.do_bind = true;
          +            }
          +
          +            if (child.nodeName == 'session') {
          +                this.do_session = true;
          +            }
          +        }
          +
          +        if (!this.do_bind) {
          +            this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
          +            return false;
          +        } else {
          +            this._addSysHandler(this._sasl_bind_cb.bind(this), null, null,
          +                                null, "_bind_auth_2");
          +
          +            var resource = Strophe.getResourceFromJid(this.jid);
          +            if (resource) {
          +                this.send($iq({type: "set", id: "_bind_auth_2"})
          +                          .c('bind', {xmlns: Strophe.NS.BIND})
          +                          .c('resource', {}).t(resource).tree());
          +            } else {
          +                this.send($iq({type: "set", id: "_bind_auth_2"})
          +                          .c('bind', {xmlns: Strophe.NS.BIND})
          +                          .tree());
          +            }
          +        }
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: _sasl_bind_cb
          +     *  _Private_ handler for binding result and session start.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The matching stanza.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _sasl_bind_cb: function (elem)
          +    {
          +        if (elem.getAttribute("type") == "error") {
          +            Strophe.info("SASL binding failed.");
          +            var conflict = elem.getElementsByTagName("conflict"), condition;
          +            if (conflict.length > 0) {
          +                condition = 'conflict';
          +            }
          +            this._changeConnectStatus(Strophe.Status.AUTHFAIL, condition);
          +            return false;
          +        }
          +
          +        // TODO - need to grab errors
          +        var bind = elem.getElementsByTagName("bind");
          +        var jidNode;
          +        if (bind.length > 0) {
          +            // Grab jid
          +            jidNode = bind[0].getElementsByTagName("jid");
          +            if (jidNode.length > 0) {
          +                this.jid = Strophe.getText(jidNode[0]);
          +
          +                if (this.do_session) {
          +                    this._addSysHandler(this._sasl_session_cb.bind(this),
          +                                        null, null, null, "_session_auth_2");
          +
          +                    this.send($iq({type: "set", id: "_session_auth_2"})
          +                                  .c('session', {xmlns: Strophe.NS.SESSION})
          +                                  .tree());
          +                } else {
          +                    this.authenticated = true;
          +                    this._changeConnectStatus(Strophe.Status.CONNECTED, null);
          +                }
          +            }
          +        } else {
          +            Strophe.info("SASL binding failed.");
          +            this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
          +            return false;
          +        }
          +    },
          +
          +    /** PrivateFunction: _sasl_session_cb
          +     *  _Private_ handler to finish successful SASL connection.
          +     *
          +     *  This sets Connection.authenticated to true on success, which
          +     *  starts the processing of user handlers.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The matching stanza.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _sasl_session_cb: function (elem)
          +    {
          +        if (elem.getAttribute("type") == "result") {
          +            this.authenticated = true;
          +            this._changeConnectStatus(Strophe.Status.CONNECTED, null);
          +        } else if (elem.getAttribute("type") == "error") {
          +            Strophe.info("Session creation failed.");
          +            this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
          +            return false;
          +        }
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: _sasl_failure_cb
          +     *  _Private_ handler for SASL authentication failure.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The matching stanza.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    /* jshint unused:false */
          +    _sasl_failure_cb: function (elem)
          +    {
          +        // delete unneeded handlers
          +        if (this._sasl_success_handler) {
          +            this.deleteHandler(this._sasl_success_handler);
          +            this._sasl_success_handler = null;
          +        }
          +        if (this._sasl_challenge_handler) {
          +            this.deleteHandler(this._sasl_challenge_handler);
          +            this._sasl_challenge_handler = null;
          +        }
          +
          +        if(this._sasl_mechanism)
          +          this._sasl_mechanism.onFailure();
          +        this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
          +        return false;
          +    },
          +    /* jshint unused:true */
          +
          +    /** PrivateFunction: _auth2_cb
          +     *  _Private_ handler to finish legacy authentication.
          +     *
          +     *  This handler is called when the result from the jabber:iq:auth
          +     *  <iq/> stanza is returned.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The stanza that triggered the callback.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _auth2_cb: function (elem)
          +    {
          +        if (elem.getAttribute("type") == "result") {
          +            this.authenticated = true;
          +            this._changeConnectStatus(Strophe.Status.CONNECTED, null);
          +        } else if (elem.getAttribute("type") == "error") {
          +            this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
          +            this.disconnect('authentication failed');
          +        }
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: _addSysTimedHandler
          +     *  _Private_ function to add a system level timed handler.
          +     *
          +     *  This function is used to add a Strophe.TimedHandler for the
          +     *  library code.  System timed handlers are allowed to run before
          +     *  authentication is complete.
          +     *
          +     *  Parameters:
          +     *    (Integer) period - The period of the handler.
          +     *    (Function) handler - The callback function.
          +     */
          +    _addSysTimedHandler: function (period, handler)
          +    {
          +        var thand = new Strophe.TimedHandler(period, handler);
          +        thand.user = false;
          +        this.addTimeds.push(thand);
          +        return thand;
          +    },
          +
          +    /** PrivateFunction: _addSysHandler
          +     *  _Private_ function to add a system level stanza handler.
          +     *
          +     *  This function is used to add a Strophe.Handler for the
          +     *  library code.  System stanza handlers are allowed to run before
          +     *  authentication is complete.
          +     *
          +     *  Parameters:
          +     *    (Function) handler - The callback function.
          +     *    (String) ns - The namespace to match.
          +     *    (String) name - The stanza name to match.
          +     *    (String) type - The stanza type attribute to match.
          +     *    (String) id - The stanza id attribute to match.
          +     */
          +    _addSysHandler: function (handler, ns, name, type, id)
          +    {
          +        var hand = new Strophe.Handler(handler, ns, name, type, id);
          +        hand.user = false;
          +        this.addHandlers.push(hand);
          +        return hand;
          +    },
          +
          +    /** PrivateFunction: _onDisconnectTimeout
          +     *  _Private_ timeout handler for handling non-graceful disconnection.
          +     *
          +     *  If the graceful disconnect process does not complete within the
          +     *  time allotted, this handler finishes the disconnect anyway.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _onDisconnectTimeout: function ()
          +    {
          +        Strophe.info("_onDisconnectTimeout was called");
          +
          +        this._proto._onDisconnectTimeout();
          +
          +        // actually disconnect
          +        this._doDisconnect();
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: _onIdle
          +     *  _Private_ handler to process events during idle cycle.
          +     *
          +     *  This handler is called every 100ms to fire timed handlers that
          +     *  are ready and keep poll requests going.
          +     */
          +    _onIdle: function ()
          +    {
          +        var i, thand, since, newList;
          +
          +        // add timed handlers scheduled for addition
          +        // NOTE: we add before remove in the case a timed handler is
          +        // added and then deleted before the next _onIdle() call.
          +        while (this.addTimeds.length > 0) {
          +            this.timedHandlers.push(this.addTimeds.pop());
          +        }
          +
          +        // remove timed handlers that have been scheduled for deletion
          +        while (this.removeTimeds.length > 0) {
          +            thand = this.removeTimeds.pop();
          +            i = this.timedHandlers.indexOf(thand);
          +            if (i >= 0) {
          +                this.timedHandlers.splice(i, 1);
          +            }
          +        }
          +
          +        // call ready timed handlers
          +        var now = new Date().getTime();
          +        newList = [];
          +        for (i = 0; i < this.timedHandlers.length; i++) {
          +            thand = this.timedHandlers[i];
          +            if (this.authenticated || !thand.user) {
          +                since = thand.lastCalled + thand.period;
          +                if (since - now <= 0) {
          +                    if (thand.run()) {
          +                        newList.push(thand);
          +                    }
          +                } else {
          +                    newList.push(thand);
          +                }
          +            }
          +        }
          +        this.timedHandlers = newList;
          +
          +        clearTimeout(this._idleTimeout);
          +
          +        this._proto._onIdle();
          +
          +        // reactivate the timer only if connected
          +        if (this.connected) {
          +            this._idleTimeout = setTimeout(this._onIdle.bind(this), 100);
          +        }
          +    }
          +};
          +
          +if (callback) {
          +    callback(Strophe, $build, $msg, $iq, $pres);
          +}
          +
          +/** Class: Strophe.SASLMechanism
          + *
          + *  encapsulates SASL authentication mechanisms.
          + *
          + *  User code may override the priority for each mechanism or disable it completely.
          + *  See <priority> for information about changing priority and <test> for informatian on
          + *  how to disable a mechanism.
          + *
          + *  By default, all mechanisms are enabled and the priorities are
          + *
          + *  SCRAM-SHA1 - 40
          + *  DIGEST-MD5 - 30
          + *  Plain - 20
          + */
          +
          +/**
          + * PrivateConstructor: Strophe.SASLMechanism
          + * SASL auth mechanism abstraction.
          + *
          + *  Parameters:
          + *    (String) name - SASL Mechanism name.
          + *    (Boolean) isClientFirst - If client should send response first without challenge.
          + *    (Number) priority - Priority.
          + *
          + *  Returns:
          + *    A new Strophe.SASLMechanism object.
          + */
          +Strophe.SASLMechanism = function(name, isClientFirst, priority) {
          +  /** PrivateVariable: name
          +   *  Mechanism name.
          +   */
          +  this.name = name;
          +  /** PrivateVariable: isClientFirst
          +   *  If client sends response without initial server challenge.
          +   */
          +  this.isClientFirst = isClientFirst;
          +  /** Variable: priority
          +   *  Determines which <SASLMechanism> is chosen for authentication (Higher is better).
          +   *  Users may override this to prioritize mechanisms differently.
          +   *
          +   *  In the default configuration the priorities are
          +   *
          +   *  SCRAM-SHA1 - 40
          +   *  DIGEST-MD5 - 30
          +   *  Plain - 20
          +   *
          +   *  Example: (This will cause Strophe to choose the mechanism that the server sent first)
          +   *
          +   *  > Strophe.SASLMD5.priority = Strophe.SASLSHA1.priority;
          +   *
          +   *  See <SASL mechanisms> for a list of available mechanisms.
          +   *
          +   */
          +  this.priority = priority;
          +};
          +
          +Strophe.SASLMechanism.prototype = {
          +  /**
          +   *  Function: test
          +   *  Checks if mechanism able to run.
          +   *  To disable a mechanism, make this return false;
          +   *
          +   *  To disable plain authentication run
          +   *  > Strophe.SASLPlain.test = function() {
          +   *  >   return false;
          +   *  > }
          +   *
          +   *  See <SASL mechanisms> for a list of available mechanisms.
          +   *
          +   *  Parameters:
          +   *    (Strophe.Connection) connection - Target Connection.
          +   *
          +   *  Returns:
          +   *    (Boolean) If mechanism was able to run.
          +   */
          +  /* jshint unused:false */
          +  test: function(connection) {
          +    return true;
          +  },
          +  /* jshint unused:true */
          +
          +  /** PrivateFunction: onStart
          +   *  Called before starting mechanism on some connection.
          +   *
          +   *  Parameters:
          +   *    (Strophe.Connection) connection - Target Connection.
          +   */
          +  onStart: function(connection)
          +  {
          +    this._connection = connection;
          +  },
          +
          +  /** PrivateFunction: onChallenge
          +   *  Called by protocol implementation on incoming challenge. If client is
          +   *  first (isClientFirst == true) challenge will be null on the first call.
          +   *
          +   *  Parameters:
          +   *    (Strophe.Connection) connection - Target Connection.
          +   *    (String) challenge - current challenge to handle.
          +   *
          +   *  Returns:
          +   *    (String) Mechanism response.
          +   */
          +  /* jshint unused:false */
          +  onChallenge: function(connection, challenge) {
          +    throw new Error("You should implement challenge handling!");
          +  },
          +  /* jshint unused:true */
          +
          +  /** PrivateFunction: onFailure
          +   *  Protocol informs mechanism implementation about SASL failure.
          +   */
          +  onFailure: function() {
          +    this._connection = null;
          +  },
          +
          +  /** PrivateFunction: onSuccess
          +   *  Protocol informs mechanism implementation about SASL success.
          +   */
          +  onSuccess: function() {
          +    this._connection = null;
          +  }
          +};
          +
          +  /** Constants: SASL mechanisms
          +   *  Available authentication mechanisms
          +   *
          +   *  Strophe.SASLAnonymous - SASL Anonymous authentication.
          +   *  Strophe.SASLPlain - SASL Plain authentication.
          +   *  Strophe.SASLMD5 - SASL Digest-MD5 authentication
          +   *  Strophe.SASLSHA1 - SASL SCRAM-SHA1 authentication
          +   */
          +
          +// Building SASL callbacks
          +
          +/** PrivateConstructor: SASLAnonymous
          + *  SASL Anonymous authentication.
          + */
          +Strophe.SASLAnonymous = function() {};
          +
          +Strophe.SASLAnonymous.prototype = new Strophe.SASLMechanism("ANONYMOUS", false, 10);
          +
          +Strophe.SASLAnonymous.test = function(connection) {
          +  return connection.authcid === null;
          +};
          +
          +Strophe.Connection.prototype.mechanisms[Strophe.SASLAnonymous.prototype.name] = Strophe.SASLAnonymous;
          +
          +/** PrivateConstructor: SASLPlain
          + *  SASL Plain authentication.
          + */
          +Strophe.SASLPlain = function() {};
          +
          +Strophe.SASLPlain.prototype = new Strophe.SASLMechanism("PLAIN", true, 20);
          +
          +Strophe.SASLPlain.test = function(connection) {
          +  return connection.authcid !== null;
          +};
          +
          +Strophe.SASLPlain.prototype.onChallenge = function(connection) {
          +  var auth_str = connection.authzid;
          +  auth_str = auth_str + "\u0000";
          +  auth_str = auth_str + connection.authcid;
          +  auth_str = auth_str + "\u0000";
          +  auth_str = auth_str + connection.pass;
          +  return auth_str;
          +};
          +
          +Strophe.Connection.prototype.mechanisms[Strophe.SASLPlain.prototype.name] = Strophe.SASLPlain;
          +
          +/** PrivateConstructor: SASLSHA1
          + *  SASL SCRAM SHA 1 authentication.
          + */
          +Strophe.SASLSHA1 = function() {};
          +
          +/* TEST:
          + * This is a simple example of a SCRAM-SHA-1 authentication exchange
          + * when the client doesn't support channel bindings (username 'user' and
          + * password 'pencil' are used):
          + *
          + * C: n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL
          + * S: r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,
          + * i=4096
          + * C: c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,
          + * p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=
          + * S: v=rmF9pqV8S7suAoZWja4dJRkFsKQ=
          + *
          + */
          +
          +Strophe.SASLSHA1.prototype = new Strophe.SASLMechanism("SCRAM-SHA-1", true, 40);
          +
          +Strophe.SASLSHA1.test = function(connection) {
          +  return connection.authcid !== null;
          +};
          +
          +Strophe.SASLSHA1.prototype.onChallenge = function(connection, challenge, test_cnonce) {
          +  var cnonce = test_cnonce || MD5.hexdigest(Math.random() * 1234567890);
          +
          +  var auth_str = "n=" + connection.authcid;
          +  auth_str += ",r=";
          +  auth_str += cnonce;
          +
          +  connection._sasl_data.cnonce = cnonce;
          +  connection._sasl_data["client-first-message-bare"] = auth_str;
          +
          +  auth_str = "n,," + auth_str;
          +
          +  this.onChallenge = function (connection, challenge)
          +  {
          +    var nonce, salt, iter, Hi, U, U_old, i, k;
          +    var clientKey, serverKey, clientSignature;
          +    var responseText = "c=biws,";
          +    var authMessage = connection._sasl_data["client-first-message-bare"] + "," +
          +      challenge + ",";
          +    var cnonce = connection._sasl_data.cnonce;
          +    var attribMatch = /([a-z]+)=([^,]+)(,|$)/;
          +
          +    while (challenge.match(attribMatch)) {
          +      var matches = challenge.match(attribMatch);
          +      challenge = challenge.replace(matches[0], "");
          +      switch (matches[1]) {
          +      case "r":
          +        nonce = matches[2];
          +        break;
          +      case "s":
          +        salt = matches[2];
          +        break;
          +      case "i":
          +        iter = matches[2];
          +        break;
          +      }
          +    }
          +
          +    if (nonce.substr(0, cnonce.length) !== cnonce) {
          +      connection._sasl_data = {};
          +      return connection._sasl_failure_cb();
          +    }
          +
          +    responseText += "r=" + nonce;
          +    authMessage += responseText;
          +
          +    salt = Base64.decode(salt);
          +    salt += "\x00\x00\x00\x01";
          +
          +    Hi = U_old = core_hmac_sha1(connection.pass, salt);
          +    for (i = 1; i < iter; i++) {
          +      U = core_hmac_sha1(connection.pass, binb2str(U_old));
          +      for (k = 0; k < 5; k++) {
          +        Hi[k] ^= U[k];
          +      }
          +      U_old = U;
          +    }
          +    Hi = binb2str(Hi);
          +
          +    clientKey = core_hmac_sha1(Hi, "Client Key");
          +    serverKey = str_hmac_sha1(Hi, "Server Key");
          +    clientSignature = core_hmac_sha1(str_sha1(binb2str(clientKey)), authMessage);
          +    connection._sasl_data["server-signature"] = b64_hmac_sha1(serverKey, authMessage);
          +
          +    for (k = 0; k < 5; k++) {
          +      clientKey[k] ^= clientSignature[k];
          +    }
          +
          +    responseText += ",p=" + Base64.encode(binb2str(clientKey));
          +
          +    return responseText;
          +  }.bind(this);
          +
          +  return auth_str;
          +};
          +
          +Strophe.Connection.prototype.mechanisms[Strophe.SASLSHA1.prototype.name] = Strophe.SASLSHA1;
          +
          +/** PrivateConstructor: SASLMD5
          + *  SASL DIGEST MD5 authentication.
          + */
          +Strophe.SASLMD5 = function() {};
          +
          +Strophe.SASLMD5.prototype = new Strophe.SASLMechanism("DIGEST-MD5", false, 30);
          +
          +Strophe.SASLMD5.test = function(connection) {
          +  return connection.authcid !== null;
          +};
          +
          +/** PrivateFunction: _quote
          + *  _Private_ utility function to backslash escape and quote strings.
          + *
          + *  Parameters:
          + *    (String) str - The string to be quoted.
          + *
          + *  Returns:
          + *    quoted string
          + */
          +Strophe.SASLMD5.prototype._quote = function (str)
          +  {
          +    return '"' + str.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '"';
          +    //" end string workaround for emacs
          +  };
          +
          +
          +Strophe.SASLMD5.prototype.onChallenge = function(connection, challenge, test_cnonce) {
          +  var attribMatch = /([a-z]+)=("[^"]+"|[^,"]+)(?:,|$)/;
          +  var cnonce = test_cnonce || MD5.hexdigest("" + (Math.random() * 1234567890));
          +  var realm = "";
          +  var host = null;
          +  var nonce = "";
          +  var qop = "";
          +  var matches;
          +
          +  while (challenge.match(attribMatch)) {
          +    matches = challenge.match(attribMatch);
          +    challenge = challenge.replace(matches[0], "");
          +    matches[2] = matches[2].replace(/^"(.+)"$/, "$1");
          +    switch (matches[1]) {
          +    case "realm":
          +      realm = matches[2];
          +      break;
          +    case "nonce":
          +      nonce = matches[2];
          +      break;
          +    case "qop":
          +      qop = matches[2];
          +      break;
          +    case "host":
          +      host = matches[2];
          +      break;
          +    }
          +  }
          +
          +  var digest_uri = connection.servtype + "/" + connection.domain;
          +  if (host !== null) {
          +    digest_uri = digest_uri + "/" + host;
          +  }
          +
          +  var A1 = MD5.hash(connection.authcid +
          +                    ":" + realm + ":" + this._connection.pass) +
          +    ":" + nonce + ":" + cnonce;
          +  var A2 = 'AUTHENTICATE:' + digest_uri;
          +
          +  var responseText = "";
          +  responseText += 'charset=utf-8,';
          +  responseText += 'username=' +
          +    this._quote(connection.authcid) + ',';
          +  responseText += 'realm=' + this._quote(realm) + ',';
          +  responseText += 'nonce=' + this._quote(nonce) + ',';
          +  responseText += 'nc=00000001,';
          +  responseText += 'cnonce=' + this._quote(cnonce) + ',';
          +  responseText += 'digest-uri=' + this._quote(digest_uri) + ',';
          +  responseText += 'response=' + MD5.hexdigest(MD5.hexdigest(A1) + ":" +
          +                                              nonce + ":00000001:" +
          +                                              cnonce + ":auth:" +
          +                                              MD5.hexdigest(A2)) + ",";
          +  responseText += 'qop=auth';
          +
          +  this.onChallenge = function ()
          +  {
          +    return "";
          +  }.bind(this);
          +
          +  return responseText;
          +};
          +
          +Strophe.Connection.prototype.mechanisms[Strophe.SASLMD5.prototype.name] = Strophe.SASLMD5;
          +
          +})(function () {
          +    window.Strophe = arguments[0];
          +    window.$build = arguments[1];
          +    window.$msg = arguments[2];
          +    window.$iq = arguments[3];
          +    window.$pres = arguments[4];
          +});
          +
          +/*
          +    This program is distributed under the terms of the MIT license.
          +    Please see the LICENSE file for details.
          +
          +    Copyright 2006-2008, OGG, LLC
          +*/
          +
          +/* jshint undef: true, unused: true:, noarg: true, latedef: true */
          +/*global window, setTimeout, clearTimeout,
          +    XMLHttpRequest, ActiveXObject,
          +    Strophe, $build */
          +
          +
          +/** PrivateClass: Strophe.Request
          + *  _Private_ helper class that provides a cross implementation abstraction
          + *  for a BOSH related XMLHttpRequest.
          + *
          + *  The Strophe.Request class is used internally to encapsulate BOSH request
          + *  information.  It is not meant to be used from user's code.
          + */
          +
          +/** PrivateConstructor: Strophe.Request
          + *  Create and initialize a new Strophe.Request object.
          + *
          + *  Parameters:
          + *    (XMLElement) elem - The XML data to be sent in the request.
          + *    (Function) func - The function that will be called when the
          + *      XMLHttpRequest readyState changes.
          + *    (Integer) rid - The BOSH rid attribute associated with this request.
          + *    (Integer) sends - The number of times this same request has been
          + *      sent.
          + */
          +Strophe.Request = function (elem, func, rid, sends)
          +{
          +    this.id = ++Strophe._requestId;
          +    this.xmlData = elem;
          +    this.data = Strophe.serialize(elem);
          +    // save original function in case we need to make a new request
          +    // from this one.
          +    this.origFunc = func;
          +    this.func = func;
          +    this.rid = rid;
          +    this.date = NaN;
          +    this.sends = sends || 0;
          +    this.abort = false;
          +    this.dead = null;
          +
          +    this.age = function () {
          +        if (!this.date) { return 0; }
          +        var now = new Date();
          +        return (now - this.date) / 1000;
          +    };
          +    this.timeDead = function () {
          +        if (!this.dead) { return 0; }
          +        var now = new Date();
          +        return (now - this.dead) / 1000;
          +    };
          +    this.xhr = this._newXHR();
          +};
          +
          +Strophe.Request.prototype = {
          +    /** PrivateFunction: getResponse
          +     *  Get a response from the underlying XMLHttpRequest.
          +     *
          +     *  This function attempts to get a response from the request and checks
          +     *  for errors.
          +     *
          +     *  Throws:
          +     *    "parsererror" - A parser error occured.
          +     *
          +     *  Returns:
          +     *    The DOM element tree of the response.
          +     */
          +    getResponse: function ()
          +    {
          +        var node = null;
          +        if (this.xhr.responseXML && this.xhr.responseXML.documentElement) {
          +            node = this.xhr.responseXML.documentElement;
          +            if (node.tagName == "parsererror") {
          +                Strophe.error("invalid response received");
          +                Strophe.error("responseText: " + this.xhr.responseText);
          +                Strophe.error("responseXML: " +
          +                              Strophe.serialize(this.xhr.responseXML));
          +                throw "parsererror";
          +            }
          +        } else if (this.xhr.responseText) {
          +            Strophe.error("invalid response received");
          +            Strophe.error("responseText: " + this.xhr.responseText);
          +            Strophe.error("responseXML: " +
          +                          Strophe.serialize(this.xhr.responseXML));
          +        }
          +
          +        return node;
          +    },
          +
          +    /** PrivateFunction: _newXHR
          +     *  _Private_ helper function to create XMLHttpRequests.
          +     *
          +     *  This function creates XMLHttpRequests across all implementations.
          +     *
          +     *  Returns:
          +     *    A new XMLHttpRequest.
          +     */
          +    _newXHR: function ()
          +    {
          +        var xhr = null;
          +        if (window.XMLHttpRequest) {
          +            xhr = new XMLHttpRequest();
          +            if (xhr.overrideMimeType) {
          +                xhr.overrideMimeType("text/xml");
          +            }
          +        } else if (window.ActiveXObject) {
          +            xhr = new ActiveXObject("Microsoft.XMLHTTP");
          +        }
          +
          +        // use Function.bind() to prepend ourselves as an argument
          +        xhr.onreadystatechange = this.func.bind(null, this);
          +
          +        return xhr;
          +    }
          +};
          +
          +/** Class: Strophe.Bosh
          + *  _Private_ helper class that handles BOSH Connections
          + *
          + *  The Strophe.Bosh class is used internally by Strophe.Connection
          + *  to encapsulate BOSH sessions. It is not meant to be used from user's code.
          + */
          +
          +/** File: bosh.js
          + *  A JavaScript library to enable BOSH in Strophejs.
          + *
          + *  this library uses Bidirectional-streams Over Synchronous HTTP (BOSH)
          + *  to emulate a persistent, stateful, two-way connection to an XMPP server.
          + *  More information on BOSH can be found in XEP 124.
          + */
          +
          +/** PrivateConstructor: Strophe.Bosh
          + *  Create and initialize a Strophe.Bosh object.
          + *
          + *  Parameters:
          + *    (Strophe.Connection) connection - The Strophe.Connection that will use BOSH.
          + *
          + *  Returns:
          + *    A new Strophe.Bosh object.
          + */
          +Strophe.Bosh = function(connection) {
          +    this._conn = connection;
          +    /* request id for body tags */
          +    this.rid = Math.floor(Math.random() * 4294967295);
          +    /* The current session ID. */
          +    this.sid = null;
          +
          +    // default BOSH values
          +    this.hold = 1;
          +    this.wait = 60;
          +    this.window = 5;
          +
          +    this._requests = [];
          +};
          +
          +Strophe.Bosh.prototype = {
          +    /** Variable: strip
          +     *
          +     *  BOSH-Connections will have all stanzas wrapped in a <body> tag when
          +     *  passed to <Strophe.Connection.xmlInput> or <Strophe.Connection.xmlOutput>.
          +     *  To strip this tag, User code can set <Strophe.Bosh.strip> to "body":
          +     *
          +     *  > Strophe.Bosh.prototype.strip = "body";
          +     *
          +     *  This will enable stripping of the body tag in both
          +     *  <Strophe.Connection.xmlInput> and <Strophe.Connection.xmlOutput>.
          +     */
          +    strip: null,
          +
          +    /** PrivateFunction: _buildBody
          +     *  _Private_ helper function to generate the <body/> wrapper for BOSH.
          +     *
          +     *  Returns:
          +     *    A Strophe.Builder with a <body/> element.
          +     */
          +    _buildBody: function ()
          +    {
          +        var bodyWrap = $build('body', {
          +            rid: this.rid++,
          +            xmlns: Strophe.NS.HTTPBIND
          +        });
          +
          +        if (this.sid !== null) {
          +            bodyWrap.attrs({sid: this.sid});
          +        }
          +
          +        return bodyWrap;
          +    },
          +
          +    /** PrivateFunction: _reset
          +     *  Reset the connection.
          +     *
          +     *  This function is called by the reset function of the Strophe Connection
          +     */
          +    _reset: function ()
          +    {
          +        this.rid = Math.floor(Math.random() * 4294967295);
          +        this.sid = null;
          +    },
          +
          +    /** PrivateFunction: _connect
          +     *  _Private_ function that initializes the BOSH connection.
          +     *
          +     *  Creates and sends the Request that initializes the BOSH connection.
          +     */
          +    _connect: function (wait, hold, route)
          +    {
          +        this.wait = wait || this.wait;
          +        this.hold = hold || this.hold;
          +
          +        // build the body tag
          +        var body = this._buildBody().attrs({
          +            to: this._conn.domain,
          +            "xml:lang": "en",
          +            wait: this.wait,
          +            hold: this.hold,
          +            content: "text/xml; charset=utf-8",
          +            ver: "1.6",
          +            "xmpp:version": "1.0",
          +            "xmlns:xmpp": Strophe.NS.BOSH
          +        });
          +
          +        if(route){
          +            body.attrs({
          +                route: route
          +            });
          +        }
          +
          +        var _connect_cb = this._conn._connect_cb;
          +
          +        this._requests.push(
          +            new Strophe.Request(body.tree(),
          +                                this._onRequestStateChange.bind(
          +                                    this, _connect_cb.bind(this._conn)),
          +                                body.tree().getAttribute("rid")));
          +        this._throttledRequestHandler();
          +    },
          +
          +    /** PrivateFunction: _attach
          +     *  Attach to an already created and authenticated BOSH session.
          +     *
          +     *  This function is provided to allow Strophe to attach to BOSH
          +     *  sessions which have been created externally, perhaps by a Web
          +     *  application.  This is often used to support auto-login type features
          +     *  without putting user credentials into the page.
          +     *
          +     *  Parameters:
          +     *    (String) jid - The full JID that is bound by the session.
          +     *    (String) sid - The SID of the BOSH session.
          +     *    (String) rid - The current RID of the BOSH session.  This RID
          +     *      will be used by the next request.
          +     *    (Function) callback The connect callback function.
          +     *    (Integer) wait - The optional HTTPBIND wait value.  This is the
          +     *      time the server will wait before returning an empty result for
          +     *      a request.  The default setting of 60 seconds is recommended.
          +     *      Other settings will require tweaks to the Strophe.TIMEOUT value.
          +     *    (Integer) hold - The optional HTTPBIND hold value.  This is the
          +     *      number of connections the server will hold at one time.  This
          +     *      should almost always be set to 1 (the default).
          +     *    (Integer) wind - The optional HTTBIND window value.  This is the
          +     *      allowed range of request ids that are valid.  The default is 5.
          +     */
          +    _attach: function (jid, sid, rid, callback, wait, hold, wind)
          +    {
          +        this._conn.jid = jid;
          +        this.sid = sid;
          +        this.rid = rid;
          +
          +        this._conn.connect_callback = callback;
          +
          +        this._conn.domain = Strophe.getDomainFromJid(this._conn.jid);
          +
          +        this._conn.authenticated = true;
          +        this._conn.connected = true;
          +
          +        this.wait = wait || this.wait;
          +        this.hold = hold || this.hold;
          +        this.window = wind || this.window;
          +
          +        this._conn._changeConnectStatus(Strophe.Status.ATTACHED, null);
          +    },
          +
          +    /** PrivateFunction: _connect_cb
          +     *  _Private_ handler for initial connection request.
          +     *
          +     *  This handler is used to process the Bosh-part of the initial request.
          +     *  Parameters:
          +     *    (Strophe.Request) bodyWrap - The received stanza.
          +     */
          +    _connect_cb: function (bodyWrap)
          +    {
          +        var typ = bodyWrap.getAttribute("type");
          +        var cond, conflict;
          +        if (typ !== null && typ == "terminate") {
          +            // an error occurred
          +            Strophe.error("BOSH-Connection failed: " + cond);
          +            cond = bodyWrap.getAttribute("condition");
          +            conflict = bodyWrap.getElementsByTagName("conflict");
          +            if (cond !== null) {
          +                if (cond == "remote-stream-error" && conflict.length > 0) {
          +                    cond = "conflict";
          +                }
          +                this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, cond);
          +            } else {
          +                this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "unknown");
          +            }
          +            this._conn._doDisconnect();
          +            return Strophe.Status.CONNFAIL;
          +        }
          +
          +        // check to make sure we don't overwrite these if _connect_cb is
          +        // called multiple times in the case of missing stream:features
          +        if (!this.sid) {
          +            this.sid = bodyWrap.getAttribute("sid");
          +        }
          +        var wind = bodyWrap.getAttribute('requests');
          +        if (wind) { this.window = parseInt(wind, 10); }
          +        var hold = bodyWrap.getAttribute('hold');
          +        if (hold) { this.hold = parseInt(hold, 10); }
          +        var wait = bodyWrap.getAttribute('wait');
          +        if (wait) { this.wait = parseInt(wait, 10); }
          +    },
          +
          +    /** PrivateFunction: _disconnect
          +     *  _Private_ part of Connection.disconnect for Bosh
          +     *
          +     *  Parameters:
          +     *    (Request) pres - This stanza will be sent before disconnecting.
          +     */
          +    _disconnect: function (pres)
          +    {
          +        this._sendTerminate(pres);
          +    },
          +
          +    /** PrivateFunction: _doDisconnect
          +     *  _Private_ function to disconnect.
          +     *
          +     *  Resets the SID and RID.
          +     */
          +    _doDisconnect: function ()
          +    {
          +        this.sid = null;
          +        this.rid = Math.floor(Math.random() * 4294967295);
          +    },
          +
          +    /** PrivateFunction: _emptyQueue
          +     * _Private_ function to check if the Request queue is empty.
          +     *
          +     *  Returns:
          +     *    True, if there are no Requests queued, False otherwise.
          +     */
          +    _emptyQueue: function ()
          +    {
          +        return this._requests.length === 0;
          +    },
          +
          +    /** PrivateFunction: _hitError
          +     *  _Private_ function to handle the error count.
          +     *
          +     *  Requests are resent automatically until their error count reaches
          +     *  5.  Each time an error is encountered, this function is called to
          +     *  increment the count and disconnect if the count is too high.
          +     *
          +     *  Parameters:
          +     *    (Integer) reqStatus - The request status.
          +     */
          +    _hitError: function (reqStatus)
          +    {
          +        this.errors++;
          +        Strophe.warn("request errored, status: " + reqStatus +
          +                     ", number of errors: " + this.errors);
          +        if (this.errors > 4) {
          +            this._onDisconnectTimeout();
          +        }
          +    },
          +
          +    /** PrivateFunction: _no_auth_received
          +     *
          +     * Called on stream start/restart when no stream:features
          +     * has been received and sends a blank poll request.
          +     */
          +    _no_auth_received: function (_callback)
          +    {
          +        if (_callback) {
          +            _callback = _callback.bind(this._conn);
          +        } else {
          +            _callback = this._conn._connect_cb.bind(this._conn);
          +        }
          +        var body = this._buildBody();
          +        this._requests.push(
          +                new Strophe.Request(body.tree(),
          +                    this._onRequestStateChange.bind(
          +                        this, _callback.bind(this._conn)),
          +                    body.tree().getAttribute("rid")));
          +        this._throttledRequestHandler();
          +    },
          +
          +    /** PrivateFunction: _onDisconnectTimeout
          +     *  _Private_ timeout handler for handling non-graceful disconnection.
          +     *
          +     *  Cancels all remaining Requests and clears the queue.
          +     */
          +    _onDisconnectTimeout: function ()
          +    {
          +        var req;
          +        while (this._requests.length > 0) {
          +            req = this._requests.pop();
          +            req.abort = true;
          +            req.xhr.abort();
          +            // jslint complains, but this is fine. setting to empty func
          +            // is necessary for IE6
          +            req.xhr.onreadystatechange = function () {}; // jshint ignore:line
          +        }
          +    },
          +
          +    /** PrivateFunction: _onIdle
          +     *  _Private_ handler called by Strophe.Connection._onIdle
          +     *
          +     *  Sends all queued Requests or polls with empty Request if there are none.
          +     */
          +    _onIdle: function () {
          +        var data = this._conn._data;
          +
          +        // if no requests are in progress, poll
          +        if (this._conn.authenticated && this._requests.length === 0 &&
          +            data.length === 0 && !this._conn.disconnecting) {
          +            Strophe.info("no requests during idle cycle, sending " +
          +                         "blank request");
          +            data.push(null);
          +        }
          +
          +        if (this._requests.length < 2 && data.length > 0 &&
          +            !this._conn.paused) {
          +            var body = this._buildBody();
          +            for (var i = 0; i < data.length; i++) {
          +                if (data[i] !== null) {
          +                    if (data[i] === "restart") {
          +                        body.attrs({
          +                            to: this._conn.domain,
          +                            "xml:lang": "en",
          +                            "xmpp:restart": "true",
          +                            "xmlns:xmpp": Strophe.NS.BOSH
          +                        });
          +                    } else {
          +                        body.cnode(data[i]).up();
          +                    }
          +                }
          +            }
          +            delete this._conn._data;
          +            this._conn._data = [];
          +            this._requests.push(
          +                new Strophe.Request(body.tree(),
          +                                    this._onRequestStateChange.bind(
          +                                        this, this._conn._dataRecv.bind(this._conn)),
          +                                    body.tree().getAttribute("rid")));
          +            this._processRequest(this._requests.length - 1);
          +        }
          +
          +        if (this._requests.length > 0) {
          +            var time_elapsed = this._requests[0].age();
          +            if (this._requests[0].dead !== null) {
          +                if (this._requests[0].timeDead() >
          +                    Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait)) {
          +                    this._throttledRequestHandler();
          +                }
          +            }
          +
          +            if (time_elapsed > Math.floor(Strophe.TIMEOUT * this.wait)) {
          +                Strophe.warn("Request " +
          +                             this._requests[0].id +
          +                             " timed out, over " + Math.floor(Strophe.TIMEOUT * this.wait) +
          +                             " seconds since last activity");
          +                this._throttledRequestHandler();
          +            }
          +        }
          +    },
          +
          +    /** PrivateFunction: _onRequestStateChange
          +     *  _Private_ handler for Strophe.Request state changes.
          +     *
          +     *  This function is called when the XMLHttpRequest readyState changes.
          +     *  It contains a lot of error handling logic for the many ways that
          +     *  requests can fail, and calls the request callback when requests
          +     *  succeed.
          +     *
          +     *  Parameters:
          +     *    (Function) func - The handler for the request.
          +     *    (Strophe.Request) req - The request that is changing readyState.
          +     */
          +    _onRequestStateChange: function (func, req)
          +    {
          +        Strophe.debug("request id " + req.id +
          +                      "." + req.sends + " state changed to " +
          +                      req.xhr.readyState);
          +
          +        if (req.abort) {
          +            req.abort = false;
          +            return;
          +        }
          +
          +        // request complete
          +        var reqStatus;
          +        if (req.xhr.readyState == 4) {
          +            reqStatus = 0;
          +            try {
          +                reqStatus = req.xhr.status;
          +            } catch (e) {
          +                // ignore errors from undefined status attribute.  works
          +                // around a browser bug
          +            }
          +
          +            if (typeof(reqStatus) == "undefined") {
          +                reqStatus = 0;
          +            }
          +
          +            if (this.disconnecting) {
          +                if (reqStatus >= 400) {
          +                    this._hitError(reqStatus);
          +                    return;
          +                }
          +            }
          +
          +            var reqIs0 = (this._requests[0] == req);
          +            var reqIs1 = (this._requests[1] == req);
          +
          +            if ((reqStatus > 0 && reqStatus < 500) || req.sends > 5) {
          +                // remove from internal queue
          +                this._removeRequest(req);
          +                Strophe.debug("request id " +
          +                              req.id +
          +                              " should now be removed");
          +            }
          +
          +            // request succeeded
          +            if (reqStatus == 200) {
          +                // if request 1 finished, or request 0 finished and request
          +                // 1 is over Strophe.SECONDARY_TIMEOUT seconds old, we need to
          +                // restart the other - both will be in the first spot, as the
          +                // completed request has been removed from the queue already
          +                if (reqIs1 ||
          +                    (reqIs0 && this._requests.length > 0 &&
          +                     this._requests[0].age() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait))) {
          +                    this._restartRequest(0);
          +                }
          +                // call handler
          +                Strophe.debug("request id " +
          +                              req.id + "." +
          +                              req.sends + " got 200");
          +                func(req);
          +                this.errors = 0;
          +            } else {
          +                Strophe.error("request id " +
          +                              req.id + "." +
          +                              req.sends + " error " + reqStatus +
          +                              " happened");
          +                if (reqStatus === 0 ||
          +                    (reqStatus >= 400 && reqStatus < 600) ||
          +                    reqStatus >= 12000) {
          +                    this._hitError(reqStatus);
          +                    if (reqStatus >= 400 && reqStatus < 500) {
          +                        this._conn._changeConnectStatus(Strophe.Status.DISCONNECTING,
          +                                                  null);
          +                        this._conn._doDisconnect();
          +                    }
          +                }
          +            }
          +
          +            if (!((reqStatus > 0 && reqStatus < 500) ||
          +                  req.sends > 5)) {
          +                this._throttledRequestHandler();
          +            }
          +        }
          +    },
          +
          +    /** PrivateFunction: _processRequest
          +     *  _Private_ function to process a request in the queue.
          +     *
          +     *  This function takes requests off the queue and sends them and
          +     *  restarts dead requests.
          +     *
          +     *  Parameters:
          +     *    (Integer) i - The index of the request in the queue.
          +     */
          +    _processRequest: function (i)
          +    {
          +        var self = this;
          +        var req = this._requests[i];
          +        var reqStatus = -1;
          +
          +        try {
          +            if (req.xhr.readyState == 4) {
          +                reqStatus = req.xhr.status;
          +            }
          +        } catch (e) {
          +            Strophe.error("caught an error in _requests[" + i +
          +                          "], reqStatus: " + reqStatus);
          +        }
          +
          +        if (typeof(reqStatus) == "undefined") {
          +            reqStatus = -1;
          +        }
          +
          +        // make sure we limit the number of retries
          +        if (req.sends > this.maxRetries) {
          +            this._onDisconnectTimeout();
          +            return;
          +        }
          +
          +        var time_elapsed = req.age();
          +        var primaryTimeout = (!isNaN(time_elapsed) &&
          +                              time_elapsed > Math.floor(Strophe.TIMEOUT * this.wait));
          +        var secondaryTimeout = (req.dead !== null &&
          +                                req.timeDead() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait));
          +        var requestCompletedWithServerError = (req.xhr.readyState == 4 &&
          +                                               (reqStatus < 1 ||
          +                                                reqStatus >= 500));
          +        if (primaryTimeout || secondaryTimeout ||
          +            requestCompletedWithServerError) {
          +            if (secondaryTimeout) {
          +                Strophe.error("Request " +
          +                              this._requests[i].id +
          +                              " timed out (secondary), restarting");
          +            }
          +            req.abort = true;
          +            req.xhr.abort();
          +            // setting to null fails on IE6, so set to empty function
          +            req.xhr.onreadystatechange = function () {};
          +            this._requests[i] = new Strophe.Request(req.xmlData,
          +                                                    req.origFunc,
          +                                                    req.rid,
          +                                                    req.sends);
          +            req = this._requests[i];
          +        }
          +
          +        if (req.xhr.readyState === 0) {
          +            Strophe.debug("request id " + req.id +
          +                          "." + req.sends + " posting");
          +
          +            try {
          +                req.xhr.open("POST", this._conn.service, this._conn.options.sync ? false : true);
          +            } catch (e2) {
          +                Strophe.error("XHR open failed.");
          +                if (!this._conn.connected) {
          +                    this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,
          +                                              "bad-service");
          +                }
          +                this._conn.disconnect();
          +                return;
          +            }
          +
          +            // Fires the XHR request -- may be invoked immediately
          +            // or on a gradually expanding retry window for reconnects
          +            var sendFunc = function () {
          +                req.date = new Date();
          +                if (self._conn.options.customHeaders){
          +                    var headers = self._conn.options.customHeaders;
          +                    for (var header in headers) {
          +                        if (headers.hasOwnProperty(header)) {
          +                            req.xhr.setRequestHeader(header, headers[header]);
          +                        }
          +                    }
          +                }
          +                req.xhr.send(req.data);
          +            };
          +
          +            // Implement progressive backoff for reconnects --
          +            // First retry (send == 1) should also be instantaneous
          +            if (req.sends > 1) {
          +                // Using a cube of the retry number creates a nicely
          +                // expanding retry window
          +                var backoff = Math.min(Math.floor(Strophe.TIMEOUT * this.wait),
          +                                       Math.pow(req.sends, 3)) * 1000;
          +                setTimeout(sendFunc, backoff);
          +            } else {
          +                sendFunc();
          +            }
          +
          +            req.sends++;
          +
          +            if (this._conn.xmlOutput !== Strophe.Connection.prototype.xmlOutput) {
          +                if (req.xmlData.nodeName === this.strip && req.xmlData.childNodes.length) {
          +                    this._conn.xmlOutput(req.xmlData.childNodes[0]);
          +                } else {
          +                    this._conn.xmlOutput(req.xmlData);
          +                }
          +            }
          +            if (this._conn.rawOutput !== Strophe.Connection.prototype.rawOutput) {
          +                this._conn.rawOutput(req.data);
          +            }
          +        } else {
          +            Strophe.debug("_processRequest: " +
          +                          (i === 0 ? "first" : "second") +
          +                          " request has readyState of " +
          +                          req.xhr.readyState);
          +        }
          +    },
          +
          +    /** PrivateFunction: _removeRequest
          +     *  _Private_ function to remove a request from the queue.
          +     *
          +     *  Parameters:
          +     *    (Strophe.Request) req - The request to remove.
          +     */
          +    _removeRequest: function (req)
          +    {
          +        Strophe.debug("removing request");
          +
          +        var i;
          +        for (i = this._requests.length - 1; i >= 0; i--) {
          +            if (req == this._requests[i]) {
          +                this._requests.splice(i, 1);
          +            }
          +        }
          +
          +        // IE6 fails on setting to null, so set to empty function
          +        req.xhr.onreadystatechange = function () {};
          +
          +        this._throttledRequestHandler();
          +    },
          +
          +    /** PrivateFunction: _restartRequest
          +     *  _Private_ function to restart a request that is presumed dead.
          +     *
          +     *  Parameters:
          +     *    (Integer) i - The index of the request in the queue.
          +     */
          +    _restartRequest: function (i)
          +    {
          +        var req = this._requests[i];
          +        if (req.dead === null) {
          +            req.dead = new Date();
          +        }
          +
          +        this._processRequest(i);
          +    },
          +
          +    /** PrivateFunction: _reqToData
          +     * _Private_ function to get a stanza out of a request.
          +     *
          +     * Tries to extract a stanza out of a Request Object.
          +     * When this fails the current connection will be disconnected.
          +     *
          +     *  Parameters:
          +     *    (Object) req - The Request.
          +     *
          +     *  Returns:
          +     *    The stanza that was passed.
          +     */
          +    _reqToData: function (req)
          +    {
          +        try {
          +            return req.getResponse();
          +        } catch (e) {
          +            if (e != "parsererror") { throw e; }
          +            this._conn.disconnect("strophe-parsererror");
          +        }
          +    },
          +
          +    /** PrivateFunction: _sendTerminate
          +     *  _Private_ function to send initial disconnect sequence.
          +     *
          +     *  This is the first step in a graceful disconnect.  It sends
          +     *  the BOSH server a terminate body and includes an unavailable
          +     *  presence if authentication has completed.
          +     */
          +    _sendTerminate: function (pres)
          +    {
          +        Strophe.info("_sendTerminate was called");
          +        var body = this._buildBody().attrs({type: "terminate"});
          +
          +        if (pres) {
          +            body.cnode(pres.tree());
          +        }
          +
          +        var req = new Strophe.Request(body.tree(),
          +                                      this._onRequestStateChange.bind(
          +                                          this, this._conn._dataRecv.bind(this._conn)),
          +                                      body.tree().getAttribute("rid"));
          +
          +        this._requests.push(req);
          +        this._throttledRequestHandler();
          +    },
          +
          +    /** PrivateFunction: _send
          +     *  _Private_ part of the Connection.send function for BOSH
          +     *
          +     * Just triggers the RequestHandler to send the messages that are in the queue
          +     */
          +    _send: function () {
          +        clearTimeout(this._conn._idleTimeout);
          +        this._throttledRequestHandler();
          +        this._conn._idleTimeout = setTimeout(this._conn._onIdle.bind(this._conn), 100);
          +    },
          +
          +    /** PrivateFunction: _sendRestart
          +     *
          +     *  Send an xmpp:restart stanza.
          +     */
          +    _sendRestart: function ()
          +    {
          +        this._throttledRequestHandler();
          +        clearTimeout(this._conn._idleTimeout);
          +    },
          +
          +    /** PrivateFunction: _throttledRequestHandler
          +     *  _Private_ function to throttle requests to the connection window.
          +     *
          +     *  This function makes sure we don't send requests so fast that the
          +     *  request ids overflow the connection window in the case that one
          +     *  request died.
          +     */
          +    _throttledRequestHandler: function ()
          +    {
          +        if (!this._requests) {
          +            Strophe.debug("_throttledRequestHandler called with " +
          +                          "undefined requests");
          +        } else {
          +            Strophe.debug("_throttledRequestHandler called with " +
          +                          this._requests.length + " requests");
          +        }
          +
          +        if (!this._requests || this._requests.length === 0) {
          +            return;
          +        }
          +
          +        if (this._requests.length > 0) {
          +            this._processRequest(0);
          +        }
          +
          +        if (this._requests.length > 1 &&
          +            Math.abs(this._requests[0].rid -
          +                     this._requests[1].rid) < this.window) {
          +            this._processRequest(1);
          +        }
          +    }
          +};
          +
          +/*
          +    This program is distributed under the terms of the MIT license.
          +    Please see the LICENSE file for details.
          +
          +    Copyright 2006-2008, OGG, LLC
          +*/
          +
          +/* jshint undef: true, unused: true:, noarg: true, latedef: true */
          +/*global document, window, clearTimeout, WebSocket,
          +    DOMParser, Strophe, $build */
          +
          +/** Class: Strophe.WebSocket
          + *  _Private_ helper class that handles WebSocket Connections
          + *
          + *  The Strophe.WebSocket class is used internally by Strophe.Connection
          + *  to encapsulate WebSocket sessions. It is not meant to be used from user's code.
          + */
          +
          +/** File: websocket.js
          + *  A JavaScript library to enable XMPP over Websocket in Strophejs.
          + *
          + *  This file implements XMPP over WebSockets for Strophejs.
          + *  If a Connection is established with a Websocket url (ws://...)
          + *  Strophe will use WebSockets.
          + *  For more information on XMPP-over WebSocket see this RFC draft:
          + *  http://tools.ietf.org/html/draft-ietf-xmpp-websocket-00
          + *
          + *  WebSocket support implemented by Andreas Guth (andreas.guth@rwth-aachen.de)
          + */
          +
          +/** PrivateConstructor: Strophe.Websocket
          + *  Create and initialize a Strophe.WebSocket object.
          + *  Currently only sets the connection Object.
          + *
          + *  Parameters:
          + *    (Strophe.Connection) connection - The Strophe.Connection that will use WebSockets.
          + *
          + *  Returns:
          + *    A new Strophe.WebSocket object.
          + */
          +Strophe.Websocket = function(connection) {
          +    this._conn = connection;
          +    this.strip = "stream:stream";
          +
          +    var service = connection.service;
          +    if (service.indexOf("ws:") !== 0 && service.indexOf("wss:") !== 0) {
          +        // If the service is not an absolute URL, assume it is a path and put the absolute
          +        // URL together from options, current URL and the path.
          +        var new_service = "";
          +
          +        if (connection.options.protocol === "ws" && window.location.protocol !== "https:") {
          +            new_service += "ws";
          +        } else {
          +            new_service += "wss";
          +        }
          +
          +        new_service += "://" + window.location.host;
          +
          +        if (service.indexOf("/") !== 0) {
          +            new_service += window.location.pathname + service;
          +        } else {
          +            new_service += service;
          +        }
          +
          +        connection.service = new_service;
          +    }
          +};
          +
          +Strophe.Websocket.prototype = {
          +    /** PrivateFunction: _buildStream
          +     *  _Private_ helper function to generate the <stream> start tag for WebSockets
          +     *
          +     *  Returns:
          +     *    A Strophe.Builder with a <stream> element.
          +     */
          +    _buildStream: function ()
          +    {
          +        return $build("stream:stream", {
          +            "to": this._conn.domain,
          +            "xmlns": Strophe.NS.CLIENT,
          +            "xmlns:stream": Strophe.NS.STREAM,
          +            "version": '1.0'
          +        });
          +    },
          +
          +    /** PrivateFunction: _check_streamerror
          +     * _Private_ checks a message for stream:error
          +     *
          +     *  Parameters:
          +     *    (Strophe.Request) bodyWrap - The received stanza.
          +     *    connectstatus - The ConnectStatus that will be set on error.
          +     *  Returns:
          +     *     true if there was a streamerror, false otherwise.
          +     */
          +    _check_streamerror: function (bodyWrap, connectstatus) {
          +        var errors = bodyWrap.getElementsByTagName("stream:error");
          +        if (errors.length === 0) {
          +            return false;
          +        }
          +        var error = errors[0];
          +
          +        var condition = "";
          +        var text = "";
          +
          +        var ns = "urn:ietf:params:xml:ns:xmpp-streams";
          +        for (var i = 0; i < error.childNodes.length; i++) {
          +            var e = error.childNodes[i];
          +            if (e.getAttribute("xmlns") !== ns) {
          +                break;
          +            } if (e.nodeName === "text") {
          +                text = e.textContent;
          +            } else {
          +                condition = e.nodeName;
          +            }
          +        }
          +
          +        var errorString = "WebSocket stream error: ";
          +
          +        if (condition) {
          +            errorString += condition;
          +        } else {
          +            errorString += "unknown";
          +        }
          +
          +        if (text) {
          +            errorString += " - " + condition;
          +        }
          +
          +        Strophe.error(errorString);
          +
          +        // close the connection on stream_error
          +        this._conn._changeConnectStatus(connectstatus, condition);
          +        this._conn._doDisconnect();
          +        return true;
          +    },
          +
          +    /** PrivateFunction: _reset
          +     *  Reset the connection.
          +     *
          +     *  This function is called by the reset function of the Strophe Connection.
          +     *  Is not needed by WebSockets.
          +     */
          +    _reset: function ()
          +    {
          +        return;
          +    },
          +
          +    /** PrivateFunction: _connect
          +     *  _Private_ function called by Strophe.Connection.connect
          +     *
          +     *  Creates a WebSocket for a connection and assigns Callbacks to it.
          +     *  Does nothing if there already is a WebSocket.
          +     */
          +    _connect: function () {
          +        // Ensure that there is no open WebSocket from a previous Connection.
          +        this._closeSocket();
          +
          +        // Create the new WobSocket
          +        this.socket = new WebSocket(this._conn.service, "xmpp");
          +        this.socket.onopen = this._onOpen.bind(this);
          +        this.socket.onerror = this._onError.bind(this);
          +        this.socket.onclose = this._onClose.bind(this);
          +        this.socket.onmessage = this._connect_cb_wrapper.bind(this);
          +    },
          +
          +    /** PrivateFunction: _connect_cb
          +     *  _Private_ function called by Strophe.Connection._connect_cb
          +     *
          +     * checks for stream:error
          +     *
          +     *  Parameters:
          +     *    (Strophe.Request) bodyWrap - The received stanza.
          +     */
          +    _connect_cb: function(bodyWrap) {
          +        var error = this._check_streamerror(bodyWrap, Strophe.Status.CONNFAIL);
          +        if (error) {
          +            return Strophe.Status.CONNFAIL;
          +        }
          +    },
          +
          +    /** PrivateFunction: _handleStreamStart
          +     * _Private_ function that checks the opening stream:stream tag for errors.
          +     *
          +     * Disconnects if there is an error and returns false, true otherwise.
          +     *
          +     *  Parameters:
          +     *    (Node) message - Stanza containing the stream:stream.
          +     */
          +    _handleStreamStart: function(message) {
          +        var error = false;
          +        // Check for errors in the stream:stream tag
          +        var ns = message.getAttribute("xmlns");
          +        if (typeof ns !== "string") {
          +            error = "Missing xmlns in stream:stream";
          +        } else if (ns !== Strophe.NS.CLIENT) {
          +            error = "Wrong xmlns in stream:stream: " + ns;
          +        }
          +
          +        var ns_stream = message.namespaceURI;
          +        if (typeof ns_stream !== "string") {
          +            error = "Missing xmlns:stream in stream:stream";
          +        } else if (ns_stream !== Strophe.NS.STREAM) {
          +            error = "Wrong xmlns:stream in stream:stream: " + ns_stream;
          +        }
          +
          +        var ver = message.getAttribute("version");
          +        if (typeof ver !== "string") {
          +            error = "Missing version in stream:stream";
          +        } else if (ver !== "1.0") {
          +            error = "Wrong version in stream:stream: " + ver;
          +        }
          +
          +        if (error) {
          +            this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, error);
          +            this._conn._doDisconnect();
          +            return false;
          +        }
          +
          +        return true;
          +    },
          +
          +    /** PrivateFunction: _connect_cb_wrapper
          +     * _Private_ function that handles the first connection messages.
          +     *
          +     * On receiving an opening stream tag this callback replaces itself with the real
          +     * message handler. On receiving a stream error the connection is terminated.
          +     */
          +    _connect_cb_wrapper: function(message) {
          +        if (message.data.indexOf("<stream:stream ") === 0 || message.data.indexOf("<?xml") === 0) {
          +            // Strip the XML Declaration, if there is one
          +            var data = message.data.replace(/^(<\?.*?\?>\s*)*/, "");
          +            if (data === '') return;
          +
          +            //Make the initial stream:stream selfclosing to parse it without a SAX parser.
          +            data = message.data.replace(/<stream:stream (.*[^\/])>/, "<stream:stream $1/>");
          +
          +            var streamStart = new DOMParser().parseFromString(data, "text/xml").documentElement;
          +            this._conn.xmlInput(streamStart);
          +            this._conn.rawInput(message.data);
          +
          +            //_handleStreamSteart will check for XML errors and disconnect on error
          +            if (this._handleStreamStart(streamStart)) {
          +
          +                //_connect_cb will check for stream:error and disconnect on error
          +                this._connect_cb(streamStart);
          +
          +                // ensure received stream:stream is NOT selfclosing and save it for following messages
          +                this.streamStart = message.data.replace(/^<stream:(.*)\/>$/, "<stream:$1>");
          +            }
          +        } else if (message.data === "</stream:stream>") {
          +            this._conn.rawInput(message.data);
          +            this._conn.xmlInput(document.createElement("stream:stream"));
          +            this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "Received closing stream");
          +            this._conn._doDisconnect();
          +            return;
          +        } else {
          +            var string = this._streamWrap(message.data);
          +            var elem = new DOMParser().parseFromString(string, "text/xml").documentElement;
          +            this.socket.onmessage = this._onMessage.bind(this);
          +            this._conn._connect_cb(elem, null, message.data);
          +        }
          +    },
          +
          +    /** PrivateFunction: _disconnect
          +     *  _Private_ function called by Strophe.Connection.disconnect
          +     *
          +     *  Disconnects and sends a last stanza if one is given
          +     *
          +     *  Parameters:
          +     *    (Request) pres - This stanza will be sent before disconnecting.
          +     */
          +    _disconnect: function (pres)
          +    {
          +        if (this.socket.readyState !== WebSocket.CLOSED) {
          +            if (pres) {
          +                this._conn.send(pres);
          +            }
          +            var close = '</stream:stream>';
          +            this._conn.xmlOutput(document.createElement("stream:stream"));
          +            this._conn.rawOutput(close);
          +            try {
          +                this.socket.send(close);
          +            } catch (e) {
          +                Strophe.info("Couldn't send closing stream tag.");
          +            }
          +        }
          +
          +        this._conn._doDisconnect();
          +    },
          +
          +    /** PrivateFunction: _doDisconnect
          +     *  _Private_ function to disconnect.
          +     *
          +     *  Just closes the Socket for WebSockets
          +     */
          +    _doDisconnect: function ()
          +    {
          +        Strophe.info("WebSockets _doDisconnect was called");
          +        this._closeSocket();
          +    },
          +
          +    /** PrivateFunction _streamWrap
          +     *  _Private_ helper function to wrap a stanza in a <stream> tag.
          +     *  This is used so Strophe can process stanzas from WebSockets like BOSH
          +     */
          +    _streamWrap: function (stanza)
          +    {
          +        return this.streamStart + stanza + '</stream:stream>';
          +    },
          +
          +
          +    /** PrivateFunction: _closeSocket
          +     *  _Private_ function to close the WebSocket.
          +     *
          +     *  Closes the socket if it is still open and deletes it
          +     */
          +    _closeSocket: function ()
          +    {
          +        if (this.socket) { try {
          +            this.socket.close();
          +        } catch (e) {} }
          +        this.socket = null;
          +    },
          +
          +    /** PrivateFunction: _emptyQueue
          +     * _Private_ function to check if the message queue is empty.
          +     *
          +     *  Returns:
          +     *    True, because WebSocket messages are send immediately after queueing.
          +     */
          +    _emptyQueue: function ()
          +    {
          +        return true;
          +    },
          +
          +    /** PrivateFunction: _onClose
          +     * _Private_ function to handle websockets closing.
          +     *
          +     * Nothing to do here for WebSockets
          +     */
          +    _onClose: function() {
          +        if(this._conn.connected && !this._conn.disconnecting) {
          +            Strophe.error("Websocket closed unexcectedly");
          +            this._conn._doDisconnect();
          +        } else {
          +            Strophe.info("Websocket closed");
          +        }
          +    },
          +
          +    /** PrivateFunction: _no_auth_received
          +     *
          +     * Called on stream start/restart when no stream:features
          +     * has been received.
          +     */
          +    _no_auth_received: function (_callback)
          +    {
          +        Strophe.error("Server did not send any auth methods");
          +        this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "Server did not send any auth methods");
          +        if (_callback) {
          +            _callback = _callback.bind(this._conn);
          +            _callback();
          +        }
          +        this._conn._doDisconnect();
          +    },
          +
          +    /** PrivateFunction: _onDisconnectTimeout
          +     *  _Private_ timeout handler for handling non-graceful disconnection.
          +     *
          +     *  This does nothing for WebSockets
          +     */
          +    _onDisconnectTimeout: function () {},
          +
          +    /** PrivateFunction: _onError
          +     * _Private_ function to handle websockets errors.
          +     *
          +     * Parameters:
          +     * (Object) error - The websocket error.
          +     */
          +    _onError: function(error) {
          +        Strophe.error("Websocket error " + error);
          +        this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "The WebSocket connection could not be established was disconnected.");
          +        this._disconnect();
          +    },
          +
          +    /** PrivateFunction: _onIdle
          +     *  _Private_ function called by Strophe.Connection._onIdle
          +     *
          +     *  sends all queued stanzas
          +     */
          +    _onIdle: function () {
          +        var data = this._conn._data;
          +        if (data.length > 0 && !this._conn.paused) {
          +            for (var i = 0; i < data.length; i++) {
          +                if (data[i] !== null) {
          +                    var stanza, rawStanza;
          +                    if (data[i] === "restart") {
          +                        stanza = this._buildStream();
          +                        rawStanza = this._removeClosingTag(stanza);
          +                        stanza = stanza.tree();
          +                    } else {
          +                        stanza = data[i];
          +                        rawStanza = Strophe.serialize(stanza);
          +                    }
          +                    this._conn.xmlOutput(stanza);
          +                    this._conn.rawOutput(rawStanza);
          +                    this.socket.send(rawStanza);
          +                }
          +            }
          +            this._conn._data = [];
          +        }
          +    },
          +
          +    /** PrivateFunction: _onMessage
          +     * _Private_ function to handle websockets messages.
          +     *
          +     * This function parses each of the messages as if they are full documents. [TODO : We may actually want to use a SAX Push parser].
          +     *
          +     * Since all XMPP traffic starts with "<stream:stream version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='3697395463' from='SERVER'>"
          +     * The first stanza will always fail to be parsed...
          +     * Addtionnaly, the seconds stanza will always be a <stream:features> with the stream NS defined in the previous stanza... so we need to 'force' the inclusion of the NS in this stanza!
          +     *
          +     * Parameters:
          +     * (string) message - The websocket message.
          +     */
          +    _onMessage: function(message) {
          +        var elem, data;
          +        // check for closing stream
          +        if (message.data === "</stream:stream>") {
          +            var close = "</stream:stream>";
          +            this._conn.rawInput(close);
          +            this._conn.xmlInput(document.createElement("stream:stream"));
          +            if (!this._conn.disconnecting) {
          +                this._conn._doDisconnect();
          +            }
          +            return;
          +        } else if (message.data.search("<stream:stream ") === 0) {
          +            //Make the initial stream:stream selfclosing to parse it without a SAX parser.
          +            data = message.data.replace(/<stream:stream (.*[^\/])>/, "<stream:stream $1/>");
          +            elem = new DOMParser().parseFromString(data, "text/xml").documentElement;
          +
          +            if (!this._handleStreamStart(elem)) {
          +                return;
          +            }
          +        } else {
          +            data = this._streamWrap(message.data);
          +            elem = new DOMParser().parseFromString(data, "text/xml").documentElement;
          +        }
          +
          +        if (this._check_streamerror(elem, Strophe.Status.ERROR)) {
          +            return;
          +        }
          +
          +        //handle unavailable presence stanza before disconnecting
          +        if (this._conn.disconnecting &&
          +                elem.firstChild.nodeName === "presence" &&
          +                elem.firstChild.getAttribute("type") === "unavailable") {
          +            this._conn.xmlInput(elem);
          +            this._conn.rawInput(Strophe.serialize(elem));
          +            // if we are already disconnecting we will ignore the unavailable stanza and
          +            // wait for the </stream:stream> tag before we close the connection
          +            return;
          +        }
          +        this._conn._dataRecv(elem, message.data);
          +    },
          +
          +    /** PrivateFunction: _onOpen
          +     * _Private_ function to handle websockets connection setup.
          +     *
          +     * The opening stream tag is sent here.
          +     */
          +    _onOpen: function() {
          +        Strophe.info("Websocket open");
          +        var start = this._buildStream();
          +        this._conn.xmlOutput(start.tree());
          +
          +        var startString = this._removeClosingTag(start);
          +        this._conn.rawOutput(startString);
          +        this.socket.send(startString);
          +    },
          +
          +    /** PrivateFunction: _removeClosingTag
          +     *  _Private_ function to Make the first <stream:stream> non-selfclosing
          +     *
          +     *  Parameters:
          +     *      (Object) elem - The <stream:stream> tag.
          +     *
          +     *  Returns:
          +     *      The stream:stream tag as String
          +     */
          +    _removeClosingTag: function(elem) {
          +        var string = Strophe.serialize(elem);
          +        string = string.replace(/<(stream:stream .*[^\/])\/>$/, "<$1>");
          +        return string;
          +    },
          +
          +    /** PrivateFunction: _reqToData
          +     * _Private_ function to get a stanza out of a request.
          +     *
          +     * WebSockets don't use requests, so the passed argument is just returned.
          +     *
          +     *  Parameters:
          +     *    (Object) stanza - The stanza.
          +     *
          +     *  Returns:
          +     *    The stanza that was passed.
          +     */
          +    _reqToData: function (stanza)
          +    {
          +        return stanza;
          +    },
          +
          +    /** PrivateFunction: _send
          +     *  _Private_ part of the Connection.send function for WebSocket
          +     *
          +     * Just flushes the messages that are in the queue
          +     */
          +    _send: function () {
          +        this._conn.flush();
          +    },
          +
          +    /** PrivateFunction: _sendRestart
          +     *
          +     *  Send an xmpp:restart stanza.
          +     */
          +    _sendRestart: function ()
          +    {
          +        clearTimeout(this._conn._idleTimeout);
          +        this._conn._onIdle.bind(this._conn)();
          +    }
          +};
          diff --git a/public/javascripts/strophejs-1.1.3/plugins/strophe.flxhr.js b/public/javascripts/strophejs-1.1.3/plugins/strophe.flxhr.js
          new file mode 100644
          index 0000000..8779775
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/plugins/strophe.flxhr.js
          @@ -0,0 +1,36 @@
          +/* flXHR plugin
          +**
          +** This plugin implements cross-domain XmlHttpRequests via an invisible
          +** Flash plugin.
          +**
          +** In order for this to work, the BOSH service *must* serve a
          +** crossdomain.xml file that allows the client access.
          +**
          +** flXHR.js should be loaded before this plugin.
          +*/
          +
          +Strophe.addConnectionPlugin('flxhr', {
          +    init: function (conn) {
          +        // replace Strophe.Request._newXHR with new flXHR version
          +        // if flXHR is detected
          +        if (flensed && flensed.flXHR) {
          +            Strophe.Request.prototype._newXHR = function () {
          +                var xhr = new flensed.flXHR({
          +                    autoUpdatePlayer: true,
          +                    instancePooling: true,
          +                    noCacheHeader: false,
          +                    onerror: function () {
          +                        conn._changeConnectStatus(Strophe.Status.CONNFAIL,
          +                                                  "flXHR connection error");
          +                        conn._onDisconnectTimeout();
          +                    }});
          +                xhr.onreadystatechange = this.func.bind(null, this);
          +
          +                return xhr;
          +            };
          +        } else {
          +            Strophe.error("flXHR plugin loaded, but flXHR not found." +
          +                          "  Falling back to native XHR implementation.");
          +        }
          +    }
          +});
          diff --git a/public/javascripts/strophejs-1.1.3/plugins/strophe.flxhr.min.js b/public/javascripts/strophejs-1.1.3/plugins/strophe.flxhr.min.js
          new file mode 100644
          index 0000000..b43c9fa
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/plugins/strophe.flxhr.min.js
          @@ -0,0 +1 @@
          +Strophe.addConnectionPlugin("flxhr",{init:function(conn){if(flensed&&flensed.flXHR){Strophe.Request.prototype._newXHR=function(){var xhr=new flensed.flXHR({autoUpdatePlayer:true,instancePooling:true,noCacheHeader:false,onerror:function(){conn._changeConnectStatus(Strophe.Status.CONNFAIL,"flXHR connection error");conn._onDisconnectTimeout()}});xhr.onreadystatechange=this.func.bind(null,this);return xhr}}else{Strophe.error("flXHR plugin loaded, but flXHR not found.  Falling back to native XHR implementation.")}}});
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/strophe.js b/public/javascripts/strophejs-1.1.3/strophe.js
          new file mode 100644
          index 0000000..f1d50ae
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/strophe.js
          @@ -0,0 +1,5139 @@
          +// This code was written by Tyler Akins and has been placed in the
          +// public domain.  It would be nice if you left this header intact.
          +// Base64 code from Tyler Akins -- http://rumkin.com
          +
          +var Base64 = (function () {
          +    var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
          +
          +    var obj = {
          +        /**
          +         * Encodes a string in base64
          +         * @param {String} input The string to encode in base64.
          +         */
          +        encode: function (input) {
          +            var output = "";
          +            var chr1, chr2, chr3;
          +            var enc1, enc2, enc3, enc4;
          +            var i = 0;
          +
          +            do {
          +                chr1 = input.charCodeAt(i++);
          +                chr2 = input.charCodeAt(i++);
          +                chr3 = input.charCodeAt(i++);
          +
          +                enc1 = chr1 >> 2;
          +                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
          +                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
          +                enc4 = chr3 & 63;
          +
          +                if (isNaN(chr2)) {
          +                    enc3 = enc4 = 64;
          +                } else if (isNaN(chr3)) {
          +                    enc4 = 64;
          +                }
          +
          +                output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) +
          +                    keyStr.charAt(enc3) + keyStr.charAt(enc4);
          +            } while (i < input.length);
          +
          +            return output;
          +        },
          +
          +        /**
          +         * Decodes a base64 string.
          +         * @param {String} input The string to decode.
          +         */
          +        decode: function (input) {
          +            var output = "";
          +            var chr1, chr2, chr3;
          +            var enc1, enc2, enc3, enc4;
          +            var i = 0;
          +
          +            // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
          +            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
          +
          +            do {
          +                enc1 = keyStr.indexOf(input.charAt(i++));
          +                enc2 = keyStr.indexOf(input.charAt(i++));
          +                enc3 = keyStr.indexOf(input.charAt(i++));
          +                enc4 = keyStr.indexOf(input.charAt(i++));
          +
          +                chr1 = (enc1 << 2) | (enc2 >> 4);
          +                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
          +                chr3 = ((enc3 & 3) << 6) | enc4;
          +
          +                output = output + String.fromCharCode(chr1);
          +
          +                if (enc3 != 64) {
          +                    output = output + String.fromCharCode(chr2);
          +                }
          +                if (enc4 != 64) {
          +                    output = output + String.fromCharCode(chr3);
          +                }
          +            } while (i < input.length);
          +
          +            return output;
          +        }
          +    };
          +
          +    return obj;
          +})();
          +
          +/*
          + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
          + * in FIPS PUB 180-1
          + * Version 2.1a Copyright Paul Johnston 2000 - 2002.
          + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
          + * Distributed under the BSD License
          + * See http://pajhome.org.uk/crypt/md5 for details.
          + */
          +
          +/* Some functions and variables have been stripped for use with Strophe */
          +
          +/*
          + * These are the functions you'll usually want to call
          + * They take string arguments and return either hex or base-64 encoded strings
          + */
          +function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * 8));}
          +function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * 8));}
          +function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
          +function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}
          +
          +/*
          + * Calculate the SHA-1 of an array of big-endian words, and a bit length
          + */
          +function core_sha1(x, len)
          +{
          +  /* append padding */
          +  x[len >> 5] |= 0x80 << (24 - len % 32);
          +  x[((len + 64 >> 9) << 4) + 15] = len;
          +
          +  var w = new Array(80);
          +  var a =  1732584193;
          +  var b = -271733879;
          +  var c = -1732584194;
          +  var d =  271733878;
          +  var e = -1009589776;
          +
          +  var i, j, t, olda, oldb, oldc, oldd, olde;
          +  for (i = 0; i < x.length; i += 16)
          +  {
          +    olda = a;
          +    oldb = b;
          +    oldc = c;
          +    oldd = d;
          +    olde = e;
          +
          +    for (j = 0; j < 80; j++)
          +    {
          +      if (j < 16) { w[j] = x[i + j]; }
          +      else { w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); }
          +      t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
          +                       safe_add(safe_add(e, w[j]), sha1_kt(j)));
          +      e = d;
          +      d = c;
          +      c = rol(b, 30);
          +      b = a;
          +      a = t;
          +    }
          +
          +    a = safe_add(a, olda);
          +    b = safe_add(b, oldb);
          +    c = safe_add(c, oldc);
          +    d = safe_add(d, oldd);
          +    e = safe_add(e, olde);
          +  }
          +  return [a, b, c, d, e];
          +}
          +
          +/*
          + * Perform the appropriate triplet combination function for the current
          + * iteration
          + */
          +function sha1_ft(t, b, c, d)
          +{
          +  if (t < 20) { return (b & c) | ((~b) & d); }
          +  if (t < 40) { return b ^ c ^ d; }
          +  if (t < 60) { return (b & c) | (b & d) | (c & d); }
          +  return b ^ c ^ d;
          +}
          +
          +/*
          + * Determine the appropriate additive constant for the current iteration
          + */
          +function sha1_kt(t)
          +{
          +  return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 :
          +         (t < 60) ? -1894007588 : -899497514;
          +}
          +
          +/*
          + * Calculate the HMAC-SHA1 of a key and some data
          + */
          +function core_hmac_sha1(key, data)
          +{
          +  var bkey = str2binb(key);
          +  if (bkey.length > 16) { bkey = core_sha1(bkey, key.length * 8); }
          +
          +  var ipad = new Array(16), opad = new Array(16);
          +  for (var i = 0; i < 16; i++)
          +  {
          +    ipad[i] = bkey[i] ^ 0x36363636;
          +    opad[i] = bkey[i] ^ 0x5C5C5C5C;
          +  }
          +
          +  var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * 8);
          +  return core_sha1(opad.concat(hash), 512 + 160);
          +}
          +
          +/*
          + * Add integers, wrapping at 2^32. This uses 16-bit operations internally
          + * to work around bugs in some JS interpreters.
          + */
          +function safe_add(x, y)
          +{
          +  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
          +  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
          +  return (msw << 16) | (lsw & 0xFFFF);
          +}
          +
          +/*
          + * Bitwise rotate a 32-bit number to the left.
          + */
          +function rol(num, cnt)
          +{
          +  return (num << cnt) | (num >>> (32 - cnt));
          +}
          +
          +/*
          + * Convert an 8-bit or 16-bit string to an array of big-endian words
          + * In 8-bit function, characters >255 have their hi-byte silently ignored.
          + */
          +function str2binb(str)
          +{
          +  var bin = [];
          +  var mask = 255;
          +  for (var i = 0; i < str.length * 8; i += 8)
          +  {
          +    bin[i>>5] |= (str.charCodeAt(i / 8) & mask) << (24 - i%32);
          +  }
          +  return bin;
          +}
          +
          +/*
          + * Convert an array of big-endian words to a string
          + */
          +function binb2str(bin)
          +{
          +  var str = "";
          +  var mask = 255;
          +  for (var i = 0; i < bin.length * 32; i += 8)
          +  {
          +    str += String.fromCharCode((bin[i>>5] >>> (24 - i%32)) & mask);
          +  }
          +  return str;
          +}
          +
          +/*
          + * Convert an array of big-endian words to a base-64 string
          + */
          +function binb2b64(binarray)
          +{
          +  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
          +  var str = "";
          +  var triplet, j;
          +  for (var i = 0; i < binarray.length * 4; i += 3)
          +  {
          +    triplet = (((binarray[i   >> 2] >> 8 * (3 -  i   %4)) & 0xFF) << 16) |
          +              (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) |
          +               ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
          +    for (j = 0; j < 4; j++)
          +    {
          +      if (i * 8 + j * 6 > binarray.length * 32) { str += "="; }
          +      else { str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); }
          +    }
          +  }
          +  return str;
          +}
          +
          +/*
          + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
          + * Digest Algorithm, as defined in RFC 1321.
          + * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
          + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
          + * Distributed under the BSD License
          + * See http://pajhome.org.uk/crypt/md5 for more info.
          + */
          +
          +/*
          + * Everything that isn't used by Strophe has been stripped here!
          + */
          +
          +var MD5 = (function () {
          +    /*
          +     * Add integers, wrapping at 2^32. This uses 16-bit operations internally
          +     * to work around bugs in some JS interpreters.
          +     */
          +    var safe_add = function (x, y) {
          +        var lsw = (x & 0xFFFF) + (y & 0xFFFF);
          +        var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
          +        return (msw << 16) | (lsw & 0xFFFF);
          +    };
          +
          +    /*
          +     * Bitwise rotate a 32-bit number to the left.
          +     */
          +    var bit_rol = function (num, cnt) {
          +        return (num << cnt) | (num >>> (32 - cnt));
          +    };
          +
          +    /*
          +     * Convert a string to an array of little-endian words
          +     */
          +    var str2binl = function (str) {
          +        var bin = [];
          +        for(var i = 0; i < str.length * 8; i += 8)
          +        {
          +            bin[i>>5] |= (str.charCodeAt(i / 8) & 255) << (i%32);
          +        }
          +        return bin;
          +    };
          +
          +    /*
          +     * Convert an array of little-endian words to a string
          +     */
          +    var binl2str = function (bin) {
          +        var str = "";
          +        for(var i = 0; i < bin.length * 32; i += 8)
          +        {
          +            str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & 255);
          +        }
          +        return str;
          +    };
          +
          +    /*
          +     * Convert an array of little-endian words to a hex string.
          +     */
          +    var binl2hex = function (binarray) {
          +        var hex_tab = "0123456789abcdef";
          +        var str = "";
          +        for(var i = 0; i < binarray.length * 4; i++)
          +        {
          +            str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
          +                hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
          +        }
          +        return str;
          +    };
          +
          +    /*
          +     * These functions implement the four basic operations the algorithm uses.
          +     */
          +    var md5_cmn = function (q, a, b, x, s, t) {
          +        return safe_add(bit_rol(safe_add(safe_add(a, q),safe_add(x, t)), s),b);
          +    };
          +
          +    var md5_ff = function (a, b, c, d, x, s, t) {
          +        return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
          +    };
          +
          +    var md5_gg = function (a, b, c, d, x, s, t) {
          +        return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
          +    };
          +
          +    var md5_hh = function (a, b, c, d, x, s, t) {
          +        return md5_cmn(b ^ c ^ d, a, b, x, s, t);
          +    };
          +
          +    var md5_ii = function (a, b, c, d, x, s, t) {
          +        return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
          +    };
          +
          +    /*
          +     * Calculate the MD5 of an array of little-endian words, and a bit length
          +     */
          +    var core_md5 = function (x, len) {
          +        /* append padding */
          +        x[len >> 5] |= 0x80 << ((len) % 32);
          +        x[(((len + 64) >>> 9) << 4) + 14] = len;
          +
          +        var a =  1732584193;
          +        var b = -271733879;
          +        var c = -1732584194;
          +        var d =  271733878;
          +
          +        var olda, oldb, oldc, oldd;
          +        for (var i = 0; i < x.length; i += 16)
          +        {
          +            olda = a;
          +            oldb = b;
          +            oldc = c;
          +            oldd = d;
          +
          +            a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
          +            d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
          +            c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
          +            b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
          +            a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
          +            d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
          +            c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
          +            b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
          +            a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
          +            d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
          +            c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
          +            b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
          +            a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
          +            d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
          +            c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
          +            b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);
          +
          +            a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
          +            d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
          +            c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
          +            b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
          +            a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
          +            d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
          +            c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
          +            b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
          +            a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
          +            d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
          +            c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
          +            b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
          +            a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
          +            d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
          +            c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
          +            b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
          +
          +            a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
          +            d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
          +            c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
          +            b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
          +            a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
          +            d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
          +            c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
          +            b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
          +            a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
          +            d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
          +            c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
          +            b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
          +            a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
          +            d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
          +            c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
          +            b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
          +
          +            a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
          +            d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
          +            c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
          +            b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
          +            a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
          +            d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
          +            c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
          +            b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
          +            a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
          +            d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
          +            c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
          +            b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
          +            a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
          +            d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
          +            c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
          +            b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
          +
          +            a = safe_add(a, olda);
          +            b = safe_add(b, oldb);
          +            c = safe_add(c, oldc);
          +            d = safe_add(d, oldd);
          +        }
          +        return [a, b, c, d];
          +    };
          +
          +
          +    var obj = {
          +        /*
          +         * These are the functions you'll usually want to call.
          +         * They take string arguments and return either hex or base-64 encoded
          +         * strings.
          +         */
          +        hexdigest: function (s) {
          +            return binl2hex(core_md5(str2binl(s), s.length * 8));
          +        },
          +
          +        hash: function (s) {
          +            return binl2str(core_md5(str2binl(s), s.length * 8));
          +        }
          +    };
          +
          +    return obj;
          +})();
          +
          +/*
          +    This program is distributed under the terms of the MIT license.
          +    Please see the LICENSE file for details.
          +
          +    Copyright 2006-2008, OGG, LLC
          +*/
          +
          +/* jshint undef: true, unused: true:, noarg: true, latedef: true */
          +/*global document, window, setTimeout, clearTimeout, console,
          +    ActiveXObject, Base64, MD5, DOMParser */
          +// from sha1.js
          +/*global core_hmac_sha1, binb2str, str_hmac_sha1, str_sha1, b64_hmac_sha1*/
          +
          +/** File: strophe.js
          + *  A JavaScript library for XMPP BOSH/XMPP over Websocket.
          + *
          + *  This is the JavaScript version of the Strophe library.  Since JavaScript
          + *  had no facilities for persistent TCP connections, this library uses
          + *  Bidirectional-streams Over Synchronous HTTP (BOSH) to emulate
          + *  a persistent, stateful, two-way connection to an XMPP server.  More
          + *  information on BOSH can be found in XEP 124.
          + *
          + *  This version of Strophe also works with WebSockets.
          + *  For more information on XMPP-over WebSocket see this RFC draft:
          + *  http://tools.ietf.org/html/draft-ietf-xmpp-websocket-00
          + */
          +
          +/** PrivateFunction: Function.prototype.bind
          + *  Bind a function to an instance.
          + *
          + *  This Function object extension method creates a bound method similar
          + *  to those in Python.  This means that the 'this' object will point
          + *  to the instance you want.  See
          + *  <a href='https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind'>MDC's bind() documentation</a> and
          + *  <a href='http://benjamin.smedbergs.us/blog/2007-01-03/bound-functions-and-function-imports-in-javascript/'>Bound Functions and Function Imports in JavaScript</a>
          + *  for a complete explanation.
          + *
          + *  This extension already exists in some browsers (namely, Firefox 3), but
          + *  we provide it to support those that don't.
          + *
          + *  Parameters:
          + *    (Object) obj - The object that will become 'this' in the bound function.
          + *    (Object) argN - An option argument that will be prepended to the
          + *      arguments given for the function call
          + *
          + *  Returns:
          + *    The bound function.
          + */
          +if (!Function.prototype.bind) {
          +    Function.prototype.bind = function (obj /*, arg1, arg2, ... */)
          +    {
          +        var func = this;
          +        var _slice = Array.prototype.slice;
          +        var _concat = Array.prototype.concat;
          +        var _args = _slice.call(arguments, 1);
          +
          +        return function () {
          +            return func.apply(obj ? obj : this,
          +                              _concat.call(_args,
          +                                           _slice.call(arguments, 0)));
          +        };
          +    };
          +}
          +
          +/** PrivateFunction: Array.prototype.indexOf
          + *  Return the index of an object in an array.
          + *
          + *  This function is not supplied by some JavaScript implementations, so
          + *  we provide it if it is missing.  This code is from:
          + *  http://developer.mozilla.org/En/Core_JavaScript_1.5_Reference:Objects:Array:indexOf
          + *
          + *  Parameters:
          + *    (Object) elt - The object to look for.
          + *    (Integer) from - The index from which to start looking. (optional).
          + *
          + *  Returns:
          + *    The index of elt in the array or -1 if not found.
          + */
          +if (!Array.prototype.indexOf)
          +{
          +    Array.prototype.indexOf = function(elt /*, from*/)
          +    {
          +        var len = this.length;
          +
          +        var from = Number(arguments[1]) || 0;
          +        from = (from < 0) ? Math.ceil(from) : Math.floor(from);
          +        if (from < 0) {
          +            from += len;
          +        }
          +
          +        for (; from < len; from++) {
          +            if (from in this && this[from] === elt) {
          +                return from;
          +            }
          +        }
          +
          +        return -1;
          +    };
          +}
          +
          +/* All of the Strophe globals are defined in this special function below so
          + * that references to the globals become closures.  This will ensure that
          + * on page reload, these references will still be available to callbacks
          + * that are still executing.
          + */
          +
          +(function (callback) {
          +var Strophe;
          +
          +/** Function: $build
          + *  Create a Strophe.Builder.
          + *  This is an alias for 'new Strophe.Builder(name, attrs)'.
          + *
          + *  Parameters:
          + *    (String) name - The root element name.
          + *    (Object) attrs - The attributes for the root element in object notation.
          + *
          + *  Returns:
          + *    A new Strophe.Builder object.
          + */
          +function $build(name, attrs) { return new Strophe.Builder(name, attrs); }
          +/** Function: $msg
          + *  Create a Strophe.Builder with a <message/> element as the root.
          + *
          + *  Parmaeters:
          + *    (Object) attrs - The <message/> element attributes in object notation.
          + *
          + *  Returns:
          + *    A new Strophe.Builder object.
          + */
          +function $msg(attrs) { return new Strophe.Builder("message", attrs); }
          +/** Function: $iq
          + *  Create a Strophe.Builder with an <iq/> element as the root.
          + *
          + *  Parameters:
          + *    (Object) attrs - The <iq/> element attributes in object notation.
          + *
          + *  Returns:
          + *    A new Strophe.Builder object.
          + */
          +function $iq(attrs) { return new Strophe.Builder("iq", attrs); }
          +/** Function: $pres
          + *  Create a Strophe.Builder with a <presence/> element as the root.
          + *
          + *  Parameters:
          + *    (Object) attrs - The <presence/> element attributes in object notation.
          + *
          + *  Returns:
          + *    A new Strophe.Builder object.
          + */
          +function $pres(attrs) { return new Strophe.Builder("presence", attrs); }
          +
          +/** Class: Strophe
          + *  An object container for all Strophe library functions.
          + *
          + *  This class is just a container for all the objects and constants
          + *  used in the library.  It is not meant to be instantiated, but to
          + *  provide a namespace for library objects, constants, and functions.
          + */
          +Strophe = {
          +    /** Constant: VERSION
          +     *  The version of the Strophe library. Unreleased builds will have
          +     *  a version of head-HASH where HASH is a partial revision.
          +     */
          +    VERSION: "1.1.3",
          +
          +    /** Constants: XMPP Namespace Constants
          +     *  Common namespace constants from the XMPP RFCs and XEPs.
          +     *
          +     *  NS.HTTPBIND - HTTP BIND namespace from XEP 124.
          +     *  NS.BOSH - BOSH namespace from XEP 206.
          +     *  NS.CLIENT - Main XMPP client namespace.
          +     *  NS.AUTH - Legacy authentication namespace.
          +     *  NS.ROSTER - Roster operations namespace.
          +     *  NS.PROFILE - Profile namespace.
          +     *  NS.DISCO_INFO - Service discovery info namespace from XEP 30.
          +     *  NS.DISCO_ITEMS - Service discovery items namespace from XEP 30.
          +     *  NS.MUC - Multi-User Chat namespace from XEP 45.
          +     *  NS.SASL - XMPP SASL namespace from RFC 3920.
          +     *  NS.STREAM - XMPP Streams namespace from RFC 3920.
          +     *  NS.BIND - XMPP Binding namespace from RFC 3920.
          +     *  NS.SESSION - XMPP Session namespace from RFC 3920.
          +     *  NS.XHTML_IM - XHTML-IM namespace from XEP 71.
          +     *  NS.XHTML - XHTML body namespace from XEP 71.
          +     */
          +    NS: {
          +        HTTPBIND: "http://jabber.org/protocol/httpbind",
          +        BOSH: "urn:xmpp:xbosh",
          +        CLIENT: "jabber:client",
          +        AUTH: "jabber:iq:auth",
          +        ROSTER: "jabber:iq:roster",
          +        PROFILE: "jabber:iq:profile",
          +        DISCO_INFO: "http://jabber.org/protocol/disco#info",
          +        DISCO_ITEMS: "http://jabber.org/protocol/disco#items",
          +        MUC: "http://jabber.org/protocol/muc",
          +        SASL: "urn:ietf:params:xml:ns:xmpp-sasl",
          +        STREAM: "http://etherx.jabber.org/streams",
          +        BIND: "urn:ietf:params:xml:ns:xmpp-bind",
          +        SESSION: "urn:ietf:params:xml:ns:xmpp-session",
          +        VERSION: "jabber:iq:version",
          +        STANZAS: "urn:ietf:params:xml:ns:xmpp-stanzas",
          +        XHTML_IM: "http://jabber.org/protocol/xhtml-im",
          +        XHTML: "http://www.w3.org/1999/xhtml"
          +    },
          +
          +
          +    /** Constants: XHTML_IM Namespace
          +     *  contains allowed tags, tag attributes, and css properties.
          +     *  Used in the createHtml function to filter incoming html into the allowed XHTML-IM subset.
          +     *  See http://xmpp.org/extensions/xep-0071.html#profile-summary for the list of recommended
          +     *  allowed tags and their attributes.
          +     */
          +    XHTML: {
          +                tags: ['a','blockquote','br','cite','em','img','li','ol','p','span','strong','ul','body'],
          +                attributes: {
          +                        'a':          ['href'],
          +                        'blockquote': ['style'],
          +                        'br':         [],
          +                        'cite':       ['style'],
          +                        'em':         [],
          +                        'img':        ['src', 'alt', 'style', 'height', 'width'],
          +                        'li':         ['style'],
          +                        'ol':         ['style'],
          +                        'p':          ['style'],
          +                        'span':       ['style'],
          +                        'strong':     [],
          +                        'ul':         ['style'],
          +                        'body':       []
          +                },
          +                css: ['background-color','color','font-family','font-size','font-style','font-weight','margin-left','margin-right','text-align','text-decoration'],
          +                validTag: function(tag)
          +                {
          +                        for(var i = 0; i < Strophe.XHTML.tags.length; i++) {
          +                                if(tag == Strophe.XHTML.tags[i]) {
          +                                        return true;
          +                                }
          +                        }
          +                        return false;
          +                },
          +                validAttribute: function(tag, attribute)
          +                {
          +                        if(typeof Strophe.XHTML.attributes[tag] !== 'undefined' && Strophe.XHTML.attributes[tag].length > 0) {
          +                                for(var i = 0; i < Strophe.XHTML.attributes[tag].length; i++) {
          +                                        if(attribute == Strophe.XHTML.attributes[tag][i]) {
          +                                                return true;
          +                                        }
          +                                }
          +                        }
          +                        return false;
          +                },
          +                validCSS: function(style)
          +                {
          +                        for(var i = 0; i < Strophe.XHTML.css.length; i++) {
          +                                if(style == Strophe.XHTML.css[i]) {
          +                                        return true;
          +                                }
          +                        }
          +                        return false;
          +                }
          +    },
          +
          +    /** Constants: Connection Status Constants
          +     *  Connection status constants for use by the connection handler
          +     *  callback.
          +     *
          +     *  Status.ERROR - An error has occurred
          +     *  Status.CONNECTING - The connection is currently being made
          +     *  Status.CONNFAIL - The connection attempt failed
          +     *  Status.AUTHENTICATING - The connection is authenticating
          +     *  Status.AUTHFAIL - The authentication attempt failed
          +     *  Status.CONNECTED - The connection has succeeded
          +     *  Status.DISCONNECTED - The connection has been terminated
          +     *  Status.DISCONNECTING - The connection is currently being terminated
          +     *  Status.ATTACHED - The connection has been attached
          +     */
          +    Status: {
          +        ERROR: 0,
          +        CONNECTING: 1,
          +        CONNFAIL: 2,
          +        AUTHENTICATING: 3,
          +        AUTHFAIL: 4,
          +        CONNECTED: 5,
          +        DISCONNECTED: 6,
          +        DISCONNECTING: 7,
          +        ATTACHED: 8
          +    },
          +
          +    /** Constants: Log Level Constants
          +     *  Logging level indicators.
          +     *
          +     *  LogLevel.DEBUG - Debug output
          +     *  LogLevel.INFO - Informational output
          +     *  LogLevel.WARN - Warnings
          +     *  LogLevel.ERROR - Errors
          +     *  LogLevel.FATAL - Fatal errors
          +     */
          +    LogLevel: {
          +        DEBUG: 0,
          +        INFO: 1,
          +        WARN: 2,
          +        ERROR: 3,
          +        FATAL: 4
          +    },
          +
          +    /** PrivateConstants: DOM Element Type Constants
          +     *  DOM element types.
          +     *
          +     *  ElementType.NORMAL - Normal element.
          +     *  ElementType.TEXT - Text data element.
          +     *  ElementType.FRAGMENT - XHTML fragment element.
          +     */
          +    ElementType: {
          +        NORMAL: 1,
          +        TEXT: 3,
          +        CDATA: 4,
          +        FRAGMENT: 11
          +    },
          +
          +    /** PrivateConstants: Timeout Values
          +     *  Timeout values for error states.  These values are in seconds.
          +     *  These should not be changed unless you know exactly what you are
          +     *  doing.
          +     *
          +     *  TIMEOUT - Timeout multiplier. A waiting request will be considered
          +     *      failed after Math.floor(TIMEOUT * wait) seconds have elapsed.
          +     *      This defaults to 1.1, and with default wait, 66 seconds.
          +     *  SECONDARY_TIMEOUT - Secondary timeout multiplier. In cases where
          +     *      Strophe can detect early failure, it will consider the request
          +     *      failed if it doesn't return after
          +     *      Math.floor(SECONDARY_TIMEOUT * wait) seconds have elapsed.
          +     *      This defaults to 0.1, and with default wait, 6 seconds.
          +     */
          +    TIMEOUT: 1.1,
          +    SECONDARY_TIMEOUT: 0.1,
          +
          +    /** Function: addNamespace
          +     *  This function is used to extend the current namespaces in
          +     *  Strophe.NS.  It takes a key and a value with the key being the
          +     *  name of the new namespace, with its actual value.
          +     *  For example:
          +     *  Strophe.addNamespace('PUBSUB', "http://jabber.org/protocol/pubsub");
          +     *
          +     *  Parameters:
          +     *    (String) name - The name under which the namespace will be
          +     *      referenced under Strophe.NS
          +     *    (String) value - The actual namespace.
          +     */
          +    addNamespace: function (name, value)
          +    {
          +      Strophe.NS[name] = value;
          +    },
          +
          +    /** Function: forEachChild
          +     *  Map a function over some or all child elements of a given element.
          +     *
          +     *  This is a small convenience function for mapping a function over
          +     *  some or all of the children of an element.  If elemName is null, all
          +     *  children will be passed to the function, otherwise only children
          +     *  whose tag names match elemName will be passed.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The element to operate on.
          +     *    (String) elemName - The child element tag name filter.
          +     *    (Function) func - The function to apply to each child.  This
          +     *      function should take a single argument, a DOM element.
          +     */
          +    forEachChild: function (elem, elemName, func)
          +    {
          +        var i, childNode;
          +
          +        for (i = 0; i < elem.childNodes.length; i++) {
          +            childNode = elem.childNodes[i];
          +            if (childNode.nodeType == Strophe.ElementType.NORMAL &&
          +                (!elemName || this.isTagEqual(childNode, elemName))) {
          +                func(childNode);
          +            }
          +        }
          +    },
          +
          +    /** Function: isTagEqual
          +     *  Compare an element's tag name with a string.
          +     *
          +     *  This function is case insensitive.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) el - A DOM element.
          +     *    (String) name - The element name.
          +     *
          +     *  Returns:
          +     *    true if the element's tag name matches _el_, and false
          +     *    otherwise.
          +     */
          +    isTagEqual: function (el, name)
          +    {
          +        return el.tagName.toLowerCase() == name.toLowerCase();
          +    },
          +
          +    /** PrivateVariable: _xmlGenerator
          +     *  _Private_ variable that caches a DOM document to
          +     *  generate elements.
          +     */
          +    _xmlGenerator: null,
          +
          +    /** PrivateFunction: _makeGenerator
          +     *  _Private_ function that creates a dummy XML DOM document to serve as
          +     *  an element and text node generator.
          +     */
          +    _makeGenerator: function () {
          +        var doc;
          +
          +        // IE9 does implement createDocument(); however, using it will cause the browser to leak memory on page unload.
          +        // Here, we test for presence of createDocument() plus IE's proprietary documentMode attribute, which would be
          +                // less than 10 in the case of IE9 and below.
          +        if (document.implementation.createDocument === undefined ||
          +                        document.implementation.createDocument && document.documentMode && document.documentMode < 10) {
          +            doc = this._getIEXmlDom();
          +            doc.appendChild(doc.createElement('strophe'));
          +        } else {
          +            doc = document.implementation
          +                .createDocument('jabber:client', 'strophe', null);
          +        }
          +
          +        return doc;
          +    },
          +
          +    /** Function: xmlGenerator
          +     *  Get the DOM document to generate elements.
          +     *
          +     *  Returns:
          +     *    The currently used DOM document.
          +     */
          +    xmlGenerator: function () {
          +        if (!Strophe._xmlGenerator) {
          +            Strophe._xmlGenerator = Strophe._makeGenerator();
          +        }
          +        return Strophe._xmlGenerator;
          +    },
          +
          +    /** PrivateFunction: _getIEXmlDom
          +     *  Gets IE xml doc object
          +     *
          +     *  Returns:
          +     *    A Microsoft XML DOM Object
          +     *  See Also:
          +     *    http://msdn.microsoft.com/en-us/library/ms757837%28VS.85%29.aspx
          +     */
          +    _getIEXmlDom : function() {
          +        var doc = null;
          +        var docStrings = [
          +            "Msxml2.DOMDocument.6.0",
          +            "Msxml2.DOMDocument.5.0",
          +            "Msxml2.DOMDocument.4.0",
          +            "MSXML2.DOMDocument.3.0",
          +            "MSXML2.DOMDocument",
          +            "MSXML.DOMDocument",
          +            "Microsoft.XMLDOM"
          +        ];
          +
          +        for (var d = 0; d < docStrings.length; d++) {
          +            if (doc === null) {
          +                try {
          +                    doc = new ActiveXObject(docStrings[d]);
          +                } catch (e) {
          +                    doc = null;
          +                }
          +            } else {
          +                break;
          +            }
          +        }
          +
          +        return doc;
          +    },
          +
          +    /** Function: xmlElement
          +     *  Create an XML DOM element.
          +     *
          +     *  This function creates an XML DOM element correctly across all
          +     *  implementations. Note that these are not HTML DOM elements, which
          +     *  aren't appropriate for XMPP stanzas.
          +     *
          +     *  Parameters:
          +     *    (String) name - The name for the element.
          +     *    (Array|Object) attrs - An optional array or object containing
          +     *      key/value pairs to use as element attributes. The object should
          +     *      be in the format {'key': 'value'} or {key: 'value'}. The array
          +     *      should have the format [['key1', 'value1'], ['key2', 'value2']].
          +     *    (String) text - The text child data for the element.
          +     *
          +     *  Returns:
          +     *    A new XML DOM element.
          +     */
          +    xmlElement: function (name)
          +    {
          +        if (!name) { return null; }
          +
          +        var node = Strophe.xmlGenerator().createElement(name);
          +
          +        // FIXME: this should throw errors if args are the wrong type or
          +        // there are more than two optional args
          +        var a, i, k;
          +        for (a = 1; a < arguments.length; a++) {
          +            if (!arguments[a]) { continue; }
          +            if (typeof(arguments[a]) == "string" ||
          +                typeof(arguments[a]) == "number") {
          +                node.appendChild(Strophe.xmlTextNode(arguments[a]));
          +            } else if (typeof(arguments[a]) == "object" &&
          +                       typeof(arguments[a].sort) == "function") {
          +                for (i = 0; i < arguments[a].length; i++) {
          +                    if (typeof(arguments[a][i]) == "object" &&
          +                        typeof(arguments[a][i].sort) == "function") {
          +                        node.setAttribute(arguments[a][i][0],
          +                                          arguments[a][i][1]);
          +                    }
          +                }
          +            } else if (typeof(arguments[a]) == "object") {
          +                for (k in arguments[a]) {
          +                    if (arguments[a].hasOwnProperty(k)) {
          +                        node.setAttribute(k, arguments[a][k]);
          +                    }
          +                }
          +            }
          +        }
          +
          +        return node;
          +    },
          +
          +    /*  Function: xmlescape
          +     *  Excapes invalid xml characters.
          +     *
          +     *  Parameters:
          +     *     (String) text - text to escape.
          +     *
          +     *  Returns:
          +     *      Escaped text.
          +     */
          +    xmlescape: function(text)
          +    {
          +        text = text.replace(/\&/g, "&amp;");
          +        text = text.replace(/</g,  "&lt;");
          +        text = text.replace(/>/g,  "&gt;");
          +        text = text.replace(/'/g,  "&apos;");
          +        text = text.replace(/"/g,  "&quot;");
          +        return text;
          +    },
          +
          +    /** Function: xmlTextNode
          +     *  Creates an XML DOM text node.
          +     *
          +     *  Provides a cross implementation version of document.createTextNode.
          +     *
          +     *  Parameters:
          +     *    (String) text - The content of the text node.
          +     *
          +     *  Returns:
          +     *    A new XML DOM text node.
          +     */
          +    xmlTextNode: function (text)
          +    {
          +        return Strophe.xmlGenerator().createTextNode(text);
          +    },
          +
          +    /** Function: xmlHtmlNode
          +     *  Creates an XML DOM html node.
          +     *
          +     *  Parameters:
          +     *    (String) html - The content of the html node.
          +     *
          +     *  Returns:
          +     *    A new XML DOM text node.
          +     */
          +    xmlHtmlNode: function (html)
          +    {
          +        var node;
          +        //ensure text is escaped
          +        if (window.DOMParser) {
          +            var parser = new DOMParser();
          +            node = parser.parseFromString(html, "text/xml");
          +        } else {
          +            node = new ActiveXObject("Microsoft.XMLDOM");
          +            node.async="false";
          +            node.loadXML(html);
          +        }
          +        return node;
          +    },
          +
          +    /** Function: getText
          +     *  Get the concatenation of all text children of an element.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - A DOM element.
          +     *
          +     *  Returns:
          +     *    A String with the concatenated text of all text element children.
          +     */
          +    getText: function (elem)
          +    {
          +        if (!elem) { return null; }
          +
          +        var str = "";
          +        if (elem.childNodes.length === 0 && elem.nodeType ==
          +            Strophe.ElementType.TEXT) {
          +            str += elem.nodeValue;
          +        }
          +
          +        for (var i = 0; i < elem.childNodes.length; i++) {
          +            if (elem.childNodes[i].nodeType == Strophe.ElementType.TEXT) {
          +                str += elem.childNodes[i].nodeValue;
          +            }
          +        }
          +
          +        return Strophe.xmlescape(str);
          +    },
          +
          +    /** Function: copyElement
          +     *  Copy an XML DOM element.
          +     *
          +     *  This function copies a DOM element and all its descendants and returns
          +     *  the new copy.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - A DOM element.
          +     *
          +     *  Returns:
          +     *    A new, copied DOM element tree.
          +     */
          +    copyElement: function (elem)
          +    {
          +        var i, el;
          +        if (elem.nodeType == Strophe.ElementType.NORMAL) {
          +            el = Strophe.xmlElement(elem.tagName);
          +
          +            for (i = 0; i < elem.attributes.length; i++) {
          +                el.setAttribute(elem.attributes[i].nodeName.toLowerCase(),
          +                                elem.attributes[i].value);
          +            }
          +
          +            for (i = 0; i < elem.childNodes.length; i++) {
          +                el.appendChild(Strophe.copyElement(elem.childNodes[i]));
          +            }
          +        } else if (elem.nodeType == Strophe.ElementType.TEXT) {
          +            el = Strophe.xmlGenerator().createTextNode(elem.nodeValue);
          +        }
          +
          +        return el;
          +    },
          +
          +
          +    /** Function: createHtml
          +     *  Copy an HTML DOM element into an XML DOM.
          +     *
          +     *  This function copies a DOM element and all its descendants and returns
          +     *  the new copy.
          +     *
          +     *  Parameters:
          +     *    (HTMLElement) elem - A DOM element.
          +     *
          +     *  Returns:
          +     *    A new, copied DOM element tree.
          +     */
          +    createHtml: function (elem)
          +    {
          +        var i, el, j, tag, attribute, value, css, cssAttrs, attr, cssName, cssValue;
          +        if (elem.nodeType == Strophe.ElementType.NORMAL) {
          +            tag = elem.nodeName.toLowerCase();
          +            if(Strophe.XHTML.validTag(tag)) {
          +                try {
          +                    el = Strophe.xmlElement(tag);
          +                    for(i = 0; i < Strophe.XHTML.attributes[tag].length; i++) {
          +                        attribute = Strophe.XHTML.attributes[tag][i];
          +                        value = elem.getAttribute(attribute);
          +                        if(typeof value == 'undefined' || value === null || value === '' || value === false || value === 0) {
          +                            continue;
          +                        }
          +                        if(attribute == 'style' && typeof value == 'object') {
          +                            if(typeof value.cssText != 'undefined') {
          +                                value = value.cssText; // we're dealing with IE, need to get CSS out
          +                            }
          +                        }
          +                        // filter out invalid css styles
          +                        if(attribute == 'style') {
          +                            css = [];
          +                            cssAttrs = value.split(';');
          +                            for(j = 0; j < cssAttrs.length; j++) {
          +                                attr = cssAttrs[j].split(':');
          +                                cssName = attr[0].replace(/^\s*/, "").replace(/\s*$/, "").toLowerCase();
          +                                if(Strophe.XHTML.validCSS(cssName)) {
          +                                    cssValue = attr[1].replace(/^\s*/, "").replace(/\s*$/, "");
          +                                    css.push(cssName + ': ' + cssValue);
          +                                }
          +                            }
          +                            if(css.length > 0) {
          +                                value = css.join('; ');
          +                                el.setAttribute(attribute, value);
          +                            }
          +                        } else {
          +                            el.setAttribute(attribute, value);
          +                        }
          +                    }
          +
          +                    for (i = 0; i < elem.childNodes.length; i++) {
          +                        el.appendChild(Strophe.createHtml(elem.childNodes[i]));
          +                    }
          +                } catch(e) { // invalid elements
          +                  el = Strophe.xmlTextNode('');
          +                }
          +            } else {
          +                el = Strophe.xmlGenerator().createDocumentFragment();
          +                for (i = 0; i < elem.childNodes.length; i++) {
          +                    el.appendChild(Strophe.createHtml(elem.childNodes[i]));
          +                }
          +            }
          +        } else if (elem.nodeType == Strophe.ElementType.FRAGMENT) {
          +            el = Strophe.xmlGenerator().createDocumentFragment();
          +            for (i = 0; i < elem.childNodes.length; i++) {
          +                el.appendChild(Strophe.createHtml(elem.childNodes[i]));
          +            }
          +        } else if (elem.nodeType == Strophe.ElementType.TEXT) {
          +            el = Strophe.xmlTextNode(elem.nodeValue);
          +        }
          +
          +        return el;
          +    },
          +
          +    /** Function: escapeNode
          +     *  Escape the node part (also called local part) of a JID.
          +     *
          +     *  Parameters:
          +     *    (String) node - A node (or local part).
          +     *
          +     *  Returns:
          +     *    An escaped node (or local part).
          +     */
          +    escapeNode: function (node)
          +    {
          +        return node.replace(/^\s+|\s+$/g, '')
          +            .replace(/\\/g,  "\\5c")
          +            .replace(/ /g,   "\\20")
          +            .replace(/\"/g,  "\\22")
          +            .replace(/\&/g,  "\\26")
          +            .replace(/\'/g,  "\\27")
          +            .replace(/\//g,  "\\2f")
          +            .replace(/:/g,   "\\3a")
          +            .replace(/</g,   "\\3c")
          +            .replace(/>/g,   "\\3e")
          +            .replace(/@/g,   "\\40");
          +    },
          +
          +    /** Function: unescapeNode
          +     *  Unescape a node part (also called local part) of a JID.
          +     *
          +     *  Parameters:
          +     *    (String) node - A node (or local part).
          +     *
          +     *  Returns:
          +     *    An unescaped node (or local part).
          +     */
          +    unescapeNode: function (node)
          +    {
          +        return node.replace(/\\20/g, " ")
          +            .replace(/\\22/g, '"')
          +            .replace(/\\26/g, "&")
          +            .replace(/\\27/g, "'")
          +            .replace(/\\2f/g, "/")
          +            .replace(/\\3a/g, ":")
          +            .replace(/\\3c/g, "<")
          +            .replace(/\\3e/g, ">")
          +            .replace(/\\40/g, "@")
          +            .replace(/\\5c/g, "\\");
          +    },
          +
          +    /** Function: getNodeFromJid
          +     *  Get the node portion of a JID String.
          +     *
          +     *  Parameters:
          +     *    (String) jid - A JID.
          +     *
          +     *  Returns:
          +     *    A String containing the node.
          +     */
          +    getNodeFromJid: function (jid)
          +    {
          +        if (jid.indexOf("@") < 0) { return null; }
          +        return jid.split("@")[0];
          +    },
          +
          +    /** Function: getDomainFromJid
          +     *  Get the domain portion of a JID String.
          +     *
          +     *  Parameters:
          +     *    (String) jid - A JID.
          +     *
          +     *  Returns:
          +     *    A String containing the domain.
          +     */
          +    getDomainFromJid: function (jid)
          +    {
          +        var bare = Strophe.getBareJidFromJid(jid);
          +        if (bare.indexOf("@") < 0) {
          +            return bare;
          +        } else {
          +            var parts = bare.split("@");
          +            parts.splice(0, 1);
          +            return parts.join('@');
          +        }
          +    },
          +
          +    /** Function: getResourceFromJid
          +     *  Get the resource portion of a JID String.
          +     *
          +     *  Parameters:
          +     *    (String) jid - A JID.
          +     *
          +     *  Returns:
          +     *    A String containing the resource.
          +     */
          +    getResourceFromJid: function (jid)
          +    {
          +        var s = jid.split("/");
          +        if (s.length < 2) { return null; }
          +        s.splice(0, 1);
          +        return s.join('/');
          +    },
          +
          +    /** Function: getBareJidFromJid
          +     *  Get the bare JID from a JID String.
          +     *
          +     *  Parameters:
          +     *    (String) jid - A JID.
          +     *
          +     *  Returns:
          +     *    A String containing the bare JID.
          +     */
          +    getBareJidFromJid: function (jid)
          +    {
          +        return jid ? jid.split("/")[0] : null;
          +    },
          +
          +    /** Function: log
          +     *  User overrideable logging function.
          +     *
          +     *  This function is called whenever the Strophe library calls any
          +     *  of the logging functions.  The default implementation of this
          +     *  function does nothing.  If client code wishes to handle the logging
          +     *  messages, it should override this with
          +     *  > Strophe.log = function (level, msg) {
          +     *  >   (user code here)
          +     *  > };
          +     *
          +     *  Please note that data sent and received over the wire is logged
          +     *  via Strophe.Connection.rawInput() and Strophe.Connection.rawOutput().
          +     *
          +     *  The different levels and their meanings are
          +     *
          +     *    DEBUG - Messages useful for debugging purposes.
          +     *    INFO - Informational messages.  This is mostly information like
          +     *      'disconnect was called' or 'SASL auth succeeded'.
          +     *    WARN - Warnings about potential problems.  This is mostly used
          +     *      to report transient connection errors like request timeouts.
          +     *    ERROR - Some error occurred.
          +     *    FATAL - A non-recoverable fatal error occurred.
          +     *
          +     *  Parameters:
          +     *    (Integer) level - The log level of the log message.  This will
          +     *      be one of the values in Strophe.LogLevel.
          +     *    (String) msg - The log message.
          +     */
          +    /* jshint ignore:start */
          +    log: function (level, msg)
          +    {
          +        return;
          +    },
          +    /* jshint ignore:end */
          +
          +    /** Function: debug
          +     *  Log a message at the Strophe.LogLevel.DEBUG level.
          +     *
          +     *  Parameters:
          +     *    (String) msg - The log message.
          +     */
          +    debug: function(msg)
          +    {
          +        this.log(this.LogLevel.DEBUG, msg);
          +    },
          +
          +    /** Function: info
          +     *  Log a message at the Strophe.LogLevel.INFO level.
          +     *
          +     *  Parameters:
          +     *    (String) msg - The log message.
          +     */
          +    info: function (msg)
          +    {
          +        this.log(this.LogLevel.INFO, msg);
          +    },
          +
          +    /** Function: warn
          +     *  Log a message at the Strophe.LogLevel.WARN level.
          +     *
          +     *  Parameters:
          +     *    (String) msg - The log message.
          +     */
          +    warn: function (msg)
          +    {
          +        this.log(this.LogLevel.WARN, msg);
          +    },
          +
          +    /** Function: error
          +     *  Log a message at the Strophe.LogLevel.ERROR level.
          +     *
          +     *  Parameters:
          +     *    (String) msg - The log message.
          +     */
          +    error: function (msg)
          +    {
          +        this.log(this.LogLevel.ERROR, msg);
          +    },
          +
          +    /** Function: fatal
          +     *  Log a message at the Strophe.LogLevel.FATAL level.
          +     *
          +     *  Parameters:
          +     *    (String) msg - The log message.
          +     */
          +    fatal: function (msg)
          +    {
          +        this.log(this.LogLevel.FATAL, msg);
          +    },
          +
          +    /** Function: serialize
          +     *  Render a DOM element and all descendants to a String.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - A DOM element.
          +     *
          +     *  Returns:
          +     *    The serialized element tree as a String.
          +     */
          +    serialize: function (elem)
          +    {
          +        var result;
          +
          +        if (!elem) { return null; }
          +
          +        if (typeof(elem.tree) === "function") {
          +            elem = elem.tree();
          +        }
          +
          +        var nodeName = elem.nodeName;
          +        var i, child;
          +
          +        if (elem.getAttribute("_realname")) {
          +            nodeName = elem.getAttribute("_realname");
          +        }
          +
          +        result = "<" + nodeName;
          +        for (i = 0; i < elem.attributes.length; i++) {
          +               if(elem.attributes[i].nodeName != "_realname") {
          +                 result += " " + elem.attributes[i].nodeName.toLowerCase() +
          +                "='" + elem.attributes[i].value
          +                    .replace(/&/g, "&amp;")
          +                       .replace(/\'/g, "&apos;")
          +                       .replace(/>/g, "&gt;")
          +                       .replace(/</g, "&lt;") + "'";
          +               }
          +        }
          +
          +        if (elem.childNodes.length > 0) {
          +            result += ">";
          +            for (i = 0; i < elem.childNodes.length; i++) {
          +                child = elem.childNodes[i];
          +                switch( child.nodeType ){
          +                  case Strophe.ElementType.NORMAL:
          +                    // normal element, so recurse
          +                    result += Strophe.serialize(child);
          +                    break;
          +                  case Strophe.ElementType.TEXT:
          +                    // text element to escape values
          +                    result += Strophe.xmlescape(child.nodeValue);
          +                    break;
          +                  case Strophe.ElementType.CDATA:
          +                    // cdata section so don't escape values
          +                    result += "<![CDATA["+child.nodeValue+"]]>";
          +                }
          +            }
          +            result += "</" + nodeName + ">";
          +        } else {
          +            result += "/>";
          +        }
          +
          +        return result;
          +    },
          +
          +    /** PrivateVariable: _requestId
          +     *  _Private_ variable that keeps track of the request ids for
          +     *  connections.
          +     */
          +    _requestId: 0,
          +
          +    /** PrivateVariable: Strophe.connectionPlugins
          +     *  _Private_ variable Used to store plugin names that need
          +     *  initialization on Strophe.Connection construction.
          +     */
          +    _connectionPlugins: {},
          +
          +    /** Function: addConnectionPlugin
          +     *  Extends the Strophe.Connection object with the given plugin.
          +     *
          +     *  Parameters:
          +     *    (String) name - The name of the extension.
          +     *    (Object) ptype - The plugin's prototype.
          +     */
          +    addConnectionPlugin: function (name, ptype)
          +    {
          +        Strophe._connectionPlugins[name] = ptype;
          +    }
          +};
          +
          +/** Class: Strophe.Builder
          + *  XML DOM builder.
          + *
          + *  This object provides an interface similar to JQuery but for building
          + *  DOM element easily and rapidly.  All the functions except for toString()
          + *  and tree() return the object, so calls can be chained.  Here's an
          + *  example using the $iq() builder helper.
          + *  > $iq({to: 'you', from: 'me', type: 'get', id: '1'})
          + *  >     .c('query', {xmlns: 'strophe:example'})
          + *  >     .c('example')
          + *  >     .toString()
          + *  The above generates this XML fragment
          + *  > <iq to='you' from='me' type='get' id='1'>
          + *  >   <query xmlns='strophe:example'>
          + *  >     <example/>
          + *  >   </query>
          + *  > </iq>
          + *  The corresponding DOM manipulations to get a similar fragment would be
          + *  a lot more tedious and probably involve several helper variables.
          + *
          + *  Since adding children makes new operations operate on the child, up()
          + *  is provided to traverse up the tree.  To add two children, do
          + *  > builder.c('child1', ...).up().c('child2', ...)
          + *  The next operation on the Builder will be relative to the second child.
          + */
          +
          +/** Constructor: Strophe.Builder
          + *  Create a Strophe.Builder object.
          + *
          + *  The attributes should be passed in object notation.  For example
          + *  > var b = new Builder('message', {to: 'you', from: 'me'});
          + *  or
          + *  > var b = new Builder('messsage', {'xml:lang': 'en'});
          + *
          + *  Parameters:
          + *    (String) name - The name of the root element.
          + *    (Object) attrs - The attributes for the root element in object notation.
          + *
          + *  Returns:
          + *    A new Strophe.Builder.
          + */
          +Strophe.Builder = function (name, attrs)
          +{
          +    // Set correct namespace for jabber:client elements
          +    if (name == "presence" || name == "message" || name == "iq") {
          +        if (attrs && !attrs.xmlns) {
          +            attrs.xmlns = Strophe.NS.CLIENT;
          +        } else if (!attrs) {
          +            attrs = {xmlns: Strophe.NS.CLIENT};
          +        }
          +    }
          +
          +    // Holds the tree being built.
          +    this.nodeTree = Strophe.xmlElement(name, attrs);
          +
          +    // Points to the current operation node.
          +    this.node = this.nodeTree;
          +};
          +
          +Strophe.Builder.prototype = {
          +    /** Function: tree
          +     *  Return the DOM tree.
          +     *
          +     *  This function returns the current DOM tree as an element object.  This
          +     *  is suitable for passing to functions like Strophe.Connection.send().
          +     *
          +     *  Returns:
          +     *    The DOM tree as a element object.
          +     */
          +    tree: function ()
          +    {
          +        return this.nodeTree;
          +    },
          +
          +    /** Function: toString
          +     *  Serialize the DOM tree to a String.
          +     *
          +     *  This function returns a string serialization of the current DOM
          +     *  tree.  It is often used internally to pass data to a
          +     *  Strophe.Request object.
          +     *
          +     *  Returns:
          +     *    The serialized DOM tree in a String.
          +     */
          +    toString: function ()
          +    {
          +        return Strophe.serialize(this.nodeTree);
          +    },
          +
          +    /** Function: up
          +     *  Make the current parent element the new current element.
          +     *
          +     *  This function is often used after c() to traverse back up the tree.
          +     *  For example, to add two children to the same element
          +     *  > builder.c('child1', {}).up().c('child2', {});
          +     *
          +     *  Returns:
          +     *    The Stophe.Builder object.
          +     */
          +    up: function ()
          +    {
          +        this.node = this.node.parentNode;
          +        return this;
          +    },
          +
          +    /** Function: attrs
          +     *  Add or modify attributes of the current element.
          +     *
          +     *  The attributes should be passed in object notation.  This function
          +     *  does not move the current element pointer.
          +     *
          +     *  Parameters:
          +     *    (Object) moreattrs - The attributes to add/modify in object notation.
          +     *
          +     *  Returns:
          +     *    The Strophe.Builder object.
          +     */
          +    attrs: function (moreattrs)
          +    {
          +        for (var k in moreattrs) {
          +            if (moreattrs.hasOwnProperty(k)) {
          +                this.node.setAttribute(k, moreattrs[k]);
          +            }
          +        }
          +        return this;
          +    },
          +
          +    /** Function: c
          +     *  Add a child to the current element and make it the new current
          +     *  element.
          +     *
          +     *  This function moves the current element pointer to the child,
          +     *  unless text is provided.  If you need to add another child, it
          +     *  is necessary to use up() to go back to the parent in the tree.
          +     *
          +     *  Parameters:
          +     *    (String) name - The name of the child.
          +     *    (Object) attrs - The attributes of the child in object notation.
          +     *    (String) text - The text to add to the child.
          +     *
          +     *  Returns:
          +     *    The Strophe.Builder object.
          +     */
          +    c: function (name, attrs, text)
          +    {
          +        var child = Strophe.xmlElement(name, attrs, text);
          +        this.node.appendChild(child);
          +        if (!text) {
          +            this.node = child;
          +        }
          +        return this;
          +    },
          +
          +    /** Function: cnode
          +     *  Add a child to the current element and make it the new current
          +     *  element.
          +     *
          +     *  This function is the same as c() except that instead of using a
          +     *  name and an attributes object to create the child it uses an
          +     *  existing DOM element object.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - A DOM element.
          +     *
          +     *  Returns:
          +     *    The Strophe.Builder object.
          +     */
          +    cnode: function (elem)
          +    {
          +        var impNode;
          +        var xmlGen = Strophe.xmlGenerator();
          +        try {
          +            impNode = (xmlGen.importNode !== undefined);
          +        }
          +        catch (e) {
          +            impNode = false;
          +        }
          +        var newElem = impNode ?
          +                      xmlGen.importNode(elem, true) :
          +                      Strophe.copyElement(elem);
          +        this.node.appendChild(newElem);
          +        this.node = newElem;
          +        return this;
          +    },
          +
          +    /** Function: t
          +     *  Add a child text element.
          +     *
          +     *  This *does not* make the child the new current element since there
          +     *  are no children of text elements.
          +     *
          +     *  Parameters:
          +     *    (String) text - The text data to append to the current element.
          +     *
          +     *  Returns:
          +     *    The Strophe.Builder object.
          +     */
          +    t: function (text)
          +    {
          +        var child = Strophe.xmlTextNode(text);
          +        this.node.appendChild(child);
          +        return this;
          +    },
          +
          +    /** Function: h
          +     *  Replace current element contents with the HTML passed in.
          +     *
          +     *  This *does not* make the child the new current element
          +     *
          +     *  Parameters:
          +     *    (String) html - The html to insert as contents of current element.
          +     *
          +     *  Returns:
          +     *    The Strophe.Builder object.
          +     */
          +    h: function (html)
          +    {
          +        var fragment = document.createElement('body');
          +
          +        // force the browser to try and fix any invalid HTML tags
          +        fragment.innerHTML = html;
          +
          +        // copy cleaned html into an xml dom
          +        var xhtml = Strophe.createHtml(fragment);
          +
          +        while(xhtml.childNodes.length > 0) {
          +            this.node.appendChild(xhtml.childNodes[0]);
          +        }
          +        return this;
          +    }
          +};
          +
          +/** PrivateClass: Strophe.Handler
          + *  _Private_ helper class for managing stanza handlers.
          + *
          + *  A Strophe.Handler encapsulates a user provided callback function to be
          + *  executed when matching stanzas are received by the connection.
          + *  Handlers can be either one-off or persistant depending on their
          + *  return value. Returning true will cause a Handler to remain active, and
          + *  returning false will remove the Handler.
          + *
          + *  Users will not use Strophe.Handler objects directly, but instead they
          + *  will use Strophe.Connection.addHandler() and
          + *  Strophe.Connection.deleteHandler().
          + */
          +
          +/** PrivateConstructor: Strophe.Handler
          + *  Create and initialize a new Strophe.Handler.
          + *
          + *  Parameters:
          + *    (Function) handler - A function to be executed when the handler is run.
          + *    (String) ns - The namespace to match.
          + *    (String) name - The element name to match.
          + *    (String) type - The element type to match.
          + *    (String) id - The element id attribute to match.
          + *    (String) from - The element from attribute to match.
          + *    (Object) options - Handler options
          + *
          + *  Returns:
          + *    A new Strophe.Handler object.
          + */
          +Strophe.Handler = function (handler, ns, name, type, id, from, options)
          +{
          +    this.handler = handler;
          +    this.ns = ns;
          +    this.name = name;
          +    this.type = type;
          +    this.id = id;
          +    this.options = options || {matchBare: false};
          +
          +    // default matchBare to false if undefined
          +    if (!this.options.matchBare) {
          +        this.options.matchBare = false;
          +    }
          +
          +    if (this.options.matchBare) {
          +        this.from = from ? Strophe.getBareJidFromJid(from) : null;
          +    } else {
          +        this.from = from;
          +    }
          +
          +    // whether the handler is a user handler or a system handler
          +    this.user = true;
          +};
          +
          +Strophe.Handler.prototype = {
          +    /** PrivateFunction: isMatch
          +     *  Tests if a stanza matches the Strophe.Handler.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The XML element to test.
          +     *
          +     *  Returns:
          +     *    true if the stanza matches and false otherwise.
          +     */
          +    isMatch: function (elem)
          +    {
          +        var nsMatch;
          +        var from = null;
          +
          +        if (this.options.matchBare) {
          +            from = Strophe.getBareJidFromJid(elem.getAttribute('from'));
          +        } else {
          +            from = elem.getAttribute('from');
          +        }
          +
          +        nsMatch = false;
          +        if (!this.ns) {
          +            nsMatch = true;
          +        } else {
          +            var that = this;
          +            Strophe.forEachChild(elem, null, function (elem) {
          +                if (elem.getAttribute("xmlns") == that.ns) {
          +                    nsMatch = true;
          +                }
          +            });
          +
          +            nsMatch = nsMatch || elem.getAttribute("xmlns") == this.ns;
          +        }
          +
          +        if (nsMatch &&
          +            (!this.name || Strophe.isTagEqual(elem, this.name)) &&
          +            (!this.type || elem.getAttribute("type") == this.type) &&
          +            (!this.id || elem.getAttribute("id") == this.id) &&
          +            (!this.from || from == this.from)) {
          +                return true;
          +        }
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: run
          +     *  Run the callback on a matching stanza.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The DOM element that triggered the
          +     *      Strophe.Handler.
          +     *
          +     *  Returns:
          +     *    A boolean indicating if the handler should remain active.
          +     */
          +    run: function (elem)
          +    {
          +        var result = null;
          +        try {
          +            result = this.handler(elem);
          +        } catch (e) {
          +            if (e.sourceURL) {
          +                Strophe.fatal("error: " + this.handler +
          +                              " " + e.sourceURL + ":" +
          +                              e.line + " - " + e.name + ": " + e.message);
          +            } else if (e.fileName) {
          +                if (typeof(console) != "undefined") {
          +                    console.trace();
          +                    console.error(this.handler, " - error - ", e, e.message);
          +                }
          +                Strophe.fatal("error: " + this.handler + " " +
          +                              e.fileName + ":" + e.lineNumber + " - " +
          +                              e.name + ": " + e.message);
          +            } else {
          +                Strophe.fatal("error: " + e.message + "\n" + e.stack);
          +            }
          +
          +            throw e;
          +        }
          +
          +        return result;
          +    },
          +
          +    /** PrivateFunction: toString
          +     *  Get a String representation of the Strophe.Handler object.
          +     *
          +     *  Returns:
          +     *    A String.
          +     */
          +    toString: function ()
          +    {
          +        return "{Handler: " + this.handler + "(" + this.name + "," +
          +            this.id + "," + this.ns + ")}";
          +    }
          +};
          +
          +/** PrivateClass: Strophe.TimedHandler
          + *  _Private_ helper class for managing timed handlers.
          + *
          + *  A Strophe.TimedHandler encapsulates a user provided callback that
          + *  should be called after a certain period of time or at regular
          + *  intervals.  The return value of the callback determines whether the
          + *  Strophe.TimedHandler will continue to fire.
          + *
          + *  Users will not use Strophe.TimedHandler objects directly, but instead
          + *  they will use Strophe.Connection.addTimedHandler() and
          + *  Strophe.Connection.deleteTimedHandler().
          + */
          +
          +/** PrivateConstructor: Strophe.TimedHandler
          + *  Create and initialize a new Strophe.TimedHandler object.
          + *
          + *  Parameters:
          + *    (Integer) period - The number of milliseconds to wait before the
          + *      handler is called.
          + *    (Function) handler - The callback to run when the handler fires.  This
          + *      function should take no arguments.
          + *
          + *  Returns:
          + *    A new Strophe.TimedHandler object.
          + */
          +Strophe.TimedHandler = function (period, handler)
          +{
          +    this.period = period;
          +    this.handler = handler;
          +
          +    this.lastCalled = new Date().getTime();
          +    this.user = true;
          +};
          +
          +Strophe.TimedHandler.prototype = {
          +    /** PrivateFunction: run
          +     *  Run the callback for the Strophe.TimedHandler.
          +     *
          +     *  Returns:
          +     *    true if the Strophe.TimedHandler should be called again, and false
          +     *      otherwise.
          +     */
          +    run: function ()
          +    {
          +        this.lastCalled = new Date().getTime();
          +        return this.handler();
          +    },
          +
          +    /** PrivateFunction: reset
          +     *  Reset the last called time for the Strophe.TimedHandler.
          +     */
          +    reset: function ()
          +    {
          +        this.lastCalled = new Date().getTime();
          +    },
          +
          +    /** PrivateFunction: toString
          +     *  Get a string representation of the Strophe.TimedHandler object.
          +     *
          +     *  Returns:
          +     *    The string representation.
          +     */
          +    toString: function ()
          +    {
          +        return "{TimedHandler: " + this.handler + "(" + this.period +")}";
          +    }
          +};
          +
          +/** Class: Strophe.Connection
          + *  XMPP Connection manager.
          + *
          + *  This class is the main part of Strophe.  It manages a BOSH connection
          + *  to an XMPP server and dispatches events to the user callbacks as
          + *  data arrives.  It supports SASL PLAIN, SASL DIGEST-MD5, SASL SCRAM-SHA1
          + *  and legacy authentication.
          + *
          + *  After creating a Strophe.Connection object, the user will typically
          + *  call connect() with a user supplied callback to handle connection level
          + *  events like authentication failure, disconnection, or connection
          + *  complete.
          + *
          + *  The user will also have several event handlers defined by using
          + *  addHandler() and addTimedHandler().  These will allow the user code to
          + *  respond to interesting stanzas or do something periodically with the
          + *  connection.  These handlers will be active once authentication is
          + *  finished.
          + *
          + *  To send data to the connection, use send().
          + */
          +
          +/** Constructor: Strophe.Connection
          + *  Create and initialize a Strophe.Connection object.
          + *
          + *  The transport-protocol for this connection will be chosen automatically
          + *  based on the given service parameter. URLs starting with "ws://" or
          + *  "wss://" will use WebSockets, URLs starting with "http://", "https://"
          + *  or without a protocol will use BOSH.
          + *
          + *  To make Strophe connect to the current host you can leave out the protocol
          + *  and host part and just pass the path, e.g.
          + *
          + *  > var conn = new Strophe.Connection("/http-bind/");
          + *
          + *  WebSocket options:
          + *
          + *  If you want to connect to the current host with a WebSocket connection you
          + *  can tell Strophe to use WebSockets through a "protocol" attribute in the
          + *  optional options parameter. Valid values are "ws" for WebSocket and "wss"
          + *  for Secure WebSocket.
          + *  So to connect to "wss://CURRENT_HOSTNAME/xmpp-websocket" you would call
          + *
          + *  > var conn = new Strophe.Connection("/xmpp-websocket/", {protocol: "wss"});
          + *
          + *  Note that relative URLs _NOT_ starting with a "/" will also include the path
          + *  of the current site.
          + *
          + *  Also because downgrading security is not permitted by browsers, when using
          + *  relative URLs both BOSH and WebSocket connections will use their secure
          + *  variants if the current connection to the site is also secure (https).
          + *
          + *  BOSH options:
          + *
          + *  by adding "sync" to the options, you can control if requests will
          + *  be made synchronously or not. The default behaviour is asynchronous.
          + *  If you want to make requests synchronous, make "sync" evaluate to true:
          + *  > var conn = new Strophe.Connection("/http-bind/", {sync: true});
          + *  You can also toggle this on an already established connection:
          + *  > conn.options.sync = true;
          + *
          + *
          + *  Parameters:
          + *    (String) service - The BOSH or WebSocket service URL.
          + *    (Object) options - A hash of configuration options
          + *
          + *  Returns:
          + *    A new Strophe.Connection object.
          + */
          +Strophe.Connection = function (service, options)
          +{
          +    // The service URL
          +    this.service = service;
          +
          +    // Configuration options
          +    this.options = options || {};
          +    var proto = this.options.protocol || "";
          +
          +    // Select protocal based on service or options
          +    if (service.indexOf("ws:") === 0 || service.indexOf("wss:") === 0 ||
          +            proto.indexOf("ws") === 0) {
          +        this._proto = new Strophe.Websocket(this);
          +    } else {
          +        this._proto = new Strophe.Bosh(this);
          +    }
          +    /* The connected JID. */
          +    this.jid = "";
          +    /* the JIDs domain */
          +    this.domain = null;
          +    /* stream:features */
          +    this.features = null;
          +
          +    // SASL
          +    this._sasl_data = {};
          +    this.do_session = false;
          +    this.do_bind = false;
          +
          +    // handler lists
          +    this.timedHandlers = [];
          +    this.handlers = [];
          +    this.removeTimeds = [];
          +    this.removeHandlers = [];
          +    this.addTimeds = [];
          +    this.addHandlers = [];
          +
          +    this._authentication = {};
          +    this._idleTimeout = null;
          +    this._disconnectTimeout = null;
          +
          +    this.do_authentication = true;
          +    this.authenticated = false;
          +    this.disconnecting = false;
          +    this.connected = false;
          +
          +    this.errors = 0;
          +
          +    this.paused = false;
          +
          +    this._data = [];
          +    this._uniqueId = 0;
          +
          +    this._sasl_success_handler = null;
          +    this._sasl_failure_handler = null;
          +    this._sasl_challenge_handler = null;
          +
          +    // Max retries before disconnecting
          +    this.maxRetries = 5;
          +
          +    // setup onIdle callback every 1/10th of a second
          +    this._idleTimeout = setTimeout(this._onIdle.bind(this), 100);
          +
          +    // initialize plugins
          +    for (var k in Strophe._connectionPlugins) {
          +        if (Strophe._connectionPlugins.hasOwnProperty(k)) {
          +            var ptype = Strophe._connectionPlugins[k];
          +            // jslint complaints about the below line, but this is fine
          +            var F = function () {}; // jshint ignore:line
          +            F.prototype = ptype;
          +            this[k] = new F();
          +            this[k].init(this);
          +        }
          +    }
          +};
          +
          +Strophe.Connection.prototype = {
          +    /** Function: reset
          +     *  Reset the connection.
          +     *
          +     *  This function should be called after a connection is disconnected
          +     *  before that connection is reused.
          +     */
          +    reset: function ()
          +    {
          +        this._proto._reset();
          +
          +        // SASL
          +        this.do_session = false;
          +        this.do_bind = false;
          +
          +        // handler lists
          +        this.timedHandlers = [];
          +        this.handlers = [];
          +        this.removeTimeds = [];
          +        this.removeHandlers = [];
          +        this.addTimeds = [];
          +        this.addHandlers = [];
          +        this._authentication = {};
          +
          +        this.authenticated = false;
          +        this.disconnecting = false;
          +        this.connected = false;
          +
          +        this.errors = 0;
          +
          +        this._requests = [];
          +        this._uniqueId = 0;
          +    },
          +
          +    /** Function: pause
          +     *  Pause the request manager.
          +     *
          +     *  This will prevent Strophe from sending any more requests to the
          +     *  server.  This is very useful for temporarily pausing
          +     *  BOSH-Connections while a lot of send() calls are happening quickly.
          +     *  This causes Strophe to send the data in a single request, saving
          +     *  many request trips.
          +     */
          +    pause: function ()
          +    {
          +        this.paused = true;
          +    },
          +
          +    /** Function: resume
          +     *  Resume the request manager.
          +     *
          +     *  This resumes after pause() has been called.
          +     */
          +    resume: function ()
          +    {
          +        this.paused = false;
          +    },
          +
          +    /** Function: getUniqueId
          +     *  Generate a unique ID for use in <iq/> elements.
          +     *
          +     *  All <iq/> stanzas are required to have unique id attributes.  This
          +     *  function makes creating these easy.  Each connection instance has
          +     *  a counter which starts from zero, and the value of this counter
          +     *  plus a colon followed by the suffix becomes the unique id. If no
          +     *  suffix is supplied, the counter is used as the unique id.
          +     *
          +     *  Suffixes are used to make debugging easier when reading the stream
          +     *  data, and their use is recommended.  The counter resets to 0 for
          +     *  every new connection for the same reason.  For connections to the
          +     *  same server that authenticate the same way, all the ids should be
          +     *  the same, which makes it easy to see changes.  This is useful for
          +     *  automated testing as well.
          +     *
          +     *  Parameters:
          +     *    (String) suffix - A optional suffix to append to the id.
          +     *
          +     *  Returns:
          +     *    A unique string to be used for the id attribute.
          +     */
          +    getUniqueId: function (suffix)
          +    {
          +        if (typeof(suffix) == "string" || typeof(suffix) == "number") {
          +            return ++this._uniqueId + ":" + suffix;
          +        } else {
          +            return ++this._uniqueId + "";
          +        }
          +    },
          +
          +    /** Function: connect
          +     *  Starts the connection process.
          +     *
          +     *  As the connection process proceeds, the user supplied callback will
          +     *  be triggered multiple times with status updates.  The callback
          +     *  should take two arguments - the status code and the error condition.
          +     *
          +     *  The status code will be one of the values in the Strophe.Status
          +     *  constants.  The error condition will be one of the conditions
          +     *  defined in RFC 3920 or the condition 'strophe-parsererror'.
          +     *
          +     *  The Parameters _wait_, _hold_ and _route_ are optional and only relevant
          +     *  for BOSH connections. Please see XEP 124 for a more detailed explanation
          +     *  of the optional parameters.
          +     *
          +     *  Parameters:
          +     *    (String) jid - The user's JID.  This may be a bare JID,
          +     *      or a full JID.  If a node is not supplied, SASL ANONYMOUS
          +     *      authentication will be attempted.
          +     *    (String) pass - The user's password.
          +     *    (Function) callback - The connect callback function.
          +     *    (Integer) wait - The optional HTTPBIND wait value.  This is the
          +     *      time the server will wait before returning an empty result for
          +     *      a request.  The default setting of 60 seconds is recommended.
          +     *    (Integer) hold - The optional HTTPBIND hold value.  This is the
          +     *      number of connections the server will hold at one time.  This
          +     *      should almost always be set to 1 (the default).
          +     *    (String) route - The optional route value.
          +     */
          +    connect: function (jid, pass, callback, wait, hold, route)
          +    {
          +        this.jid = jid;
          +        /** Variable: authzid
          +         *  Authorization identity.
          +         */
          +        this.authzid = Strophe.getBareJidFromJid(this.jid);
          +        /** Variable: authcid
          +         *  Authentication identity (User name).
          +         */
          +        this.authcid = Strophe.getNodeFromJid(this.jid);
          +        /** Variable: pass
          +         *  Authentication identity (User password).
          +         */
          +        this.pass = pass;
          +        /** Variable: servtype
          +         *  Digest MD5 compatibility.
          +         */
          +        this.servtype = "xmpp";
          +        this.connect_callback = callback;
          +        this.disconnecting = false;
          +        this.connected = false;
          +        this.authenticated = false;
          +        this.errors = 0;
          +
          +        // parse jid for domain
          +        this.domain = Strophe.getDomainFromJid(this.jid);
          +
          +        this._changeConnectStatus(Strophe.Status.CONNECTING, null);
          +
          +        this._proto._connect(wait, hold, route);
          +    },
          +
          +    /** Function: attach
          +     *  Attach to an already created and authenticated BOSH session.
          +     *
          +     *  This function is provided to allow Strophe to attach to BOSH
          +     *  sessions which have been created externally, perhaps by a Web
          +     *  application.  This is often used to support auto-login type features
          +     *  without putting user credentials into the page.
          +     *
          +     *  Parameters:
          +     *    (String) jid - The full JID that is bound by the session.
          +     *    (String) sid - The SID of the BOSH session.
          +     *    (String) rid - The current RID of the BOSH session.  This RID
          +     *      will be used by the next request.
          +     *    (Function) callback The connect callback function.
          +     *    (Integer) wait - The optional HTTPBIND wait value.  This is the
          +     *      time the server will wait before returning an empty result for
          +     *      a request.  The default setting of 60 seconds is recommended.
          +     *      Other settings will require tweaks to the Strophe.TIMEOUT value.
          +     *    (Integer) hold - The optional HTTPBIND hold value.  This is the
          +     *      number of connections the server will hold at one time.  This
          +     *      should almost always be set to 1 (the default).
          +     *    (Integer) wind - The optional HTTBIND window value.  This is the
          +     *      allowed range of request ids that are valid.  The default is 5.
          +     */
          +    attach: function (jid, sid, rid, callback, wait, hold, wind)
          +    {
          +        this._proto._attach(jid, sid, rid, callback, wait, hold, wind);
          +    },
          +
          +    /** Function: xmlInput
          +     *  User overrideable function that receives XML data coming into the
          +     *  connection.
          +     *
          +     *  The default function does nothing.  User code can override this with
          +     *  > Strophe.Connection.xmlInput = function (elem) {
          +     *  >   (user code)
          +     *  > };
          +     *
          +     *  Due to limitations of current Browsers' XML-Parsers the opening and closing
          +     *  <stream> tag for WebSocket-Connoctions will be passed as selfclosing here.
          +     *
          +     *  BOSH-Connections will have all stanzas wrapped in a <body> tag. See
          +     *  <Strophe.Bosh.strip> if you want to strip this tag.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The XML data received by the connection.
          +     */
          +    /* jshint unused:false */
          +    xmlInput: function (elem)
          +    {
          +        return;
          +    },
          +    /* jshint unused:true */
          +
          +    /** Function: xmlOutput
          +     *  User overrideable function that receives XML data sent to the
          +     *  connection.
          +     *
          +     *  The default function does nothing.  User code can override this with
          +     *  > Strophe.Connection.xmlOutput = function (elem) {
          +     *  >   (user code)
          +     *  > };
          +     *
          +     *  Due to limitations of current Browsers' XML-Parsers the opening and closing
          +     *  <stream> tag for WebSocket-Connoctions will be passed as selfclosing here.
          +     *
          +     *  BOSH-Connections will have all stanzas wrapped in a <body> tag. See
          +     *  <Strophe.Bosh.strip> if you want to strip this tag.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The XMLdata sent by the connection.
          +     */
          +    /* jshint unused:false */
          +    xmlOutput: function (elem)
          +    {
          +        return;
          +    },
          +    /* jshint unused:true */
          +
          +    /** Function: rawInput
          +     *  User overrideable function that receives raw data coming into the
          +     *  connection.
          +     *
          +     *  The default function does nothing.  User code can override this with
          +     *  > Strophe.Connection.rawInput = function (data) {
          +     *  >   (user code)
          +     *  > };
          +     *
          +     *  Parameters:
          +     *    (String) data - The data received by the connection.
          +     */
          +    /* jshint unused:false */
          +    rawInput: function (data)
          +    {
          +        return;
          +    },
          +    /* jshint unused:true */
          +
          +    /** Function: rawOutput
          +     *  User overrideable function that receives raw data sent to the
          +     *  connection.
          +     *
          +     *  The default function does nothing.  User code can override this with
          +     *  > Strophe.Connection.rawOutput = function (data) {
          +     *  >   (user code)
          +     *  > };
          +     *
          +     *  Parameters:
          +     *    (String) data - The data sent by the connection.
          +     */
          +    /* jshint unused:false */
          +    rawOutput: function (data)
          +    {
          +        return;
          +    },
          +    /* jshint unused:true */
          +
          +    /** Function: send
          +     *  Send a stanza.
          +     *
          +     *  This function is called to push data onto the send queue to
          +     *  go out over the wire.  Whenever a request is sent to the BOSH
          +     *  server, all pending data is sent and the queue is flushed.
          +     *
          +     *  Parameters:
          +     *    (XMLElement |
          +     *     [XMLElement] |
          +     *     Strophe.Builder) elem - The stanza to send.
          +     */
          +    send: function (elem)
          +    {
          +        if (elem === null) { return ; }
          +        if (typeof(elem.sort) === "function") {
          +            for (var i = 0; i < elem.length; i++) {
          +                this._queueData(elem[i]);
          +            }
          +        } else if (typeof(elem.tree) === "function") {
          +            this._queueData(elem.tree());
          +        } else {
          +            this._queueData(elem);
          +        }
          +
          +        this._proto._send();
          +    },
          +
          +    /** Function: flush
          +     *  Immediately send any pending outgoing data.
          +     *
          +     *  Normally send() queues outgoing data until the next idle period
          +     *  (100ms), which optimizes network use in the common cases when
          +     *  several send()s are called in succession. flush() can be used to
          +     *  immediately send all pending data.
          +     */
          +    flush: function ()
          +    {
          +        // cancel the pending idle period and run the idle function
          +        // immediately
          +        clearTimeout(this._idleTimeout);
          +        this._onIdle();
          +    },
          +
          +    /** Function: sendIQ
          +     *  Helper function to send IQ stanzas.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The stanza to send.
          +     *    (Function) callback - The callback function for a successful request.
          +     *    (Function) errback - The callback function for a failed or timed
          +     *      out request.  On timeout, the stanza will be null.
          +     *    (Integer) timeout - The time specified in milliseconds for a
          +     *      timeout to occur.
          +     *
          +     *  Returns:
          +     *    The id used to send the IQ.
          +    */
          +    sendIQ: function(elem, callback, errback, timeout) {
          +        var timeoutHandler = null;
          +        var that = this;
          +
          +        if (typeof(elem.tree) === "function") {
          +            elem = elem.tree();
          +        }
          +        var id = elem.getAttribute('id');
          +
          +        // inject id if not found
          +        if (!id) {
          +            id = this.getUniqueId("sendIQ");
          +            elem.setAttribute("id", id);
          +        }
          +
          +        var handler = this.addHandler(function (stanza) {
          +            // remove timeout handler if there is one
          +            if (timeoutHandler) {
          +                that.deleteTimedHandler(timeoutHandler);
          +            }
          +
          +            var iqtype = stanza.getAttribute('type');
          +            if (iqtype == 'result') {
          +                if (callback) {
          +                    callback(stanza);
          +                }
          +            } else if (iqtype == 'error') {
          +                if (errback) {
          +                    errback(stanza);
          +                }
          +            } else {
          +                throw {
          +                    name: "StropheError",
          +            message: "Got bad IQ type of " + iqtype
          +                };
          +            }
          +        }, null, 'iq', null, id);
          +
          +        // if timeout specified, setup timeout handler.
          +        if (timeout) {
          +            timeoutHandler = this.addTimedHandler(timeout, function () {
          +                // get rid of normal handler
          +                that.deleteHandler(handler);
          +
          +                // call errback on timeout with null stanza
          +                if (errback) {
          +                    errback(null);
          +                }
          +                return false;
          +            });
          +        }
          +
          +        this.send(elem);
          +
          +        return id;
          +    },
          +
          +    /** PrivateFunction: _queueData
          +     *  Queue outgoing data for later sending.  Also ensures that the data
          +     *  is a DOMElement.
          +     */
          +    _queueData: function (element) {
          +        if (element === null ||
          +            !element.tagName ||
          +            !element.childNodes) {
          +            throw {
          +                name: "StropheError",
          +                message: "Cannot queue non-DOMElement."
          +            };
          +        }
          +
          +        this._data.push(element);
          +    },
          +
          +    /** PrivateFunction: _sendRestart
          +     *  Send an xmpp:restart stanza.
          +     */
          +    _sendRestart: function ()
          +    {
          +        this._data.push("restart");
          +
          +        this._proto._sendRestart();
          +
          +        this._idleTimeout = setTimeout(this._onIdle.bind(this), 100);
          +    },
          +
          +    /** Function: addTimedHandler
          +     *  Add a timed handler to the connection.
          +     *
          +     *  This function adds a timed handler.  The provided handler will
          +     *  be called every period milliseconds until it returns false,
          +     *  the connection is terminated, or the handler is removed.  Handlers
          +     *  that wish to continue being invoked should return true.
          +     *
          +     *  Because of method binding it is necessary to save the result of
          +     *  this function if you wish to remove a handler with
          +     *  deleteTimedHandler().
          +     *
          +     *  Note that user handlers are not active until authentication is
          +     *  successful.
          +     *
          +     *  Parameters:
          +     *    (Integer) period - The period of the handler.
          +     *    (Function) handler - The callback function.
          +     *
          +     *  Returns:
          +     *    A reference to the handler that can be used to remove it.
          +     */
          +    addTimedHandler: function (period, handler)
          +    {
          +        var thand = new Strophe.TimedHandler(period, handler);
          +        this.addTimeds.push(thand);
          +        return thand;
          +    },
          +
          +    /** Function: deleteTimedHandler
          +     *  Delete a timed handler for a connection.
          +     *
          +     *  This function removes a timed handler from the connection.  The
          +     *  handRef parameter is *not* the function passed to addTimedHandler(),
          +     *  but is the reference returned from addTimedHandler().
          +     *
          +     *  Parameters:
          +     *    (Strophe.TimedHandler) handRef - The handler reference.
          +     */
          +    deleteTimedHandler: function (handRef)
          +    {
          +        // this must be done in the Idle loop so that we don't change
          +        // the handlers during iteration
          +        this.removeTimeds.push(handRef);
          +    },
          +
          +    /** Function: addHandler
          +     *  Add a stanza handler for the connection.
          +     *
          +     *  This function adds a stanza handler to the connection.  The
          +     *  handler callback will be called for any stanza that matches
          +     *  the parameters.  Note that if multiple parameters are supplied,
          +     *  they must all match for the handler to be invoked.
          +     *
          +     *  The handler will receive the stanza that triggered it as its argument.
          +     *  The handler should return true if it is to be invoked again;
          +     *  returning false will remove the handler after it returns.
          +     *
          +     *  As a convenience, the ns parameters applies to the top level element
          +     *  and also any of its immediate children.  This is primarily to make
          +     *  matching /iq/query elements easy.
          +     *
          +     *  The options argument contains handler matching flags that affect how
          +     *  matches are determined. Currently the only flag is matchBare (a
          +     *  boolean). When matchBare is true, the from parameter and the from
          +     *  attribute on the stanza will be matched as bare JIDs instead of
          +     *  full JIDs. To use this, pass {matchBare: true} as the value of
          +     *  options. The default value for matchBare is false.
          +     *
          +     *  The return value should be saved if you wish to remove the handler
          +     *  with deleteHandler().
          +     *
          +     *  Parameters:
          +     *    (Function) handler - The user callback.
          +     *    (String) ns - The namespace to match.
          +     *    (String) name - The stanza name to match.
          +     *    (String) type - The stanza type attribute to match.
          +     *    (String) id - The stanza id attribute to match.
          +     *    (String) from - The stanza from attribute to match.
          +     *    (String) options - The handler options
          +     *
          +     *  Returns:
          +     *    A reference to the handler that can be used to remove it.
          +     */
          +    addHandler: function (handler, ns, name, type, id, from, options)
          +    {
          +        var hand = new Strophe.Handler(handler, ns, name, type, id, from, options);
          +        this.addHandlers.push(hand);
          +        return hand;
          +    },
          +
          +    /** Function: deleteHandler
          +     *  Delete a stanza handler for a connection.
          +     *
          +     *  This function removes a stanza handler from the connection.  The
          +     *  handRef parameter is *not* the function passed to addHandler(),
          +     *  but is the reference returned from addHandler().
          +     *
          +     *  Parameters:
          +     *    (Strophe.Handler) handRef - The handler reference.
          +     */
          +    deleteHandler: function (handRef)
          +    {
          +        // this must be done in the Idle loop so that we don't change
          +        // the handlers during iteration
          +        this.removeHandlers.push(handRef);
          +    },
          +
          +    /** Function: disconnect
          +     *  Start the graceful disconnection process.
          +     *
          +     *  This function starts the disconnection process.  This process starts
          +     *  by sending unavailable presence and sending BOSH body of type
          +     *  terminate.  A timeout handler makes sure that disconnection happens
          +     *  even if the BOSH server does not respond.
          +     *
          +     *  The user supplied connection callback will be notified of the
          +     *  progress as this process happens.
          +     *
          +     *  Parameters:
          +     *    (String) reason - The reason the disconnect is occuring.
          +     */
          +    disconnect: function (reason)
          +    {
          +        this._changeConnectStatus(Strophe.Status.DISCONNECTING, reason);
          +
          +        Strophe.info("Disconnect was called because: " + reason);
          +        if (this.connected) {
          +            var pres = false;
          +            this.disconnecting = true;
          +            if (this.authenticated) {
          +                pres = $pres({
          +                    xmlns: Strophe.NS.CLIENT,
          +                    type: 'unavailable'
          +                });
          +            }
          +            // setup timeout handler
          +            this._disconnectTimeout = this._addSysTimedHandler(
          +                3000, this._onDisconnectTimeout.bind(this));
          +            this._proto._disconnect(pres);
          +        }
          +    },
          +
          +    /** PrivateFunction: _changeConnectStatus
          +     *  _Private_ helper function that makes sure plugins and the user's
          +     *  callback are notified of connection status changes.
          +     *
          +     *  Parameters:
          +     *    (Integer) status - the new connection status, one of the values
          +     *      in Strophe.Status
          +     *    (String) condition - the error condition or null
          +     */
          +    _changeConnectStatus: function (status, condition)
          +    {
          +        // notify all plugins listening for status changes
          +        for (var k in Strophe._connectionPlugins) {
          +            if (Strophe._connectionPlugins.hasOwnProperty(k)) {
          +                var plugin = this[k];
          +                if (plugin.statusChanged) {
          +                    try {
          +                        plugin.statusChanged(status, condition);
          +                    } catch (err) {
          +                        Strophe.error("" + k + " plugin caused an exception " +
          +                                      "changing status: " + err);
          +                    }
          +                }
          +            }
          +        }
          +
          +        // notify the user's callback
          +        if (this.connect_callback) {
          +            try {
          +                this.connect_callback(status, condition);
          +            } catch (e) {
          +                Strophe.error("User connection callback caused an " +
          +                              "exception: " + e);
          +            }
          +        }
          +    },
          +
          +    /** PrivateFunction: _doDisconnect
          +     *  _Private_ function to disconnect.
          +     *
          +     *  This is the last piece of the disconnection logic.  This resets the
          +     *  connection and alerts the user's connection callback.
          +     */
          +    _doDisconnect: function ()
          +    {
          +        // Cancel Disconnect Timeout
          +        if (this._disconnectTimeout !== null) {
          +            this.deleteTimedHandler(this._disconnectTimeout);
          +            this._disconnectTimeout = null;
          +        }
          +
          +        Strophe.info("_doDisconnect was called");
          +        this._proto._doDisconnect();
          +
          +        this.authenticated = false;
          +        this.disconnecting = false;
          +
          +        // delete handlers
          +        this.handlers = [];
          +        this.timedHandlers = [];
          +        this.removeTimeds = [];
          +        this.removeHandlers = [];
          +        this.addTimeds = [];
          +        this.addHandlers = [];
          +
          +        // tell the parent we disconnected
          +        this._changeConnectStatus(Strophe.Status.DISCONNECTED, null);
          +        this.connected = false;
          +    },
          +
          +    /** PrivateFunction: _dataRecv
          +     *  _Private_ handler to processes incoming data from the the connection.
          +     *
          +     *  Except for _connect_cb handling the initial connection request,
          +     *  this function handles the incoming data for all requests.  This
          +     *  function also fires stanza handlers that match each incoming
          +     *  stanza.
          +     *
          +     *  Parameters:
          +     *    (Strophe.Request) req - The request that has data ready.
          +     *    (string) req - The stanza a raw string (optiona).
          +     */
          +    _dataRecv: function (req, raw)
          +    {
          +        Strophe.info("_dataRecv called");
          +        var elem = this._proto._reqToData(req);
          +        if (elem === null) { return; }
          +
          +        if (this.xmlInput !== Strophe.Connection.prototype.xmlInput) {
          +            if (elem.nodeName === this._proto.strip && elem.childNodes.length) {
          +                this.xmlInput(elem.childNodes[0]);
          +            } else {
          +                this.xmlInput(elem);
          +            }
          +        }
          +        if (this.rawInput !== Strophe.Connection.prototype.rawInput) {
          +            if (raw) {
          +                this.rawInput(raw);
          +            } else {
          +                this.rawInput(Strophe.serialize(elem));
          +            }
          +        }
          +
          +        // remove handlers scheduled for deletion
          +        var i, hand;
          +        while (this.removeHandlers.length > 0) {
          +            hand = this.removeHandlers.pop();
          +            i = this.handlers.indexOf(hand);
          +            if (i >= 0) {
          +                this.handlers.splice(i, 1);
          +            }
          +        }
          +
          +        // add handlers scheduled for addition
          +        while (this.addHandlers.length > 0) {
          +            this.handlers.push(this.addHandlers.pop());
          +        }
          +
          +        // handle graceful disconnect
          +        if (this.disconnecting && this._proto._emptyQueue()) {
          +            this._doDisconnect();
          +            return;
          +        }
          +
          +        var typ = elem.getAttribute("type");
          +        var cond, conflict;
          +        if (typ !== null && typ == "terminate") {
          +            // Don't process stanzas that come in after disconnect
          +            if (this.disconnecting) {
          +                return;
          +            }
          +
          +            // an error occurred
          +            cond = elem.getAttribute("condition");
          +            conflict = elem.getElementsByTagName("conflict");
          +            if (cond !== null) {
          +                if (cond == "remote-stream-error" && conflict.length > 0) {
          +                    cond = "conflict";
          +                }
          +                this._changeConnectStatus(Strophe.Status.CONNFAIL, cond);
          +            } else {
          +                this._changeConnectStatus(Strophe.Status.CONNFAIL, "unknown");
          +            }
          +            this.disconnect('unknown stream-error');
          +            return;
          +        }
          +
          +        // send each incoming stanza through the handler chain
          +        var that = this;
          +        Strophe.forEachChild(elem, null, function (child) {
          +            var i, newList;
          +            // process handlers
          +            newList = that.handlers;
          +            that.handlers = [];
          +            for (i = 0; i < newList.length; i++) {
          +                var hand = newList[i];
          +                // encapsulate 'handler.run' not to lose the whole handler list if
          +                // one of the handlers throws an exception
          +                try {
          +                    if (hand.isMatch(child) &&
          +                        (that.authenticated || !hand.user)) {
          +                        if (hand.run(child)) {
          +                            that.handlers.push(hand);
          +                        }
          +                    } else {
          +                        that.handlers.push(hand);
          +                    }
          +                } catch(e) {
          +                    // if the handler throws an exception, we consider it as false
          +                    Strophe.warn('Removing Strophe handlers due to uncaught exception: ' + e.message);
          +                }
          +            }
          +        });
          +    },
          +
          +
          +    /** Attribute: mechanisms
          +     *  SASL Mechanisms available for Conncection.
          +     */
          +    mechanisms: {},
          +
          +    /** PrivateFunction: _connect_cb
          +     *  _Private_ handler for initial connection request.
          +     *
          +     *  This handler is used to process the initial connection request
          +     *  response from the BOSH server. It is used to set up authentication
          +     *  handlers and start the authentication process.
          +     *
          +     *  SASL authentication will be attempted if available, otherwise
          +     *  the code will fall back to legacy authentication.
          +     *
          +     *  Parameters:
          +     *    (Strophe.Request) req - The current request.
          +     *    (Function) _callback - low level (xmpp) connect callback function.
          +     *      Useful for plugins with their own xmpp connect callback (when their)
          +     *      want to do something special).
          +     */
          +    _connect_cb: function (req, _callback, raw)
          +    {
          +        Strophe.info("_connect_cb was called");
          +
          +        this.connected = true;
          +
          +        var bodyWrap = this._proto._reqToData(req);
          +        if (!bodyWrap) { return; }
          +
          +        if (this.xmlInput !== Strophe.Connection.prototype.xmlInput) {
          +            if (bodyWrap.nodeName === this._proto.strip && bodyWrap.childNodes.length) {
          +                this.xmlInput(bodyWrap.childNodes[0]);
          +            } else {
          +                this.xmlInput(bodyWrap);
          +            }
          +        }
          +        if (this.rawInput !== Strophe.Connection.prototype.rawInput) {
          +            if (raw) {
          +                this.rawInput(raw);
          +            } else {
          +                this.rawInput(Strophe.serialize(bodyWrap));
          +            }
          +        }
          +
          +        var conncheck = this._proto._connect_cb(bodyWrap);
          +        if (conncheck === Strophe.Status.CONNFAIL) {
          +            return;
          +        }
          +
          +        this._authentication.sasl_scram_sha1 = false;
          +        this._authentication.sasl_plain = false;
          +        this._authentication.sasl_digest_md5 = false;
          +        this._authentication.sasl_anonymous = false;
          +
          +        this._authentication.legacy_auth = false;
          +
          +        // Check for the stream:features tag
          +        var hasFeatures = bodyWrap.getElementsByTagName("stream:features").length > 0;
          +        if (!hasFeatures) {
          +            hasFeatures = bodyWrap.getElementsByTagName("features").length > 0;
          +        }
          +        var mechanisms = bodyWrap.getElementsByTagName("mechanism");
          +        var matched = [];
          +        var i, mech, found_authentication = false;
          +        if (!hasFeatures) {
          +            this._proto._no_auth_received(_callback);
          +            return;
          +        }
          +        if (mechanisms.length > 0) {
          +            for (i = 0; i < mechanisms.length; i++) {
          +                mech = Strophe.getText(mechanisms[i]);
          +                if (this.mechanisms[mech]) matched.push(this.mechanisms[mech]);
          +            }
          +        }
          +        this._authentication.legacy_auth =
          +            bodyWrap.getElementsByTagName("auth").length > 0;
          +        found_authentication = this._authentication.legacy_auth ||
          +            matched.length > 0;
          +        if (!found_authentication) {
          +            this._proto._no_auth_received(_callback);
          +            return;
          +        }
          +        if (this.do_authentication !== false)
          +            this.authenticate(matched);
          +    },
          +
          +    /** Function: authenticate
          +     * Set up authentication
          +     *
          +     *  Contiunues the initial connection request by setting up authentication
          +     *  handlers and start the authentication process.
          +     *
          +     *  SASL authentication will be attempted if available, otherwise
          +     *  the code will fall back to legacy authentication.
          +     *
          +     */
          +    authenticate: function (matched)
          +    {
          +      var i;
          +      // Sorting matched mechanisms according to priority.
          +      for (i = 0; i < matched.length - 1; ++i) {
          +        var higher = i;
          +        for (var j = i + 1; j < matched.length; ++j) {
          +          if (matched[j].prototype.priority > matched[higher].prototype.priority) {
          +            higher = j;
          +          }
          +        }
          +        if (higher != i) {
          +          var swap = matched[i];
          +          matched[i] = matched[higher];
          +          matched[higher] = swap;
          +        }
          +      }
          +
          +      // run each mechanism
          +      var mechanism_found = false;
          +      for (i = 0; i < matched.length; ++i) {
          +        if (!matched[i].test(this)) continue;
          +
          +        this._sasl_success_handler = this._addSysHandler(
          +          this._sasl_success_cb.bind(this), null,
          +          "success", null, null);
          +        this._sasl_failure_handler = this._addSysHandler(
          +          this._sasl_failure_cb.bind(this), null,
          +          "failure", null, null);
          +        this._sasl_challenge_handler = this._addSysHandler(
          +          this._sasl_challenge_cb.bind(this), null,
          +          "challenge", null, null);
          +
          +        this._sasl_mechanism = new matched[i]();
          +        this._sasl_mechanism.onStart(this);
          +
          +        var request_auth_exchange = $build("auth", {
          +          xmlns: Strophe.NS.SASL,
          +          mechanism: this._sasl_mechanism.name
          +        });
          +
          +        if (this._sasl_mechanism.isClientFirst) {
          +          var response = this._sasl_mechanism.onChallenge(this, null);
          +          request_auth_exchange.t(Base64.encode(response));
          +        }
          +
          +        this.send(request_auth_exchange.tree());
          +
          +        mechanism_found = true;
          +        break;
          +      }
          +
          +      if (!mechanism_found) {
          +        // if none of the mechanism worked
          +        if (Strophe.getNodeFromJid(this.jid) === null) {
          +            // we don't have a node, which is required for non-anonymous
          +            // client connections
          +            this._changeConnectStatus(Strophe.Status.CONNFAIL,
          +                                      'x-strophe-bad-non-anon-jid');
          +            this.disconnect('x-strophe-bad-non-anon-jid');
          +        } else {
          +          // fall back to legacy authentication
          +          this._changeConnectStatus(Strophe.Status.AUTHENTICATING, null);
          +          this._addSysHandler(this._auth1_cb.bind(this), null, null,
          +                              null, "_auth_1");
          +
          +          this.send($iq({
          +            type: "get",
          +            to: this.domain,
          +            id: "_auth_1"
          +          }).c("query", {
          +            xmlns: Strophe.NS.AUTH
          +          }).c("username", {}).t(Strophe.getNodeFromJid(this.jid)).tree());
          +        }
          +      }
          +
          +    },
          +
          +    _sasl_challenge_cb: function(elem) {
          +      var challenge = Base64.decode(Strophe.getText(elem));
          +      var response = this._sasl_mechanism.onChallenge(this, challenge);
          +
          +      var stanza = $build('response', {
          +          xmlns: Strophe.NS.SASL
          +      });
          +      if (response !== "") {
          +        stanza.t(Base64.encode(response));
          +      }
          +      this.send(stanza.tree());
          +
          +      return true;
          +    },
          +
          +    /** PrivateFunction: _auth1_cb
          +     *  _Private_ handler for legacy authentication.
          +     *
          +     *  This handler is called in response to the initial <iq type='get'/>
          +     *  for legacy authentication.  It builds an authentication <iq/> and
          +     *  sends it, creating a handler (calling back to _auth2_cb()) to
          +     *  handle the result
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The stanza that triggered the callback.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    /* jshint unused:false */
          +    _auth1_cb: function (elem)
          +    {
          +        // build plaintext auth iq
          +        var iq = $iq({type: "set", id: "_auth_2"})
          +            .c('query', {xmlns: Strophe.NS.AUTH})
          +            .c('username', {}).t(Strophe.getNodeFromJid(this.jid))
          +            .up()
          +            .c('password').t(this.pass);
          +
          +        if (!Strophe.getResourceFromJid(this.jid)) {
          +            // since the user has not supplied a resource, we pick
          +            // a default one here.  unlike other auth methods, the server
          +            // cannot do this for us.
          +            this.jid = Strophe.getBareJidFromJid(this.jid) + '/strophe';
          +        }
          +        iq.up().c('resource', {}).t(Strophe.getResourceFromJid(this.jid));
          +
          +        this._addSysHandler(this._auth2_cb.bind(this), null,
          +                            null, null, "_auth_2");
          +
          +        this.send(iq.tree());
          +
          +        return false;
          +    },
          +    /* jshint unused:true */
          +
          +    /** PrivateFunction: _sasl_success_cb
          +     *  _Private_ handler for succesful SASL authentication.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The matching stanza.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _sasl_success_cb: function (elem)
          +    {
          +        if (this._sasl_data["server-signature"]) {
          +            var serverSignature;
          +            var success = Base64.decode(Strophe.getText(elem));
          +            var attribMatch = /([a-z]+)=([^,]+)(,|$)/;
          +            var matches = success.match(attribMatch);
          +            if (matches[1] == "v") {
          +                serverSignature = matches[2];
          +            }
          +
          +            if (serverSignature != this._sasl_data["server-signature"]) {
          +              // remove old handlers
          +              this.deleteHandler(this._sasl_failure_handler);
          +              this._sasl_failure_handler = null;
          +              if (this._sasl_challenge_handler) {
          +                this.deleteHandler(this._sasl_challenge_handler);
          +                this._sasl_challenge_handler = null;
          +              }
          +
          +              this._sasl_data = {};
          +              return this._sasl_failure_cb(null);
          +            }
          +        }
          +
          +        Strophe.info("SASL authentication succeeded.");
          +
          +        if(this._sasl_mechanism)
          +          this._sasl_mechanism.onSuccess();
          +
          +        // remove old handlers
          +        this.deleteHandler(this._sasl_failure_handler);
          +        this._sasl_failure_handler = null;
          +        if (this._sasl_challenge_handler) {
          +            this.deleteHandler(this._sasl_challenge_handler);
          +            this._sasl_challenge_handler = null;
          +        }
          +
          +        this._addSysHandler(this._sasl_auth1_cb.bind(this), null,
          +                            "stream:features", null, null);
          +
          +        // we must send an xmpp:restart now
          +        this._sendRestart();
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: _sasl_auth1_cb
          +     *  _Private_ handler to start stream binding.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The matching stanza.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _sasl_auth1_cb: function (elem)
          +    {
          +        // save stream:features for future usage
          +        this.features = elem;
          +
          +        var i, child;
          +
          +        for (i = 0; i < elem.childNodes.length; i++) {
          +            child = elem.childNodes[i];
          +            if (child.nodeName == 'bind') {
          +                this.do_bind = true;
          +            }
          +
          +            if (child.nodeName == 'session') {
          +                this.do_session = true;
          +            }
          +        }
          +
          +        if (!this.do_bind) {
          +            this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
          +            return false;
          +        } else {
          +            this._addSysHandler(this._sasl_bind_cb.bind(this), null, null,
          +                                null, "_bind_auth_2");
          +
          +            var resource = Strophe.getResourceFromJid(this.jid);
          +            if (resource) {
          +                this.send($iq({type: "set", id: "_bind_auth_2"})
          +                          .c('bind', {xmlns: Strophe.NS.BIND})
          +                          .c('resource', {}).t(resource).tree());
          +            } else {
          +                this.send($iq({type: "set", id: "_bind_auth_2"})
          +                          .c('bind', {xmlns: Strophe.NS.BIND})
          +                          .tree());
          +            }
          +        }
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: _sasl_bind_cb
          +     *  _Private_ handler for binding result and session start.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The matching stanza.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _sasl_bind_cb: function (elem)
          +    {
          +        if (elem.getAttribute("type") == "error") {
          +            Strophe.info("SASL binding failed.");
          +            var conflict = elem.getElementsByTagName("conflict"), condition;
          +            if (conflict.length > 0) {
          +                condition = 'conflict';
          +            }
          +            this._changeConnectStatus(Strophe.Status.AUTHFAIL, condition);
          +            return false;
          +        }
          +
          +        // TODO - need to grab errors
          +        var bind = elem.getElementsByTagName("bind");
          +        var jidNode;
          +        if (bind.length > 0) {
          +            // Grab jid
          +            jidNode = bind[0].getElementsByTagName("jid");
          +            if (jidNode.length > 0) {
          +                this.jid = Strophe.getText(jidNode[0]);
          +
          +                if (this.do_session) {
          +                    this._addSysHandler(this._sasl_session_cb.bind(this),
          +                                        null, null, null, "_session_auth_2");
          +
          +                    this.send($iq({type: "set", id: "_session_auth_2"})
          +                                  .c('session', {xmlns: Strophe.NS.SESSION})
          +                                  .tree());
          +                } else {
          +                    this.authenticated = true;
          +                    this._changeConnectStatus(Strophe.Status.CONNECTED, null);
          +                }
          +            }
          +        } else {
          +            Strophe.info("SASL binding failed.");
          +            this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
          +            return false;
          +        }
          +    },
          +
          +    /** PrivateFunction: _sasl_session_cb
          +     *  _Private_ handler to finish successful SASL connection.
          +     *
          +     *  This sets Connection.authenticated to true on success, which
          +     *  starts the processing of user handlers.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The matching stanza.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _sasl_session_cb: function (elem)
          +    {
          +        if (elem.getAttribute("type") == "result") {
          +            this.authenticated = true;
          +            this._changeConnectStatus(Strophe.Status.CONNECTED, null);
          +        } else if (elem.getAttribute("type") == "error") {
          +            Strophe.info("Session creation failed.");
          +            this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
          +            return false;
          +        }
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: _sasl_failure_cb
          +     *  _Private_ handler for SASL authentication failure.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The matching stanza.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    /* jshint unused:false */
          +    _sasl_failure_cb: function (elem)
          +    {
          +        // delete unneeded handlers
          +        if (this._sasl_success_handler) {
          +            this.deleteHandler(this._sasl_success_handler);
          +            this._sasl_success_handler = null;
          +        }
          +        if (this._sasl_challenge_handler) {
          +            this.deleteHandler(this._sasl_challenge_handler);
          +            this._sasl_challenge_handler = null;
          +        }
          +
          +        if(this._sasl_mechanism)
          +          this._sasl_mechanism.onFailure();
          +        this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
          +        return false;
          +    },
          +    /* jshint unused:true */
          +
          +    /** PrivateFunction: _auth2_cb
          +     *  _Private_ handler to finish legacy authentication.
          +     *
          +     *  This handler is called when the result from the jabber:iq:auth
          +     *  <iq/> stanza is returned.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The stanza that triggered the callback.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _auth2_cb: function (elem)
          +    {
          +        if (elem.getAttribute("type") == "result") {
          +            this.authenticated = true;
          +            this._changeConnectStatus(Strophe.Status.CONNECTED, null);
          +        } else if (elem.getAttribute("type") == "error") {
          +            this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
          +            this.disconnect('authentication failed');
          +        }
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: _addSysTimedHandler
          +     *  _Private_ function to add a system level timed handler.
          +     *
          +     *  This function is used to add a Strophe.TimedHandler for the
          +     *  library code.  System timed handlers are allowed to run before
          +     *  authentication is complete.
          +     *
          +     *  Parameters:
          +     *    (Integer) period - The period of the handler.
          +     *    (Function) handler - The callback function.
          +     */
          +    _addSysTimedHandler: function (period, handler)
          +    {
          +        var thand = new Strophe.TimedHandler(period, handler);
          +        thand.user = false;
          +        this.addTimeds.push(thand);
          +        return thand;
          +    },
          +
          +    /** PrivateFunction: _addSysHandler
          +     *  _Private_ function to add a system level stanza handler.
          +     *
          +     *  This function is used to add a Strophe.Handler for the
          +     *  library code.  System stanza handlers are allowed to run before
          +     *  authentication is complete.
          +     *
          +     *  Parameters:
          +     *    (Function) handler - The callback function.
          +     *    (String) ns - The namespace to match.
          +     *    (String) name - The stanza name to match.
          +     *    (String) type - The stanza type attribute to match.
          +     *    (String) id - The stanza id attribute to match.
          +     */
          +    _addSysHandler: function (handler, ns, name, type, id)
          +    {
          +        var hand = new Strophe.Handler(handler, ns, name, type, id);
          +        hand.user = false;
          +        this.addHandlers.push(hand);
          +        return hand;
          +    },
          +
          +    /** PrivateFunction: _onDisconnectTimeout
          +     *  _Private_ timeout handler for handling non-graceful disconnection.
          +     *
          +     *  If the graceful disconnect process does not complete within the
          +     *  time allotted, this handler finishes the disconnect anyway.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _onDisconnectTimeout: function ()
          +    {
          +        Strophe.info("_onDisconnectTimeout was called");
          +
          +        this._proto._onDisconnectTimeout();
          +
          +        // actually disconnect
          +        this._doDisconnect();
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: _onIdle
          +     *  _Private_ handler to process events during idle cycle.
          +     *
          +     *  This handler is called every 100ms to fire timed handlers that
          +     *  are ready and keep poll requests going.
          +     */
          +    _onIdle: function ()
          +    {
          +        var i, thand, since, newList;
          +
          +        // add timed handlers scheduled for addition
          +        // NOTE: we add before remove in the case a timed handler is
          +        // added and then deleted before the next _onIdle() call.
          +        while (this.addTimeds.length > 0) {
          +            this.timedHandlers.push(this.addTimeds.pop());
          +        }
          +
          +        // remove timed handlers that have been scheduled for deletion
          +        while (this.removeTimeds.length > 0) {
          +            thand = this.removeTimeds.pop();
          +            i = this.timedHandlers.indexOf(thand);
          +            if (i >= 0) {
          +                this.timedHandlers.splice(i, 1);
          +            }
          +        }
          +
          +        // call ready timed handlers
          +        var now = new Date().getTime();
          +        newList = [];
          +        for (i = 0; i < this.timedHandlers.length; i++) {
          +            thand = this.timedHandlers[i];
          +            if (this.authenticated || !thand.user) {
          +                since = thand.lastCalled + thand.period;
          +                if (since - now <= 0) {
          +                    if (thand.run()) {
          +                        newList.push(thand);
          +                    }
          +                } else {
          +                    newList.push(thand);
          +                }
          +            }
          +        }
          +        this.timedHandlers = newList;
          +
          +        clearTimeout(this._idleTimeout);
          +
          +        this._proto._onIdle();
          +
          +        // reactivate the timer only if connected
          +        if (this.connected) {
          +            this._idleTimeout = setTimeout(this._onIdle.bind(this), 100);
          +        }
          +    }
          +};
          +
          +if (callback) {
          +    callback(Strophe, $build, $msg, $iq, $pres);
          +}
          +
          +/** Class: Strophe.SASLMechanism
          + *
          + *  encapsulates SASL authentication mechanisms.
          + *
          + *  User code may override the priority for each mechanism or disable it completely.
          + *  See <priority> for information about changing priority and <test> for informatian on
          + *  how to disable a mechanism.
          + *
          + *  By default, all mechanisms are enabled and the priorities are
          + *
          + *  SCRAM-SHA1 - 40
          + *  DIGEST-MD5 - 30
          + *  Plain - 20
          + */
          +
          +/**
          + * PrivateConstructor: Strophe.SASLMechanism
          + * SASL auth mechanism abstraction.
          + *
          + *  Parameters:
          + *    (String) name - SASL Mechanism name.
          + *    (Boolean) isClientFirst - If client should send response first without challenge.
          + *    (Number) priority - Priority.
          + *
          + *  Returns:
          + *    A new Strophe.SASLMechanism object.
          + */
          +Strophe.SASLMechanism = function(name, isClientFirst, priority) {
          +  /** PrivateVariable: name
          +   *  Mechanism name.
          +   */
          +  this.name = name;
          +  /** PrivateVariable: isClientFirst
          +   *  If client sends response without initial server challenge.
          +   */
          +  this.isClientFirst = isClientFirst;
          +  /** Variable: priority
          +   *  Determines which <SASLMechanism> is chosen for authentication (Higher is better).
          +   *  Users may override this to prioritize mechanisms differently.
          +   *
          +   *  In the default configuration the priorities are
          +   *
          +   *  SCRAM-SHA1 - 40
          +   *  DIGEST-MD5 - 30
          +   *  Plain - 20
          +   *
          +   *  Example: (This will cause Strophe to choose the mechanism that the server sent first)
          +   *
          +   *  > Strophe.SASLMD5.priority = Strophe.SASLSHA1.priority;
          +   *
          +   *  See <SASL mechanisms> for a list of available mechanisms.
          +   *
          +   */
          +  this.priority = priority;
          +};
          +
          +Strophe.SASLMechanism.prototype = {
          +  /**
          +   *  Function: test
          +   *  Checks if mechanism able to run.
          +   *  To disable a mechanism, make this return false;
          +   *
          +   *  To disable plain authentication run
          +   *  > Strophe.SASLPlain.test = function() {
          +   *  >   return false;
          +   *  > }
          +   *
          +   *  See <SASL mechanisms> for a list of available mechanisms.
          +   *
          +   *  Parameters:
          +   *    (Strophe.Connection) connection - Target Connection.
          +   *
          +   *  Returns:
          +   *    (Boolean) If mechanism was able to run.
          +   */
          +  /* jshint unused:false */
          +  test: function(connection) {
          +    return true;
          +  },
          +  /* jshint unused:true */
          +
          +  /** PrivateFunction: onStart
          +   *  Called before starting mechanism on some connection.
          +   *
          +   *  Parameters:
          +   *    (Strophe.Connection) connection - Target Connection.
          +   */
          +  onStart: function(connection)
          +  {
          +    this._connection = connection;
          +  },
          +
          +  /** PrivateFunction: onChallenge
          +   *  Called by protocol implementation on incoming challenge. If client is
          +   *  first (isClientFirst == true) challenge will be null on the first call.
          +   *
          +   *  Parameters:
          +   *    (Strophe.Connection) connection - Target Connection.
          +   *    (String) challenge - current challenge to handle.
          +   *
          +   *  Returns:
          +   *    (String) Mechanism response.
          +   */
          +  /* jshint unused:false */
          +  onChallenge: function(connection, challenge) {
          +    throw new Error("You should implement challenge handling!");
          +  },
          +  /* jshint unused:true */
          +
          +  /** PrivateFunction: onFailure
          +   *  Protocol informs mechanism implementation about SASL failure.
          +   */
          +  onFailure: function() {
          +    this._connection = null;
          +  },
          +
          +  /** PrivateFunction: onSuccess
          +   *  Protocol informs mechanism implementation about SASL success.
          +   */
          +  onSuccess: function() {
          +    this._connection = null;
          +  }
          +};
          +
          +  /** Constants: SASL mechanisms
          +   *  Available authentication mechanisms
          +   *
          +   *  Strophe.SASLAnonymous - SASL Anonymous authentication.
          +   *  Strophe.SASLPlain - SASL Plain authentication.
          +   *  Strophe.SASLMD5 - SASL Digest-MD5 authentication
          +   *  Strophe.SASLSHA1 - SASL SCRAM-SHA1 authentication
          +   */
          +
          +// Building SASL callbacks
          +
          +/** PrivateConstructor: SASLAnonymous
          + *  SASL Anonymous authentication.
          + */
          +Strophe.SASLAnonymous = function() {};
          +
          +Strophe.SASLAnonymous.prototype = new Strophe.SASLMechanism("ANONYMOUS", false, 10);
          +
          +Strophe.SASLAnonymous.test = function(connection) {
          +  return connection.authcid === null;
          +};
          +
          +Strophe.Connection.prototype.mechanisms[Strophe.SASLAnonymous.prototype.name] = Strophe.SASLAnonymous;
          +
          +/** PrivateConstructor: SASLPlain
          + *  SASL Plain authentication.
          + */
          +Strophe.SASLPlain = function() {};
          +
          +Strophe.SASLPlain.prototype = new Strophe.SASLMechanism("PLAIN", true, 20);
          +
          +Strophe.SASLPlain.test = function(connection) {
          +  return connection.authcid !== null;
          +};
          +
          +Strophe.SASLPlain.prototype.onChallenge = function(connection) {
          +  var auth_str = connection.authzid;
          +  auth_str = auth_str + "\u0000";
          +  auth_str = auth_str + connection.authcid;
          +  auth_str = auth_str + "\u0000";
          +  auth_str = auth_str + connection.pass;
          +  return auth_str;
          +};
          +
          +Strophe.Connection.prototype.mechanisms[Strophe.SASLPlain.prototype.name] = Strophe.SASLPlain;
          +
          +/** PrivateConstructor: SASLSHA1
          + *  SASL SCRAM SHA 1 authentication.
          + */
          +Strophe.SASLSHA1 = function() {};
          +
          +/* TEST:
          + * This is a simple example of a SCRAM-SHA-1 authentication exchange
          + * when the client doesn't support channel bindings (username 'user' and
          + * password 'pencil' are used):
          + *
          + * C: n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL
          + * S: r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,
          + * i=4096
          + * C: c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,
          + * p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=
          + * S: v=rmF9pqV8S7suAoZWja4dJRkFsKQ=
          + *
          + */
          +
          +Strophe.SASLSHA1.prototype = new Strophe.SASLMechanism("SCRAM-SHA-1", true, 40);
          +
          +Strophe.SASLSHA1.test = function(connection) {
          +  return connection.authcid !== null;
          +};
          +
          +Strophe.SASLSHA1.prototype.onChallenge = function(connection, challenge, test_cnonce) {
          +  var cnonce = test_cnonce || MD5.hexdigest(Math.random() * 1234567890);
          +
          +  var auth_str = "n=" + connection.authcid;
          +  auth_str += ",r=";
          +  auth_str += cnonce;
          +
          +  connection._sasl_data.cnonce = cnonce;
          +  connection._sasl_data["client-first-message-bare"] = auth_str;
          +
          +  auth_str = "n,," + auth_str;
          +
          +  this.onChallenge = function (connection, challenge)
          +  {
          +    var nonce, salt, iter, Hi, U, U_old, i, k;
          +    var clientKey, serverKey, clientSignature;
          +    var responseText = "c=biws,";
          +    var authMessage = connection._sasl_data["client-first-message-bare"] + "," +
          +      challenge + ",";
          +    var cnonce = connection._sasl_data.cnonce;
          +    var attribMatch = /([a-z]+)=([^,]+)(,|$)/;
          +
          +    while (challenge.match(attribMatch)) {
          +      var matches = challenge.match(attribMatch);
          +      challenge = challenge.replace(matches[0], "");
          +      switch (matches[1]) {
          +      case "r":
          +        nonce = matches[2];
          +        break;
          +      case "s":
          +        salt = matches[2];
          +        break;
          +      case "i":
          +        iter = matches[2];
          +        break;
          +      }
          +    }
          +
          +    if (nonce.substr(0, cnonce.length) !== cnonce) {
          +      connection._sasl_data = {};
          +      return connection._sasl_failure_cb();
          +    }
          +
          +    responseText += "r=" + nonce;
          +    authMessage += responseText;
          +
          +    salt = Base64.decode(salt);
          +    salt += "\x00\x00\x00\x01";
          +
          +    Hi = U_old = core_hmac_sha1(connection.pass, salt);
          +    for (i = 1; i < iter; i++) {
          +      U = core_hmac_sha1(connection.pass, binb2str(U_old));
          +      for (k = 0; k < 5; k++) {
          +        Hi[k] ^= U[k];
          +      }
          +      U_old = U;
          +    }
          +    Hi = binb2str(Hi);
          +
          +    clientKey = core_hmac_sha1(Hi, "Client Key");
          +    serverKey = str_hmac_sha1(Hi, "Server Key");
          +    clientSignature = core_hmac_sha1(str_sha1(binb2str(clientKey)), authMessage);
          +    connection._sasl_data["server-signature"] = b64_hmac_sha1(serverKey, authMessage);
          +
          +    for (k = 0; k < 5; k++) {
          +      clientKey[k] ^= clientSignature[k];
          +    }
          +
          +    responseText += ",p=" + Base64.encode(binb2str(clientKey));
          +
          +    return responseText;
          +  }.bind(this);
          +
          +  return auth_str;
          +};
          +
          +Strophe.Connection.prototype.mechanisms[Strophe.SASLSHA1.prototype.name] = Strophe.SASLSHA1;
          +
          +/** PrivateConstructor: SASLMD5
          + *  SASL DIGEST MD5 authentication.
          + */
          +Strophe.SASLMD5 = function() {};
          +
          +Strophe.SASLMD5.prototype = new Strophe.SASLMechanism("DIGEST-MD5", false, 30);
          +
          +Strophe.SASLMD5.test = function(connection) {
          +  return connection.authcid !== null;
          +};
          +
          +/** PrivateFunction: _quote
          + *  _Private_ utility function to backslash escape and quote strings.
          + *
          + *  Parameters:
          + *    (String) str - The string to be quoted.
          + *
          + *  Returns:
          + *    quoted string
          + */
          +Strophe.SASLMD5.prototype._quote = function (str)
          +  {
          +    return '"' + str.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '"';
          +    //" end string workaround for emacs
          +  };
          +
          +
          +Strophe.SASLMD5.prototype.onChallenge = function(connection, challenge, test_cnonce) {
          +  var attribMatch = /([a-z]+)=("[^"]+"|[^,"]+)(?:,|$)/;
          +  var cnonce = test_cnonce || MD5.hexdigest("" + (Math.random() * 1234567890));
          +  var realm = "";
          +  var host = null;
          +  var nonce = "";
          +  var qop = "";
          +  var matches;
          +
          +  while (challenge.match(attribMatch)) {
          +    matches = challenge.match(attribMatch);
          +    challenge = challenge.replace(matches[0], "");
          +    matches[2] = matches[2].replace(/^"(.+)"$/, "$1");
          +    switch (matches[1]) {
          +    case "realm":
          +      realm = matches[2];
          +      break;
          +    case "nonce":
          +      nonce = matches[2];
          +      break;
          +    case "qop":
          +      qop = matches[2];
          +      break;
          +    case "host":
          +      host = matches[2];
          +      break;
          +    }
          +  }
          +
          +  var digest_uri = connection.servtype + "/" + connection.domain;
          +  if (host !== null) {
          +    digest_uri = digest_uri + "/" + host;
          +  }
          +
          +  var A1 = MD5.hash(connection.authcid +
          +                    ":" + realm + ":" + this._connection.pass) +
          +    ":" + nonce + ":" + cnonce;
          +  var A2 = 'AUTHENTICATE:' + digest_uri;
          +
          +  var responseText = "";
          +  responseText += 'charset=utf-8,';
          +  responseText += 'username=' +
          +    this._quote(connection.authcid) + ',';
          +  responseText += 'realm=' + this._quote(realm) + ',';
          +  responseText += 'nonce=' + this._quote(nonce) + ',';
          +  responseText += 'nc=00000001,';
          +  responseText += 'cnonce=' + this._quote(cnonce) + ',';
          +  responseText += 'digest-uri=' + this._quote(digest_uri) + ',';
          +  responseText += 'response=' + MD5.hexdigest(MD5.hexdigest(A1) + ":" +
          +                                              nonce + ":00000001:" +
          +                                              cnonce + ":auth:" +
          +                                              MD5.hexdigest(A2)) + ",";
          +  responseText += 'qop=auth';
          +
          +  this.onChallenge = function ()
          +  {
          +    return "";
          +  }.bind(this);
          +
          +  return responseText;
          +};
          +
          +Strophe.Connection.prototype.mechanisms[Strophe.SASLMD5.prototype.name] = Strophe.SASLMD5;
          +
          +})(function () {
          +    window.Strophe = arguments[0];
          +    window.$build = arguments[1];
          +    window.$msg = arguments[2];
          +    window.$iq = arguments[3];
          +    window.$pres = arguments[4];
          +});
          +
          +/*
          +    This program is distributed under the terms of the MIT license.
          +    Please see the LICENSE file for details.
          +
          +    Copyright 2006-2008, OGG, LLC
          +*/
          +
          +/* jshint undef: true, unused: true:, noarg: true, latedef: true */
          +/*global window, setTimeout, clearTimeout,
          +    XMLHttpRequest, ActiveXObject,
          +    Strophe, $build */
          +
          +
          +/** PrivateClass: Strophe.Request
          + *  _Private_ helper class that provides a cross implementation abstraction
          + *  for a BOSH related XMLHttpRequest.
          + *
          + *  The Strophe.Request class is used internally to encapsulate BOSH request
          + *  information.  It is not meant to be used from user's code.
          + */
          +
          +/** PrivateConstructor: Strophe.Request
          + *  Create and initialize a new Strophe.Request object.
          + *
          + *  Parameters:
          + *    (XMLElement) elem - The XML data to be sent in the request.
          + *    (Function) func - The function that will be called when the
          + *      XMLHttpRequest readyState changes.
          + *    (Integer) rid - The BOSH rid attribute associated with this request.
          + *    (Integer) sends - The number of times this same request has been
          + *      sent.
          + */
          +Strophe.Request = function (elem, func, rid, sends)
          +{
          +    this.id = ++Strophe._requestId;
          +    this.xmlData = elem;
          +    this.data = Strophe.serialize(elem);
          +    // save original function in case we need to make a new request
          +    // from this one.
          +    this.origFunc = func;
          +    this.func = func;
          +    this.rid = rid;
          +    this.date = NaN;
          +    this.sends = sends || 0;
          +    this.abort = false;
          +    this.dead = null;
          +
          +    this.age = function () {
          +        if (!this.date) { return 0; }
          +        var now = new Date();
          +        return (now - this.date) / 1000;
          +    };
          +    this.timeDead = function () {
          +        if (!this.dead) { return 0; }
          +        var now = new Date();
          +        return (now - this.dead) / 1000;
          +    };
          +    this.xhr = this._newXHR();
          +};
          +
          +Strophe.Request.prototype = {
          +    /** PrivateFunction: getResponse
          +     *  Get a response from the underlying XMLHttpRequest.
          +     *
          +     *  This function attempts to get a response from the request and checks
          +     *  for errors.
          +     *
          +     *  Throws:
          +     *    "parsererror" - A parser error occured.
          +     *
          +     *  Returns:
          +     *    The DOM element tree of the response.
          +     */
          +    getResponse: function ()
          +    {
          +        var node = null;
          +        if (this.xhr.responseXML && this.xhr.responseXML.documentElement) {
          +            node = this.xhr.responseXML.documentElement;
          +            if (node.tagName == "parsererror") {
          +                Strophe.error("invalid response received");
          +                Strophe.error("responseText: " + this.xhr.responseText);
          +                Strophe.error("responseXML: " +
          +                              Strophe.serialize(this.xhr.responseXML));
          +                throw "parsererror";
          +            }
          +        } else if (this.xhr.responseText) {
          +            Strophe.error("invalid response received");
          +            Strophe.error("responseText: " + this.xhr.responseText);
          +            Strophe.error("responseXML: " +
          +                          Strophe.serialize(this.xhr.responseXML));
          +        }
          +
          +        return node;
          +    },
          +
          +    /** PrivateFunction: _newXHR
          +     *  _Private_ helper function to create XMLHttpRequests.
          +     *
          +     *  This function creates XMLHttpRequests across all implementations.
          +     *
          +     *  Returns:
          +     *    A new XMLHttpRequest.
          +     */
          +    _newXHR: function ()
          +    {
          +        var xhr = null;
          +        if (window.XMLHttpRequest) {
          +            xhr = new XMLHttpRequest();
          +            if (xhr.overrideMimeType) {
          +                xhr.overrideMimeType("text/xml");
          +            }
          +        } else if (window.ActiveXObject) {
          +            xhr = new ActiveXObject("Microsoft.XMLHTTP");
          +        }
          +
          +        // use Function.bind() to prepend ourselves as an argument
          +        xhr.onreadystatechange = this.func.bind(null, this);
          +
          +        return xhr;
          +    }
          +};
          +
          +/** Class: Strophe.Bosh
          + *  _Private_ helper class that handles BOSH Connections
          + *
          + *  The Strophe.Bosh class is used internally by Strophe.Connection
          + *  to encapsulate BOSH sessions. It is not meant to be used from user's code.
          + */
          +
          +/** File: bosh.js
          + *  A JavaScript library to enable BOSH in Strophejs.
          + *
          + *  this library uses Bidirectional-streams Over Synchronous HTTP (BOSH)
          + *  to emulate a persistent, stateful, two-way connection to an XMPP server.
          + *  More information on BOSH can be found in XEP 124.
          + */
          +
          +/** PrivateConstructor: Strophe.Bosh
          + *  Create and initialize a Strophe.Bosh object.
          + *
          + *  Parameters:
          + *    (Strophe.Connection) connection - The Strophe.Connection that will use BOSH.
          + *
          + *  Returns:
          + *    A new Strophe.Bosh object.
          + */
          +Strophe.Bosh = function(connection) {
          +    this._conn = connection;
          +    /* request id for body tags */
          +    this.rid = Math.floor(Math.random() * 4294967295);
          +    /* The current session ID. */
          +    this.sid = null;
          +
          +    // default BOSH values
          +    this.hold = 1;
          +    this.wait = 60;
          +    this.window = 5;
          +
          +    this._requests = [];
          +};
          +
          +Strophe.Bosh.prototype = {
          +    /** Variable: strip
          +     *
          +     *  BOSH-Connections will have all stanzas wrapped in a <body> tag when
          +     *  passed to <Strophe.Connection.xmlInput> or <Strophe.Connection.xmlOutput>.
          +     *  To strip this tag, User code can set <Strophe.Bosh.strip> to "body":
          +     *
          +     *  > Strophe.Bosh.prototype.strip = "body";
          +     *
          +     *  This will enable stripping of the body tag in both
          +     *  <Strophe.Connection.xmlInput> and <Strophe.Connection.xmlOutput>.
          +     */
          +    strip: null,
          +
          +    /** PrivateFunction: _buildBody
          +     *  _Private_ helper function to generate the <body/> wrapper for BOSH.
          +     *
          +     *  Returns:
          +     *    A Strophe.Builder with a <body/> element.
          +     */
          +    _buildBody: function ()
          +    {
          +        var bodyWrap = $build('body', {
          +            rid: this.rid++,
          +            xmlns: Strophe.NS.HTTPBIND
          +        });
          +
          +        if (this.sid !== null) {
          +            bodyWrap.attrs({sid: this.sid});
          +        }
          +
          +        return bodyWrap;
          +    },
          +
          +    /** PrivateFunction: _reset
          +     *  Reset the connection.
          +     *
          +     *  This function is called by the reset function of the Strophe Connection
          +     */
          +    _reset: function ()
          +    {
          +        this.rid = Math.floor(Math.random() * 4294967295);
          +        this.sid = null;
          +    },
          +
          +    /** PrivateFunction: _connect
          +     *  _Private_ function that initializes the BOSH connection.
          +     *
          +     *  Creates and sends the Request that initializes the BOSH connection.
          +     */
          +    _connect: function (wait, hold, route)
          +    {
          +        this.wait = wait || this.wait;
          +        this.hold = hold || this.hold;
          +
          +        // build the body tag
          +        var body = this._buildBody().attrs({
          +            to: this._conn.domain,
          +            "xml:lang": "en",
          +            wait: this.wait,
          +            hold: this.hold,
          +            content: "text/xml; charset=utf-8",
          +            ver: "1.6",
          +            "xmpp:version": "1.0",
          +            "xmlns:xmpp": Strophe.NS.BOSH
          +        });
          +
          +        if(route){
          +            body.attrs({
          +                route: route
          +            });
          +        }
          +
          +        var _connect_cb = this._conn._connect_cb;
          +
          +        this._requests.push(
          +            new Strophe.Request(body.tree(),
          +                                this._onRequestStateChange.bind(
          +                                    this, _connect_cb.bind(this._conn)),
          +                                body.tree().getAttribute("rid")));
          +        this._throttledRequestHandler();
          +    },
          +
          +    /** PrivateFunction: _attach
          +     *  Attach to an already created and authenticated BOSH session.
          +     *
          +     *  This function is provided to allow Strophe to attach to BOSH
          +     *  sessions which have been created externally, perhaps by a Web
          +     *  application.  This is often used to support auto-login type features
          +     *  without putting user credentials into the page.
          +     *
          +     *  Parameters:
          +     *    (String) jid - The full JID that is bound by the session.
          +     *    (String) sid - The SID of the BOSH session.
          +     *    (String) rid - The current RID of the BOSH session.  This RID
          +     *      will be used by the next request.
          +     *    (Function) callback The connect callback function.
          +     *    (Integer) wait - The optional HTTPBIND wait value.  This is the
          +     *      time the server will wait before returning an empty result for
          +     *      a request.  The default setting of 60 seconds is recommended.
          +     *      Other settings will require tweaks to the Strophe.TIMEOUT value.
          +     *    (Integer) hold - The optional HTTPBIND hold value.  This is the
          +     *      number of connections the server will hold at one time.  This
          +     *      should almost always be set to 1 (the default).
          +     *    (Integer) wind - The optional HTTBIND window value.  This is the
          +     *      allowed range of request ids that are valid.  The default is 5.
          +     */
          +    _attach: function (jid, sid, rid, callback, wait, hold, wind)
          +    {
          +        this._conn.jid = jid;
          +        this.sid = sid;
          +        this.rid = rid;
          +
          +        this._conn.connect_callback = callback;
          +
          +        this._conn.domain = Strophe.getDomainFromJid(this._conn.jid);
          +
          +        this._conn.authenticated = true;
          +        this._conn.connected = true;
          +
          +        this.wait = wait || this.wait;
          +        this.hold = hold || this.hold;
          +        this.window = wind || this.window;
          +
          +        this._conn._changeConnectStatus(Strophe.Status.ATTACHED, null);
          +    },
          +
          +    /** PrivateFunction: _connect_cb
          +     *  _Private_ handler for initial connection request.
          +     *
          +     *  This handler is used to process the Bosh-part of the initial request.
          +     *  Parameters:
          +     *    (Strophe.Request) bodyWrap - The received stanza.
          +     */
          +    _connect_cb: function (bodyWrap)
          +    {
          +        var typ = bodyWrap.getAttribute("type");
          +        var cond, conflict;
          +        if (typ !== null && typ == "terminate") {
          +            // an error occurred
          +            Strophe.error("BOSH-Connection failed: " + cond);
          +            cond = bodyWrap.getAttribute("condition");
          +            conflict = bodyWrap.getElementsByTagName("conflict");
          +            if (cond !== null) {
          +                if (cond == "remote-stream-error" && conflict.length > 0) {
          +                    cond = "conflict";
          +                }
          +                this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, cond);
          +            } else {
          +                this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "unknown");
          +            }
          +            this._conn._doDisconnect();
          +            return Strophe.Status.CONNFAIL;
          +        }
          +
          +        // check to make sure we don't overwrite these if _connect_cb is
          +        // called multiple times in the case of missing stream:features
          +        if (!this.sid) {
          +            this.sid = bodyWrap.getAttribute("sid");
          +        }
          +        var wind = bodyWrap.getAttribute('requests');
          +        if (wind) { this.window = parseInt(wind, 10); }
          +        var hold = bodyWrap.getAttribute('hold');
          +        if (hold) { this.hold = parseInt(hold, 10); }
          +        var wait = bodyWrap.getAttribute('wait');
          +        if (wait) { this.wait = parseInt(wait, 10); }
          +    },
          +
          +    /** PrivateFunction: _disconnect
          +     *  _Private_ part of Connection.disconnect for Bosh
          +     *
          +     *  Parameters:
          +     *    (Request) pres - This stanza will be sent before disconnecting.
          +     */
          +    _disconnect: function (pres)
          +    {
          +        this._sendTerminate(pres);
          +    },
          +
          +    /** PrivateFunction: _doDisconnect
          +     *  _Private_ function to disconnect.
          +     *
          +     *  Resets the SID and RID.
          +     */
          +    _doDisconnect: function ()
          +    {
          +        this.sid = null;
          +        this.rid = Math.floor(Math.random() * 4294967295);
          +    },
          +
          +    /** PrivateFunction: _emptyQueue
          +     * _Private_ function to check if the Request queue is empty.
          +     *
          +     *  Returns:
          +     *    True, if there are no Requests queued, False otherwise.
          +     */
          +    _emptyQueue: function ()
          +    {
          +        return this._requests.length === 0;
          +    },
          +
          +    /** PrivateFunction: _hitError
          +     *  _Private_ function to handle the error count.
          +     *
          +     *  Requests are resent automatically until their error count reaches
          +     *  5.  Each time an error is encountered, this function is called to
          +     *  increment the count and disconnect if the count is too high.
          +     *
          +     *  Parameters:
          +     *    (Integer) reqStatus - The request status.
          +     */
          +    _hitError: function (reqStatus)
          +    {
          +        this.errors++;
          +        Strophe.warn("request errored, status: " + reqStatus +
          +                     ", number of errors: " + this.errors);
          +        if (this.errors > 4) {
          +            this._onDisconnectTimeout();
          +        }
          +    },
          +
          +    /** PrivateFunction: _no_auth_received
          +     *
          +     * Called on stream start/restart when no stream:features
          +     * has been received and sends a blank poll request.
          +     */
          +    _no_auth_received: function (_callback)
          +    {
          +        if (_callback) {
          +            _callback = _callback.bind(this._conn);
          +        } else {
          +            _callback = this._conn._connect_cb.bind(this._conn);
          +        }
          +        var body = this._buildBody();
          +        this._requests.push(
          +                new Strophe.Request(body.tree(),
          +                    this._onRequestStateChange.bind(
          +                        this, _callback.bind(this._conn)),
          +                    body.tree().getAttribute("rid")));
          +        this._throttledRequestHandler();
          +    },
          +
          +    /** PrivateFunction: _onDisconnectTimeout
          +     *  _Private_ timeout handler for handling non-graceful disconnection.
          +     *
          +     *  Cancels all remaining Requests and clears the queue.
          +     */
          +    _onDisconnectTimeout: function ()
          +    {
          +        var req;
          +        while (this._requests.length > 0) {
          +            req = this._requests.pop();
          +            req.abort = true;
          +            req.xhr.abort();
          +            // jslint complains, but this is fine. setting to empty func
          +            // is necessary for IE6
          +            req.xhr.onreadystatechange = function () {}; // jshint ignore:line
          +        }
          +    },
          +
          +    /** PrivateFunction: _onIdle
          +     *  _Private_ handler called by Strophe.Connection._onIdle
          +     *
          +     *  Sends all queued Requests or polls with empty Request if there are none.
          +     */
          +    _onIdle: function () {
          +        var data = this._conn._data;
          +
          +        // if no requests are in progress, poll
          +        if (this._conn.authenticated && this._requests.length === 0 &&
          +            data.length === 0 && !this._conn.disconnecting) {
          +            Strophe.info("no requests during idle cycle, sending " +
          +                         "blank request");
          +            data.push(null);
          +        }
          +
          +        if (this._requests.length < 2 && data.length > 0 &&
          +            !this._conn.paused) {
          +            var body = this._buildBody();
          +            for (var i = 0; i < data.length; i++) {
          +                if (data[i] !== null) {
          +                    if (data[i] === "restart") {
          +                        body.attrs({
          +                            to: this._conn.domain,
          +                            "xml:lang": "en",
          +                            "xmpp:restart": "true",
          +                            "xmlns:xmpp": Strophe.NS.BOSH
          +                        });
          +                    } else {
          +                        body.cnode(data[i]).up();
          +                    }
          +                }
          +            }
          +            delete this._conn._data;
          +            this._conn._data = [];
          +            this._requests.push(
          +                new Strophe.Request(body.tree(),
          +                                    this._onRequestStateChange.bind(
          +                                        this, this._conn._dataRecv.bind(this._conn)),
          +                                    body.tree().getAttribute("rid")));
          +            this._processRequest(this._requests.length - 1);
          +        }
          +
          +        if (this._requests.length > 0) {
          +            var time_elapsed = this._requests[0].age();
          +            if (this._requests[0].dead !== null) {
          +                if (this._requests[0].timeDead() >
          +                    Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait)) {
          +                    this._throttledRequestHandler();
          +                }
          +            }
          +
          +            if (time_elapsed > Math.floor(Strophe.TIMEOUT * this.wait)) {
          +                Strophe.warn("Request " +
          +                             this._requests[0].id +
          +                             " timed out, over " + Math.floor(Strophe.TIMEOUT * this.wait) +
          +                             " seconds since last activity");
          +                this._throttledRequestHandler();
          +            }
          +        }
          +    },
          +
          +    /** PrivateFunction: _onRequestStateChange
          +     *  _Private_ handler for Strophe.Request state changes.
          +     *
          +     *  This function is called when the XMLHttpRequest readyState changes.
          +     *  It contains a lot of error handling logic for the many ways that
          +     *  requests can fail, and calls the request callback when requests
          +     *  succeed.
          +     *
          +     *  Parameters:
          +     *    (Function) func - The handler for the request.
          +     *    (Strophe.Request) req - The request that is changing readyState.
          +     */
          +    _onRequestStateChange: function (func, req)
          +    {
          +        Strophe.debug("request id " + req.id +
          +                      "." + req.sends + " state changed to " +
          +                      req.xhr.readyState);
          +
          +        if (req.abort) {
          +            req.abort = false;
          +            return;
          +        }
          +
          +        // request complete
          +        var reqStatus;
          +        if (req.xhr.readyState == 4) {
          +            reqStatus = 0;
          +            try {
          +                reqStatus = req.xhr.status;
          +            } catch (e) {
          +                // ignore errors from undefined status attribute.  works
          +                // around a browser bug
          +            }
          +
          +            if (typeof(reqStatus) == "undefined") {
          +                reqStatus = 0;
          +            }
          +
          +            if (this.disconnecting) {
          +                if (reqStatus >= 400) {
          +                    this._hitError(reqStatus);
          +                    return;
          +                }
          +            }
          +
          +            var reqIs0 = (this._requests[0] == req);
          +            var reqIs1 = (this._requests[1] == req);
          +
          +            if ((reqStatus > 0 && reqStatus < 500) || req.sends > 5) {
          +                // remove from internal queue
          +                this._removeRequest(req);
          +                Strophe.debug("request id " +
          +                              req.id +
          +                              " should now be removed");
          +            }
          +
          +            // request succeeded
          +            if (reqStatus == 200) {
          +                // if request 1 finished, or request 0 finished and request
          +                // 1 is over Strophe.SECONDARY_TIMEOUT seconds old, we need to
          +                // restart the other - both will be in the first spot, as the
          +                // completed request has been removed from the queue already
          +                if (reqIs1 ||
          +                    (reqIs0 && this._requests.length > 0 &&
          +                     this._requests[0].age() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait))) {
          +                    this._restartRequest(0);
          +                }
          +                // call handler
          +                Strophe.debug("request id " +
          +                              req.id + "." +
          +                              req.sends + " got 200");
          +                func(req);
          +                this.errors = 0;
          +            } else {
          +                Strophe.error("request id " +
          +                              req.id + "." +
          +                              req.sends + " error " + reqStatus +
          +                              " happened");
          +                if (reqStatus === 0 ||
          +                    (reqStatus >= 400 && reqStatus < 600) ||
          +                    reqStatus >= 12000) {
          +                    this._hitError(reqStatus);
          +                    if (reqStatus >= 400 && reqStatus < 500) {
          +                        this._conn._changeConnectStatus(Strophe.Status.DISCONNECTING,
          +                                                  null);
          +                        this._conn._doDisconnect();
          +                    }
          +                }
          +            }
          +
          +            if (!((reqStatus > 0 && reqStatus < 500) ||
          +                  req.sends > 5)) {
          +                this._throttledRequestHandler();
          +            }
          +        }
          +    },
          +
          +    /** PrivateFunction: _processRequest
          +     *  _Private_ function to process a request in the queue.
          +     *
          +     *  This function takes requests off the queue and sends them and
          +     *  restarts dead requests.
          +     *
          +     *  Parameters:
          +     *    (Integer) i - The index of the request in the queue.
          +     */
          +    _processRequest: function (i)
          +    {
          +        var self = this;
          +        var req = this._requests[i];
          +        var reqStatus = -1;
          +
          +        try {
          +            if (req.xhr.readyState == 4) {
          +                reqStatus = req.xhr.status;
          +            }
          +        } catch (e) {
          +            Strophe.error("caught an error in _requests[" + i +
          +                          "], reqStatus: " + reqStatus);
          +        }
          +
          +        if (typeof(reqStatus) == "undefined") {
          +            reqStatus = -1;
          +        }
          +
          +        // make sure we limit the number of retries
          +        if (req.sends > this.maxRetries) {
          +            this._onDisconnectTimeout();
          +            return;
          +        }
          +
          +        var time_elapsed = req.age();
          +        var primaryTimeout = (!isNaN(time_elapsed) &&
          +                              time_elapsed > Math.floor(Strophe.TIMEOUT * this.wait));
          +        var secondaryTimeout = (req.dead !== null &&
          +                                req.timeDead() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait));
          +        var requestCompletedWithServerError = (req.xhr.readyState == 4 &&
          +                                               (reqStatus < 1 ||
          +                                                reqStatus >= 500));
          +        if (primaryTimeout || secondaryTimeout ||
          +            requestCompletedWithServerError) {
          +            if (secondaryTimeout) {
          +                Strophe.error("Request " +
          +                              this._requests[i].id +
          +                              " timed out (secondary), restarting");
          +            }
          +            req.abort = true;
          +            req.xhr.abort();
          +            // setting to null fails on IE6, so set to empty function
          +            req.xhr.onreadystatechange = function () {};
          +            this._requests[i] = new Strophe.Request(req.xmlData,
          +                                                    req.origFunc,
          +                                                    req.rid,
          +                                                    req.sends);
          +            req = this._requests[i];
          +        }
          +
          +        if (req.xhr.readyState === 0) {
          +            Strophe.debug("request id " + req.id +
          +                          "." + req.sends + " posting");
          +
          +            try {
          +                req.xhr.open("POST", this._conn.service, this._conn.options.sync ? false : true);
          +            } catch (e2) {
          +                Strophe.error("XHR open failed.");
          +                if (!this._conn.connected) {
          +                    this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,
          +                                              "bad-service");
          +                }
          +                this._conn.disconnect();
          +                return;
          +            }
          +
          +            // Fires the XHR request -- may be invoked immediately
          +            // or on a gradually expanding retry window for reconnects
          +            var sendFunc = function () {
          +                req.date = new Date();
          +                if (self._conn.options.customHeaders){
          +                    var headers = self._conn.options.customHeaders;
          +                    for (var header in headers) {
          +                        if (headers.hasOwnProperty(header)) {
          +                            req.xhr.setRequestHeader(header, headers[header]);
          +                        }
          +                    }
          +                }
          +                req.xhr.send(req.data);
          +            };
          +
          +            // Implement progressive backoff for reconnects --
          +            // First retry (send == 1) should also be instantaneous
          +            if (req.sends > 1) {
          +                // Using a cube of the retry number creates a nicely
          +                // expanding retry window
          +                var backoff = Math.min(Math.floor(Strophe.TIMEOUT * this.wait),
          +                                       Math.pow(req.sends, 3)) * 1000;
          +                setTimeout(sendFunc, backoff);
          +            } else {
          +                sendFunc();
          +            }
          +
          +            req.sends++;
          +
          +            if (this._conn.xmlOutput !== Strophe.Connection.prototype.xmlOutput) {
          +                if (req.xmlData.nodeName === this.strip && req.xmlData.childNodes.length) {
          +                    this._conn.xmlOutput(req.xmlData.childNodes[0]);
          +                } else {
          +                    this._conn.xmlOutput(req.xmlData);
          +                }
          +            }
          +            if (this._conn.rawOutput !== Strophe.Connection.prototype.rawOutput) {
          +                this._conn.rawOutput(req.data);
          +            }
          +        } else {
          +            Strophe.debug("_processRequest: " +
          +                          (i === 0 ? "first" : "second") +
          +                          " request has readyState of " +
          +                          req.xhr.readyState);
          +        }
          +    },
          +
          +    /** PrivateFunction: _removeRequest
          +     *  _Private_ function to remove a request from the queue.
          +     *
          +     *  Parameters:
          +     *    (Strophe.Request) req - The request to remove.
          +     */
          +    _removeRequest: function (req)
          +    {
          +        Strophe.debug("removing request");
          +
          +        var i;
          +        for (i = this._requests.length - 1; i >= 0; i--) {
          +            if (req == this._requests[i]) {
          +                this._requests.splice(i, 1);
          +            }
          +        }
          +
          +        // IE6 fails on setting to null, so set to empty function
          +        req.xhr.onreadystatechange = function () {};
          +
          +        this._throttledRequestHandler();
          +    },
          +
          +    /** PrivateFunction: _restartRequest
          +     *  _Private_ function to restart a request that is presumed dead.
          +     *
          +     *  Parameters:
          +     *    (Integer) i - The index of the request in the queue.
          +     */
          +    _restartRequest: function (i)
          +    {
          +        var req = this._requests[i];
          +        if (req.dead === null) {
          +            req.dead = new Date();
          +        }
          +
          +        this._processRequest(i);
          +    },
          +
          +    /** PrivateFunction: _reqToData
          +     * _Private_ function to get a stanza out of a request.
          +     *
          +     * Tries to extract a stanza out of a Request Object.
          +     * When this fails the current connection will be disconnected.
          +     *
          +     *  Parameters:
          +     *    (Object) req - The Request.
          +     *
          +     *  Returns:
          +     *    The stanza that was passed.
          +     */
          +    _reqToData: function (req)
          +    {
          +        try {
          +            return req.getResponse();
          +        } catch (e) {
          +            if (e != "parsererror") { throw e; }
          +            this._conn.disconnect("strophe-parsererror");
          +        }
          +    },
          +
          +    /** PrivateFunction: _sendTerminate
          +     *  _Private_ function to send initial disconnect sequence.
          +     *
          +     *  This is the first step in a graceful disconnect.  It sends
          +     *  the BOSH server a terminate body and includes an unavailable
          +     *  presence if authentication has completed.
          +     */
          +    _sendTerminate: function (pres)
          +    {
          +        Strophe.info("_sendTerminate was called");
          +        var body = this._buildBody().attrs({type: "terminate"});
          +
          +        if (pres) {
          +            body.cnode(pres.tree());
          +        }
          +
          +        var req = new Strophe.Request(body.tree(),
          +                                      this._onRequestStateChange.bind(
          +                                          this, this._conn._dataRecv.bind(this._conn)),
          +                                      body.tree().getAttribute("rid"));
          +
          +        this._requests.push(req);
          +        this._throttledRequestHandler();
          +    },
          +
          +    /** PrivateFunction: _send
          +     *  _Private_ part of the Connection.send function for BOSH
          +     *
          +     * Just triggers the RequestHandler to send the messages that are in the queue
          +     */
          +    _send: function () {
          +        clearTimeout(this._conn._idleTimeout);
          +        this._throttledRequestHandler();
          +        this._conn._idleTimeout = setTimeout(this._conn._onIdle.bind(this._conn), 100);
          +    },
          +
          +    /** PrivateFunction: _sendRestart
          +     *
          +     *  Send an xmpp:restart stanza.
          +     */
          +    _sendRestart: function ()
          +    {
          +        this._throttledRequestHandler();
          +        clearTimeout(this._conn._idleTimeout);
          +    },
          +
          +    /** PrivateFunction: _throttledRequestHandler
          +     *  _Private_ function to throttle requests to the connection window.
          +     *
          +     *  This function makes sure we don't send requests so fast that the
          +     *  request ids overflow the connection window in the case that one
          +     *  request died.
          +     */
          +    _throttledRequestHandler: function ()
          +    {
          +        if (!this._requests) {
          +            Strophe.debug("_throttledRequestHandler called with " +
          +                          "undefined requests");
          +        } else {
          +            Strophe.debug("_throttledRequestHandler called with " +
          +                          this._requests.length + " requests");
          +        }
          +
          +        if (!this._requests || this._requests.length === 0) {
          +            return;
          +        }
          +
          +        if (this._requests.length > 0) {
          +            this._processRequest(0);
          +        }
          +
          +        if (this._requests.length > 1 &&
          +            Math.abs(this._requests[0].rid -
          +                     this._requests[1].rid) < this.window) {
          +            this._processRequest(1);
          +        }
          +    }
          +};
          +
          +/*
          +    This program is distributed under the terms of the MIT license.
          +    Please see the LICENSE file for details.
          +
          +    Copyright 2006-2008, OGG, LLC
          +*/
          +
          +/* jshint undef: true, unused: true:, noarg: true, latedef: true */
          +/*global document, window, clearTimeout, WebSocket,
          +    DOMParser, Strophe, $build */
          +
          +/** Class: Strophe.WebSocket
          + *  _Private_ helper class that handles WebSocket Connections
          + *
          + *  The Strophe.WebSocket class is used internally by Strophe.Connection
          + *  to encapsulate WebSocket sessions. It is not meant to be used from user's code.
          + */
          +
          +/** File: websocket.js
          + *  A JavaScript library to enable XMPP over Websocket in Strophejs.
          + *
          + *  This file implements XMPP over WebSockets for Strophejs.
          + *  If a Connection is established with a Websocket url (ws://...)
          + *  Strophe will use WebSockets.
          + *  For more information on XMPP-over WebSocket see this RFC draft:
          + *  http://tools.ietf.org/html/draft-ietf-xmpp-websocket-00
          + *
          + *  WebSocket support implemented by Andreas Guth (andreas.guth@rwth-aachen.de)
          + */
          +
          +/** PrivateConstructor: Strophe.Websocket
          + *  Create and initialize a Strophe.WebSocket object.
          + *  Currently only sets the connection Object.
          + *
          + *  Parameters:
          + *    (Strophe.Connection) connection - The Strophe.Connection that will use WebSockets.
          + *
          + *  Returns:
          + *    A new Strophe.WebSocket object.
          + */
          +Strophe.Websocket = function(connection) {
          +    this._conn = connection;
          +    this.strip = "stream:stream";
          +
          +    var service = connection.service;
          +    if (service.indexOf("ws:") !== 0 && service.indexOf("wss:") !== 0) {
          +        // If the service is not an absolute URL, assume it is a path and put the absolute
          +        // URL together from options, current URL and the path.
          +        var new_service = "";
          +
          +        if (connection.options.protocol === "ws" && window.location.protocol !== "https:") {
          +            new_service += "ws";
          +        } else {
          +            new_service += "wss";
          +        }
          +
          +        new_service += "://" + window.location.host;
          +
          +        if (service.indexOf("/") !== 0) {
          +            new_service += window.location.pathname + service;
          +        } else {
          +            new_service += service;
          +        }
          +
          +        connection.service = new_service;
          +    }
          +};
          +
          +Strophe.Websocket.prototype = {
          +    /** PrivateFunction: _buildStream
          +     *  _Private_ helper function to generate the <stream> start tag for WebSockets
          +     *
          +     *  Returns:
          +     *    A Strophe.Builder with a <stream> element.
          +     */
          +    _buildStream: function ()
          +    {
          +        return $build("stream:stream", {
          +            "to": this._conn.domain,
          +            "xmlns": Strophe.NS.CLIENT,
          +            "xmlns:stream": Strophe.NS.STREAM,
          +            "version": '1.0'
          +        });
          +    },
          +
          +    /** PrivateFunction: _check_streamerror
          +     * _Private_ checks a message for stream:error
          +     *
          +     *  Parameters:
          +     *    (Strophe.Request) bodyWrap - The received stanza.
          +     *    connectstatus - The ConnectStatus that will be set on error.
          +     *  Returns:
          +     *     true if there was a streamerror, false otherwise.
          +     */
          +    _check_streamerror: function (bodyWrap, connectstatus) {
          +        var errors = bodyWrap.getElementsByTagName("stream:error");
          +        if (errors.length === 0) {
          +            return false;
          +        }
          +        var error = errors[0];
          +
          +        var condition = "";
          +        var text = "";
          +
          +        var ns = "urn:ietf:params:xml:ns:xmpp-streams";
          +        for (var i = 0; i < error.childNodes.length; i++) {
          +            var e = error.childNodes[i];
          +            if (e.getAttribute("xmlns") !== ns) {
          +                break;
          +            } if (e.nodeName === "text") {
          +                text = e.textContent;
          +            } else {
          +                condition = e.nodeName;
          +            }
          +        }
          +
          +        var errorString = "WebSocket stream error: ";
          +
          +        if (condition) {
          +            errorString += condition;
          +        } else {
          +            errorString += "unknown";
          +        }
          +
          +        if (text) {
          +            errorString += " - " + condition;
          +        }
          +
          +        Strophe.error(errorString);
          +
          +        // close the connection on stream_error
          +        this._conn._changeConnectStatus(connectstatus, condition);
          +        this._conn._doDisconnect();
          +        return true;
          +    },
          +
          +    /** PrivateFunction: _reset
          +     *  Reset the connection.
          +     *
          +     *  This function is called by the reset function of the Strophe Connection.
          +     *  Is not needed by WebSockets.
          +     */
          +    _reset: function ()
          +    {
          +        return;
          +    },
          +
          +    /** PrivateFunction: _connect
          +     *  _Private_ function called by Strophe.Connection.connect
          +     *
          +     *  Creates a WebSocket for a connection and assigns Callbacks to it.
          +     *  Does nothing if there already is a WebSocket.
          +     */
          +    _connect: function () {
          +        // Ensure that there is no open WebSocket from a previous Connection.
          +        this._closeSocket();
          +
          +        // Create the new WobSocket
          +        this.socket = new WebSocket(this._conn.service, "xmpp");
          +        this.socket.onopen = this._onOpen.bind(this);
          +        this.socket.onerror = this._onError.bind(this);
          +        this.socket.onclose = this._onClose.bind(this);
          +        this.socket.onmessage = this._connect_cb_wrapper.bind(this);
          +    },
          +
          +    /** PrivateFunction: _connect_cb
          +     *  _Private_ function called by Strophe.Connection._connect_cb
          +     *
          +     * checks for stream:error
          +     *
          +     *  Parameters:
          +     *    (Strophe.Request) bodyWrap - The received stanza.
          +     */
          +    _connect_cb: function(bodyWrap) {
          +        var error = this._check_streamerror(bodyWrap, Strophe.Status.CONNFAIL);
          +        if (error) {
          +            return Strophe.Status.CONNFAIL;
          +        }
          +    },
          +
          +    /** PrivateFunction: _handleStreamStart
          +     * _Private_ function that checks the opening stream:stream tag for errors.
          +     *
          +     * Disconnects if there is an error and returns false, true otherwise.
          +     *
          +     *  Parameters:
          +     *    (Node) message - Stanza containing the stream:stream.
          +     */
          +    _handleStreamStart: function(message) {
          +        var error = false;
          +        // Check for errors in the stream:stream tag
          +        var ns = message.getAttribute("xmlns");
          +        if (typeof ns !== "string") {
          +            error = "Missing xmlns in stream:stream";
          +        } else if (ns !== Strophe.NS.CLIENT) {
          +            error = "Wrong xmlns in stream:stream: " + ns;
          +        }
          +
          +        var ns_stream = message.namespaceURI;
          +        if (typeof ns_stream !== "string") {
          +            error = "Missing xmlns:stream in stream:stream";
          +        } else if (ns_stream !== Strophe.NS.STREAM) {
          +            error = "Wrong xmlns:stream in stream:stream: " + ns_stream;
          +        }
          +
          +        var ver = message.getAttribute("version");
          +        if (typeof ver !== "string") {
          +            error = "Missing version in stream:stream";
          +        } else if (ver !== "1.0") {
          +            error = "Wrong version in stream:stream: " + ver;
          +        }
          +
          +        if (error) {
          +            this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, error);
          +            this._conn._doDisconnect();
          +            return false;
          +        }
          +
          +        return true;
          +    },
          +
          +    /** PrivateFunction: _connect_cb_wrapper
          +     * _Private_ function that handles the first connection messages.
          +     *
          +     * On receiving an opening stream tag this callback replaces itself with the real
          +     * message handler. On receiving a stream error the connection is terminated.
          +     */
          +    _connect_cb_wrapper: function(message) {
          +        if (message.data.indexOf("<stream:stream ") === 0 || message.data.indexOf("<?xml") === 0) {
          +            // Strip the XML Declaration, if there is one
          +            var data = message.data.replace(/^(<\?.*?\?>\s*)*/, "");
          +            if (data === '') return;
          +
          +            //Make the initial stream:stream selfclosing to parse it without a SAX parser.
          +            data = message.data.replace(/<stream:stream (.*[^\/])>/, "<stream:stream $1/>");
          +
          +            var streamStart = new DOMParser().parseFromString(data, "text/xml").documentElement;
          +            this._conn.xmlInput(streamStart);
          +            this._conn.rawInput(message.data);
          +
          +            //_handleStreamSteart will check for XML errors and disconnect on error
          +            if (this._handleStreamStart(streamStart)) {
          +
          +                //_connect_cb will check for stream:error and disconnect on error
          +                this._connect_cb(streamStart);
          +
          +                // ensure received stream:stream is NOT selfclosing and save it for following messages
          +                this.streamStart = message.data.replace(/^<stream:(.*)\/>$/, "<stream:$1>");
          +            }
          +        } else if (message.data === "</stream:stream>") {
          +            this._conn.rawInput(message.data);
          +            this._conn.xmlInput(document.createElement("stream:stream"));
          +            this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "Received closing stream");
          +            this._conn._doDisconnect();
          +            return;
          +        } else {
          +            var string = this._streamWrap(message.data);
          +            var elem = new DOMParser().parseFromString(string, "text/xml").documentElement;
          +            this.socket.onmessage = this._onMessage.bind(this);
          +            this._conn._connect_cb(elem, null, message.data);
          +        }
          +    },
          +
          +    /** PrivateFunction: _disconnect
          +     *  _Private_ function called by Strophe.Connection.disconnect
          +     *
          +     *  Disconnects and sends a last stanza if one is given
          +     *
          +     *  Parameters:
          +     *    (Request) pres - This stanza will be sent before disconnecting.
          +     */
          +    _disconnect: function (pres)
          +    {
          +        if (this.socket.readyState !== WebSocket.CLOSED) {
          +            if (pres) {
          +                this._conn.send(pres);
          +            }
          +            var close = '</stream:stream>';
          +            this._conn.xmlOutput(document.createElement("stream:stream"));
          +            this._conn.rawOutput(close);
          +            try {
          +                this.socket.send(close);
          +            } catch (e) {
          +                Strophe.info("Couldn't send closing stream tag.");
          +            }
          +        }
          +
          +        this._conn._doDisconnect();
          +    },
          +
          +    /** PrivateFunction: _doDisconnect
          +     *  _Private_ function to disconnect.
          +     *
          +     *  Just closes the Socket for WebSockets
          +     */
          +    _doDisconnect: function ()
          +    {
          +        Strophe.info("WebSockets _doDisconnect was called");
          +        this._closeSocket();
          +    },
          +
          +    /** PrivateFunction _streamWrap
          +     *  _Private_ helper function to wrap a stanza in a <stream> tag.
          +     *  This is used so Strophe can process stanzas from WebSockets like BOSH
          +     */
          +    _streamWrap: function (stanza)
          +    {
          +        return this.streamStart + stanza + '</stream:stream>';
          +    },
          +
          +
          +    /** PrivateFunction: _closeSocket
          +     *  _Private_ function to close the WebSocket.
          +     *
          +     *  Closes the socket if it is still open and deletes it
          +     */
          +    _closeSocket: function ()
          +    {
          +        if (this.socket) { try {
          +            this.socket.close();
          +        } catch (e) {} }
          +        this.socket = null;
          +    },
          +
          +    /** PrivateFunction: _emptyQueue
          +     * _Private_ function to check if the message queue is empty.
          +     *
          +     *  Returns:
          +     *    True, because WebSocket messages are send immediately after queueing.
          +     */
          +    _emptyQueue: function ()
          +    {
          +        return true;
          +    },
          +
          +    /** PrivateFunction: _onClose
          +     * _Private_ function to handle websockets closing.
          +     *
          +     * Nothing to do here for WebSockets
          +     */
          +    _onClose: function() {
          +        if(this._conn.connected && !this._conn.disconnecting) {
          +            Strophe.error("Websocket closed unexcectedly");
          +            this._conn._doDisconnect();
          +        } else {
          +            Strophe.info("Websocket closed");
          +        }
          +    },
          +
          +    /** PrivateFunction: _no_auth_received
          +     *
          +     * Called on stream start/restart when no stream:features
          +     * has been received.
          +     */
          +    _no_auth_received: function (_callback)
          +    {
          +        Strophe.error("Server did not send any auth methods");
          +        this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "Server did not send any auth methods");
          +        if (_callback) {
          +            _callback = _callback.bind(this._conn);
          +            _callback();
          +        }
          +        this._conn._doDisconnect();
          +    },
          +
          +    /** PrivateFunction: _onDisconnectTimeout
          +     *  _Private_ timeout handler for handling non-graceful disconnection.
          +     *
          +     *  This does nothing for WebSockets
          +     */
          +    _onDisconnectTimeout: function () {},
          +
          +    /** PrivateFunction: _onError
          +     * _Private_ function to handle websockets errors.
          +     *
          +     * Parameters:
          +     * (Object) error - The websocket error.
          +     */
          +    _onError: function(error) {
          +        Strophe.error("Websocket error " + error);
          +        this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "The WebSocket connection could not be established was disconnected.");
          +        this._disconnect();
          +    },
          +
          +    /** PrivateFunction: _onIdle
          +     *  _Private_ function called by Strophe.Connection._onIdle
          +     *
          +     *  sends all queued stanzas
          +     */
          +    _onIdle: function () {
          +        var data = this._conn._data;
          +        if (data.length > 0 && !this._conn.paused) {
          +            for (var i = 0; i < data.length; i++) {
          +                if (data[i] !== null) {
          +                    var stanza, rawStanza;
          +                    if (data[i] === "restart") {
          +                        stanza = this._buildStream();
          +                        rawStanza = this._removeClosingTag(stanza);
          +                        stanza = stanza.tree();
          +                    } else {
          +                        stanza = data[i];
          +                        rawStanza = Strophe.serialize(stanza);
          +                    }
          +                    this._conn.xmlOutput(stanza);
          +                    this._conn.rawOutput(rawStanza);
          +                    this.socket.send(rawStanza);
          +                }
          +            }
          +            this._conn._data = [];
          +        }
          +    },
          +
          +    /** PrivateFunction: _onMessage
          +     * _Private_ function to handle websockets messages.
          +     *
          +     * This function parses each of the messages as if they are full documents. [TODO : We may actually want to use a SAX Push parser].
          +     *
          +     * Since all XMPP traffic starts with "<stream:stream version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='3697395463' from='SERVER'>"
          +     * The first stanza will always fail to be parsed...
          +     * Addtionnaly, the seconds stanza will always be a <stream:features> with the stream NS defined in the previous stanza... so we need to 'force' the inclusion of the NS in this stanza!
          +     *
          +     * Parameters:
          +     * (string) message - The websocket message.
          +     */
          +    _onMessage: function(message) {
          +        var elem, data;
          +        // check for closing stream
          +        if (message.data === "</stream:stream>") {
          +            var close = "</stream:stream>";
          +            this._conn.rawInput(close);
          +            this._conn.xmlInput(document.createElement("stream:stream"));
          +            if (!this._conn.disconnecting) {
          +                this._conn._doDisconnect();
          +            }
          +            return;
          +        } else if (message.data.search("<stream:stream ") === 0) {
          +            //Make the initial stream:stream selfclosing to parse it without a SAX parser.
          +            data = message.data.replace(/<stream:stream (.*[^\/])>/, "<stream:stream $1/>");
          +            elem = new DOMParser().parseFromString(data, "text/xml").documentElement;
          +
          +            if (!this._handleStreamStart(elem)) {
          +                return;
          +            }
          +        } else {
          +            data = this._streamWrap(message.data);
          +            elem = new DOMParser().parseFromString(data, "text/xml").documentElement;
          +        }
          +
          +        if (this._check_streamerror(elem, Strophe.Status.ERROR)) {
          +            return;
          +        }
          +
          +        //handle unavailable presence stanza before disconnecting
          +        if (this._conn.disconnecting &&
          +                elem.firstChild.nodeName === "presence" &&
          +                elem.firstChild.getAttribute("type") === "unavailable") {
          +            this._conn.xmlInput(elem);
          +            this._conn.rawInput(Strophe.serialize(elem));
          +            // if we are already disconnecting we will ignore the unavailable stanza and
          +            // wait for the </stream:stream> tag before we close the connection
          +            return;
          +        }
          +        this._conn._dataRecv(elem, message.data);
          +    },
          +
          +    /** PrivateFunction: _onOpen
          +     * _Private_ function to handle websockets connection setup.
          +     *
          +     * The opening stream tag is sent here.
          +     */
          +    _onOpen: function() {
          +        Strophe.info("Websocket open");
          +        var start = this._buildStream();
          +        this._conn.xmlOutput(start.tree());
          +
          +        var startString = this._removeClosingTag(start);
          +        this._conn.rawOutput(startString);
          +        this.socket.send(startString);
          +    },
          +
          +    /** PrivateFunction: _removeClosingTag
          +     *  _Private_ function to Make the first <stream:stream> non-selfclosing
          +     *
          +     *  Parameters:
          +     *      (Object) elem - The <stream:stream> tag.
          +     *
          +     *  Returns:
          +     *      The stream:stream tag as String
          +     */
          +    _removeClosingTag: function(elem) {
          +        var string = Strophe.serialize(elem);
          +        string = string.replace(/<(stream:stream .*[^\/])\/>$/, "<$1>");
          +        return string;
          +    },
          +
          +    /** PrivateFunction: _reqToData
          +     * _Private_ function to get a stanza out of a request.
          +     *
          +     * WebSockets don't use requests, so the passed argument is just returned.
          +     *
          +     *  Parameters:
          +     *    (Object) stanza - The stanza.
          +     *
          +     *  Returns:
          +     *    The stanza that was passed.
          +     */
          +    _reqToData: function (stanza)
          +    {
          +        return stanza;
          +    },
          +
          +    /** PrivateFunction: _send
          +     *  _Private_ part of the Connection.send function for WebSocket
          +     *
          +     * Just flushes the messages that are in the queue
          +     */
          +    _send: function () {
          +        this._conn.flush();
          +    },
          +
          +    /** PrivateFunction: _sendRestart
          +     *
          +     *  Send an xmpp:restart stanza.
          +     */
          +    _sendRestart: function ()
          +    {
          +        clearTimeout(this._conn._idleTimeout);
          +        this._conn._onIdle.bind(this._conn)();
          +    }
          +};
          diff --git a/public/javascripts/strophejs-1.1.3/strophe.min.js b/public/javascripts/strophejs-1.1.3/strophe.min.js
          new file mode 100644
          index 0000000..3f2cbaf
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/strophe.min.js
          @@ -0,0 +1,3 @@
          +/*! strophe.js v1.1.3 - built on 20-01-2014 */
          +function b64_sha1(a){return binb2b64(core_sha1(str2binb(a),8*a.length))}function str_sha1(a){return binb2str(core_sha1(str2binb(a),8*a.length))}function b64_hmac_sha1(a,b){return binb2b64(core_hmac_sha1(a,b))}function str_hmac_sha1(a,b){return binb2str(core_hmac_sha1(a,b))}function core_sha1(a,b){a[b>>5]|=128<<24-b%32,a[(b+64>>9<<4)+15]=b;var c,d,e,f,g,h,i,j,k=new Array(80),l=1732584193,m=-271733879,n=-1732584194,o=271733878,p=-1009589776;for(c=0;c<a.length;c+=16){for(f=l,g=m,h=n,i=o,j=p,d=0;80>d;d++)k[d]=16>d?a[c+d]:rol(k[d-3]^k[d-8]^k[d-14]^k[d-16],1),e=safe_add(safe_add(rol(l,5),sha1_ft(d,m,n,o)),safe_add(safe_add(p,k[d]),sha1_kt(d))),p=o,o=n,n=rol(m,30),m=l,l=e;l=safe_add(l,f),m=safe_add(m,g),n=safe_add(n,h),o=safe_add(o,i),p=safe_add(p,j)}return[l,m,n,o,p]}function sha1_ft(a,b,c,d){return 20>a?b&c|~b&d:40>a?b^c^d:60>a?b&c|b&d|c&d:b^c^d}function sha1_kt(a){return 20>a?1518500249:40>a?1859775393:60>a?-1894007588:-899497514}function core_hmac_sha1(a,b){var c=str2binb(a);c.length>16&&(c=core_sha1(c,8*a.length));for(var d=new Array(16),e=new Array(16),f=0;16>f;f++)d[f]=909522486^c[f],e[f]=1549556828^c[f];var g=core_sha1(d.concat(str2binb(b)),512+8*b.length);return core_sha1(e.concat(g),672)}function safe_add(a,b){var c=(65535&a)+(65535&b),d=(a>>16)+(b>>16)+(c>>16);return d<<16|65535&c}function rol(a,b){return a<<b|a>>>32-b}function str2binb(a){for(var b=[],c=255,d=0;d<8*a.length;d+=8)b[d>>5]|=(a.charCodeAt(d/8)&c)<<24-d%32;return b}function binb2str(a){for(var b="",c=255,d=0;d<32*a.length;d+=8)b+=String.fromCharCode(a[d>>5]>>>24-d%32&c);return b}function binb2b64(a){for(var b,c,d="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",e="",f=0;f<4*a.length;f+=3)for(b=(a[f>>2]>>8*(3-f%4)&255)<<16|(a[f+1>>2]>>8*(3-(f+1)%4)&255)<<8|a[f+2>>2]>>8*(3-(f+2)%4)&255,c=0;4>c;c++)e+=8*f+6*c>32*a.length?"=":d.charAt(b>>6*(3-c)&63);return e}var Base64=function(){var a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",b={encode:function(b){var c,d,e,f,g,h,i,j="",k=0;do c=b.charCodeAt(k++),d=b.charCodeAt(k++),e=b.charCodeAt(k++),f=c>>2,g=(3&c)<<4|d>>4,h=(15&d)<<2|e>>6,i=63&e,isNaN(d)?h=i=64:isNaN(e)&&(i=64),j=j+a.charAt(f)+a.charAt(g)+a.charAt(h)+a.charAt(i);while(k<b.length);return j},decode:function(b){var c,d,e,f,g,h,i,j="",k=0;b=b.replace(/[^A-Za-z0-9\+\/\=]/g,"");do f=a.indexOf(b.charAt(k++)),g=a.indexOf(b.charAt(k++)),h=a.indexOf(b.charAt(k++)),i=a.indexOf(b.charAt(k++)),c=f<<2|g>>4,d=(15&g)<<4|h>>2,e=(3&h)<<6|i,j+=String.fromCharCode(c),64!=h&&(j+=String.fromCharCode(d)),64!=i&&(j+=String.fromCharCode(e));while(k<b.length);return j}};return b}(),MD5=function(){var a=function(a,b){var c=(65535&a)+(65535&b),d=(a>>16)+(b>>16)+(c>>16);return d<<16|65535&c},b=function(a,b){return a<<b|a>>>32-b},c=function(a){for(var b=[],c=0;c<8*a.length;c+=8)b[c>>5]|=(255&a.charCodeAt(c/8))<<c%32;return b},d=function(a){for(var b="",c=0;c<32*a.length;c+=8)b+=String.fromCharCode(a[c>>5]>>>c%32&255);return b},e=function(a){for(var b="0123456789abcdef",c="",d=0;d<4*a.length;d++)c+=b.charAt(a[d>>2]>>d%4*8+4&15)+b.charAt(a[d>>2]>>d%4*8&15);return c},f=function(c,d,e,f,g,h){return a(b(a(a(d,c),a(f,h)),g),e)},g=function(a,b,c,d,e,g,h){return f(b&c|~b&d,a,b,e,g,h)},h=function(a,b,c,d,e,g,h){return f(b&d|c&~d,a,b,e,g,h)},i=function(a,b,c,d,e,g,h){return f(b^c^d,a,b,e,g,h)},j=function(a,b,c,d,e,g,h){return f(c^(b|~d),a,b,e,g,h)},k=function(b,c){b[c>>5]|=128<<c%32,b[(c+64>>>9<<4)+14]=c;for(var d,e,f,k,l=1732584193,m=-271733879,n=-1732584194,o=271733878,p=0;p<b.length;p+=16)d=l,e=m,f=n,k=o,l=g(l,m,n,o,b[p+0],7,-680876936),o=g(o,l,m,n,b[p+1],12,-389564586),n=g(n,o,l,m,b[p+2],17,606105819),m=g(m,n,o,l,b[p+3],22,-1044525330),l=g(l,m,n,o,b[p+4],7,-176418897),o=g(o,l,m,n,b[p+5],12,1200080426),n=g(n,o,l,m,b[p+6],17,-1473231341),m=g(m,n,o,l,b[p+7],22,-45705983),l=g(l,m,n,o,b[p+8],7,1770035416),o=g(o,l,m,n,b[p+9],12,-1958414417),n=g(n,o,l,m,b[p+10],17,-42063),m=g(m,n,o,l,b[p+11],22,-1990404162),l=g(l,m,n,o,b[p+12],7,1804603682),o=g(o,l,m,n,b[p+13],12,-40341101),n=g(n,o,l,m,b[p+14],17,-1502002290),m=g(m,n,o,l,b[p+15],22,1236535329),l=h(l,m,n,o,b[p+1],5,-165796510),o=h(o,l,m,n,b[p+6],9,-1069501632),n=h(n,o,l,m,b[p+11],14,643717713),m=h(m,n,o,l,b[p+0],20,-373897302),l=h(l,m,n,o,b[p+5],5,-701558691),o=h(o,l,m,n,b[p+10],9,38016083),n=h(n,o,l,m,b[p+15],14,-660478335),m=h(m,n,o,l,b[p+4],20,-405537848),l=h(l,m,n,o,b[p+9],5,568446438),o=h(o,l,m,n,b[p+14],9,-1019803690),n=h(n,o,l,m,b[p+3],14,-187363961),m=h(m,n,o,l,b[p+8],20,1163531501),l=h(l,m,n,o,b[p+13],5,-1444681467),o=h(o,l,m,n,b[p+2],9,-51403784),n=h(n,o,l,m,b[p+7],14,1735328473),m=h(m,n,o,l,b[p+12],20,-1926607734),l=i(l,m,n,o,b[p+5],4,-378558),o=i(o,l,m,n,b[p+8],11,-2022574463),n=i(n,o,l,m,b[p+11],16,1839030562),m=i(m,n,o,l,b[p+14],23,-35309556),l=i(l,m,n,o,b[p+1],4,-1530992060),o=i(o,l,m,n,b[p+4],11,1272893353),n=i(n,o,l,m,b[p+7],16,-155497632),m=i(m,n,o,l,b[p+10],23,-1094730640),l=i(l,m,n,o,b[p+13],4,681279174),o=i(o,l,m,n,b[p+0],11,-358537222),n=i(n,o,l,m,b[p+3],16,-722521979),m=i(m,n,o,l,b[p+6],23,76029189),l=i(l,m,n,o,b[p+9],4,-640364487),o=i(o,l,m,n,b[p+12],11,-421815835),n=i(n,o,l,m,b[p+15],16,530742520),m=i(m,n,o,l,b[p+2],23,-995338651),l=j(l,m,n,o,b[p+0],6,-198630844),o=j(o,l,m,n,b[p+7],10,1126891415),n=j(n,o,l,m,b[p+14],15,-1416354905),m=j(m,n,o,l,b[p+5],21,-57434055),l=j(l,m,n,o,b[p+12],6,1700485571),o=j(o,l,m,n,b[p+3],10,-1894986606),n=j(n,o,l,m,b[p+10],15,-1051523),m=j(m,n,o,l,b[p+1],21,-2054922799),l=j(l,m,n,o,b[p+8],6,1873313359),o=j(o,l,m,n,b[p+15],10,-30611744),n=j(n,o,l,m,b[p+6],15,-1560198380),m=j(m,n,o,l,b[p+13],21,1309151649),l=j(l,m,n,o,b[p+4],6,-145523070),o=j(o,l,m,n,b[p+11],10,-1120210379),n=j(n,o,l,m,b[p+2],15,718787259),m=j(m,n,o,l,b[p+9],21,-343485551),l=a(l,d),m=a(m,e),n=a(n,f),o=a(o,k);return[l,m,n,o]},l={hexdigest:function(a){return e(k(c(a),8*a.length))},hash:function(a){return d(k(c(a),8*a.length))}};return l}();Function.prototype.bind||(Function.prototype.bind=function(a){var b=this,c=Array.prototype.slice,d=Array.prototype.concat,e=c.call(arguments,1);return function(){return b.apply(a?a:this,d.call(e,c.call(arguments,0)))}}),Array.prototype.indexOf||(Array.prototype.indexOf=function(a){var b=this.length,c=Number(arguments[1])||0;for(c=0>c?Math.ceil(c):Math.floor(c),0>c&&(c+=b);b>c;c++)if(c in this&&this[c]===a)return c;return-1}),function(a){function b(a,b){return new f.Builder(a,b)}function c(a){return new f.Builder("message",a)}function d(a){return new f.Builder("iq",a)}function e(a){return new f.Builder("presence",a)}var f;f={VERSION:"1.1.3",NS:{HTTPBIND:"http://jabber.org/protocol/httpbind",BOSH:"urn:xmpp:xbosh",CLIENT:"jabber:client",AUTH:"jabber:iq:auth",ROSTER:"jabber:iq:roster",PROFILE:"jabber:iq:profile",DISCO_INFO:"http://jabber.org/protocol/disco#info",DISCO_ITEMS:"http://jabber.org/protocol/disco#items",MUC:"http://jabber.org/protocol/muc",SASL:"urn:ietf:params:xml:ns:xmpp-sasl",STREAM:"http://etherx.jabber.org/streams",BIND:"urn:ietf:params:xml:ns:xmpp-bind",SESSION:"urn:ietf:params:xml:ns:xmpp-session",VERSION:"jabber:iq:version",STANZAS:"urn:ietf:params:xml:ns:xmpp-stanzas",XHTML_IM:"http://jabber.org/protocol/xhtml-im",XHTML:"http://www.w3.org/1999/xhtml"},XHTML:{tags:["a","blockquote","br","cite","em","img","li","ol","p","span","strong","ul","body"],attributes:{a:["href"],blockquote:["style"],br:[],cite:["style"],em:[],img:["src","alt","style","height","width"],li:["style"],ol:["style"],p:["style"],span:["style"],strong:[],ul:["style"],body:[]},css:["background-color","color","font-family","font-size","font-style","font-weight","margin-left","margin-right","text-align","text-decoration"],validTag:function(a){for(var b=0;b<f.XHTML.tags.length;b++)if(a==f.XHTML.tags[b])return!0;return!1},validAttribute:function(a,b){if("undefined"!=typeof f.XHTML.attributes[a]&&f.XHTML.attributes[a].length>0)for(var c=0;c<f.XHTML.attributes[a].length;c++)if(b==f.XHTML.attributes[a][c])return!0;return!1},validCSS:function(a){for(var b=0;b<f.XHTML.css.length;b++)if(a==f.XHTML.css[b])return!0;return!1}},Status:{ERROR:0,CONNECTING:1,CONNFAIL:2,AUTHENTICATING:3,AUTHFAIL:4,CONNECTED:5,DISCONNECTED:6,DISCONNECTING:7,ATTACHED:8},LogLevel:{DEBUG:0,INFO:1,WARN:2,ERROR:3,FATAL:4},ElementType:{NORMAL:1,TEXT:3,CDATA:4,FRAGMENT:11},TIMEOUT:1.1,SECONDARY_TIMEOUT:.1,addNamespace:function(a,b){f.NS[a]=b},forEachChild:function(a,b,c){var d,e;for(d=0;d<a.childNodes.length;d++)e=a.childNodes[d],e.nodeType!=f.ElementType.NORMAL||b&&!this.isTagEqual(e,b)||c(e)},isTagEqual:function(a,b){return a.tagName.toLowerCase()==b.toLowerCase()},_xmlGenerator:null,_makeGenerator:function(){var a;return void 0===document.implementation.createDocument||document.implementation.createDocument&&document.documentMode&&document.documentMode<10?(a=this._getIEXmlDom(),a.appendChild(a.createElement("strophe"))):a=document.implementation.createDocument("jabber:client","strophe",null),a},xmlGenerator:function(){return f._xmlGenerator||(f._xmlGenerator=f._makeGenerator()),f._xmlGenerator},_getIEXmlDom:function(){for(var a=null,b=["Msxml2.DOMDocument.6.0","Msxml2.DOMDocument.5.0","Msxml2.DOMDocument.4.0","MSXML2.DOMDocument.3.0","MSXML2.DOMDocument","MSXML.DOMDocument","Microsoft.XMLDOM"],c=0;c<b.length&&null===a;c++)try{a=new ActiveXObject(b[c])}catch(d){a=null}return a},xmlElement:function(a){if(!a)return null;var b,c,d,e=f.xmlGenerator().createElement(a);for(b=1;b<arguments.length;b++)if(arguments[b])if("string"==typeof arguments[b]||"number"==typeof arguments[b])e.appendChild(f.xmlTextNode(arguments[b]));else if("object"==typeof arguments[b]&&"function"==typeof arguments[b].sort)for(c=0;c<arguments[b].length;c++)"object"==typeof arguments[b][c]&&"function"==typeof arguments[b][c].sort&&e.setAttribute(arguments[b][c][0],arguments[b][c][1]);else if("object"==typeof arguments[b])for(d in arguments[b])arguments[b].hasOwnProperty(d)&&e.setAttribute(d,arguments[b][d]);return e},xmlescape:function(a){return a=a.replace(/\&/g,"&amp;"),a=a.replace(/</g,"&lt;"),a=a.replace(/>/g,"&gt;"),a=a.replace(/'/g,"&apos;"),a=a.replace(/"/g,"&quot;")},xmlTextNode:function(a){return f.xmlGenerator().createTextNode(a)},xmlHtmlNode:function(a){var b;if(window.DOMParser){var c=new DOMParser;b=c.parseFromString(a,"text/xml")}else b=new ActiveXObject("Microsoft.XMLDOM"),b.async="false",b.loadXML(a);return b},getText:function(a){if(!a)return null;var b="";0===a.childNodes.length&&a.nodeType==f.ElementType.TEXT&&(b+=a.nodeValue);for(var c=0;c<a.childNodes.length;c++)a.childNodes[c].nodeType==f.ElementType.TEXT&&(b+=a.childNodes[c].nodeValue);return f.xmlescape(b)},copyElement:function(a){var b,c;if(a.nodeType==f.ElementType.NORMAL){for(c=f.xmlElement(a.tagName),b=0;b<a.attributes.length;b++)c.setAttribute(a.attributes[b].nodeName.toLowerCase(),a.attributes[b].value);for(b=0;b<a.childNodes.length;b++)c.appendChild(f.copyElement(a.childNodes[b]))}else a.nodeType==f.ElementType.TEXT&&(c=f.xmlGenerator().createTextNode(a.nodeValue));return c},createHtml:function(a){var b,c,d,e,g,h,i,j,k,l,m;if(a.nodeType==f.ElementType.NORMAL)if(e=a.nodeName.toLowerCase(),f.XHTML.validTag(e))try{for(c=f.xmlElement(e),b=0;b<f.XHTML.attributes[e].length;b++)if(g=f.XHTML.attributes[e][b],h=a.getAttribute(g),"undefined"!=typeof h&&null!==h&&""!==h&&h!==!1&&0!==h)if("style"==g&&"object"==typeof h&&"undefined"!=typeof h.cssText&&(h=h.cssText),"style"==g){for(i=[],j=h.split(";"),d=0;d<j.length;d++)k=j[d].split(":"),l=k[0].replace(/^\s*/,"").replace(/\s*$/,"").toLowerCase(),f.XHTML.validCSS(l)&&(m=k[1].replace(/^\s*/,"").replace(/\s*$/,""),i.push(l+": "+m));i.length>0&&(h=i.join("; "),c.setAttribute(g,h))}else c.setAttribute(g,h);for(b=0;b<a.childNodes.length;b++)c.appendChild(f.createHtml(a.childNodes[b]))}catch(n){c=f.xmlTextNode("")}else for(c=f.xmlGenerator().createDocumentFragment(),b=0;b<a.childNodes.length;b++)c.appendChild(f.createHtml(a.childNodes[b]));else if(a.nodeType==f.ElementType.FRAGMENT)for(c=f.xmlGenerator().createDocumentFragment(),b=0;b<a.childNodes.length;b++)c.appendChild(f.createHtml(a.childNodes[b]));else a.nodeType==f.ElementType.TEXT&&(c=f.xmlTextNode(a.nodeValue));return c},escapeNode:function(a){return a.replace(/^\s+|\s+$/g,"").replace(/\\/g,"\\5c").replace(/ /g,"\\20").replace(/\"/g,"\\22").replace(/\&/g,"\\26").replace(/\'/g,"\\27").replace(/\//g,"\\2f").replace(/:/g,"\\3a").replace(/</g,"\\3c").replace(/>/g,"\\3e").replace(/@/g,"\\40")},unescapeNode:function(a){return a.replace(/\\20/g," ").replace(/\\22/g,'"').replace(/\\26/g,"&").replace(/\\27/g,"'").replace(/\\2f/g,"/").replace(/\\3a/g,":").replace(/\\3c/g,"<").replace(/\\3e/g,">").replace(/\\40/g,"@").replace(/\\5c/g,"\\")},getNodeFromJid:function(a){return a.indexOf("@")<0?null:a.split("@")[0]},getDomainFromJid:function(a){var b=f.getBareJidFromJid(a);if(b.indexOf("@")<0)return b;var c=b.split("@");return c.splice(0,1),c.join("@")},getResourceFromJid:function(a){var b=a.split("/");return b.length<2?null:(b.splice(0,1),b.join("/"))},getBareJidFromJid:function(a){return a?a.split("/")[0]:null},log:function(){},debug:function(a){this.log(this.LogLevel.DEBUG,a)},info:function(a){this.log(this.LogLevel.INFO,a)},warn:function(a){this.log(this.LogLevel.WARN,a)},error:function(a){this.log(this.LogLevel.ERROR,a)},fatal:function(a){this.log(this.LogLevel.FATAL,a)},serialize:function(a){var b;if(!a)return null;"function"==typeof a.tree&&(a=a.tree());var c,d,e=a.nodeName;for(a.getAttribute("_realname")&&(e=a.getAttribute("_realname")),b="<"+e,c=0;c<a.attributes.length;c++)"_realname"!=a.attributes[c].nodeName&&(b+=" "+a.attributes[c].nodeName.toLowerCase()+"='"+a.attributes[c].value.replace(/&/g,"&amp;").replace(/\'/g,"&apos;").replace(/>/g,"&gt;").replace(/</g,"&lt;")+"'");if(a.childNodes.length>0){for(b+=">",c=0;c<a.childNodes.length;c++)switch(d=a.childNodes[c],d.nodeType){case f.ElementType.NORMAL:b+=f.serialize(d);break;case f.ElementType.TEXT:b+=f.xmlescape(d.nodeValue);break;case f.ElementType.CDATA:b+="<![CDATA["+d.nodeValue+"]]>"}b+="</"+e+">"}else b+="/>";return b},_requestId:0,_connectionPlugins:{},addConnectionPlugin:function(a,b){f._connectionPlugins[a]=b}},f.Builder=function(a,b){("presence"==a||"message"==a||"iq"==a)&&(b&&!b.xmlns?b.xmlns=f.NS.CLIENT:b||(b={xmlns:f.NS.CLIENT})),this.nodeTree=f.xmlElement(a,b),this.node=this.nodeTree},f.Builder.prototype={tree:function(){return this.nodeTree},toString:function(){return f.serialize(this.nodeTree)},up:function(){return this.node=this.node.parentNode,this},attrs:function(a){for(var b in a)a.hasOwnProperty(b)&&this.node.setAttribute(b,a[b]);return this},c:function(a,b,c){var d=f.xmlElement(a,b,c);return this.node.appendChild(d),c||(this.node=d),this},cnode:function(a){var b,c=f.xmlGenerator();try{b=void 0!==c.importNode}catch(d){b=!1}var e=b?c.importNode(a,!0):f.copyElement(a);return this.node.appendChild(e),this.node=e,this},t:function(a){var b=f.xmlTextNode(a);return this.node.appendChild(b),this},h:function(a){var b=document.createElement("body");b.innerHTML=a;for(var c=f.createHtml(b);c.childNodes.length>0;)this.node.appendChild(c.childNodes[0]);return this}},f.Handler=function(a,b,c,d,e,g,h){this.handler=a,this.ns=b,this.name=c,this.type=d,this.id=e,this.options=h||{matchBare:!1},this.options.matchBare||(this.options.matchBare=!1),this.from=this.options.matchBare?g?f.getBareJidFromJid(g):null:g,this.user=!0},f.Handler.prototype={isMatch:function(a){var b,c=null;if(c=this.options.matchBare?f.getBareJidFromJid(a.getAttribute("from")):a.getAttribute("from"),b=!1,this.ns){var d=this;f.forEachChild(a,null,function(a){a.getAttribute("xmlns")==d.ns&&(b=!0)}),b=b||a.getAttribute("xmlns")==this.ns}else b=!0;return!b||this.name&&!f.isTagEqual(a,this.name)||this.type&&a.getAttribute("type")!=this.type||this.id&&a.getAttribute("id")!=this.id||this.from&&c!=this.from?!1:!0},run:function(a){var b=null;try{b=this.handler(a)}catch(c){throw c.sourceURL?f.fatal("error: "+this.handler+" "+c.sourceURL+":"+c.line+" - "+c.name+": "+c.message):c.fileName?("undefined"!=typeof console&&(console.trace(),console.error(this.handler," - error - ",c,c.message)),f.fatal("error: "+this.handler+" "+c.fileName+":"+c.lineNumber+" - "+c.name+": "+c.message)):f.fatal("error: "+c.message+"\n"+c.stack),c}return b},toString:function(){return"{Handler: "+this.handler+"("+this.name+","+this.id+","+this.ns+")}"}},f.TimedHandler=function(a,b){this.period=a,this.handler=b,this.lastCalled=(new Date).getTime(),this.user=!0},f.TimedHandler.prototype={run:function(){return this.lastCalled=(new Date).getTime(),this.handler()},reset:function(){this.lastCalled=(new Date).getTime()},toString:function(){return"{TimedHandler: "+this.handler+"("+this.period+")}"}},f.Connection=function(a,b){this.service=a,this.options=b||{};var c=this.options.protocol||"";this._proto=0===a.indexOf("ws:")||0===a.indexOf("wss:")||0===c.indexOf("ws")?new f.Websocket(this):new f.Bosh(this),this.jid="",this.domain=null,this.features=null,this._sasl_data={},this.do_session=!1,this.do_bind=!1,this.timedHandlers=[],this.handlers=[],this.removeTimeds=[],this.removeHandlers=[],this.addTimeds=[],this.addHandlers=[],this._authentication={},this._idleTimeout=null,this._disconnectTimeout=null,this.do_authentication=!0,this.authenticated=!1,this.disconnecting=!1,this.connected=!1,this.errors=0,this.paused=!1,this._data=[],this._uniqueId=0,this._sasl_success_handler=null,this._sasl_failure_handler=null,this._sasl_challenge_handler=null,this.maxRetries=5,this._idleTimeout=setTimeout(this._onIdle.bind(this),100);for(var d in f._connectionPlugins)if(f._connectionPlugins.hasOwnProperty(d)){var e=f._connectionPlugins[d],g=function(){};g.prototype=e,this[d]=new g,this[d].init(this)}},f.Connection.prototype={reset:function(){this._proto._reset(),this.do_session=!1,this.do_bind=!1,this.timedHandlers=[],this.handlers=[],this.removeTimeds=[],this.removeHandlers=[],this.addTimeds=[],this.addHandlers=[],this._authentication={},this.authenticated=!1,this.disconnecting=!1,this.connected=!1,this.errors=0,this._requests=[],this._uniqueId=0},pause:function(){this.paused=!0},resume:function(){this.paused=!1},getUniqueId:function(a){return"string"==typeof a||"number"==typeof a?++this._uniqueId+":"+a:++this._uniqueId+""},connect:function(a,b,c,d,e,g){this.jid=a,this.authzid=f.getBareJidFromJid(this.jid),this.authcid=f.getNodeFromJid(this.jid),this.pass=b,this.servtype="xmpp",this.connect_callback=c,this.disconnecting=!1,this.connected=!1,this.authenticated=!1,this.errors=0,this.domain=f.getDomainFromJid(this.jid),this._changeConnectStatus(f.Status.CONNECTING,null),this._proto._connect(d,e,g)},attach:function(a,b,c,d,e,f,g){this._proto._attach(a,b,c,d,e,f,g)},xmlInput:function(){},xmlOutput:function(){},rawInput:function(){},rawOutput:function(){},send:function(a){if(null!==a){if("function"==typeof a.sort)for(var b=0;b<a.length;b++)this._queueData(a[b]);else"function"==typeof a.tree?this._queueData(a.tree()):this._queueData(a);this._proto._send()}},flush:function(){clearTimeout(this._idleTimeout),this._onIdle()},sendIQ:function(a,b,c,d){var e=null,f=this;"function"==typeof a.tree&&(a=a.tree());var g=a.getAttribute("id");g||(g=this.getUniqueId("sendIQ"),a.setAttribute("id",g));var h=this.addHandler(function(a){e&&f.deleteTimedHandler(e);var d=a.getAttribute("type");if("result"==d)b&&b(a);else{if("error"!=d)throw{name:"StropheError",message:"Got bad IQ type of "+d};c&&c(a)}},null,"iq",null,g);return d&&(e=this.addTimedHandler(d,function(){return f.deleteHandler(h),c&&c(null),!1})),this.send(a),g},_queueData:function(a){if(null===a||!a.tagName||!a.childNodes)throw{name:"StropheError",message:"Cannot queue non-DOMElement."};this._data.push(a)},_sendRestart:function(){this._data.push("restart"),this._proto._sendRestart(),this._idleTimeout=setTimeout(this._onIdle.bind(this),100)},addTimedHandler:function(a,b){var c=new f.TimedHandler(a,b);return this.addTimeds.push(c),c},deleteTimedHandler:function(a){this.removeTimeds.push(a)},addHandler:function(a,b,c,d,e,g,h){var i=new f.Handler(a,b,c,d,e,g,h);return this.addHandlers.push(i),i},deleteHandler:function(a){this.removeHandlers.push(a)},disconnect:function(a){if(this._changeConnectStatus(f.Status.DISCONNECTING,a),f.info("Disconnect was called because: "+a),this.connected){var b=!1;this.disconnecting=!0,this.authenticated&&(b=e({xmlns:f.NS.CLIENT,type:"unavailable"})),this._disconnectTimeout=this._addSysTimedHandler(3e3,this._onDisconnectTimeout.bind(this)),this._proto._disconnect(b)}},_changeConnectStatus:function(a,b){for(var c in f._connectionPlugins)if(f._connectionPlugins.hasOwnProperty(c)){var d=this[c];if(d.statusChanged)try{d.statusChanged(a,b)}catch(e){f.error(""+c+" plugin caused an exception changing status: "+e)}}if(this.connect_callback)try{this.connect_callback(a,b)}catch(g){f.error("User connection callback caused an exception: "+g)}},_doDisconnect:function(){null!==this._disconnectTimeout&&(this.deleteTimedHandler(this._disconnectTimeout),this._disconnectTimeout=null),f.info("_doDisconnect was called"),this._proto._doDisconnect(),this.authenticated=!1,this.disconnecting=!1,this.handlers=[],this.timedHandlers=[],this.removeTimeds=[],this.removeHandlers=[],this.addTimeds=[],this.addHandlers=[],this._changeConnectStatus(f.Status.DISCONNECTED,null),this.connected=!1},_dataRecv:function(a,b){f.info("_dataRecv called");var c=this._proto._reqToData(a);if(null!==c){this.xmlInput!==f.Connection.prototype.xmlInput&&(c.nodeName===this._proto.strip&&c.childNodes.length?this.xmlInput(c.childNodes[0]):this.xmlInput(c)),this.rawInput!==f.Connection.prototype.rawInput&&(b?this.rawInput(b):this.rawInput(f.serialize(c)));for(var d,e;this.removeHandlers.length>0;)e=this.removeHandlers.pop(),d=this.handlers.indexOf(e),d>=0&&this.handlers.splice(d,1);for(;this.addHandlers.length>0;)this.handlers.push(this.addHandlers.pop());if(this.disconnecting&&this._proto._emptyQueue())return this._doDisconnect(),void 0;var g,h,i=c.getAttribute("type");if(null!==i&&"terminate"==i){if(this.disconnecting)return;return g=c.getAttribute("condition"),h=c.getElementsByTagName("conflict"),null!==g?("remote-stream-error"==g&&h.length>0&&(g="conflict"),this._changeConnectStatus(f.Status.CONNFAIL,g)):this._changeConnectStatus(f.Status.CONNFAIL,"unknown"),this.disconnect("unknown stream-error"),void 0}var j=this;f.forEachChild(c,null,function(a){var b,c;for(c=j.handlers,j.handlers=[],b=0;b<c.length;b++){var d=c[b];try{!d.isMatch(a)||!j.authenticated&&d.user?j.handlers.push(d):d.run(a)&&j.handlers.push(d)}catch(e){f.warn("Removing Strophe handlers due to uncaught exception: "+e.message)}}})}},mechanisms:{},_connect_cb:function(a,b,c){f.info("_connect_cb was called"),this.connected=!0;var d=this._proto._reqToData(a);if(d){this.xmlInput!==f.Connection.prototype.xmlInput&&(d.nodeName===this._proto.strip&&d.childNodes.length?this.xmlInput(d.childNodes[0]):this.xmlInput(d)),this.rawInput!==f.Connection.prototype.rawInput&&(c?this.rawInput(c):this.rawInput(f.serialize(d)));var e=this._proto._connect_cb(d);if(e!==f.Status.CONNFAIL){this._authentication.sasl_scram_sha1=!1,this._authentication.sasl_plain=!1,this._authentication.sasl_digest_md5=!1,this._authentication.sasl_anonymous=!1,this._authentication.legacy_auth=!1;var g=d.getElementsByTagName("stream:features").length>0;g||(g=d.getElementsByTagName("features").length>0);var h,i,j=d.getElementsByTagName("mechanism"),k=[],l=!1;if(!g)return this._proto._no_auth_received(b),void 0;if(j.length>0)for(h=0;h<j.length;h++)i=f.getText(j[h]),this.mechanisms[i]&&k.push(this.mechanisms[i]);return this._authentication.legacy_auth=d.getElementsByTagName("auth").length>0,(l=this._authentication.legacy_auth||k.length>0)?(this.do_authentication!==!1&&this.authenticate(k),void 0):(this._proto._no_auth_received(b),void 0)}}},authenticate:function(a){var c;for(c=0;c<a.length-1;++c){for(var e=c,g=c+1;g<a.length;++g)a[g].prototype.priority>a[e].prototype.priority&&(e=g);if(e!=c){var h=a[c];a[c]=a[e],a[e]=h}}var i=!1;for(c=0;c<a.length;++c)if(a[c].test(this)){this._sasl_success_handler=this._addSysHandler(this._sasl_success_cb.bind(this),null,"success",null,null),this._sasl_failure_handler=this._addSysHandler(this._sasl_failure_cb.bind(this),null,"failure",null,null),this._sasl_challenge_handler=this._addSysHandler(this._sasl_challenge_cb.bind(this),null,"challenge",null,null),this._sasl_mechanism=new a[c],this._sasl_mechanism.onStart(this);var j=b("auth",{xmlns:f.NS.SASL,mechanism:this._sasl_mechanism.name});if(this._sasl_mechanism.isClientFirst){var k=this._sasl_mechanism.onChallenge(this,null);j.t(Base64.encode(k))}this.send(j.tree()),i=!0;break}i||(null===f.getNodeFromJid(this.jid)?(this._changeConnectStatus(f.Status.CONNFAIL,"x-strophe-bad-non-anon-jid"),this.disconnect("x-strophe-bad-non-anon-jid")):(this._changeConnectStatus(f.Status.AUTHENTICATING,null),this._addSysHandler(this._auth1_cb.bind(this),null,null,null,"_auth_1"),this.send(d({type:"get",to:this.domain,id:"_auth_1"}).c("query",{xmlns:f.NS.AUTH}).c("username",{}).t(f.getNodeFromJid(this.jid)).tree())))},_sasl_challenge_cb:function(a){var c=Base64.decode(f.getText(a)),d=this._sasl_mechanism.onChallenge(this,c),e=b("response",{xmlns:f.NS.SASL});return""!==d&&e.t(Base64.encode(d)),this.send(e.tree()),!0},_auth1_cb:function(){var a=d({type:"set",id:"_auth_2"}).c("query",{xmlns:f.NS.AUTH}).c("username",{}).t(f.getNodeFromJid(this.jid)).up().c("password").t(this.pass);return f.getResourceFromJid(this.jid)||(this.jid=f.getBareJidFromJid(this.jid)+"/strophe"),a.up().c("resource",{}).t(f.getResourceFromJid(this.jid)),this._addSysHandler(this._auth2_cb.bind(this),null,null,null,"_auth_2"),this.send(a.tree()),!1},_sasl_success_cb:function(a){if(this._sasl_data["server-signature"]){var b,c=Base64.decode(f.getText(a)),d=/([a-z]+)=([^,]+)(,|$)/,e=c.match(d);if("v"==e[1]&&(b=e[2]),b!=this._sasl_data["server-signature"])return this.deleteHandler(this._sasl_failure_handler),this._sasl_failure_handler=null,this._sasl_challenge_handler&&(this.deleteHandler(this._sasl_challenge_handler),this._sasl_challenge_handler=null),this._sasl_data={},this._sasl_failure_cb(null)}return f.info("SASL authentication succeeded."),this._sasl_mechanism&&this._sasl_mechanism.onSuccess(),this.deleteHandler(this._sasl_failure_handler),this._sasl_failure_handler=null,this._sasl_challenge_handler&&(this.deleteHandler(this._sasl_challenge_handler),this._sasl_challenge_handler=null),this._addSysHandler(this._sasl_auth1_cb.bind(this),null,"stream:features",null,null),this._sendRestart(),!1},_sasl_auth1_cb:function(a){this.features=a;var b,c;for(b=0;b<a.childNodes.length;b++)c=a.childNodes[b],"bind"==c.nodeName&&(this.do_bind=!0),"session"==c.nodeName&&(this.do_session=!0);if(!this.do_bind)return this._changeConnectStatus(f.Status.AUTHFAIL,null),!1;this._addSysHandler(this._sasl_bind_cb.bind(this),null,null,null,"_bind_auth_2");var e=f.getResourceFromJid(this.jid);return e?this.send(d({type:"set",id:"_bind_auth_2"}).c("bind",{xmlns:f.NS.BIND}).c("resource",{}).t(e).tree()):this.send(d({type:"set",id:"_bind_auth_2"}).c("bind",{xmlns:f.NS.BIND}).tree()),!1},_sasl_bind_cb:function(a){if("error"==a.getAttribute("type")){f.info("SASL binding failed.");var b,c=a.getElementsByTagName("conflict");return c.length>0&&(b="conflict"),this._changeConnectStatus(f.Status.AUTHFAIL,b),!1}var e,g=a.getElementsByTagName("bind");return g.length>0?(e=g[0].getElementsByTagName("jid"),e.length>0&&(this.jid=f.getText(e[0]),this.do_session?(this._addSysHandler(this._sasl_session_cb.bind(this),null,null,null,"_session_auth_2"),this.send(d({type:"set",id:"_session_auth_2"}).c("session",{xmlns:f.NS.SESSION}).tree())):(this.authenticated=!0,this._changeConnectStatus(f.Status.CONNECTED,null))),void 0):(f.info("SASL binding failed."),this._changeConnectStatus(f.Status.AUTHFAIL,null),!1)},_sasl_session_cb:function(a){if("result"==a.getAttribute("type"))this.authenticated=!0,this._changeConnectStatus(f.Status.CONNECTED,null);else if("error"==a.getAttribute("type"))return f.info("Session creation failed."),this._changeConnectStatus(f.Status.AUTHFAIL,null),!1;return!1},_sasl_failure_cb:function(){return this._sasl_success_handler&&(this.deleteHandler(this._sasl_success_handler),this._sasl_success_handler=null),this._sasl_challenge_handler&&(this.deleteHandler(this._sasl_challenge_handler),this._sasl_challenge_handler=null),this._sasl_mechanism&&this._sasl_mechanism.onFailure(),this._changeConnectStatus(f.Status.AUTHFAIL,null),!1},_auth2_cb:function(a){return"result"==a.getAttribute("type")?(this.authenticated=!0,this._changeConnectStatus(f.Status.CONNECTED,null)):"error"==a.getAttribute("type")&&(this._changeConnectStatus(f.Status.AUTHFAIL,null),this.disconnect("authentication failed")),!1},_addSysTimedHandler:function(a,b){var c=new f.TimedHandler(a,b);return c.user=!1,this.addTimeds.push(c),c},_addSysHandler:function(a,b,c,d,e){var g=new f.Handler(a,b,c,d,e);return g.user=!1,this.addHandlers.push(g),g},_onDisconnectTimeout:function(){return f.info("_onDisconnectTimeout was called"),this._proto._onDisconnectTimeout(),this._doDisconnect(),!1},_onIdle:function(){for(var a,b,c,d;this.addTimeds.length>0;)this.timedHandlers.push(this.addTimeds.pop());for(;this.removeTimeds.length>0;)b=this.removeTimeds.pop(),a=this.timedHandlers.indexOf(b),a>=0&&this.timedHandlers.splice(a,1);var e=(new Date).getTime();for(d=[],a=0;a<this.timedHandlers.length;a++)b=this.timedHandlers[a],(this.authenticated||!b.user)&&(c=b.lastCalled+b.period,0>=c-e?b.run()&&d.push(b):d.push(b));this.timedHandlers=d,clearTimeout(this._idleTimeout),this._proto._onIdle(),this.connected&&(this._idleTimeout=setTimeout(this._onIdle.bind(this),100))}},a&&a(f,b,c,d,e),f.SASLMechanism=function(a,b,c){this.name=a,this.isClientFirst=b,this.priority=c},f.SASLMechanism.prototype={test:function(){return!0},onStart:function(a){this._connection=a},onChallenge:function(){throw new Error("You should implement challenge handling!")},onFailure:function(){this._connection=null},onSuccess:function(){this._connection=null}},f.SASLAnonymous=function(){},f.SASLAnonymous.prototype=new f.SASLMechanism("ANONYMOUS",!1,10),f.SASLAnonymous.test=function(a){return null===a.authcid},f.Connection.prototype.mechanisms[f.SASLAnonymous.prototype.name]=f.SASLAnonymous,f.SASLPlain=function(){},f.SASLPlain.prototype=new f.SASLMechanism("PLAIN",!0,20),f.SASLPlain.test=function(a){return null!==a.authcid},f.SASLPlain.prototype.onChallenge=function(a){var b=a.authzid;return b+="\x00",b+=a.authcid,b+="\x00",b+=a.pass},f.Connection.prototype.mechanisms[f.SASLPlain.prototype.name]=f.SASLPlain,f.SASLSHA1=function(){},f.SASLSHA1.prototype=new f.SASLMechanism("SCRAM-SHA-1",!0,40),f.SASLSHA1.test=function(a){return null!==a.authcid},f.SASLSHA1.prototype.onChallenge=function(a,b,c){var d=c||MD5.hexdigest(1234567890*Math.random()),e="n="+a.authcid;return e+=",r=",e+=d,a._sasl_data.cnonce=d,a._sasl_data["client-first-message-bare"]=e,e="n,,"+e,this.onChallenge=function(a,b){for(var c,d,e,f,g,h,i,j,k,l,m,n="c=biws,",o=a._sasl_data["client-first-message-bare"]+","+b+",",p=a._sasl_data.cnonce,q=/([a-z]+)=([^,]+)(,|$)/;b.match(q);){var r=b.match(q);switch(b=b.replace(r[0],""),r[1]){case"r":c=r[2];break;case"s":d=r[2];break;case"i":e=r[2]}}if(c.substr(0,p.length)!==p)return a._sasl_data={},a._sasl_failure_cb();for(n+="r="+c,o+=n,d=Base64.decode(d),d+="\x00\x00\x00",f=h=core_hmac_sha1(a.pass,d),i=1;e>i;i++){for(g=core_hmac_sha1(a.pass,binb2str(h)),j=0;5>j;j++)f[j]^=g[j];h=g}for(f=binb2str(f),k=core_hmac_sha1(f,"Client Key"),l=str_hmac_sha1(f,"Server Key"),m=core_hmac_sha1(str_sha1(binb2str(k)),o),a._sasl_data["server-signature"]=b64_hmac_sha1(l,o),j=0;5>j;j++)k[j]^=m[j];return n+=",p="+Base64.encode(binb2str(k))}.bind(this),e},f.Connection.prototype.mechanisms[f.SASLSHA1.prototype.name]=f.SASLSHA1,f.SASLMD5=function(){},f.SASLMD5.prototype=new f.SASLMechanism("DIGEST-MD5",!1,30),f.SASLMD5.test=function(a){return null!==a.authcid},f.SASLMD5.prototype._quote=function(a){return'"'+a.replace(/\\/g,"\\\\").replace(/"/g,'\\"')+'"'},f.SASLMD5.prototype.onChallenge=function(a,b,c){for(var d,e=/([a-z]+)=("[^"]+"|[^,"]+)(?:,|$)/,f=c||MD5.hexdigest(""+1234567890*Math.random()),g="",h=null,i="",j="";b.match(e);)switch(d=b.match(e),b=b.replace(d[0],""),d[2]=d[2].replace(/^"(.+)"$/,"$1"),d[1]){case"realm":g=d[2];
          +break;case"nonce":i=d[2];break;case"qop":j=d[2];break;case"host":h=d[2]}var k=a.servtype+"/"+a.domain;null!==h&&(k=k+"/"+h);var l=MD5.hash(a.authcid+":"+g+":"+this._connection.pass)+":"+i+":"+f,m="AUTHENTICATE:"+k,n="";return n+="charset=utf-8,",n+="username="+this._quote(a.authcid)+",",n+="realm="+this._quote(g)+",",n+="nonce="+this._quote(i)+",",n+="nc=00000001,",n+="cnonce="+this._quote(f)+",",n+="digest-uri="+this._quote(k)+",",n+="response="+MD5.hexdigest(MD5.hexdigest(l)+":"+i+":00000001:"+f+":auth:"+MD5.hexdigest(m))+",",n+="qop=auth",this.onChallenge=function(){return""}.bind(this),n},f.Connection.prototype.mechanisms[f.SASLMD5.prototype.name]=f.SASLMD5}(function(){window.Strophe=arguments[0],window.$build=arguments[1],window.$msg=arguments[2],window.$iq=arguments[3],window.$pres=arguments[4]}),Strophe.Request=function(a,b,c,d){this.id=++Strophe._requestId,this.xmlData=a,this.data=Strophe.serialize(a),this.origFunc=b,this.func=b,this.rid=c,this.date=0/0,this.sends=d||0,this.abort=!1,this.dead=null,this.age=function(){if(!this.date)return 0;var a=new Date;return(a-this.date)/1e3},this.timeDead=function(){if(!this.dead)return 0;var a=new Date;return(a-this.dead)/1e3},this.xhr=this._newXHR()},Strophe.Request.prototype={getResponse:function(){var a=null;if(this.xhr.responseXML&&this.xhr.responseXML.documentElement){if(a=this.xhr.responseXML.documentElement,"parsererror"==a.tagName)throw Strophe.error("invalid response received"),Strophe.error("responseText: "+this.xhr.responseText),Strophe.error("responseXML: "+Strophe.serialize(this.xhr.responseXML)),"parsererror"}else this.xhr.responseText&&(Strophe.error("invalid response received"),Strophe.error("responseText: "+this.xhr.responseText),Strophe.error("responseXML: "+Strophe.serialize(this.xhr.responseXML)));return a},_newXHR:function(){var a=null;return window.XMLHttpRequest?(a=new XMLHttpRequest,a.overrideMimeType&&a.overrideMimeType("text/xml")):window.ActiveXObject&&(a=new ActiveXObject("Microsoft.XMLHTTP")),a.onreadystatechange=this.func.bind(null,this),a}},Strophe.Bosh=function(a){this._conn=a,this.rid=Math.floor(4294967295*Math.random()),this.sid=null,this.hold=1,this.wait=60,this.window=5,this._requests=[]},Strophe.Bosh.prototype={strip:null,_buildBody:function(){var a=$build("body",{rid:this.rid++,xmlns:Strophe.NS.HTTPBIND});return null!==this.sid&&a.attrs({sid:this.sid}),a},_reset:function(){this.rid=Math.floor(4294967295*Math.random()),this.sid=null},_connect:function(a,b,c){this.wait=a||this.wait,this.hold=b||this.hold;var d=this._buildBody().attrs({to:this._conn.domain,"xml:lang":"en",wait:this.wait,hold:this.hold,content:"text/xml; charset=utf-8",ver:"1.6","xmpp:version":"1.0","xmlns:xmpp":Strophe.NS.BOSH});c&&d.attrs({route:c});var e=this._conn._connect_cb;this._requests.push(new Strophe.Request(d.tree(),this._onRequestStateChange.bind(this,e.bind(this._conn)),d.tree().getAttribute("rid"))),this._throttledRequestHandler()},_attach:function(a,b,c,d,e,f,g){this._conn.jid=a,this.sid=b,this.rid=c,this._conn.connect_callback=d,this._conn.domain=Strophe.getDomainFromJid(this._conn.jid),this._conn.authenticated=!0,this._conn.connected=!0,this.wait=e||this.wait,this.hold=f||this.hold,this.window=g||this.window,this._conn._changeConnectStatus(Strophe.Status.ATTACHED,null)},_connect_cb:function(a){var b,c,d=a.getAttribute("type");if(null!==d&&"terminate"==d)return Strophe.error("BOSH-Connection failed: "+b),b=a.getAttribute("condition"),c=a.getElementsByTagName("conflict"),null!==b?("remote-stream-error"==b&&c.length>0&&(b="conflict"),this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,b)):this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,"unknown"),this._conn._doDisconnect(),Strophe.Status.CONNFAIL;this.sid||(this.sid=a.getAttribute("sid"));var e=a.getAttribute("requests");e&&(this.window=parseInt(e,10));var f=a.getAttribute("hold");f&&(this.hold=parseInt(f,10));var g=a.getAttribute("wait");g&&(this.wait=parseInt(g,10))},_disconnect:function(a){this._sendTerminate(a)},_doDisconnect:function(){this.sid=null,this.rid=Math.floor(4294967295*Math.random())},_emptyQueue:function(){return 0===this._requests.length},_hitError:function(a){this.errors++,Strophe.warn("request errored, status: "+a+", number of errors: "+this.errors),this.errors>4&&this._onDisconnectTimeout()},_no_auth_received:function(a){a=a?a.bind(this._conn):this._conn._connect_cb.bind(this._conn);var b=this._buildBody();this._requests.push(new Strophe.Request(b.tree(),this._onRequestStateChange.bind(this,a.bind(this._conn)),b.tree().getAttribute("rid"))),this._throttledRequestHandler()},_onDisconnectTimeout:function(){for(var a;this._requests.length>0;)a=this._requests.pop(),a.abort=!0,a.xhr.abort(),a.xhr.onreadystatechange=function(){}},_onIdle:function(){var a=this._conn._data;if(this._conn.authenticated&&0===this._requests.length&&0===a.length&&!this._conn.disconnecting&&(Strophe.info("no requests during idle cycle, sending blank request"),a.push(null)),this._requests.length<2&&a.length>0&&!this._conn.paused){for(var b=this._buildBody(),c=0;c<a.length;c++)null!==a[c]&&("restart"===a[c]?b.attrs({to:this._conn.domain,"xml:lang":"en","xmpp:restart":"true","xmlns:xmpp":Strophe.NS.BOSH}):b.cnode(a[c]).up());delete this._conn._data,this._conn._data=[],this._requests.push(new Strophe.Request(b.tree(),this._onRequestStateChange.bind(this,this._conn._dataRecv.bind(this._conn)),b.tree().getAttribute("rid"))),this._processRequest(this._requests.length-1)}if(this._requests.length>0){var d=this._requests[0].age();null!==this._requests[0].dead&&this._requests[0].timeDead()>Math.floor(Strophe.SECONDARY_TIMEOUT*this.wait)&&this._throttledRequestHandler(),d>Math.floor(Strophe.TIMEOUT*this.wait)&&(Strophe.warn("Request "+this._requests[0].id+" timed out, over "+Math.floor(Strophe.TIMEOUT*this.wait)+" seconds since last activity"),this._throttledRequestHandler())}},_onRequestStateChange:function(a,b){if(Strophe.debug("request id "+b.id+"."+b.sends+" state changed to "+b.xhr.readyState),b.abort)return b.abort=!1,void 0;var c;if(4==b.xhr.readyState){c=0;try{c=b.xhr.status}catch(d){}if("undefined"==typeof c&&(c=0),this.disconnecting&&c>=400)return this._hitError(c),void 0;var e=this._requests[0]==b,f=this._requests[1]==b;(c>0&&500>c||b.sends>5)&&(this._removeRequest(b),Strophe.debug("request id "+b.id+" should now be removed")),200==c?((f||e&&this._requests.length>0&&this._requests[0].age()>Math.floor(Strophe.SECONDARY_TIMEOUT*this.wait))&&this._restartRequest(0),Strophe.debug("request id "+b.id+"."+b.sends+" got 200"),a(b),this.errors=0):(Strophe.error("request id "+b.id+"."+b.sends+" error "+c+" happened"),(0===c||c>=400&&600>c||c>=12e3)&&(this._hitError(c),c>=400&&500>c&&(this._conn._changeConnectStatus(Strophe.Status.DISCONNECTING,null),this._conn._doDisconnect()))),c>0&&500>c||b.sends>5||this._throttledRequestHandler()}},_processRequest:function(a){var b=this,c=this._requests[a],d=-1;try{4==c.xhr.readyState&&(d=c.xhr.status)}catch(e){Strophe.error("caught an error in _requests["+a+"], reqStatus: "+d)}if("undefined"==typeof d&&(d=-1),c.sends>this.maxRetries)return this._onDisconnectTimeout(),void 0;var f=c.age(),g=!isNaN(f)&&f>Math.floor(Strophe.TIMEOUT*this.wait),h=null!==c.dead&&c.timeDead()>Math.floor(Strophe.SECONDARY_TIMEOUT*this.wait),i=4==c.xhr.readyState&&(1>d||d>=500);if((g||h||i)&&(h&&Strophe.error("Request "+this._requests[a].id+" timed out (secondary), restarting"),c.abort=!0,c.xhr.abort(),c.xhr.onreadystatechange=function(){},this._requests[a]=new Strophe.Request(c.xmlData,c.origFunc,c.rid,c.sends),c=this._requests[a]),0===c.xhr.readyState){Strophe.debug("request id "+c.id+"."+c.sends+" posting");try{c.xhr.open("POST",this._conn.service,this._conn.options.sync?!1:!0)}catch(j){return Strophe.error("XHR open failed."),this._conn.connected||this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,"bad-service"),this._conn.disconnect(),void 0}var k=function(){if(c.date=new Date,b._conn.options.customHeaders){var a=b._conn.options.customHeaders;for(var d in a)a.hasOwnProperty(d)&&c.xhr.setRequestHeader(d,a[d])}c.xhr.send(c.data)};if(c.sends>1){var l=1e3*Math.min(Math.floor(Strophe.TIMEOUT*this.wait),Math.pow(c.sends,3));setTimeout(k,l)}else k();c.sends++,this._conn.xmlOutput!==Strophe.Connection.prototype.xmlOutput&&(c.xmlData.nodeName===this.strip&&c.xmlData.childNodes.length?this._conn.xmlOutput(c.xmlData.childNodes[0]):this._conn.xmlOutput(c.xmlData)),this._conn.rawOutput!==Strophe.Connection.prototype.rawOutput&&this._conn.rawOutput(c.data)}else Strophe.debug("_processRequest: "+(0===a?"first":"second")+" request has readyState of "+c.xhr.readyState)},_removeRequest:function(a){Strophe.debug("removing request");var b;for(b=this._requests.length-1;b>=0;b--)a==this._requests[b]&&this._requests.splice(b,1);a.xhr.onreadystatechange=function(){},this._throttledRequestHandler()},_restartRequest:function(a){var b=this._requests[a];null===b.dead&&(b.dead=new Date),this._processRequest(a)},_reqToData:function(a){try{return a.getResponse()}catch(b){if("parsererror"!=b)throw b;this._conn.disconnect("strophe-parsererror")}},_sendTerminate:function(a){Strophe.info("_sendTerminate was called");var b=this._buildBody().attrs({type:"terminate"});a&&b.cnode(a.tree());var c=new Strophe.Request(b.tree(),this._onRequestStateChange.bind(this,this._conn._dataRecv.bind(this._conn)),b.tree().getAttribute("rid"));this._requests.push(c),this._throttledRequestHandler()},_send:function(){clearTimeout(this._conn._idleTimeout),this._throttledRequestHandler(),this._conn._idleTimeout=setTimeout(this._conn._onIdle.bind(this._conn),100)},_sendRestart:function(){this._throttledRequestHandler(),clearTimeout(this._conn._idleTimeout)},_throttledRequestHandler:function(){this._requests?Strophe.debug("_throttledRequestHandler called with "+this._requests.length+" requests"):Strophe.debug("_throttledRequestHandler called with undefined requests"),this._requests&&0!==this._requests.length&&(this._requests.length>0&&this._processRequest(0),this._requests.length>1&&Math.abs(this._requests[0].rid-this._requests[1].rid)<this.window&&this._processRequest(1))}},Strophe.Websocket=function(a){this._conn=a,this.strip="stream:stream";var b=a.service;if(0!==b.indexOf("ws:")&&0!==b.indexOf("wss:")){var c="";c+="ws"===a.options.protocol&&"https:"!==window.location.protocol?"ws":"wss",c+="://"+window.location.host,c+=0!==b.indexOf("/")?window.location.pathname+b:b,a.service=c}},Strophe.Websocket.prototype={_buildStream:function(){return $build("stream:stream",{to:this._conn.domain,xmlns:Strophe.NS.CLIENT,"xmlns:stream":Strophe.NS.STREAM,version:"1.0"})},_check_streamerror:function(a,b){var c=a.getElementsByTagName("stream:error");if(0===c.length)return!1;for(var d=c[0],e="",f="",g="urn:ietf:params:xml:ns:xmpp-streams",h=0;h<d.childNodes.length;h++){var i=d.childNodes[h];if(i.getAttribute("xmlns")!==g)break;"text"===i.nodeName?f=i.textContent:e=i.nodeName}var j="WebSocket stream error: ";return j+=e?e:"unknown",f&&(j+=" - "+e),Strophe.error(j),this._conn._changeConnectStatus(b,e),this._conn._doDisconnect(),!0},_reset:function(){},_connect:function(){this._closeSocket(),this.socket=new WebSocket(this._conn.service,"xmpp"),this.socket.onopen=this._onOpen.bind(this),this.socket.onerror=this._onError.bind(this),this.socket.onclose=this._onClose.bind(this),this.socket.onmessage=this._connect_cb_wrapper.bind(this)},_connect_cb:function(a){var b=this._check_streamerror(a,Strophe.Status.CONNFAIL);return b?Strophe.Status.CONNFAIL:void 0},_handleStreamStart:function(a){var b=!1,c=a.getAttribute("xmlns");"string"!=typeof c?b="Missing xmlns in stream:stream":c!==Strophe.NS.CLIENT&&(b="Wrong xmlns in stream:stream: "+c);var d=a.namespaceURI;"string"!=typeof d?b="Missing xmlns:stream in stream:stream":d!==Strophe.NS.STREAM&&(b="Wrong xmlns:stream in stream:stream: "+d);var e=a.getAttribute("version");return"string"!=typeof e?b="Missing version in stream:stream":"1.0"!==e&&(b="Wrong version in stream:stream: "+e),b?(this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,b),this._conn._doDisconnect(),!1):!0},_connect_cb_wrapper:function(a){if(0===a.data.indexOf("<stream:stream ")||0===a.data.indexOf("<?xml")){var b=a.data.replace(/^(<\?.*?\?>\s*)*/,"");if(""===b)return;b=a.data.replace(/<stream:stream (.*[^\/])>/,"<stream:stream $1/>");var c=(new DOMParser).parseFromString(b,"text/xml").documentElement;this._conn.xmlInput(c),this._conn.rawInput(a.data),this._handleStreamStart(c)&&(this._connect_cb(c),this.streamStart=a.data.replace(/^<stream:(.*)\/>$/,"<stream:$1>"))}else{if("</stream:stream>"===a.data)return this._conn.rawInput(a.data),this._conn.xmlInput(document.createElement("stream:stream")),this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,"Received closing stream"),this._conn._doDisconnect(),void 0;var d=this._streamWrap(a.data),e=(new DOMParser).parseFromString(d,"text/xml").documentElement;this.socket.onmessage=this._onMessage.bind(this),this._conn._connect_cb(e,null,a.data)}},_disconnect:function(a){if(this.socket.readyState!==WebSocket.CLOSED){a&&this._conn.send(a);var b="</stream:stream>";this._conn.xmlOutput(document.createElement("stream:stream")),this._conn.rawOutput(b);try{this.socket.send(b)}catch(c){Strophe.info("Couldn't send closing stream tag.")}}this._conn._doDisconnect()},_doDisconnect:function(){Strophe.info("WebSockets _doDisconnect was called"),this._closeSocket()},_streamWrap:function(a){return this.streamStart+a+"</stream:stream>"},_closeSocket:function(){if(this.socket)try{this.socket.close()}catch(a){}this.socket=null},_emptyQueue:function(){return!0},_onClose:function(){this._conn.connected&&!this._conn.disconnecting?(Strophe.error("Websocket closed unexcectedly"),this._conn._doDisconnect()):Strophe.info("Websocket closed")},_no_auth_received:function(a){Strophe.error("Server did not send any auth methods"),this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,"Server did not send any auth methods"),a&&(a=a.bind(this._conn))(),this._conn._doDisconnect()},_onDisconnectTimeout:function(){},_onError:function(a){Strophe.error("Websocket error "+a),this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,"The WebSocket connection could not be established was disconnected."),this._disconnect()},_onIdle:function(){var a=this._conn._data;if(a.length>0&&!this._conn.paused){for(var b=0;b<a.length;b++)if(null!==a[b]){var c,d;"restart"===a[b]?(c=this._buildStream(),d=this._removeClosingTag(c),c=c.tree()):(c=a[b],d=Strophe.serialize(c)),this._conn.xmlOutput(c),this._conn.rawOutput(d),this.socket.send(d)}this._conn._data=[]}},_onMessage:function(a){var b,c;if("</stream:stream>"===a.data){var d="</stream:stream>";return this._conn.rawInput(d),this._conn.xmlInput(document.createElement("stream:stream")),this._conn.disconnecting||this._conn._doDisconnect(),void 0}if(0===a.data.search("<stream:stream ")){if(c=a.data.replace(/<stream:stream (.*[^\/])>/,"<stream:stream $1/>"),b=(new DOMParser).parseFromString(c,"text/xml").documentElement,!this._handleStreamStart(b))return}else c=this._streamWrap(a.data),b=(new DOMParser).parseFromString(c,"text/xml").documentElement;if(!this._check_streamerror(b,Strophe.Status.ERROR))return this._conn.disconnecting&&"presence"===b.firstChild.nodeName&&"unavailable"===b.firstChild.getAttribute("type")?(this._conn.xmlInput(b),this._conn.rawInput(Strophe.serialize(b)),void 0):(this._conn._dataRecv(b,a.data),void 0)},_onOpen:function(){Strophe.info("Websocket open");var a=this._buildStream();this._conn.xmlOutput(a.tree());var b=this._removeClosingTag(a);this._conn.rawOutput(b),this.socket.send(b)},_removeClosingTag:function(a){var b=Strophe.serialize(a);return b=b.replace(/<(stream:stream .*[^\/])\/>$/,"<$1>")},_reqToData:function(a){return a},_send:function(){this._conn.flush()},_sendRestart:function(){clearTimeout(this._conn._idleTimeout),this._conn._onIdle.bind(this._conn)()}};
          \ No newline at end of file
          diff --git a/public/javascripts/strophejs-1.1.3/tests/muc.html b/public/javascripts/strophejs-1.1.3/tests/muc.html
          new file mode 100644
          index 0000000..a1a5bad
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/tests/muc.html
          @@ -0,0 +1,28 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
          +                    "http://www.w3.org/TR/html4/loose.dtd">
          +<html>
          +<head>
          +  <script src="http://code.jquery.com/jquery-latest.js"></script>
          +  <script type="text/javascript" src="testrunner.js"></script>
          +  <script type="text/javascript" src="../strophe.js"></script>
          +  <script type="text/javascript" src="../plugins/strophe.muc.js"></script>
          +  <script type="text/javascript" src="muc.js"></script>
          +  <link rel="stylesheet" href="testsuite.css" type="text/css" media="screen" />
          +
          +  <script>
          +   Strophe.Test.run();
          +  </script>
          +  
          +</head>
          +<body>
          + <h1>QUnit tests for Strophe</h1>
          + <h2 id="userAgent"></h2>
          + <div><a style='display:none;' id="run_tests" href='#'>Run tests.</a>
          + <a sytle='display:none;' id="disconnect" href='#'>Disconnect.</a>
          + </div>
          + <div id="muc_item">
          + </div>
          + <ol id="tests"></ol>
          + <div id='main'></div> 
          +</body>
          +</html>
          diff --git a/public/javascripts/strophejs-1.1.3/tests/muc.js b/public/javascripts/strophejs-1.1.3/tests/muc.js
          new file mode 100644
          index 0000000..585a8d9
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/tests/muc.js
          @@ -0,0 +1,104 @@
          +
          +
          +Strophe.Test = {
          +    BOSH_URL: "/xmpp-httpbind",
          +    XMPP_DOMAIN: 'speeqe.com',
          +    room_name: 'speeqers@chat.speeqe.com',
          +    connection: null, //connection object created in run function
          +    
          +    run: function() {
          +	$(document).ready(function(){
          +	    //Connect strophe, uses localhost to test
          +	    Strophe.Test.connection =
          +                new Strophe.Connection(Strophe.Test.BOSH_URL);
          +	    
          +	    //connect anonymously to run most tests
          +	    Strophe.Test.connection.connect(Strophe.Test.XMPP_DOMAIN,
          +                                            null,
          +			                    Strophe.Test.connectCallback);
          +
          +	    //set up the test client UI
          +	    $("#disconnect").click(function() {
          +		Strophe.Test.connection.disconnect();
          +	    });
          +	    $("#run_tests").click(function() {      
          +		test("Anonymous connection test.", function() {
          +		    if(Strophe.Test.connection.connected)
          +		    {
          +			ok( true, "all good");
          +		    }
          +		    else
          +		    {
          +			ok( false, "not connected anonymously");
          +		    }
          +		});
          +		test("join a room test",function() {
          +                    Strophe.Test.connection.muc.join(Strophe.Test.room_name,
          +                                                     "testnick",
          +                                                     function(msg) {
          +                                                         $('#muc_item').append($(msg).text());
          +                                                     },
          +                                                     function(pres) {
          +                                                         $('#muc_item').append($(pres).text());
          +                                                     });
          +		    ok(true,
          +		       "joined " + Strophe.Test.room_name);
          +                    
          +		});
          +		test("send a message", function() {
          +                    Strophe.Test.connection.muc.message(Strophe.Test.room_name,
          +                                                        "testnick",
          +                                                        "test message");
          +                });
          +                test("configure room", function() {
          +                    Strophe.Test
          +                        .connection.muc.configure(Strophe.Test.room_name);
          +                    Strophe.Test
          +                        .connection.muc.cancelConfigure(Strophe.Test.room_name);
          +                });
          +		test("leave a room test", function() {
          +                    var iqid = Strophe.Test
          +                        .connection.muc.leave(Strophe.Test.room_name,
          +                                              "testnick",
          +                                              function() {
          +                                                  $('#muc_item').append("left room "+
          +                                                                        Strophe.Test.room_name);
          +                                              });
          +		    if(iqid)
          +			ok(true,
          +			   "left room");
          +		});
          +	    });
          +	});
          +    },
          +
          +    connectCallback: function(status,cond) {
          +	var error_message = null;
          +	if(status == Strophe.Status.CONNECTED)
          +	{
          +	    $('#run_tests').show();
          +	    $('#disconnect').show();
          +	    var bare_jid =
          +                Strophe.getBareJidFromJid(Strophe.Test.connection.jid)
          +                .split("@")[0];
          +	}
          +	else if (status == Strophe.Status.DISCONNECTED || status == Strophe.Status.DICONNECTING)
          +	{
          +	    $('#run_tests').hide();
          +	    $('#disconnect').hide();
          +	}	
          +	else if ((status == 0) || (status == Strophe.Status.CONNFAIL))
          +	{
          +	    error_message = "Failed to connect to xmpp server.";
          +	}
          +	else if (status == Strophe.Status.AUTHFAIL)
          +	{
          +	    error_message = "Failed to authenticate to xmpp server.";
          +	}
          +	if(error_message)
          +	{
          +	    $('muc_item').text(error_message);
          +	    
          +	}
          +    }
          +};
          diff --git a/public/javascripts/strophejs-1.1.3/tests/pubsub.html b/public/javascripts/strophejs-1.1.3/tests/pubsub.html
          new file mode 100644
          index 0000000..42b8259
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/tests/pubsub.html
          @@ -0,0 +1,28 @@
          +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
          +                    "http://www.w3.org/TR/html4/loose.dtd">
          +<html>
          +<head>
          +  <script src="http://code.jquery.com/jquery-latest.js"></script>
          +  <script type="text/javascript" src="testrunner.js"></script>
          +  <script type="text/javascript" src="../strophe.js"></script>
          +  <script type="text/javascript" src="../plugins/strophe.pubsub.js"></script>
          +  <script type="text/javascript" src="pubsub.js"></script>
          +  <link rel="stylesheet" href="testsuite.css" type="text/css" media="screen" />
          +
          +  <script>
          +   Strophe.Test.run();
          +  </script>
          +  
          +</head>
          +<body>
          + <h1>QUnit tests for Strophe</h1>
          + <h2 id="userAgent"></h2>
          + <div><a style='display:none;' id="run_tests" href='#'>Run tests.</a>
          + <a sytle='display:none;' id="disconnect" href='#'>Disconnect.</a>
          + </div>
          + <div id="published_item">
          + </div>
          + <ol id="tests"></ol>
          + <div id='main'></div> 
          +</body>
          +</html>
          diff --git a/public/javascripts/strophejs-1.1.3/tests/pubsub.js b/public/javascripts/strophejs-1.1.3/tests/pubsub.js
          new file mode 100644
          index 0000000..50ce2de
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/tests/pubsub.js
          @@ -0,0 +1,314 @@
          +
          +
          +Strophe.Test = {
          +    BOSH_URL: "/xmpp-httpbind",
          +    XMPP_DOMAIN: 'localhost',
          +    PUBSUB_COMPONENT: "pubsub.localhost",
          +    _node_name: "", //node name created in connectCallback function
          +    connection: null, //connection object created in run function
          +    
          +    run: function() {
          +	$(document).ready(function(){
          +	    //Connect strophe, uses localhost to test
          +	    Strophe.Test.connection = new Strophe.Connection(Strophe.Test.BOSH_URL);
          +	    
          +	    //connect anonymously to run most tests
          +	    Strophe.Test.connection.connect(Strophe.Test.XMPP_DOMAIN,
          +                                            null,
          +			                    Strophe.Test.connectCallback);
          +
          +	    //set up the test client UI
          +	    $("#disconnect").click(function() {
          +		Strophe.Test.connection.disconnect();
          +	    });
          +	    $("#run_tests").click(function() {      
          +		test("Anonymous connection test.", function() {
          +		    if(Strophe.Test.connection.connected)
          +		    {
          +			ok( true, "all good");
          +		    }
          +		    else
          +		    {
          +			ok( false, "not connected anonymously");
          +		    }
          +		});
          +
          +		test("Create default node test.",function(){
          +		    var iqid =  Strophe.Test.connection.pubsub
          +                        .createNode(Strophe.Test.connection.jid,
          +				    Strophe.Test.PUBSUB_COMPONENT,
          +				    Strophe.Test._node_name, {}, 
          +                                    function(stanza) {
          +			                test("handled create node.",
          +				             function() {
          +				                 var error = $(stanza).find("error");
          +				                 
          +				                 if(error.length == 0)
          +				                 {
          +					             ok(true, "returned");
          +				                 }
          +				                 else
          +				                 {
          +					             ok(false,"error creating node.");
          +				                 }
          +				             });
          +				    });
          +		    ok(true,"sent create request. "+ iqid);
          +		});
          +
          +		test("subscribe to a node",function() {
          +		    var iqid = Strophe.Test.connection.pubsub
          +                        .subscribe(Strophe.Test.connection.jid,
          +				   Strophe.Test.PUBSUB_COMPONENT,
          +				   Strophe.Test._node_name,
          +				   [],
          +			           function(stanza) {
          +			               test("items received", function() {
          +				           console.log(stanza);
          +				           if($(stanza).length > 0)
          +				           {
          +				               ok(true,"item received.");
          +				           }
          +				           else
          +				           {
          +				               ok(false,"no items.");
          +				           }
          +			               });
          +			           },
          +			           function(stanza) {
          +			               var error = $(stanza).find("error");
          +			               
          +			               test("handled subscribe",
          +				            function() {
          +				                if(error.length == 0)
          +				                {
          +					            ok(true,"subscribed");
          +				                }
          +				                else
          +				                {
          +					            console.log(error.get(0));
          +					            ok(false,
          +					               "not subscribed");
          +				                }
          +				                
          +			                    });
          +			           });
          +		    
          +		    if(iqid)
          +			ok(true,
          +			   "subscribed to " + Strophe.Test._node_name);
          +		});
          +
          +		test("publish to a node",function() {
          +		    var iqid = Strophe.Test.connection.pubsub
          +                        .publish(Strophe.Test.connection.jid,
          +				 Strophe.Test.PUBSUB_COMPONENT,
          +				 Strophe.Test._node_name,
          +			         {test:'test'},
          +				 function(stanza) {
          +				     var error = $(stanza).find("error");
          +				     
          +				     test("handled published item",
          +					  function() {
          +					      if(error.length == 0)
          +					      {
          +						  ok(true,"got item");
          +					      }
          +					      else
          +					      {
          +						  ok(false,
          +						     "no item");
          +					      }
          +					      
          +					  });
          +				 });
          +		    
          +		    if(iqid)
          +			ok(true,
          +			   "published to " + Strophe.Test._node_name);
          +                    
          +		});		
          +
          +		test("subscribe to a node with options",function() {
          +		    var keyword_elem = Strophe.xmlElement("field",
          +							  [["var",
          +							    "http://stanziq.com/search#keyword"],
          +							   ["type",
          +							    'text-single'],
          +							   ["label",
          +							    "keyword to match"]]);
          +		    var value = Strophe.xmlElement("value",[]);
          +		    var text = Strophe.xmlTextNode("crazy");
          +		    value.appendChild(text);
          +		    keyword_elem.appendChild(value);
          +		    
          +		    var iqid = Strophe.Test.connection.pubsub
          +                        .subscribe(Strophe.Test.connection.jid,
          +				   Strophe.Test.PUBSUB_COMPONENT,
          +				   Strophe.Test._node_name,
          +			           [keyword_elem],
          +		                   function(stanza) {console.log(stanza);},
          +			           function(stanza) {
          +			               
          +			               var error = $(stanza).find("error");
          +			               
          +			               test("handled subscribe with options",
          +				            function() {
          +				                if(error.length == 0)
          +				                {
          +					            ok(true,"search subscribed");
          +				                }
          +				                else
          +				                {
          +					            console.log(error.get(0));
          +					            ok(false,
          +					               "search not subscribed");
          +				                }
          +				                
          +			                    });
          +			           });
          +		    
          +		    if(iqid)
          +			ok(true,
          +			   "subscribed to search");
          +		});
          +
          +		test("unsubscribe to a node",function() {
          +		    var iqid = Strophe.Test.connection.pubsub
          +                        .unsubscribe(Strophe.Test.connection.jid,
          +				     Strophe.Test.PUBSUB_COMPONENT,
          +				     Strophe.Test._node_name,
          +		                     function(stanza) {
          +			                 var error = $(stanza).find("error");
          +			                 
          +			                 test("handled unsubscribe",
          +				              function() {
          +			                          if(error.length == 0)
          +				                  {
          +				                      ok(true,"unsubscribed");
          +				                  }
          +			                          else
          +				                  {
          +				                      console.log(error.get(0));
          +				                      ok(false,
          +					                 "unable to unsubscribed");
          +				                  }
          +			                      });
          +		                     });
          +		    
          +		    if(iqid)
          +			ok(true,
          +			   "unsubscribed from search with no options.");
          +		});
          +
          +		test("test items retrieval",function(){
          +		    var itemid = Strophe.Test.connection.pubsub
          +                        .items(Strophe.Test.connection.jid,
          +			       Strophe.Test.PUBSUB_COMPONENT,
          +			       Strophe.Test._node_name,
          +			       function(stanza) {
          +				   ok(true,"item request successful.");
          +			       },
          +			       function(stanza) {
          +				   ok(false,"failed to send request.");
          +			       });
          +                    
          +		    if(itemid)
          +		    {
          +			ok(true,"item request sent.");
          +		    }
          +		});
          +
          +		test("test sendIQ interface.",function(){
          +		    var sendiq_good = false;
          +		    //setup timeout for sendIQ for 3 seconds
          +		    setTimeout(function() {
          +                        test("Timeout check", function () {
          +			    ok(sendiq_good, "The iq didn't timeout.");
          +                        });
          +		    }, 3000);
          +                    
          +		    //send a pubsub subscribe stanza
          +                    
          +		    var sub = $iq({from:Strophe.Test.connection.jid,
          +			           to:Strophe.Test.PUBSUB_COMPONENT,
          +			           type:'set'})
          +		        .c('pubsub', { xmlns:Strophe.NS.PUBSUB })
          +                        .c('subscribe',
          +		           {node:Strophe.Test._node_name,
          +			    jid:Strophe.Test.connection.jid});
          +		    var stanza=sub.tree();
          +		    //call sendIQ with several call backs
          +		    Strophe.Test.connection
          +                        .sendIQ(stanza, 
          +                                function(stanza) {
          +			            test("iq sent",function() {
          +			                sendiq_good = true;
          +			                ok(true,"iq sent succesfully.");
          +			            });
          +		                },
          +		                function(stz) {
          +			            test("iq fail",function() {
          +                                        if (stz)
          +			                    sendiq_good = true;
          +			                console.log(stanza);
          +			                ok(true,"failed to send iq.");
          +			            });
          +		                });
          +		});
          +
          +		test("test sendIQ failed.",function(){
          +		    var sub = $iq({from:Strophe.Test.connection.jid, 
          +			           to:Strophe.Test.PUBSUB_COMPONENT, 
          +			           type:'get'});
          +
          +		    //call sendIQ with several call backs
          +		    Strophe.Test.connection
          +                        .sendIQ(sub.tree(),
          +		                function(stanza) {
          +			            console.log(stanza);
          +			            test("iq sent",function() {
          +			                ok(false,
          +			                   "iq sent succesfully when should have failed.");
          +			            });
          +		                },
          +		                function(stanza) {
          +			            test("iq fail",function() {
          +			                ok(true,
          +			                   "success on failure test: failed to send iq.");
          +			            });
          +		                });		    
          +		});
          +	    });
          +	});
          +    },
          +
          +    connectCallback: function(status,cond) {
          +	var error_message = null;
          +	if(status == Strophe.Status.CONNECTED)
          +	{
          +	    $('#run_tests').show();
          +	    $('#disconnect').show();
          +	    var bare_jid = Strophe.getBareJidFromJid(Strophe.Test.connection.jid).split("@")[0];
          +	    Strophe.Test._node_name = "/home/"+Strophe.Test.XMPP_DOMAIN+"/"+bare_jid;
          +	}
          +	else if (status == Strophe.Status.DISCONNECTED || status == Strophe.Status.DICONNECTING)
          +	{
          +	    $('#run_tests').hide();
          +	    $('#disconnect').hide();
          +	}	
          +	else if ((status == 0) || (status == Strophe.Status.CONNFAIL))
          +	{
          +	    error_message = "Failed to connect to xmpp server.";
          +	}
          +	else if (status == Strophe.Status.AUTHFAIL)
          +	{
          +	    error_message = "Failed to authenticate to xmpp server.";
          +	}
          +	if(error_message)
          +	{
          +	    $('published_item').text(error_message);
          +	    
          +	}
          +    }
          +};
          diff --git a/public/javascripts/strophejs-1.1.3/tests/strophe.html b/public/javascripts/strophejs-1.1.3/tests/strophe.html
          new file mode 100644
          index 0000000..513e214
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/tests/strophe.html
          @@ -0,0 +1,30 @@
          +<!DOCTYPE html>
          +<html>
          +  <head>
          +    <script>
          +      <!--
          +          // remove Function.prototype.bind so we can test Strophe's
          +          Function.prototype.bind = undefined;
          +          // -->
          +    </script>
          +
          +    <script src="http://code.jquery.com/jquery-latest.js"></script>
          +    <link rel="stylesheet"
          +          href="http://code.jquery.com/qunit/qunit-git.css"
          +          type="text/css">
          +    <script src="http://code.jquery.com/qunit/qunit-git.js"></script>
          +    <script src="http://cjohansen.no/sinon/releases/sinon-0.8.0.js"></script>
          +    <script src="http://cjohansen.no/sinon/releases/sinon-qunit-0.8.0.js"></script>
          +    <script src='../strophe.js'></script>
          +    <script src='tests.js'></script>
          +    
          +    <title>Strophe.js Tests</title>
          +  </head>
          +  <body>
          +    <h1 id="qunit-header">Strophe.js Tests</h1>
          +    <h2 id="qunit-banner"></h2>
          +    <h2 id="qunit-userAgent"></h2>
          +    <ol id="qunit-tests"></ol>
          +    <div id="main"></div>
          +  </body>
          +</html>
          diff --git a/public/javascripts/strophejs-1.1.3/tests/strophe.js b/public/javascripts/strophejs-1.1.3/tests/strophe.js
          new file mode 100644
          index 0000000..f1d50ae
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/tests/strophe.js
          @@ -0,0 +1,5139 @@
          +// This code was written by Tyler Akins and has been placed in the
          +// public domain.  It would be nice if you left this header intact.
          +// Base64 code from Tyler Akins -- http://rumkin.com
          +
          +var Base64 = (function () {
          +    var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
          +
          +    var obj = {
          +        /**
          +         * Encodes a string in base64
          +         * @param {String} input The string to encode in base64.
          +         */
          +        encode: function (input) {
          +            var output = "";
          +            var chr1, chr2, chr3;
          +            var enc1, enc2, enc3, enc4;
          +            var i = 0;
          +
          +            do {
          +                chr1 = input.charCodeAt(i++);
          +                chr2 = input.charCodeAt(i++);
          +                chr3 = input.charCodeAt(i++);
          +
          +                enc1 = chr1 >> 2;
          +                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
          +                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
          +                enc4 = chr3 & 63;
          +
          +                if (isNaN(chr2)) {
          +                    enc3 = enc4 = 64;
          +                } else if (isNaN(chr3)) {
          +                    enc4 = 64;
          +                }
          +
          +                output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) +
          +                    keyStr.charAt(enc3) + keyStr.charAt(enc4);
          +            } while (i < input.length);
          +
          +            return output;
          +        },
          +
          +        /**
          +         * Decodes a base64 string.
          +         * @param {String} input The string to decode.
          +         */
          +        decode: function (input) {
          +            var output = "";
          +            var chr1, chr2, chr3;
          +            var enc1, enc2, enc3, enc4;
          +            var i = 0;
          +
          +            // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
          +            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
          +
          +            do {
          +                enc1 = keyStr.indexOf(input.charAt(i++));
          +                enc2 = keyStr.indexOf(input.charAt(i++));
          +                enc3 = keyStr.indexOf(input.charAt(i++));
          +                enc4 = keyStr.indexOf(input.charAt(i++));
          +
          +                chr1 = (enc1 << 2) | (enc2 >> 4);
          +                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
          +                chr3 = ((enc3 & 3) << 6) | enc4;
          +
          +                output = output + String.fromCharCode(chr1);
          +
          +                if (enc3 != 64) {
          +                    output = output + String.fromCharCode(chr2);
          +                }
          +                if (enc4 != 64) {
          +                    output = output + String.fromCharCode(chr3);
          +                }
          +            } while (i < input.length);
          +
          +            return output;
          +        }
          +    };
          +
          +    return obj;
          +})();
          +
          +/*
          + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
          + * in FIPS PUB 180-1
          + * Version 2.1a Copyright Paul Johnston 2000 - 2002.
          + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
          + * Distributed under the BSD License
          + * See http://pajhome.org.uk/crypt/md5 for details.
          + */
          +
          +/* Some functions and variables have been stripped for use with Strophe */
          +
          +/*
          + * These are the functions you'll usually want to call
          + * They take string arguments and return either hex or base-64 encoded strings
          + */
          +function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * 8));}
          +function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * 8));}
          +function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
          +function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}
          +
          +/*
          + * Calculate the SHA-1 of an array of big-endian words, and a bit length
          + */
          +function core_sha1(x, len)
          +{
          +  /* append padding */
          +  x[len >> 5] |= 0x80 << (24 - len % 32);
          +  x[((len + 64 >> 9) << 4) + 15] = len;
          +
          +  var w = new Array(80);
          +  var a =  1732584193;
          +  var b = -271733879;
          +  var c = -1732584194;
          +  var d =  271733878;
          +  var e = -1009589776;
          +
          +  var i, j, t, olda, oldb, oldc, oldd, olde;
          +  for (i = 0; i < x.length; i += 16)
          +  {
          +    olda = a;
          +    oldb = b;
          +    oldc = c;
          +    oldd = d;
          +    olde = e;
          +
          +    for (j = 0; j < 80; j++)
          +    {
          +      if (j < 16) { w[j] = x[i + j]; }
          +      else { w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); }
          +      t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
          +                       safe_add(safe_add(e, w[j]), sha1_kt(j)));
          +      e = d;
          +      d = c;
          +      c = rol(b, 30);
          +      b = a;
          +      a = t;
          +    }
          +
          +    a = safe_add(a, olda);
          +    b = safe_add(b, oldb);
          +    c = safe_add(c, oldc);
          +    d = safe_add(d, oldd);
          +    e = safe_add(e, olde);
          +  }
          +  return [a, b, c, d, e];
          +}
          +
          +/*
          + * Perform the appropriate triplet combination function for the current
          + * iteration
          + */
          +function sha1_ft(t, b, c, d)
          +{
          +  if (t < 20) { return (b & c) | ((~b) & d); }
          +  if (t < 40) { return b ^ c ^ d; }
          +  if (t < 60) { return (b & c) | (b & d) | (c & d); }
          +  return b ^ c ^ d;
          +}
          +
          +/*
          + * Determine the appropriate additive constant for the current iteration
          + */
          +function sha1_kt(t)
          +{
          +  return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 :
          +         (t < 60) ? -1894007588 : -899497514;
          +}
          +
          +/*
          + * Calculate the HMAC-SHA1 of a key and some data
          + */
          +function core_hmac_sha1(key, data)
          +{
          +  var bkey = str2binb(key);
          +  if (bkey.length > 16) { bkey = core_sha1(bkey, key.length * 8); }
          +
          +  var ipad = new Array(16), opad = new Array(16);
          +  for (var i = 0; i < 16; i++)
          +  {
          +    ipad[i] = bkey[i] ^ 0x36363636;
          +    opad[i] = bkey[i] ^ 0x5C5C5C5C;
          +  }
          +
          +  var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * 8);
          +  return core_sha1(opad.concat(hash), 512 + 160);
          +}
          +
          +/*
          + * Add integers, wrapping at 2^32. This uses 16-bit operations internally
          + * to work around bugs in some JS interpreters.
          + */
          +function safe_add(x, y)
          +{
          +  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
          +  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
          +  return (msw << 16) | (lsw & 0xFFFF);
          +}
          +
          +/*
          + * Bitwise rotate a 32-bit number to the left.
          + */
          +function rol(num, cnt)
          +{
          +  return (num << cnt) | (num >>> (32 - cnt));
          +}
          +
          +/*
          + * Convert an 8-bit or 16-bit string to an array of big-endian words
          + * In 8-bit function, characters >255 have their hi-byte silently ignored.
          + */
          +function str2binb(str)
          +{
          +  var bin = [];
          +  var mask = 255;
          +  for (var i = 0; i < str.length * 8; i += 8)
          +  {
          +    bin[i>>5] |= (str.charCodeAt(i / 8) & mask) << (24 - i%32);
          +  }
          +  return bin;
          +}
          +
          +/*
          + * Convert an array of big-endian words to a string
          + */
          +function binb2str(bin)
          +{
          +  var str = "";
          +  var mask = 255;
          +  for (var i = 0; i < bin.length * 32; i += 8)
          +  {
          +    str += String.fromCharCode((bin[i>>5] >>> (24 - i%32)) & mask);
          +  }
          +  return str;
          +}
          +
          +/*
          + * Convert an array of big-endian words to a base-64 string
          + */
          +function binb2b64(binarray)
          +{
          +  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
          +  var str = "";
          +  var triplet, j;
          +  for (var i = 0; i < binarray.length * 4; i += 3)
          +  {
          +    triplet = (((binarray[i   >> 2] >> 8 * (3 -  i   %4)) & 0xFF) << 16) |
          +              (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) |
          +               ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
          +    for (j = 0; j < 4; j++)
          +    {
          +      if (i * 8 + j * 6 > binarray.length * 32) { str += "="; }
          +      else { str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); }
          +    }
          +  }
          +  return str;
          +}
          +
          +/*
          + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
          + * Digest Algorithm, as defined in RFC 1321.
          + * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
          + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
          + * Distributed under the BSD License
          + * See http://pajhome.org.uk/crypt/md5 for more info.
          + */
          +
          +/*
          + * Everything that isn't used by Strophe has been stripped here!
          + */
          +
          +var MD5 = (function () {
          +    /*
          +     * Add integers, wrapping at 2^32. This uses 16-bit operations internally
          +     * to work around bugs in some JS interpreters.
          +     */
          +    var safe_add = function (x, y) {
          +        var lsw = (x & 0xFFFF) + (y & 0xFFFF);
          +        var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
          +        return (msw << 16) | (lsw & 0xFFFF);
          +    };
          +
          +    /*
          +     * Bitwise rotate a 32-bit number to the left.
          +     */
          +    var bit_rol = function (num, cnt) {
          +        return (num << cnt) | (num >>> (32 - cnt));
          +    };
          +
          +    /*
          +     * Convert a string to an array of little-endian words
          +     */
          +    var str2binl = function (str) {
          +        var bin = [];
          +        for(var i = 0; i < str.length * 8; i += 8)
          +        {
          +            bin[i>>5] |= (str.charCodeAt(i / 8) & 255) << (i%32);
          +        }
          +        return bin;
          +    };
          +
          +    /*
          +     * Convert an array of little-endian words to a string
          +     */
          +    var binl2str = function (bin) {
          +        var str = "";
          +        for(var i = 0; i < bin.length * 32; i += 8)
          +        {
          +            str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & 255);
          +        }
          +        return str;
          +    };
          +
          +    /*
          +     * Convert an array of little-endian words to a hex string.
          +     */
          +    var binl2hex = function (binarray) {
          +        var hex_tab = "0123456789abcdef";
          +        var str = "";
          +        for(var i = 0; i < binarray.length * 4; i++)
          +        {
          +            str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
          +                hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
          +        }
          +        return str;
          +    };
          +
          +    /*
          +     * These functions implement the four basic operations the algorithm uses.
          +     */
          +    var md5_cmn = function (q, a, b, x, s, t) {
          +        return safe_add(bit_rol(safe_add(safe_add(a, q),safe_add(x, t)), s),b);
          +    };
          +
          +    var md5_ff = function (a, b, c, d, x, s, t) {
          +        return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
          +    };
          +
          +    var md5_gg = function (a, b, c, d, x, s, t) {
          +        return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
          +    };
          +
          +    var md5_hh = function (a, b, c, d, x, s, t) {
          +        return md5_cmn(b ^ c ^ d, a, b, x, s, t);
          +    };
          +
          +    var md5_ii = function (a, b, c, d, x, s, t) {
          +        return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
          +    };
          +
          +    /*
          +     * Calculate the MD5 of an array of little-endian words, and a bit length
          +     */
          +    var core_md5 = function (x, len) {
          +        /* append padding */
          +        x[len >> 5] |= 0x80 << ((len) % 32);
          +        x[(((len + 64) >>> 9) << 4) + 14] = len;
          +
          +        var a =  1732584193;
          +        var b = -271733879;
          +        var c = -1732584194;
          +        var d =  271733878;
          +
          +        var olda, oldb, oldc, oldd;
          +        for (var i = 0; i < x.length; i += 16)
          +        {
          +            olda = a;
          +            oldb = b;
          +            oldc = c;
          +            oldd = d;
          +
          +            a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
          +            d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
          +            c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
          +            b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
          +            a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
          +            d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
          +            c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
          +            b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
          +            a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
          +            d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
          +            c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
          +            b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
          +            a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
          +            d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
          +            c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
          +            b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);
          +
          +            a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
          +            d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
          +            c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
          +            b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
          +            a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
          +            d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
          +            c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
          +            b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
          +            a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
          +            d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
          +            c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
          +            b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
          +            a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
          +            d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
          +            c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
          +            b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
          +
          +            a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
          +            d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
          +            c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
          +            b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
          +            a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
          +            d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
          +            c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
          +            b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
          +            a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
          +            d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
          +            c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
          +            b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
          +            a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
          +            d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
          +            c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
          +            b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
          +
          +            a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
          +            d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
          +            c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
          +            b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
          +            a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
          +            d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
          +            c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
          +            b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
          +            a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
          +            d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
          +            c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
          +            b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
          +            a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
          +            d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
          +            c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
          +            b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
          +
          +            a = safe_add(a, olda);
          +            b = safe_add(b, oldb);
          +            c = safe_add(c, oldc);
          +            d = safe_add(d, oldd);
          +        }
          +        return [a, b, c, d];
          +    };
          +
          +
          +    var obj = {
          +        /*
          +         * These are the functions you'll usually want to call.
          +         * They take string arguments and return either hex or base-64 encoded
          +         * strings.
          +         */
          +        hexdigest: function (s) {
          +            return binl2hex(core_md5(str2binl(s), s.length * 8));
          +        },
          +
          +        hash: function (s) {
          +            return binl2str(core_md5(str2binl(s), s.length * 8));
          +        }
          +    };
          +
          +    return obj;
          +})();
          +
          +/*
          +    This program is distributed under the terms of the MIT license.
          +    Please see the LICENSE file for details.
          +
          +    Copyright 2006-2008, OGG, LLC
          +*/
          +
          +/* jshint undef: true, unused: true:, noarg: true, latedef: true */
          +/*global document, window, setTimeout, clearTimeout, console,
          +    ActiveXObject, Base64, MD5, DOMParser */
          +// from sha1.js
          +/*global core_hmac_sha1, binb2str, str_hmac_sha1, str_sha1, b64_hmac_sha1*/
          +
          +/** File: strophe.js
          + *  A JavaScript library for XMPP BOSH/XMPP over Websocket.
          + *
          + *  This is the JavaScript version of the Strophe library.  Since JavaScript
          + *  had no facilities for persistent TCP connections, this library uses
          + *  Bidirectional-streams Over Synchronous HTTP (BOSH) to emulate
          + *  a persistent, stateful, two-way connection to an XMPP server.  More
          + *  information on BOSH can be found in XEP 124.
          + *
          + *  This version of Strophe also works with WebSockets.
          + *  For more information on XMPP-over WebSocket see this RFC draft:
          + *  http://tools.ietf.org/html/draft-ietf-xmpp-websocket-00
          + */
          +
          +/** PrivateFunction: Function.prototype.bind
          + *  Bind a function to an instance.
          + *
          + *  This Function object extension method creates a bound method similar
          + *  to those in Python.  This means that the 'this' object will point
          + *  to the instance you want.  See
          + *  <a href='https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind'>MDC's bind() documentation</a> and
          + *  <a href='http://benjamin.smedbergs.us/blog/2007-01-03/bound-functions-and-function-imports-in-javascript/'>Bound Functions and Function Imports in JavaScript</a>
          + *  for a complete explanation.
          + *
          + *  This extension already exists in some browsers (namely, Firefox 3), but
          + *  we provide it to support those that don't.
          + *
          + *  Parameters:
          + *    (Object) obj - The object that will become 'this' in the bound function.
          + *    (Object) argN - An option argument that will be prepended to the
          + *      arguments given for the function call
          + *
          + *  Returns:
          + *    The bound function.
          + */
          +if (!Function.prototype.bind) {
          +    Function.prototype.bind = function (obj /*, arg1, arg2, ... */)
          +    {
          +        var func = this;
          +        var _slice = Array.prototype.slice;
          +        var _concat = Array.prototype.concat;
          +        var _args = _slice.call(arguments, 1);
          +
          +        return function () {
          +            return func.apply(obj ? obj : this,
          +                              _concat.call(_args,
          +                                           _slice.call(arguments, 0)));
          +        };
          +    };
          +}
          +
          +/** PrivateFunction: Array.prototype.indexOf
          + *  Return the index of an object in an array.
          + *
          + *  This function is not supplied by some JavaScript implementations, so
          + *  we provide it if it is missing.  This code is from:
          + *  http://developer.mozilla.org/En/Core_JavaScript_1.5_Reference:Objects:Array:indexOf
          + *
          + *  Parameters:
          + *    (Object) elt - The object to look for.
          + *    (Integer) from - The index from which to start looking. (optional).
          + *
          + *  Returns:
          + *    The index of elt in the array or -1 if not found.
          + */
          +if (!Array.prototype.indexOf)
          +{
          +    Array.prototype.indexOf = function(elt /*, from*/)
          +    {
          +        var len = this.length;
          +
          +        var from = Number(arguments[1]) || 0;
          +        from = (from < 0) ? Math.ceil(from) : Math.floor(from);
          +        if (from < 0) {
          +            from += len;
          +        }
          +
          +        for (; from < len; from++) {
          +            if (from in this && this[from] === elt) {
          +                return from;
          +            }
          +        }
          +
          +        return -1;
          +    };
          +}
          +
          +/* All of the Strophe globals are defined in this special function below so
          + * that references to the globals become closures.  This will ensure that
          + * on page reload, these references will still be available to callbacks
          + * that are still executing.
          + */
          +
          +(function (callback) {
          +var Strophe;
          +
          +/** Function: $build
          + *  Create a Strophe.Builder.
          + *  This is an alias for 'new Strophe.Builder(name, attrs)'.
          + *
          + *  Parameters:
          + *    (String) name - The root element name.
          + *    (Object) attrs - The attributes for the root element in object notation.
          + *
          + *  Returns:
          + *    A new Strophe.Builder object.
          + */
          +function $build(name, attrs) { return new Strophe.Builder(name, attrs); }
          +/** Function: $msg
          + *  Create a Strophe.Builder with a <message/> element as the root.
          + *
          + *  Parmaeters:
          + *    (Object) attrs - The <message/> element attributes in object notation.
          + *
          + *  Returns:
          + *    A new Strophe.Builder object.
          + */
          +function $msg(attrs) { return new Strophe.Builder("message", attrs); }
          +/** Function: $iq
          + *  Create a Strophe.Builder with an <iq/> element as the root.
          + *
          + *  Parameters:
          + *    (Object) attrs - The <iq/> element attributes in object notation.
          + *
          + *  Returns:
          + *    A new Strophe.Builder object.
          + */
          +function $iq(attrs) { return new Strophe.Builder("iq", attrs); }
          +/** Function: $pres
          + *  Create a Strophe.Builder with a <presence/> element as the root.
          + *
          + *  Parameters:
          + *    (Object) attrs - The <presence/> element attributes in object notation.
          + *
          + *  Returns:
          + *    A new Strophe.Builder object.
          + */
          +function $pres(attrs) { return new Strophe.Builder("presence", attrs); }
          +
          +/** Class: Strophe
          + *  An object container for all Strophe library functions.
          + *
          + *  This class is just a container for all the objects and constants
          + *  used in the library.  It is not meant to be instantiated, but to
          + *  provide a namespace for library objects, constants, and functions.
          + */
          +Strophe = {
          +    /** Constant: VERSION
          +     *  The version of the Strophe library. Unreleased builds will have
          +     *  a version of head-HASH where HASH is a partial revision.
          +     */
          +    VERSION: "1.1.3",
          +
          +    /** Constants: XMPP Namespace Constants
          +     *  Common namespace constants from the XMPP RFCs and XEPs.
          +     *
          +     *  NS.HTTPBIND - HTTP BIND namespace from XEP 124.
          +     *  NS.BOSH - BOSH namespace from XEP 206.
          +     *  NS.CLIENT - Main XMPP client namespace.
          +     *  NS.AUTH - Legacy authentication namespace.
          +     *  NS.ROSTER - Roster operations namespace.
          +     *  NS.PROFILE - Profile namespace.
          +     *  NS.DISCO_INFO - Service discovery info namespace from XEP 30.
          +     *  NS.DISCO_ITEMS - Service discovery items namespace from XEP 30.
          +     *  NS.MUC - Multi-User Chat namespace from XEP 45.
          +     *  NS.SASL - XMPP SASL namespace from RFC 3920.
          +     *  NS.STREAM - XMPP Streams namespace from RFC 3920.
          +     *  NS.BIND - XMPP Binding namespace from RFC 3920.
          +     *  NS.SESSION - XMPP Session namespace from RFC 3920.
          +     *  NS.XHTML_IM - XHTML-IM namespace from XEP 71.
          +     *  NS.XHTML - XHTML body namespace from XEP 71.
          +     */
          +    NS: {
          +        HTTPBIND: "http://jabber.org/protocol/httpbind",
          +        BOSH: "urn:xmpp:xbosh",
          +        CLIENT: "jabber:client",
          +        AUTH: "jabber:iq:auth",
          +        ROSTER: "jabber:iq:roster",
          +        PROFILE: "jabber:iq:profile",
          +        DISCO_INFO: "http://jabber.org/protocol/disco#info",
          +        DISCO_ITEMS: "http://jabber.org/protocol/disco#items",
          +        MUC: "http://jabber.org/protocol/muc",
          +        SASL: "urn:ietf:params:xml:ns:xmpp-sasl",
          +        STREAM: "http://etherx.jabber.org/streams",
          +        BIND: "urn:ietf:params:xml:ns:xmpp-bind",
          +        SESSION: "urn:ietf:params:xml:ns:xmpp-session",
          +        VERSION: "jabber:iq:version",
          +        STANZAS: "urn:ietf:params:xml:ns:xmpp-stanzas",
          +        XHTML_IM: "http://jabber.org/protocol/xhtml-im",
          +        XHTML: "http://www.w3.org/1999/xhtml"
          +    },
          +
          +
          +    /** Constants: XHTML_IM Namespace
          +     *  contains allowed tags, tag attributes, and css properties.
          +     *  Used in the createHtml function to filter incoming html into the allowed XHTML-IM subset.
          +     *  See http://xmpp.org/extensions/xep-0071.html#profile-summary for the list of recommended
          +     *  allowed tags and their attributes.
          +     */
          +    XHTML: {
          +                tags: ['a','blockquote','br','cite','em','img','li','ol','p','span','strong','ul','body'],
          +                attributes: {
          +                        'a':          ['href'],
          +                        'blockquote': ['style'],
          +                        'br':         [],
          +                        'cite':       ['style'],
          +                        'em':         [],
          +                        'img':        ['src', 'alt', 'style', 'height', 'width'],
          +                        'li':         ['style'],
          +                        'ol':         ['style'],
          +                        'p':          ['style'],
          +                        'span':       ['style'],
          +                        'strong':     [],
          +                        'ul':         ['style'],
          +                        'body':       []
          +                },
          +                css: ['background-color','color','font-family','font-size','font-style','font-weight','margin-left','margin-right','text-align','text-decoration'],
          +                validTag: function(tag)
          +                {
          +                        for(var i = 0; i < Strophe.XHTML.tags.length; i++) {
          +                                if(tag == Strophe.XHTML.tags[i]) {
          +                                        return true;
          +                                }
          +                        }
          +                        return false;
          +                },
          +                validAttribute: function(tag, attribute)
          +                {
          +                        if(typeof Strophe.XHTML.attributes[tag] !== 'undefined' && Strophe.XHTML.attributes[tag].length > 0) {
          +                                for(var i = 0; i < Strophe.XHTML.attributes[tag].length; i++) {
          +                                        if(attribute == Strophe.XHTML.attributes[tag][i]) {
          +                                                return true;
          +                                        }
          +                                }
          +                        }
          +                        return false;
          +                },
          +                validCSS: function(style)
          +                {
          +                        for(var i = 0; i < Strophe.XHTML.css.length; i++) {
          +                                if(style == Strophe.XHTML.css[i]) {
          +                                        return true;
          +                                }
          +                        }
          +                        return false;
          +                }
          +    },
          +
          +    /** Constants: Connection Status Constants
          +     *  Connection status constants for use by the connection handler
          +     *  callback.
          +     *
          +     *  Status.ERROR - An error has occurred
          +     *  Status.CONNECTING - The connection is currently being made
          +     *  Status.CONNFAIL - The connection attempt failed
          +     *  Status.AUTHENTICATING - The connection is authenticating
          +     *  Status.AUTHFAIL - The authentication attempt failed
          +     *  Status.CONNECTED - The connection has succeeded
          +     *  Status.DISCONNECTED - The connection has been terminated
          +     *  Status.DISCONNECTING - The connection is currently being terminated
          +     *  Status.ATTACHED - The connection has been attached
          +     */
          +    Status: {
          +        ERROR: 0,
          +        CONNECTING: 1,
          +        CONNFAIL: 2,
          +        AUTHENTICATING: 3,
          +        AUTHFAIL: 4,
          +        CONNECTED: 5,
          +        DISCONNECTED: 6,
          +        DISCONNECTING: 7,
          +        ATTACHED: 8
          +    },
          +
          +    /** Constants: Log Level Constants
          +     *  Logging level indicators.
          +     *
          +     *  LogLevel.DEBUG - Debug output
          +     *  LogLevel.INFO - Informational output
          +     *  LogLevel.WARN - Warnings
          +     *  LogLevel.ERROR - Errors
          +     *  LogLevel.FATAL - Fatal errors
          +     */
          +    LogLevel: {
          +        DEBUG: 0,
          +        INFO: 1,
          +        WARN: 2,
          +        ERROR: 3,
          +        FATAL: 4
          +    },
          +
          +    /** PrivateConstants: DOM Element Type Constants
          +     *  DOM element types.
          +     *
          +     *  ElementType.NORMAL - Normal element.
          +     *  ElementType.TEXT - Text data element.
          +     *  ElementType.FRAGMENT - XHTML fragment element.
          +     */
          +    ElementType: {
          +        NORMAL: 1,
          +        TEXT: 3,
          +        CDATA: 4,
          +        FRAGMENT: 11
          +    },
          +
          +    /** PrivateConstants: Timeout Values
          +     *  Timeout values for error states.  These values are in seconds.
          +     *  These should not be changed unless you know exactly what you are
          +     *  doing.
          +     *
          +     *  TIMEOUT - Timeout multiplier. A waiting request will be considered
          +     *      failed after Math.floor(TIMEOUT * wait) seconds have elapsed.
          +     *      This defaults to 1.1, and with default wait, 66 seconds.
          +     *  SECONDARY_TIMEOUT - Secondary timeout multiplier. In cases where
          +     *      Strophe can detect early failure, it will consider the request
          +     *      failed if it doesn't return after
          +     *      Math.floor(SECONDARY_TIMEOUT * wait) seconds have elapsed.
          +     *      This defaults to 0.1, and with default wait, 6 seconds.
          +     */
          +    TIMEOUT: 1.1,
          +    SECONDARY_TIMEOUT: 0.1,
          +
          +    /** Function: addNamespace
          +     *  This function is used to extend the current namespaces in
          +     *  Strophe.NS.  It takes a key and a value with the key being the
          +     *  name of the new namespace, with its actual value.
          +     *  For example:
          +     *  Strophe.addNamespace('PUBSUB', "http://jabber.org/protocol/pubsub");
          +     *
          +     *  Parameters:
          +     *    (String) name - The name under which the namespace will be
          +     *      referenced under Strophe.NS
          +     *    (String) value - The actual namespace.
          +     */
          +    addNamespace: function (name, value)
          +    {
          +      Strophe.NS[name] = value;
          +    },
          +
          +    /** Function: forEachChild
          +     *  Map a function over some or all child elements of a given element.
          +     *
          +     *  This is a small convenience function for mapping a function over
          +     *  some or all of the children of an element.  If elemName is null, all
          +     *  children will be passed to the function, otherwise only children
          +     *  whose tag names match elemName will be passed.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The element to operate on.
          +     *    (String) elemName - The child element tag name filter.
          +     *    (Function) func - The function to apply to each child.  This
          +     *      function should take a single argument, a DOM element.
          +     */
          +    forEachChild: function (elem, elemName, func)
          +    {
          +        var i, childNode;
          +
          +        for (i = 0; i < elem.childNodes.length; i++) {
          +            childNode = elem.childNodes[i];
          +            if (childNode.nodeType == Strophe.ElementType.NORMAL &&
          +                (!elemName || this.isTagEqual(childNode, elemName))) {
          +                func(childNode);
          +            }
          +        }
          +    },
          +
          +    /** Function: isTagEqual
          +     *  Compare an element's tag name with a string.
          +     *
          +     *  This function is case insensitive.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) el - A DOM element.
          +     *    (String) name - The element name.
          +     *
          +     *  Returns:
          +     *    true if the element's tag name matches _el_, and false
          +     *    otherwise.
          +     */
          +    isTagEqual: function (el, name)
          +    {
          +        return el.tagName.toLowerCase() == name.toLowerCase();
          +    },
          +
          +    /** PrivateVariable: _xmlGenerator
          +     *  _Private_ variable that caches a DOM document to
          +     *  generate elements.
          +     */
          +    _xmlGenerator: null,
          +
          +    /** PrivateFunction: _makeGenerator
          +     *  _Private_ function that creates a dummy XML DOM document to serve as
          +     *  an element and text node generator.
          +     */
          +    _makeGenerator: function () {
          +        var doc;
          +
          +        // IE9 does implement createDocument(); however, using it will cause the browser to leak memory on page unload.
          +        // Here, we test for presence of createDocument() plus IE's proprietary documentMode attribute, which would be
          +                // less than 10 in the case of IE9 and below.
          +        if (document.implementation.createDocument === undefined ||
          +                        document.implementation.createDocument && document.documentMode && document.documentMode < 10) {
          +            doc = this._getIEXmlDom();
          +            doc.appendChild(doc.createElement('strophe'));
          +        } else {
          +            doc = document.implementation
          +                .createDocument('jabber:client', 'strophe', null);
          +        }
          +
          +        return doc;
          +    },
          +
          +    /** Function: xmlGenerator
          +     *  Get the DOM document to generate elements.
          +     *
          +     *  Returns:
          +     *    The currently used DOM document.
          +     */
          +    xmlGenerator: function () {
          +        if (!Strophe._xmlGenerator) {
          +            Strophe._xmlGenerator = Strophe._makeGenerator();
          +        }
          +        return Strophe._xmlGenerator;
          +    },
          +
          +    /** PrivateFunction: _getIEXmlDom
          +     *  Gets IE xml doc object
          +     *
          +     *  Returns:
          +     *    A Microsoft XML DOM Object
          +     *  See Also:
          +     *    http://msdn.microsoft.com/en-us/library/ms757837%28VS.85%29.aspx
          +     */
          +    _getIEXmlDom : function() {
          +        var doc = null;
          +        var docStrings = [
          +            "Msxml2.DOMDocument.6.0",
          +            "Msxml2.DOMDocument.5.0",
          +            "Msxml2.DOMDocument.4.0",
          +            "MSXML2.DOMDocument.3.0",
          +            "MSXML2.DOMDocument",
          +            "MSXML.DOMDocument",
          +            "Microsoft.XMLDOM"
          +        ];
          +
          +        for (var d = 0; d < docStrings.length; d++) {
          +            if (doc === null) {
          +                try {
          +                    doc = new ActiveXObject(docStrings[d]);
          +                } catch (e) {
          +                    doc = null;
          +                }
          +            } else {
          +                break;
          +            }
          +        }
          +
          +        return doc;
          +    },
          +
          +    /** Function: xmlElement
          +     *  Create an XML DOM element.
          +     *
          +     *  This function creates an XML DOM element correctly across all
          +     *  implementations. Note that these are not HTML DOM elements, which
          +     *  aren't appropriate for XMPP stanzas.
          +     *
          +     *  Parameters:
          +     *    (String) name - The name for the element.
          +     *    (Array|Object) attrs - An optional array or object containing
          +     *      key/value pairs to use as element attributes. The object should
          +     *      be in the format {'key': 'value'} or {key: 'value'}. The array
          +     *      should have the format [['key1', 'value1'], ['key2', 'value2']].
          +     *    (String) text - The text child data for the element.
          +     *
          +     *  Returns:
          +     *    A new XML DOM element.
          +     */
          +    xmlElement: function (name)
          +    {
          +        if (!name) { return null; }
          +
          +        var node = Strophe.xmlGenerator().createElement(name);
          +
          +        // FIXME: this should throw errors if args are the wrong type or
          +        // there are more than two optional args
          +        var a, i, k;
          +        for (a = 1; a < arguments.length; a++) {
          +            if (!arguments[a]) { continue; }
          +            if (typeof(arguments[a]) == "string" ||
          +                typeof(arguments[a]) == "number") {
          +                node.appendChild(Strophe.xmlTextNode(arguments[a]));
          +            } else if (typeof(arguments[a]) == "object" &&
          +                       typeof(arguments[a].sort) == "function") {
          +                for (i = 0; i < arguments[a].length; i++) {
          +                    if (typeof(arguments[a][i]) == "object" &&
          +                        typeof(arguments[a][i].sort) == "function") {
          +                        node.setAttribute(arguments[a][i][0],
          +                                          arguments[a][i][1]);
          +                    }
          +                }
          +            } else if (typeof(arguments[a]) == "object") {
          +                for (k in arguments[a]) {
          +                    if (arguments[a].hasOwnProperty(k)) {
          +                        node.setAttribute(k, arguments[a][k]);
          +                    }
          +                }
          +            }
          +        }
          +
          +        return node;
          +    },
          +
          +    /*  Function: xmlescape
          +     *  Excapes invalid xml characters.
          +     *
          +     *  Parameters:
          +     *     (String) text - text to escape.
          +     *
          +     *  Returns:
          +     *      Escaped text.
          +     */
          +    xmlescape: function(text)
          +    {
          +        text = text.replace(/\&/g, "&amp;");
          +        text = text.replace(/</g,  "&lt;");
          +        text = text.replace(/>/g,  "&gt;");
          +        text = text.replace(/'/g,  "&apos;");
          +        text = text.replace(/"/g,  "&quot;");
          +        return text;
          +    },
          +
          +    /** Function: xmlTextNode
          +     *  Creates an XML DOM text node.
          +     *
          +     *  Provides a cross implementation version of document.createTextNode.
          +     *
          +     *  Parameters:
          +     *    (String) text - The content of the text node.
          +     *
          +     *  Returns:
          +     *    A new XML DOM text node.
          +     */
          +    xmlTextNode: function (text)
          +    {
          +        return Strophe.xmlGenerator().createTextNode(text);
          +    },
          +
          +    /** Function: xmlHtmlNode
          +     *  Creates an XML DOM html node.
          +     *
          +     *  Parameters:
          +     *    (String) html - The content of the html node.
          +     *
          +     *  Returns:
          +     *    A new XML DOM text node.
          +     */
          +    xmlHtmlNode: function (html)
          +    {
          +        var node;
          +        //ensure text is escaped
          +        if (window.DOMParser) {
          +            var parser = new DOMParser();
          +            node = parser.parseFromString(html, "text/xml");
          +        } else {
          +            node = new ActiveXObject("Microsoft.XMLDOM");
          +            node.async="false";
          +            node.loadXML(html);
          +        }
          +        return node;
          +    },
          +
          +    /** Function: getText
          +     *  Get the concatenation of all text children of an element.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - A DOM element.
          +     *
          +     *  Returns:
          +     *    A String with the concatenated text of all text element children.
          +     */
          +    getText: function (elem)
          +    {
          +        if (!elem) { return null; }
          +
          +        var str = "";
          +        if (elem.childNodes.length === 0 && elem.nodeType ==
          +            Strophe.ElementType.TEXT) {
          +            str += elem.nodeValue;
          +        }
          +
          +        for (var i = 0; i < elem.childNodes.length; i++) {
          +            if (elem.childNodes[i].nodeType == Strophe.ElementType.TEXT) {
          +                str += elem.childNodes[i].nodeValue;
          +            }
          +        }
          +
          +        return Strophe.xmlescape(str);
          +    },
          +
          +    /** Function: copyElement
          +     *  Copy an XML DOM element.
          +     *
          +     *  This function copies a DOM element and all its descendants and returns
          +     *  the new copy.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - A DOM element.
          +     *
          +     *  Returns:
          +     *    A new, copied DOM element tree.
          +     */
          +    copyElement: function (elem)
          +    {
          +        var i, el;
          +        if (elem.nodeType == Strophe.ElementType.NORMAL) {
          +            el = Strophe.xmlElement(elem.tagName);
          +
          +            for (i = 0; i < elem.attributes.length; i++) {
          +                el.setAttribute(elem.attributes[i].nodeName.toLowerCase(),
          +                                elem.attributes[i].value);
          +            }
          +
          +            for (i = 0; i < elem.childNodes.length; i++) {
          +                el.appendChild(Strophe.copyElement(elem.childNodes[i]));
          +            }
          +        } else if (elem.nodeType == Strophe.ElementType.TEXT) {
          +            el = Strophe.xmlGenerator().createTextNode(elem.nodeValue);
          +        }
          +
          +        return el;
          +    },
          +
          +
          +    /** Function: createHtml
          +     *  Copy an HTML DOM element into an XML DOM.
          +     *
          +     *  This function copies a DOM element and all its descendants and returns
          +     *  the new copy.
          +     *
          +     *  Parameters:
          +     *    (HTMLElement) elem - A DOM element.
          +     *
          +     *  Returns:
          +     *    A new, copied DOM element tree.
          +     */
          +    createHtml: function (elem)
          +    {
          +        var i, el, j, tag, attribute, value, css, cssAttrs, attr, cssName, cssValue;
          +        if (elem.nodeType == Strophe.ElementType.NORMAL) {
          +            tag = elem.nodeName.toLowerCase();
          +            if(Strophe.XHTML.validTag(tag)) {
          +                try {
          +                    el = Strophe.xmlElement(tag);
          +                    for(i = 0; i < Strophe.XHTML.attributes[tag].length; i++) {
          +                        attribute = Strophe.XHTML.attributes[tag][i];
          +                        value = elem.getAttribute(attribute);
          +                        if(typeof value == 'undefined' || value === null || value === '' || value === false || value === 0) {
          +                            continue;
          +                        }
          +                        if(attribute == 'style' && typeof value == 'object') {
          +                            if(typeof value.cssText != 'undefined') {
          +                                value = value.cssText; // we're dealing with IE, need to get CSS out
          +                            }
          +                        }
          +                        // filter out invalid css styles
          +                        if(attribute == 'style') {
          +                            css = [];
          +                            cssAttrs = value.split(';');
          +                            for(j = 0; j < cssAttrs.length; j++) {
          +                                attr = cssAttrs[j].split(':');
          +                                cssName = attr[0].replace(/^\s*/, "").replace(/\s*$/, "").toLowerCase();
          +                                if(Strophe.XHTML.validCSS(cssName)) {
          +                                    cssValue = attr[1].replace(/^\s*/, "").replace(/\s*$/, "");
          +                                    css.push(cssName + ': ' + cssValue);
          +                                }
          +                            }
          +                            if(css.length > 0) {
          +                                value = css.join('; ');
          +                                el.setAttribute(attribute, value);
          +                            }
          +                        } else {
          +                            el.setAttribute(attribute, value);
          +                        }
          +                    }
          +
          +                    for (i = 0; i < elem.childNodes.length; i++) {
          +                        el.appendChild(Strophe.createHtml(elem.childNodes[i]));
          +                    }
          +                } catch(e) { // invalid elements
          +                  el = Strophe.xmlTextNode('');
          +                }
          +            } else {
          +                el = Strophe.xmlGenerator().createDocumentFragment();
          +                for (i = 0; i < elem.childNodes.length; i++) {
          +                    el.appendChild(Strophe.createHtml(elem.childNodes[i]));
          +                }
          +            }
          +        } else if (elem.nodeType == Strophe.ElementType.FRAGMENT) {
          +            el = Strophe.xmlGenerator().createDocumentFragment();
          +            for (i = 0; i < elem.childNodes.length; i++) {
          +                el.appendChild(Strophe.createHtml(elem.childNodes[i]));
          +            }
          +        } else if (elem.nodeType == Strophe.ElementType.TEXT) {
          +            el = Strophe.xmlTextNode(elem.nodeValue);
          +        }
          +
          +        return el;
          +    },
          +
          +    /** Function: escapeNode
          +     *  Escape the node part (also called local part) of a JID.
          +     *
          +     *  Parameters:
          +     *    (String) node - A node (or local part).
          +     *
          +     *  Returns:
          +     *    An escaped node (or local part).
          +     */
          +    escapeNode: function (node)
          +    {
          +        return node.replace(/^\s+|\s+$/g, '')
          +            .replace(/\\/g,  "\\5c")
          +            .replace(/ /g,   "\\20")
          +            .replace(/\"/g,  "\\22")
          +            .replace(/\&/g,  "\\26")
          +            .replace(/\'/g,  "\\27")
          +            .replace(/\//g,  "\\2f")
          +            .replace(/:/g,   "\\3a")
          +            .replace(/</g,   "\\3c")
          +            .replace(/>/g,   "\\3e")
          +            .replace(/@/g,   "\\40");
          +    },
          +
          +    /** Function: unescapeNode
          +     *  Unescape a node part (also called local part) of a JID.
          +     *
          +     *  Parameters:
          +     *    (String) node - A node (or local part).
          +     *
          +     *  Returns:
          +     *    An unescaped node (or local part).
          +     */
          +    unescapeNode: function (node)
          +    {
          +        return node.replace(/\\20/g, " ")
          +            .replace(/\\22/g, '"')
          +            .replace(/\\26/g, "&")
          +            .replace(/\\27/g, "'")
          +            .replace(/\\2f/g, "/")
          +            .replace(/\\3a/g, ":")
          +            .replace(/\\3c/g, "<")
          +            .replace(/\\3e/g, ">")
          +            .replace(/\\40/g, "@")
          +            .replace(/\\5c/g, "\\");
          +    },
          +
          +    /** Function: getNodeFromJid
          +     *  Get the node portion of a JID String.
          +     *
          +     *  Parameters:
          +     *    (String) jid - A JID.
          +     *
          +     *  Returns:
          +     *    A String containing the node.
          +     */
          +    getNodeFromJid: function (jid)
          +    {
          +        if (jid.indexOf("@") < 0) { return null; }
          +        return jid.split("@")[0];
          +    },
          +
          +    /** Function: getDomainFromJid
          +     *  Get the domain portion of a JID String.
          +     *
          +     *  Parameters:
          +     *    (String) jid - A JID.
          +     *
          +     *  Returns:
          +     *    A String containing the domain.
          +     */
          +    getDomainFromJid: function (jid)
          +    {
          +        var bare = Strophe.getBareJidFromJid(jid);
          +        if (bare.indexOf("@") < 0) {
          +            return bare;
          +        } else {
          +            var parts = bare.split("@");
          +            parts.splice(0, 1);
          +            return parts.join('@');
          +        }
          +    },
          +
          +    /** Function: getResourceFromJid
          +     *  Get the resource portion of a JID String.
          +     *
          +     *  Parameters:
          +     *    (String) jid - A JID.
          +     *
          +     *  Returns:
          +     *    A String containing the resource.
          +     */
          +    getResourceFromJid: function (jid)
          +    {
          +        var s = jid.split("/");
          +        if (s.length < 2) { return null; }
          +        s.splice(0, 1);
          +        return s.join('/');
          +    },
          +
          +    /** Function: getBareJidFromJid
          +     *  Get the bare JID from a JID String.
          +     *
          +     *  Parameters:
          +     *    (String) jid - A JID.
          +     *
          +     *  Returns:
          +     *    A String containing the bare JID.
          +     */
          +    getBareJidFromJid: function (jid)
          +    {
          +        return jid ? jid.split("/")[0] : null;
          +    },
          +
          +    /** Function: log
          +     *  User overrideable logging function.
          +     *
          +     *  This function is called whenever the Strophe library calls any
          +     *  of the logging functions.  The default implementation of this
          +     *  function does nothing.  If client code wishes to handle the logging
          +     *  messages, it should override this with
          +     *  > Strophe.log = function (level, msg) {
          +     *  >   (user code here)
          +     *  > };
          +     *
          +     *  Please note that data sent and received over the wire is logged
          +     *  via Strophe.Connection.rawInput() and Strophe.Connection.rawOutput().
          +     *
          +     *  The different levels and their meanings are
          +     *
          +     *    DEBUG - Messages useful for debugging purposes.
          +     *    INFO - Informational messages.  This is mostly information like
          +     *      'disconnect was called' or 'SASL auth succeeded'.
          +     *    WARN - Warnings about potential problems.  This is mostly used
          +     *      to report transient connection errors like request timeouts.
          +     *    ERROR - Some error occurred.
          +     *    FATAL - A non-recoverable fatal error occurred.
          +     *
          +     *  Parameters:
          +     *    (Integer) level - The log level of the log message.  This will
          +     *      be one of the values in Strophe.LogLevel.
          +     *    (String) msg - The log message.
          +     */
          +    /* jshint ignore:start */
          +    log: function (level, msg)
          +    {
          +        return;
          +    },
          +    /* jshint ignore:end */
          +
          +    /** Function: debug
          +     *  Log a message at the Strophe.LogLevel.DEBUG level.
          +     *
          +     *  Parameters:
          +     *    (String) msg - The log message.
          +     */
          +    debug: function(msg)
          +    {
          +        this.log(this.LogLevel.DEBUG, msg);
          +    },
          +
          +    /** Function: info
          +     *  Log a message at the Strophe.LogLevel.INFO level.
          +     *
          +     *  Parameters:
          +     *    (String) msg - The log message.
          +     */
          +    info: function (msg)
          +    {
          +        this.log(this.LogLevel.INFO, msg);
          +    },
          +
          +    /** Function: warn
          +     *  Log a message at the Strophe.LogLevel.WARN level.
          +     *
          +     *  Parameters:
          +     *    (String) msg - The log message.
          +     */
          +    warn: function (msg)
          +    {
          +        this.log(this.LogLevel.WARN, msg);
          +    },
          +
          +    /** Function: error
          +     *  Log a message at the Strophe.LogLevel.ERROR level.
          +     *
          +     *  Parameters:
          +     *    (String) msg - The log message.
          +     */
          +    error: function (msg)
          +    {
          +        this.log(this.LogLevel.ERROR, msg);
          +    },
          +
          +    /** Function: fatal
          +     *  Log a message at the Strophe.LogLevel.FATAL level.
          +     *
          +     *  Parameters:
          +     *    (String) msg - The log message.
          +     */
          +    fatal: function (msg)
          +    {
          +        this.log(this.LogLevel.FATAL, msg);
          +    },
          +
          +    /** Function: serialize
          +     *  Render a DOM element and all descendants to a String.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - A DOM element.
          +     *
          +     *  Returns:
          +     *    The serialized element tree as a String.
          +     */
          +    serialize: function (elem)
          +    {
          +        var result;
          +
          +        if (!elem) { return null; }
          +
          +        if (typeof(elem.tree) === "function") {
          +            elem = elem.tree();
          +        }
          +
          +        var nodeName = elem.nodeName;
          +        var i, child;
          +
          +        if (elem.getAttribute("_realname")) {
          +            nodeName = elem.getAttribute("_realname");
          +        }
          +
          +        result = "<" + nodeName;
          +        for (i = 0; i < elem.attributes.length; i++) {
          +               if(elem.attributes[i].nodeName != "_realname") {
          +                 result += " " + elem.attributes[i].nodeName.toLowerCase() +
          +                "='" + elem.attributes[i].value
          +                    .replace(/&/g, "&amp;")
          +                       .replace(/\'/g, "&apos;")
          +                       .replace(/>/g, "&gt;")
          +                       .replace(/</g, "&lt;") + "'";
          +               }
          +        }
          +
          +        if (elem.childNodes.length > 0) {
          +            result += ">";
          +            for (i = 0; i < elem.childNodes.length; i++) {
          +                child = elem.childNodes[i];
          +                switch( child.nodeType ){
          +                  case Strophe.ElementType.NORMAL:
          +                    // normal element, so recurse
          +                    result += Strophe.serialize(child);
          +                    break;
          +                  case Strophe.ElementType.TEXT:
          +                    // text element to escape values
          +                    result += Strophe.xmlescape(child.nodeValue);
          +                    break;
          +                  case Strophe.ElementType.CDATA:
          +                    // cdata section so don't escape values
          +                    result += "<![CDATA["+child.nodeValue+"]]>";
          +                }
          +            }
          +            result += "</" + nodeName + ">";
          +        } else {
          +            result += "/>";
          +        }
          +
          +        return result;
          +    },
          +
          +    /** PrivateVariable: _requestId
          +     *  _Private_ variable that keeps track of the request ids for
          +     *  connections.
          +     */
          +    _requestId: 0,
          +
          +    /** PrivateVariable: Strophe.connectionPlugins
          +     *  _Private_ variable Used to store plugin names that need
          +     *  initialization on Strophe.Connection construction.
          +     */
          +    _connectionPlugins: {},
          +
          +    /** Function: addConnectionPlugin
          +     *  Extends the Strophe.Connection object with the given plugin.
          +     *
          +     *  Parameters:
          +     *    (String) name - The name of the extension.
          +     *    (Object) ptype - The plugin's prototype.
          +     */
          +    addConnectionPlugin: function (name, ptype)
          +    {
          +        Strophe._connectionPlugins[name] = ptype;
          +    }
          +};
          +
          +/** Class: Strophe.Builder
          + *  XML DOM builder.
          + *
          + *  This object provides an interface similar to JQuery but for building
          + *  DOM element easily and rapidly.  All the functions except for toString()
          + *  and tree() return the object, so calls can be chained.  Here's an
          + *  example using the $iq() builder helper.
          + *  > $iq({to: 'you', from: 'me', type: 'get', id: '1'})
          + *  >     .c('query', {xmlns: 'strophe:example'})
          + *  >     .c('example')
          + *  >     .toString()
          + *  The above generates this XML fragment
          + *  > <iq to='you' from='me' type='get' id='1'>
          + *  >   <query xmlns='strophe:example'>
          + *  >     <example/>
          + *  >   </query>
          + *  > </iq>
          + *  The corresponding DOM manipulations to get a similar fragment would be
          + *  a lot more tedious and probably involve several helper variables.
          + *
          + *  Since adding children makes new operations operate on the child, up()
          + *  is provided to traverse up the tree.  To add two children, do
          + *  > builder.c('child1', ...).up().c('child2', ...)
          + *  The next operation on the Builder will be relative to the second child.
          + */
          +
          +/** Constructor: Strophe.Builder
          + *  Create a Strophe.Builder object.
          + *
          + *  The attributes should be passed in object notation.  For example
          + *  > var b = new Builder('message', {to: 'you', from: 'me'});
          + *  or
          + *  > var b = new Builder('messsage', {'xml:lang': 'en'});
          + *
          + *  Parameters:
          + *    (String) name - The name of the root element.
          + *    (Object) attrs - The attributes for the root element in object notation.
          + *
          + *  Returns:
          + *    A new Strophe.Builder.
          + */
          +Strophe.Builder = function (name, attrs)
          +{
          +    // Set correct namespace for jabber:client elements
          +    if (name == "presence" || name == "message" || name == "iq") {
          +        if (attrs && !attrs.xmlns) {
          +            attrs.xmlns = Strophe.NS.CLIENT;
          +        } else if (!attrs) {
          +            attrs = {xmlns: Strophe.NS.CLIENT};
          +        }
          +    }
          +
          +    // Holds the tree being built.
          +    this.nodeTree = Strophe.xmlElement(name, attrs);
          +
          +    // Points to the current operation node.
          +    this.node = this.nodeTree;
          +};
          +
          +Strophe.Builder.prototype = {
          +    /** Function: tree
          +     *  Return the DOM tree.
          +     *
          +     *  This function returns the current DOM tree as an element object.  This
          +     *  is suitable for passing to functions like Strophe.Connection.send().
          +     *
          +     *  Returns:
          +     *    The DOM tree as a element object.
          +     */
          +    tree: function ()
          +    {
          +        return this.nodeTree;
          +    },
          +
          +    /** Function: toString
          +     *  Serialize the DOM tree to a String.
          +     *
          +     *  This function returns a string serialization of the current DOM
          +     *  tree.  It is often used internally to pass data to a
          +     *  Strophe.Request object.
          +     *
          +     *  Returns:
          +     *    The serialized DOM tree in a String.
          +     */
          +    toString: function ()
          +    {
          +        return Strophe.serialize(this.nodeTree);
          +    },
          +
          +    /** Function: up
          +     *  Make the current parent element the new current element.
          +     *
          +     *  This function is often used after c() to traverse back up the tree.
          +     *  For example, to add two children to the same element
          +     *  > builder.c('child1', {}).up().c('child2', {});
          +     *
          +     *  Returns:
          +     *    The Stophe.Builder object.
          +     */
          +    up: function ()
          +    {
          +        this.node = this.node.parentNode;
          +        return this;
          +    },
          +
          +    /** Function: attrs
          +     *  Add or modify attributes of the current element.
          +     *
          +     *  The attributes should be passed in object notation.  This function
          +     *  does not move the current element pointer.
          +     *
          +     *  Parameters:
          +     *    (Object) moreattrs - The attributes to add/modify in object notation.
          +     *
          +     *  Returns:
          +     *    The Strophe.Builder object.
          +     */
          +    attrs: function (moreattrs)
          +    {
          +        for (var k in moreattrs) {
          +            if (moreattrs.hasOwnProperty(k)) {
          +                this.node.setAttribute(k, moreattrs[k]);
          +            }
          +        }
          +        return this;
          +    },
          +
          +    /** Function: c
          +     *  Add a child to the current element and make it the new current
          +     *  element.
          +     *
          +     *  This function moves the current element pointer to the child,
          +     *  unless text is provided.  If you need to add another child, it
          +     *  is necessary to use up() to go back to the parent in the tree.
          +     *
          +     *  Parameters:
          +     *    (String) name - The name of the child.
          +     *    (Object) attrs - The attributes of the child in object notation.
          +     *    (String) text - The text to add to the child.
          +     *
          +     *  Returns:
          +     *    The Strophe.Builder object.
          +     */
          +    c: function (name, attrs, text)
          +    {
          +        var child = Strophe.xmlElement(name, attrs, text);
          +        this.node.appendChild(child);
          +        if (!text) {
          +            this.node = child;
          +        }
          +        return this;
          +    },
          +
          +    /** Function: cnode
          +     *  Add a child to the current element and make it the new current
          +     *  element.
          +     *
          +     *  This function is the same as c() except that instead of using a
          +     *  name and an attributes object to create the child it uses an
          +     *  existing DOM element object.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - A DOM element.
          +     *
          +     *  Returns:
          +     *    The Strophe.Builder object.
          +     */
          +    cnode: function (elem)
          +    {
          +        var impNode;
          +        var xmlGen = Strophe.xmlGenerator();
          +        try {
          +            impNode = (xmlGen.importNode !== undefined);
          +        }
          +        catch (e) {
          +            impNode = false;
          +        }
          +        var newElem = impNode ?
          +                      xmlGen.importNode(elem, true) :
          +                      Strophe.copyElement(elem);
          +        this.node.appendChild(newElem);
          +        this.node = newElem;
          +        return this;
          +    },
          +
          +    /** Function: t
          +     *  Add a child text element.
          +     *
          +     *  This *does not* make the child the new current element since there
          +     *  are no children of text elements.
          +     *
          +     *  Parameters:
          +     *    (String) text - The text data to append to the current element.
          +     *
          +     *  Returns:
          +     *    The Strophe.Builder object.
          +     */
          +    t: function (text)
          +    {
          +        var child = Strophe.xmlTextNode(text);
          +        this.node.appendChild(child);
          +        return this;
          +    },
          +
          +    /** Function: h
          +     *  Replace current element contents with the HTML passed in.
          +     *
          +     *  This *does not* make the child the new current element
          +     *
          +     *  Parameters:
          +     *    (String) html - The html to insert as contents of current element.
          +     *
          +     *  Returns:
          +     *    The Strophe.Builder object.
          +     */
          +    h: function (html)
          +    {
          +        var fragment = document.createElement('body');
          +
          +        // force the browser to try and fix any invalid HTML tags
          +        fragment.innerHTML = html;
          +
          +        // copy cleaned html into an xml dom
          +        var xhtml = Strophe.createHtml(fragment);
          +
          +        while(xhtml.childNodes.length > 0) {
          +            this.node.appendChild(xhtml.childNodes[0]);
          +        }
          +        return this;
          +    }
          +};
          +
          +/** PrivateClass: Strophe.Handler
          + *  _Private_ helper class for managing stanza handlers.
          + *
          + *  A Strophe.Handler encapsulates a user provided callback function to be
          + *  executed when matching stanzas are received by the connection.
          + *  Handlers can be either one-off or persistant depending on their
          + *  return value. Returning true will cause a Handler to remain active, and
          + *  returning false will remove the Handler.
          + *
          + *  Users will not use Strophe.Handler objects directly, but instead they
          + *  will use Strophe.Connection.addHandler() and
          + *  Strophe.Connection.deleteHandler().
          + */
          +
          +/** PrivateConstructor: Strophe.Handler
          + *  Create and initialize a new Strophe.Handler.
          + *
          + *  Parameters:
          + *    (Function) handler - A function to be executed when the handler is run.
          + *    (String) ns - The namespace to match.
          + *    (String) name - The element name to match.
          + *    (String) type - The element type to match.
          + *    (String) id - The element id attribute to match.
          + *    (String) from - The element from attribute to match.
          + *    (Object) options - Handler options
          + *
          + *  Returns:
          + *    A new Strophe.Handler object.
          + */
          +Strophe.Handler = function (handler, ns, name, type, id, from, options)
          +{
          +    this.handler = handler;
          +    this.ns = ns;
          +    this.name = name;
          +    this.type = type;
          +    this.id = id;
          +    this.options = options || {matchBare: false};
          +
          +    // default matchBare to false if undefined
          +    if (!this.options.matchBare) {
          +        this.options.matchBare = false;
          +    }
          +
          +    if (this.options.matchBare) {
          +        this.from = from ? Strophe.getBareJidFromJid(from) : null;
          +    } else {
          +        this.from = from;
          +    }
          +
          +    // whether the handler is a user handler or a system handler
          +    this.user = true;
          +};
          +
          +Strophe.Handler.prototype = {
          +    /** PrivateFunction: isMatch
          +     *  Tests if a stanza matches the Strophe.Handler.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The XML element to test.
          +     *
          +     *  Returns:
          +     *    true if the stanza matches and false otherwise.
          +     */
          +    isMatch: function (elem)
          +    {
          +        var nsMatch;
          +        var from = null;
          +
          +        if (this.options.matchBare) {
          +            from = Strophe.getBareJidFromJid(elem.getAttribute('from'));
          +        } else {
          +            from = elem.getAttribute('from');
          +        }
          +
          +        nsMatch = false;
          +        if (!this.ns) {
          +            nsMatch = true;
          +        } else {
          +            var that = this;
          +            Strophe.forEachChild(elem, null, function (elem) {
          +                if (elem.getAttribute("xmlns") == that.ns) {
          +                    nsMatch = true;
          +                }
          +            });
          +
          +            nsMatch = nsMatch || elem.getAttribute("xmlns") == this.ns;
          +        }
          +
          +        if (nsMatch &&
          +            (!this.name || Strophe.isTagEqual(elem, this.name)) &&
          +            (!this.type || elem.getAttribute("type") == this.type) &&
          +            (!this.id || elem.getAttribute("id") == this.id) &&
          +            (!this.from || from == this.from)) {
          +                return true;
          +        }
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: run
          +     *  Run the callback on a matching stanza.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The DOM element that triggered the
          +     *      Strophe.Handler.
          +     *
          +     *  Returns:
          +     *    A boolean indicating if the handler should remain active.
          +     */
          +    run: function (elem)
          +    {
          +        var result = null;
          +        try {
          +            result = this.handler(elem);
          +        } catch (e) {
          +            if (e.sourceURL) {
          +                Strophe.fatal("error: " + this.handler +
          +                              " " + e.sourceURL + ":" +
          +                              e.line + " - " + e.name + ": " + e.message);
          +            } else if (e.fileName) {
          +                if (typeof(console) != "undefined") {
          +                    console.trace();
          +                    console.error(this.handler, " - error - ", e, e.message);
          +                }
          +                Strophe.fatal("error: " + this.handler + " " +
          +                              e.fileName + ":" + e.lineNumber + " - " +
          +                              e.name + ": " + e.message);
          +            } else {
          +                Strophe.fatal("error: " + e.message + "\n" + e.stack);
          +            }
          +
          +            throw e;
          +        }
          +
          +        return result;
          +    },
          +
          +    /** PrivateFunction: toString
          +     *  Get a String representation of the Strophe.Handler object.
          +     *
          +     *  Returns:
          +     *    A String.
          +     */
          +    toString: function ()
          +    {
          +        return "{Handler: " + this.handler + "(" + this.name + "," +
          +            this.id + "," + this.ns + ")}";
          +    }
          +};
          +
          +/** PrivateClass: Strophe.TimedHandler
          + *  _Private_ helper class for managing timed handlers.
          + *
          + *  A Strophe.TimedHandler encapsulates a user provided callback that
          + *  should be called after a certain period of time or at regular
          + *  intervals.  The return value of the callback determines whether the
          + *  Strophe.TimedHandler will continue to fire.
          + *
          + *  Users will not use Strophe.TimedHandler objects directly, but instead
          + *  they will use Strophe.Connection.addTimedHandler() and
          + *  Strophe.Connection.deleteTimedHandler().
          + */
          +
          +/** PrivateConstructor: Strophe.TimedHandler
          + *  Create and initialize a new Strophe.TimedHandler object.
          + *
          + *  Parameters:
          + *    (Integer) period - The number of milliseconds to wait before the
          + *      handler is called.
          + *    (Function) handler - The callback to run when the handler fires.  This
          + *      function should take no arguments.
          + *
          + *  Returns:
          + *    A new Strophe.TimedHandler object.
          + */
          +Strophe.TimedHandler = function (period, handler)
          +{
          +    this.period = period;
          +    this.handler = handler;
          +
          +    this.lastCalled = new Date().getTime();
          +    this.user = true;
          +};
          +
          +Strophe.TimedHandler.prototype = {
          +    /** PrivateFunction: run
          +     *  Run the callback for the Strophe.TimedHandler.
          +     *
          +     *  Returns:
          +     *    true if the Strophe.TimedHandler should be called again, and false
          +     *      otherwise.
          +     */
          +    run: function ()
          +    {
          +        this.lastCalled = new Date().getTime();
          +        return this.handler();
          +    },
          +
          +    /** PrivateFunction: reset
          +     *  Reset the last called time for the Strophe.TimedHandler.
          +     */
          +    reset: function ()
          +    {
          +        this.lastCalled = new Date().getTime();
          +    },
          +
          +    /** PrivateFunction: toString
          +     *  Get a string representation of the Strophe.TimedHandler object.
          +     *
          +     *  Returns:
          +     *    The string representation.
          +     */
          +    toString: function ()
          +    {
          +        return "{TimedHandler: " + this.handler + "(" + this.period +")}";
          +    }
          +};
          +
          +/** Class: Strophe.Connection
          + *  XMPP Connection manager.
          + *
          + *  This class is the main part of Strophe.  It manages a BOSH connection
          + *  to an XMPP server and dispatches events to the user callbacks as
          + *  data arrives.  It supports SASL PLAIN, SASL DIGEST-MD5, SASL SCRAM-SHA1
          + *  and legacy authentication.
          + *
          + *  After creating a Strophe.Connection object, the user will typically
          + *  call connect() with a user supplied callback to handle connection level
          + *  events like authentication failure, disconnection, or connection
          + *  complete.
          + *
          + *  The user will also have several event handlers defined by using
          + *  addHandler() and addTimedHandler().  These will allow the user code to
          + *  respond to interesting stanzas or do something periodically with the
          + *  connection.  These handlers will be active once authentication is
          + *  finished.
          + *
          + *  To send data to the connection, use send().
          + */
          +
          +/** Constructor: Strophe.Connection
          + *  Create and initialize a Strophe.Connection object.
          + *
          + *  The transport-protocol for this connection will be chosen automatically
          + *  based on the given service parameter. URLs starting with "ws://" or
          + *  "wss://" will use WebSockets, URLs starting with "http://", "https://"
          + *  or without a protocol will use BOSH.
          + *
          + *  To make Strophe connect to the current host you can leave out the protocol
          + *  and host part and just pass the path, e.g.
          + *
          + *  > var conn = new Strophe.Connection("/http-bind/");
          + *
          + *  WebSocket options:
          + *
          + *  If you want to connect to the current host with a WebSocket connection you
          + *  can tell Strophe to use WebSockets through a "protocol" attribute in the
          + *  optional options parameter. Valid values are "ws" for WebSocket and "wss"
          + *  for Secure WebSocket.
          + *  So to connect to "wss://CURRENT_HOSTNAME/xmpp-websocket" you would call
          + *
          + *  > var conn = new Strophe.Connection("/xmpp-websocket/", {protocol: "wss"});
          + *
          + *  Note that relative URLs _NOT_ starting with a "/" will also include the path
          + *  of the current site.
          + *
          + *  Also because downgrading security is not permitted by browsers, when using
          + *  relative URLs both BOSH and WebSocket connections will use their secure
          + *  variants if the current connection to the site is also secure (https).
          + *
          + *  BOSH options:
          + *
          + *  by adding "sync" to the options, you can control if requests will
          + *  be made synchronously or not. The default behaviour is asynchronous.
          + *  If you want to make requests synchronous, make "sync" evaluate to true:
          + *  > var conn = new Strophe.Connection("/http-bind/", {sync: true});
          + *  You can also toggle this on an already established connection:
          + *  > conn.options.sync = true;
          + *
          + *
          + *  Parameters:
          + *    (String) service - The BOSH or WebSocket service URL.
          + *    (Object) options - A hash of configuration options
          + *
          + *  Returns:
          + *    A new Strophe.Connection object.
          + */
          +Strophe.Connection = function (service, options)
          +{
          +    // The service URL
          +    this.service = service;
          +
          +    // Configuration options
          +    this.options = options || {};
          +    var proto = this.options.protocol || "";
          +
          +    // Select protocal based on service or options
          +    if (service.indexOf("ws:") === 0 || service.indexOf("wss:") === 0 ||
          +            proto.indexOf("ws") === 0) {
          +        this._proto = new Strophe.Websocket(this);
          +    } else {
          +        this._proto = new Strophe.Bosh(this);
          +    }
          +    /* The connected JID. */
          +    this.jid = "";
          +    /* the JIDs domain */
          +    this.domain = null;
          +    /* stream:features */
          +    this.features = null;
          +
          +    // SASL
          +    this._sasl_data = {};
          +    this.do_session = false;
          +    this.do_bind = false;
          +
          +    // handler lists
          +    this.timedHandlers = [];
          +    this.handlers = [];
          +    this.removeTimeds = [];
          +    this.removeHandlers = [];
          +    this.addTimeds = [];
          +    this.addHandlers = [];
          +
          +    this._authentication = {};
          +    this._idleTimeout = null;
          +    this._disconnectTimeout = null;
          +
          +    this.do_authentication = true;
          +    this.authenticated = false;
          +    this.disconnecting = false;
          +    this.connected = false;
          +
          +    this.errors = 0;
          +
          +    this.paused = false;
          +
          +    this._data = [];
          +    this._uniqueId = 0;
          +
          +    this._sasl_success_handler = null;
          +    this._sasl_failure_handler = null;
          +    this._sasl_challenge_handler = null;
          +
          +    // Max retries before disconnecting
          +    this.maxRetries = 5;
          +
          +    // setup onIdle callback every 1/10th of a second
          +    this._idleTimeout = setTimeout(this._onIdle.bind(this), 100);
          +
          +    // initialize plugins
          +    for (var k in Strophe._connectionPlugins) {
          +        if (Strophe._connectionPlugins.hasOwnProperty(k)) {
          +            var ptype = Strophe._connectionPlugins[k];
          +            // jslint complaints about the below line, but this is fine
          +            var F = function () {}; // jshint ignore:line
          +            F.prototype = ptype;
          +            this[k] = new F();
          +            this[k].init(this);
          +        }
          +    }
          +};
          +
          +Strophe.Connection.prototype = {
          +    /** Function: reset
          +     *  Reset the connection.
          +     *
          +     *  This function should be called after a connection is disconnected
          +     *  before that connection is reused.
          +     */
          +    reset: function ()
          +    {
          +        this._proto._reset();
          +
          +        // SASL
          +        this.do_session = false;
          +        this.do_bind = false;
          +
          +        // handler lists
          +        this.timedHandlers = [];
          +        this.handlers = [];
          +        this.removeTimeds = [];
          +        this.removeHandlers = [];
          +        this.addTimeds = [];
          +        this.addHandlers = [];
          +        this._authentication = {};
          +
          +        this.authenticated = false;
          +        this.disconnecting = false;
          +        this.connected = false;
          +
          +        this.errors = 0;
          +
          +        this._requests = [];
          +        this._uniqueId = 0;
          +    },
          +
          +    /** Function: pause
          +     *  Pause the request manager.
          +     *
          +     *  This will prevent Strophe from sending any more requests to the
          +     *  server.  This is very useful for temporarily pausing
          +     *  BOSH-Connections while a lot of send() calls are happening quickly.
          +     *  This causes Strophe to send the data in a single request, saving
          +     *  many request trips.
          +     */
          +    pause: function ()
          +    {
          +        this.paused = true;
          +    },
          +
          +    /** Function: resume
          +     *  Resume the request manager.
          +     *
          +     *  This resumes after pause() has been called.
          +     */
          +    resume: function ()
          +    {
          +        this.paused = false;
          +    },
          +
          +    /** Function: getUniqueId
          +     *  Generate a unique ID for use in <iq/> elements.
          +     *
          +     *  All <iq/> stanzas are required to have unique id attributes.  This
          +     *  function makes creating these easy.  Each connection instance has
          +     *  a counter which starts from zero, and the value of this counter
          +     *  plus a colon followed by the suffix becomes the unique id. If no
          +     *  suffix is supplied, the counter is used as the unique id.
          +     *
          +     *  Suffixes are used to make debugging easier when reading the stream
          +     *  data, and their use is recommended.  The counter resets to 0 for
          +     *  every new connection for the same reason.  For connections to the
          +     *  same server that authenticate the same way, all the ids should be
          +     *  the same, which makes it easy to see changes.  This is useful for
          +     *  automated testing as well.
          +     *
          +     *  Parameters:
          +     *    (String) suffix - A optional suffix to append to the id.
          +     *
          +     *  Returns:
          +     *    A unique string to be used for the id attribute.
          +     */
          +    getUniqueId: function (suffix)
          +    {
          +        if (typeof(suffix) == "string" || typeof(suffix) == "number") {
          +            return ++this._uniqueId + ":" + suffix;
          +        } else {
          +            return ++this._uniqueId + "";
          +        }
          +    },
          +
          +    /** Function: connect
          +     *  Starts the connection process.
          +     *
          +     *  As the connection process proceeds, the user supplied callback will
          +     *  be triggered multiple times with status updates.  The callback
          +     *  should take two arguments - the status code and the error condition.
          +     *
          +     *  The status code will be one of the values in the Strophe.Status
          +     *  constants.  The error condition will be one of the conditions
          +     *  defined in RFC 3920 or the condition 'strophe-parsererror'.
          +     *
          +     *  The Parameters _wait_, _hold_ and _route_ are optional and only relevant
          +     *  for BOSH connections. Please see XEP 124 for a more detailed explanation
          +     *  of the optional parameters.
          +     *
          +     *  Parameters:
          +     *    (String) jid - The user's JID.  This may be a bare JID,
          +     *      or a full JID.  If a node is not supplied, SASL ANONYMOUS
          +     *      authentication will be attempted.
          +     *    (String) pass - The user's password.
          +     *    (Function) callback - The connect callback function.
          +     *    (Integer) wait - The optional HTTPBIND wait value.  This is the
          +     *      time the server will wait before returning an empty result for
          +     *      a request.  The default setting of 60 seconds is recommended.
          +     *    (Integer) hold - The optional HTTPBIND hold value.  This is the
          +     *      number of connections the server will hold at one time.  This
          +     *      should almost always be set to 1 (the default).
          +     *    (String) route - The optional route value.
          +     */
          +    connect: function (jid, pass, callback, wait, hold, route)
          +    {
          +        this.jid = jid;
          +        /** Variable: authzid
          +         *  Authorization identity.
          +         */
          +        this.authzid = Strophe.getBareJidFromJid(this.jid);
          +        /** Variable: authcid
          +         *  Authentication identity (User name).
          +         */
          +        this.authcid = Strophe.getNodeFromJid(this.jid);
          +        /** Variable: pass
          +         *  Authentication identity (User password).
          +         */
          +        this.pass = pass;
          +        /** Variable: servtype
          +         *  Digest MD5 compatibility.
          +         */
          +        this.servtype = "xmpp";
          +        this.connect_callback = callback;
          +        this.disconnecting = false;
          +        this.connected = false;
          +        this.authenticated = false;
          +        this.errors = 0;
          +
          +        // parse jid for domain
          +        this.domain = Strophe.getDomainFromJid(this.jid);
          +
          +        this._changeConnectStatus(Strophe.Status.CONNECTING, null);
          +
          +        this._proto._connect(wait, hold, route);
          +    },
          +
          +    /** Function: attach
          +     *  Attach to an already created and authenticated BOSH session.
          +     *
          +     *  This function is provided to allow Strophe to attach to BOSH
          +     *  sessions which have been created externally, perhaps by a Web
          +     *  application.  This is often used to support auto-login type features
          +     *  without putting user credentials into the page.
          +     *
          +     *  Parameters:
          +     *    (String) jid - The full JID that is bound by the session.
          +     *    (String) sid - The SID of the BOSH session.
          +     *    (String) rid - The current RID of the BOSH session.  This RID
          +     *      will be used by the next request.
          +     *    (Function) callback The connect callback function.
          +     *    (Integer) wait - The optional HTTPBIND wait value.  This is the
          +     *      time the server will wait before returning an empty result for
          +     *      a request.  The default setting of 60 seconds is recommended.
          +     *      Other settings will require tweaks to the Strophe.TIMEOUT value.
          +     *    (Integer) hold - The optional HTTPBIND hold value.  This is the
          +     *      number of connections the server will hold at one time.  This
          +     *      should almost always be set to 1 (the default).
          +     *    (Integer) wind - The optional HTTBIND window value.  This is the
          +     *      allowed range of request ids that are valid.  The default is 5.
          +     */
          +    attach: function (jid, sid, rid, callback, wait, hold, wind)
          +    {
          +        this._proto._attach(jid, sid, rid, callback, wait, hold, wind);
          +    },
          +
          +    /** Function: xmlInput
          +     *  User overrideable function that receives XML data coming into the
          +     *  connection.
          +     *
          +     *  The default function does nothing.  User code can override this with
          +     *  > Strophe.Connection.xmlInput = function (elem) {
          +     *  >   (user code)
          +     *  > };
          +     *
          +     *  Due to limitations of current Browsers' XML-Parsers the opening and closing
          +     *  <stream> tag for WebSocket-Connoctions will be passed as selfclosing here.
          +     *
          +     *  BOSH-Connections will have all stanzas wrapped in a <body> tag. See
          +     *  <Strophe.Bosh.strip> if you want to strip this tag.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The XML data received by the connection.
          +     */
          +    /* jshint unused:false */
          +    xmlInput: function (elem)
          +    {
          +        return;
          +    },
          +    /* jshint unused:true */
          +
          +    /** Function: xmlOutput
          +     *  User overrideable function that receives XML data sent to the
          +     *  connection.
          +     *
          +     *  The default function does nothing.  User code can override this with
          +     *  > Strophe.Connection.xmlOutput = function (elem) {
          +     *  >   (user code)
          +     *  > };
          +     *
          +     *  Due to limitations of current Browsers' XML-Parsers the opening and closing
          +     *  <stream> tag for WebSocket-Connoctions will be passed as selfclosing here.
          +     *
          +     *  BOSH-Connections will have all stanzas wrapped in a <body> tag. See
          +     *  <Strophe.Bosh.strip> if you want to strip this tag.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The XMLdata sent by the connection.
          +     */
          +    /* jshint unused:false */
          +    xmlOutput: function (elem)
          +    {
          +        return;
          +    },
          +    /* jshint unused:true */
          +
          +    /** Function: rawInput
          +     *  User overrideable function that receives raw data coming into the
          +     *  connection.
          +     *
          +     *  The default function does nothing.  User code can override this with
          +     *  > Strophe.Connection.rawInput = function (data) {
          +     *  >   (user code)
          +     *  > };
          +     *
          +     *  Parameters:
          +     *    (String) data - The data received by the connection.
          +     */
          +    /* jshint unused:false */
          +    rawInput: function (data)
          +    {
          +        return;
          +    },
          +    /* jshint unused:true */
          +
          +    /** Function: rawOutput
          +     *  User overrideable function that receives raw data sent to the
          +     *  connection.
          +     *
          +     *  The default function does nothing.  User code can override this with
          +     *  > Strophe.Connection.rawOutput = function (data) {
          +     *  >   (user code)
          +     *  > };
          +     *
          +     *  Parameters:
          +     *    (String) data - The data sent by the connection.
          +     */
          +    /* jshint unused:false */
          +    rawOutput: function (data)
          +    {
          +        return;
          +    },
          +    /* jshint unused:true */
          +
          +    /** Function: send
          +     *  Send a stanza.
          +     *
          +     *  This function is called to push data onto the send queue to
          +     *  go out over the wire.  Whenever a request is sent to the BOSH
          +     *  server, all pending data is sent and the queue is flushed.
          +     *
          +     *  Parameters:
          +     *    (XMLElement |
          +     *     [XMLElement] |
          +     *     Strophe.Builder) elem - The stanza to send.
          +     */
          +    send: function (elem)
          +    {
          +        if (elem === null) { return ; }
          +        if (typeof(elem.sort) === "function") {
          +            for (var i = 0; i < elem.length; i++) {
          +                this._queueData(elem[i]);
          +            }
          +        } else if (typeof(elem.tree) === "function") {
          +            this._queueData(elem.tree());
          +        } else {
          +            this._queueData(elem);
          +        }
          +
          +        this._proto._send();
          +    },
          +
          +    /** Function: flush
          +     *  Immediately send any pending outgoing data.
          +     *
          +     *  Normally send() queues outgoing data until the next idle period
          +     *  (100ms), which optimizes network use in the common cases when
          +     *  several send()s are called in succession. flush() can be used to
          +     *  immediately send all pending data.
          +     */
          +    flush: function ()
          +    {
          +        // cancel the pending idle period and run the idle function
          +        // immediately
          +        clearTimeout(this._idleTimeout);
          +        this._onIdle();
          +    },
          +
          +    /** Function: sendIQ
          +     *  Helper function to send IQ stanzas.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The stanza to send.
          +     *    (Function) callback - The callback function for a successful request.
          +     *    (Function) errback - The callback function for a failed or timed
          +     *      out request.  On timeout, the stanza will be null.
          +     *    (Integer) timeout - The time specified in milliseconds for a
          +     *      timeout to occur.
          +     *
          +     *  Returns:
          +     *    The id used to send the IQ.
          +    */
          +    sendIQ: function(elem, callback, errback, timeout) {
          +        var timeoutHandler = null;
          +        var that = this;
          +
          +        if (typeof(elem.tree) === "function") {
          +            elem = elem.tree();
          +        }
          +        var id = elem.getAttribute('id');
          +
          +        // inject id if not found
          +        if (!id) {
          +            id = this.getUniqueId("sendIQ");
          +            elem.setAttribute("id", id);
          +        }
          +
          +        var handler = this.addHandler(function (stanza) {
          +            // remove timeout handler if there is one
          +            if (timeoutHandler) {
          +                that.deleteTimedHandler(timeoutHandler);
          +            }
          +
          +            var iqtype = stanza.getAttribute('type');
          +            if (iqtype == 'result') {
          +                if (callback) {
          +                    callback(stanza);
          +                }
          +            } else if (iqtype == 'error') {
          +                if (errback) {
          +                    errback(stanza);
          +                }
          +            } else {
          +                throw {
          +                    name: "StropheError",
          +            message: "Got bad IQ type of " + iqtype
          +                };
          +            }
          +        }, null, 'iq', null, id);
          +
          +        // if timeout specified, setup timeout handler.
          +        if (timeout) {
          +            timeoutHandler = this.addTimedHandler(timeout, function () {
          +                // get rid of normal handler
          +                that.deleteHandler(handler);
          +
          +                // call errback on timeout with null stanza
          +                if (errback) {
          +                    errback(null);
          +                }
          +                return false;
          +            });
          +        }
          +
          +        this.send(elem);
          +
          +        return id;
          +    },
          +
          +    /** PrivateFunction: _queueData
          +     *  Queue outgoing data for later sending.  Also ensures that the data
          +     *  is a DOMElement.
          +     */
          +    _queueData: function (element) {
          +        if (element === null ||
          +            !element.tagName ||
          +            !element.childNodes) {
          +            throw {
          +                name: "StropheError",
          +                message: "Cannot queue non-DOMElement."
          +            };
          +        }
          +
          +        this._data.push(element);
          +    },
          +
          +    /** PrivateFunction: _sendRestart
          +     *  Send an xmpp:restart stanza.
          +     */
          +    _sendRestart: function ()
          +    {
          +        this._data.push("restart");
          +
          +        this._proto._sendRestart();
          +
          +        this._idleTimeout = setTimeout(this._onIdle.bind(this), 100);
          +    },
          +
          +    /** Function: addTimedHandler
          +     *  Add a timed handler to the connection.
          +     *
          +     *  This function adds a timed handler.  The provided handler will
          +     *  be called every period milliseconds until it returns false,
          +     *  the connection is terminated, or the handler is removed.  Handlers
          +     *  that wish to continue being invoked should return true.
          +     *
          +     *  Because of method binding it is necessary to save the result of
          +     *  this function if you wish to remove a handler with
          +     *  deleteTimedHandler().
          +     *
          +     *  Note that user handlers are not active until authentication is
          +     *  successful.
          +     *
          +     *  Parameters:
          +     *    (Integer) period - The period of the handler.
          +     *    (Function) handler - The callback function.
          +     *
          +     *  Returns:
          +     *    A reference to the handler that can be used to remove it.
          +     */
          +    addTimedHandler: function (period, handler)
          +    {
          +        var thand = new Strophe.TimedHandler(period, handler);
          +        this.addTimeds.push(thand);
          +        return thand;
          +    },
          +
          +    /** Function: deleteTimedHandler
          +     *  Delete a timed handler for a connection.
          +     *
          +     *  This function removes a timed handler from the connection.  The
          +     *  handRef parameter is *not* the function passed to addTimedHandler(),
          +     *  but is the reference returned from addTimedHandler().
          +     *
          +     *  Parameters:
          +     *    (Strophe.TimedHandler) handRef - The handler reference.
          +     */
          +    deleteTimedHandler: function (handRef)
          +    {
          +        // this must be done in the Idle loop so that we don't change
          +        // the handlers during iteration
          +        this.removeTimeds.push(handRef);
          +    },
          +
          +    /** Function: addHandler
          +     *  Add a stanza handler for the connection.
          +     *
          +     *  This function adds a stanza handler to the connection.  The
          +     *  handler callback will be called for any stanza that matches
          +     *  the parameters.  Note that if multiple parameters are supplied,
          +     *  they must all match for the handler to be invoked.
          +     *
          +     *  The handler will receive the stanza that triggered it as its argument.
          +     *  The handler should return true if it is to be invoked again;
          +     *  returning false will remove the handler after it returns.
          +     *
          +     *  As a convenience, the ns parameters applies to the top level element
          +     *  and also any of its immediate children.  This is primarily to make
          +     *  matching /iq/query elements easy.
          +     *
          +     *  The options argument contains handler matching flags that affect how
          +     *  matches are determined. Currently the only flag is matchBare (a
          +     *  boolean). When matchBare is true, the from parameter and the from
          +     *  attribute on the stanza will be matched as bare JIDs instead of
          +     *  full JIDs. To use this, pass {matchBare: true} as the value of
          +     *  options. The default value for matchBare is false.
          +     *
          +     *  The return value should be saved if you wish to remove the handler
          +     *  with deleteHandler().
          +     *
          +     *  Parameters:
          +     *    (Function) handler - The user callback.
          +     *    (String) ns - The namespace to match.
          +     *    (String) name - The stanza name to match.
          +     *    (String) type - The stanza type attribute to match.
          +     *    (String) id - The stanza id attribute to match.
          +     *    (String) from - The stanza from attribute to match.
          +     *    (String) options - The handler options
          +     *
          +     *  Returns:
          +     *    A reference to the handler that can be used to remove it.
          +     */
          +    addHandler: function (handler, ns, name, type, id, from, options)
          +    {
          +        var hand = new Strophe.Handler(handler, ns, name, type, id, from, options);
          +        this.addHandlers.push(hand);
          +        return hand;
          +    },
          +
          +    /** Function: deleteHandler
          +     *  Delete a stanza handler for a connection.
          +     *
          +     *  This function removes a stanza handler from the connection.  The
          +     *  handRef parameter is *not* the function passed to addHandler(),
          +     *  but is the reference returned from addHandler().
          +     *
          +     *  Parameters:
          +     *    (Strophe.Handler) handRef - The handler reference.
          +     */
          +    deleteHandler: function (handRef)
          +    {
          +        // this must be done in the Idle loop so that we don't change
          +        // the handlers during iteration
          +        this.removeHandlers.push(handRef);
          +    },
          +
          +    /** Function: disconnect
          +     *  Start the graceful disconnection process.
          +     *
          +     *  This function starts the disconnection process.  This process starts
          +     *  by sending unavailable presence and sending BOSH body of type
          +     *  terminate.  A timeout handler makes sure that disconnection happens
          +     *  even if the BOSH server does not respond.
          +     *
          +     *  The user supplied connection callback will be notified of the
          +     *  progress as this process happens.
          +     *
          +     *  Parameters:
          +     *    (String) reason - The reason the disconnect is occuring.
          +     */
          +    disconnect: function (reason)
          +    {
          +        this._changeConnectStatus(Strophe.Status.DISCONNECTING, reason);
          +
          +        Strophe.info("Disconnect was called because: " + reason);
          +        if (this.connected) {
          +            var pres = false;
          +            this.disconnecting = true;
          +            if (this.authenticated) {
          +                pres = $pres({
          +                    xmlns: Strophe.NS.CLIENT,
          +                    type: 'unavailable'
          +                });
          +            }
          +            // setup timeout handler
          +            this._disconnectTimeout = this._addSysTimedHandler(
          +                3000, this._onDisconnectTimeout.bind(this));
          +            this._proto._disconnect(pres);
          +        }
          +    },
          +
          +    /** PrivateFunction: _changeConnectStatus
          +     *  _Private_ helper function that makes sure plugins and the user's
          +     *  callback are notified of connection status changes.
          +     *
          +     *  Parameters:
          +     *    (Integer) status - the new connection status, one of the values
          +     *      in Strophe.Status
          +     *    (String) condition - the error condition or null
          +     */
          +    _changeConnectStatus: function (status, condition)
          +    {
          +        // notify all plugins listening for status changes
          +        for (var k in Strophe._connectionPlugins) {
          +            if (Strophe._connectionPlugins.hasOwnProperty(k)) {
          +                var plugin = this[k];
          +                if (plugin.statusChanged) {
          +                    try {
          +                        plugin.statusChanged(status, condition);
          +                    } catch (err) {
          +                        Strophe.error("" + k + " plugin caused an exception " +
          +                                      "changing status: " + err);
          +                    }
          +                }
          +            }
          +        }
          +
          +        // notify the user's callback
          +        if (this.connect_callback) {
          +            try {
          +                this.connect_callback(status, condition);
          +            } catch (e) {
          +                Strophe.error("User connection callback caused an " +
          +                              "exception: " + e);
          +            }
          +        }
          +    },
          +
          +    /** PrivateFunction: _doDisconnect
          +     *  _Private_ function to disconnect.
          +     *
          +     *  This is the last piece of the disconnection logic.  This resets the
          +     *  connection and alerts the user's connection callback.
          +     */
          +    _doDisconnect: function ()
          +    {
          +        // Cancel Disconnect Timeout
          +        if (this._disconnectTimeout !== null) {
          +            this.deleteTimedHandler(this._disconnectTimeout);
          +            this._disconnectTimeout = null;
          +        }
          +
          +        Strophe.info("_doDisconnect was called");
          +        this._proto._doDisconnect();
          +
          +        this.authenticated = false;
          +        this.disconnecting = false;
          +
          +        // delete handlers
          +        this.handlers = [];
          +        this.timedHandlers = [];
          +        this.removeTimeds = [];
          +        this.removeHandlers = [];
          +        this.addTimeds = [];
          +        this.addHandlers = [];
          +
          +        // tell the parent we disconnected
          +        this._changeConnectStatus(Strophe.Status.DISCONNECTED, null);
          +        this.connected = false;
          +    },
          +
          +    /** PrivateFunction: _dataRecv
          +     *  _Private_ handler to processes incoming data from the the connection.
          +     *
          +     *  Except for _connect_cb handling the initial connection request,
          +     *  this function handles the incoming data for all requests.  This
          +     *  function also fires stanza handlers that match each incoming
          +     *  stanza.
          +     *
          +     *  Parameters:
          +     *    (Strophe.Request) req - The request that has data ready.
          +     *    (string) req - The stanza a raw string (optiona).
          +     */
          +    _dataRecv: function (req, raw)
          +    {
          +        Strophe.info("_dataRecv called");
          +        var elem = this._proto._reqToData(req);
          +        if (elem === null) { return; }
          +
          +        if (this.xmlInput !== Strophe.Connection.prototype.xmlInput) {
          +            if (elem.nodeName === this._proto.strip && elem.childNodes.length) {
          +                this.xmlInput(elem.childNodes[0]);
          +            } else {
          +                this.xmlInput(elem);
          +            }
          +        }
          +        if (this.rawInput !== Strophe.Connection.prototype.rawInput) {
          +            if (raw) {
          +                this.rawInput(raw);
          +            } else {
          +                this.rawInput(Strophe.serialize(elem));
          +            }
          +        }
          +
          +        // remove handlers scheduled for deletion
          +        var i, hand;
          +        while (this.removeHandlers.length > 0) {
          +            hand = this.removeHandlers.pop();
          +            i = this.handlers.indexOf(hand);
          +            if (i >= 0) {
          +                this.handlers.splice(i, 1);
          +            }
          +        }
          +
          +        // add handlers scheduled for addition
          +        while (this.addHandlers.length > 0) {
          +            this.handlers.push(this.addHandlers.pop());
          +        }
          +
          +        // handle graceful disconnect
          +        if (this.disconnecting && this._proto._emptyQueue()) {
          +            this._doDisconnect();
          +            return;
          +        }
          +
          +        var typ = elem.getAttribute("type");
          +        var cond, conflict;
          +        if (typ !== null && typ == "terminate") {
          +            // Don't process stanzas that come in after disconnect
          +            if (this.disconnecting) {
          +                return;
          +            }
          +
          +            // an error occurred
          +            cond = elem.getAttribute("condition");
          +            conflict = elem.getElementsByTagName("conflict");
          +            if (cond !== null) {
          +                if (cond == "remote-stream-error" && conflict.length > 0) {
          +                    cond = "conflict";
          +                }
          +                this._changeConnectStatus(Strophe.Status.CONNFAIL, cond);
          +            } else {
          +                this._changeConnectStatus(Strophe.Status.CONNFAIL, "unknown");
          +            }
          +            this.disconnect('unknown stream-error');
          +            return;
          +        }
          +
          +        // send each incoming stanza through the handler chain
          +        var that = this;
          +        Strophe.forEachChild(elem, null, function (child) {
          +            var i, newList;
          +            // process handlers
          +            newList = that.handlers;
          +            that.handlers = [];
          +            for (i = 0; i < newList.length; i++) {
          +                var hand = newList[i];
          +                // encapsulate 'handler.run' not to lose the whole handler list if
          +                // one of the handlers throws an exception
          +                try {
          +                    if (hand.isMatch(child) &&
          +                        (that.authenticated || !hand.user)) {
          +                        if (hand.run(child)) {
          +                            that.handlers.push(hand);
          +                        }
          +                    } else {
          +                        that.handlers.push(hand);
          +                    }
          +                } catch(e) {
          +                    // if the handler throws an exception, we consider it as false
          +                    Strophe.warn('Removing Strophe handlers due to uncaught exception: ' + e.message);
          +                }
          +            }
          +        });
          +    },
          +
          +
          +    /** Attribute: mechanisms
          +     *  SASL Mechanisms available for Conncection.
          +     */
          +    mechanisms: {},
          +
          +    /** PrivateFunction: _connect_cb
          +     *  _Private_ handler for initial connection request.
          +     *
          +     *  This handler is used to process the initial connection request
          +     *  response from the BOSH server. It is used to set up authentication
          +     *  handlers and start the authentication process.
          +     *
          +     *  SASL authentication will be attempted if available, otherwise
          +     *  the code will fall back to legacy authentication.
          +     *
          +     *  Parameters:
          +     *    (Strophe.Request) req - The current request.
          +     *    (Function) _callback - low level (xmpp) connect callback function.
          +     *      Useful for plugins with their own xmpp connect callback (when their)
          +     *      want to do something special).
          +     */
          +    _connect_cb: function (req, _callback, raw)
          +    {
          +        Strophe.info("_connect_cb was called");
          +
          +        this.connected = true;
          +
          +        var bodyWrap = this._proto._reqToData(req);
          +        if (!bodyWrap) { return; }
          +
          +        if (this.xmlInput !== Strophe.Connection.prototype.xmlInput) {
          +            if (bodyWrap.nodeName === this._proto.strip && bodyWrap.childNodes.length) {
          +                this.xmlInput(bodyWrap.childNodes[0]);
          +            } else {
          +                this.xmlInput(bodyWrap);
          +            }
          +        }
          +        if (this.rawInput !== Strophe.Connection.prototype.rawInput) {
          +            if (raw) {
          +                this.rawInput(raw);
          +            } else {
          +                this.rawInput(Strophe.serialize(bodyWrap));
          +            }
          +        }
          +
          +        var conncheck = this._proto._connect_cb(bodyWrap);
          +        if (conncheck === Strophe.Status.CONNFAIL) {
          +            return;
          +        }
          +
          +        this._authentication.sasl_scram_sha1 = false;
          +        this._authentication.sasl_plain = false;
          +        this._authentication.sasl_digest_md5 = false;
          +        this._authentication.sasl_anonymous = false;
          +
          +        this._authentication.legacy_auth = false;
          +
          +        // Check for the stream:features tag
          +        var hasFeatures = bodyWrap.getElementsByTagName("stream:features").length > 0;
          +        if (!hasFeatures) {
          +            hasFeatures = bodyWrap.getElementsByTagName("features").length > 0;
          +        }
          +        var mechanisms = bodyWrap.getElementsByTagName("mechanism");
          +        var matched = [];
          +        var i, mech, found_authentication = false;
          +        if (!hasFeatures) {
          +            this._proto._no_auth_received(_callback);
          +            return;
          +        }
          +        if (mechanisms.length > 0) {
          +            for (i = 0; i < mechanisms.length; i++) {
          +                mech = Strophe.getText(mechanisms[i]);
          +                if (this.mechanisms[mech]) matched.push(this.mechanisms[mech]);
          +            }
          +        }
          +        this._authentication.legacy_auth =
          +            bodyWrap.getElementsByTagName("auth").length > 0;
          +        found_authentication = this._authentication.legacy_auth ||
          +            matched.length > 0;
          +        if (!found_authentication) {
          +            this._proto._no_auth_received(_callback);
          +            return;
          +        }
          +        if (this.do_authentication !== false)
          +            this.authenticate(matched);
          +    },
          +
          +    /** Function: authenticate
          +     * Set up authentication
          +     *
          +     *  Contiunues the initial connection request by setting up authentication
          +     *  handlers and start the authentication process.
          +     *
          +     *  SASL authentication will be attempted if available, otherwise
          +     *  the code will fall back to legacy authentication.
          +     *
          +     */
          +    authenticate: function (matched)
          +    {
          +      var i;
          +      // Sorting matched mechanisms according to priority.
          +      for (i = 0; i < matched.length - 1; ++i) {
          +        var higher = i;
          +        for (var j = i + 1; j < matched.length; ++j) {
          +          if (matched[j].prototype.priority > matched[higher].prototype.priority) {
          +            higher = j;
          +          }
          +        }
          +        if (higher != i) {
          +          var swap = matched[i];
          +          matched[i] = matched[higher];
          +          matched[higher] = swap;
          +        }
          +      }
          +
          +      // run each mechanism
          +      var mechanism_found = false;
          +      for (i = 0; i < matched.length; ++i) {
          +        if (!matched[i].test(this)) continue;
          +
          +        this._sasl_success_handler = this._addSysHandler(
          +          this._sasl_success_cb.bind(this), null,
          +          "success", null, null);
          +        this._sasl_failure_handler = this._addSysHandler(
          +          this._sasl_failure_cb.bind(this), null,
          +          "failure", null, null);
          +        this._sasl_challenge_handler = this._addSysHandler(
          +          this._sasl_challenge_cb.bind(this), null,
          +          "challenge", null, null);
          +
          +        this._sasl_mechanism = new matched[i]();
          +        this._sasl_mechanism.onStart(this);
          +
          +        var request_auth_exchange = $build("auth", {
          +          xmlns: Strophe.NS.SASL,
          +          mechanism: this._sasl_mechanism.name
          +        });
          +
          +        if (this._sasl_mechanism.isClientFirst) {
          +          var response = this._sasl_mechanism.onChallenge(this, null);
          +          request_auth_exchange.t(Base64.encode(response));
          +        }
          +
          +        this.send(request_auth_exchange.tree());
          +
          +        mechanism_found = true;
          +        break;
          +      }
          +
          +      if (!mechanism_found) {
          +        // if none of the mechanism worked
          +        if (Strophe.getNodeFromJid(this.jid) === null) {
          +            // we don't have a node, which is required for non-anonymous
          +            // client connections
          +            this._changeConnectStatus(Strophe.Status.CONNFAIL,
          +                                      'x-strophe-bad-non-anon-jid');
          +            this.disconnect('x-strophe-bad-non-anon-jid');
          +        } else {
          +          // fall back to legacy authentication
          +          this._changeConnectStatus(Strophe.Status.AUTHENTICATING, null);
          +          this._addSysHandler(this._auth1_cb.bind(this), null, null,
          +                              null, "_auth_1");
          +
          +          this.send($iq({
          +            type: "get",
          +            to: this.domain,
          +            id: "_auth_1"
          +          }).c("query", {
          +            xmlns: Strophe.NS.AUTH
          +          }).c("username", {}).t(Strophe.getNodeFromJid(this.jid)).tree());
          +        }
          +      }
          +
          +    },
          +
          +    _sasl_challenge_cb: function(elem) {
          +      var challenge = Base64.decode(Strophe.getText(elem));
          +      var response = this._sasl_mechanism.onChallenge(this, challenge);
          +
          +      var stanza = $build('response', {
          +          xmlns: Strophe.NS.SASL
          +      });
          +      if (response !== "") {
          +        stanza.t(Base64.encode(response));
          +      }
          +      this.send(stanza.tree());
          +
          +      return true;
          +    },
          +
          +    /** PrivateFunction: _auth1_cb
          +     *  _Private_ handler for legacy authentication.
          +     *
          +     *  This handler is called in response to the initial <iq type='get'/>
          +     *  for legacy authentication.  It builds an authentication <iq/> and
          +     *  sends it, creating a handler (calling back to _auth2_cb()) to
          +     *  handle the result
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The stanza that triggered the callback.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    /* jshint unused:false */
          +    _auth1_cb: function (elem)
          +    {
          +        // build plaintext auth iq
          +        var iq = $iq({type: "set", id: "_auth_2"})
          +            .c('query', {xmlns: Strophe.NS.AUTH})
          +            .c('username', {}).t(Strophe.getNodeFromJid(this.jid))
          +            .up()
          +            .c('password').t(this.pass);
          +
          +        if (!Strophe.getResourceFromJid(this.jid)) {
          +            // since the user has not supplied a resource, we pick
          +            // a default one here.  unlike other auth methods, the server
          +            // cannot do this for us.
          +            this.jid = Strophe.getBareJidFromJid(this.jid) + '/strophe';
          +        }
          +        iq.up().c('resource', {}).t(Strophe.getResourceFromJid(this.jid));
          +
          +        this._addSysHandler(this._auth2_cb.bind(this), null,
          +                            null, null, "_auth_2");
          +
          +        this.send(iq.tree());
          +
          +        return false;
          +    },
          +    /* jshint unused:true */
          +
          +    /** PrivateFunction: _sasl_success_cb
          +     *  _Private_ handler for succesful SASL authentication.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The matching stanza.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _sasl_success_cb: function (elem)
          +    {
          +        if (this._sasl_data["server-signature"]) {
          +            var serverSignature;
          +            var success = Base64.decode(Strophe.getText(elem));
          +            var attribMatch = /([a-z]+)=([^,]+)(,|$)/;
          +            var matches = success.match(attribMatch);
          +            if (matches[1] == "v") {
          +                serverSignature = matches[2];
          +            }
          +
          +            if (serverSignature != this._sasl_data["server-signature"]) {
          +              // remove old handlers
          +              this.deleteHandler(this._sasl_failure_handler);
          +              this._sasl_failure_handler = null;
          +              if (this._sasl_challenge_handler) {
          +                this.deleteHandler(this._sasl_challenge_handler);
          +                this._sasl_challenge_handler = null;
          +              }
          +
          +              this._sasl_data = {};
          +              return this._sasl_failure_cb(null);
          +            }
          +        }
          +
          +        Strophe.info("SASL authentication succeeded.");
          +
          +        if(this._sasl_mechanism)
          +          this._sasl_mechanism.onSuccess();
          +
          +        // remove old handlers
          +        this.deleteHandler(this._sasl_failure_handler);
          +        this._sasl_failure_handler = null;
          +        if (this._sasl_challenge_handler) {
          +            this.deleteHandler(this._sasl_challenge_handler);
          +            this._sasl_challenge_handler = null;
          +        }
          +
          +        this._addSysHandler(this._sasl_auth1_cb.bind(this), null,
          +                            "stream:features", null, null);
          +
          +        // we must send an xmpp:restart now
          +        this._sendRestart();
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: _sasl_auth1_cb
          +     *  _Private_ handler to start stream binding.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The matching stanza.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _sasl_auth1_cb: function (elem)
          +    {
          +        // save stream:features for future usage
          +        this.features = elem;
          +
          +        var i, child;
          +
          +        for (i = 0; i < elem.childNodes.length; i++) {
          +            child = elem.childNodes[i];
          +            if (child.nodeName == 'bind') {
          +                this.do_bind = true;
          +            }
          +
          +            if (child.nodeName == 'session') {
          +                this.do_session = true;
          +            }
          +        }
          +
          +        if (!this.do_bind) {
          +            this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
          +            return false;
          +        } else {
          +            this._addSysHandler(this._sasl_bind_cb.bind(this), null, null,
          +                                null, "_bind_auth_2");
          +
          +            var resource = Strophe.getResourceFromJid(this.jid);
          +            if (resource) {
          +                this.send($iq({type: "set", id: "_bind_auth_2"})
          +                          .c('bind', {xmlns: Strophe.NS.BIND})
          +                          .c('resource', {}).t(resource).tree());
          +            } else {
          +                this.send($iq({type: "set", id: "_bind_auth_2"})
          +                          .c('bind', {xmlns: Strophe.NS.BIND})
          +                          .tree());
          +            }
          +        }
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: _sasl_bind_cb
          +     *  _Private_ handler for binding result and session start.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The matching stanza.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _sasl_bind_cb: function (elem)
          +    {
          +        if (elem.getAttribute("type") == "error") {
          +            Strophe.info("SASL binding failed.");
          +            var conflict = elem.getElementsByTagName("conflict"), condition;
          +            if (conflict.length > 0) {
          +                condition = 'conflict';
          +            }
          +            this._changeConnectStatus(Strophe.Status.AUTHFAIL, condition);
          +            return false;
          +        }
          +
          +        // TODO - need to grab errors
          +        var bind = elem.getElementsByTagName("bind");
          +        var jidNode;
          +        if (bind.length > 0) {
          +            // Grab jid
          +            jidNode = bind[0].getElementsByTagName("jid");
          +            if (jidNode.length > 0) {
          +                this.jid = Strophe.getText(jidNode[0]);
          +
          +                if (this.do_session) {
          +                    this._addSysHandler(this._sasl_session_cb.bind(this),
          +                                        null, null, null, "_session_auth_2");
          +
          +                    this.send($iq({type: "set", id: "_session_auth_2"})
          +                                  .c('session', {xmlns: Strophe.NS.SESSION})
          +                                  .tree());
          +                } else {
          +                    this.authenticated = true;
          +                    this._changeConnectStatus(Strophe.Status.CONNECTED, null);
          +                }
          +            }
          +        } else {
          +            Strophe.info("SASL binding failed.");
          +            this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
          +            return false;
          +        }
          +    },
          +
          +    /** PrivateFunction: _sasl_session_cb
          +     *  _Private_ handler to finish successful SASL connection.
          +     *
          +     *  This sets Connection.authenticated to true on success, which
          +     *  starts the processing of user handlers.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The matching stanza.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _sasl_session_cb: function (elem)
          +    {
          +        if (elem.getAttribute("type") == "result") {
          +            this.authenticated = true;
          +            this._changeConnectStatus(Strophe.Status.CONNECTED, null);
          +        } else if (elem.getAttribute("type") == "error") {
          +            Strophe.info("Session creation failed.");
          +            this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
          +            return false;
          +        }
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: _sasl_failure_cb
          +     *  _Private_ handler for SASL authentication failure.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The matching stanza.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    /* jshint unused:false */
          +    _sasl_failure_cb: function (elem)
          +    {
          +        // delete unneeded handlers
          +        if (this._sasl_success_handler) {
          +            this.deleteHandler(this._sasl_success_handler);
          +            this._sasl_success_handler = null;
          +        }
          +        if (this._sasl_challenge_handler) {
          +            this.deleteHandler(this._sasl_challenge_handler);
          +            this._sasl_challenge_handler = null;
          +        }
          +
          +        if(this._sasl_mechanism)
          +          this._sasl_mechanism.onFailure();
          +        this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
          +        return false;
          +    },
          +    /* jshint unused:true */
          +
          +    /** PrivateFunction: _auth2_cb
          +     *  _Private_ handler to finish legacy authentication.
          +     *
          +     *  This handler is called when the result from the jabber:iq:auth
          +     *  <iq/> stanza is returned.
          +     *
          +     *  Parameters:
          +     *    (XMLElement) elem - The stanza that triggered the callback.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _auth2_cb: function (elem)
          +    {
          +        if (elem.getAttribute("type") == "result") {
          +            this.authenticated = true;
          +            this._changeConnectStatus(Strophe.Status.CONNECTED, null);
          +        } else if (elem.getAttribute("type") == "error") {
          +            this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
          +            this.disconnect('authentication failed');
          +        }
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: _addSysTimedHandler
          +     *  _Private_ function to add a system level timed handler.
          +     *
          +     *  This function is used to add a Strophe.TimedHandler for the
          +     *  library code.  System timed handlers are allowed to run before
          +     *  authentication is complete.
          +     *
          +     *  Parameters:
          +     *    (Integer) period - The period of the handler.
          +     *    (Function) handler - The callback function.
          +     */
          +    _addSysTimedHandler: function (period, handler)
          +    {
          +        var thand = new Strophe.TimedHandler(period, handler);
          +        thand.user = false;
          +        this.addTimeds.push(thand);
          +        return thand;
          +    },
          +
          +    /** PrivateFunction: _addSysHandler
          +     *  _Private_ function to add a system level stanza handler.
          +     *
          +     *  This function is used to add a Strophe.Handler for the
          +     *  library code.  System stanza handlers are allowed to run before
          +     *  authentication is complete.
          +     *
          +     *  Parameters:
          +     *    (Function) handler - The callback function.
          +     *    (String) ns - The namespace to match.
          +     *    (String) name - The stanza name to match.
          +     *    (String) type - The stanza type attribute to match.
          +     *    (String) id - The stanza id attribute to match.
          +     */
          +    _addSysHandler: function (handler, ns, name, type, id)
          +    {
          +        var hand = new Strophe.Handler(handler, ns, name, type, id);
          +        hand.user = false;
          +        this.addHandlers.push(hand);
          +        return hand;
          +    },
          +
          +    /** PrivateFunction: _onDisconnectTimeout
          +     *  _Private_ timeout handler for handling non-graceful disconnection.
          +     *
          +     *  If the graceful disconnect process does not complete within the
          +     *  time allotted, this handler finishes the disconnect anyway.
          +     *
          +     *  Returns:
          +     *    false to remove the handler.
          +     */
          +    _onDisconnectTimeout: function ()
          +    {
          +        Strophe.info("_onDisconnectTimeout was called");
          +
          +        this._proto._onDisconnectTimeout();
          +
          +        // actually disconnect
          +        this._doDisconnect();
          +
          +        return false;
          +    },
          +
          +    /** PrivateFunction: _onIdle
          +     *  _Private_ handler to process events during idle cycle.
          +     *
          +     *  This handler is called every 100ms to fire timed handlers that
          +     *  are ready and keep poll requests going.
          +     */
          +    _onIdle: function ()
          +    {
          +        var i, thand, since, newList;
          +
          +        // add timed handlers scheduled for addition
          +        // NOTE: we add before remove in the case a timed handler is
          +        // added and then deleted before the next _onIdle() call.
          +        while (this.addTimeds.length > 0) {
          +            this.timedHandlers.push(this.addTimeds.pop());
          +        }
          +
          +        // remove timed handlers that have been scheduled for deletion
          +        while (this.removeTimeds.length > 0) {
          +            thand = this.removeTimeds.pop();
          +            i = this.timedHandlers.indexOf(thand);
          +            if (i >= 0) {
          +                this.timedHandlers.splice(i, 1);
          +            }
          +        }
          +
          +        // call ready timed handlers
          +        var now = new Date().getTime();
          +        newList = [];
          +        for (i = 0; i < this.timedHandlers.length; i++) {
          +            thand = this.timedHandlers[i];
          +            if (this.authenticated || !thand.user) {
          +                since = thand.lastCalled + thand.period;
          +                if (since - now <= 0) {
          +                    if (thand.run()) {
          +                        newList.push(thand);
          +                    }
          +                } else {
          +                    newList.push(thand);
          +                }
          +            }
          +        }
          +        this.timedHandlers = newList;
          +
          +        clearTimeout(this._idleTimeout);
          +
          +        this._proto._onIdle();
          +
          +        // reactivate the timer only if connected
          +        if (this.connected) {
          +            this._idleTimeout = setTimeout(this._onIdle.bind(this), 100);
          +        }
          +    }
          +};
          +
          +if (callback) {
          +    callback(Strophe, $build, $msg, $iq, $pres);
          +}
          +
          +/** Class: Strophe.SASLMechanism
          + *
          + *  encapsulates SASL authentication mechanisms.
          + *
          + *  User code may override the priority for each mechanism or disable it completely.
          + *  See <priority> for information about changing priority and <test> for informatian on
          + *  how to disable a mechanism.
          + *
          + *  By default, all mechanisms are enabled and the priorities are
          + *
          + *  SCRAM-SHA1 - 40
          + *  DIGEST-MD5 - 30
          + *  Plain - 20
          + */
          +
          +/**
          + * PrivateConstructor: Strophe.SASLMechanism
          + * SASL auth mechanism abstraction.
          + *
          + *  Parameters:
          + *    (String) name - SASL Mechanism name.
          + *    (Boolean) isClientFirst - If client should send response first without challenge.
          + *    (Number) priority - Priority.
          + *
          + *  Returns:
          + *    A new Strophe.SASLMechanism object.
          + */
          +Strophe.SASLMechanism = function(name, isClientFirst, priority) {
          +  /** PrivateVariable: name
          +   *  Mechanism name.
          +   */
          +  this.name = name;
          +  /** PrivateVariable: isClientFirst
          +   *  If client sends response without initial server challenge.
          +   */
          +  this.isClientFirst = isClientFirst;
          +  /** Variable: priority
          +   *  Determines which <SASLMechanism> is chosen for authentication (Higher is better).
          +   *  Users may override this to prioritize mechanisms differently.
          +   *
          +   *  In the default configuration the priorities are
          +   *
          +   *  SCRAM-SHA1 - 40
          +   *  DIGEST-MD5 - 30
          +   *  Plain - 20
          +   *
          +   *  Example: (This will cause Strophe to choose the mechanism that the server sent first)
          +   *
          +   *  > Strophe.SASLMD5.priority = Strophe.SASLSHA1.priority;
          +   *
          +   *  See <SASL mechanisms> for a list of available mechanisms.
          +   *
          +   */
          +  this.priority = priority;
          +};
          +
          +Strophe.SASLMechanism.prototype = {
          +  /**
          +   *  Function: test
          +   *  Checks if mechanism able to run.
          +   *  To disable a mechanism, make this return false;
          +   *
          +   *  To disable plain authentication run
          +   *  > Strophe.SASLPlain.test = function() {
          +   *  >   return false;
          +   *  > }
          +   *
          +   *  See <SASL mechanisms> for a list of available mechanisms.
          +   *
          +   *  Parameters:
          +   *    (Strophe.Connection) connection - Target Connection.
          +   *
          +   *  Returns:
          +   *    (Boolean) If mechanism was able to run.
          +   */
          +  /* jshint unused:false */
          +  test: function(connection) {
          +    return true;
          +  },
          +  /* jshint unused:true */
          +
          +  /** PrivateFunction: onStart
          +   *  Called before starting mechanism on some connection.
          +   *
          +   *  Parameters:
          +   *    (Strophe.Connection) connection - Target Connection.
          +   */
          +  onStart: function(connection)
          +  {
          +    this._connection = connection;
          +  },
          +
          +  /** PrivateFunction: onChallenge
          +   *  Called by protocol implementation on incoming challenge. If client is
          +   *  first (isClientFirst == true) challenge will be null on the first call.
          +   *
          +   *  Parameters:
          +   *    (Strophe.Connection) connection - Target Connection.
          +   *    (String) challenge - current challenge to handle.
          +   *
          +   *  Returns:
          +   *    (String) Mechanism response.
          +   */
          +  /* jshint unused:false */
          +  onChallenge: function(connection, challenge) {
          +    throw new Error("You should implement challenge handling!");
          +  },
          +  /* jshint unused:true */
          +
          +  /** PrivateFunction: onFailure
          +   *  Protocol informs mechanism implementation about SASL failure.
          +   */
          +  onFailure: function() {
          +    this._connection = null;
          +  },
          +
          +  /** PrivateFunction: onSuccess
          +   *  Protocol informs mechanism implementation about SASL success.
          +   */
          +  onSuccess: function() {
          +    this._connection = null;
          +  }
          +};
          +
          +  /** Constants: SASL mechanisms
          +   *  Available authentication mechanisms
          +   *
          +   *  Strophe.SASLAnonymous - SASL Anonymous authentication.
          +   *  Strophe.SASLPlain - SASL Plain authentication.
          +   *  Strophe.SASLMD5 - SASL Digest-MD5 authentication
          +   *  Strophe.SASLSHA1 - SASL SCRAM-SHA1 authentication
          +   */
          +
          +// Building SASL callbacks
          +
          +/** PrivateConstructor: SASLAnonymous
          + *  SASL Anonymous authentication.
          + */
          +Strophe.SASLAnonymous = function() {};
          +
          +Strophe.SASLAnonymous.prototype = new Strophe.SASLMechanism("ANONYMOUS", false, 10);
          +
          +Strophe.SASLAnonymous.test = function(connection) {
          +  return connection.authcid === null;
          +};
          +
          +Strophe.Connection.prototype.mechanisms[Strophe.SASLAnonymous.prototype.name] = Strophe.SASLAnonymous;
          +
          +/** PrivateConstructor: SASLPlain
          + *  SASL Plain authentication.
          + */
          +Strophe.SASLPlain = function() {};
          +
          +Strophe.SASLPlain.prototype = new Strophe.SASLMechanism("PLAIN", true, 20);
          +
          +Strophe.SASLPlain.test = function(connection) {
          +  return connection.authcid !== null;
          +};
          +
          +Strophe.SASLPlain.prototype.onChallenge = function(connection) {
          +  var auth_str = connection.authzid;
          +  auth_str = auth_str + "\u0000";
          +  auth_str = auth_str + connection.authcid;
          +  auth_str = auth_str + "\u0000";
          +  auth_str = auth_str + connection.pass;
          +  return auth_str;
          +};
          +
          +Strophe.Connection.prototype.mechanisms[Strophe.SASLPlain.prototype.name] = Strophe.SASLPlain;
          +
          +/** PrivateConstructor: SASLSHA1
          + *  SASL SCRAM SHA 1 authentication.
          + */
          +Strophe.SASLSHA1 = function() {};
          +
          +/* TEST:
          + * This is a simple example of a SCRAM-SHA-1 authentication exchange
          + * when the client doesn't support channel bindings (username 'user' and
          + * password 'pencil' are used):
          + *
          + * C: n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL
          + * S: r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,
          + * i=4096
          + * C: c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,
          + * p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=
          + * S: v=rmF9pqV8S7suAoZWja4dJRkFsKQ=
          + *
          + */
          +
          +Strophe.SASLSHA1.prototype = new Strophe.SASLMechanism("SCRAM-SHA-1", true, 40);
          +
          +Strophe.SASLSHA1.test = function(connection) {
          +  return connection.authcid !== null;
          +};
          +
          +Strophe.SASLSHA1.prototype.onChallenge = function(connection, challenge, test_cnonce) {
          +  var cnonce = test_cnonce || MD5.hexdigest(Math.random() * 1234567890);
          +
          +  var auth_str = "n=" + connection.authcid;
          +  auth_str += ",r=";
          +  auth_str += cnonce;
          +
          +  connection._sasl_data.cnonce = cnonce;
          +  connection._sasl_data["client-first-message-bare"] = auth_str;
          +
          +  auth_str = "n,," + auth_str;
          +
          +  this.onChallenge = function (connection, challenge)
          +  {
          +    var nonce, salt, iter, Hi, U, U_old, i, k;
          +    var clientKey, serverKey, clientSignature;
          +    var responseText = "c=biws,";
          +    var authMessage = connection._sasl_data["client-first-message-bare"] + "," +
          +      challenge + ",";
          +    var cnonce = connection._sasl_data.cnonce;
          +    var attribMatch = /([a-z]+)=([^,]+)(,|$)/;
          +
          +    while (challenge.match(attribMatch)) {
          +      var matches = challenge.match(attribMatch);
          +      challenge = challenge.replace(matches[0], "");
          +      switch (matches[1]) {
          +      case "r":
          +        nonce = matches[2];
          +        break;
          +      case "s":
          +        salt = matches[2];
          +        break;
          +      case "i":
          +        iter = matches[2];
          +        break;
          +      }
          +    }
          +
          +    if (nonce.substr(0, cnonce.length) !== cnonce) {
          +      connection._sasl_data = {};
          +      return connection._sasl_failure_cb();
          +    }
          +
          +    responseText += "r=" + nonce;
          +    authMessage += responseText;
          +
          +    salt = Base64.decode(salt);
          +    salt += "\x00\x00\x00\x01";
          +
          +    Hi = U_old = core_hmac_sha1(connection.pass, salt);
          +    for (i = 1; i < iter; i++) {
          +      U = core_hmac_sha1(connection.pass, binb2str(U_old));
          +      for (k = 0; k < 5; k++) {
          +        Hi[k] ^= U[k];
          +      }
          +      U_old = U;
          +    }
          +    Hi = binb2str(Hi);
          +
          +    clientKey = core_hmac_sha1(Hi, "Client Key");
          +    serverKey = str_hmac_sha1(Hi, "Server Key");
          +    clientSignature = core_hmac_sha1(str_sha1(binb2str(clientKey)), authMessage);
          +    connection._sasl_data["server-signature"] = b64_hmac_sha1(serverKey, authMessage);
          +
          +    for (k = 0; k < 5; k++) {
          +      clientKey[k] ^= clientSignature[k];
          +    }
          +
          +    responseText += ",p=" + Base64.encode(binb2str(clientKey));
          +
          +    return responseText;
          +  }.bind(this);
          +
          +  return auth_str;
          +};
          +
          +Strophe.Connection.prototype.mechanisms[Strophe.SASLSHA1.prototype.name] = Strophe.SASLSHA1;
          +
          +/** PrivateConstructor: SASLMD5
          + *  SASL DIGEST MD5 authentication.
          + */
          +Strophe.SASLMD5 = function() {};
          +
          +Strophe.SASLMD5.prototype = new Strophe.SASLMechanism("DIGEST-MD5", false, 30);
          +
          +Strophe.SASLMD5.test = function(connection) {
          +  return connection.authcid !== null;
          +};
          +
          +/** PrivateFunction: _quote
          + *  _Private_ utility function to backslash escape and quote strings.
          + *
          + *  Parameters:
          + *    (String) str - The string to be quoted.
          + *
          + *  Returns:
          + *    quoted string
          + */
          +Strophe.SASLMD5.prototype._quote = function (str)
          +  {
          +    return '"' + str.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '"';
          +    //" end string workaround for emacs
          +  };
          +
          +
          +Strophe.SASLMD5.prototype.onChallenge = function(connection, challenge, test_cnonce) {
          +  var attribMatch = /([a-z]+)=("[^"]+"|[^,"]+)(?:,|$)/;
          +  var cnonce = test_cnonce || MD5.hexdigest("" + (Math.random() * 1234567890));
          +  var realm = "";
          +  var host = null;
          +  var nonce = "";
          +  var qop = "";
          +  var matches;
          +
          +  while (challenge.match(attribMatch)) {
          +    matches = challenge.match(attribMatch);
          +    challenge = challenge.replace(matches[0], "");
          +    matches[2] = matches[2].replace(/^"(.+)"$/, "$1");
          +    switch (matches[1]) {
          +    case "realm":
          +      realm = matches[2];
          +      break;
          +    case "nonce":
          +      nonce = matches[2];
          +      break;
          +    case "qop":
          +      qop = matches[2];
          +      break;
          +    case "host":
          +      host = matches[2];
          +      break;
          +    }
          +  }
          +
          +  var digest_uri = connection.servtype + "/" + connection.domain;
          +  if (host !== null) {
          +    digest_uri = digest_uri + "/" + host;
          +  }
          +
          +  var A1 = MD5.hash(connection.authcid +
          +                    ":" + realm + ":" + this._connection.pass) +
          +    ":" + nonce + ":" + cnonce;
          +  var A2 = 'AUTHENTICATE:' + digest_uri;
          +
          +  var responseText = "";
          +  responseText += 'charset=utf-8,';
          +  responseText += 'username=' +
          +    this._quote(connection.authcid) + ',';
          +  responseText += 'realm=' + this._quote(realm) + ',';
          +  responseText += 'nonce=' + this._quote(nonce) + ',';
          +  responseText += 'nc=00000001,';
          +  responseText += 'cnonce=' + this._quote(cnonce) + ',';
          +  responseText += 'digest-uri=' + this._quote(digest_uri) + ',';
          +  responseText += 'response=' + MD5.hexdigest(MD5.hexdigest(A1) + ":" +
          +                                              nonce + ":00000001:" +
          +                                              cnonce + ":auth:" +
          +                                              MD5.hexdigest(A2)) + ",";
          +  responseText += 'qop=auth';
          +
          +  this.onChallenge = function ()
          +  {
          +    return "";
          +  }.bind(this);
          +
          +  return responseText;
          +};
          +
          +Strophe.Connection.prototype.mechanisms[Strophe.SASLMD5.prototype.name] = Strophe.SASLMD5;
          +
          +})(function () {
          +    window.Strophe = arguments[0];
          +    window.$build = arguments[1];
          +    window.$msg = arguments[2];
          +    window.$iq = arguments[3];
          +    window.$pres = arguments[4];
          +});
          +
          +/*
          +    This program is distributed under the terms of the MIT license.
          +    Please see the LICENSE file for details.
          +
          +    Copyright 2006-2008, OGG, LLC
          +*/
          +
          +/* jshint undef: true, unused: true:, noarg: true, latedef: true */
          +/*global window, setTimeout, clearTimeout,
          +    XMLHttpRequest, ActiveXObject,
          +    Strophe, $build */
          +
          +
          +/** PrivateClass: Strophe.Request
          + *  _Private_ helper class that provides a cross implementation abstraction
          + *  for a BOSH related XMLHttpRequest.
          + *
          + *  The Strophe.Request class is used internally to encapsulate BOSH request
          + *  information.  It is not meant to be used from user's code.
          + */
          +
          +/** PrivateConstructor: Strophe.Request
          + *  Create and initialize a new Strophe.Request object.
          + *
          + *  Parameters:
          + *    (XMLElement) elem - The XML data to be sent in the request.
          + *    (Function) func - The function that will be called when the
          + *      XMLHttpRequest readyState changes.
          + *    (Integer) rid - The BOSH rid attribute associated with this request.
          + *    (Integer) sends - The number of times this same request has been
          + *      sent.
          + */
          +Strophe.Request = function (elem, func, rid, sends)
          +{
          +    this.id = ++Strophe._requestId;
          +    this.xmlData = elem;
          +    this.data = Strophe.serialize(elem);
          +    // save original function in case we need to make a new request
          +    // from this one.
          +    this.origFunc = func;
          +    this.func = func;
          +    this.rid = rid;
          +    this.date = NaN;
          +    this.sends = sends || 0;
          +    this.abort = false;
          +    this.dead = null;
          +
          +    this.age = function () {
          +        if (!this.date) { return 0; }
          +        var now = new Date();
          +        return (now - this.date) / 1000;
          +    };
          +    this.timeDead = function () {
          +        if (!this.dead) { return 0; }
          +        var now = new Date();
          +        return (now - this.dead) / 1000;
          +    };
          +    this.xhr = this._newXHR();
          +};
          +
          +Strophe.Request.prototype = {
          +    /** PrivateFunction: getResponse
          +     *  Get a response from the underlying XMLHttpRequest.
          +     *
          +     *  This function attempts to get a response from the request and checks
          +     *  for errors.
          +     *
          +     *  Throws:
          +     *    "parsererror" - A parser error occured.
          +     *
          +     *  Returns:
          +     *    The DOM element tree of the response.
          +     */
          +    getResponse: function ()
          +    {
          +        var node = null;
          +        if (this.xhr.responseXML && this.xhr.responseXML.documentElement) {
          +            node = this.xhr.responseXML.documentElement;
          +            if (node.tagName == "parsererror") {
          +                Strophe.error("invalid response received");
          +                Strophe.error("responseText: " + this.xhr.responseText);
          +                Strophe.error("responseXML: " +
          +                              Strophe.serialize(this.xhr.responseXML));
          +                throw "parsererror";
          +            }
          +        } else if (this.xhr.responseText) {
          +            Strophe.error("invalid response received");
          +            Strophe.error("responseText: " + this.xhr.responseText);
          +            Strophe.error("responseXML: " +
          +                          Strophe.serialize(this.xhr.responseXML));
          +        }
          +
          +        return node;
          +    },
          +
          +    /** PrivateFunction: _newXHR
          +     *  _Private_ helper function to create XMLHttpRequests.
          +     *
          +     *  This function creates XMLHttpRequests across all implementations.
          +     *
          +     *  Returns:
          +     *    A new XMLHttpRequest.
          +     */
          +    _newXHR: function ()
          +    {
          +        var xhr = null;
          +        if (window.XMLHttpRequest) {
          +            xhr = new XMLHttpRequest();
          +            if (xhr.overrideMimeType) {
          +                xhr.overrideMimeType("text/xml");
          +            }
          +        } else if (window.ActiveXObject) {
          +            xhr = new ActiveXObject("Microsoft.XMLHTTP");
          +        }
          +
          +        // use Function.bind() to prepend ourselves as an argument
          +        xhr.onreadystatechange = this.func.bind(null, this);
          +
          +        return xhr;
          +    }
          +};
          +
          +/** Class: Strophe.Bosh
          + *  _Private_ helper class that handles BOSH Connections
          + *
          + *  The Strophe.Bosh class is used internally by Strophe.Connection
          + *  to encapsulate BOSH sessions. It is not meant to be used from user's code.
          + */
          +
          +/** File: bosh.js
          + *  A JavaScript library to enable BOSH in Strophejs.
          + *
          + *  this library uses Bidirectional-streams Over Synchronous HTTP (BOSH)
          + *  to emulate a persistent, stateful, two-way connection to an XMPP server.
          + *  More information on BOSH can be found in XEP 124.
          + */
          +
          +/** PrivateConstructor: Strophe.Bosh
          + *  Create and initialize a Strophe.Bosh object.
          + *
          + *  Parameters:
          + *    (Strophe.Connection) connection - The Strophe.Connection that will use BOSH.
          + *
          + *  Returns:
          + *    A new Strophe.Bosh object.
          + */
          +Strophe.Bosh = function(connection) {
          +    this._conn = connection;
          +    /* request id for body tags */
          +    this.rid = Math.floor(Math.random() * 4294967295);
          +    /* The current session ID. */
          +    this.sid = null;
          +
          +    // default BOSH values
          +    this.hold = 1;
          +    this.wait = 60;
          +    this.window = 5;
          +
          +    this._requests = [];
          +};
          +
          +Strophe.Bosh.prototype = {
          +    /** Variable: strip
          +     *
          +     *  BOSH-Connections will have all stanzas wrapped in a <body> tag when
          +     *  passed to <Strophe.Connection.xmlInput> or <Strophe.Connection.xmlOutput>.
          +     *  To strip this tag, User code can set <Strophe.Bosh.strip> to "body":
          +     *
          +     *  > Strophe.Bosh.prototype.strip = "body";
          +     *
          +     *  This will enable stripping of the body tag in both
          +     *  <Strophe.Connection.xmlInput> and <Strophe.Connection.xmlOutput>.
          +     */
          +    strip: null,
          +
          +    /** PrivateFunction: _buildBody
          +     *  _Private_ helper function to generate the <body/> wrapper for BOSH.
          +     *
          +     *  Returns:
          +     *    A Strophe.Builder with a <body/> element.
          +     */
          +    _buildBody: function ()
          +    {
          +        var bodyWrap = $build('body', {
          +            rid: this.rid++,
          +            xmlns: Strophe.NS.HTTPBIND
          +        });
          +
          +        if (this.sid !== null) {
          +            bodyWrap.attrs({sid: this.sid});
          +        }
          +
          +        return bodyWrap;
          +    },
          +
          +    /** PrivateFunction: _reset
          +     *  Reset the connection.
          +     *
          +     *  This function is called by the reset function of the Strophe Connection
          +     */
          +    _reset: function ()
          +    {
          +        this.rid = Math.floor(Math.random() * 4294967295);
          +        this.sid = null;
          +    },
          +
          +    /** PrivateFunction: _connect
          +     *  _Private_ function that initializes the BOSH connection.
          +     *
          +     *  Creates and sends the Request that initializes the BOSH connection.
          +     */
          +    _connect: function (wait, hold, route)
          +    {
          +        this.wait = wait || this.wait;
          +        this.hold = hold || this.hold;
          +
          +        // build the body tag
          +        var body = this._buildBody().attrs({
          +            to: this._conn.domain,
          +            "xml:lang": "en",
          +            wait: this.wait,
          +            hold: this.hold,
          +            content: "text/xml; charset=utf-8",
          +            ver: "1.6",
          +            "xmpp:version": "1.0",
          +            "xmlns:xmpp": Strophe.NS.BOSH
          +        });
          +
          +        if(route){
          +            body.attrs({
          +                route: route
          +            });
          +        }
          +
          +        var _connect_cb = this._conn._connect_cb;
          +
          +        this._requests.push(
          +            new Strophe.Request(body.tree(),
          +                                this._onRequestStateChange.bind(
          +                                    this, _connect_cb.bind(this._conn)),
          +                                body.tree().getAttribute("rid")));
          +        this._throttledRequestHandler();
          +    },
          +
          +    /** PrivateFunction: _attach
          +     *  Attach to an already created and authenticated BOSH session.
          +     *
          +     *  This function is provided to allow Strophe to attach to BOSH
          +     *  sessions which have been created externally, perhaps by a Web
          +     *  application.  This is often used to support auto-login type features
          +     *  without putting user credentials into the page.
          +     *
          +     *  Parameters:
          +     *    (String) jid - The full JID that is bound by the session.
          +     *    (String) sid - The SID of the BOSH session.
          +     *    (String) rid - The current RID of the BOSH session.  This RID
          +     *      will be used by the next request.
          +     *    (Function) callback The connect callback function.
          +     *    (Integer) wait - The optional HTTPBIND wait value.  This is the
          +     *      time the server will wait before returning an empty result for
          +     *      a request.  The default setting of 60 seconds is recommended.
          +     *      Other settings will require tweaks to the Strophe.TIMEOUT value.
          +     *    (Integer) hold - The optional HTTPBIND hold value.  This is the
          +     *      number of connections the server will hold at one time.  This
          +     *      should almost always be set to 1 (the default).
          +     *    (Integer) wind - The optional HTTBIND window value.  This is the
          +     *      allowed range of request ids that are valid.  The default is 5.
          +     */
          +    _attach: function (jid, sid, rid, callback, wait, hold, wind)
          +    {
          +        this._conn.jid = jid;
          +        this.sid = sid;
          +        this.rid = rid;
          +
          +        this._conn.connect_callback = callback;
          +
          +        this._conn.domain = Strophe.getDomainFromJid(this._conn.jid);
          +
          +        this._conn.authenticated = true;
          +        this._conn.connected = true;
          +
          +        this.wait = wait || this.wait;
          +        this.hold = hold || this.hold;
          +        this.window = wind || this.window;
          +
          +        this._conn._changeConnectStatus(Strophe.Status.ATTACHED, null);
          +    },
          +
          +    /** PrivateFunction: _connect_cb
          +     *  _Private_ handler for initial connection request.
          +     *
          +     *  This handler is used to process the Bosh-part of the initial request.
          +     *  Parameters:
          +     *    (Strophe.Request) bodyWrap - The received stanza.
          +     */
          +    _connect_cb: function (bodyWrap)
          +    {
          +        var typ = bodyWrap.getAttribute("type");
          +        var cond, conflict;
          +        if (typ !== null && typ == "terminate") {
          +            // an error occurred
          +            Strophe.error("BOSH-Connection failed: " + cond);
          +            cond = bodyWrap.getAttribute("condition");
          +            conflict = bodyWrap.getElementsByTagName("conflict");
          +            if (cond !== null) {
          +                if (cond == "remote-stream-error" && conflict.length > 0) {
          +                    cond = "conflict";
          +                }
          +                this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, cond);
          +            } else {
          +                this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "unknown");
          +            }
          +            this._conn._doDisconnect();
          +            return Strophe.Status.CONNFAIL;
          +        }
          +
          +        // check to make sure we don't overwrite these if _connect_cb is
          +        // called multiple times in the case of missing stream:features
          +        if (!this.sid) {
          +            this.sid = bodyWrap.getAttribute("sid");
          +        }
          +        var wind = bodyWrap.getAttribute('requests');
          +        if (wind) { this.window = parseInt(wind, 10); }
          +        var hold = bodyWrap.getAttribute('hold');
          +        if (hold) { this.hold = parseInt(hold, 10); }
          +        var wait = bodyWrap.getAttribute('wait');
          +        if (wait) { this.wait = parseInt(wait, 10); }
          +    },
          +
          +    /** PrivateFunction: _disconnect
          +     *  _Private_ part of Connection.disconnect for Bosh
          +     *
          +     *  Parameters:
          +     *    (Request) pres - This stanza will be sent before disconnecting.
          +     */
          +    _disconnect: function (pres)
          +    {
          +        this._sendTerminate(pres);
          +    },
          +
          +    /** PrivateFunction: _doDisconnect
          +     *  _Private_ function to disconnect.
          +     *
          +     *  Resets the SID and RID.
          +     */
          +    _doDisconnect: function ()
          +    {
          +        this.sid = null;
          +        this.rid = Math.floor(Math.random() * 4294967295);
          +    },
          +
          +    /** PrivateFunction: _emptyQueue
          +     * _Private_ function to check if the Request queue is empty.
          +     *
          +     *  Returns:
          +     *    True, if there are no Requests queued, False otherwise.
          +     */
          +    _emptyQueue: function ()
          +    {
          +        return this._requests.length === 0;
          +    },
          +
          +    /** PrivateFunction: _hitError
          +     *  _Private_ function to handle the error count.
          +     *
          +     *  Requests are resent automatically until their error count reaches
          +     *  5.  Each time an error is encountered, this function is called to
          +     *  increment the count and disconnect if the count is too high.
          +     *
          +     *  Parameters:
          +     *    (Integer) reqStatus - The request status.
          +     */
          +    _hitError: function (reqStatus)
          +    {
          +        this.errors++;
          +        Strophe.warn("request errored, status: " + reqStatus +
          +                     ", number of errors: " + this.errors);
          +        if (this.errors > 4) {
          +            this._onDisconnectTimeout();
          +        }
          +    },
          +
          +    /** PrivateFunction: _no_auth_received
          +     *
          +     * Called on stream start/restart when no stream:features
          +     * has been received and sends a blank poll request.
          +     */
          +    _no_auth_received: function (_callback)
          +    {
          +        if (_callback) {
          +            _callback = _callback.bind(this._conn);
          +        } else {
          +            _callback = this._conn._connect_cb.bind(this._conn);
          +        }
          +        var body = this._buildBody();
          +        this._requests.push(
          +                new Strophe.Request(body.tree(),
          +                    this._onRequestStateChange.bind(
          +                        this, _callback.bind(this._conn)),
          +                    body.tree().getAttribute("rid")));
          +        this._throttledRequestHandler();
          +    },
          +
          +    /** PrivateFunction: _onDisconnectTimeout
          +     *  _Private_ timeout handler for handling non-graceful disconnection.
          +     *
          +     *  Cancels all remaining Requests and clears the queue.
          +     */
          +    _onDisconnectTimeout: function ()
          +    {
          +        var req;
          +        while (this._requests.length > 0) {
          +            req = this._requests.pop();
          +            req.abort = true;
          +            req.xhr.abort();
          +            // jslint complains, but this is fine. setting to empty func
          +            // is necessary for IE6
          +            req.xhr.onreadystatechange = function () {}; // jshint ignore:line
          +        }
          +    },
          +
          +    /** PrivateFunction: _onIdle
          +     *  _Private_ handler called by Strophe.Connection._onIdle
          +     *
          +     *  Sends all queued Requests or polls with empty Request if there are none.
          +     */
          +    _onIdle: function () {
          +        var data = this._conn._data;
          +
          +        // if no requests are in progress, poll
          +        if (this._conn.authenticated && this._requests.length === 0 &&
          +            data.length === 0 && !this._conn.disconnecting) {
          +            Strophe.info("no requests during idle cycle, sending " +
          +                         "blank request");
          +            data.push(null);
          +        }
          +
          +        if (this._requests.length < 2 && data.length > 0 &&
          +            !this._conn.paused) {
          +            var body = this._buildBody();
          +            for (var i = 0; i < data.length; i++) {
          +                if (data[i] !== null) {
          +                    if (data[i] === "restart") {
          +                        body.attrs({
          +                            to: this._conn.domain,
          +                            "xml:lang": "en",
          +                            "xmpp:restart": "true",
          +                            "xmlns:xmpp": Strophe.NS.BOSH
          +                        });
          +                    } else {
          +                        body.cnode(data[i]).up();
          +                    }
          +                }
          +            }
          +            delete this._conn._data;
          +            this._conn._data = [];
          +            this._requests.push(
          +                new Strophe.Request(body.tree(),
          +                                    this._onRequestStateChange.bind(
          +                                        this, this._conn._dataRecv.bind(this._conn)),
          +                                    body.tree().getAttribute("rid")));
          +            this._processRequest(this._requests.length - 1);
          +        }
          +
          +        if (this._requests.length > 0) {
          +            var time_elapsed = this._requests[0].age();
          +            if (this._requests[0].dead !== null) {
          +                if (this._requests[0].timeDead() >
          +                    Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait)) {
          +                    this._throttledRequestHandler();
          +                }
          +            }
          +
          +            if (time_elapsed > Math.floor(Strophe.TIMEOUT * this.wait)) {
          +                Strophe.warn("Request " +
          +                             this._requests[0].id +
          +                             " timed out, over " + Math.floor(Strophe.TIMEOUT * this.wait) +
          +                             " seconds since last activity");
          +                this._throttledRequestHandler();
          +            }
          +        }
          +    },
          +
          +    /** PrivateFunction: _onRequestStateChange
          +     *  _Private_ handler for Strophe.Request state changes.
          +     *
          +     *  This function is called when the XMLHttpRequest readyState changes.
          +     *  It contains a lot of error handling logic for the many ways that
          +     *  requests can fail, and calls the request callback when requests
          +     *  succeed.
          +     *
          +     *  Parameters:
          +     *    (Function) func - The handler for the request.
          +     *    (Strophe.Request) req - The request that is changing readyState.
          +     */
          +    _onRequestStateChange: function (func, req)
          +    {
          +        Strophe.debug("request id " + req.id +
          +                      "." + req.sends + " state changed to " +
          +                      req.xhr.readyState);
          +
          +        if (req.abort) {
          +            req.abort = false;
          +            return;
          +        }
          +
          +        // request complete
          +        var reqStatus;
          +        if (req.xhr.readyState == 4) {
          +            reqStatus = 0;
          +            try {
          +                reqStatus = req.xhr.status;
          +            } catch (e) {
          +                // ignore errors from undefined status attribute.  works
          +                // around a browser bug
          +            }
          +
          +            if (typeof(reqStatus) == "undefined") {
          +                reqStatus = 0;
          +            }
          +
          +            if (this.disconnecting) {
          +                if (reqStatus >= 400) {
          +                    this._hitError(reqStatus);
          +                    return;
          +                }
          +            }
          +
          +            var reqIs0 = (this._requests[0] == req);
          +            var reqIs1 = (this._requests[1] == req);
          +
          +            if ((reqStatus > 0 && reqStatus < 500) || req.sends > 5) {
          +                // remove from internal queue
          +                this._removeRequest(req);
          +                Strophe.debug("request id " +
          +                              req.id +
          +                              " should now be removed");
          +            }
          +
          +            // request succeeded
          +            if (reqStatus == 200) {
          +                // if request 1 finished, or request 0 finished and request
          +                // 1 is over Strophe.SECONDARY_TIMEOUT seconds old, we need to
          +                // restart the other - both will be in the first spot, as the
          +                // completed request has been removed from the queue already
          +                if (reqIs1 ||
          +                    (reqIs0 && this._requests.length > 0 &&
          +                     this._requests[0].age() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait))) {
          +                    this._restartRequest(0);
          +                }
          +                // call handler
          +                Strophe.debug("request id " +
          +                              req.id + "." +
          +                              req.sends + " got 200");
          +                func(req);
          +                this.errors = 0;
          +            } else {
          +                Strophe.error("request id " +
          +                              req.id + "." +
          +                              req.sends + " error " + reqStatus +
          +                              " happened");
          +                if (reqStatus === 0 ||
          +                    (reqStatus >= 400 && reqStatus < 600) ||
          +                    reqStatus >= 12000) {
          +                    this._hitError(reqStatus);
          +                    if (reqStatus >= 400 && reqStatus < 500) {
          +                        this._conn._changeConnectStatus(Strophe.Status.DISCONNECTING,
          +                                                  null);
          +                        this._conn._doDisconnect();
          +                    }
          +                }
          +            }
          +
          +            if (!((reqStatus > 0 && reqStatus < 500) ||
          +                  req.sends > 5)) {
          +                this._throttledRequestHandler();
          +            }
          +        }
          +    },
          +
          +    /** PrivateFunction: _processRequest
          +     *  _Private_ function to process a request in the queue.
          +     *
          +     *  This function takes requests off the queue and sends them and
          +     *  restarts dead requests.
          +     *
          +     *  Parameters:
          +     *    (Integer) i - The index of the request in the queue.
          +     */
          +    _processRequest: function (i)
          +    {
          +        var self = this;
          +        var req = this._requests[i];
          +        var reqStatus = -1;
          +
          +        try {
          +            if (req.xhr.readyState == 4) {
          +                reqStatus = req.xhr.status;
          +            }
          +        } catch (e) {
          +            Strophe.error("caught an error in _requests[" + i +
          +                          "], reqStatus: " + reqStatus);
          +        }
          +
          +        if (typeof(reqStatus) == "undefined") {
          +            reqStatus = -1;
          +        }
          +
          +        // make sure we limit the number of retries
          +        if (req.sends > this.maxRetries) {
          +            this._onDisconnectTimeout();
          +            return;
          +        }
          +
          +        var time_elapsed = req.age();
          +        var primaryTimeout = (!isNaN(time_elapsed) &&
          +                              time_elapsed > Math.floor(Strophe.TIMEOUT * this.wait));
          +        var secondaryTimeout = (req.dead !== null &&
          +                                req.timeDead() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait));
          +        var requestCompletedWithServerError = (req.xhr.readyState == 4 &&
          +                                               (reqStatus < 1 ||
          +                                                reqStatus >= 500));
          +        if (primaryTimeout || secondaryTimeout ||
          +            requestCompletedWithServerError) {
          +            if (secondaryTimeout) {
          +                Strophe.error("Request " +
          +                              this._requests[i].id +
          +                              " timed out (secondary), restarting");
          +            }
          +            req.abort = true;
          +            req.xhr.abort();
          +            // setting to null fails on IE6, so set to empty function
          +            req.xhr.onreadystatechange = function () {};
          +            this._requests[i] = new Strophe.Request(req.xmlData,
          +                                                    req.origFunc,
          +                                                    req.rid,
          +                                                    req.sends);
          +            req = this._requests[i];
          +        }
          +
          +        if (req.xhr.readyState === 0) {
          +            Strophe.debug("request id " + req.id +
          +                          "." + req.sends + " posting");
          +
          +            try {
          +                req.xhr.open("POST", this._conn.service, this._conn.options.sync ? false : true);
          +            } catch (e2) {
          +                Strophe.error("XHR open failed.");
          +                if (!this._conn.connected) {
          +                    this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,
          +                                              "bad-service");
          +                }
          +                this._conn.disconnect();
          +                return;
          +            }
          +
          +            // Fires the XHR request -- may be invoked immediately
          +            // or on a gradually expanding retry window for reconnects
          +            var sendFunc = function () {
          +                req.date = new Date();
          +                if (self._conn.options.customHeaders){
          +                    var headers = self._conn.options.customHeaders;
          +                    for (var header in headers) {
          +                        if (headers.hasOwnProperty(header)) {
          +                            req.xhr.setRequestHeader(header, headers[header]);
          +                        }
          +                    }
          +                }
          +                req.xhr.send(req.data);
          +            };
          +
          +            // Implement progressive backoff for reconnects --
          +            // First retry (send == 1) should also be instantaneous
          +            if (req.sends > 1) {
          +                // Using a cube of the retry number creates a nicely
          +                // expanding retry window
          +                var backoff = Math.min(Math.floor(Strophe.TIMEOUT * this.wait),
          +                                       Math.pow(req.sends, 3)) * 1000;
          +                setTimeout(sendFunc, backoff);
          +            } else {
          +                sendFunc();
          +            }
          +
          +            req.sends++;
          +
          +            if (this._conn.xmlOutput !== Strophe.Connection.prototype.xmlOutput) {
          +                if (req.xmlData.nodeName === this.strip && req.xmlData.childNodes.length) {
          +                    this._conn.xmlOutput(req.xmlData.childNodes[0]);
          +                } else {
          +                    this._conn.xmlOutput(req.xmlData);
          +                }
          +            }
          +            if (this._conn.rawOutput !== Strophe.Connection.prototype.rawOutput) {
          +                this._conn.rawOutput(req.data);
          +            }
          +        } else {
          +            Strophe.debug("_processRequest: " +
          +                          (i === 0 ? "first" : "second") +
          +                          " request has readyState of " +
          +                          req.xhr.readyState);
          +        }
          +    },
          +
          +    /** PrivateFunction: _removeRequest
          +     *  _Private_ function to remove a request from the queue.
          +     *
          +     *  Parameters:
          +     *    (Strophe.Request) req - The request to remove.
          +     */
          +    _removeRequest: function (req)
          +    {
          +        Strophe.debug("removing request");
          +
          +        var i;
          +        for (i = this._requests.length - 1; i >= 0; i--) {
          +            if (req == this._requests[i]) {
          +                this._requests.splice(i, 1);
          +            }
          +        }
          +
          +        // IE6 fails on setting to null, so set to empty function
          +        req.xhr.onreadystatechange = function () {};
          +
          +        this._throttledRequestHandler();
          +    },
          +
          +    /** PrivateFunction: _restartRequest
          +     *  _Private_ function to restart a request that is presumed dead.
          +     *
          +     *  Parameters:
          +     *    (Integer) i - The index of the request in the queue.
          +     */
          +    _restartRequest: function (i)
          +    {
          +        var req = this._requests[i];
          +        if (req.dead === null) {
          +            req.dead = new Date();
          +        }
          +
          +        this._processRequest(i);
          +    },
          +
          +    /** PrivateFunction: _reqToData
          +     * _Private_ function to get a stanza out of a request.
          +     *
          +     * Tries to extract a stanza out of a Request Object.
          +     * When this fails the current connection will be disconnected.
          +     *
          +     *  Parameters:
          +     *    (Object) req - The Request.
          +     *
          +     *  Returns:
          +     *    The stanza that was passed.
          +     */
          +    _reqToData: function (req)
          +    {
          +        try {
          +            return req.getResponse();
          +        } catch (e) {
          +            if (e != "parsererror") { throw e; }
          +            this._conn.disconnect("strophe-parsererror");
          +        }
          +    },
          +
          +    /** PrivateFunction: _sendTerminate
          +     *  _Private_ function to send initial disconnect sequence.
          +     *
          +     *  This is the first step in a graceful disconnect.  It sends
          +     *  the BOSH server a terminate body and includes an unavailable
          +     *  presence if authentication has completed.
          +     */
          +    _sendTerminate: function (pres)
          +    {
          +        Strophe.info("_sendTerminate was called");
          +        var body = this._buildBody().attrs({type: "terminate"});
          +
          +        if (pres) {
          +            body.cnode(pres.tree());
          +        }
          +
          +        var req = new Strophe.Request(body.tree(),
          +                                      this._onRequestStateChange.bind(
          +                                          this, this._conn._dataRecv.bind(this._conn)),
          +                                      body.tree().getAttribute("rid"));
          +
          +        this._requests.push(req);
          +        this._throttledRequestHandler();
          +    },
          +
          +    /** PrivateFunction: _send
          +     *  _Private_ part of the Connection.send function for BOSH
          +     *
          +     * Just triggers the RequestHandler to send the messages that are in the queue
          +     */
          +    _send: function () {
          +        clearTimeout(this._conn._idleTimeout);
          +        this._throttledRequestHandler();
          +        this._conn._idleTimeout = setTimeout(this._conn._onIdle.bind(this._conn), 100);
          +    },
          +
          +    /** PrivateFunction: _sendRestart
          +     *
          +     *  Send an xmpp:restart stanza.
          +     */
          +    _sendRestart: function ()
          +    {
          +        this._throttledRequestHandler();
          +        clearTimeout(this._conn._idleTimeout);
          +    },
          +
          +    /** PrivateFunction: _throttledRequestHandler
          +     *  _Private_ function to throttle requests to the connection window.
          +     *
          +     *  This function makes sure we don't send requests so fast that the
          +     *  request ids overflow the connection window in the case that one
          +     *  request died.
          +     */
          +    _throttledRequestHandler: function ()
          +    {
          +        if (!this._requests) {
          +            Strophe.debug("_throttledRequestHandler called with " +
          +                          "undefined requests");
          +        } else {
          +            Strophe.debug("_throttledRequestHandler called with " +
          +                          this._requests.length + " requests");
          +        }
          +
          +        if (!this._requests || this._requests.length === 0) {
          +            return;
          +        }
          +
          +        if (this._requests.length > 0) {
          +            this._processRequest(0);
          +        }
          +
          +        if (this._requests.length > 1 &&
          +            Math.abs(this._requests[0].rid -
          +                     this._requests[1].rid) < this.window) {
          +            this._processRequest(1);
          +        }
          +    }
          +};
          +
          +/*
          +    This program is distributed under the terms of the MIT license.
          +    Please see the LICENSE file for details.
          +
          +    Copyright 2006-2008, OGG, LLC
          +*/
          +
          +/* jshint undef: true, unused: true:, noarg: true, latedef: true */
          +/*global document, window, clearTimeout, WebSocket,
          +    DOMParser, Strophe, $build */
          +
          +/** Class: Strophe.WebSocket
          + *  _Private_ helper class that handles WebSocket Connections
          + *
          + *  The Strophe.WebSocket class is used internally by Strophe.Connection
          + *  to encapsulate WebSocket sessions. It is not meant to be used from user's code.
          + */
          +
          +/** File: websocket.js
          + *  A JavaScript library to enable XMPP over Websocket in Strophejs.
          + *
          + *  This file implements XMPP over WebSockets for Strophejs.
          + *  If a Connection is established with a Websocket url (ws://...)
          + *  Strophe will use WebSockets.
          + *  For more information on XMPP-over WebSocket see this RFC draft:
          + *  http://tools.ietf.org/html/draft-ietf-xmpp-websocket-00
          + *
          + *  WebSocket support implemented by Andreas Guth (andreas.guth@rwth-aachen.de)
          + */
          +
          +/** PrivateConstructor: Strophe.Websocket
          + *  Create and initialize a Strophe.WebSocket object.
          + *  Currently only sets the connection Object.
          + *
          + *  Parameters:
          + *    (Strophe.Connection) connection - The Strophe.Connection that will use WebSockets.
          + *
          + *  Returns:
          + *    A new Strophe.WebSocket object.
          + */
          +Strophe.Websocket = function(connection) {
          +    this._conn = connection;
          +    this.strip = "stream:stream";
          +
          +    var service = connection.service;
          +    if (service.indexOf("ws:") !== 0 && service.indexOf("wss:") !== 0) {
          +        // If the service is not an absolute URL, assume it is a path and put the absolute
          +        // URL together from options, current URL and the path.
          +        var new_service = "";
          +
          +        if (connection.options.protocol === "ws" && window.location.protocol !== "https:") {
          +            new_service += "ws";
          +        } else {
          +            new_service += "wss";
          +        }
          +
          +        new_service += "://" + window.location.host;
          +
          +        if (service.indexOf("/") !== 0) {
          +            new_service += window.location.pathname + service;
          +        } else {
          +            new_service += service;
          +        }
          +
          +        connection.service = new_service;
          +    }
          +};
          +
          +Strophe.Websocket.prototype = {
          +    /** PrivateFunction: _buildStream
          +     *  _Private_ helper function to generate the <stream> start tag for WebSockets
          +     *
          +     *  Returns:
          +     *    A Strophe.Builder with a <stream> element.
          +     */
          +    _buildStream: function ()
          +    {
          +        return $build("stream:stream", {
          +            "to": this._conn.domain,
          +            "xmlns": Strophe.NS.CLIENT,
          +            "xmlns:stream": Strophe.NS.STREAM,
          +            "version": '1.0'
          +        });
          +    },
          +
          +    /** PrivateFunction: _check_streamerror
          +     * _Private_ checks a message for stream:error
          +     *
          +     *  Parameters:
          +     *    (Strophe.Request) bodyWrap - The received stanza.
          +     *    connectstatus - The ConnectStatus that will be set on error.
          +     *  Returns:
          +     *     true if there was a streamerror, false otherwise.
          +     */
          +    _check_streamerror: function (bodyWrap, connectstatus) {
          +        var errors = bodyWrap.getElementsByTagName("stream:error");
          +        if (errors.length === 0) {
          +            return false;
          +        }
          +        var error = errors[0];
          +
          +        var condition = "";
          +        var text = "";
          +
          +        var ns = "urn:ietf:params:xml:ns:xmpp-streams";
          +        for (var i = 0; i < error.childNodes.length; i++) {
          +            var e = error.childNodes[i];
          +            if (e.getAttribute("xmlns") !== ns) {
          +                break;
          +            } if (e.nodeName === "text") {
          +                text = e.textContent;
          +            } else {
          +                condition = e.nodeName;
          +            }
          +        }
          +
          +        var errorString = "WebSocket stream error: ";
          +
          +        if (condition) {
          +            errorString += condition;
          +        } else {
          +            errorString += "unknown";
          +        }
          +
          +        if (text) {
          +            errorString += " - " + condition;
          +        }
          +
          +        Strophe.error(errorString);
          +
          +        // close the connection on stream_error
          +        this._conn._changeConnectStatus(connectstatus, condition);
          +        this._conn._doDisconnect();
          +        return true;
          +    },
          +
          +    /** PrivateFunction: _reset
          +     *  Reset the connection.
          +     *
          +     *  This function is called by the reset function of the Strophe Connection.
          +     *  Is not needed by WebSockets.
          +     */
          +    _reset: function ()
          +    {
          +        return;
          +    },
          +
          +    /** PrivateFunction: _connect
          +     *  _Private_ function called by Strophe.Connection.connect
          +     *
          +     *  Creates a WebSocket for a connection and assigns Callbacks to it.
          +     *  Does nothing if there already is a WebSocket.
          +     */
          +    _connect: function () {
          +        // Ensure that there is no open WebSocket from a previous Connection.
          +        this._closeSocket();
          +
          +        // Create the new WobSocket
          +        this.socket = new WebSocket(this._conn.service, "xmpp");
          +        this.socket.onopen = this._onOpen.bind(this);
          +        this.socket.onerror = this._onError.bind(this);
          +        this.socket.onclose = this._onClose.bind(this);
          +        this.socket.onmessage = this._connect_cb_wrapper.bind(this);
          +    },
          +
          +    /** PrivateFunction: _connect_cb
          +     *  _Private_ function called by Strophe.Connection._connect_cb
          +     *
          +     * checks for stream:error
          +     *
          +     *  Parameters:
          +     *    (Strophe.Request) bodyWrap - The received stanza.
          +     */
          +    _connect_cb: function(bodyWrap) {
          +        var error = this._check_streamerror(bodyWrap, Strophe.Status.CONNFAIL);
          +        if (error) {
          +            return Strophe.Status.CONNFAIL;
          +        }
          +    },
          +
          +    /** PrivateFunction: _handleStreamStart
          +     * _Private_ function that checks the opening stream:stream tag for errors.
          +     *
          +     * Disconnects if there is an error and returns false, true otherwise.
          +     *
          +     *  Parameters:
          +     *    (Node) message - Stanza containing the stream:stream.
          +     */
          +    _handleStreamStart: function(message) {
          +        var error = false;
          +        // Check for errors in the stream:stream tag
          +        var ns = message.getAttribute("xmlns");
          +        if (typeof ns !== "string") {
          +            error = "Missing xmlns in stream:stream";
          +        } else if (ns !== Strophe.NS.CLIENT) {
          +            error = "Wrong xmlns in stream:stream: " + ns;
          +        }
          +
          +        var ns_stream = message.namespaceURI;
          +        if (typeof ns_stream !== "string") {
          +            error = "Missing xmlns:stream in stream:stream";
          +        } else if (ns_stream !== Strophe.NS.STREAM) {
          +            error = "Wrong xmlns:stream in stream:stream: " + ns_stream;
          +        }
          +
          +        var ver = message.getAttribute("version");
          +        if (typeof ver !== "string") {
          +            error = "Missing version in stream:stream";
          +        } else if (ver !== "1.0") {
          +            error = "Wrong version in stream:stream: " + ver;
          +        }
          +
          +        if (error) {
          +            this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, error);
          +            this._conn._doDisconnect();
          +            return false;
          +        }
          +
          +        return true;
          +    },
          +
          +    /** PrivateFunction: _connect_cb_wrapper
          +     * _Private_ function that handles the first connection messages.
          +     *
          +     * On receiving an opening stream tag this callback replaces itself with the real
          +     * message handler. On receiving a stream error the connection is terminated.
          +     */
          +    _connect_cb_wrapper: function(message) {
          +        if (message.data.indexOf("<stream:stream ") === 0 || message.data.indexOf("<?xml") === 0) {
          +            // Strip the XML Declaration, if there is one
          +            var data = message.data.replace(/^(<\?.*?\?>\s*)*/, "");
          +            if (data === '') return;
          +
          +            //Make the initial stream:stream selfclosing to parse it without a SAX parser.
          +            data = message.data.replace(/<stream:stream (.*[^\/])>/, "<stream:stream $1/>");
          +
          +            var streamStart = new DOMParser().parseFromString(data, "text/xml").documentElement;
          +            this._conn.xmlInput(streamStart);
          +            this._conn.rawInput(message.data);
          +
          +            //_handleStreamSteart will check for XML errors and disconnect on error
          +            if (this._handleStreamStart(streamStart)) {
          +
          +                //_connect_cb will check for stream:error and disconnect on error
          +                this._connect_cb(streamStart);
          +
          +                // ensure received stream:stream is NOT selfclosing and save it for following messages
          +                this.streamStart = message.data.replace(/^<stream:(.*)\/>$/, "<stream:$1>");
          +            }
          +        } else if (message.data === "</stream:stream>") {
          +            this._conn.rawInput(message.data);
          +            this._conn.xmlInput(document.createElement("stream:stream"));
          +            this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "Received closing stream");
          +            this._conn._doDisconnect();
          +            return;
          +        } else {
          +            var string = this._streamWrap(message.data);
          +            var elem = new DOMParser().parseFromString(string, "text/xml").documentElement;
          +            this.socket.onmessage = this._onMessage.bind(this);
          +            this._conn._connect_cb(elem, null, message.data);
          +        }
          +    },
          +
          +    /** PrivateFunction: _disconnect
          +     *  _Private_ function called by Strophe.Connection.disconnect
          +     *
          +     *  Disconnects and sends a last stanza if one is given
          +     *
          +     *  Parameters:
          +     *    (Request) pres - This stanza will be sent before disconnecting.
          +     */
          +    _disconnect: function (pres)
          +    {
          +        if (this.socket.readyState !== WebSocket.CLOSED) {
          +            if (pres) {
          +                this._conn.send(pres);
          +            }
          +            var close = '</stream:stream>';
          +            this._conn.xmlOutput(document.createElement("stream:stream"));
          +            this._conn.rawOutput(close);
          +            try {
          +                this.socket.send(close);
          +            } catch (e) {
          +                Strophe.info("Couldn't send closing stream tag.");
          +            }
          +        }
          +
          +        this._conn._doDisconnect();
          +    },
          +
          +    /** PrivateFunction: _doDisconnect
          +     *  _Private_ function to disconnect.
          +     *
          +     *  Just closes the Socket for WebSockets
          +     */
          +    _doDisconnect: function ()
          +    {
          +        Strophe.info("WebSockets _doDisconnect was called");
          +        this._closeSocket();
          +    },
          +
          +    /** PrivateFunction _streamWrap
          +     *  _Private_ helper function to wrap a stanza in a <stream> tag.
          +     *  This is used so Strophe can process stanzas from WebSockets like BOSH
          +     */
          +    _streamWrap: function (stanza)
          +    {
          +        return this.streamStart + stanza + '</stream:stream>';
          +    },
          +
          +
          +    /** PrivateFunction: _closeSocket
          +     *  _Private_ function to close the WebSocket.
          +     *
          +     *  Closes the socket if it is still open and deletes it
          +     */
          +    _closeSocket: function ()
          +    {
          +        if (this.socket) { try {
          +            this.socket.close();
          +        } catch (e) {} }
          +        this.socket = null;
          +    },
          +
          +    /** PrivateFunction: _emptyQueue
          +     * _Private_ function to check if the message queue is empty.
          +     *
          +     *  Returns:
          +     *    True, because WebSocket messages are send immediately after queueing.
          +     */
          +    _emptyQueue: function ()
          +    {
          +        return true;
          +    },
          +
          +    /** PrivateFunction: _onClose
          +     * _Private_ function to handle websockets closing.
          +     *
          +     * Nothing to do here for WebSockets
          +     */
          +    _onClose: function() {
          +        if(this._conn.connected && !this._conn.disconnecting) {
          +            Strophe.error("Websocket closed unexcectedly");
          +            this._conn._doDisconnect();
          +        } else {
          +            Strophe.info("Websocket closed");
          +        }
          +    },
          +
          +    /** PrivateFunction: _no_auth_received
          +     *
          +     * Called on stream start/restart when no stream:features
          +     * has been received.
          +     */
          +    _no_auth_received: function (_callback)
          +    {
          +        Strophe.error("Server did not send any auth methods");
          +        this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "Server did not send any auth methods");
          +        if (_callback) {
          +            _callback = _callback.bind(this._conn);
          +            _callback();
          +        }
          +        this._conn._doDisconnect();
          +    },
          +
          +    /** PrivateFunction: _onDisconnectTimeout
          +     *  _Private_ timeout handler for handling non-graceful disconnection.
          +     *
          +     *  This does nothing for WebSockets
          +     */
          +    _onDisconnectTimeout: function () {},
          +
          +    /** PrivateFunction: _onError
          +     * _Private_ function to handle websockets errors.
          +     *
          +     * Parameters:
          +     * (Object) error - The websocket error.
          +     */
          +    _onError: function(error) {
          +        Strophe.error("Websocket error " + error);
          +        this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "The WebSocket connection could not be established was disconnected.");
          +        this._disconnect();
          +    },
          +
          +    /** PrivateFunction: _onIdle
          +     *  _Private_ function called by Strophe.Connection._onIdle
          +     *
          +     *  sends all queued stanzas
          +     */
          +    _onIdle: function () {
          +        var data = this._conn._data;
          +        if (data.length > 0 && !this._conn.paused) {
          +            for (var i = 0; i < data.length; i++) {
          +                if (data[i] !== null) {
          +                    var stanza, rawStanza;
          +                    if (data[i] === "restart") {
          +                        stanza = this._buildStream();
          +                        rawStanza = this._removeClosingTag(stanza);
          +                        stanza = stanza.tree();
          +                    } else {
          +                        stanza = data[i];
          +                        rawStanza = Strophe.serialize(stanza);
          +                    }
          +                    this._conn.xmlOutput(stanza);
          +                    this._conn.rawOutput(rawStanza);
          +                    this.socket.send(rawStanza);
          +                }
          +            }
          +            this._conn._data = [];
          +        }
          +    },
          +
          +    /** PrivateFunction: _onMessage
          +     * _Private_ function to handle websockets messages.
          +     *
          +     * This function parses each of the messages as if they are full documents. [TODO : We may actually want to use a SAX Push parser].
          +     *
          +     * Since all XMPP traffic starts with "<stream:stream version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='3697395463' from='SERVER'>"
          +     * The first stanza will always fail to be parsed...
          +     * Addtionnaly, the seconds stanza will always be a <stream:features> with the stream NS defined in the previous stanza... so we need to 'force' the inclusion of the NS in this stanza!
          +     *
          +     * Parameters:
          +     * (string) message - The websocket message.
          +     */
          +    _onMessage: function(message) {
          +        var elem, data;
          +        // check for closing stream
          +        if (message.data === "</stream:stream>") {
          +            var close = "</stream:stream>";
          +            this._conn.rawInput(close);
          +            this._conn.xmlInput(document.createElement("stream:stream"));
          +            if (!this._conn.disconnecting) {
          +                this._conn._doDisconnect();
          +            }
          +            return;
          +        } else if (message.data.search("<stream:stream ") === 0) {
          +            //Make the initial stream:stream selfclosing to parse it without a SAX parser.
          +            data = message.data.replace(/<stream:stream (.*[^\/])>/, "<stream:stream $1/>");
          +            elem = new DOMParser().parseFromString(data, "text/xml").documentElement;
          +
          +            if (!this._handleStreamStart(elem)) {
          +                return;
          +            }
          +        } else {
          +            data = this._streamWrap(message.data);
          +            elem = new DOMParser().parseFromString(data, "text/xml").documentElement;
          +        }
          +
          +        if (this._check_streamerror(elem, Strophe.Status.ERROR)) {
          +            return;
          +        }
          +
          +        //handle unavailable presence stanza before disconnecting
          +        if (this._conn.disconnecting &&
          +                elem.firstChild.nodeName === "presence" &&
          +                elem.firstChild.getAttribute("type") === "unavailable") {
          +            this._conn.xmlInput(elem);
          +            this._conn.rawInput(Strophe.serialize(elem));
          +            // if we are already disconnecting we will ignore the unavailable stanza and
          +            // wait for the </stream:stream> tag before we close the connection
          +            return;
          +        }
          +        this._conn._dataRecv(elem, message.data);
          +    },
          +
          +    /** PrivateFunction: _onOpen
          +     * _Private_ function to handle websockets connection setup.
          +     *
          +     * The opening stream tag is sent here.
          +     */
          +    _onOpen: function() {
          +        Strophe.info("Websocket open");
          +        var start = this._buildStream();
          +        this._conn.xmlOutput(start.tree());
          +
          +        var startString = this._removeClosingTag(start);
          +        this._conn.rawOutput(startString);
          +        this.socket.send(startString);
          +    },
          +
          +    /** PrivateFunction: _removeClosingTag
          +     *  _Private_ function to Make the first <stream:stream> non-selfclosing
          +     *
          +     *  Parameters:
          +     *      (Object) elem - The <stream:stream> tag.
          +     *
          +     *  Returns:
          +     *      The stream:stream tag as String
          +     */
          +    _removeClosingTag: function(elem) {
          +        var string = Strophe.serialize(elem);
          +        string = string.replace(/<(stream:stream .*[^\/])\/>$/, "<$1>");
          +        return string;
          +    },
          +
          +    /** PrivateFunction: _reqToData
          +     * _Private_ function to get a stanza out of a request.
          +     *
          +     * WebSockets don't use requests, so the passed argument is just returned.
          +     *
          +     *  Parameters:
          +     *    (Object) stanza - The stanza.
          +     *
          +     *  Returns:
          +     *    The stanza that was passed.
          +     */
          +    _reqToData: function (stanza)
          +    {
          +        return stanza;
          +    },
          +
          +    /** PrivateFunction: _send
          +     *  _Private_ part of the Connection.send function for WebSocket
          +     *
          +     * Just flushes the messages that are in the queue
          +     */
          +    _send: function () {
          +        this._conn.flush();
          +    },
          +
          +    /** PrivateFunction: _sendRestart
          +     *
          +     *  Send an xmpp:restart stanza.
          +     */
          +    _sendRestart: function ()
          +    {
          +        clearTimeout(this._conn._idleTimeout);
          +        this._conn._onIdle.bind(this._conn)();
          +    }
          +};
          diff --git a/public/javascripts/strophejs-1.1.3/tests/testrunner.js b/public/javascripts/strophejs-1.1.3/tests/testrunner.js
          new file mode 100644
          index 0000000..fd3abd5
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/tests/testrunner.js
          @@ -0,0 +1,735 @@
          +/*
          + * QUnit - jQuery unit testrunner
          + * 
          + * http://docs.jquery.com/QUnit
          + *
          + * Copyright (c) 2008 John Resig, Jörn Zaefferer
          + * Dual licensed under the MIT (MIT-LICENSE.txt)
          + * and GPL (GPL-LICENSE.txt) licenses.
          + *
          + * $Id$
          + */
          +
          +(function($) {
          +
          +// Tests for equality any JavaScript type and structure without unexpected results.
          +// Discussions and reference: http://philrathe.com/articles/equiv
          +// Test suites: http://philrathe.com/tests/equiv
          +// Author: Philippe Rathé <prathe@gmail.com>
          +var equiv = function () {
          +
          +    var innerEquiv; // the real equiv function
          +    var callers = []; // stack to decide between skip/abort functions
          +
          +    // Determine what is o.
          +    function hoozit(o) {
          +        if (typeof o === "string") {
          +            return "string";
          +
          +        } else if (typeof o === "boolean") {
          +            return "boolean";
          +
          +        } else if (typeof o === "number") {
          +
          +            if (isNaN(o)) {
          +                return "nan";
          +            } else {
          +                return "number";
          +            }
          +
          +        } else if (typeof o === "undefined") {
          +            return "undefined";
          +
          +        // consider: typeof null === object
          +        } else if (o === null) {
          +            return "null";
          +
          +        // consider: typeof [] === object
          +        } else if (o instanceof Array) {
          +            return "array";
          +        
          +        // consider: typeof new Date() === object
          +        } else if (o instanceof Date) {
          +            return "date";
          +
          +        // consider: /./ instanceof Object;
          +        //           /./ instanceof RegExp;
          +        //          typeof /./ === "function"; // => false in IE and Opera,
          +        //                                          true in FF and Safari
          +        } else if (o instanceof RegExp) {
          +            return "regexp";
          +
          +        } else if (typeof o === "object") {
          +            return "object";
          +
          +        } else if (o instanceof Function) {
          +            return "function";
          +        }
          +    }
          +
          +    // Call the o related callback with the given arguments.
          +    function bindCallbacks(o, callbacks, args) {
          +        var prop = hoozit(o);
          +        if (prop) {
          +            if (hoozit(callbacks[prop]) === "function") {
          +                return callbacks[prop].apply(callbacks, args);
          +            } else {
          +                return callbacks[prop]; // or undefined
          +            }
          +        }
          +    }
          +
          +    var callbacks = function () {
          +
          +        // for string, boolean, number and null
          +        function useStrictEquality(b, a) {
          +            return a === b;
          +        }
          +
          +        return {
          +            "string": useStrictEquality,
          +            "boolean": useStrictEquality,
          +            "number": useStrictEquality,
          +            "null": useStrictEquality,
          +            "undefined": useStrictEquality,
          +
          +            "nan": function (b) {
          +                return isNaN(b);
          +            },
          +
          +            "date": function (b, a) {
          +                return hoozit(b) === "date" && a.valueOf() === b.valueOf();
          +            },
          +
          +            "regexp": function (b, a) {
          +                return hoozit(b) === "regexp" &&
          +                    a.source === b.source && // the regex itself
          +                    a.global === b.global && // and its modifers (gmi) ...
          +                    a.ignoreCase === b.ignoreCase &&
          +                    a.multiline === b.multiline;
          +            },
          +
          +            // - skip when the property is a method of an instance (OOP)
          +            // - abort otherwise,
          +            //   initial === would have catch identical references anyway
          +            "function": function () {
          +                var caller = callers[callers.length - 1];
          +                return caller !== Object &&
          +                        typeof caller !== "undefined";
          +            },
          +
          +            "array": function (b, a) {
          +                var i;
          +                var len;
          +
          +                // b could be an object literal here
          +                if ( ! (hoozit(b) === "array")) {
          +                    return false;
          +                }
          +
          +                len = a.length;
          +                if (len !== b.length) { // safe and faster
          +                    return false;
          +                }
          +                for (i = 0; i < len; i++) {
          +                    if( ! innerEquiv(a[i], b[i])) {
          +                        return false;
          +                    }
          +                }
          +                return true;
          +            },
          +
          +            "object": function (b, a) {
          +                var i;
          +                var eq = true; // unless we can proove it
          +                var aProperties = [], bProperties = []; // collection of strings
          +
          +                // comparing constructors is more strict than using instanceof
          +                if ( a.constructor !== b.constructor) {
          +                    return false;
          +                }
          +
          +                // stack constructor before traversing properties
          +                callers.push(a.constructor);
          +
          +                for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
          +
          +                    aProperties.push(i); // collect a's properties
          +
          +                    if ( ! innerEquiv(a[i], b[i])) {
          +                        eq = false;
          +                    }
          +                }
          +
          +                callers.pop(); // unstack, we are done
          +
          +                for (i in b) {
          +                    bProperties.push(i); // collect b's properties
          +                }
          +
          +                // Ensures identical properties name
          +                return eq && innerEquiv(aProperties.sort(), bProperties.sort());
          +            }
          +        };
          +    }();
          +
          +    innerEquiv = function () { // can take multiple arguments
          +        var args = Array.prototype.slice.apply(arguments);
          +        if (args.length < 2) {
          +            return true; // end transition
          +        }
          +
          +        return (function (a, b) {
          +            if (a === b) {
          +                return true; // catch the most you can
          +
          +            } else if (typeof a !== typeof b || a === null || b === null || typeof a === "undefined" || typeof b === "undefined") {
          +                return false; // don't lose time with error prone cases
          +
          +            } else {
          +                return bindCallbacks(a, callbacks, [b, a]);
          +            }
          +
          +        // apply transition with (1..n) arguments
          +        })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));
          +    };
          +
          +    return innerEquiv;
          +}(); // equiv
          +	
          +var config = {
          +	stats: {
          +		all: 0,
          +		bad: 0
          +	},
          +	queue: [],
          +	// block until document ready
          +	blocking: true,
          +	//restrict modules/tests by get parameters
          +	filters: location.search.length > 1 && $.map( location.search.slice(1).split('&'), decodeURIComponent ),
          +	isLocal: !!(window.location.protocol == 'file:')
          +};
          +
          +// public API as global methods
          +$.extend(window, {
          +	test: test,
          +	module: module,
          +	expect: expect,
          +	ok: ok,
          +	equals: equals,
          +	start: start,
          +	stop: stop,
          +	reset: reset,
          +	isLocal: config.isLocal,
          +	same: function(a, b, message) {
          +		push(equiv(a, b), a, b, message);
          +	},
          +	QUnit: {
          +		equiv: equiv
          +	},
          +	// legacy methods below
          +	isSet: isSet,
          +	isObj: isObj,
          +	compare: function() {
          +		throw "compare is deprecated - use same() instead";
          +	},
          +	compare2: function() {
          +		throw "compare2 is deprecated - use same() instead";
          +	},
          +	serialArray: function() {
          +		throw "serialArray is deprecated - use jsDump.parse() instead";
          +	},
          +	q: q,
          +	t: t,
          +	url: url,
          +	triggerEvent: triggerEvent
          +});
          +
          +$(window).load(function() {
          +	$('#userAgent').html(navigator.userAgent);
          +	var head = $('<div class="testrunner-toolbar"><label for="filter">Hide passed tests</label></div>').insertAfter("#userAgent");
          +	$('<input type="checkbox" id="filter" />').attr("disabled", true).prependTo(head).click(function() {
          +		$('li.pass')[this.checked ? 'hide' : 'show']();
          +	});
          +	runTest();	
          +});
          +
          +function synchronize(callback) {
          +	config.queue.push(callback);
          +	if(!config.blocking) {
          +		process();
          +	}
          +}
          +
          +function process() {
          +	while(config.queue.length && !config.blocking) {
          +		config.queue.shift()();
          +	}
          +}
          +
          +function stop(timeout) {
          +	config.blocking = true;
          +	if (timeout)
          +		config.timeout = setTimeout(function() {
          +			ok( false, "Test timed out" );
          +			start();
          +		}, timeout);
          +}
          +function start() {
          +	// A slight delay, to avoid any current callbacks
          +	setTimeout(function() {
          +		if(config.timeout)
          +			clearTimeout(config.timeout);
          +		config.blocking = false;
          +		process();
          +	}, 13);
          +}
          +
          +function validTest( name ) {
          +	var filters = config.filters;
          +	if( !filters )
          +		return true;
          +
          +	var i = filters.length,
          +		run = false;
          +	while( i-- ){
          +		var filter = filters[i],
          +			not = filter.charAt(0) == '!';
          +		if( not ) 
          +			filter = filter.slice(1);
          +		if( name.indexOf(filter) != -1 )
          +			return !not;
          +		if( not )
          +			run = true;
          +	}
          +	return run;
          +}
          +
          +function runTest() {
          +	config.blocking = false;
          +	var started = +new Date;
          +	config.fixture = document.getElementById('main').innerHTML;
          +	config.ajaxSettings = $.ajaxSettings;
          +	synchronize(function() {
          +		$('<p id="testresult" class="result">').html(['Tests completed in ',
          +			+new Date - started, ' milliseconds.<br/>',
          +			'<span class="bad">', config.stats.bad, '</span> tests of <span class="all">', config.stats.all, '</span> failed.</p>']
          +			.join(''))
          +			.appendTo("body");
          +		$("#banner").addClass(config.stats.bad ? "fail" : "pass");
          +	});
          +}
          +
          +function test(name, callback) {
          +	if(config.currentModule)
          +		name = config.currentModule + " module: " + name;
          +	var lifecycle = $.extend({
          +		setup: function() {},
          +		teardown: function() {}
          +	}, config.moduleLifecycle);
          +	
          +	if ( !validTest(name) )
          +		return;
          +		
          +	synchronize(function() {
          +		config.assertions = [];
          +		config.expected = null;
          +		try {
          +			lifecycle.setup();
          +			callback();
          +			lifecycle.teardown();
          +		} catch(e) {
          +			if( typeof console != "undefined" && console.error && console.warn ) {
          +				console.error("Test " + name + " died, exception and test follows");
          +				console.error(e);
          +				console.warn(callback.toString());
          +			}
          +			config.assertions.push( {
          +				result: false,
          +				message: "Died on test #" + (config.assertions.length + 1) + ": " + e.message
          +			});
          +		}
          +	});
          +	synchronize(function() {
          +		try {
          +			reset();
          +		} catch(e) {
          +			if( typeof console != "undefined" && console.error && console.warn ) {
          +				console.error("reset() failed, following Test " + name + ", exception and reset fn follows");
          +				console.error(e);
          +				console.warn(reset.toString());
          +			}
          +		}
          +		
          +		if(config.expected && config.expected != config.assertions.length) {
          +			config.assertions.push({
          +				result: false,
          +				message: "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run"
          +			});
          +		}
          +		
          +		var good = 0, bad = 0;
          +		var ol  = $("<ol/>").hide();
          +		config.stats.all += config.assertions.length;
          +		for ( var i = 0; i < config.assertions.length; i++ ) {
          +			var assertion = config.assertions[i];
          +			$("<li/>").addClass(assertion.result ? "pass" : "fail").text(assertion.message || "(no message)").appendTo(ol);
          +			assertion.result ? good++ : bad++;
          +		}
          +		config.stats.bad += bad;
          +	
          +		var b = $("<strong/>").html(name + " <b style='color:black;'>(<b class='fail'>" + bad + "</b>, <b class='pass'>" + good + "</b>, " + config.assertions.length + ")</b>")
          +		.click(function(){
          +			$(this).next().toggle();
          +		})
          +		.dblclick(function(event) {
          +			var target = $(event.target).filter("strong").clone();
          +			if ( target.length ) {
          +				target.children().remove();
          +				location.href = location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent($.trim(target.text()));
          +			}
          +		});
          +		
          +		$("<li/>").addClass(bad ? "fail" : "pass").append(b).append(ol).appendTo("#tests");
          +	
          +		if(bad) {
          +			$("#filter").attr("disabled", null);
          +		}
          +	});
          +}
          +
          +// call on start of module test to prepend name to all tests
          +function module(name, lifecycle) {
          +	config.currentModule = name;
          +	config.moduleLifecycle = lifecycle;
          +}
          +
          +/**
          + * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
          + */
          +function expect(asserts) {
          +	config.expected = asserts;
          +}
          +
          +/**
          + * Resets the test setup. Useful for tests that modify the DOM.
          + */
          +function reset() {
          +	$("#main").html( config.fixture );
          +	$.event.global = {};
          +	$.ajaxSettings = $.extend({}, config.ajaxSettings);
          +}
          +
          +/**
          + * Asserts true.
          + * @example ok( $("a").size() > 5, "There must be at least 5 anchors" );
          + */
          +function ok(a, msg) {
          +	config.assertions.push({
          +		result: !!a,
          +		message: msg
          +	});
          +}
          +
          +/**
          + * Asserts that two arrays are the same
          + */
          +function isSet(a, b, msg) {
          +	function serialArray( a ) {
          +		var r = [];
          +		
          +		if ( a && a.length )
          +	        for ( var i = 0; i < a.length; i++ ) {
          +	            var str = a[i].nodeName;
          +	            if ( str ) {
          +	                str = str.toLowerCase();
          +	                if ( a[i].id )
          +	                    str += "#" + a[i].id;
          +	            } else
          +	                str = a[i];
          +	            r.push( str );
          +	        }
          +	
          +		return "[ " + r.join(", ") + " ]";
          +	}
          +	var ret = true;
          +	if ( a && b && a.length != undefined && a.length == b.length ) {
          +		for ( var i = 0; i < a.length; i++ )
          +			if ( a[i] != b[i] )
          +				ret = false;
          +	} else
          +		ret = false;
          +	config.assertions.push({
          +		result: ret,
          +		message: !ret ? (msg + " expected: " + serialArray(b) + " result: " + serialArray(a)) : msg
          +	});
          +}
          +
          +/**
          + * Asserts that two objects are equivalent
          + */
          +function isObj(a, b, msg) {
          +	var ret = true;
          +	
          +	if ( a && b ) {
          +		for ( var i in a )
          +			if ( a[i] != b[i] )
          +				ret = false;
          +
          +		for ( i in b )
          +			if ( a[i] != b[i] )
          +				ret = false;
          +	} else
          +		ret = false;
          +
          +    config.assertions.push({
          +		result: ret,
          +		message: msg
          +	});
          +}
          +
          +/**
          + * Returns an array of elements with the given IDs, eg.
          + * @example q("main", "foo", "bar")
          + * @result [<div id="main">, <span id="foo">, <input id="bar">]
          + */
          +function q() {
          +	var r = [];
          +	for ( var i = 0; i < arguments.length; i++ )
          +		r.push( document.getElementById( arguments[i] ) );
          +	return r;
          +}
          +
          +/**
          + * Asserts that a select matches the given IDs
          + * @example t("Check for something", "//[a]", ["foo", "baar"]);
          + * @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baar'
          + */
          +function t(a,b,c) {
          +	var f = $(b);
          +	var s = "";
          +	for ( var i = 0; i < f.length; i++ )
          +		s += (s && ",") + '"' + f[i].id + '"';
          +	isSet(f, q.apply(q,c), a + " (" + b + ")");
          +}
          +
          +/**
          + * Add random number to url to stop IE from caching
          + *
          + * @example url("data/test.html")
          + * @result "data/test.html?10538358428943"
          + *
          + * @example url("data/test.php?foo=bar")
          + * @result "data/test.php?foo=bar&10538358345554"
          + */
          +function url(value) {
          +	return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random()*100000);
          +}
          +
          +/**
          + * Checks that the first two arguments are equal, with an optional message.
          + * Prints out both actual and expected values.
          + *
          + * Prefered to ok( actual == expected, message )
          + *
          + * @example equals( $.format("Received {0} bytes.", 2), "Received 2 bytes." );
          + *
          + * @param Object actual
          + * @param Object expected
          + * @param String message (optional)
          + */
          +function equals(actual, expected, message) {
          +	push(expected == actual, actual, expected, message);
          +}
          +
          +function push(result, actual, expected, message) {
          +	message = message || (result ? "okay" : "failed");
          +	config.assertions.push({
          +		result: result,
          +		message: result ? message + ": " + expected : message + ", expected: " + jsDump.parse(expected) + " result: " + jsDump.parse(actual)
          +	});
          +}
          +
          +/**
          + * Trigger an event on an element.
          + *
          + * @example triggerEvent( document.body, "click" );
          + *
          + * @param DOMElement elem
          + * @param String type
          + */
          +function triggerEvent( elem, type, event ) {
          +	if ( $.browser.mozilla || $.browser.opera ) {
          +		event = document.createEvent("MouseEvents");
          +		event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
          +			0, 0, 0, 0, 0, false, false, false, false, 0, null);
          +		elem.dispatchEvent( event );
          +	} else if ( $.browser.msie ) {
          +		elem.fireEvent("on"+type);
          +	}
          +}
          +
          +})(jQuery);
          +
          +/**
          + * jsDump
          + * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
          + * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
          + * Date: 5/15/2008
          + * @projectDescription Advanced and extensible data dumping for Javascript.
          + * @version 1.0.0
          + * @author Ariel Flesler
          + * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
          + */
          +(function(){
          +	function quote( str ){
          +		return '"' + str.toString().replace(/"/g, '\\"') + '"';
          +	};
          +	function literal( o ){
          +		return o + '';	
          +	};
          +	function join( pre, arr, post ){
          +		var s = jsDump.separator(),
          +			base = jsDump.indent();
          +			inner = jsDump.indent(1);
          +		if( arr.join )
          +			arr = arr.join( ',' + s + inner );
          +		if( !arr )
          +			return pre + post;
          +		return [ pre, inner + arr, base + post ].join(s);
          +	};
          +	function array( arr ){
          +		var i = arr.length,	ret = Array(i);					
          +		this.up();
          +		while( i-- )
          +			ret[i] = this.parse( arr[i] );				
          +		this.down();
          +		return join( '[', ret, ']' );
          +	};
          +	
          +	var reName = /^function (\w+)/;
          +	
          +	var jsDump = window.jsDump = {
          +		parse:function( obj, type ){//type is used mostly internally, you can fix a (custom)type in advance
          +			var	parser = this.parsers[ type || this.typeOf(obj) ];
          +			type = typeof parser;			
          +			
          +			return type == 'function' ? parser.call( this, obj ) :
          +				   type == 'string' ? parser :
          +				   this.parsers.error;
          +		},
          +		typeOf:function( obj ){
          +			var type = typeof obj,
          +				f = 'function';//we'll use it 3 times, save it
          +			return type != 'object' && type != f ? type :
          +				!obj ? 'null' :
          +				obj.exec ? 'regexp' :// some browsers (FF) consider regexps functions
          +				obj.getHours ? 'date' :
          +				obj.scrollBy ?  'window' :
          +				obj.nodeName == '#document' ? 'document' :
          +				obj.nodeName ? 'node' :
          +				obj.item ? 'nodelist' : // Safari reports nodelists as functions
          +				obj.callee ? 'arguments' :
          +				obj.call || obj.constructor != Array && //an array would also fall on this hack
          +					(obj+'').indexOf(f) != -1 ? f : //IE reports functions like alert, as objects
          +				'length' in obj ? 'array' :
          +				type;
          +		},
          +		separator:function(){
          +			return this.multiline ?	this.HTML ? '<br />' : '\n' : this.HTML ? '&nbsp;' : ' ';
          +		},
          +		indent:function( extra ){// extra can be a number, shortcut for increasing-calling-decreasing
          +			if( !this.multiline )
          +				return '';
          +			var chr = this.indentChar;
          +			if( this.HTML )
          +				chr = chr.replace(/\t/g,'   ').replace(/ /g,'&nbsp;');
          +			return Array( this._depth_ + (extra||0) ).join(chr);
          +		},
          +		up:function( a ){
          +			this._depth_ += a || 1;
          +		},
          +		down:function( a ){
          +			this._depth_ -= a || 1;
          +		},
          +		setParser:function( name, parser ){
          +			this.parsers[name] = parser;
          +		},
          +		// The next 3 are exposed so you can use them
          +		quote:quote, 
          +		literal:literal,
          +		join:join,
          +		//
          +		_depth_: 1,
          +		// This is the list of parsers, to modify them, use jsDump.setParser
          +		parsers:{
          +			window: '[Window]',
          +			document: '[Document]',
          +			error:'[ERROR]', //when no parser is found, shouldn't happen
          +			unknown: '[Unknown]',
          +			'null':'null',
          +			undefined:'undefined',
          +			'function':function( fn ){
          +				var ret = 'function',
          +					name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
          +				if( name )
          +					ret += ' ' + name;
          +				ret += '(';
          +				
          +				ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join('');
          +				return join( ret, this.parse(fn,'functionCode'), '}' );
          +			},
          +			array: array,
          +			nodelist: array,
          +			arguments: array,
          +			object:function( map ){
          +				var ret = [ ];
          +				this.up();
          +				for( var key in map )
          +					ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) );
          +				this.down();
          +				return join( '{', ret, '}' );
          +			},
          +			node:function( node ){
          +				var open = this.HTML ? '&lt;' : '<',
          +					close = this.HTML ? '&gt;' : '>';
          +					
          +				var tag = node.nodeName.toLowerCase(),
          +					ret = open + tag;
          +					
          +				for( var a in this.DOMAttrs ){
          +					var val = node[this.DOMAttrs[a]];
          +					if( val )
          +						ret += ' ' + a + '=' + this.parse( val, 'attribute' );
          +				}
          +				return ret + close + open + '/' + tag + close;
          +			},
          +			functionArgs:function( fn ){//function calls it internally, it's the arguments part of the function
          +				var l = fn.length;
          +				if( !l ) return '';				
          +				
          +				var args = Array(l);
          +				while( l-- )
          +					args[l] = String.fromCharCode(97+l);//97 is 'a'
          +				return ' ' + args.join(', ') + ' ';
          +			},
          +			key:quote, //object calls it internally, the key part of an item in a map
          +			functionCode:'[code]', //function calls it internally, it's the content of the function
          +			attribute:quote, //node calls it internally, it's an html attribute value
          +			string:quote,
          +			date:quote,
          +			regexp:literal, //regex
          +			number:literal,
          +			'boolean':literal
          +		},
          +		DOMAttrs:{//attributes to dump from nodes, name=>realName
          +			id:'id',
          +			name:'name',
          +			'class':'className'
          +		},
          +		HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
          +		indentChar:'   ',//indentation unit
          +		multiline:true //if true, items in a collection, are separated by a \n, else just a space.
          +	};
          +
          +})();
          diff --git a/public/javascripts/strophejs-1.1.3/tests/tests.js b/public/javascripts/strophejs-1.1.3/tests/tests.js
          new file mode 100644
          index 0000000..125688b
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/tests/tests.js
          @@ -0,0 +1,339 @@
          +$(document).ready(function () {
          +    module("JIDs");
          +
          +    test("Normal JID", function () {
          +        var jid = "darcy@pemberley.lit/library";
          +        equal(Strophe.getNodeFromJid(jid), "darcy",
          +               "Node should be 'darcy'");
          +        equal(Strophe.getDomainFromJid(jid), "pemberley.lit",
          +               "Domain should be 'pemberley.lit'");
          +        equal(Strophe.getResourceFromJid(jid), "library",
          +               "Node should be 'library'");
          +        equal(Strophe.getBareJidFromJid(jid),
          +               "darcy@pemberley.lit",
          +               "Bare JID should be 'darcy@pemberley.lit'");
          +    });
          +
          +    test("Weird node (unescaped)", function () {
          +        var jid = "darcy@netherfield.lit@pemberley.lit/library";
          +        equal(Strophe.getNodeFromJid(jid), "darcy",
          +               "Node should be 'darcy'");
          +        equal(Strophe.getDomainFromJid(jid),
          +               "netherfield.lit@pemberley.lit",
          +               "Domain should be 'netherfield.lit@pemberley.lit'");
          +        equal(Strophe.getResourceFromJid(jid), "library",
          +               "Resource should be 'library'");
          +        equal(Strophe.getBareJidFromJid(jid),
          +               "darcy@netherfield.lit@pemberley.lit",
          +               "Bare JID should be 'darcy@netherfield.lit@pemberley.lit'");
          +    });
          +
          +    test("Weird node (escaped)", function () {
          +        var escapedNode = Strophe.escapeNode("darcy@netherfield.lit");
          +        var jid = escapedNode + "@pemberley.lit/library";
          +        equal(Strophe.getNodeFromJid(jid), "darcy\\40netherfield.lit",
          +               "Node should be 'darcy\\40netherfield.lit'");
          +        equal(Strophe.getDomainFromJid(jid),
          +               "pemberley.lit",
          +               "Domain should be 'pemberley.lit'");
          +        equal(Strophe.getResourceFromJid(jid), "library",
          +               "Resource should be 'library'");
          +        equal(Strophe.getBareJidFromJid(jid),
          +               "darcy\\40netherfield.lit@pemberley.lit",
          +               "Bare JID should be 'darcy\\40netherfield.lit@pemberley.lit'");
          +    });
          +
          +    test("Weird resource", function () {
          +        var jid = "books@chat.pemberley.lit/darcy@pemberley.lit/library";
          +        equal(Strophe.getNodeFromJid(jid), "books",
          +               "Node should be 'books'");
          +        equal(Strophe.getDomainFromJid(jid), "chat.pemberley.lit",
          +               "Domain should be 'chat.pemberley.lit'");
          +        equal(Strophe.getResourceFromJid(jid),
          +               "darcy@pemberley.lit/library",
          +               "Resource should be 'darcy@pemberley.lit/library'");
          +        equal(Strophe.getBareJidFromJid(jid),
          +               "books@chat.pemberley.lit",
          +               "Bare JID should be 'books@chat.pemberley.lit'");
          +    });
          +
          +    module("Builder");
          +
          +    test("Correct namespace (#32)", function () {
          +        var stanzas = [new Strophe.Builder("message", {foo: "asdf"}).tree(),
          +                       $build("iq", {}).tree(),
          +                       $pres().tree()];
          +        $.each(stanzas, function () {
          +            equal($(this).attr('xmlns'), Strophe.NS.CLIENT,
          +                  "Namespace should be '" + Strophe.NS.CLIENT + "'");
          +        });
          +    });
          +    
          +    test("send() accepts Builders (#27)", function () {
          +        var stanza = $pres();
          +        var conn = new Strophe.Connection("");
          +        // fake connection callback to avoid errors
          +        conn.connect_callback = function () {};
          +        
          +        ok(conn._data.length === 0, "Output queue is clean");
          +        try {
          +            conn.send(stanza);
          +        } catch (e) {}
          +        ok(conn._data.length === 1, "Output queue contains an element");
          +    });
          +
          +    test("send() does not accept strings", function () {
          +        var stanza = "<presence/>";
          +        var conn = new Strophe.Connection("");
          +        // fake connection callback to avoid errors
          +        conn.connect_callback = function () {};
          +        expect(1);
          +        try {
          +            conn.send(stanza);
          +        } catch (e) {
          +            equal(e.name, "StropheError", "send() should throw exception");
          +        }
          +    });
          +
          +    test("Builder with XML attribute escaping test", function () {
          +        var text = "<b>";
          +        var expected = "<presence to='&lt;b&gt;' xmlns='jabber:client'/>";
          +        var pres = $pres({to: text});
          +        equal(pres.toString(), expected, "< should be escaped");
          +
          +        text = "foo&bar";
          +        expected = "<presence to='foo&amp;bar' xmlns='jabber:client'/>";
          +        pres = $pres({to: text});
          +        equal(pres.toString(), expected, "& should be escaped");
          +    });
          +
          +    test("c() accepts text and passes it to xmlElement", function () {
          +        var pres = $pres({from: "darcy@pemberley.lit", to: "books@chat.pemberley.lit"})
          +            .c("nick", {xmlns: "http://jabber.org/protocol/nick"}, "Darcy");
          +        var expected = "<presence from='darcy@pemberley.lit' to='books@chat.pemberley.lit' xmlns='jabber:client'><nick xmlns='http://jabber.org/protocol/nick'>Darcy</nick></presence>";
          +        equal(pres.toString(), expected, "'Darcy' should be a child of <presence>");
          +    });
          +
          +    module("XML");
          +
          +    test("XML escaping test", function () {
          +        var text = "s & p";
          +        var textNode = Strophe.xmlTextNode(text);
          +        equal(Strophe.getText(textNode), "s &amp; p", "should be escaped");
          +        var text0 = "s < & > p";
          +        var textNode0 = Strophe.xmlTextNode(text0);
          +        equal(Strophe.getText(textNode0), "s &lt; &amp; &gt; p", "should be escaped");
          +        var text1 = "s's or \"p\"";
          +        var textNode1 = Strophe.xmlTextNode(text1);
          +        equal(Strophe.getText(textNode1), "s&apos;s or &quot;p&quot;", "should be escaped");
          +        var text2 = "<![CDATA[<foo>]]>";
          +        var textNode2 = Strophe.xmlTextNode(text2);
          +        equal(Strophe.getText(textNode2), "&lt;![CDATA[&lt;foo&gt;]]&gt;", "should be escaped");
          +        var text3 = "<![CDATA[]]]]><![CDATA[>]]>";
          +        var textNode3 = Strophe.xmlTextNode(text3);
          +        equal(Strophe.getText(textNode3), "&lt;![CDATA[]]]]&gt;&lt;![CDATA[&gt;]]&gt;", "should be escaped");
          +        var text4 = "&lt;foo&gt;<![CDATA[<foo>]]>";
          +        var textNode4 = Strophe.xmlTextNode(text4);
          +        equal(Strophe.getText(textNode4), "&amp;lt;foo&amp;gt;&lt;![CDATA[&lt;foo&gt;]]&gt;", "should be escaped");
          +    });
          +
          +    test("XML element creation", function () {
          +        var elem = Strophe.xmlElement("message");
          +        equal(elem.tagName, "message", "Element name should be the same");
          +    });
          +
          +    test("copyElement() double escape bug", function() {
          +        var cloned = Strophe.copyElement(Strophe.xmlGenerator()
          +                                         .createTextNode('<>&lt;&gt;'));
          +        equal(cloned.nodeValue, '<>&lt;&gt;');
          +    });
          +    
          +    test("XML serializing", function() {
          +        var parser = new DOMParser();
          +        // Attributes
          +        var element1 = parser.parseFromString("<foo attr1='abc' attr2='edf'>bar</foo>","text/xml").documentElement;
          +        equal(Strophe.serialize(element1), "<foo attr1='abc' attr2='edf'>bar</foo>", "should be serialized");
          +        var element2 = parser.parseFromString("<foo attr1=\"abc\" attr2=\"edf\">bar</foo>","text/xml").documentElement;
          +        equal(Strophe.serialize(element2), "<foo attr1='abc' attr2='edf'>bar</foo>", "should be serialized");
          +        // Escaping values
          +        var element3 = parser.parseFromString("<foo>a &gt; &apos;b&apos; &amp; &quot;b&quot; &lt; c</foo>","text/xml").documentElement;
          +        equal(Strophe.serialize(element3), "<foo>a &gt; &apos;b&apos; &amp; &quot;b&quot; &lt; c</foo>", "should be serialized");
          +        // Escaping attributes
          +        var element4 = parser.parseFromString("<foo attr='&lt;a> &apos;b&apos;'>bar</foo>","text/xml").documentElement;
          +        equal(Strophe.serialize(element4), "<foo attr='&lt;a&gt; &apos;b&apos;'>bar</foo>", "should be serialized");
          +        var element5 = parser.parseFromString("<foo attr=\"&lt;a> &quot;b&quot;\">bar</foo>","text/xml").documentElement;
          +        equal(Strophe.serialize(element5), "<foo attr='&lt;a&gt; \"b\"'>bar</foo>", "should be serialized");
          +        // Empty elements
          +        var element6 = parser.parseFromString("<foo><empty></empty></foo>","text/xml").documentElement;
          +        equal(Strophe.serialize(element6), "<foo><empty/></foo>", "should be serialized");
          +        // Children
          +        var element7 = parser.parseFromString("<foo><bar>a</bar><baz><wibble>b</wibble></baz></foo>","text/xml").documentElement;
          +        equal(Strophe.serialize(element7), "<foo><bar>a</bar><baz><wibble>b</wibble></baz></foo>", "should be serialized");
          +        var element8 = parser.parseFromString("<foo><bar>a</bar><baz>b<wibble>c</wibble>d</baz></foo>","text/xml").documentElement;
          +        equal(Strophe.serialize(element8), "<foo><bar>a</bar><baz>b<wibble>c</wibble>d</baz></foo>", "should be serialized");
          +        // CDATA
          +        var element9 = parser.parseFromString("<foo><![CDATA[<foo>]]></foo>","text/xml").documentElement;
          +        equal(Strophe.serialize(element9), "<foo><![CDATA[<foo>]]></foo>", "should be serialized");
          +        var element10 = parser.parseFromString("<foo><![CDATA[]]]]><![CDATA[>]]></foo>","text/xml").documentElement;
          +        equal(Strophe.serialize(element10), "<foo><![CDATA[]]]]><![CDATA[>]]></foo>", "should be serialized");
          +        var element11 = parser.parseFromString("<foo>&lt;foo&gt;<![CDATA[<foo>]]></foo>","text/xml").documentElement;
          +        equal(Strophe.serialize(element11), "<foo>&lt;foo&gt;<![CDATA[<foo>]]></foo>", "should be serialized");
          +    });
          +
          +    module("Handler");
          +
          +    test("Full JID matching", function () {
          +        var elem = $msg({from: 'darcy@pemberley.lit/library'}).tree();
          +        
          +        var hand = new Strophe.Handler(null, null, null, null, null,
          +                                       'darcy@pemberley.lit/library');
          +        equal(hand.isMatch(elem), true, "Full JID should match");
          +
          +        hand = new Strophe.Handler(null, null, null, null, null,
          +                                       'darcy@pemberley.lit')
          +        equal(hand.isMatch(elem), false, "Bare JID shouldn't match");
          +    });
          +
          +    test("Bare JID matching", function () {
          +        var elem = $msg({from: 'darcy@pemberley.lit/library'}).tree();
          +
          +        var hand = new Strophe.Handler(null, null, null, null, null,
          +                                       'darcy@pemberley.lit/library',
          +                                       {matchBare: true});
          +        equal(hand.isMatch(elem), true, "Full JID should match");
          +        
          +        hand = new Strophe.Handler(null, null, null, null, null,
          +                                   'darcy@pemberley.lit',
          +                                   {matchBare: true});
          +        equal(hand.isMatch(elem), true, "Bare JID should match");
          +    });
          +    
          +    module("Misc");
          +
          +    test("Quoting strings", function () {
          +        var input = '"beep \\40"';
          +        var saslmd5 = new Strophe.SASLMD5();
          +        var output = saslmd5._quote(input);
          +        equal(output, "\"\\\"beep \\\\40\\\"\"",
          +               "string should be quoted and escaped");
          +    });
          +
          +    test("Function binding", function () {
          +        var spy = sinon.spy();
          +        var obj = {};
          +        var arg1 = "foo";
          +        var arg2 = "bar";
          +        var arg3 = "baz";
          +
          +        var f = spy.bind(obj, arg1, arg2);
          +        f(arg3);
          +        equal(spy.called, true, "bound function should be called");
          +        equal(spy.calledOn(obj), true,
          +               "bound function should have correct context");
          +        equal(spy.alwaysCalledWithExactly(arg1, arg2, arg3),
          +               true,
          +               "bound function should get all arguments");
          +    });
          +
          +    module("XHR error handling");
          +
          +    // Note that these tests are pretty dependent on the actual code.
          +
          +    test("Aborted requests do nothing", function () {
          +        Strophe.Connection.prototype._onIdle = function () {};
          +        var conn = new Strophe.Connection("http://fake");
          +
          +        // simulate a finished but aborted request
          +        var req = {id: 43,
          +                   sends: 1,
          +                   xhr: {
          +                       readyState: 4
          +                   },
          +                   abort: true};
          +
          +        conn._requests = [req];
          +
          +        var spy = sinon.spy();
          +
          +        conn._proto._onRequestStateChange(spy, req);
          +
          +        equal(req.abort, false, "abort flag should be toggled");
          +        equal(conn._requests.length, 1, "_requests should be same length");
          +        equal(spy.called, false, "callback should not be called");
          +    });
          +
          +    test("Incomplete requests do nothing", function () {
          +        Strophe.Connection.prototype._onIdle = function () {};
          +        var conn = new Strophe.Connection("http://fake");
          +
          +        // simulate a finished but aborted request
          +        var req = {id: 44,
          +                   sends: 1,
          +                   xhr: {
          +                       readyState: 3
          +                   }};
          +
          +        conn._requests = [req];
          +
          +        var spy = sinon.spy();
          +
          +        conn._proto._onRequestStateChange(spy, req);
          +
          +        equal(conn._requests.length, 1, "_requests should be same length");
          +        equal(spy.called, false, "callback should not be called");
          +    });
          +
          +  module("SASL Mechanisms");
          +
          +  test("SASL Plain Auth", function () {
          +    var conn = {pass: "password", authcid: "user", authzid: "user@xmpp.org"};
          +
          +    ok(Strophe.SASLPlain.test(conn), "plain should pass the test");
          +
          +    var saslplain = new Strophe.SASLPlain();
          +    saslplain.onStart(conn);
          +    var response = saslplain.onChallenge(conn, null);
          +    equal(response, [conn.authzid, conn.authcid, conn.pass].join("\u0000"),
          +          "checking plain auth challenge");
          +    saslplain.onSuccess();
          +  });
          +
          +  test("SASL SCRAM-SHA-1 Auth", function () {
          +    var conn = {pass: "pencil", authcid: "user",
          +                authzid: "user@xmpp.org", _sasl_data: []};
          +
          +    ok(Strophe.SASLSHA1.test(conn), "sha-1 should pass the test");
          +
          +    var saslsha1 = new Strophe.SASLSHA1();
          +    saslsha1.onStart(conn);
          +    // test taken from example section on:
          +    // URL: http://tools.ietf.org/html/rfc5802#section-5
          +    var response = saslsha1.onChallenge(conn, null, "fyko+d2lbbFgONRv9qkxdawL");
          +    equal(response, "n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL",
          +          "checking first auth challenge");
          +    var response = saslsha1.onChallenge(conn, "r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096");
          +    equal(response, "c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=",
          +          "checking second auth challenge");
          +    saslsha1.onSuccess();
          +  });
          +
          +  test("SASL DIGEST-MD-5 Auth", function () {
          +    var conn = {pass: "secret", authcid: "chris",
          +                authzid: "user@xmpp.org", servtype: "imap",
          +                domain: "elwood.innosoft.com",
          +                _sasl_data: []};
          +
          +    ok(Strophe.SASLMD5.test(conn), "md-5 should pass the test");
          +
          +    var saslmd5 = new Strophe.SASLMD5();
          +    saslmd5.onStart(conn);
          +    // test taken from example section on:
          +    // URL: http://www.ietf.org/rfc/rfc2831.txt
          +    var response = saslmd5.onChallenge(conn, "realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",qop=\"auth\",algorithm=md5-sess,charset=utf-8", "OA6MHXh6VqTrRk");
          +    equal(response, "charset=utf-8,username=\"chris\",realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",nc=00000001,cnonce=\"OA6MHXh6VqTrRk\",digest-uri=\"imap/elwood.innosoft.com\",response=d388dad90d4bbd760a152321f2143af7,qop=auth",
          +          "checking first auth challenge");
          +    var response = saslmd5.onChallenge(conn, "rspauth=ea40f60335c427b5527b84dbabcdfffd");
          +    equal(response, "", "checking second auth challenge");
          +    saslmd5.onSuccess();
          +  });
          +});
          diff --git a/public/javascripts/strophejs-1.1.3/tests/testsuite.css b/public/javascripts/strophejs-1.1.3/tests/testsuite.css
          new file mode 100644
          index 0000000..dbfc43a
          --- /dev/null
          +++ b/public/javascripts/strophejs-1.1.3/tests/testsuite.css
          @@ -0,0 +1,120 @@
          +body, div, h1 { font-family: 'trebuchet ms', verdana, arial; margin: 0; padding: 0 }
          +body {font-size: 10pt; }
          +h1 { padding: 15px; font-size: large; background-color: #06b; color: white; }
          +h1 a { color: white; }
          +h2 { padding: 10px; background-color: #eee; color: black; margin: 0; font-size: small; font-weight: normal }
          +
          +.pass { color: green; } 
          +.fail { color: red; } 
          +p.result { margin-left: 1em; }
          +
          +#banner { height: 2em; border-bottom: 1px solid white; }
          +h2.pass { background-color: green; }
          +h2.fail { background-color: red; }
          +
          +div.testrunner-toolbar { background: #eee; border-top: 1px solid black; padding: 10px; }
          +
          +ol#tests > li > strong { cursor:pointer; }
          +
          +div#fx-tests h4 {
          +	background: red;
          +}
          +
          +div#fx-tests h4.pass {
          +	background: green;
          +}
          +
          +div#fx-tests div.box {
          +	background: red url(data/cow.jpg) no-repeat;
          +	overflow: hidden;
          +	border: 2px solid #000;
          +}
          +
          +div#fx-tests div.overflow {
          +	overflow: visible;
          +}
          +
          +div.inline {
          +	display: inline;
          +}
          +
          +div.autoheight {
          +	height: auto;
          +}
          +
          +div.autowidth {
          +	width: auto;
          +}
          +
          +div.autoopacity {
          +	opacity: auto;
          +}
          +
          +div.largewidth {
          +	width: 100px;
          +}
          +
          +div.largeheight {
          +	height: 100px;
          +}
          +
          +div.largeopacity {
          +	filter: progid:DXImageTransform.Microsoft.Alpha(opacity=100);
          +}
          +
          +div.medwidth {
          +	width: 50px;
          +}
          +
          +div.medheight {
          +	height: 50px;
          +}
          +
          +div.medopacity {
          +	opacity: 0.5;
          +	filter: progid:DXImageTransform.Microsoft.Alpha(opacity=50);
          +}
          +
          +div.nowidth {
          +	width: 0px;
          +}
          +
          +div.noheight {
          +	height: 0px;
          +}
          +
          +div.noopacity {
          +	opacity: 0;
          +	filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0);
          +}
          +
          +div.hidden {
          +	display: none;
          +}
          +
          +div#fx-tests div.widewidth {
          +	background-repeat: repeat-x;
          +}
          +
          +div#fx-tests div.wideheight {
          +	background-repeat: repeat-y;
          +}
          +
          +div#fx-tests div.widewidth.wideheight {
          +	background-repeat: repeat;
          +}
          +
          +div#fx-tests div.noback {
          +	background-image: none;
          +}
          +
          +div.chain, div.chain div { width: 100px; height: 20px; position: relative; float: left; }
          +div.chain div { position: absolute; top: 0px; left: 0px; }
          +
          +div.chain.test { background: red; }
          +div.chain.test div { background: green; }
          +
          +div.chain.out { background: green; }
          +div.chain.out div { background: red; display: none; }
          +
          +div#show-tests * { display: none; }
          --
          libgit2 0.21.2