| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494 | 
							- /** 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:
 -  *  http://tools.ietf.org/html/rfc7395
 -  */
 - 
 - /* 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.
 -  */
 - 
 - /* jshint ignore:start */
 - (function (callback) {
 - /* jshint ignore:end */
 - 
 - // 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
 - 
 - (function (root, factory) {
 -     if (typeof define === 'function' && define.amd) {
 -         define('strophe-base64', function () {
 -             return factory();
 -         });
 -     } else {
 -         // Browser globals
 -         root.Base64 = factory();
 -     }
 - }(this, 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)) {
 -                     enc2 = ((chr1 & 3) << 4);
 -                     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.
 -  */
 - 
 - /* jshint undef: true, unused: true:, noarg: true, latedef: true */
 - /* global define */
 - 
 - /* Some functions and variables have been stripped for use with Strophe */
 - 
 - (function (root, factory) {
 -     if (typeof define === 'function' && define.amd) {
 -         define('strophe-sha1', function () {
 -             return factory();
 -         });
 -     } else {
 -         // Browser globals
 -         root.SHA1 = factory();
 -     }
 - }(this, function () {
 - 
 - /*
 -  * 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;
 - }
 - 
 - /*
 -  * These are the functions you'll usually want to call
 -  * They take string arguments and return either hex or base-64 encoded strings
 -  */
 - return {
 -     b64_hmac_sha1:  function (key, data){ return binb2b64(core_hmac_sha1(key, data)); },
 -     b64_sha1:       function (s) { return binb2b64(core_sha1(str2binb(s),s.length * 8)); },
 -     binb2str:       binb2str,
 -     core_hmac_sha1: core_hmac_sha1,
 -     str_hmac_sha1:  function (key, data){ return binb2str(core_hmac_sha1(key, data)); },
 -     str_sha1:       function (s) { return binb2str(core_sha1(str2binb(s),s.length * 8)); },
 - };
 - }));
 - 
 - /*
 -  * 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!
 -  */
 - 
 - (function (root, factory) {
 -     if (typeof define === 'function' && define.amd) {
 -         define('strophe-md5', function () {
 -             return factory();
 -         });
 -     } else {
 -         // Browser globals
 -         root.MD5 = factory();
 -     }
 - }(this, function (b) {
 -     /*
 -      * 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 */
 - 
 - /** 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.isArray
 -  *  This is a polyfill for the ES5 Array.isArray method.
 -  */
 - if (!Array.isArray) {
 -     Array.isArray = function(arg) {
 -         return Object.prototype.toString.call(arg) === '[object Array]';
 -     };
 - }
 - 
 - /** 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;
 -         };
 -     }
 - 
 - /*
 -     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 define, document, window, setTimeout, clearTimeout, console, ActiveXObject, DOMParser */
 - 
 - (function (root, factory) {
 -     if (typeof define === 'function' && define.amd) {
 -         define('strophe-core', [
 -             'strophe-sha1',
 -             'strophe-base64',
 -             'strophe-md5',
 -             "strophe-polyfill"
 -         ], function () {
 -             return factory.apply(this, arguments);
 -         });
 -     } else {
 -         // Browser globals
 -         var o = factory(root.SHA1, root.Base64, root.MD5);
 -         window.Strophe =        o.Strophe;
 -         window.$build =         o.$build;
 -         window.$iq =            o.$iq;
 -         window.$msg =           o.$msg;
 -         window.$pres =          o.$pres;
 -         window.SHA1 =           o.SHA1;
 -         window.Base64 =         o.Base64;
 -         window.MD5 =            o.MD5;
 -         window.b64_hmac_sha1 =  o.SHA1.b64_hmac_sha1;
 -         window.b64_sha1 =       o.SHA1.b64_sha1;
 -         window.str_hmac_sha1 =  o.SHA1.str_hmac_sha1;
 -         window.str_sha1 =       o.SHA1.str_sha1;
 -     }
 - }(this, function (SHA1, Base64, MD5) {
 - 
 - 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.2.2",
 - 
 -     /** 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",
 -         FRAMING: "urn:ietf:params:xml:ns:xmpp-framing",
 -         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'],
 -                 /** Function: XHTML.validTag
 -                  *
 -                  * Utility method to determine whether a tag is allowed
 -                  * in the XHTML_IM namespace.
 -                  *
 -                  * XHTML tag names are case sensitive and must be lower case.
 -                  */
 -                 validTag: function(tag) {
 -                         for (var i = 0; i < Strophe.XHTML.tags.length; i++) {
 -                                 if (tag == Strophe.XHTML.tags[i]) {
 -                                         return true;
 -                                 }
 -                         }
 -                         return false;
 -                 },
 -                 /** Function: XHTML.validAttribute
 -                  *
 -                  * Utility method to determine whether an attribute is allowed
 -                  * as recommended per XEP-0071
 -                  *
 -                  * XHTML attribute names are case sensitive and must be lower case.
 -                  */
 -                 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,
 -         REDIRECT: 9
 -     },
 - 
 -     /** 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 sensitive.
 -      *
 -      *  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 == name;
 -     },
 - 
 -     /** 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++) {
 -             var arg = arguments[a];
 -             if (!arg) { continue; }
 -             if (typeof(arg) == "string" ||
 -                 typeof(arg) == "number") {
 -                 node.appendChild(Strophe.xmlTextNode(arg));
 -             } else if (typeof(arg) == "object" &&
 -                        typeof(arg.sort) == "function") {
 -                 for (i = 0; i < arg.length; i++) {
 -                     var attr = arg[i];
 -                     if (typeof(attr) == "object" &&
 -                         typeof(attr.sort) == "function" &&
 -                         attr[1] !== undefined) {
 -                         node.setAttribute(attr[0], attr[1]);
 -                     }
 -                 }
 -             } else if (typeof(arg) == "object") {
 -                 for (k in arg) {
 -                     if (arg.hasOwnProperty(k)) {
 -                         if (arg[k] !== undefined) {
 -                             node.setAttribute(k, arg[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,  "<");
 -         text = text.replace(/>/g,  ">");
 -         text = text.replace(/'/g,  "'");
 -         text = text.replace(/"/g,  """);
 -         return text;
 -     },
 - 
 -     /*  Function: xmlunescape
 -     *  Unexcapes invalid xml characters.
 -     *
 -     *  Parameters:
 -     *     (String) text - text to unescape.
 -     *
 -     *  Returns:
 -     *      Unescaped text.
 -     */
 -     xmlunescape: function(text)
 -     {
 -         text = text.replace(/\&/g, "&");
 -         text = text.replace(/</g,  "<");
 -         text = text.replace(/>/g,  ">");
 -         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)
 -     {
 -         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,
 -                                 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(); // XHTML tags must be lower case.
 -             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)
 -     {
 -         if (typeof node !== "string") { return 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)
 -     {
 -         if (typeof node !== "string") { return 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 +
 -                 "='" + elem.attributes[i].value
 -                     .replace(/&/g, "&")
 -                        .replace(/\'/g, "'")
 -                        .replace(/>/g, ">")
 -                        .replace(/</g, "<") + "'";
 -                }
 -         }
 - 
 -         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)) {
 -                 if (moreattrs[k] === undefined) {
 -                     this.node.removeAttribute(k);
 -                 } else {
 -                     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 (typeof text !== "string") {
 -             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;
 -         }
 - 
 -         var elem_type = elem.getAttribute("type");
 -         if (nsMatch &&
 -             (!this.name || Strophe.isTagEqual(elem, this.name)) &&
 -             (!this.type || (Array.isArray(this.type) ? this.type.indexOf(elem_type) != -1 : elem_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 or websocket
 -  *  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;
 -  *
 -  *  The "customHeaders" option can be used to provide custom HTTP headers to be
 -  *  included in the XMLHttpRequests made.
 -  *
 -  *  The "keepalive" option can be used to instruct Strophe to maintain the
 -  *  current BOSH session across interruptions such as webpage reloads.
 -  *
 -  *  It will do this by caching the sessions tokens in sessionStorage, and when
 -  *  "restore" is called it will check whether there are cached tokens with
 -  *  which it can resume an existing session.
 -  *
 -  *  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.authenticated = false;
 -     this.connected = false;
 -     this.disconnecting = false;
 -     this.do_authentication = true;
 -     this.paused = false;
 -     this.restored = 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.connected = false;
 -         this.disconnecting = false;
 -         this.restored = false;
 - 
 -         this._data = [];
 -         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.
 -      *    (String) authcid - The optional alternative authentication identity
 -      *      (username) if intending to impersonate another user.
 -      */
 -     connect: function (jid, pass, callback, wait, hold, route, authcid)
 -     {
 -         this.jid = jid;
 -         /** Variable: authzid
 -          *  Authorization identity.
 -          */
 -         this.authzid = Strophe.getBareJidFromJid(this.jid);
 -         /** Variable: authcid
 -          *  Authentication identity (User name).
 -          */
 -         this.authcid = 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.restored = false;
 - 
 -         // 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)
 -     {
 -         if (this._proto instanceof Strophe.Bosh) {
 -             this._proto._attach(jid, sid, rid, callback, wait, hold, wind);
 -         } else {
 -             throw {
 -                 name: 'StropheSessionError',
 -                 message: 'The "attach" method can only be used with a BOSH connection.'
 -             };
 -         }
 -     },
 - 
 -     /** Function: restore
 -      *  Attempt to restore a cached BOSH session.
 -      *
 -      *  This function is only useful in conjunction with providing the
 -      *  "keepalive":true option when instantiating a new Strophe.Connection.
 -      *
 -      *  When "keepalive" is set to true, Strophe will cache the BOSH tokens
 -      *  RID (Request ID) and SID (Session ID) and then when this function is
 -      *  called, it will attempt to restore the session from those cached
 -      *  tokens.
 -      *
 -      *  This function must therefore be called instead of connect or attach.
 -      *
 -      *  For an example on how to use it, please see examples/restore.js
 -      *
 -      *  Parameters:
 -      *    (String) jid - The user's JID.  This may be a bare JID or a full JID.
 -      *    (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).
 -      *    (Integer) wind - The optional HTTBIND window value.  This is the
 -      *      allowed range of request ids that are valid.  The default is 5.
 -      */
 -     restore: function (jid, callback, wait, hold, wind)
 -     {
 -         if (this._sessionCachingSupported()) {
 -             this._proto._restore(jid, callback, wait, hold, wind);
 -         } else {
 -             throw {
 -                 name: 'StropheSessionError',
 -                 message: 'The "restore" method can only be used with a BOSH connection.'
 -             };
 -         }
 -     },
 - 
 -     /** PrivateFunction: _sessionCachingSupported
 -      * Checks whether sessionStorage and JSON are supported and whether we're
 -      * using BOSH.
 -      */
 -     _sessionCachingSupported: function ()
 -     {
 -         if (this._proto instanceof Strophe.Bosh) {
 -             if (!JSON) { return false; }
 -             try {
 -                 window.sessionStorage.setItem('_strophe_', '_strophe_');
 -                 window.sessionStorage.removeItem('_strophe_');
 -             } catch (e) {
 -                 return false;
 -             }
 -             return true;
 -         }
 -         return false;
 -     },
 - 
 -     /** 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 expectedFrom = elem.getAttribute("to");
 -         var fulljid = this.jid;
 - 
 -         var handler = this.addHandler(function (stanza) {
 -             // remove timeout handler if there is one
 -             if (timeoutHandler) {
 -                 that.deleteTimedHandler(timeoutHandler);
 -             }
 - 
 -             var acceptable = false;
 -             var from = stanza.getAttribute("from");
 -             if (from === expectedFrom ||
 -                (expectedFrom === null &&
 -                    (from === Strophe.getBareJidFromJid(fulljid) ||
 -                     from === Strophe.getDomainFromJid(fulljid) ||
 -                     from === fulljid))) {
 -                 acceptable = true;
 -             }
 - 
 -             if (!acceptable) {
 -                 console.error("req: ", elem, "Resp:", stanza);
 -                 throw {
 -                     name: "StropheError",
 -                     message: "Got answer to IQ from wrong jid:" + from +
 -                              "\nExpected jid: " + expectedFrom +"" +
 -                              "\n stanza to String: " + stanza.toString()
 -                 };
 -             }
 - 
 -             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', ['error', 'result'], 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);
 -         // If a handler is being deleted while it is being added,
 -         // prevent it from getting added
 -         var i = this.addHandlers.indexOf(handRef);
 -         if (i >= 0) {
 -             this.addHandlers.splice(i, 1);
 -         }
 -     },
 - 
 -     /** 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.
 -      *  If the Connection object isn't connected, at least tries to abort all pending requests
 -      *  so the connection object won't generate successful requests (which were already opened).
 -      *
 -      *  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);
 -         } else {
 -             Strophe.info("Disconnect was called before Strophe connected to the server");
 -             this._proto._abortAllRequests();
 -         }
 -     },
 - 
 -     /** 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 (condition)
 -     {
 -         if (typeof this._idleTimeout == "number") {
 -             clearTimeout(this._idleTimeout);
 -         }
 - 
 -         // 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;
 -         this.restored = 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, condition);
 -         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 type = elem.getAttribute("type");
 -         var cond, conflict;
 -         if (type !== null && type == "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._doDisconnect(cond);
 -             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;
 -         if (bodyWrap.getElementsByTagNameNS) {
 -             hasFeatures = bodyWrap.getElementsByTagNameNS(Strophe.NS.STREAM, "features").length > 0;
 -         } else {
 -             hasFeatures = bodyWrap.getElementsByTagName("stream:features").length > 0 || 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;
 -         }
 - 
 -         var streamfeature_handlers = [];
 -         var wrapper = function(handlers, elem) {
 -             while (handlers.length) {
 -                 this.deleteHandler(handlers.pop());
 -             }
 -             this._sasl_auth1_cb.bind(this)(elem);
 -             return false;
 -         };
 -         streamfeature_handlers.push(this._addSysHandler(function(elem) {
 -             wrapper.bind(this)(streamfeature_handlers, elem);
 -         }.bind(this), null, "stream:features", null, null));
 -         streamfeature_handlers.push(this._addSysHandler(function(elem) {
 -             wrapper.bind(this)(streamfeature_handlers, elem);
 -         }.bind(this), Strophe.NS.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);
 -         }
 -     }
 - };
 - 
 - /** 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 = SHA1.core_hmac_sha1(connection.pass, salt);
 -     for (i = 1; i < iter; i++) {
 -       U = SHA1.core_hmac_sha1(connection.pass, SHA1.binb2str(U_old));
 -       for (k = 0; k < 5; k++) {
 -         Hi[k] ^= U[k];
 -       }
 -       U_old = U;
 -     }
 -     Hi = SHA1.binb2str(Hi);
 - 
 -     clientKey = SHA1.core_hmac_sha1(Hi, "Client Key");
 -     serverKey = SHA1.str_hmac_sha1(Hi, "Server Key");
 -     clientSignature = SHA1.core_hmac_sha1(SHA1.str_sha1(SHA1.binb2str(clientKey)), authMessage);
 -     connection._sasl_data["server-signature"] = SHA1.b64_hmac_sha1(serverKey, authMessage);
 - 
 -     for (k = 0; k < 5; k++) {
 -       clientKey[k] ^= clientSignature[k];
 -     }
 - 
 -     responseText += ",p=" + Base64.encode(SHA1.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;
 - 
 - return {
 -     Strophe:        Strophe,
 -     $build:         $build,
 -     $msg:           $msg,
 -     $iq:            $iq,
 -     $pres:          $pres,
 -     SHA1:           SHA1,
 -     Base64:         Base64,
 -     MD5:            MD5,
 - };
 - }));
 - 
 - /*
 -     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 define, window, setTimeout, clearTimeout, XMLHttpRequest, ActiveXObject, Strophe, $build */
 - 
 - (function (root, factory) {
 -     if (typeof define === 'function' && define.amd) {
 -         define('strophe-bosh', ['strophe-core'], function (core) {
 -             return factory(
 -                 core.Strophe,
 -                 core.$build
 -             );
 -         });
 -     } else {
 -         // Browser globals
 -         return factory(Strophe, $build);
 -     }
 - }(this, function (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; charset=utf-8");
 -             }
 -         } 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.errors = 0;
 - 
 -     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});
 -         }
 -         if (this._conn.options.keepalive) {
 -             this._cacheSession();
 -         }
 -         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;
 -         this.errors = 0;
 -         window.sessionStorage.removeItem('strophe-bosh-session');
 -     },
 - 
 -     /** 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;
 -         this.errors = 0;
 - 
 -         // 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: _restore
 -      *  Attempt to restore a cached BOSH session
 -      *
 -      *  Parameters:
 -      *    (String) jid - The full JID that is bound by the session.
 -      *      This parameter is optional but recommended, specifically in cases
 -      *      where prebinded BOSH sessions are used where it's important to know
 -      *      that the right session is being restored.
 -      *    (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.
 -      */
 -     _restore: function (jid, callback, wait, hold, wind)
 -     {
 -         var session = JSON.parse(window.sessionStorage.getItem('strophe-bosh-session'));
 -         if (typeof session !== "undefined" &&
 -                    session !== null &&
 -                    session.rid &&
 -                    session.sid &&
 -                    session.jid &&
 -                    (typeof jid === "undefined" || Strophe.getBareJidFromJid(session.jid) == Strophe.getBareJidFromJid(jid)))
 -         {
 -             this._conn.restored = true;
 -             this._attach(session.jid, session.sid, session.rid, callback, wait, hold, wind);
 -         } else {
 -             throw { name: "StropheSessionError", message: "_restore: no restoreable session." };
 -         }
 -     },
 - 
 -     /** PrivateFunction: _cacheSession
 -      *  _Private_ handler for the beforeunload event.
 -      *
 -      *  This handler is used to process the Bosh-part of the initial request.
 -      *  Parameters:
 -      *    (Strophe.Request) bodyWrap - The received stanza.
 -      */
 -     _cacheSession: function ()
 -     {
 -         if (this._conn.authenticated) {
 -             if (this._conn.jid && this.rid && this.sid) {
 -                 window.sessionStorage.setItem('strophe-bosh-session', JSON.stringify({
 -                     'jid': this._conn.jid,
 -                     'rid': this.rid,
 -                     'sid': this.sid
 -                 }));
 -             }
 -         } else {
 -             window.sessionStorage.removeItem('strophe-bosh-session');
 -         }
 -     },
 - 
 -     /** 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
 -             cond = bodyWrap.getAttribute("condition");
 -             Strophe.error("BOSH-Connection failed: " + cond);
 -             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(cond);
 -             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);
 -         window.sessionStorage.removeItem('strophe-bosh-session');
 -     },
 - 
 -     /** 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._conn._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 () {
 -         this._abortAllRequests();
 -     },
 - 
 -     /** PrivateFunction: _abortAllRequests
 -      *  _Private_ helper function that makes sure all pending requests are aborted.
 -      */
 -     _abortAllRequests: function _abortAllRequests() {
 -         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._conn.paused) {
 -             return;
 -         }
 - 
 -         if (this._requests.length < 2 && data.length > 0) {
 -             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._throttledRequestHandler();
 -         }
 - 
 -         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._conn.maxRetries) {
 -             this._conn._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);
 -                 req.xhr.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
 -             } 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);
 -         }
 -     }
 - };
 - return Strophe;
 - }));
 - 
 - /*
 -     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 define, window, clearTimeout, WebSocket, DOMParser, Strophe, $build */
 - 
 - (function (root, factory) {
 -     if (typeof define === 'function' && define.amd) {
 -         define('strophe-websocket', ['strophe-core'], function (core) {
 -             return factory(
 -                 core.Strophe,
 -                 core.$build
 -             );
 -         });
 -     } else {
 -         // Browser globals
 -         return factory(Strophe, $build);
 -     }
 - }(this, function (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 RFC 7395:
 -  *  http://tools.ietf.org/html/rfc7395
 -  *
 -  *  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 = "wrapper";
 - 
 -     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("open", {
 -             "xmlns": Strophe.NS.FRAMING,
 -             "to": this._conn.domain,
 -             "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;
 -         if (bodyWrap.getElementsByTagNameNS) {
 -             errors = bodyWrap.getElementsByTagNameNS(Strophe.NS.STREAM, "error");
 -         } else {
 -             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 <open /> tag for errors.
 -      *
 -      * Disconnects if there is an error and returns false, true otherwise.
 -      *
 -      *  Parameters:
 -      *    (Node) message - Stanza containing the <open /> tag.
 -      */
 -     _handleStreamStart: function(message) {
 -         var error = false;
 - 
 -         // Check for errors in the <open /> tag
 -         var ns = message.getAttribute("xmlns");
 -         if (typeof ns !== "string") {
 -             error = "Missing xmlns in <open />";
 -         } else if (ns !== Strophe.NS.FRAMING) {
 -             error = "Wrong xmlns in <open />: " + ns;
 -         }
 - 
 -         var ver = message.getAttribute("version");
 -         if (typeof ver !== "string") {
 -             error = "Missing version in <open />";
 -         } else if (ver !== "1.0") {
 -             error = "Wrong version in <open />: " + 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("<open ") === 0 || message.data.indexOf("<?xml") === 0) {
 -             // Strip the XML Declaration, if there is one
 -             var data = message.data.replace(/^(<\?.*?\?>\s*)*/, "");
 -             if (data === '') return;
 - 
 -             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);
 -             }
 -         } else if (message.data.indexOf("<close ") === 0) { //'<close xmlns="urn:ietf:params:xml:ns:xmpp-framing />') {
 -             this._conn.rawInput(message.data);
 -             this._conn.xmlInput(message);
 -             var see_uri = message.getAttribute("see-other-uri");
 -             if (see_uri) {
 -                 this._conn._changeConnectStatus(Strophe.Status.REDIRECT, "Received see-other-uri, resetting connection");
 -                 this._conn.reset();
 -                 this._conn.service = see_uri;
 -                 this._connect();
 -             } else {
 -                 this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "Received closing stream");
 -                 this._conn._doDisconnect();
 -             }
 -         } 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 && this.socket.readyState !== WebSocket.CLOSED) {
 -             if (pres) {
 -                 this._conn.send(pres);
 -             }
 -             var close = $build("close", { "xmlns": Strophe.NS.FRAMING, });
 -             this._conn.xmlOutput(close);
 -             var closeString = Strophe.serialize(close);
 -             this._conn.rawOutput(closeString);
 -             try {
 -                 this.socket.send(closeString);
 -             } catch (e) {
 -                 Strophe.info("Couldn't send <close /> 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 "<wrapper>" + stanza + '</wrapper>';
 -     },
 - 
 - 
 -     /** 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: _abortAllRequests
 -      *  _Private_ helper function that makes sure all pending requests are aborted.
 -      */
 -     _abortAllRequests: 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().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
 -         var close = '<close xmlns="urn:ietf:params:xml:ns:xmpp-framing" />';
 -         if (message.data === close) {
 -             this._conn.rawInput(close);
 -             this._conn.xmlInput(message);
 -             if (!this._conn.disconnecting) {
 -                 this._conn._doDisconnect();
 -             }
 -             return;
 -         } else if (message.data.search("<open ") === 0) {
 -             // This handles stream restarts
 -             elem = new DOMParser().parseFromString(message.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 = Strophe.serialize(start);
 -         this._conn.rawOutput(startString);
 -         this.socket.send(startString);
 -     },
 - 
 -     /** 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)();
 -     }
 - };
 - return Strophe;
 - }));
 - 
 - /* jshint ignore:start */
 - if (callback) {
 -     return callback(Strophe, $build, $msg, $iq, $pres);
 - }
 - 
 - 
 - })(function (Strophe, build, msg, iq, pres) {
 -     window.Strophe = Strophe;
 -     window.$build = build;
 -     window.$msg = msg;
 -     window.$iq = iq;
 -     window.$pres = pres;
 - });
 - /* jshint ignore:end */
 
 
  |