PNG  IHDRQgAMA a cHRMz&u0`:pQ<bKGDgmIDATxwUﹻ& ^CX(J I@ "% (** BX +*i"]j(IH{~R)[~>h{}gy)I$Ij .I$I$ʊy@}x.: $I$Ii}VZPC)I$IF ^0ʐJ$I$Q^}{"r=OzI$gRZeC.IOvH eKX $IMpxsk.쒷/&r[޳<v| .I~)@$updYRa$I |M.e JaֶpSYR6j>h%IRز if&uJ)M$I vLi=H;7UJ,],X$I1AҒJ$ XY XzI@GNҥRT)E@;]K*Mw;#5_wOn~\ DC&$(A5 RRFkvIR}l!RytRl;~^ǷJj اy뷦BZJr&ӥ8Pjw~vnv X^(I;4R=P[3]J,]ȏ~:3?[ a&e)`e*P[4]T=Cq6R[ ~ޤrXR Հg(t_HZ-Hg M$ãmL5R uk*`%C-E6/%[t X.{8P9Z.vkXŐKjgKZHg(aK9ڦmKjѺm_ \#$5,)-  61eJ,5m| r'= &ڡd%-]J on Xm|{ RҞe $eڧY XYrԮ-a7RK6h>n$5AVڴi*ֆK)mѦtmr1p| q:흺,)Oi*ֺK)ܬ֦K-5r3>0ԔHjJئEZj,%re~/z%jVMڸmrt)3]J,T K֦OvԒgii*bKiNO~%PW0=dii2tJ9Jݕ{7"I P9JKTbu,%r"6RKU}Ij2HKZXJ,妝 XYrP ެ24c%i^IK|.H,%rb:XRl1X4Pe/`x&P8Pj28Mzsx2r\zRPz4J}yP[g=L) .Q[6RjWgp FIH*-`IMRaK9TXcq*I y[jE>cw%gLRԕiFCj-ďa`#e~I j,%r,)?[gp FI˨mnWX#>mʔ XA DZf9,nKҲzIZXJ,L#kiPz4JZF,I,`61%2s $,VOϚ2/UFJfy7K> X+6 STXIeJILzMfKm LRaK9%|4p9LwJI!`NsiazĔ)%- XMq>pk$-$Q2x#N ؎-QR}ᶦHZډ)J,l#i@yn3LN`;nڔ XuX5pF)m|^0(>BHF9(cզEerJI rg7 4I@z0\JIi䵙RR0s;$s6eJ,`n 䂦0a)S)A 1eJ,堌#635RIgpNHuTH_SԕqVe ` &S)>p;S$魁eKIuX`I4춒o}`m$1":PI<[v9^\pTJjriRŭ P{#{R2,`)e-`mgj~1ϣLKam7&U\j/3mJ,`F;M'䱀 .KR#)yhTq;pcK9(q!w?uRR,n.yw*UXj#\]ɱ(qv2=RqfB#iJmmL<]Y͙#$5 uTU7ӦXR+q,`I}qL'`6Kͷ6r,]0S$- [RKR3oiRE|nӦXR.(i:LDLTJjY%o:)6rxzҒqTJjh㞦I.$YR.ʼnGZ\ֿf:%55 I˼!6dKxm4E"mG_ s? .e*?LRfK9%q#uh$)i3ULRfK9yxm܌bj84$i1U^@Wbm4uJ,ҪA>_Ij?1v32[gLRD96oTaR׿N7%L2 NT,`)7&ƝL*꽙yp_$M2#AS,`)7$rkTA29_Iye"|/0t)$n XT2`YJ;6Jx".e<`$) PI$5V4]29SRI>~=@j]lp2`K9Jaai^" Ԋ29ORI%:XV5]JmN9]H;1UC39NI%Xe78t)a;Oi Ҙ>Xt"~G>_mn:%|~ޅ_+]$o)@ǀ{hgN;IK6G&rp)T2i୦KJuv*T=TOSV>(~D>dm,I*Ɛ:R#ۙNI%D>G.n$o;+#RR!.eU˽TRI28t)1LWϚ>IJa3oFbu&:tJ*(F7y0ZR ^p'Ii L24x| XRI%ۄ>S1]Jy[zL$adB7.eh4%%누>WETf+3IR:I3Xה)3אOۦSRO'ٺ)S}"qOr[B7ϙ.edG)^ETR"RtRݜh0}LFVӦDB^k_JDj\=LS(Iv─aTeZ%eUAM-0;~˃@i|l @S4y72>sX-vA}ϛBI!ݎߨWl*)3{'Y|iSlEڻ(5KtSI$Uv02,~ԩ~x;P4ցCrO%tyn425:KMlD ^4JRxSهF_}شJTS6uj+ﷸk$eZO%G*^V2u3EMj3k%)okI]dT)URKDS 7~m@TJR~荪fT"֛L \sM -0T KfJz+nإKr L&j()[E&I ߴ>e FW_kJR|!O:5/2跌3T-'|zX ryp0JS ~^F>-2< `*%ZFP)bSn"L :)+pʷf(pO3TMW$~>@~ū:TAIsV1}S2<%ޟM?@iT ,Eūoz%i~g|`wS(]oȤ8)$ ntu`өe`6yPl IzMI{ʣzʨ )IZ2= ld:5+請M$-ї;U>_gsY$ÁN5WzWfIZ)-yuXIfp~S*IZdt;t>KūKR|$#LcԀ+2\;kJ`]YǔM1B)UbG"IRߊ<xܾӔJ0Z='Y嵤 Leveg)$znV-º^3Ւof#0Tfk^Zs[*I꯳3{)ˬW4Ւ4 OdpbZRS|*I 55#"&-IvT&/윚Ye:i$ 9{LkuRe[I~_\ؠ%>GL$iY8 9ܕ"S`kS.IlC;Ҏ4x&>u_0JLr<J2(^$5L s=MgV ~,Iju> 7r2)^=G$1:3G< `J3~&IR% 6Tx/rIj3O< ʔ&#f_yXJiގNSz; Tx(i8%#4 ~AS+IjerIUrIj362v885+IjAhK__5X%nV%Iͳ-y|7XV2v4fzo_68"S/I-qbf; LkF)KSM$ Ms>K WNV}^`-큧32ŒVؙGdu,^^m%6~Nn&͓3ŒVZMsRpfEW%IwdǀLm[7W&bIRL@Q|)* i ImsIMmKmyV`i$G+R 0tV'!V)֏28vU7͒vHꦼtxꗞT ;S}7Mf+fIRHNZUkUx5SAJㄌ9MqμAIRi|j5)o*^'<$TwI1hEU^c_j?Е$%d`z cyf,XO IJnTgA UXRD }{H}^S,P5V2\Xx`pZ|Yk:$e ~ @nWL.j+ϝYb퇪bZ BVu)u/IJ_ 1[p.p60bC >|X91P:N\!5qUB}5a5ja `ubcVxYt1N0Zzl4]7­gKj]?4ϻ *[bg$)+À*x쳀ogO$~,5 زUS9 lq3+5mgw@np1sso Ӻ=|N6 /g(Wv7U;zωM=wk,0uTg_`_P`uz?2yI!b`kĸSo+Qx%!\οe|އԁKS-s6pu_(ֿ$i++T8=eY; צP+phxWQv*|p1. ά. XRkIQYP,drZ | B%wP|S5`~́@i޾ E;Չaw{o'Q?%iL{u D?N1BD!owPHReFZ* k_-~{E9b-~P`fE{AܶBJAFO wx6Rox5 K5=WwehS8 (JClJ~ p+Fi;ŗo+:bD#g(C"wA^ r.F8L;dzdIHUX݆ϞXg )IFqem%I4dj&ppT{'{HOx( Rk6^C٫O.)3:s(۳(Z?~ٻ89zmT"PLtw䥈5&b<8GZ-Y&K?e8,`I6e(֍xb83 `rzXj)F=l($Ij 2*(F?h(/9ik:I`m#p3MgLaKjc/U#n5S# m(^)=y=đx8ŬI[U]~SцA4p$-F i(R,7Cx;X=cI>{Km\ o(Tv2vx2qiiDJN,Ҏ!1f 5quBj1!8 rDFd(!WQl,gSkL1Bxg''՞^ǘ;pQ P(c_ IRujg(Wz bs#P­rz> k c&nB=q+ؔXn#r5)co*Ũ+G?7< |PQӣ'G`uOd>%Mctz# Ԫڞ&7CaQ~N'-P.W`Oedp03C!IZcIAMPUۀ5J<\u~+{9(FbbyAeBhOSܳ1 bÈT#ŠyDžs,`5}DC-`̞%r&ڙa87QWWp6e7 Rϫ/oY ꇅ Nܶըtc!LA T7V4Jsū I-0Pxz7QNF_iZgúWkG83 0eWr9 X]㾮݁#Jˢ C}0=3ݱtBi]_ &{{[/o[~ \q鯜00٩|cD3=4B_b RYb$óBRsf&lLX#M*C_L܄:gx)WΘsGSbuL rF$9';\4Ɍq'n[%p.Q`u hNb`eCQyQ|l_C>Lb꟟3hSb #xNxSs^ 88|Mz)}:](vbۢamŖ࿥ 0)Q7@0=?^k(*J}3ibkFn HjB׻NO z x}7p 0tfDX.lwgȔhԾŲ }6g E |LkLZteu+=q\Iv0쮑)QٵpH8/2?Σo>Jvppho~f>%bMM}\//":PTc(v9v!gոQ )UfVG+! 35{=x\2+ki,y$~A1iC6#)vC5^>+gǵ@1Hy٪7u;p psϰu/S <aʸGu'tD1ԝI<pg|6j'p:tպhX{o(7v],*}6a_ wXRk,O]Lܳ~Vo45rp"N5k;m{rZbΦ${#)`(Ŵg,;j%6j.pyYT?}-kBDc3qA`NWQū20/^AZW%NQ MI.X#P#,^Ebc&?XR tAV|Y.1!؅⨉ccww>ivl(JT~ u`ٵDm q)+Ri x/x8cyFO!/*!/&,7<.N,YDŽ&ܑQF1Bz)FPʛ?5d 6`kQձ λc؎%582Y&nD_$Je4>a?! ͨ|ȎWZSsv8 j(I&yj Jb5m?HWp=g}G3#|I,5v珿] H~R3@B[☉9Ox~oMy=J;xUVoj bUsl_35t-(ՃɼRB7U!qc+x4H_Qo֮$[GO<4`&č\GOc[.[*Af%mG/ ňM/r W/Nw~B1U3J?P&Y )`ѓZ1p]^l“W#)lWZilUQu`-m|xĐ,_ƪ|9i:_{*(3Gѧ}UoD+>m_?VPۅ15&}2|/pIOʵ> GZ9cmíتmnz)yߐbD >e}:) r|@R5qVSA10C%E_'^8cR7O;6[eKePGϦX7jb}OTGO^jn*媓7nGMC t,k31Rb (vyܴʭ!iTh8~ZYZp(qsRL ?b}cŨʊGO^!rPJO15MJ[c&~Z`"ѓޔH1C&^|Ш|rʼ,AwĴ?b5)tLU)F| &g٣O]oqSUjy(x<Ϳ3 .FSkoYg2 \_#wj{u'rQ>o;%n|F*O_L"e9umDds?.fuuQbIWz |4\0 sb;OvxOSs; G%T4gFRurj(֍ڑb uԖKDu1MK{1^ q; C=6\8FR艇!%\YÔU| 88m)֓NcLve C6z;o&X x59:q61Z(T7>C?gcļxѐ Z oo-08jہ x,`' ҔOcRlf~`jj".Nv+sM_]Zk g( UOPyεx%pUh2(@il0ݽQXxppx-NS( WO+轾 nFߢ3M<;z)FBZjciu/QoF 7R¥ ZFLF~#ȣߨ^<쩡ݛкvџ))ME>ώx4m#!-m!L;vv#~Y[đKmx9.[,UFS CVkZ +ߟrY٧IZd/ioi$%͝ب_ֶX3ܫhNU ZZgk=]=bbJS[wjU()*I =ώ:}-蹞lUj:1}MWm=̛ _ ¾,8{__m{_PVK^n3esw5ӫh#$-q=A̟> ,^I}P^J$qY~Q[ Xq9{#&T.^GVj__RKpn,b=`żY@^՝;z{paVKkQXj/)y TIc&F;FBG7wg ZZDG!x r_tƢ!}i/V=M/#nB8 XxЫ ^@CR<{䤭YCN)eKOSƟa $&g[i3.C6xrOc8TI;o hH6P&L{@q6[ Gzp^71j(l`J}]e6X☉#͕ ׈$AB1Vjh㭦IRsqFBjwQ_7Xk>y"N=MB0 ,C #o6MRc0|$)ف"1!ixY<B9mx `,tA>)5ػQ?jQ?cn>YZe Tisvh# GMމȇp:ԴVuږ8ɼH]C.5C!UV;F`mbBk LTMvPʍϤj?ԯ/Qr1NB`9s"s TYsz &9S%U԰> {<ؿSMxB|H\3@!U| k']$U+> |HHMLޢ?V9iD!-@x TIî%6Z*9X@HMW#?nN ,oe6?tQwڱ.]-y':mW0#!J82qFjH -`ѓ&M0u Uγmxϵ^-_\])@0Rt.8/?ٰCY]x}=sD3ojަЫNuS%U}ԤwHH>ڗjܷ_3gN q7[q2la*ArǓԖ+p8/RGM ]jacd(JhWko6ڎbj]i5Bj3+3!\j1UZLsLTv8HHmup<>gKMJj0@H%,W΃7R) ">c, xixј^ aܖ>H[i.UIHc U1=yW\=S*GR~)AF=`&2h`DzT󑓶J+?W+}C%P:|0H܆}-<;OC[~o.$~i}~HQ TvXΈr=b}$vizL4:ȰT|4~*!oXQR6Lk+#t/g lԁߖ[Jڶ_N$k*". xsxX7jRVbAAʯKҎU3)zSNN _'s?f)6X!%ssAkʱ>qƷb hg %n ~p1REGMHH=BJiy[<5 ǁJҖgKR*倳e~HUy)Ag,K)`Vw6bRR:qL#\rclK/$sh*$ 6덤 KԖc 3Z9=Ɣ=o>X Ώ"1 )a`SJJ6k(<c e{%kϊP+SL'TcMJWRm ŏ"w)qc ef꒵i?b7b('"2r%~HUS1\<(`1Wx9=8HY9m:X18bgD1u ~|H;K-Uep,, C1 RV.MR5άh,tWO8WC$ XRVsQS]3GJ|12 [vM :k#~tH30Rf-HYݺ-`I9%lIDTm\ S{]9gOڒMNCV\G*2JRŨ;Rҏ^ڽ̱mq1Eu?To3I)y^#jJw^Ńj^vvlB_⋌P4x>0$c>K†Aļ9s_VjTt0l#m>E-,,x,-W)سo&96RE XR.6bXw+)GAEvL)͞K4$p=Ũi_ѱOjb HY/+@θH9޼]Nԥ%n{ &zjT? Ty) s^ULlb,PiTf^<À] 62R^V7)S!nllS6~͝V}-=%* ʻ>G DnK<y&>LPy7'r=Hj 9V`[c"*^8HpcO8bnU`4JȪAƋ#1_\ XϘHPRgik(~G~0DAA_2p|J묭a2\NCr]M_0 ^T%e#vD^%xy-n}-E\3aS%yN!r_{ )sAw ڼp1pEAk~v<:`'ӭ^5 ArXOI驻T (dk)_\ PuA*BY]yB"l\ey hH*tbK)3 IKZ򹞋XjN n *n>k]X_d!ryBH ]*R 0(#'7 %es9??ښFC,ՁQPjARJ\Ρw K#jahgw;2$l*) %Xq5!U᢯6Re] |0[__64ch&_}iL8KEgҎ7 M/\`|.p,~`a=BR?xܐrQ8K XR2M8f ?`sgWS%" Ԉ 7R%$ N}?QL1|-эټwIZ%pvL3Hk>,ImgW7{E xPHx73RA @RS CC !\ȟ5IXR^ZxHл$Q[ŝ40 (>+ _C >BRt<,TrT {O/H+˟Pl6 I B)/VC<6a2~(XwV4gnXR ϱ5ǀHٻ?tw똤Eyxp{#WK qG%5],(0ӈH HZ])ג=K1j&G(FbM@)%I` XRg ʔ KZG(vP,<`[ Kn^ SJRsAʠ5xՅF`0&RbV tx:EaUE/{fi2;.IAwW8/tTxAGOoN?G}l L(n`Zv?pB8K_gI+ܗ #i?ޙ.) p$utc ~DžfՈEo3l/)I-U?aԅ^jxArA ΧX}DmZ@QLےbTXGd.^|xKHR{|ΕW_h] IJ`[G9{).y) 0X YA1]qp?p_k+J*Y@HI>^?gt.06Rn ,` ?);p pSF9ZXLBJPWjgQ|&)7! HjQt<| ؅W5 x W HIzYoVMGP Hjn`+\(dNW)F+IrS[|/a`K|ͻ0Hj{R,Q=\ (F}\WR)AgSG`IsnAR=|8$}G(vC$)s FBJ?]_u XRvύ6z ŨG[36-T9HzpW̞ú Xg큽=7CufzI$)ki^qk-) 0H*N` QZkk]/tnnsI^Gu't=7$ Z;{8^jB% IItRQS7[ϭ3 $_OQJ`7!]W"W,)Iy W AJA;KWG`IY{8k$I$^%9.^(`N|LJ%@$I}ֽp=FB*xN=gI?Q{٥4B)mw $Igc~dZ@G9K X?7)aK%݅K$IZ-`IpC U6$I\0>!9k} Xa IIS0H$I H ?1R.Чj:4~Rw@p$IrA*u}WjWFPJ$I➓/6#! LӾ+ X36x8J |+L;v$Io4301R20M I$-E}@,pS^ޟR[/s¹'0H$IKyfŸfVOπFT*a$I>He~VY/3R/)>d$I>28`Cjw,n@FU*9ttf$I~<;=/4RD~@ X-ѕzἱI$: ԍR a@b X{+Qxuq$IЛzo /~3\8ڒ4BN7$IҀj V]n18H$IYFBj3̵̚ja pp $Is/3R Ӻ-Yj+L;.0ŔI$Av? #!5"aʄj}UKmɽH$IjCYs?h$IDl843.v}m7UiI=&=0Lg0$I4: embe` eQbm0u? $IT!Sƍ'-sv)s#C0:XB2a w I$zbww{."pPzO =Ɔ\[ o($Iaw]`E).Kvi:L*#gР7[$IyGPI=@R 4yR~̮´cg I$I/<tPͽ hDgo 94Z^k盇΄8I56^W$I^0̜N?4*H`237}g+hxoq)SJ@p|` $I%>-hO0eO>\ԣNߌZD6R=K ~n($I$y3D>o4b#px2$yڪtzW~a $I~?x'BwwpH$IZݑnC㧄Pc_9sO gwJ=l1:mKB>Ab<4Lp$Ib o1ZQ@85b̍ S'F,Fe,^I$IjEdù{l4 8Ys_s Z8.x m"+{~?q,Z D!I$ϻ'|XhB)=…']M>5 rgotԎ 獽PH$IjIPhh)n#cÔqA'ug5qwU&rF|1E%I$%]!'3AFD/;Ck_`9 v!ٴtPV;x`'*bQa w I$Ix5 FC3D_~A_#O݆DvV?<qw+I$I{=Z8".#RIYyjǪ=fDl9%M,a8$I$Ywi[7ݍFe$s1ՋBVA?`]#!oz4zjLJo8$I$%@3jAa4(o ;p,,dya=F9ً[LSPH$IJYЉ+3> 5"39aZ<ñh!{TpBGkj}Sp $IlvF.F$I z< '\K*qq.f<2Y!S"-\I$IYwčjF$ w9 \ߪB.1v!Ʊ?+r:^!I$BϹB H"B;L'G[ 4U#5>੐)|#o0aڱ$I>}k&1`U#V?YsV x>{t1[I~D&(I$I/{H0fw"q"y%4 IXyE~M3 8XψL}qE$I[> nD?~sf ]o΁ cT6"?'_Ἣ $I>~.f|'!N?⟩0G KkXZE]ޡ;/&?k OۘH$IRۀwXӨ<7@PnS04aӶp.:@\IWQJ6sS%I$e5ڑv`3:x';wq_vpgHyXZ 3gЂ7{{EuԹn±}$I$8t;b|591nءQ"P6O5i }iR̈́%Q̄p!I䮢]O{H$IRϻ9s֧ a=`- aB\X0"+5"C1Hb?߮3x3&gşggl_hZ^,`5?ߎvĸ%̀M!OZC2#0x LJ0 Gw$I$I}<{Eb+y;iI,`ܚF:5ܛA8-O-|8K7s|#Z8a&><a&/VtbtLʌI$I$I$I$I$I$IRjDD%tEXtdate:create2022-05-31T04:40:26+00:00!Î%tEXtdate:modify2022-05-31T04:40:26+00:00|{2IENDB`Mini Shell

HOME


Mini Shell 1.0
DIR:/home/htlwork.com/www/awesomecandy/pub/static/frontend/Magento/blank/en_US/js/bundle/
Upload File :
Current File : /home/htlwork.com/www/awesomecandy/pub/static/frontend/Magento/blank/en_US/js/bundle/bundle4.js
require.config({"config": {
        "jsbuild":{"mage/gallery/gallery.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'fotorama/fotorama',\n    'underscore',\n    'matchMedia',\n    'mage/template',\n    'text!mage/gallery/gallery.html',\n    'uiClass',\n    'mage/translate'\n], function ($, fotorama, _, mediaCheck, template, galleryTpl, Class, $t) {\n    'use strict';\n\n    /**\n     * Retrieves index if the main item.\n     * @param {Array.<Object>} data - Set of gallery items.\n     */\n    var getMainImageIndex = function (data) {\n            var mainIndex;\n\n            if (_.every(data, function (item) {\n                    return _.isObject(item);\n                })\n            ) {\n                mainIndex = _.findIndex(data, function (item) {\n                    return item.isMain;\n                });\n            }\n\n            return mainIndex > 0 ? mainIndex : 0;\n        },\n\n        /**\n         * Helper for parse translate property\n         *\n         * @param {Element} el - el that to parse\n         * @returns {Array} - array of properties.\n         */\n        getTranslate = function (el) {\n            var slideTransform = $(el).attr('style').split(';');\n\n            slideTransform = $.map(slideTransform, function (style) {\n                style = style.trim();\n\n                if (style.startsWith('transform: translate3d')) {\n                    return style.match(/transform: translate3d\\((.+)px,(.+)px,(.+)px\\)/);\n                }\n\n                return false;\n            });\n\n            return slideTransform.filter(Boolean);\n        },\n\n        /**\n         * @param {*} str\n         * @return {*}\n         * @private\n         */\n        _toNumber = function (str) {\n            var type = typeof str;\n\n            if (type === 'string') {\n                return parseInt(str); //eslint-disable-line radix\n            }\n\n            return str;\n        };\n\n    return Class.extend({\n\n        defaults: {\n            settings: {},\n            config: {},\n            startConfig: {}\n        },\n\n        /**\n         * Checks if device has touch interface.\n         * @return {Boolean} The result of searching touch events on device.\n         */\n        isTouchEnabled: (function () {\n            return 'ontouchstart' in document.documentElement;\n        })(),\n\n        /**\n         * Initializes gallery.\n         * @param {Object} config - Gallery configuration.\n         * @param {String} element - String selector of gallery DOM element.\n         */\n        initialize: function (config, element) {\n            var self = this;\n\n            this._super();\n\n            _.bindAll(this,\n                '_focusSwitcher'\n            );\n\n            /*turn off arrows for touch devices*/\n            if (this.isTouchEnabled) {\n                config.options.arrows = false;\n\n                if (config.fullscreen) {\n                    config.fullscreen.arrows = false;\n                }\n            }\n\n            config.options.width = _toNumber(config.options.width);\n            config.options.height = _toNumber(config.options.height);\n            config.options.thumbwidth = _toNumber(config.options.thumbwidth);\n            config.options.thumbheight = _toNumber(config.options.thumbheight);\n\n            config.options.swipe = true;\n            this.config = config;\n\n            this.settings = {\n                $element: $(element),\n                $pageWrapper: $('body>.page-wrapper'),\n                currentConfig: config,\n                defaultConfig: _.clone(config),\n                fullscreenConfig: _.clone(config.fullscreen),\n                breakpoints: config.breakpoints,\n                activeBreakpoint: {},\n                fotoramaApi: null,\n                isFullscreen: false,\n                api: null,\n                data: _.clone(config.data)\n            };\n            config.options.ratio = config.options.width / config.options.height;\n            config.options.height = null;\n\n            $.extend(true, this.startConfig, config);\n\n            this.initGallery();\n            this.initApi();\n            this.setupBreakpoints();\n            this.initFullscreenSettings();\n\n            this.settings.$element.on('click', '.fotorama__stage__frame', function () {\n                if (\n                    !$(this).parents('.fotorama__shadows--left, .fotorama__shadows--right').length &&\n                    !$(this).hasClass('fotorama-video-container')\n                ) {\n                    self.openFullScreen();\n                }\n            });\n\n            if (this.isTouchEnabled && this.settings.isFullscreen) {\n                this.settings.$element.on('tap', '.fotorama__stage__frame', function () {\n                    var translate = getTranslate($(this).parents('.fotorama__stage__shaft'));\n\n                    if (translate[1] === '0' && !$(this).hasClass('fotorama-video-container')) {\n                        self.openFullScreen();\n                        self.settings.$pageWrapper.hide();\n                    }\n                });\n            }\n        },\n\n        /**\n         * Open gallery fullscreen\n         */\n        openFullScreen: function () {\n            this.settings.api.fotorama.requestFullScreen();\n            this.settings.$fullscreenIcon.css({\n                opacity: 1,\n                visibility: 'visible',\n                display: 'block'\n            });\n        },\n\n        /**\n         * Gallery fullscreen settings.\n         */\n        initFullscreenSettings: function () {\n            var settings = this.settings,\n                self = this;\n\n            settings.$gallery = this.settings.$element.find('[data-gallery-role=\"gallery\"]');\n            settings.$fullscreenIcon = this.settings.$element.find('[data-gallery-role=\"fotorama__fullscreen-icon\"]');\n            settings.focusableStart = this.settings.$element.find('[data-gallery-role=\"fotorama__focusable-start\"]');\n            settings.focusableEnd = this.settings.$element.find('[data-gallery-role=\"fotorama__focusable-end\"]');\n            settings.closeIcon = this.settings.$element.find('[data-gallery-role=\"fotorama__fullscreen-icon\"]');\n            settings.fullscreenConfig.swipe = true;\n\n            settings.$gallery.on('fotorama:fullscreenenter', function () {\n                settings.closeIcon.show();\n                settings.focusableStart.attr('tabindex', '0');\n                settings.focusableEnd.attr('tabindex', '0');\n                settings.focusableStart.on('focusin', self._focusSwitcher);\n                settings.focusableEnd.on('focusin', self._focusSwitcher);\n                settings.api.updateOptions(settings.defaultConfig.options, true);\n                settings.api.updateOptions(settings.fullscreenConfig, true);\n\n                if (!_.isEqual(settings.activeBreakpoint, {}) && settings.breakpoints) {\n                    settings.api.updateOptions(settings.activeBreakpoint.options, true);\n                }\n                settings.isFullscreen = true;\n            });\n\n            settings.$gallery.on('fotorama:fullscreenexit', function () {\n                settings.closeIcon.hide();\n                settings.focusableStart.attr('tabindex', '-1');\n                settings.focusableEnd.attr('tabindex', '-1');\n                settings.api.updateOptions(settings.defaultConfig.options, true);\n                settings.focusableStart.off('focusin', this._focusSwitcher);\n                settings.focusableEnd.off('focusin', this._focusSwitcher);\n                settings.closeIcon.hide();\n\n                if (!_.isEqual(settings.activeBreakpoint, {}) && settings.breakpoints) {\n                    settings.api.updateOptions(settings.activeBreakpoint.options, true);\n                }\n                settings.isFullscreen = false;\n                settings.$element.data('gallery').updateOptions({\n                    swipe: true\n                });\n            });\n        },\n\n        /**\n         * Switcher focus.\n         */\n        _focusSwitcher: function (e) {\n            var target = $(e.target),\n                settings = this.settings;\n\n            if (target.is(settings.focusableStart)) {\n                this._setFocus('start');\n            } else if (target.is(settings.focusableEnd)) {\n                this._setFocus('end');\n            }\n        },\n\n        /**\n         * Set focus to element.\n         * @param {String} position - can be \"start\" and \"end\"\n         *      positions.\n         *      If position is \"end\" - sets focus to first\n         *      focusable element in modal window scope.\n         *      If position is \"start\" - sets focus to last\n         *      focusable element in modal window scope\n         */\n        _setFocus: function (position) {\n            var settings = this.settings,\n                focusableElements,\n                infelicity;\n\n            if (position === 'end') {\n                settings.$gallery.find(settings.closeIcon).trigger('focus');\n            } else if (position === 'start') {\n                infelicity = 3; //Constant for find last focusable element\n                focusableElements = settings.$gallery.find(':focusable');\n                focusableElements.eq(focusableElements.length - infelicity).trigger('focus');\n            }\n        },\n\n        /**\n         * Initializes gallery with configuration options.\n         */\n        initGallery: function () {\n            var breakpoints = {},\n                settings = this.settings,\n                config = this.config,\n                tpl = template(galleryTpl, {\n                    next: $t('Next'),\n                    previous: $t('Previous')\n                }),\n                mainImageIndex,\n                $element = settings.$element,\n                $fotoramaElement,\n                $fotoramaStage;\n\n            if (settings.breakpoints) {\n                _.each(_.values(settings.breakpoints), function (breakpoint) {\n                    var conditions;\n\n                    _.each(_.pairs(breakpoint.conditions), function (pair) {\n                        conditions = conditions ? conditions + ' and (' + pair[0] + ': ' + pair[1] + ')' :\n                        '(' + pair[0] + ': ' + pair[1] + ')';\n                    });\n                    breakpoints[conditions] = breakpoint.options;\n                });\n                settings.breakpoints = breakpoints;\n            }\n\n            _.extend(config, config.options,\n                {\n                    options: undefined,\n                    click: false,\n                    breakpoints: null\n                }\n            );\n            settings.currentConfig = config;\n\n            $element\n                .css('min-height', settings.$element.height())\n                .append(tpl);\n\n            $fotoramaElement = $element.find('[data-gallery-role=\"gallery\"]');\n\n            $fotoramaStage = $fotoramaElement.find('.fotorama__stage');\n            $fotoramaStage.css('position', 'absolute');\n\n            $fotoramaElement.fotorama(config);\n            $fotoramaElement.find('.fotorama__stage__frame.fotorama__active')\n                    .one('f:load', function () {\n                        // Remove placeholder when main gallery image loads.\n                        $element.find('.gallery-placeholder__image').remove();\n                        $element\n                            .removeClass('_block-content-loading')\n                            .css('min-height', '');\n\n                        $fotoramaStage.css('position', '');\n                    });\n            settings.$elementF = $fotoramaElement;\n            settings.fotoramaApi = $fotoramaElement.data('fotorama');\n\n            $.extend(true, config, this.startConfig);\n\n            mainImageIndex = getMainImageIndex(config.data);\n\n            if (mainImageIndex) {\n                this.settings.fotoramaApi.show({\n                    index: mainImageIndex,\n                    time: 0\n                });\n            }\n        },\n\n        /**\n         * Creates breakpoints for gallery.\n         */\n        setupBreakpoints: function () {\n            var pairs,\n                settings = this.settings,\n                config = this.config,\n                startConfig = this.startConfig,\n                isInitialized = {},\n                isTouchEnabled = this.isTouchEnabled;\n\n            if (_.isObject(settings.breakpoints)) {\n                pairs = _.pairs(settings.breakpoints);\n                _.each(pairs, function (pair) {\n                    var mediaQuery = pair[0];\n\n                    isInitialized[mediaQuery] = false;\n                    mediaCheck({\n                        media: mediaQuery,\n\n                        /**\n                         * Is triggered when breakpoint enties.\n                         */\n                        entry: function () {\n                            $.extend(true, config, _.clone(startConfig));\n\n                            settings.api.updateOptions(settings.defaultConfig.options, true);\n\n                            if (settings.isFullscreen) {\n                                settings.api.updateOptions(settings.fullscreenConfig, true);\n                            }\n\n                            if (isTouchEnabled) {\n                                settings.breakpoints[mediaQuery].options.arrows = false;\n\n                                if (settings.breakpoints[mediaQuery].options.fullscreen) {\n                                    settings.breakpoints[mediaQuery].options.fullscreen.arrows = false;\n                                }\n                            }\n\n                            settings.api.updateOptions(settings.breakpoints[mediaQuery].options, true);\n                            $.extend(true, config, settings.breakpoints[mediaQuery]);\n                            settings.activeBreakpoint = settings.breakpoints[mediaQuery];\n\n                            isInitialized[mediaQuery] = true;\n                        },\n\n                        /**\n                         * Is triggered when breakpoint exits.\n                         */\n                        exit: function () {\n                            if (isInitialized[mediaQuery]) {\n                                $.extend(true, config, _.clone(startConfig));\n                                settings.api.updateOptions(settings.defaultConfig.options, true);\n\n                                if (settings.isFullscreen) {\n                                    settings.api.updateOptions(settings.fullscreenConfig, true);\n                                }\n                                settings.activeBreakpoint = {};\n                            } else {\n                                isInitialized[mediaQuery] = true;\n                            }\n                        }\n                    });\n                });\n            }\n        },\n\n        /**\n         * Creates gallery's API.\n         */\n        initApi: function () {\n            var settings = this.settings,\n                config = this.config,\n                api = {\n\n                    /**\n                     * Contains fotorama's API methods.\n                     */\n                    fotorama: settings.fotoramaApi,\n\n                    /**\n                     * Displays the last image on preview.\n                     */\n                    last: function () {\n                        settings.fotoramaApi.show('>>');\n                    },\n\n                    /**\n                     * Displays the first image on preview.\n                     */\n                    first: function () {\n                        settings.fotoramaApi.show('<<');\n                    },\n\n                    /**\n                     * Displays previous element on preview.\n                     */\n                    prev: function () {\n                        settings.fotoramaApi.show('<');\n                    },\n\n                    /**\n                     * Displays next element on preview.\n                     */\n                    next: function () {\n                        settings.fotoramaApi.show('>');\n                    },\n\n                    /**\n                     * Displays image with appropriate count number on preview.\n                     * @param {Number} index - Number of image that should be displayed.\n                     */\n                    seek: function (index) {\n                        if (_.isNumber(index) && index !== 0) {\n\n                            if (index > 0) {\n                                index -= 1;\n                            }\n                            settings.fotoramaApi.show(index);\n                        }\n                    },\n\n                    /**\n                     * Updates gallery with new set of options.\n                     * @param {Object} configuration - Standart gallery configuration object.\n                     * @param {Boolean} isInternal - Is this function called via breakpoints.\n                     */\n                    updateOptions: function (configuration, isInternal) {\n\n                        var $selectable = $('a[href], area[href], input, select, ' +\n                                'textarea, button, iframe, object, embed, *[tabindex], *[contenteditable]')\n                                .not('[tabindex=-1], [disabled], :hidden'),\n                            $focus = $(':focus'),\n                            index;\n\n                        if (_.isObject(configuration)) {\n\n                            //Saves index of focus\n                            $selectable.each(function (number) {\n                                if ($(this).is($focus)) {\n                                    index = number;\n                                }\n                            });\n\n                            if (this.isTouchEnabled) {\n                                configuration.arrows = false;\n                            }\n                            configuration.click = false;\n                            configuration.breakpoints = null;\n\n                            if (!isInternal) {\n                                !_.isEqual(settings.activeBreakpoint, {} && settings.breakpoints) ?\n                                    $.extend(true, settings.activeBreakpoint.options, configuration) :\n\n                                    settings.isFullscreen ?\n                                        $.extend(true, settings.fullscreenConfig, configuration) :\n                                        $.extend(true, settings.defaultConfig.options, configuration);\n\n                            }\n                            $.extend(true, settings.currentConfig.options, configuration);\n                            settings.fotoramaApi.setOptions(settings.currentConfig.options);\n\n                            if (_.isNumber(index)) {\n                                $selectable.eq(index).trigger('focus');\n                            }\n                        }\n                    },\n\n                    /**\n                     * Updates gallery with specific set of items.\n                     * @param {Array.<Object>} data - Set of gallery items to update.\n                     */\n                    updateData: function (data) {\n                        var mainImageIndex;\n\n                        if (_.isArray(data)) {\n                            settings.fotoramaApi.load(data);\n                            mainImageIndex = getMainImageIndex(data);\n\n                            if (settings.fotoramaApi.activeIndex !== mainImageIndex) {\n                                settings.fotoramaApi.show({\n                                    index: mainImageIndex,\n                                    time: 0\n                                });\n                            }\n\n                            $.extend(false, settings, {\n                                data: data,\n                                defaultConfig: data\n                            });\n                            $.extend(false, config, {\n                                data: data\n                            });\n                        }\n                    },\n\n                    /**\n                     * Returns current images list\n                     *\n                     * @returns {Array}\n                     */\n                    returnCurrentImages: function () {\n                        var images = [];\n\n                        _.each(this.fotorama.data, function (item) {\n                            images.push(_.omit(item, '$navThumbFrame', '$navDotFrame', '$stageFrame', 'labelledby'));\n                        });\n\n                        return images;\n                    },\n\n                    /**\n                     * Updates gallery data partially by index\n                     * @param {Number} index - Index of image in data array to be updated.\n                     * @param {Object} item - Standart gallery image object.\n                     *\n                     */\n                    updateDataByIndex: function (index, item) {\n                        settings.fotoramaApi.spliceByIndex(index, item);\n                    }\n                };\n\n            settings.$element.data('gallery', api);\n            settings.api = settings.$element.data('gallery');\n            settings.$element.trigger('gallery:loaded');\n        }\n    });\n});\n","mage/msie/file-reader.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    /**\n     * Init \"readAsBinaryString\" function for FileReader class.\n     * It need for IE11\n     * @param {Blob} fileData\n     */\n    var readAsBinaryStringIEFunc = function (fileData) {\n        var binary = '',\n            self = this,\n            reader = new FileReader();\n\n        /**\n         * Read file as binary string\n         */\n        reader.onload = function () {\n            var bytes, length, index;\n\n            /* eslint-disable no-undef */\n            bytes = new Uint8Array(reader.result);\n            /* eslint-enable */\n            length = bytes.length;\n\n            for (index = 0; index < length; index++) {\n                binary += String.fromCharCode(bytes[index]);\n            }\n            //self.result  - readonly so assign binary\n            self.content = binary;\n            $(self).trigger('onload');\n        };\n        reader.readAsArrayBuffer(fileData);\n    };\n\n    if (typeof FileReader.prototype.readAsBinaryString === 'undefined') {\n        FileReader.prototype.readAsBinaryString = readAsBinaryStringIEFunc;\n    }\n});\n","mage/apply/main.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'jquery',\n    './scripts'\n], function (_, $, processScripts) {\n    'use strict';\n\n    var dataAttr = 'data-mage-init',\n        nodeSelector = '[' + dataAttr + ']';\n\n    /**\n     * Initializes components assigned to a specified element via data-* attribute.\n     *\n     * @param {HTMLElement} el - Element to initialize components with.\n     * @param {Object|String} config - Initial components' config.\n     * @param {String} component - Components' path.\n     */\n    function init(el, config, component) {\n        require([component], function (fn) {\n            var $el;\n\n            if (typeof fn === 'object') {\n                fn = fn[component].bind(fn);\n            }\n\n            if (_.isFunction(fn)) {\n                fn = fn.bind(null, config, el);\n            } else {\n                $el = $(el);\n\n                if ($el[component]) {\n                    // eslint-disable-next-line jquery-no-bind-unbind\n                    fn = $el[component].bind($el, config);\n                }\n            }\n            // Init module in separate task to prevent blocking main thread.\n            setTimeout(fn);\n        }, function (error) {\n            if ('console' in window && typeof window.console.error === 'function') {\n                console.error(error);\n            }\n\n            return true;\n        });\n    }\n\n    /**\n     * Parses elements 'data-mage-init' attribute as a valid JSON data.\n     * Note: data-mage-init attribute will be removed.\n     *\n     * @param {HTMLElement} el - Element whose attribute should be parsed.\n     * @returns {Object}\n     */\n    function getData(el) {\n        var data = el.getAttribute(dataAttr);\n\n        el.removeAttribute(dataAttr);\n\n        return {\n            el: el,\n            data: JSON.parse(data)\n        };\n    }\n\n    return {\n        /**\n         * Initializes components assigned to HTML elements via [data-mage-init].\n         *\n         * @example Sample 'data-mage-init' declaration.\n         *      data-mage-init='{\"path/to/component\": {\"foo\": \"bar\"}}'\n         */\n        apply: function (context) {\n            var virtuals = processScripts(!context ? document : context),\n                nodes = document.querySelectorAll(nodeSelector);\n\n            _.toArray(nodes)\n                .map(getData)\n                .concat(virtuals)\n                .forEach(function (itemContainer) {\n                    var element = itemContainer.el;\n\n                    _.each(itemContainer.data, function (obj, key) {\n                            if (obj.mixins) {\n                                require(obj.mixins, function () { //eslint-disable-line max-nested-callbacks\n                                    var i, len;\n\n                                    for (i = 0, len = arguments.length; i < len; i++) {\n                                        $.extend(\n                                            true,\n                                            itemContainer.data[key],\n                                            arguments[i](itemContainer.data[key], element)\n                                        );\n                                    }\n\n                                    delete obj.mixins;\n                                    init.call(null, element, obj, key);\n                                });\n                            } else {\n                                init.call(null, element, obj, key);\n                            }\n\n                        }\n                    );\n\n                });\n        },\n        applyFor: init\n    };\n});\n","mage/apply/scripts.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'jquery'\n], function (_, $) {\n    'use strict';\n\n    var scriptSelector = 'script[type=\"text/x-magento-init\"]',\n        dataAttr = 'data-mage-init',\n        virtuals = [];\n\n    /**\n     * Adds components to the virtual list.\n     *\n     * @param {Object} components\n     */\n    function addVirtual(components) {\n        virtuals.push({\n            el: false,\n            data: components\n        });\n    }\n\n    /**\n     * Merges provided data with a current data\n     * of a elements' \"data-mage-init\" attribute.\n     *\n     * @param {Object} components - Object with components and theirs configuration.\n     * @param {HTMLElement} elem - Element whose data should be modified.\n     */\n    function setData(components, elem) {\n        var data = elem.getAttribute(dataAttr);\n\n        data = data ? JSON.parse(data) : {};\n        _.each(components, function (obj, key) {\n            if (_.has(obj, 'mixins')) {\n                data[key] = data[key] || {};\n                data[key].mixins = data[key].mixins || [];\n                data[key].mixins = data[key].mixins.concat(obj.mixins);\n                delete obj.mixins;\n            }\n        });\n\n        data = $.extend(true, data, components);\n        data = JSON.stringify(data);\n        elem.setAttribute(dataAttr, data);\n    }\n\n    /**\n     * Search for the elements by privded selector and extends theirs data.\n     *\n     * @param {Object} components - Object with components and theirs configuration.\n     * @param {String} selector - Selector for the elements.\n     */\n    function processElems(components, selector) {\n        var elems,\n            iterator;\n\n        if (selector === '*') {\n            addVirtual(components);\n\n            return;\n        }\n\n        elems = document.querySelectorAll(selector);\n        iterator = setData.bind(null, components);\n\n        _.toArray(elems).forEach(iterator);\n    }\n\n    /**\n     * Parses content of a provided script node.\n     * Note: node will be removed from DOM.\n     *\n     * @param {HTMLScriptElement} node - Node to be processed.\n     * @returns {Object}\n     */\n    function getNodeData(node) {\n        var data = node.textContent;\n\n        node.parentNode.removeChild(node);\n\n        return JSON.parse(data);\n    }\n\n    /**\n     * Parses 'script' tags with a custom type attribute and moves it's data\n     * to a 'data-mage-init' attribute of an element found by provided selector.\n     * Note: All found script nodes will be removed from DOM.\n     *\n     * @returns {Array} An array of components not assigned to the specific element.\n     *\n     * @example Sample declaration.\n     *      <script type=\"text/x-magento-init\">\n     *          {\n     *              \"body\": {\n     *                  \"path/to/component\": {\"foo\": \"bar\"}\n     *              }\n     *          }\n     *      </script>\n     *\n     * @example Providing data without selector.\n     *      {\n     *          \"*\": {\n     *              \"path/to/component\": {\"bar\": \"baz\"}\n     *          }\n     *      }\n     */\n    return function () {\n        var nodes = document.querySelectorAll(scriptSelector);\n\n        _.toArray(nodes)\n            .map(getNodeData)\n            .forEach(function (item) {\n                _.each(item, processElems);\n            });\n\n        return virtuals.splice(0, virtuals.length);\n    };\n});\n","mage/utils/objects.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    'jquery',\n    'underscore',\n    'mage/utils/strings'\n], function (ko, $, _, stringUtils) {\n    'use strict';\n\n    var primitives = [\n        'undefined',\n        'boolean',\n        'number',\n        'string'\n    ];\n\n    /**\n     * Sets nested property of a specified object.\n     * @private\n     *\n     * @param {Object} parent - Object to look inside for the properties.\n     * @param {Array} path - Splitted path the property.\n     * @param {*} value - Value of the last property in 'path' array.\n     * returns {*} New value for the property.\n     */\n    function setNested(parent, path, value) {\n        var last = path.pop(),\n            len = path.length,\n            pi = 0,\n            part = path[pi];\n\n        for (; pi < len; part = path[++pi]) {\n            if (!_.isObject(parent[part])) {\n                parent[part] = {};\n            }\n\n            parent = parent[part];\n        }\n\n        if (typeof parent[last] === 'function') {\n            parent[last](value);\n        } else {\n            parent[last] = value;\n        }\n\n        return value;\n    }\n\n    /**\n     * Retrieves value of a nested property.\n     * @private\n     *\n     * @param {Object} parent - Object to look inside for the properties.\n     * @param {Array} path - Splitted path the property.\n     * @returns {*} Value of the property.\n     */\n    function getNested(parent, path) {\n        var exists = true,\n            len = path.length,\n            pi = 0;\n\n        for (; pi < len && exists; pi++) {\n            parent = parent[path[pi]];\n\n            if (typeof parent === 'undefined') {\n                exists = false;\n            }\n        }\n\n        if (exists) {\n            if (ko.isObservable(parent)) {\n                parent = parent();\n            }\n\n            return parent;\n        }\n    }\n\n    /**\n     * Removes property from a specified object.\n     * @private\n     *\n     * @param {Object} parent - Object from which to remove property.\n     * @param {Array} path - Splitted path to the property.\n     */\n    function removeNested(parent, path) {\n        var field = path.pop();\n\n        parent = getNested(parent, path);\n\n        if (_.isObject(parent)) {\n            delete parent[field];\n        }\n    }\n\n    return {\n\n        /**\n         * Retrieves or defines objects' property by a composite path.\n         *\n         * @param {Object} data - Container for the properties specified in path.\n         * @param {String} path - Objects' properties divided by dots.\n         * @param {*} [value] - New value for the last property.\n         * @returns {*} Returns value of the last property in chain.\n         *\n         * @example\n         *      utils.nested({}, 'one.two', 3);\n         *      => { one: {two: 3} }\n         */\n        nested: function (data, path, value) {\n            var action = arguments.length > 2 ? setNested : getNested;\n\n            path = path ? path.split('.') : [];\n\n            return action(data, path, value);\n        },\n\n        /**\n         * Removes nested property from an object.\n         *\n         * @param {Object} data - Data source.\n         * @param {String} path - Path to the property e.g. 'one.two.three'\n         */\n        nestedRemove: function (data, path) {\n            path = path.split('.');\n\n            removeNested(data, path);\n        },\n\n        /**\n         * Flattens objects' nested properties.\n         *\n         * @param {Object} data - Object to flatten.\n         * @param {String} [separator='.'] - Objects' keys separator.\n         * @returns {Object} Flattened object.\n         *\n         * @example Example with a default separator.\n         *      utils.flatten({one: { two: { three: 'value'} }});\n         *      => { 'one.two.three': 'value' };\n         *\n         * @example Example with a custom separator.\n         *      utils.flatten({one: { two: { three: 'value'} }}, '=>');\n         *      => {'one=>two=>three': 'value'};\n         */\n        flatten: function (data, separator, parent, result) {\n            separator = separator || '.';\n            result = result || {};\n\n            if (!data) {\n                return result;\n            }\n\n            // UnderscoreJS each breaks when an object has a length property so we use Object.keys\n            _.each(Object.keys(data), function (name) {\n                var node = data[name];\n\n                if ({}.toString.call(node) === '[object Function]') {\n                    return;\n                }\n\n                if (parent) {\n                    name = parent + separator + name;\n                }\n\n                typeof node === 'object' ?\n                    this.flatten(node, separator, name, result) :\n                    result[name] = node;\n\n            }, this);\n\n            return result;\n        },\n\n        /**\n         * Opposite operation of the 'flatten' method.\n         *\n         * @param {Object} data - Previously flattened object.\n         * @param {String} [separator='.'] - Keys separator.\n         * @returns {Object} Object with nested properties.\n         *\n         * @example Example using custom separator.\n         *      utils.unflatten({'one=>two': 'value'}, '=>');\n         *      => {\n         *          one: { two: 'value' }\n         *      };\n         */\n        unflatten: function (data, separator) {\n            var result = {};\n\n            separator = separator || '.';\n\n            _.each(data, function (value, nodes) {\n                nodes = nodes.split(separator);\n\n                setNested(result, nodes, value);\n            });\n\n            return result;\n        },\n\n        /**\n         * Same operation as 'flatten' method,\n         * but returns objects' keys wrapped in '[]'.\n         *\n         * @param {Object} data - Object that should be serialized.\n         * @returns {Object} Serialized data.\n         *\n         * @example\n         *      utils.serialize({one: { two: { three: 'value'} }});\n         *      => { 'one[two][three]': 'value' }\n         */\n        serialize: function (data) {\n            var result = {};\n\n            data = this.flatten(data);\n\n            _.each(data, function (value, keys) {\n                keys = stringUtils.serializeName(keys);\n                value = _.isUndefined(value) ? '' : value;\n\n                result[keys] = value;\n            }, this);\n\n            return result;\n        },\n\n        /**\n         * Performs deep extend of specified objects.\n         *\n         * @returns {Object|Array} Extended object.\n         */\n        extend: function () {\n            var args = _.toArray(arguments);\n\n            args.unshift(true);\n\n            return $.extend.apply($, args);\n        },\n\n        /**\n         * Performs a deep clone of a specified object.\n         *\n         * @param {(Object|Array)} data - Data that should be copied.\n         * @returns {Object|Array} Cloned object.\n         */\n        copy: function (data) {\n            var result = data,\n                isArray = Array.isArray(data),\n                placeholder;\n\n            if (this.isObject(data) || isArray) {\n                placeholder = isArray ? [] : {};\n                result = this.extend(placeholder, data);\n            }\n\n            return result;\n        },\n\n        /**\n         * Performs a deep clone of a specified object.\n         * Doesn't save links to original object.\n         *\n         * @param {*} original - Object to clone\n         * @returns {*}\n         */\n        hardCopy: function (original) {\n            if (original === null || typeof original !== 'object') {\n                return original;\n            }\n\n            return JSON.parse(JSON.stringify(original));\n        },\n\n        /**\n         * Removes specified nested properties from the target object.\n         *\n         * @param {Object} target - Object whose properties should be removed.\n         * @param {(...String|Array|Object)} list - List that specifies properties to be removed.\n         * @returns {Object} Modified object.\n         *\n         * @example Basic usage\n         *      var obj = {a: {b: 2}, c: 'a'};\n         *\n         *      omit(obj, 'a.b');\n         *      => {'a.b': 2};\n         *      obj => {a: {}, c: 'a'};\n         *\n         * @example Various syntaxes that would return same result\n         *      omit(obj, ['a.b', 'c']);\n         *      omit(obj, 'a.b', 'c');\n         *      omit(obj, {'a.b': true, 'c': true});\n         */\n        omit: function (target, list) {\n            var removed = {},\n                ignored = list;\n\n            if (this.isObject(list)) {\n                ignored = [];\n\n                _.each(list, function (value, key) {\n                    if (value) {\n                        ignored.push(key);\n                    }\n                });\n            } else if (_.isString(list)) {\n                ignored = _.toArray(arguments).slice(1);\n            }\n\n            _.each(ignored, function (path) {\n                var value = this.nested(target, path);\n\n                if (!_.isUndefined(value)) {\n                    removed[path] = value;\n\n                    this.nestedRemove(target, path);\n                }\n            }, this);\n\n            return removed;\n        },\n\n        /**\n         * Checks if provided value is a plain object.\n         *\n         * @param {*} value - Value to be checked.\n         * @returns {Boolean}\n         */\n        isObject: function (value) {\n            var objProto = Object.prototype;\n\n            return typeof value == 'object' ?\n            objProto.toString.call(value) === '[object Object]' :\n                false;\n        },\n\n        /**\n         *\n         * @param {*} value\n         * @returns {Boolean}\n         */\n        isPrimitive: function (value) {\n            return value === null || ~primitives.indexOf(typeof value);\n        },\n\n        /**\n         * Iterates over obj props/array elems recursively, applying action to each one\n         *\n         * @param {Object|Array} data - Data to be iterated.\n         * @param {Function} action - Callback to be called with each item as an argument.\n         * @param {Number} [maxDepth=7] - Max recursion depth.\n         */\n        forEachRecursive: function (data, action, maxDepth) {\n            maxDepth = typeof maxDepth === 'number' && !isNaN(maxDepth) ? maxDepth - 1 : 7;\n\n            if (!_.isFunction(action) || _.isFunction(data) || maxDepth < 0) {\n                return;\n            }\n\n            if (!_.isObject(data)) {\n                action(data);\n\n                return;\n            }\n\n            _.each(data, function (value) {\n                this.forEachRecursive(value, action, maxDepth);\n            }, this);\n\n            action(data);\n        },\n\n        /**\n         * Maps obj props/array elems recursively\n         *\n         * @param {Object|Array} data - Data to be iterated.\n         * @param {Function} action - Callback to transform each item.\n         * @param {Number} [maxDepth=7] - Max recursion depth.\n         *\n         * @returns {Object|Array}\n         */\n        mapRecursive: function (data, action, maxDepth) {\n            var newData;\n\n            maxDepth = typeof maxDepth === 'number' && !isNaN(maxDepth) ? maxDepth - 1 : 7;\n\n            if (!_.isFunction(action) || _.isFunction(data) || maxDepth < 0) {\n                return data;\n            }\n\n            if (!_.isObject(data)) {\n                return action(data);\n            }\n\n            if (_.isArray(data)) {\n                newData = _.map(data, function (item) {\n                    return this.mapRecursive(item, action, maxDepth);\n                }, this);\n\n                return action(newData);\n            }\n\n            newData = _.mapObject(data, function (val, key) {\n                if (data.hasOwnProperty(key)) {\n                    return this.mapRecursive(val, action, maxDepth);\n                }\n\n                return val;\n            }, this);\n\n            return action(newData);\n        },\n\n        /**\n         * Removes empty(in common sence) obj props/array elems\n         *\n         * @param {*} data - Data to be cleaned.\n         * @returns {*}\n         */\n        removeEmptyValues: function (data) {\n            if (!_.isObject(data)) {\n                return data;\n            }\n\n            if (_.isArray(data)) {\n                return data.filter(function (item) {\n                    return !this.isEmptyObj(item);\n                }, this);\n            }\n\n            return _.omit(data, this.isEmptyObj.bind(this));\n        },\n\n        /**\n         * Checks that argument of any type is empty in common sence:\n         * empty string, string with spaces only, object without own props, empty array, null or undefined\n         *\n         * @param {*} val - Value to be checked.\n         * @returns {Boolean}\n         */\n        isEmptyObj: function (val) {\n\n            return _.isObject(val) && _.isEmpty(val) ||\n            this.isEmpty(val) ||\n            val && val.trim && this.isEmpty(val.trim());\n        }\n    };\n});\n\n","mage/utils/misc.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'jquery',\n    'mage/utils/objects'\n], function (_, $, utils) {\n    'use strict';\n\n    var defaultAttributes,\n        ajaxSettings,\n        map;\n\n    defaultAttributes = {\n        method: 'post',\n        enctype: 'multipart/form-data'\n    };\n\n    ajaxSettings = {\n        default: {\n            method: 'POST',\n            cache: false,\n            processData: false,\n            contentType: false\n        },\n        simple: {\n            method: 'POST',\n            dataType: 'json'\n        }\n    };\n\n    map = {\n        'D': 'DDD',\n        'dd': 'DD',\n        'd': 'D',\n        'EEEE': 'dddd',\n        'EEE': 'ddd',\n        'e': 'd',\n        'yyyy': 'YYYY',\n        'yy': 'YY',\n        'y': 'YYYY',\n        'a': 'A'\n    };\n\n    return {\n\n        /**\n         * Generates a unique identifier.\n         *\n         * @param {Number} [size=7] - Length of a resulting identifier.\n         * @returns {String}\n         */\n        uniqueid: function (size) {\n            var code = Math.random() * 25 + 65 | 0,\n                idstr = String.fromCharCode(code);\n\n            size = size || 7;\n\n            while (idstr.length < size) {\n                code = Math.floor(Math.random() * 42 + 48);\n\n                if (code < 58 || code > 64) {\n                    idstr += String.fromCharCode(code);\n                }\n            }\n\n            return idstr;\n        },\n\n        /**\n         * Limits function call.\n         *\n         * @param {Object} owner\n         * @param {String} target\n         * @param {Number} limit\n         */\n        limit: function (owner, target, limit) {\n            var fn = owner[target];\n\n            owner[target] = _.debounce(fn.bind(owner), limit);\n        },\n\n        /**\n         * Converts mage date format to a moment.js format.\n         *\n         * @param {String} mageFormat\n         * @returns {String}\n         */\n        normalizeDate: function (mageFormat) {\n            var result = mageFormat;\n\n            _.each(map, function (moment, mage) {\n                result = result.replace(\n                    new RegExp(mage + '(?=([^\\u0027]*\\u0027[^\\u0027]*\\u0027)*[^\\u0027]*$)'),\n                    moment\n                );\n            });\n            result = result.replace(/'(.*?)'/g, '[$1]');\n            return result;\n        },\n\n        /**\n         * Puts provided value in range of min and max parameters.\n         *\n         * @param {Number} value - Value to be located.\n         * @param {Number} min - Min value.\n         * @param {Number} max - Max value.\n         * @returns {Number}\n         */\n        inRange: function (value, min, max) {\n            return Math.min(Math.max(min, value), max);\n        },\n\n        /**\n         * Serializes and sends data via POST request.\n         *\n         * @param {Object} options - Options object that consists of\n         *      a 'url' and 'data' properties.\n         * @param {Object} attrs - Attributes that will be added to virtual form.\n         */\n        submit: function (options, attrs) {\n            var form        = document.createElement('form'),\n                data        = utils.serialize(options.data),\n                attributes  = _.extend({}, defaultAttributes, attrs || {});\n\n            if (!attributes.action) {\n                attributes.action = options.url;\n            }\n\n            data['form_key'] = window.FORM_KEY;\n\n            _.each(attributes, function (value, name) {\n                form.setAttribute(name, value);\n            });\n\n            data = _.map(\n                data,\n                function (value, name) {\n                    return '<input type=\"hidden\" ' +\n                        'name=\"' + _.escape(name) + '\" ' +\n                        'value=\"' + _.escape(value) + '\"' +\n                        ' />';\n                }\n            ).join('');\n\n            form.insertAdjacentHTML('afterbegin', data);\n            document.body.appendChild(form);\n\n            form.submit();\n        },\n\n        /**\n         * Serializes and sends data via AJAX POST request.\n         *\n         * @param {Object} options - Options object that consists of\n         *      a 'url' and 'data' properties.\n         * @param {Object} config\n         */\n        ajaxSubmit: function (options, config) {\n            var t = new Date().getTime(),\n                settings;\n\n            options.data['form_key'] = window.FORM_KEY;\n            options.data = this.prepareFormData(options.data, config.ajaxSaveType);\n            settings = _.extend({}, ajaxSettings[config.ajaxSaveType], options || {});\n\n            if (!config.ignoreProcessEvents) {\n                $('body').trigger('processStart');\n            }\n\n            return $.ajax(settings)\n                .done(function (data) {\n                    if (config.response) {\n                        data.t = t;\n                        config.response.data(data);\n                        config.response.status(undefined);\n                        config.response.status(!data.error);\n                    }\n                })\n                .fail(function () {\n                    if (config.response) {\n                        config.response.status(undefined);\n                        config.response.status(false);\n                        config.response.data({\n                            error: true,\n                            messages: 'Something went wrong.',\n                            t: t\n                        });\n                    }\n                })\n                .always(function () {\n                    if (!config.ignoreProcessEvents) {\n                        $('body').trigger('processStop');\n                    }\n                });\n        },\n\n        /**\n         * Creates FormData object and append this data.\n         *\n         * @param {Object} data\n         * @param {String} type\n         * @returns {FormData}\n         */\n        prepareFormData: function (data, type) {\n            var formData;\n\n            if (type === 'default') {\n                formData = new FormData();\n                _.each(utils.serialize(data), function (val, name) {\n                    formData.append(name, val);\n                });\n            } else if (type === 'simple') {\n                formData = utils.serialize(data);\n            }\n\n            return formData;\n        },\n\n        /**\n         * Filters data object. Finds properties with suffix\n         * and sets their values to properties with the same name without suffix.\n         *\n         * @param {Object} data - The data object that should be filtered\n         * @param {String} suffix - The string by which data object should be filtered\n         * @param {String} separator - The string that is separator between property and suffix\n         *\n         * @returns {Object} Filtered data object\n         */\n        filterFormData: function (data, suffix, separator) {\n            data = data || {};\n            suffix = suffix || 'prepared-for-send';\n            separator = separator || '-';\n\n            _.each(data, function (value, key) {\n                if (_.isObject(value) && !Array.isArray(value)) {\n                    this.filterFormData(value, suffix, separator);\n                } else if (_.isString(key) && ~key.indexOf(suffix)) {\n                    data[key.split(separator)[0]] = value;\n                    delete data[key];\n                }\n            }, this);\n\n            return data;\n        },\n\n        /**\n         * Replaces special characters with their corresponding HTML entities.\n         *\n         * @param {String} string - Text to escape.\n         * @returns {String} Escaped text.\n         */\n        escape: function (string) {\n            return string ? $('<p></p>').text(string).html().replace(/\"/g, '&quot;') : string;\n        },\n\n        /**\n         * Replaces symbol codes with their unescaped counterparts.\n         *\n         * @param {String} data\n         *\n         * @returns {String}\n         */\n        unescape: function (data) {\n            var unescaped = _.unescape(data),\n                mapCharacters = {\n                    '&#039;': '\\''\n                };\n\n            _.each(mapCharacters, function (value, key) {\n                unescaped = unescaped.replace(key, value);\n            });\n\n            return unescaped;\n        },\n\n        /**\n         * Converts PHP IntlFormatter format to moment format.\n         *\n         * @param {String} format - PHP format\n         * @returns {String} - moment compatible formatting\n         */\n        convertToMomentFormat: function (format) {\n            var newFormat;\n\n            newFormat = format.replace(/yyyy|yy|y/, 'YYYY'); // replace the year\n            newFormat = newFormat.replace(/dd|d/g, 'DD'); // replace the date\n\n            return newFormat;\n        },\n\n        /**\n         * Get Url Parameters.\n         *\n         * @param {String} url - Url string\n         * @returns {Object}\n         */\n        getUrlParameters: function (url) {\n            var params = {},\n                queries = url.split('?'),\n                temp,\n                i,\n                l;\n\n            if (!queries[1]) {\n                return params;\n            }\n\n            queries = queries[1].split('&');\n\n            for (i = 0, l = queries.length; i < l; i++) {\n                temp = queries[i].split('=');\n\n                if (temp[1]) {\n                    params[temp[0]] = decodeURIComponent(temp[1].replace(/\\+/g, '%20'));\n                } else {\n                    params[temp[0]] = '';\n                }\n            }\n\n            return params;\n        }\n    };\n});\n","mage/utils/strings.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore'\n], function (_) {\n    'use strict';\n\n    var jsonRe = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/;\n\n    return {\n\n        /**\n         * Attempts to convert string to one of the primitive values,\n         * or to parse it as a valid json object.\n         *\n         * @param {String} str - String to be processed.\n         * @returns {*}\n         */\n        castString: function (str) {\n            try {\n                str = str === 'true' ? true :\n                    str === 'false' ? false :\n                        str === 'null' ? null :\n                            +str + '' === str ? +str :\n                                jsonRe.test(str) ? JSON.parse(str) :\n                                    str;\n            } catch (e) {\n            }\n\n            return str;\n        },\n\n        /**\n         * Splits string by separator if it's possible,\n         * otherwise returns the incoming value.\n         *\n         * @param {(String|Array|*)} str - String to split.\n         * @param {String} [separator=' '] - Seperator based on which to split the string.\n         * @returns {Array|*} Splitted string or the incoming value.\n         */\n        stringToArray: function (str, separator) {\n            separator = separator || ' ';\n\n            return typeof str === 'string' ?\n                str.split(separator) :\n                str;\n        },\n\n        /**\n         * Converts the incoming string which consists\n         * of a specified delimiters into a format commonly used in form elements.\n         *\n         * @param {String} name - The incoming string.\n         * @param {String} [separator='.']\n         * @returns {String} Serialized string.\n         *\n         * @example\n         *      utils.serializeName('one.two.three');\n         *      => 'one[two][three]';\n         */\n        serializeName: function (name, separator) {\n            var result;\n\n            separator = separator || '.';\n            name = name.split(separator);\n\n            result = name.shift();\n\n            name.forEach(function (part) {\n                result += '[' + part + ']';\n            });\n\n            return result;\n        },\n\n        /**\n         * Checks wether the incoming value is not empty,\n         * e.g. not 'null' or 'undefined'\n         *\n         * @param {*} value - Value to check.\n         * @returns {Boolean}\n         */\n        isEmpty: function (value) {\n            return value === '' || _.isUndefined(value) || _.isNull(value);\n        },\n\n        /**\n         * Adds 'prefix' to the 'part' value if it was provided.\n         *\n         * @param {String} prefix\n         * @param {String} part\n         * @returns {String}\n         */\n        fullPath: function (prefix, part) {\n            return prefix ? prefix + '.' + part : part;\n        },\n\n        /**\n         * Splits incoming string and returns its' part specified by offset.\n         *\n         * @param {String} parts\n         * @param {Number} [offset]\n         * @param {String} [delimiter=.]\n         * @returns {String}\n         */\n        getPart: function (parts, offset, delimiter) {\n            delimiter = delimiter || '.';\n            parts = parts.split(delimiter);\n            offset = this.formatOffset(parts, offset);\n\n            parts.splice(offset, 1);\n\n            return parts.join(delimiter) || '';\n        },\n\n        /**\n         * Converts nameThroughCamelCase to name-through-minus\n         *\n         * @param {String} string\n         * @returns {String}\n         */\n        camelCaseToMinus: function camelCaseToMinus(string) {\n            return ('' + string)\n                .split('')\n                .map(function (symbol, index) {\n                    return index ?\n                        symbol.toUpperCase() === symbol ?\n                        '-' + symbol.toLowerCase() :\n                            symbol :\n                        symbol.toLowerCase();\n                })\n                .join('');\n        },\n\n        /**\n         * Converts name-through-minus to nameThroughCamelCase\n         *\n         * @param {String} string\n         * @returns {String}\n         */\n        minusToCamelCase: function minusToCamelCase(string) {\n            return ('' + string)\n                .split('-')\n                .map(function (part, index) {\n                    return index ? part.charAt(0).toUpperCase() + part.slice(1) : part;\n                })\n                .join('');\n        }\n    };\n});\n","mage/utils/arrays.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    './strings'\n], function (_, utils) {\n    'use strict';\n\n    /**\n     * Defines index of an item in a specified container.\n     *\n     * @param {*} item - Item whose index should be defined.\n     * @param {Array} container - Container upon which to perform search.\n     * @returns {Number}\n     */\n    function getIndex(item, container) {\n        var index = container.indexOf(item);\n\n        if (~index) {\n            return index;\n        }\n\n        return _.findIndex(container, function (value) {\n            return value && value.name === item;\n        });\n    }\n\n    return {\n        /**\n         * Facade method to remove/add value from/to array\n         * without creating a new instance.\n         *\n         * @param {Array} arr - Array to be modified.\n         * @param {*} value - Value to add/remove.\n         * @param {Boolean} add - Flag that specfies operation.\n         * @returns {Utils} Chainable.\n         */\n        toggle: function (arr, value, add) {\n            return add ?\n                this.add(arr, value) :\n                this.remove(arr, value);\n        },\n\n        /**\n         * Removes the incoming value from array in case\n         * without creating a new instance of it.\n         *\n         * @param {Array} arr - Array to be modified.\n         * @param {*} value - Value to be removed.\n         * @returns {Utils} Chainable.\n         */\n        remove: function (arr, value) {\n            var index = arr.indexOf(value);\n\n            if (~index) {\n                arr.splice(index, 1);\n            }\n\n            return this;\n        },\n\n        /**\n         * Adds the incoming value to array if\n         * it's not alredy present in there.\n         *\n         * @param {Array} arr - Array to be modifed.\n         * @param {...*} arguments - Values to be added.\n         * @returns {Utils} Chainable.\n         */\n        add: function (arr) {\n            var values = _.toArray(arguments).slice(1);\n\n            values.forEach(function (value) {\n                if (!~arr.indexOf(value)) {\n                    arr.push(value);\n                }\n            });\n\n            return this;\n        },\n\n        /**\n         * Inserts specified item into container at a specified position.\n         *\n         * @param {*} item - Item to be inserted into container.\n         * @param {Array} container - Container of items.\n         * @param {*} [position=-1] - Position at which item should be inserted.\n         *      Position can represent:\n         *          - specific index in container\n         *          - item which might already be present in container\n         *          - structure with one of these properties: after, before\n         * @returns {Boolean|*}\n         *      - true if element has changed its' position\n         *      - false if nothing has changed\n         *      - inserted value if it wasn't present in container\n         */\n        insert: function (item, container, position) {\n            var currentIndex = getIndex(item, container),\n                newIndex,\n                target;\n\n            if (typeof position === 'undefined') {\n                position = -1;\n            } else if (typeof position === 'string') {\n                position = isNaN(+position) ? position : +position;\n            }\n\n            newIndex = position;\n\n            if (~currentIndex) {\n                target = container.splice(currentIndex, 1)[0];\n\n                if (typeof item === 'string') {\n                    item = target;\n                }\n            }\n\n            if (typeof position !== 'number') {\n                target = position.after || position.before || position;\n\n                newIndex = getIndex(target, container);\n\n                if (~newIndex && (position.after || newIndex >= currentIndex)) {\n                    newIndex++;\n                }\n            }\n\n            if (newIndex < 0) {\n                newIndex += container.length + 1;\n            }\n\n            container[newIndex] ?\n                container.splice(newIndex, 0, item) :\n                container[newIndex] = item;\n\n            return !~currentIndex ? item : currentIndex !== newIndex;\n        },\n\n        /**\n         * @param {Array} elems\n         * @param {Number} offset\n         * @return {Number|*}\n         */\n        formatOffset: function (elems, offset) {\n            if (utils.isEmpty(offset)) {\n                offset = -1;\n            }\n\n            offset = +offset;\n\n            if (offset < 0) {\n                offset += elems.length + 1;\n            }\n\n            return offset;\n        }\n    };\n});\n","mage/utils/wrapper.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * Utility methods used to wrap and extend functions.\n *\n * @example Usage of a 'wrap' method with arguments delegation.\n *      var multiply = function (a, b) {\n *          return a * b;\n *      };\n *\n *      multiply = module.wrap(multiply, function (orig) {\n *          return 'Result is: ' + orig();\n *      });\n *\n *      multiply(2, 2);\n *      => 'Result is: 4'\n *\n * @example Usage of 'wrapSuper' method.\n *      var multiply = function (a, b) {\n *         return a * b;\n *      };\n *\n *      var obj = {\n *          multiply: module.wrapSuper(multiply, function () {\n *              return 'Result is: ' + this._super();\n *          });\n *      };\n *\n *      obj.multiply(2, 2);\n *      => 'Result is: 4'\n */\ndefine([\n    'underscore'\n], function (_) {\n    'use strict';\n\n    /**\n     * Checks if string has a '_super' substring.\n     */\n    var superReg = /\\b_super\\b/;\n\n    return {\n\n        /**\n         * Wraps target function with a specified wrapper, which will receive\n         * reference to the original function as a first argument.\n         *\n         * @param {Function} target - Function to be wrapped.\n         * @param {Function} wrapper - Wrapper function.\n         * @returns {Function} Wrapper function.\n         */\n        wrap: function (target, wrapper) {\n            if (!_.isFunction(target) || !_.isFunction(wrapper)) {\n                return wrapper;\n            }\n\n            return function () {\n                var args    = _.toArray(arguments),\n                    ctx     = this,\n                    _super;\n\n                /**\n                 * Function that will be passed to the wrapper.\n                 * If no arguments will be passed to it, then the original\n                 * function will be called with an arguments of a wrapper function.\n                 */\n                _super = function () {\n                    var superArgs = arguments.length ? arguments : args.slice(1);\n\n                    return target.apply(ctx, superArgs);\n                };\n\n                args.unshift(_super);\n\n                return wrapper.apply(ctx, args);\n            };\n        },\n\n        /**\n         * Wraps the incoming function to implement support of the '_super' method.\n         *\n         * @param {Function} target - Function to be wrapped.\n         * @param {Function} wrapper - Wrapper function.\n         * @returns {Function} Wrapped function.\n         */\n        wrapSuper: function (target, wrapper) {\n            if (!this.hasSuper(wrapper) || !_.isFunction(target)) {\n                return wrapper;\n            }\n\n            return function () {\n                var _super  = this._super,\n                    args    = arguments,\n                    result;\n\n                /**\n                 * Temporary define '_super' method which\n                 * contains call to the original function.\n                 */\n                this._super = function () {\n                    var superArgs = arguments.length ? arguments : args;\n\n                    return target.apply(this, superArgs);\n                };\n\n                result = wrapper.apply(this, args);\n\n                this._super = _super;\n\n                return result;\n            };\n        },\n\n        /**\n         * Checks wether the incoming method contains calls of the '_super' method.\n         *\n         * @param {Function} fn - Function to be checked.\n         * @returns {Boolean}\n         */\n        hasSuper: function (fn) {\n            return _.isFunction(fn) && superReg.test(fn);\n        },\n\n        /**\n         * Extends target object with provided extenders.\n         * If property in target and extender objects is a function,\n         * then it will be wrapped using 'wrap' method.\n         *\n         * @param {Object} target - Object to be extended.\n         * @param {...Object} extenders - Multiple extenders objects.\n         * @returns {Object} Modified target object.\n         */\n        extend: function (target) {\n            var extenders = _.toArray(arguments).slice(1),\n                iterator = this._extend.bind(this, target);\n\n            extenders.forEach(iterator);\n\n            return target;\n        },\n\n        /**\n         * Same as the 'extend' method, but operates only on one extender object.\n         *\n         * @private\n         * @param {Object} target\n         * @param {Object} extender\n         */\n        _extend: function (target, extender) {\n            _.each(extender, function (value, key) {\n                target[key] = this.wrap(target[key], extender[key]);\n            }, this);\n        }\n    };\n});\n","mage/utils/main.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(function (require) {\n    'use strict';\n\n    var utils = {},\n        _ = require('underscore'),\n        root = typeof self == 'object' && self.self === self && self ||\n            typeof global == 'object' && global.global === global && global ||\n            Function('return this')() || {};\n\n    root._ = _;\n\n    return _.extend(\n        utils,\n        require('./arrays'),\n        require('./compare'),\n        require('./misc'),\n        require('./objects'),\n        require('./strings'),\n        require('./template')\n    );\n});\n","mage/utils/template.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-shadow */\n\ndefine([\n    'jquery',\n    'underscore',\n    'mage/utils/objects',\n    'mage/utils/strings'\n], function ($, _, utils, stringUtils) {\n    'use strict';\n\n    var tmplSettings = _.templateSettings,\n        interpolate = /\\$\\{([\\s\\S]+?)\\}/g,\n        opener = '${',\n        template,\n        hasStringTmpls;\n\n    /**\n     * Identifies whether ES6 templates are supported.\n     */\n    hasStringTmpls = (function () {\n        var testString = 'var foo = \"bar\"; return `${ foo }` === foo';\n\n        try {\n            return Function(testString)();\n        } catch (e) {\n            return false;\n        }\n    })();\n\n    /**\n     * Objects can specify how to use templating for their properties - getting that configuration.\n     *\n     * To disable rendering for all properties of your object add __disableTmpl: true.\n     * To disable for specific property add __disableTmpl: {propertyName: true}.\n     * To limit recursion for a specific property add __disableTmpl: {propertyName: numberOfCycles}.\n     *\n     * @param {String} tmpl\n     * @param {Object | undefined} target\n     * @returns {Boolean|Object}\n     */\n    function isTmplIgnored(tmpl, target) {\n        var parsedTmpl;\n\n        try {\n            parsedTmpl = JSON.parse(tmpl);\n\n            if (typeof parsedTmpl === 'object') {\n                return tmpl.includes('__disableTmpl');\n            }\n        } catch (e) {\n        }\n\n        if (typeof target !== 'undefined') {\n            if (typeof target === 'object' && target.hasOwnProperty('__disableTmpl')) {\n                return target.__disableTmpl;\n            }\n        }\n\n        return false;\n\n    }\n\n    if (hasStringTmpls) {\n\n        /*eslint-disable no-unused-vars, no-eval*/\n        /**\n         * Evaluates template string using ES6 templates.\n         *\n         * @param {String} tmpl - Template string.\n         * @param {Object} $ - Data object used in a template.\n         * @returns {String} Compiled template.\n         */\n        template = function (tmpl, $) {\n            return eval('`' + tmpl + '`');\n        };\n\n        /*eslint-enable no-unused-vars, no-eval*/\n    } else {\n\n        /**\n         * Fallback function used when ES6 templates are not supported.\n         * Uses underscore templates renderer.\n         *\n         * @param {String} tmpl - Template string.\n         * @param {Object} data - Data object used in a template.\n         * @returns {String} Compiled template.\n         */\n        template = function (tmpl, data) {\n            var cached = tmplSettings.interpolate;\n\n            tmplSettings.interpolate = interpolate;\n\n            tmpl = _.template(tmpl, {\n                variable: '$'\n            })(data);\n\n            tmplSettings.interpolate = cached;\n\n            return tmpl;\n        };\n    }\n\n    /**\n     * Checks if provided value contains template syntax.\n     *\n     * @param {*} value - Value to be checked.\n     * @returns {Boolean}\n     */\n    function isTemplate(value) {\n        return typeof value === 'string' &&\n            value.indexOf(opener) !== -1 &&\n            // the below pattern almost always indicates an accident which should not cause template evaluation\n            // refuse to evaluate\n            value.indexOf('${{') === -1;\n    }\n\n    /**\n     * Iteratively processes provided string\n     * until no templates syntax will be found.\n     *\n     * @param {String} tmpl - Template string.\n     * @param {Object} data - Data object used in a template.\n     * @param {Boolean} [castString=false] - Flag that indicates whether template\n     *      should be casted after evaluation to a value of another type or\n     *      that it should be leaved as a string.\n     * @param {Number|undefined} maxCycles - Maximum number of rendering cycles, can be 0.\n     * @returns {*} Compiled template.\n     */\n    function render(tmpl, data, castString, maxCycles) {\n        var last = tmpl,\n            cycles = 0;\n\n        while (~tmpl.indexOf(opener) && (typeof maxCycles === 'undefined' || cycles < maxCycles)) {\n            if (!isTmplIgnored(tmpl)) {\n                tmpl = template(tmpl, data);\n            }\n\n            if (tmpl === last) {\n                break;\n            }\n\n            last = tmpl;\n            cycles++;\n        }\n\n        return castString ?\n            stringUtils.castString(tmpl) :\n            tmpl;\n    }\n\n    return {\n\n        /**\n         * Applies provided data to the template.\n         *\n         * @param {Object|String} tmpl\n         * @param {Object} [data] - Data object to match with template.\n         * @param {Boolean} [castString=false] - Flag that indicates whether template\n         *      should be casted after evaluation to a value of another type or\n         *      that it should be leaved as a string.\n         * @returns {*}\n         *\n         * @example Template defined as a string.\n         *      var source = { foo: 'Random Stuff', bar: 'Some' };\n         *\n         *      utils.template('${ $.bar } ${ $.foo }', source);\n         *      => 'Some Random Stuff';\n         *\n         * @example Template defined as an object.\n         *      var tmpl = {\n         *              key: {'${ $.$data.bar }': '${ $.$data.foo }'},\n         *              foo: 'bar',\n         *              x1: 2, x2: 5,\n         *              delta: '${ $.x2 - $.x1 }',\n         *              baz: 'Upper ${ $.foo.toUpperCase() }'\n         *      };\n         *\n         *      utils.template(tmpl, source);\n         *      => {\n         *          key: {'Some': 'Random Stuff'},\n         *          foo: 'bar',\n         *          x1: 2, x2: 5,\n         *          delta: 3,\n         *          baz: 'Upper BAR'\n         *      };\n         */\n        template: function (tmpl, data, castString, dontClone) {\n            if (typeof tmpl === 'string') {\n                return render(tmpl, data, castString);\n            }\n\n            if (!dontClone) {\n                tmpl = utils.copy(tmpl);\n            }\n\n            tmpl.$data = data || {};\n\n            /**\n             * Template iterator function.\n             */\n            _.each(tmpl, function iterate(value, key, list) {\n                var disabled,\n                    maxCycles;\n\n                if (key === '$data') {\n                    return;\n                }\n\n                if (isTemplate(key)) {\n                    delete list[key];\n\n                    key = render(key, tmpl);\n                    list[key] = value;\n                }\n\n                if (isTemplate(value)) {\n                    //Getting template disabling settings, can be true for all disabled and separate settings\n                    //for each property.\n                    disabled = isTmplIgnored(value, list);\n\n                    if (typeof disabled === 'object' && disabled.hasOwnProperty(key) && disabled[key] !== false) {\n                        //Checking if specific settings for a property provided.\n                        maxCycles = disabled[key];\n                    }\n\n                    if (disabled === true || maxCycles === true) {\n                        //Rendering for all properties is disabled.\n                        maxCycles = 0;\n                    }\n\n                    list[key] = render(value, tmpl, castString, maxCycles);\n                } else if ($.isPlainObject(value) || Array.isArray(value)) {\n                    _.each(value, iterate);\n                }\n            });\n\n            delete tmpl.$data;\n\n            return tmpl;\n        }\n    };\n});\n","mage/utils/compare.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'mage/utils/objects'\n], function (_, utils) {\n    'use strict';\n\n    var result = [];\n\n    /**\n     * Checks if all of the provided arrays contains equal values.\n     *\n     * @param {(Boolean|Array)} [keepOrder=false]\n     * @param {Array} target\n     * @returns {Boolean}\n     */\n    function equalArrays(keepOrder, target) {\n        var args = _.toArray(arguments),\n            arrays;\n\n        if (!Array.isArray(keepOrder)) {\n            arrays      = args.slice(2);\n        } else {\n            target      = keepOrder;\n            keepOrder   = false;\n            arrays      = args.slice(1);\n        }\n\n        if (!arrays.length) {\n            return true;\n        }\n\n        return arrays.every(function (array) {\n            if (array === target) {\n                return true;\n            } else if (array.length !== target.length) {\n                return false;\n            } else if (!keepOrder) {\n                return !_.difference(target, array).length;\n            }\n\n            return array.every(function (value, index) {\n                return target[index] === value;\n            });\n        });\n    }\n\n    /**\n     * Checks if two values are different.\n     *\n     * @param {*} a - First value.\n     * @param {*} b - Second value.\n     * @returns {Boolean}\n     */\n    function isDifferent(a, b) {\n        var oldIsPrimitive = utils.isPrimitive(a);\n\n        if (Array.isArray(a) && Array.isArray(b)) {\n            return !equalArrays(true, a, b);\n        }\n\n        return oldIsPrimitive ? a !== b : true;\n    }\n\n    /**\n     * @param {String} prefix\n     * @param {String} part\n     */\n    function getPath(prefix, part) {\n        return prefix ? prefix + '.' + part : part;\n    }\n\n    /**\n     * Checks if object has own specified property.\n     *\n     * @param {*} obj - Value to be checked.\n     * @param {String} key - Key of the property.\n     * @returns {Boolean}\n     */\n    function hasOwn(obj, key) {\n        return Object.prototype.hasOwnProperty.call(obj, key);\n    }\n\n    /**\n     * @param {Array} changes\n     */\n    function getContainers(changes) {\n        var containers  = {},\n            indexed     = _.indexBy(changes, 'path');\n\n        _.each(indexed, function (change, name) {\n            var path;\n\n            name.split('.').forEach(function (part) {\n                path = getPath(path, part);\n\n                if (path in indexed) {\n                    return;\n                }\n\n                (containers[path] = containers[path] || []).push(change);\n            });\n        });\n\n        return containers;\n    }\n\n    /**\n     * @param {String} path\n     * @param {String} name\n     * @param {String} type\n     * @param {String} newValue\n     * @param {String} oldValue\n     */\n    function addChange(path, name, type, newValue, oldValue) {\n        var data;\n\n        data = {\n            path: path,\n            name: name,\n            type: type\n        };\n\n        if (type !== 'remove') {\n            data.value = newValue;\n            data.oldValue = oldValue;\n        } else {\n            data.oldValue = newValue;\n        }\n\n        result.push(data);\n    }\n\n    /**\n     * @param {String} ns\n     * @param {String} name\n     * @param {String} type\n     * @param {String} iterator\n     * @param {String} placeholder\n     */\n    function setAll(ns, name, type, iterator, placeholder) {\n        var key;\n\n        if (arguments.length > 4) {\n            type === 'add' ?\n                addChange(ns, name, 'update', iterator, placeholder) :\n                addChange(ns, name, 'update', placeholder, iterator);\n        } else {\n            addChange(ns, name, type, iterator);\n        }\n\n        if (!utils.isObject(iterator)) {\n            return;\n        }\n\n        for (key in iterator) {\n            if (hasOwn(iterator, key)) {\n                setAll(getPath(ns, key), key, type, iterator[key]);\n            }\n        }\n    }\n\n    /*eslint-disable max-depth*/\n    /**\n     * @param {Object} old\n     * @param {Object} current\n     * @param {String} ns\n     * @param {String} name\n     */\n    function compare(old, current, ns, name) {\n        var key,\n            oldIsObj = utils.isObject(old),\n            newIsObj = utils.isObject(current);\n\n        if (oldIsObj && newIsObj) {\n            for (key in old) {\n                if (hasOwn(old, key) && !hasOwn(current, key)) {\n                    setAll(getPath(ns, key), key, 'remove', old[key]);\n                }\n            }\n\n            for (key in current) {\n                if (hasOwn(current, key)) {\n                    hasOwn(old, key) ?\n                        compare(old[key], current[key], getPath(ns, key), key) :\n                        setAll(getPath(ns, key), key, 'add', current[key]);\n                }\n            }\n        } else if (oldIsObj) {\n            setAll(ns, name, 'remove', old, current);\n        } else if (newIsObj) {\n            setAll(ns, name, 'add', current, old);\n        } else if (isDifferent(old, current)) {\n            addChange(ns, name, 'update', current, old);\n        }\n    }\n\n    /*eslint-enable max-depth*/\n\n    return {\n\n        /**\n         *\n         * @returns {Object}\n         */\n        compare: function () {\n            var changes;\n\n            compare.apply(null, arguments);\n\n            changes = result.splice(0);\n\n            return {\n                containers: getContainers(changes),\n                changes: changes,\n                equal: !changes.length\n            };\n        },\n\n        equalArrays: equalArrays\n    };\n});\n","Magento_ProductAlert/js/form-submitter.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    return function (data, element) {\n\n        $(element).trigger('submit');\n    };\n});\n","Magento_OfflinePayments/js/view/payment/offline-payments.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'uiComponent',\n    'Magento_Checkout/js/model/payment/renderer-list'\n], function (Component, rendererList) {\n    'use strict';\n\n    rendererList.push(\n        {\n            type: 'checkmo',\n            component: 'Magento_OfflinePayments/js/view/payment/method-renderer/checkmo-method'\n        },\n        {\n            type: 'banktransfer',\n            component: 'Magento_OfflinePayments/js/view/payment/method-renderer/banktransfer-method'\n        },\n        {\n            type: 'cashondelivery',\n            component: 'Magento_OfflinePayments/js/view/payment/method-renderer/cashondelivery-method'\n        },\n        {\n            type: 'purchaseorder',\n            component: 'Magento_OfflinePayments/js/view/payment/method-renderer/purchaseorder-method'\n        }\n    );\n\n    /** Add view logic here if needed */\n    return Component.extend({});\n});\n","Magento_OfflinePayments/js/view/payment/method-renderer/banktransfer-method.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'ko',\n    'Magento_Checkout/js/view/payment/default'\n], function (ko, Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_OfflinePayments/payment/banktransfer'\n        },\n\n        /**\n         * Get value of instruction field.\n         * @returns {String}\n         */\n        getInstructions: function () {\n            return window.checkoutConfig.payment.instructions[this.item.method];\n        }\n    });\n});\n","Magento_OfflinePayments/js/view/payment/method-renderer/purchaseorder-method.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'Magento_Checkout/js/view/payment/default',\n    'jquery',\n    'mage/validation'\n], function (Component, $) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_OfflinePayments/payment/purchaseorder-form',\n            purchaseOrderNumber: ''\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            this._super()\n                .observe('purchaseOrderNumber');\n\n            return this;\n        },\n\n        /**\n         * @return {Object}\n         */\n        getData: function () {\n            return {\n                method: this.item.method,\n                'po_number': this.purchaseOrderNumber(),\n                'additional_data': null\n            };\n        },\n\n        /**\n         * @return {jQuery}\n         */\n        validate: function () {\n            var form = 'form[data-role=purchaseorder-form]';\n\n            return $(form).validation() && $(form).validation('isValid');\n        }\n    });\n});\n","Magento_OfflinePayments/js/view/payment/method-renderer/checkmo-method.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'Magento_Checkout/js/view/payment/default'\n], function (Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_OfflinePayments/payment/checkmo'\n        },\n\n        /**\n         * Returns send check to info.\n         *\n         * @return {*}\n         */\n        getMailingAddress: function () {\n            return window.checkoutConfig.payment.checkmo.mailingAddress;\n        },\n\n        /**\n         * Returns payable to info.\n         *\n         * @return {*}\n         */\n        getPayableTo: function () {\n            return window.checkoutConfig.payment.checkmo.payableTo;\n        }\n    });\n});\n","Magento_OfflinePayments/js/view/payment/method-renderer/cashondelivery-method.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'Magento_Checkout/js/view/payment/default'\n], function (Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_OfflinePayments/payment/cashondelivery'\n        },\n\n        /**\n         * Returns payment method instructions.\n         *\n         * @return {*}\n         */\n        getInstructions: function () {\n            return window.checkoutConfig.payment.instructions[this.item.method];\n        }\n    });\n});\n","Magento_InstantPurchase/js/view/instant-purchase.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    'jquery',\n    'underscore',\n    'uiComponent',\n    'Magento_Ui/js/modal/confirm',\n    'Magento_Customer/js/customer-data',\n    'mage/url',\n    'mage/template',\n    'mage/translate',\n    'text!Magento_InstantPurchase/template/confirmation.html',\n    'mage/validation'\n], function (ko, $, _, Component, confirm, customerData, urlBuilder, mageTemplate, $t, confirmationTemplate) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_InstantPurchase/instant-purchase',\n            buttonText: $t('Instant Purchase'),\n            purchaseUrl: urlBuilder.build('instantpurchase/button/placeOrder'),\n            showButton: false,\n            paymentToken: null,\n            shippingAddress: null,\n            billingAddress: null,\n            shippingMethod: null,\n            productFormSelector: '#product_addtocart_form',\n            confirmationTitle: $t('Instant Purchase Confirmation'),\n            confirmationData: {\n                message: $t('Are you sure you want to place order and pay?'),\n                shippingAddressTitle: $t('Shipping Address'),\n                billingAddressTitle: $t('Billing Address'),\n                paymentMethodTitle: $t('Payment Method'),\n                shippingMethodTitle: $t('Shipping Method')\n            }\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            var instantPurchase = customerData.get('instant-purchase');\n\n            this._super();\n\n            this.setPurchaseData(instantPurchase());\n            instantPurchase.subscribe(this.setPurchaseData, this);\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            this._super()\n                .observe('showButton paymentToken shippingAddress billingAddress shippingMethod');\n\n            return this;\n        },\n\n        /**\n         * Set data from customerData.\n         *\n         * @param {Object} data\n         */\n        setPurchaseData: function (data) {\n            this.showButton(data.available);\n            this.paymentToken(data.paymentToken);\n            this.shippingAddress(data.shippingAddress);\n            this.billingAddress(data.billingAddress);\n            this.shippingMethod(data.shippingMethod);\n        },\n\n        /**\n         * Confirmation method\n         */\n        instantPurchase: function () {\n            var form = $(this.productFormSelector),\n                confirmTemplate = mageTemplate(confirmationTemplate),\n                confirmData = _.extend({}, this.confirmationData, {\n                    paymentToken: this.paymentToken().summary,\n                    shippingAddress: this.shippingAddress().summary,\n                    billingAddress: this.billingAddress().summary,\n                    shippingMethod: this.shippingMethod().summary\n                });\n\n            if (!(form.validation() && form.validation('isValid'))) {\n                return;\n            }\n\n            confirm({\n                title: this.confirmationTitle,\n                content: confirmTemplate({\n                    data: confirmData\n                }),\n                actions: {\n                    /** @inheritdoc */\n                    confirm: function () {\n                        $.ajax({\n                            url: this.purchaseUrl,\n                            data: form.serialize(),\n                            type: 'post',\n                            dataType: 'json',\n\n                            /** Show loader before send */\n                            beforeSend: function () {\n                                $('body').trigger('processStart');\n                            }\n                        }).always(function () {\n                            $('body').trigger('processStop');\n                        });\n                    }.bind(this)\n                }\n            });\n        }\n    });\n});\n","Smartwave_Megamenu/js/sw_megamenu.js":"(function (factory) {\n    'use strict';\n\n    if (typeof define === 'function' && define.amd) {\n        define([\n            'jquery'\n        ], factory);\n    } else {\n        factory(window.jQuery);\n    }\n}(function ($) {\n    'use strict';\n\n    $.fn.swMegamenu = function() {\n        $(\".navigation.sw-megamenu li.classic .submenu, .navigation.sw-megamenu li.staticwidth .submenu, .navigation.sw-megamenu li.classic .subchildmenu .subchildmenu\").each(function(){\n            $(this).css(\"left\",\"-9999px\");\n            $(this).css(\"right\",\"auto\");\n        });\n        $(this).find(\"li.classic .subchildmenu > li.parent\").mouseover(function(){\n            var popup = $(this).children(\"ul.subchildmenu\");\n            var w_width = $(window).innerWidth();\n\n            if(popup) {\n                var pos = $(this).offset();\n                var c_width = $(popup).outerWidth();\n                if(w_width <= pos.left + $(this).outerWidth() + c_width) {\n                    $(popup).css(\"left\",\"auto\");\n                    $(popup).css(\"right\",\"100%\");\n                } else {\n                    $(popup).css(\"left\",\"100%\");\n                    $(popup).css(\"right\",\"auto\");\n                }\n            }\n        });\n        $(this).find(\"li.staticwidth.parent,li.classic.parent\").mouseover(function(){\n            var popup = $(this).children(\".submenu\");\n            var w_width = $(window).innerWidth();\n\n            if(popup) {\n                var pos = $(this).offset();\n                var c_width = $(popup).outerWidth();\n                if(w_width <= pos.left + $(this).outerWidth() + c_width) {\n                    $(popup).css(\"left\",\"auto\");\n                    $(popup).css(\"right\",\"0\");\n                } else {\n                    $(popup).css(\"left\",\"0\");\n                    $(popup).css(\"right\",\"auto\"); \n                }\n            }\n        });\n        $(window).resize(function(){\n            $(\".navigation.sw-megamenu li.classic .submenu, .navigation.sw-megamenu li.staticwidth .submenu, .navigation.sw-megamenu li.classic .subchildmenu .subchildmenu\").each(function(){\n                $(this).css(\"left\",\"-9999px\");\n                $(this).css(\"right\",\"auto\");\n            });\n        });\n        $(\".nav-toggle\").off('click').on('click',function(e){\n            if(!$(\"html\").hasClass(\"nav-open\")) {\n                $(\"html\").addClass(\"nav-before-open\");\n                setTimeout(function(){\n                    $(\"html\").addClass(\"nav-open\");\n                }, 300);\n            }\n            else {\n                $(\"html\").removeClass(\"nav-open\");\n                setTimeout(function(){\n                    $(\"html\").removeClass(\"nav-before-open\");\n                }, 300);\n            }\n        });\n        $(\"li.ui-menu-item > .open-children-toggle\").off(\"click\").on(\"click\", function(){\n            if(!$(this).parent().children(\".submenu\").hasClass(\"opened\")) {\n                $(this).parent().children(\".submenu\").addClass(\"opened\");\n                $(this).parent().children(\"a\").addClass(\"ui-state-active\");\n            }\n            else {\n                $(this).parent().children(\".submenu\").removeClass(\"opened\");\n                $(this).parent().children(\"a\").removeClass(\"ui-state-active\");\n            }\n        });\n    };\n}));\n","Magento_Variable/js/grid/columns/radioselect.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'mage/translate',\n    'Magento_Ui/js/grid/columns/column',\n    'jquery'\n], function (_, $t, Column, jQuery) {\n    'use strict';\n\n    return Column.extend({\n        defaults: {\n            bodyTmpl: 'Magento_Variable/grid/cells/radioselect',\n            draggable: false,\n            sortable: false,\n            selectedVariableCode: null,\n            selectedVariableType: null\n        },\n\n        /**\n         * Calls 'initObservable' of parent\n         *\n         * @returns {Object} Chainable.\n         */\n        initObservable: function () {\n            this._super().observe(['selectedVariableCode']);\n\n            return this;\n        },\n\n        /**\n         * Remove disable class from Insert Variable button after Variable has been chosen.\n         *\n         * @return {Boolean}\n         */\n        selectVariable: function () {\n            if (jQuery('#insert_variable').hasClass('disabled')) {\n                jQuery('#insert_variable').removeClass('disabled');\n            }\n\n            return true;\n        }\n    });\n});\n","Magento_ReCaptchaFrontendUi/js/reCaptchaScriptLoader.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n    'use strict';\n\n    var scriptTagAdded = false;\n\n    return {\n        /**\n         * Add script tag. Script tag should be added once\n         */\n        addReCaptchaScriptTag: function () {\n            var element, scriptTag;\n\n            if (!scriptTagAdded) {\n                element = document.createElement('script');\n                scriptTag = document.getElementsByTagName('script')[0];\n\n                element.async = true;\n                element.src = 'https://www.google.com/recaptcha/api.js' +\n                    '?onload=globalOnRecaptchaOnLoadCallback&render=explicit';\n\n                scriptTag.parentNode.insertBefore(element, scriptTag);\n                scriptTagAdded = true;\n            }\n        }\n    };\n});\n","Magento_ReCaptchaFrontendUi/js/ui-messages-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['Magento_ReCaptchaFrontendUi/js/registry'], function (registry) {\n    'use strict';\n\n    return function (originalComponent) {\n        return originalComponent.extend({\n            /**\n             * Initialize reset on messages\n             * @returns {initialize}\n             */\n            initialize: function () {\n                this._super();\n\n                this.messageContainer.errorMessages.subscribe(function () {\n                    var\n                        i,\n                        captchaList = registry.captchaList(),\n                        tokenFieldsList = registry.tokenFields();\n\n                    for (i = 0; i < captchaList.length; i++) {\n                        // eslint-disable-next-line no-undef\n                        grecaptcha.reset(captchaList[i]);\n\n                        if (tokenFieldsList[i]) {\n                            tokenFieldsList[i].value = '';\n                        }\n                    }\n                }, null, 'arrayChange');\n\n                return this;\n            }\n        });\n    };\n});\n","Magento_ReCaptchaFrontendUi/js/reCaptcha.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global grecaptcha */\ndefine(\n    [\n        'uiComponent',\n        'jquery',\n        'ko',\n        'underscore',\n        'Magento_ReCaptchaFrontendUi/js/registry',\n        'Magento_ReCaptchaFrontendUi/js/reCaptchaScriptLoader',\n        'Magento_ReCaptchaFrontendUi/js/nonInlineReCaptchaRenderer'\n    ], function (Component, $, ko, _, registry, reCaptchaLoader, nonInlineReCaptchaRenderer) {\n        'use strict';\n\n        return Component.extend({\n\n            defaults: {\n                template: 'Magento_ReCaptchaFrontendUi/reCaptcha',\n                reCaptchaId: 'recaptcha'\n            },\n\n            /**\n             * @inheritdoc\n             */\n            initialize: function () {\n                this._super();\n                this._loadApi();\n            },\n\n            /**\n             * Loads recaptchaapi API and triggers event, when loaded\n             * @private\n             */\n            _loadApi: function () {\n                if (this._isApiRegistered !== undefined) {\n                    if (this._isApiRegistered === true) {\n                        $(window).trigger('recaptchaapiready');\n                    }\n\n                    return;\n                }\n                this._isApiRegistered = false;\n\n                // global function\n                window.globalOnRecaptchaOnLoadCallback = function () {\n                    this._isApiRegistered = true;\n                    $(window).trigger('recaptchaapiready');\n                }.bind(this);\n\n                reCaptchaLoader.addReCaptchaScriptTag();\n            },\n\n            /**\n             * Checking that reCAPTCHA is invisible type\n             * @returns {Boolean}\n             */\n            getIsInvisibleRecaptcha: function () {\n                if (this.settings ===\n\n                    void 0) {\n                    return false;\n                }\n\n                return this.settings.invisible;\n            },\n\n            /**\n             * reCAPTCHA callback\n             * @param {String} token\n             */\n            reCaptchaCallback: function (token) {\n                if (this.getIsInvisibleRecaptcha()) {\n                    this.tokenField.value = token;\n                    this.$parentForm.submit();\n                }\n            },\n\n            /**\n             * Initialize reCAPTCHA after first rendering\n             */\n            initCaptcha: function () {\n                var $parentForm,\n                    $wrapper,\n                    $reCaptcha,\n                    widgetId,\n                    parameters;\n\n                if (this.captchaInitialized || this.settings ===\n\n                    void 0) {\n                    return;\n                }\n\n                this.captchaInitialized = true;\n\n                /*\n                 * Workaround for data-bind issue:\n                 * We cannot use data-bind to link a dynamic id to our component\n                 * See:\n                 * https://stackoverflow.com/questions/46657573/recaptcha-the-bind-parameter-must-be-an-element-or-id\n                 *\n                 * We create a wrapper element with a wrapping id and we inject the real ID with jQuery.\n                 * In this way we have no data-bind attribute at all in our reCAPTCHA div\n                 */\n                $wrapper = $('#' + this.getReCaptchaId() + '-wrapper');\n                $reCaptcha = $wrapper.find('.g-recaptcha');\n                $reCaptcha.attr('id', this.getReCaptchaId());\n\n                $parentForm = $wrapper.parents('form');\n\n                if (this.settings === undefined) {\n\n                    return;\n                }\n\n                parameters = _.extend(\n                    {\n                        'callback': function (token) { // jscs:ignore jsDoc\n                            this.reCaptchaCallback(token);\n                            this.validateReCaptcha(true);\n                        }.bind(this),\n                        'expired-callback': function () {\n                            this.validateReCaptcha(false);\n                        }.bind(this)\n                    },\n                    this.settings.rendering\n                );\n\n                if (parameters.size === 'invisible' && parameters.badge !== 'inline') {\n                    nonInlineReCaptchaRenderer.add($reCaptcha, parameters);\n                }\n\n                // eslint-disable-next-line no-undef\n                widgetId = grecaptcha.render(this.getReCaptchaId(), parameters);\n                this.initParentForm($parentForm, widgetId);\n\n                registry.ids.push(this.getReCaptchaId());\n                registry.captchaList.push(widgetId);\n                registry.tokenFields.push(this.tokenField);\n\n            },\n\n            /**\n             * Initialize parent form.\n             *\n             * @param {Object} parentForm\n             * @param {String} widgetId\n             */\n            initParentForm: function (parentForm, widgetId) {\n                var listeners;\n\n                if (this.getIsInvisibleRecaptcha() && parentForm.length > 0) {\n                    parentForm.submit(function (event) {\n                        if (!this.tokenField.value) {\n                            // eslint-disable-next-line no-undef\n                            grecaptcha.execute(widgetId);\n                            event.preventDefault(event);\n                            event.stopImmediatePropagation();\n                        }\n                    }.bind(this));\n\n                    // Move our (last) handler topmost. We need this to avoid submit bindings with ko.\n                    listeners = $._data(parentForm[0], 'events').submit;\n                    listeners.unshift(listeners.pop());\n\n                    // Create a virtual token field\n                    this.tokenField = $('<input type=\"text\" name=\"token\" style=\"display: none\" />')[0];\n                    this.$parentForm = parentForm;\n                    parentForm.append(this.tokenField);\n                } else {\n                    this.tokenField = null;\n                }\n                if ($('#send2').length > 0) {$('#send2').prop('disabled', false);}\n            },\n\n            /**\n             * Validates reCAPTCHA\n             * @param {*} state\n             * @returns {jQuery}\n             */\n            validateReCaptcha: function (state) {\n                if (!this.getIsInvisibleRecaptcha()) {\n                    return $(document).find('input[type=checkbox].required-captcha').prop('checked', state);\n                }\n            },\n\n            /**\n             * Render reCAPTCHA\n             */\n            renderReCaptcha: function () {\n                if (window.grecaptcha && window.grecaptcha.render) { // Check if reCAPTCHA is already loaded\n                    this.initCaptcha();\n                } else { // Wait for reCAPTCHA to be loaded\n                    $(window).on('recaptchaapiready', function () {\n                        this.initCaptcha();\n                    }.bind(this));\n                }\n            },\n\n            /**\n             * Get reCAPTCHA ID\n             * @returns {String}\n             */\n            getReCaptchaId: function () {\n                return this.reCaptchaId;\n            }\n        });\n    });\n","Magento_ReCaptchaFrontendUi/js/registry.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['ko'], function (ko) {\n    'use strict';\n\n    return {\n        ids: ko.observableArray([]),\n        captchaList: ko.observableArray([]),\n        tokenFields: ko.observableArray([])\n    };\n});\n","Magento_ReCaptchaFrontendUi/js/nonInlineReCaptchaRenderer.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global grecaptcha */\ndefine([\n    'jquery',\n    'jquery/z-index'\n], function ($) {\n    'use strict';\n\n    var reCaptchaEntities = [],\n        initialized = false,\n        rendererRecaptchaId = 'recaptcha-invisible',\n        rendererReCaptcha = null;\n\n    return {\n        /**\n         * Add reCaptcha entity to checklist.\n         *\n         * @param {jQuery} reCaptchaEntity\n         * @param {Object} parameters\n         */\n        add: function (reCaptchaEntity, parameters) {\n            if (!initialized) {\n                this.init();\n                grecaptcha.render(rendererRecaptchaId, parameters);\n                setInterval(this.resolveVisibility, 100);\n                initialized = true;\n            }\n\n            reCaptchaEntities.push(reCaptchaEntity);\n        },\n\n        /**\n         * Show additional reCaptcha instance if any other should be visible, otherwise hide it.\n         */\n        resolveVisibility: function () {\n            reCaptchaEntities.some(function (entity) {\n                return entity.is(':visible') &&\n                    // 900 is some magic z-index value of modal popups.\n                    (entity.closest('[data-role=\\'modal\\']').length === 0 || entity.zIndex() > 900);\n            }) ? rendererReCaptcha.show() : rendererReCaptcha.hide();\n        },\n\n        /**\n         * Initialize additional reCaptcha instance.\n         */\n        init: function () {\n            rendererReCaptcha = $('<div/>', {\n                'id': rendererRecaptchaId\n            });\n            rendererReCaptcha.hide();\n            $('body').append(rendererReCaptcha);\n        }\n    };\n});\n","Magento_InventoryInStorePickupFrontend/js/checkout-data-ext.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Customer/js/customer-data'\n], function (\n    storage\n) {\n    'use strict';\n\n    return function (checkoutData) {\n\n        var cacheKey = 'checkout-data',\n\n            /**\n             * @param {Object} data\n             */\n            saveData = function (data) {\n                storage.set(cacheKey, data);\n            },\n\n            /**\n             * @return {Object}\n             */\n            getData = function () {\n                //Makes sure that checkout storage is initiated (any method can be used)\n                checkoutData.getSelectedShippingAddress();\n\n                return storage.get(cacheKey)();\n            };\n\n        /**\n         * Save the pickup address in persistence storage\n         *\n         * @param {Object} data\n         */\n        checkoutData.setSelectedPickupAddress = function (data) {\n            var obj = getData();\n\n            obj.selectedPickupAddress = data;\n            saveData(obj);\n        };\n\n        /**\n         * Get the pickup address from persistence storage\n         *\n         * @return {*}\n         */\n        checkoutData.getSelectedPickupAddress = function () {\n            return getData().selectedPickupAddress || null;\n        };\n\n        return checkoutData;\n    };\n});\n","Magento_InventoryInStorePickupFrontend/js/view/store-pickup.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent',\n    'underscore',\n    'jquery',\n    'knockout',\n    'uiRegistry',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/action/select-shipping-method',\n    'Magento_Checkout/js/checkout-data',\n    'Magento_Checkout/js/model/shipping-service',\n    'Magento_Checkout/js/model/step-navigator',\n    'Magento_Checkout/js/model/shipping-rate-service',\n    'Magento_InventoryInStorePickupFrontend/js/model/shipping-rate-processor/store-pickup-address',\n    'Magento_InventoryInStorePickupFrontend/js/model/pickup-locations-service',\n    'Magento_InventoryInStorePickupFrontend/js/model/pickup-address-converter',\n    'Magento_Checkout/js/model/checkout-data-resolver',\n    'Magento_Checkout/js/action/select-shipping-address'\n], function (\n    Component,\n    _,\n    $,\n    ko,\n    registry,\n    quote,\n    selectShippingMethodAction,\n    checkoutData,\n    shippingService,\n    stepNavigator,\n    shippingRateService,\n    shippingRateProcessor,\n    pickupLocationsService,\n    pickupAddressConverter,\n    checkoutDataResolver,\n    selectShippingAddress\n) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_InventoryInStorePickupFrontend/store-pickup',\n            deliveryMethodSelectorTemplate: 'Magento_InventoryInStorePickupFrontend/delivery-method-selector',\n            isVisible: false,\n            isAvailable: false,\n            isStorePickupSelected: false,\n            rate: {\n                'carrier_code': 'instore',\n                'method_code': 'pickup'\n            },\n            nearbySearchLimit: 50,\n            defaultCountry: window.checkoutConfig.defaultCountryId,\n            delimiter: window.checkoutConfig.storePickupApiSearchTermDelimiter,\n            rates: shippingService.getShippingRates(),\n            inStoreMethod: null,\n            lastSelectedNonPickUpShippingAddress: null\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function () {\n            this._super();\n\n            shippingRateService.registerProcessor('store-pickup-address', shippingRateProcessor);\n\n            this.convertAddressType(quote.shippingAddress());\n\n            this.isStorePickupSelected.subscribe(function () {\n                this.preselectLocation();\n            }, this);\n            this.preselectLocation();\n\n            this.syncWithShipping();\n        },\n\n        /**\n         * Init component observable variables\n         *\n         * @return {exports}\n         */\n        initObservable: function () {\n            this._super().observe(['isVisible']);\n\n            this.isStorePickupSelected = ko.pureComputed(function () {\n                return _.isMatch(quote.shippingMethod(), this.rate);\n            }, this);\n\n            this.isAvailable = ko.pureComputed(function () {\n                return _.findWhere(this.rates(), {\n                    'carrier_code': this.rate['carrier_code'],\n                    'method_code': this.rate['method_code']\n                });\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Synchronize store pickup visibility with shipping step.\n         *\n         * @returns void\n         */\n        syncWithShipping: function () {\n            var shippingStep = _.findWhere(stepNavigator.steps(), {\n                code: 'shipping'\n            });\n\n            shippingStep.isVisible.subscribe(function (isShippingVisible) {\n                this.isVisible(this.isAvailable && isShippingVisible);\n            }, this);\n            this.isVisible(this.isAvailable && shippingStep.isVisible());\n        },\n\n        /**\n         * @returns void\n         */\n        selectShipping: function () {\n            var nonPickupShippingMethod = _.find(\n                this.rates(),\n                function (rate) {\n                    return (\n                        rate['carrier_code'] !== this.rate['carrier_code'] &&\n                        rate['method_code'] !== this.rate['method_code']\n                    );\n                },\n                this\n            ),\n                nonPickupShippingAddress;\n\n            checkoutData.setSelectedShippingAddress(this.lastSelectedNonPickUpShippingAddress);\n            this.selectShippingMethod(nonPickupShippingMethod);\n\n            if (this.isStorePickupAddress(quote.shippingAddress())) {\n                nonPickupShippingAddress = checkoutDataResolver.getShippingAddressFromCustomerAddressList();\n\n                if (nonPickupShippingAddress) {\n                    selectShippingAddress(nonPickupShippingAddress);\n                }\n            }\n        },\n\n        /**\n         * @returns void\n         */\n        selectStorePickup: function () {\n            var pickupShippingMethod = _.findWhere(\n                this.rates(),\n                {\n                    'carrier_code': this.rate['carrier_code'],\n                    'method_code': this.rate['method_code']\n                },\n                this\n            );\n\n            this.lastSelectedNonPickUpShippingAddress = checkoutData.getSelectedShippingAddress();\n            checkoutData.setSelectedShippingAddress(null);\n            this.preselectLocation();\n            this.selectShippingMethod(pickupShippingMethod);\n        },\n\n        /**\n         * @param {Object} shippingMethod\n         */\n        selectShippingMethod: function (shippingMethod) {\n            selectShippingMethodAction(shippingMethod);\n            checkoutData.setSelectedShippingRate(\n                shippingMethod ? shippingMethod['carrier_code'] + '_' + shippingMethod['method_code'] : null\n            );\n        },\n\n        /**\n         * @param {Object} shippingAddress\n         * @returns void\n         */\n        convertAddressType: function (shippingAddress) {\n            var pickUpAddress;\n\n            if (\n                !this.isStorePickupAddress(shippingAddress) &&\n                this.isStorePickupSelected()\n            ) {\n                pickUpAddress = pickupAddressConverter.formatAddressToPickupAddress(shippingAddress);\n\n                if (quote.shippingAddress() !== pickUpAddress) {\n                    quote.shippingAddress(pickUpAddress);\n                }\n            }\n        },\n\n        /**\n         * @returns void\n         */\n        preselectLocation: function () {\n            var selectedLocation,\n                shippingAddress,\n                selectedPickupAddress,\n                customAttributes,\n                selectedSource,\n                selectedSourceCode,\n                nearestLocation,\n                productsInfo = [],\n                items = quote.getItems();\n\n            if (!this.isStorePickupSelected()) {\n                return;\n            }\n\n            selectedLocation = pickupLocationsService.selectedLocation();\n\n            if (selectedLocation) {\n                pickupLocationsService.selectForShipping(selectedLocation);\n\n                return;\n            }\n\n            shippingAddress = quote.shippingAddress();\n            customAttributes = shippingAddress.customAttributes || [];\n            selectedSource = _.findWhere(customAttributes, {\n                'attribute_code': 'sourceCode'\n            });\n\n            if (selectedSource) {\n                selectedSourceCode = selectedSource.value;\n            }\n\n            if (!selectedSourceCode) {\n                selectedSourceCode = this.getPickupLocationCodeFromAddress(shippingAddress);\n            }\n\n            if (!selectedSourceCode) {\n                selectedPickupAddress = pickupLocationsService.getSelectedPickupAddress();\n                selectedSourceCode = this.getPickupLocationCodeFromAddress(selectedPickupAddress);\n            }\n\n            if (selectedSourceCode) {\n                pickupLocationsService\n                    .getLocation(selectedSourceCode)\n                    .then(function (location) {\n                        pickupLocationsService.selectForShipping(location);\n                    });\n            } else if (shippingAddress.city && shippingAddress.postcode) {\n                _.each(items, function (item) {\n                    if (item['qty_options'] === undefined || item['qty_options'].length === 0) {\n                        productsInfo.push(\n                            {\n                                sku: item.sku\n                            }\n                        );\n                    }\n                });\n                pickupLocationsService\n                    .getNearbyLocations({\n                        area: {\n                            radius: this.nearbySearchRadius,\n                            searchTerm: shippingAddress.postcode + this.delimiter +\n                                        shippingAddress.countryId || this.defaultCountry\n                        },\n                        extensionAttributes: {\n                            productsInfo: productsInfo\n                        },\n                        pageSize: this.nearbySearchLimit\n                    })\n                    .then(function (locations) {\n                        nearestLocation = locations[0];\n\n                        if (nearestLocation) {\n                            pickupLocationsService.selectForShipping(\n                                nearestLocation\n                            );\n                        }\n                    });\n            }\n        },\n\n        /**\n         * @param {Object} address\n         * @returns {Boolean}\n         */\n        isStorePickupAddress: function (address) {\n            return address.getType() === 'store-pickup-address';\n        },\n\n        /**\n         * @param {Object} address\n         * @returns {String|null}\n         */\n        getPickupLocationCodeFromAddress: function (address) {\n            if (address &&\n                !_.isEmpty(address.extensionAttributes) &&\n                address.extensionAttributes['pickup_location_code']\n            ) {\n                return address.extensionAttributes['pickup_location_code'];\n            }\n\n            return null;\n        }\n    });\n});\n","Magento_InventoryInStorePickupFrontend/js/view/shipping-information-ext.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Checkout/js/model/quote'\n], function (quote) {\n    'use strict';\n\n    var storePickupShippingInformation = {\n        defaults: {\n            template: 'Magento_InventoryInStorePickupFrontend/shipping-information'\n        },\n\n        /**\n         * Get shipping method title based on delivery method.\n         *\n         * @return {String}\n         */\n        getShippingMethodTitle: function () {\n            var shippingMethod = quote.shippingMethod(),\n                locationName = '',\n                title;\n\n            if (!this.isStorePickup()) {\n\n                return this._super();\n            }\n\n            title = shippingMethod['carrier_title'] + ' - ' + shippingMethod['method_title'];\n\n            if (quote.shippingAddress().firstname !== undefined) {\n                locationName = quote.shippingAddress().firstname + ' ' + quote.shippingAddress().lastname;\n                title += ' \"' + locationName + '\"';\n            }\n\n            return title;\n        },\n\n        /**\n         * Get is store pickup delivery method selected.\n         *\n         * @returns {Boolean}\n         */\n        isStorePickup: function () {\n            var shippingMethod = quote.shippingMethod(),\n                isStorePickup = false;\n\n            if (shippingMethod !== null) {\n                isStorePickup = shippingMethod['carrier_code'] === 'instore' &&\n                    shippingMethod['method_code'] === 'pickup';\n            }\n\n            return isStorePickup;\n        }\n    };\n\n    return function (shippingInformation) {\n        return shippingInformation.extend(storePickupShippingInformation);\n    };\n});\n","Magento_InventoryInStorePickupFrontend/js/view/store-selector.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'underscore',\n    'uiComponent',\n    'uiRegistry',\n    'Magento_Ui/js/modal/modal',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Customer/js/model/customer',\n    'Magento_Checkout/js/model/step-navigator',\n    'Magento_Checkout/js/model/address-converter',\n    'Magento_Checkout/js/action/set-shipping-information',\n    'Magento_InventoryInStorePickupFrontend/js/model/pickup-locations-service'\n], function (\n    $,\n    _,\n    Component,\n    registry,\n    modal,\n    quote,\n    customer,\n    stepNavigator,\n    addressConverter,\n    setShippingInformationAction,\n    pickupLocationsService\n) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_InventoryInStorePickupFrontend/store-selector',\n            selectedLocationTemplate:\n                'Magento_InventoryInStorePickupFrontend/store-selector/selected-location',\n            storeSelectorPopupTemplate:\n                'Magento_InventoryInStorePickupFrontend/store-selector/popup',\n            storeSelectorPopupItemTemplate:\n                'Magento_InventoryInStorePickupFrontend/store-selector/popup-item',\n            loginFormSelector:\n                '#store-selector form[data-role=email-with-possible-login]',\n            defaultCountryId: window.checkoutConfig.defaultCountryId,\n            delimiter: window.checkoutConfig.storePickupApiSearchTermDelimiter,\n            selectedLocation: pickupLocationsService.selectedLocation,\n            quoteIsVirtual: quote.isVirtual,\n            searchQuery: '',\n            nearbyLocations: null,\n            isLoading: pickupLocationsService.isLoading,\n            popup: null,\n            searchDebounceTimeout: 300,\n            imports: {\n                nearbySearchRadius: '${ $.parentName }:nearbySearchRadius',\n                nearbySearchLimit: '${ $.parentName }:nearbySearchLimit'\n            }\n        },\n\n        /**\n         * Init component\n         *\n         * @return {exports}\n         */\n        initialize: function () {\n            var updateNearbyLocations, country;\n\n            this._super();\n\n            updateNearbyLocations = _.debounce(function (searchQuery) {\n                country = quote.shippingAddress() && quote.shippingAddress().countryId ?\n                    quote.shippingAddress().countryId : this.defaultCountryId;\n                searchQuery = this.getSearchTerm(searchQuery, country);\n                this.updateNearbyLocations(searchQuery);\n            }, this.searchDebounceTimeout).bind(this);\n            this.searchQuery.subscribe(updateNearbyLocations);\n\n            return this;\n        },\n\n        /**\n         * Init component observable variables\n         *\n         * @return {exports}\n         */\n        initObservable: function () {\n            return this._super().observe(['nearbyLocations', 'searchQuery']);\n        },\n\n        /**\n         * Set shipping information handler\n         */\n        setPickupInformation: function () {\n            if (this.validatePickupInformation()) {\n                setShippingInformationAction().done(function () {\n                    stepNavigator.next();\n                });\n            }\n        },\n\n        /**\n         * @return {*}\n         */\n        getPopup: function () {\n            if (!this.popup) {\n                this.popup = modal(\n                    this.popUpList.options,\n                    $(this.popUpList.element)\n                );\n            }\n\n            return this.popup;\n        },\n\n        /**\n         * Get Search Term from search query and country.\n         *\n         * @param {String} searchQuery\n         * @param {String} country\n         * @returns {String}\n         */\n        getSearchTerm: function (searchQuery, country) {\n            return searchQuery ? searchQuery + this.delimiter + country : searchQuery;\n        },\n\n        /**\n         * @returns void\n         */\n        openPopup: function () {\n            var shippingAddress = quote.shippingAddress(),\n                country = shippingAddress.countryId ? shippingAddress.countryId :\n                this.defaultCountryId,\n                searchTerm = '';\n\n            this.getPopup().openModal();\n\n            if (shippingAddress.city && shippingAddress.postcode) {\n                searchTerm = this.getSearchTerm(shippingAddress.postcode, country);\n            }\n\n            this.updateNearbyLocations(searchTerm);\n        },\n\n        /**\n         * @param {Object} location\n         * @returns void\n         */\n        selectPickupLocation: function (location) {\n            pickupLocationsService.selectForShipping(location);\n            this.getPopup().closeModal();\n        },\n\n        /**\n         * @param {Object} location\n         * @returns {*|Boolean}\n         */\n        isPickupLocationSelected: function (location) {\n            return _.isEqual(this.selectedLocation(), location);\n        },\n\n        /**\n         * @param {String} searchQuery\n         * @returns {*}\n         */\n        updateNearbyLocations: function (searchQuery) {\n            var self = this,\n                productsInfo = [],\n                items = quote.getItems(),\n                searchCriteria;\n\n            _.each(items, function (item) {\n                if (item['qty_options'] === undefined || item['qty_options'].length === 0) {\n                    productsInfo.push(\n                        {\n                            sku: item.sku\n                        }\n                    );\n                }\n            });\n\n            searchCriteria = {\n                extensionAttributes: {\n                    productsInfo: productsInfo\n                },\n                pageSize: this.nearbySearchLimit\n            };\n\n            if (searchQuery) {\n                searchCriteria.area = {\n                    radius: this.nearbySearchRadius,\n                    searchTerm: searchQuery\n                };\n            }\n\n            return pickupLocationsService\n                .getNearbyLocations(searchCriteria)\n                .then(function (locations) {\n                    self.nearbyLocations(locations);\n                })\n                .fail(function () {\n                    self.nearbyLocations([]);\n                });\n        },\n\n        /**\n         * @returns {Boolean}\n         */\n        validatePickupInformation: function () {\n            var emailValidationResult,\n                loginFormSelector = this.loginFormSelector;\n\n            if (!customer.isLoggedIn()) {\n                $(loginFormSelector).validation();\n                emailValidationResult = $(loginFormSelector + ' input[name=username]').valid() ? true : false;\n\n                if (!emailValidationResult) {\n                    $(this.loginFormSelector + ' input[name=username]').trigger('focus');\n\n                    return false;\n                }\n            }\n\n            return true;\n        }\n    });\n});\n","Magento_InventoryInStorePickupFrontend/js/view/form/element/email.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['jquery', 'Magento_Checkout/js/view/form/element/email'], function (\n    $,\n    Component\n) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template:\n                'Magento_InventoryInStorePickupFrontend/form/element/email',\n            links: {\n                email:\n                    'checkout.steps.shipping-step.shippingAddress.customer-email:email'\n            }\n        }\n    });\n});\n","Magento_InventoryInStorePickupFrontend/js/model/checkout-data-resolver-ext.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'mage/utils/wrapper',\n    'Magento_Checkout/js/checkout-data',\n    'Magento_Checkout/js/action/select-shipping-address',\n    'Magento_Checkout/js/model/address-converter',\n    'Magento_InventoryInStorePickupFrontend/js/model/pickup-address-converter'\n], function (\n    wrapper,\n    checkoutData,\n    selectShippingAddress,\n    addressConverter,\n    pickupAddressConverter\n) {\n    'use strict';\n\n    return function (checkoutDataResolver) {\n        checkoutDataResolver.resolveShippingAddress = wrapper.wrapSuper(\n            checkoutDataResolver.resolveShippingAddress,\n            function () {\n                var shippingAddress,\n                    pickUpAddress;\n\n                if (checkoutData.getSelectedPickupAddress() && checkoutData.getSelectedShippingAddress()) {\n                    shippingAddress = addressConverter.formAddressDataToQuoteAddress(\n                        checkoutData.getSelectedPickupAddress()\n                    );\n                    pickUpAddress = pickupAddressConverter.formatAddressToPickupAddress(\n                        shippingAddress\n                    );\n\n                    if (pickUpAddress.getKey() === checkoutData.getSelectedShippingAddress()) {\n                        selectShippingAddress(pickUpAddress);\n\n                        return;\n                    }\n                }\n                this._super();\n            });\n\n        return checkoutDataResolver;\n    };\n});\n","Magento_InventoryInStorePickupFrontend/js/model/pickup-address-converter.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(['underscore'], function (_) {\n    'use strict';\n\n    return {\n        /**\n         * Format address to use in store pickup\n         *\n         * @param {Object} address\n         * @return {*}\n         */\n        formatAddressToPickupAddress: function (address) {\n            var sourceCode = _.findWhere(address.customAttributes, {\n                'attribute_code': 'sourceCode'\n            });\n\n            if (!sourceCode &&\n                !_.isEmpty(address.extensionAttributes) &&\n                address.extensionAttributes['pickup_location_code']\n            ) {\n                sourceCode = {\n                    value: address.extensionAttributes['pickup_location_code']\n                };\n            }\n\n            if (sourceCode && address.getType() !== 'store-pickup-address') {\n                address = _.extend({}, address, {\n                    saveInAddressBook: 0,\n\n                    /**\n                     * Is address can be used for billing\n                     *\n                     * @return {Boolean}\n                     */\n                    canUseForBilling: function () {\n                        return false;\n                    },\n\n                    /**\n                     * Returns address type\n                     *\n                     * @return {String}\n                     */\n                    getType: function () {\n                        return 'store-pickup-address';\n                    },\n\n                    /**\n                     * Returns address key\n                     *\n                     * @return {*}\n                     */\n                    getKey: function () {\n                        return this.getType() + sourceCode.value;\n                    }\n                });\n            }\n\n            return address;\n        }\n    };\n});\n","Magento_InventoryInStorePickupFrontend/js/model/quote-ext.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'Magento_InventoryInStorePickupFrontend/js/model/pickup-address-converter'\n], function (ko, pickupAddressConverter) {\n    'use strict';\n\n    return function (quote) {\n        var shippingAddress = quote.shippingAddress;\n\n        /**\n         * Makes sure that shipping address gets appropriate type when it points\n         * to a store pickup location.\n         */\n        quote.shippingAddress = ko.pureComputed({\n            /**\n             * Return quote shipping address\n             */\n            read: function () {\n                return shippingAddress();\n            },\n\n            /**\n             * Set quote shipping address\n             */\n            write: function (address) {\n                shippingAddress(\n                    pickupAddressConverter.formatAddressToPickupAddress(address)\n                );\n            }\n        });\n\n        return quote;\n    };\n});\n","Magento_InventoryInStorePickupFrontend/js/model/pickup-locations-service.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'knockout',\n    'Magento_InventoryInStorePickupFrontend/js/model/resource-url-manager',\n    'mage/storage',\n    'Magento_Customer/js/customer-data',\n    'Magento_Checkout/js/checkout-data',\n    'Magento_Checkout/js/model/address-converter',\n    'Magento_Checkout/js/action/select-shipping-address',\n    'underscore',\n    'mage/translate',\n    'mage/url',\n    'Magento_InventoryInStorePickupFrontend/js/model/pickup-address-converter'\n], function (\n    $,\n    ko,\n    resourceUrlManager,\n    storage,\n    customerData,\n    checkoutData,\n    addressConverter,\n    selectShippingAddressAction,\n    _,\n    $t,\n    url,\n    pickupAddressConverter\n) {\n    'use strict';\n\n    var websiteCode = window.checkoutConfig.websiteCode,\n        countryData = customerData.get('directory-data');\n\n    return {\n        isLoading: ko.observable(false),\n        selectedLocation: ko.observable(null),\n        locationsCache: [],\n\n        /**\n         * Get shipping rates for specified address.\n         *\n         * @param {String} sourceCode\n         */\n        getLocation: function (sourceCode) {\n            var serviceUrl = resourceUrlManager.getUrlForPickupLocation(websiteCode, sourceCode);\n\n            this.isLoading(true);\n\n            return storage\n                .get(serviceUrl, {}, false)\n                .then(function (result) {\n                    var addresses = result.items || [],\n                        address = addresses[0] || {};\n\n                    return this.formatAddress(address);\n                }.bind(this))\n                .fail(function (response) {\n                    this.processError(response);\n\n                    return [];\n                }.bind(this))\n                .always(function () {\n                    this.isLoading(false);\n                }.bind(this));\n        },\n\n        /**\n         * Get nearby pickup locations based on given search criteria.\n         *\n         * @param {Object} searchCriteria - Search criteria object.\n         * @see Magento/InventoryInStorePickup/Model/SearchCriteria/GetNearbyLocationsCriteria.php\n         */\n        getNearbyLocations: function (searchCriteria) {\n            var self = this,\n                serviceUrl = resourceUrlManager.getUrlForNearbyPickupLocations(websiteCode, searchCriteria);\n\n            if (self.locationsCache[serviceUrl]) {\n                return $.Deferred().resolve(self.locationsCache[serviceUrl]).promise();\n            }\n\n            self.isLoading(true);\n\n            return storage\n                .get(serviceUrl, {}, false)\n                .then(function (result) {\n                    self.locationsCache[serviceUrl] = _.map(result.items, function (address) {\n                        return self.formatAddress(address);\n                    });\n\n                    return self.locationsCache[serviceUrl];\n                })\n                .fail(function (response) {\n                    self.processError(response);\n\n                    return [];\n                })\n                .always(function () {\n                    self.isLoading(false);\n                });\n        },\n\n        /**\n         * Select location for sipping.\n         *\n         * @param {Object} location\n         * @returns void\n         */\n        selectForShipping: function (location) {\n            var address = $.extend(\n                {},\n                addressConverter.formAddressDataToQuoteAddress({\n                    firstname: location.name,\n                    lastname: 'Store',\n                    street: location.street,\n                    city: location.city,\n                    postcode: location.postcode,\n                    'country_id': location['country_id'],\n                    telephone: location.telephone,\n                    'region_id': location['region_id'],\n                    'save_in_address_book': 0,\n                    'extension_attributes': {\n                        'pickup_location_code': location['pickup_location_code']\n                    }\n                }));\n\n            address = pickupAddressConverter.formatAddressToPickupAddress(address);\n            this.selectedLocation(location);\n            selectShippingAddressAction(address);\n            checkoutData.setSelectedShippingAddress(address.getKey());\n            checkoutData.setSelectedPickupAddress(\n                addressConverter.quoteAddressToFormAddressData(address)\n            );\n        },\n\n        /**\n         * Formats address returned by REST endpoint to match checkout address field naming.\n         *\n         * @param {Object} address - Address object returned by REST endpoint.\n         */\n        formatAddress: function (address) {\n            return {\n                name: address.name,\n                description: address.description,\n                latitude: address.latitude,\n                longitude: address.longitude,\n                street: [address.street],\n                city: address.city,\n                postcode: address.postcode,\n                'country_id': address['country_id'],\n                country: this.getCountryName(address['country_id']),\n                telephone: address.phone,\n                'region_id': address['region_id'],\n                region: this.getRegionName(\n                    address['country_id'],\n                    address['region_id']\n                ),\n                'pickup_location_code': address['pickup_location_code']\n            };\n        },\n\n        /**\n         * Get country name by id.\n         *\n         * @param {*} countryId\n         * @return {String}\n         */\n        getCountryName: function (countryId) {\n            return countryData()[countryId] !== undefined ?\n                countryData()[countryId].name\n                : ''; //eslint-disable-line\n        },\n\n        /**\n         * Returns region name based on given country and region identifiers.\n         *\n         * @param {String} countryId - Country identifier.\n         * @param {String} regionId - Region identifier.\n         */\n        getRegionName: function (countryId, regionId) {\n            var regions = countryData()[countryId] ?\n                countryData()[countryId].regions\n                : null;\n\n            return regions && regions[regionId] ? regions[regionId].name : '';\n        },\n\n        /**\n         * Process response errors.\n         *\n         * @param {Object} response\n         * @returns void\n         */\n        processError: function (response) {\n            var expr = /([%])\\w+/g,\n                error;\n\n            if (response.status === 401) {\n                //eslint-disable-line eqeqeq\n                window.location.replace(url.build('customer/account/login/'));\n\n                return;\n            }\n\n            try {\n                error = JSON.parse(response.responseText);\n            } catch (exception) {\n                error = $t(\n                    'Something went wrong with your request. Please try again later.'\n                );\n            }\n\n            if (error.hasOwnProperty('parameters')) {\n                error = error.message.replace(expr, function (varName) {\n                    varName = varName.substr(1);\n\n                    if (error.parameters.hasOwnProperty(varName)) {\n                        return error.parameters[varName];\n                    }\n\n                    return error.parameters.shift();\n                });\n            }\n        },\n\n        /**\n         * Returns selected pick up address from local storage\n         *\n         * @returns {Object|null}\n         */\n        getSelectedPickupAddress: function () {\n            var shippingAddress,\n                pickUpAddress;\n\n            if (checkoutData.getSelectedPickupAddress()) {\n                shippingAddress = addressConverter.formAddressDataToQuoteAddress(\n                    checkoutData.getSelectedPickupAddress()\n                );\n                pickUpAddress = pickupAddressConverter.formatAddressToPickupAddress(\n                    shippingAddress\n                );\n\n                return pickUpAddress;\n            }\n\n            return null;\n        }\n    };\n});\n","Magento_InventoryInStorePickupFrontend/js/model/resource-url-manager.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['jquery', 'Magento_Checkout/js/model/resource-url-manager'], function (\n    $,\n    resourceUrlManager\n) {\n    'use strict';\n\n    return {\n        /**\n         * Returns URL for REST API to fetch nearby pickup locations defined for given sales channel.\n         *\n         * @param {String} salesChannelCode - Code of the sales channel.\n         * @param {Object} searchCriteria\n         */\n        getUrlForNearbyPickupLocations: function (\n            salesChannelCode,\n            searchCriteria\n        ) {\n            var urls = {\n                    default: '/inventory/in-store-pickup/pickup-locations/'\n                },\n                criteria = {\n                    searchRequest: {\n                        scopeCode: salesChannelCode\n                    }\n                };\n\n            searchCriteria = {\n                searchRequest: searchCriteria\n            };\n\n            return (\n                resourceUrlManager.getUrl(urls, {}) +\n                '?' +\n                $.param($.extend(true, criteria, searchCriteria))\n            );\n        },\n\n        /**\n         * Returns URL for REST API to fetch all pickup locations defined for given sales channel.\n         *\n         * @param {String} salesChannelType - Type of the sales channel, e.g. website.\n         * @param {String} salesChannelCode - Code of the sales channel.\n         */\n        getUrlForPickupLocationsAssignedToSalesChannel: function (\n            salesChannelType,\n            salesChannelCode\n        ) {\n            var params = {\n                    salesChannelType: salesChannelType,\n                    salesChannelCode: salesChannelCode\n                },\n                urls = {\n                    default: '/inventory/in-store-pickup/pickup-locations-assigned-to-sales-channel/' +\n                        ':salesChannelType/:salesChannelCode'\n                };\n\n            return resourceUrlManager.getUrl(urls, params);\n        },\n\n        /**\n         * Returns URL for REST API to fetch pickup location with given code defined for given sales channel.\n         *\n         * @param {String} salesChannelCode - Code of the sales channel.\n         * @param {String} pickupLocationCode - Code of the pickup location.\n         */\n        getUrlForPickupLocation: function (\n            salesChannelCode,\n            pickupLocationCode\n        ) {\n            var urls = {\n                    default: '/inventory/in-store-pickup/pickup-locations/'\n                },\n                searchRequest = {\n                    searchRequest: {\n                        filters: {\n                            pickupLocationCode: {\n                                value: pickupLocationCode\n                            }\n                        },\n                        scopeCode: salesChannelCode\n                    }\n                };\n\n            return resourceUrlManager.getUrl(urls, {}) +\n                '?' +\n                $.param(searchRequest);\n        }\n    };\n});\n","Magento_InventoryInStorePickupFrontend/js/model/shipping-rate-processor/store-pickup-address.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n    'use strict';\n\n    return {\n        /*eslint-disable no-unused-vars*/\n        /**\n         * @param {Object} address\n         */\n        getRates: function (address) {}\n    };\n});\n","js/navigation-menu.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * @deprecated\n * @see lib/web/mage/menu.js\n */\ndefine([\n    'jquery',\n    'matchMedia',\n    'mage/template',\n    'mage/dropdowns',\n    'mage/terms'\n], function ($, mediaCheck, mageTemplate) {\n    'use strict';\n\n    $.widget('mage.navigationMenu', {\n        options: {\n            itemsContainer: '> ul',\n            topLevel: 'li.level0',\n            topLevelSubmenu: '> .submenu',\n            topLevelHoverClass: 'hover',\n            expandedTopLevel: '.more',\n            hoverInTimeout: 300,\n            hoverOutTimeout: 500,\n            submenuAnimationSpeed: 200,\n            collapsable: true,\n            collapsableDropdownTemplate:\n                '<script type=\"text/x-magento-template\">' +\n                    '<li class=\"level0 level-top more parent\">' +\n                        '<div class=\"submenu\">' +\n                            '<ul><%= elems %></ul>' +\n                        '</div>' +\n                    '</li>' +\n                '</script>'\n        },\n\n        /** @inheritdoc */\n        _create: function () {\n            this.itemsContainer = $(this.options.itemsContainer, this.element);\n            this.topLevel = $(this.options.topLevel, this.element);\n            this.topLevelSubmenu = $(this.options.topLevelSubmenu, this.topLevel);\n\n            this._bind();\n        },\n\n        /**\n         * @private\n         */\n        _init: function () {\n            if (this.options.collapsable) {\n                setTimeout($.proxy(function () {\n                    this._checkToCollapseOrExpand();\n                }, this), 100);\n            }\n        },\n\n        /**\n         * @private\n         */\n        _bind: function () {\n            this._on({\n                /**\n                 * @param {jQuery.Event} e\n                 */\n                'mouseenter > ul > li.level0': function (e) {\n                    if (!this.entered) { // fix IE bug with 'mouseenter' event\n                        this.timeoutId && clearTimeout(this.timeoutId);\n                        this.timeoutId = setTimeout($.proxy(function () {\n                            this._openSubmenu(e);\n                        }, this), this.options.hoverInTimeout);\n                        this.entered = true;\n                    }\n                },\n\n                /**\n                 * @param {jQuery.Event} e\n                 */\n                'mouseleave > ul > li.level0': function (e) {\n                    this.entered = null;\n\n                    this.timeoutId && clearTimeout(this.timeoutId);\n                    this.timeoutId = setTimeout($.proxy(function () {\n                        this._closeSubmenu(e.currentTarget);\n                    }, this), this.options.hoverOutTimeout);\n                },\n\n                /**\n                 * @param {jQuert.Event} e\n                 */\n                'click': function (e) {\n                    e.stopPropagation();\n                }\n            });\n\n            $(document)\n                .on('click.hideMenu', $.proxy(function () {\n                    var isOpened = this.topLevel.filter(function () {\n                        return $(this).data('opened');\n                    });\n\n                    if (isOpened) {\n                        this._closeSubmenu(null, false);\n                    }\n                }, this));\n\n            $(window)\n                .on('resize', $.proxy(function () {\n                    this.timeoutOnResize && clearTimeout(this.timeoutOnResize);\n                    this.timeoutOnResize = setTimeout($.proxy(function () {\n                        if (this.options.collapsable) {\n                            if ($(this.options.expandedTopLevel, this.element).length) {\n                                this._expandMenu();\n                            }\n                            this._checkToCollapseOrExpand();\n                        }\n                    }, this), 300);\n                }, this));\n        },\n\n        /**\n         * @param {jQuery.Event} e\n         * @private\n         */\n        _openSubmenu: function (e) {\n            var menuItem = e.currentTarget;\n\n            if (!$(menuItem).data('opened')) {\n                this._closeSubmenu(menuItem, true, true);\n\n                $(this.options.topLevelSubmenu, menuItem)\n                    .slideDown(this.options.submenuAnimationSpeed, $.proxy(function () {\n                        $(menuItem).addClass(this.options.topLevelHoverClass);\n                        $(menuItem).data('opened', true);\n                    }, this));\n            } else if ($(e.target).closest(this.options.topLevel)) {\n                $(e.target)\n                    .addClass(this.options.topLevelHoverClass)\n                    .siblings(this.options.topLevel)\n                        .removeClass(this.options.topLevelHoverClass);\n            }\n        },\n\n        /**\n         * @param {*} menuItem\n         * @param {*} excludeCurrent\n         * @param {*} fast\n         * @private\n         */\n        _closeSubmenu: function (menuItem, excludeCurrent, fast) {\n            var topLevel = $(this.options.topLevel, this.element),\n                activeSubmenu = $(this.options.topLevelSubmenu, menuItem || null);\n\n            $(this.options.topLevelSubmenu, topLevel)\n                .filter(function () {\n                    return excludeCurrent ? $(this).not(activeSubmenu) : true;\n                })\n                .slideUp(fast ? 0 : this.options.submenuAnimationSpeed);\n\n            topLevel\n                .removeClass(this.options.topLevelHoverClass)\n                .data('opened', false);\n        },\n\n        /**\n         * @private\n         */\n        _checkToCollapseOrExpand: function () {\n            var navWidth, totalWidth, startCollapseIndex;\n\n            if ($('html').hasClass('lt-640') || $('html').hasClass('w-640')) {\n                return;\n            }\n\n            navWidth = this.itemsContainer.width();\n            totalWidth = 0;\n            startCollapseIndex = 0;\n\n            $.each($(this.options.topLevel, this.element), function (index, item) {\n                totalWidth += $(item).outerWidth(true);\n\n                if (totalWidth > navWidth && !startCollapseIndex) {\n                    startCollapseIndex = index - 2;\n                }\n            });\n\n            this[startCollapseIndex ? '_collapseMenu' : '_expandMenu'](startCollapseIndex);\n        },\n\n        /**\n         * @param {*} startCollapseIndex\n         * @private\n         */\n        _collapseMenu: function (startCollapseIndex) {\n            this.elemsToCollapse = this.topLevel.filter(function (index) {\n                return index > startCollapseIndex;\n            });\n            this.elemsToCollapseClone = $('<div></div>').append(this.elemsToCollapse.clone()).html();\n\n            this.collapsableDropdown = $(\n                mageTemplate(\n                    this.options.collapsableDropdownTemplate,\n                    {\n                        elems: this.elemsToCollapseClone\n                    }\n                )\n            );\n\n            this.itemsContainer.append(this.collapsableDropdown);\n            this.elemsToCollapse.detach();\n        },\n\n        /**\n         * @private\n         */\n        _expandMenu: function () {\n            this.elemsToCollapse && this.elemsToCollapse.appendTo(this.itemsContainer);\n            this.collapsableDropdown && this.collapsableDropdown.remove();\n        },\n\n        /**\n         * @private\n         */\n        _destroy: function () {\n            this._expandMenu();\n        }\n    });\n\n    /*\n     * Provides \"Continium\" effect for submenu\n     * */\n    $.widget('mage.navigationMenu', $.mage.navigationMenu, {\n        options: {\n            parentLevel: '> ul > li.level0',\n            submenuAnimationSpeed: 150,\n            submenuContiniumEffect: false\n        },\n\n        /**\n         * @private\n         */\n        _init: function () {\n            this._super();\n            this._applySubmenuStyles();\n        },\n\n        /**\n         * @private\n         */\n        _applySubmenuStyles: function () {\n            $(this.options.topLevelSubmenu, $(this.options.topLevel, this.element))\n                .removeAttr('style');\n\n            $(this.options.topLevelSubmenu, $(this.options.parentLevel, this.element))\n                .css({\n                    display: 'block',\n                    height: 0,\n                    overflow: 'hidden'\n                });\n        },\n\n        /**\n         * @param {jQuery.Event} e\n         * @private\n         */\n        _openSubmenu: function (e) {\n            var menuItem = e.currentTarget,\n                submenu = $(this.options.topLevelSubmenu, menuItem),\n                openedItems = $(this.options.topLevel, this.element).filter(function () {\n                    return $(this).data('opened');\n                });\n\n            if (submenu.length) {\n                this.heightToAnimate = $(this.options.itemsContainer, submenu).outerHeight(true);\n\n                if (openedItems.length) {\n                    this._closeSubmenu(menuItem, true, this.heightToAnimate, $.proxy(function () {\n                        submenu.css({\n                            height: 'auto'\n                        });\n                        $(menuItem)\n                            .addClass(this.options.topLevelHoverClass);\n                    }, this), e);\n                } else {\n                    submenu.animate({\n                        height: this.heightToAnimate\n                    }, this.options.submenuAnimationSpeed, $.proxy(function () {\n                        $(menuItem)\n                            .addClass(this.options.topLevelHoverClass);\n                    }, this));\n                }\n\n                $(menuItem)\n                    .data('opened', true);\n            } else {\n                this._closeSubmenu(menuItem);\n            }\n        },\n\n        /**\n         * @param {*} menuItem\n         * @param {*} excludeCurrent\n         * @param {*} heightToAnimate\n         * @param {Function} callback\n         * @private\n         */\n        _closeSubmenu: function (menuItem, excludeCurrent, heightToAnimate, callback) {\n            var topLevel = $(this.options.topLevel, this.itemsContainer),\n                prevOpenedItem, prevOpenedSubmenu;\n\n            if (!excludeCurrent) {\n                $(this.options.topLevelSubmenu, $(this.options.parentLevel, this.element))\n                    .animate({\n                        height: 0\n                    });\n\n                topLevel\n                    .data('opened', false)\n                    .removeClass(this.options.topLevelHoverClass);\n            } else {\n                prevOpenedItem = topLevel.filter(function () {\n                    return $(this).data('opened');\n                });\n                prevOpenedSubmenu = $(this.options.topLevelSubmenu, prevOpenedItem);\n\n                prevOpenedSubmenu.animate({\n                    height: heightToAnimate\n                }, this.options.submenuAnimationSpeed, 'linear', function () {\n                    $(this).css({\n                        height: 0\n                    });\n                    callback && callback();\n                });\n\n                prevOpenedItem\n                    .data('opened', false)\n                    .removeClass(this.options.topLevelHoverClass);\n            }\n        },\n\n        /**\n         * @private\n         */\n        _collapseMenu: function () {\n            this._superApply(arguments);\n            this._applySubmenuStyles();\n        }\n    });\n\n    //  Responsive menu\n    $.widget('mage.navigationMenu', $.mage.navigationMenu, {\n        options: {\n            responsive: false,\n            origNavPlaceholder: '.page-header',\n            mainContainer: 'body',\n            pageWrapper: '.page-wrapper',\n            openedMenuClass: 'opened',\n            toggleActionPlaceholder: '.block-search',\n            itemWithSubmenu: 'li.parent',\n            titleWithSubmenu: 'li.parent > a',\n            submenu: 'li.parent > .submenu',\n            toggleActionTemplate:\n                '<script type=\"text/x-magento-template\">' +\n                    '<span data-action=\"toggle-nav\" class=\"action toggle nav\">Toggle Nav</span>' +\n                '</script>',\n            submenuActionsTemplate:\n                '<script type=\"text/x-magento-template\">' +\n                    '<li class=\"action all\">' +\n                        '<a href=\"<%= categoryURL %>\"><span>All <%= category %></span></a>' +\n                    '</li>' +\n                '</script>',\n            navigationSectionsWrapperTemplate:\n                '<script type=\"text/x-magento-template\">' +\n                    '<dl class=\"navigation-tabs\" data-sections=\"tabs\">' +\n                    '</dl>' +\n                '</script>',\n            navigationItemWrapperTemplate:\n                '<script type=\"text/x-magento-template\">' +\n                    '<dt class=\"item title <% if (active) { %>active<% } %>\" data-section=\"title\">' +\n                        '<a class=\"switch\" data-toggle=\"switch\" href=\"#TODO\"><%= title %></a>' +\n                    '</dt>' +\n                    '<dd class=\"item content <% if (active) { %>active<%}%>\" data-section=\"content\">' +\n                    '</dd>' +\n                '</script>'\n        },\n\n        /**\n         * @private\n         */\n        _init: function () {\n            this._super();\n\n            this.mainContainer = $(this.options.mainContainer);\n            this.pageWrapper = $(this.options.pageWrapper);\n            this.toggleAction = $(mageTemplate(this.options.toggleActionTemplate, {}));\n\n            if (this.options.responsive) {\n                mediaCheck({\n                    media: '(min-width: 768px)',\n                    entry: $.proxy(function () {\n                        this._toggleDesktopMode();\n                    }, this),\n                    exit: $.proxy(function () {\n                        this._toggleMobileMode();\n                    }, this)\n                });\n            }\n        },\n\n        /**\n         * @private\n         */\n        _bind: function () {\n            this._super();\n            this._bindDocumentEvents();\n        },\n\n        /**\n         * @private\n         */\n        _bindDocumentEvents: function () {\n            if (!this.eventsBound) {\n                $(document)\n                    .on('click.toggleMenu', '.action.toggle.nav', $.proxy(function (e) {\n                        if ($(this.element).data('opened')) {\n                            this._hideMenu();\n                        } else {\n                            this._showMenu();\n                        }\n                        e.stopPropagation();\n                        this.mobileNav.scrollTop(0);\n                        this._fixedBackLink();\n                    }, this))\n                    .on('click.hideMenu', this.options.pageWrapper, $.proxy(function () {\n                        if ($(this.element).data('opened')) {\n                            this._hideMenu();\n                            this.mobileNav.scrollTop(0);\n                            this._fixedBackLink();\n                        }\n                    }, this))\n                    .on('click.showSubmenu', this.options.titleWithSubmenu, $.proxy(function (e) {\n                        this._showSubmenu(e);\n\n                        e.preventDefault();\n                        this.mobileNav.scrollTop(0);\n                        this._fixedBackLink();\n                    }, this))\n                    .on('click.hideSubmenu', '.action.back', $.proxy(function (e) {\n                        this._hideSubmenu(e);\n                        this.mobileNav.scrollTop(0);\n                        this._fixedBackLink();\n                    }, this));\n\n                this.eventsBound = true;\n            }\n        },\n\n        /**\n         * @private\n         */\n        _showMenu: function () {\n            $(this.element).data('opened', true);\n            this.mainContainer.add('html').addClass(this.options.openedMenuClass);\n        },\n\n        /**\n         * @private\n         */\n        _hideMenu: function () {\n            $(this.element).data('opened', false);\n            this.mainContainer.add('html').removeClass(this.options.openedMenuClass);\n        },\n\n        /**\n         * @param {jQuery.Event} e\n         * @private\n         */\n        _showSubmenu: function (e) {\n            var submenu;\n\n            $(e.currentTarget).addClass('action back');\n            submenu = $(e.currentTarget).siblings('.submenu');\n\n            submenu.addClass('opened');\n        },\n\n        /**\n         * @param {jQuery.Event} e\n         * @private\n         */\n        _hideSubmenu: function (e) {\n            var submenuSelector = '.submenu',\n                submenu = $(e.currentTarget).next(submenuSelector);\n\n            $(e.currentTarget).removeClass('action back');\n            submenu.removeClass('opened');\n        },\n\n        /**\n         * @private\n         */\n        _renderSubmenuActions: function () {\n            $.each(\n                $(this.options.itemWithSubmenu),\n                $.proxy(function (index, item) {\n                    var actions = $(mageTemplate(\n                            this.options.submenuActionsTemplate,\n                            {\n                                category: $('> a > span', item).text(),\n                                categoryURL: $('> a', item).attr('href')\n                            }\n                        )),\n                        submenu = $('> .submenu', item),\n                        items = $('> ul', submenu);\n\n                    items.prepend(actions);\n                }, this)\n            );\n        },\n\n        /**\n         * @private\n         */\n        _toggleMobileMode: function () {\n            this._expandMenu();\n\n            $(this.options.topLevelSubmenu, $(this.options.topLevel, this.element))\n                .removeAttr('style');\n\n            this.toggleAction.insertBefore(this.options.toggleActionPlaceholder);\n            this.mobileNav = $(this.element).detach().clone();\n            this.mainContainer.prepend(this.mobileNav);\n            this.mobileNav.find('> ul').addClass('nav');\n            this._insertExtraItems();\n            this._wrapItemsInSections();\n            this.mobileNav.scroll($.proxy(function () {\n                this._fixedBackLink();\n            }, this));\n\n            this._renderSubmenuActions();\n            this._bindDocumentEvents();\n        },\n\n        /**\n         * @private\n         */\n        _toggleDesktopMode: function () {\n            this.mobileNav && this.mobileNav.remove();\n            this.toggleAction.detach();\n            $(this.element).insertAfter(this.options.origNavPlaceholder);\n\n            $(document)\n                .off('click.toggleMenu', '.action.toggle.nav')\n                .off('click.hideMenu', this.options.pageWrapper)\n                .off('click.showSubmenu', this.options.titleWithSubmenu)\n                .off('click.hideSubmenu', '.action.back');\n\n            this.eventsBound = false;\n\n            this._applySubmenuStyles();\n        },\n\n        /**\n         * @private\n         */\n        _insertExtraItems: function () {\n            var settings, footerSettings, account;\n\n            if ($('.header.panel .switcher').length) {\n                settings = $('.header.panel .switcher')\n                    .clone()\n                    .addClass('settings');\n\n                this.mobileNav.prepend(settings);\n            }\n\n            if ($('.footer .switcher').length) {\n                footerSettings = $('.footer .switcher')\n                    .clone()\n                    .addClass('settings');\n\n                this.mobileNav.prepend(footerSettings);\n            }\n\n            if ($('.header.panel .header.links li').length) {\n                account = $('.header.panel > .header.links')\n                    .clone()\n                    .addClass('account');\n\n                this.mobileNav.prepend(account);\n            }\n        },\n\n        /**\n         * @private\n         */\n        _wrapItemsInSections: function () {\n            var account = $('> .account', this.mobileNav),\n                settings = $('> .settings', this.mobileNav),\n                nav = $('> .nav', this.mobileNav),\n                navigationSectionsWrapper = $(mageTemplate(this.options.navigationSectionsWrapperTemplate, {})),\n                navigationItemWrapper;\n\n            this.mobileNav.append(navigationSectionsWrapper);\n\n            if (nav.length) {\n                navigationItemWrapper = $(mageTemplate(this.options.navigationItemWrapperTemplate, {\n                    title: 'Menu'\n                }));\n                navigationSectionsWrapper.append(navigationItemWrapper);\n                navigationItemWrapper.eq(1).append(nav);\n            }\n\n            if (account.length) {\n                navigationItemWrapper = $(mageTemplate(this.options.navigationItemWrapperTemplate, {\n                    title: 'Account'\n                }));\n                navigationSectionsWrapper.append(navigationItemWrapper);\n                navigationItemWrapper.eq(1).append(account);\n            }\n\n            if (settings.length) {\n                navigationItemWrapper = $(\n                    mageTemplate(this.options.navigationItemWrapperTemplate, {\n                        title: 'Settings'\n                    })\n                );\n                navigationSectionsWrapper.append(navigationItemWrapper);\n                navigationItemWrapper.eq(1).append(settings);\n            }\n\n            navigationSectionsWrapper.addClass(\n                'navigation-tabs-' + navigationSectionsWrapper.find('[data-section=\"title\"]').length\n            );\n            navigationSectionsWrapper.terms();\n        },\n\n        /**\n         * @private\n         */\n        _fixedBackLink: function () {\n            var linksBack = this.mobileNav.find('.submenu .action.back'),\n                linkBack = this.mobileNav.find('.submenu.opened > ul > .action.back').last(),\n                subMenu, navOffset, linkBackHeight;\n\n            linksBack.removeClass('fixed');\n\n            if (linkBack.length) {\n                subMenu = linkBack.parent();\n                navOffset = this.mobileNav.find('.nav').position().top;\n                linkBackHeight = linkBack.height();\n\n                if (navOffset <= 0) {\n                    linkBack.addClass('fixed');\n                    subMenu.css({\n                        paddingTop: linkBackHeight\n                    });\n                } else {\n                    linkBack.removeClass('fixed');\n                    subMenu.css({\n                        paddingTop: 0\n                    });\n                }\n            }\n        }\n    });\n\n    return $.mage.navigationMenu;\n});\n","Magento_ReCaptchaCheckout/js/webapiReCaptchaRegistry-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n    'use strict';\n\n    return function (originalFunction) {\n        /**\n         * {@inheritDoc}\n         */\n       originalFunction.addListener = function (id , func) {\n            this._listeners[id] = func;\n       };\n\n        return originalFunction;\n    };\n\n});\n","Magento_ReCaptchaCheckout/js/model/place-order-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable max-nested-callbacks */\n\ndefine([\n    'jquery',\n    'mage/utils/wrapper',\n    'Magento_ReCaptchaWebapiUi/js/webapiReCaptchaRegistry'\n], function ($, wrapper, recaptchaRegistry) {\n    'use strict';\n\n    return function (placeOrder) {\n        return wrapper.wrap(placeOrder, function (originalAction, serviceUrl, payload, messageContainer) {\n            var recaptchaDeferred;\n\n            if (recaptchaRegistry.triggers.hasOwnProperty('recaptcha-checkout-place-order')) {\n                //ReCaptcha is present for checkout\n                recaptchaDeferred = $.Deferred();\n                recaptchaRegistry.addListener('recaptcha-checkout-place-order', function (token) {\n                    //Add reCaptcha value to place-order request and resolve deferred with the API call results\n                    payload.xReCaptchaValue = token;\n                    originalAction(serviceUrl, payload, messageContainer).done(function () {\n                        recaptchaDeferred.resolve.apply(recaptchaDeferred, arguments);\n                    }).fail(function () {\n                        recaptchaDeferred.reject.apply(recaptchaDeferred, arguments);\n                    });\n                });\n                //Trigger ReCaptcha validation\n                recaptchaRegistry.triggers['recaptcha-checkout-place-order']();\n\n                if (\n                    !recaptchaRegistry._isInvisibleType.hasOwnProperty('recaptcha-checkout-place-order') ||\n                    recaptchaRegistry._isInvisibleType['recaptcha-checkout-place-order'] === false\n                ) {\n                    //remove listener so that place order action is only triggered by the 'Place Order' button\n                    recaptchaRegistry.removeListener('recaptcha-checkout-place-order');\n                }\n\n                return recaptchaDeferred;\n            }\n\n            //No ReCaptcha, just sending the request\n            return originalAction(serviceUrl, payload, messageContainer);\n        });\n    };\n});\n","Magento_Newsletter/js/newsletter-sign-up.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'uiElement',\n    'mage/url',\n    'subscriptionStatusResolver',\n    'mage/validation'\n], function ($, Component, urlBuilder, subscriptionStatusResolver) {\n    'use strict';\n\n    return Component.extend({\n\n        defaults: {\n            signUpElement: '',\n            submitButton: '',\n            element: null\n        },\n\n        /** @inheritdoc */\n        initialize: function (config, element) {\n            this._super();\n            this.element = element;\n            $(element).on('change', $.proxy(this.updateSignUpStatus, this));\n            this.updateSignUpStatus();\n        },\n\n        /**\n         * Send status request and update subscription element according to result.\n         */\n        updateSignUpStatus: function () {\n            var element = $(this.element),\n                email = element.val(),\n                self = this,\n                newsletterSubscription;\n\n            if ($(self.signUpElement).is(':checked')) {\n                return;\n            }\n\n            if (!email || !$.validator.methods['validate-email'].call(this, email, element)) {\n                return;\n            }\n\n            newsletterSubscription = $.Deferred();\n\n            $(self.submitButton).prop('disabled', true);\n\n            subscriptionStatusResolver(email, newsletterSubscription);\n\n            $.when(newsletterSubscription).done(function (isSubscribed) {\n                if (isSubscribed) {\n                    $(self.signUpElement).prop('checked', true);\n                }\n            }).always(function () {\n                $(self.submitButton).prop('disabled', false);\n            });\n        }\n    });\n});\n","Magento_Newsletter/js/subscription-status-resolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/url'\n], function ($, urlBuilder) {\n    'use strict';\n\n    return function (email, deferred) {\n        return $.getJSON(\n            urlBuilder.build('newsletter/ajax/status'),\n            {\n                email: email\n            }\n        ).done(function (response) {\n            if (response.errors) {\n                deferred.reject();\n            } else {\n                deferred.resolve(response.subscribed);\n            }\n        }).fail(function () {\n            deferred.reject();\n        });\n    };\n});\n","Magento_Weee/js/tax-toggle.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    /**\n     * @param {Object} config\n     * @param {jQuery.Event} e\n     */\n    function onToggle(config, e) {\n        var elem = $(e.currentTarget),\n            expandedClassName = config.expandedClassName || 'cart-tax-total-expanded';\n\n        elem.toggleClass(expandedClassName);\n\n        $(config.itemTaxId).toggle();\n    }\n\n    return function (data, el) {\n        $(el).on('click', onToggle.bind(null, data));\n    };\n});\n","Magento_Weee/js/price/adjustment.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/grid/columns/column'\n], function (Element) {\n    'use strict';\n\n    return Element.extend({\n        defaults: {\n            bodyTmpl: 'Magento_Weee/price/adjustment',\n            dataSource: '${ $.parentName }.provider',\n            //Weee configuration constants can be configured from backend\n            inclFptWithDesc: 1,//show FPT and description\n            inclFpt: 0, //show FPT attribute\n            exclFpt: 2, //do not show FPT\n            bothFptPrices: 3 //show price without FPT and with FPT and with description\n        },\n\n        /**\n         * Get Weee attributes.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} Weee html\n         */\n        getWeeeAttributes: function (row) {\n            return row['price_info']['extension_attributes']['weee_attributes'];\n        },\n\n        /**\n         * Get Weee without Tax attributes.\n         *\n         * @param {Object} taxAmount\n         * @return {HTMLElement} Weee html\n         */\n        getWeeeTaxWithoutTax: function (taxAmount) {\n            return taxAmount['amount_excl_tax'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getWeeeTaxWithoutTax.\n         *\n         * @param {Object} taxAmount\n         * @return {HTMLElement} Weee html\n         */\n        getWeeeTaxWithoutTaxUnsanitizedHtml: function (taxAmount) {\n            return this.getWeeeTaxWithoutTax(taxAmount);\n        },\n\n        /**\n         * Get Weee with Tax attributes.\n         *\n         * @param {Object} taxAmount\n         * @return {HTMLElement} Weee html\n         */\n        getWeeeTaxWithTax: function (taxAmount) {\n            return taxAmount['tax_amount_incl_tax'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getWeeeTaxWithTax.\n         *\n         * @param {Object} taxAmount\n         * @return {HTMLElement} Weee html\n         */\n        getWeeeTaxWithTaxUnsanitizedHtml: function (taxAmount) {\n            return this.getWeeeTaxWithTax(taxAmount);\n        },\n\n        /**\n         * Get Weee Tax name.\n         *\n         * @param {String} taxAmount\n         * @return {String} Weee name\n         */\n        getWeeTaxAttributeName: function (taxAmount) {\n            return taxAmount['attribute_code'];\n        },\n\n        /**\n         * Set price type.\n         *\n         * @param {String} priceType\n         * @return {Object}\n         */\n        setPriceType: function (priceType) {\n            this.taxPriceType = priceType;\n\n            return this;\n        },\n\n        /**\n         * Check if Weee Tax must be shown.\n         *\n         * @param {Object} row\n         * @return {Boolean}\n         */\n        isShown: function (row) {\n            return row['price_info']['extension_attributes']['weee_attributes'].length;\n        },\n\n        /**\n         * Get Weee final price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} Weee final price html\n         */\n        getWeeeAdjustment: function (row) {\n            return row['price_info']['extension_attributes']['weee_adjustment'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getWeeeAdjustment.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} Weee final price html\n         */\n        getWeeeAdjustmentUnsanitizedHtml: function (row) {\n            return this.getWeeeAdjustment(row);\n        },\n\n        /**\n         * Return whether display setting is to display price including FPT only.\n         *\n         * @return {Boolean}\n         */\n        displayPriceInclFpt: function () {\n            return +this.source.data.displayWeee === this.inclFpt;\n        },\n\n        /**\n         * Return whether display setting is to display\n         * price including FPT and FPT description.\n         *\n         * @return {Boolean}\n         */\n        displayPriceInclFptDescr: function () {\n            return +this.source.data.displayWeee === this.inclFptWithDesc;\n        },\n\n        /**\n         * Return whether display setting is to display price\n         * excluding FPT but including FPT description and final price.\n         *\n         * @return {Boolean}\n         */\n        displayPriceExclFptDescr: function () {\n            return +this.source.data.displayWeee === this.exclFpt;\n        },\n\n        /**\n         * Return whether display setting is to display price excluding FPT.\n         *\n         * @return {Boolean}\n         */\n        displayPriceExclFpt: function () {\n            return +this.source.data.displayWeee === this.bothFptPrices;\n        },\n\n        /**\n         * Return whether display setting is to display price excluding tax.\n         *\n         * @return {Boolean}\n         */\n        displayPriceExclTax: function () {\n            return +this.source.data.displayTaxes === this.inclFptWithDesc;\n        },\n\n        /**\n         * Return whether display setting is to display price including tax.\n         *\n         * @return {Boolean}\n         */\n        displayPriceInclTax: function () {\n            return +this.source.data.displayTaxes === this.exclFpt;\n        },\n\n        /**\n         * Return whether display setting is to display\n         * both price including tax and price excluding tax.\n         *\n         * @return {Boolean}\n         */\n        displayBothPricesTax: function () {\n            return +this.source.data.displayTaxes === this.bothFptPrices;\n        }\n    });\n});\n","Magento_Weee/js/view/checkout/summary/weee.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n    'Magento_Checkout/js/view/summary/abstract-total',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/model/totals',\n    'Magento_Catalog/js/price-utils'\n], function (Component, quote, totals) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Weee/checkout/summary/weee'\n        },\n        isIncludedInSubtotal: window.checkoutConfig.isIncludedInSubtotal,\n        totals: totals.totals,\n\n        /**\n         * @returns {Number}\n         */\n        getWeeeTaxSegment: function () {\n            var weee = totals.getSegment('weee_tax') || totals.getSegment('weee');\n\n            if (weee !== null && weee.hasOwnProperty('value')) {\n                return weee.value;\n            }\n\n            return 0;\n        },\n\n        /**\n         * Get weee value\n         * @returns {String}\n         */\n        getValue: function () {\n            return this.getFormattedPrice(this.getWeeeTaxSegment());\n        },\n\n        /**\n         * Weee display flag\n         * @returns {Boolean}\n         */\n        isDisplayed: function () {\n            return this.isFullMode() && this.getWeeeTaxSegment() > 0;\n        }\n    });\n});\n","Magento_Weee/js/view/checkout/summary/item/price/row_incl_tax.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n    'Magento_Weee/js/view/checkout/summary/item/price/weee'\n], function (weee) {\n    'use strict';\n\n    return weee.extend({\n        defaults: {\n            template: 'Magento_Weee/checkout/summary/item/price/row_incl_tax',\n            displayArea: 'row_incl_tax'\n        },\n\n        /**\n         * @param {Object} item\n         * @return {Number}\n         */\n        getFinalRowDisplayPriceInclTax: function (item) {\n            var rowTotalInclTax = parseFloat(item['row_total_incl_tax']);\n\n            if (!window.checkoutConfig.getIncludeWeeeFlag) {\n                rowTotalInclTax += this.getRowWeeeTaxInclTax(item);\n            }\n\n            return rowTotalInclTax;\n        },\n\n        /**\n         * @param {Object} item\n         * @return {Number}\n         */\n        getRowDisplayPriceInclTax: function (item) {\n            var rowTotalInclTax = parseFloat(item['row_total_incl_tax']);\n\n            if (window.checkoutConfig.getIncludeWeeeFlag) {\n                rowTotalInclTax += this.getRowWeeeTaxInclTax(item);\n            }\n\n            return rowTotalInclTax;\n        },\n\n        /**\n         * @param {Object}item\n         * @return {Number}\n         */\n        getRowWeeeTaxInclTax: function (item) {\n            var totalWeeeTaxInclTaxApplied = 0,\n                weeeTaxAppliedAmounts;\n\n            if (item['weee_tax_applied']) {\n                weeeTaxAppliedAmounts = JSON.parse(item['weee_tax_applied']);\n                weeeTaxAppliedAmounts.forEach(function (weeeTaxAppliedAmount) {\n                    totalWeeeTaxInclTaxApplied += parseFloat(Math.max(weeeTaxAppliedAmount['row_amount_incl_tax'], 0));\n                });\n            }\n\n            return totalWeeeTaxInclTaxApplied;\n        }\n\n    });\n});\n","Magento_Weee/js/view/checkout/summary/item/price/row_excl_tax.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n    'Magento_Weee/js/view/checkout/summary/item/price/weee'\n], function (weee) {\n    'use strict';\n\n    return weee.extend({\n        defaults: {\n            template: 'Magento_Weee/checkout/summary/item/price/row_excl_tax'\n        },\n\n        /**\n         * @param {Object} item\n         * @return {Number}\n         */\n        getFinalRowDisplayPriceExclTax: function (item) {\n            var rowTotalExclTax = parseFloat(item['row_total']);\n\n            if (!window.checkoutConfig.getIncludeWeeeFlag) {\n                rowTotalExclTax += parseFloat(item['qty']) *\n                    parseFloat(item['weee_tax_applied_amount']);\n            }\n\n            return rowTotalExclTax;\n        },\n\n        /**\n         * @param {Object} item\n         * @return {Number}\n         */\n        getRowDisplayPriceExclTax: function (item) {\n            var rowTotalExclTax = parseFloat(item['row_total']);\n\n            if (window.checkoutConfig.getIncludeWeeeFlag) {\n                rowTotalExclTax += this.getRowWeeeTaxExclTax(item);\n            }\n\n            return rowTotalExclTax;\n        },\n\n        /**\n         * @param {Object} item\n         * @return {Number}\n         */\n        getRowWeeeTaxExclTax: function (item) {\n            var totalWeeeTaxExclTaxApplied = 0,\n                weeeTaxAppliedAmounts;\n\n            if (item['weee_tax_applied']) {\n                weeeTaxAppliedAmounts = JSON.parse(item['weee_tax_applied']);\n                weeeTaxAppliedAmounts.forEach(function (weeeTaxAppliedAmount) {\n                    totalWeeeTaxExclTaxApplied += parseFloat(Math.max(weeeTaxAppliedAmount['row_amount'], 0));\n                });\n            }\n\n            return totalWeeeTaxExclTaxApplied;\n        }\n\n    });\n});\n","Magento_Weee/js/view/checkout/summary/item/price/weee.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n    'Magento_Checkout/js/view/summary/abstract-total',\n    'Magento_Checkout/js/model/quote'\n], function (Component) {\n    'use strict';\n\n    return Component.extend({\n        /**\n         * @param {Object} item\n         * @return {Boolean}\n         */\n        isDisplayPriceWithWeeeDetails: function (item) {\n            if (!parseFloat(item['weee_tax_applied_amount']) || parseFloat(item['weee_tax_applied_amount'] <= 0)) {\n                return false;\n            }\n\n            return window.checkoutConfig.isDisplayPriceWithWeeeDetails;\n        },\n\n        /**\n         * @param {Object} item\n         * @return {Boolean}\n         */\n        isDisplayFinalPrice: function (item) {\n            if (!parseFloat(item['weee_tax_applied_amount'])) {\n                return false;\n            }\n\n            return window.checkoutConfig.isDisplayFinalPrice;\n        },\n\n        /**\n         * @param {Object} item\n         * @return {Array}\n         */\n        getWeeeTaxApplied: function (item) {\n            if (item['weee_tax_applied']) {\n                return JSON.parse(item['weee_tax_applied']);\n            }\n\n            return [];\n        }\n    });\n});\n","Magento_Weee/js/view/cart/totals/weee.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Weee/js/view/checkout/summary/weee'\n], function (Component) {\n    'use strict';\n\n    return Component.extend({\n\n        /**\n         * @override\n         */\n        isFullMode: function () {\n            return true;\n        }\n    });\n});\n","knockoutjs/knockout-repeat.js":"// REPEAT binding for Knockout http://knockoutjs.com/\n// (c) Michael Best\n// License: MIT (http://www.opensource.org/licenses/mit-license.php)\n// Version 2.1.0\n\n(function(factory) {\n    if (typeof define === 'function' && define.amd) {\n        // [1] AMD anonymous module\n        define(['knockout'], factory);\n    } else if (typeof exports === 'object') {\n        // [2] commonJS\n        factory(require('knockout'));\n    } else {\n        // [3] No module loader (plain <script> tag) - put directly in global namespace\n        factory(window.ko);\n    }\n})(function(ko) {\n\nif (!ko.virtualElements)\n    throw Error('Repeat requires at least Knockout 2.1');\n\nvar ko_bindingFlags = ko.bindingFlags || {};\nvar ko_unwrap = ko.utils.unwrapObservable;\n\nvar koProtoName = '__ko_proto__';\n\nif (ko.version >= \"3.0.0\") {\n    // In Knockout 3.0.0, use the node preprocessor to replace a node with a repeat binding with a virtual element\n    var provider = ko.bindingProvider.instance, previousPreprocessFn = provider.preprocessNode;\n    provider.preprocessNode = function(node) {\n        var newNodes, nodeBinding;\n        if (!previousPreprocessFn || !(newNodes = previousPreprocessFn.call(this, node))) {\n            if (node.nodeType === 1 && (nodeBinding = node.getAttribute('data-bind'))) {\n                if (/^\\s*repeat\\s*:/.test(nodeBinding)) {\n                    var leadingComment = node.ownerDocument.createComment('ko ' + nodeBinding),\n                        trailingComment = node.ownerDocument.createComment('/ko');\n                    node.parentNode.insertBefore(leadingComment, node);\n                    node.parentNode.insertBefore(trailingComment, node.nextSibling);\n                    node.removeAttribute('data-bind');\n                    newNodes = [leadingComment, node, trailingComment];\n                }\n            }\n        }\n        return newNodes;\n    };\n}\n\nko.virtualElements.allowedBindings.repeat = true;\nko.bindingHandlers.repeat = {\n    flags: ko_bindingFlags.contentBind | ko_bindingFlags.canUseVirtual,\n    init: function(element, valueAccessor, allBindingsAccessor, xxx, bindingContext) {\n\n        // Read and set fixed options--these options cannot be changed\n        var repeatParam = ko_unwrap(valueAccessor());\n        if (repeatParam && typeof repeatParam == 'object' && !('length' in repeatParam)) {\n            var repeatIndex = repeatParam.index,\n                repeatData = repeatParam.item,\n                repeatStep = repeatParam.step,\n                repeatReversed = repeatParam.reverse,\n                repeatBind = repeatParam.bind,\n                repeatInit = repeatParam.init,\n                repeatUpdate = repeatParam.update;\n        }\n        // Set default values for options that need it\n        repeatIndex = repeatIndex || '$index';\n        repeatData = repeatData || ko.bindingHandlers.repeat.itemName || '$item';\n        repeatStep = repeatStep || 1;\n        repeatReversed = repeatReversed || false;\n\n        var parent = element.parentNode, placeholder;\n        if (element.nodeType == 8) {    // virtual element\n            // Extract the \"children\" and find the single element node\n            var childNodes = ko.utils.arrayFilter(ko.virtualElements.childNodes(element), function(node) { return node.nodeType == 1;});\n            if (childNodes.length !== 1) {\n                throw Error(\"Repeat binding requires a single element to repeat\");\n            }\n            ko.virtualElements.emptyNode(element);\n\n            // The placeholder is the closing comment normally, or the opening comment if reversed\n            placeholder = repeatReversed ? element : element.nextSibling;\n            // The element to repeat is the contained element\n            element = childNodes[0];\n        } else {    // regular element\n            // First clean the element node and remove node's binding\n            var origBindString = element.getAttribute('data-bind');\n            ko.cleanNode(element);\n            element.removeAttribute('data-bind');\n\n            // Original element is no longer needed: delete it and create a placeholder comment\n            placeholder = element.ownerDocument.createComment('ko_repeatplaceholder ' + origBindString);\n            parent.replaceChild(placeholder, element);\n        }\n\n        // extract and remove a data-repeat-bind attribute, if present\n        if (!repeatBind) {\n            repeatBind = element.getAttribute('data-repeat-bind');\n            if (repeatBind) {\n                element.removeAttribute('data-repeat-bind');\n            }\n        }\n\n        // Make a copy of the element node to be copied for each repetition\n        var cleanNode = element.cloneNode(true);\n        if (typeof repeatBind == \"string\") {\n            cleanNode.setAttribute('data-bind', repeatBind);\n            repeatBind = null;\n        }\n\n        // Set up persistent data\n        var lastRepeatCount = 0,\n            notificationObservable = ko.observable(),\n            repeatArray, arrayObservable;\n\n        if (repeatInit) {\n            repeatInit(parent);\n        }\n\n        var subscribable = ko.computed(function() {\n            function makeArrayItemAccessor(index) {\n                var f = function(newValue) {\n                    var item = repeatArray[index];\n                    // Reading the value of the item\n                    if (!arguments.length) {\n                        notificationObservable();   // for dependency tracking\n                        return ko_unwrap(item);\n                    }\n                    // Writing a value to the item\n                    if (ko.isObservable(item)) {\n                        item(newValue);\n                    } else if (arrayObservable && arrayObservable.splice) {\n                        arrayObservable.splice(index, 1, newValue);\n                    } else {\n                        repeatArray[index] = newValue;\n                    }\n                    return this;\n                };\n                // Pretend that our accessor function is an observable\n                f[koProtoName] = ko.observable;\n                return f;\n            }\n\n            function makeBinding(item, index, context) {\n                return repeatArray\n                    ? function() { return repeatBind.call(bindingContext.$data, item, index, context); }\n                    : function() { return repeatBind.call(bindingContext.$data, index, context); }\n            }\n\n            // Read and set up variable options--these options can change and will update the binding\n            var paramObservable = valueAccessor(), repeatParam = ko_unwrap(paramObservable), repeatCount = 0;\n            if (repeatParam && typeof repeatParam == 'object') {\n                if ('length' in repeatParam) {\n                    repeatArray = repeatParam;\n                    repeatCount = repeatArray.length;\n                } else {\n                    if ('foreach' in repeatParam) {\n                        repeatArray = ko_unwrap(paramObservable = repeatParam.foreach);\n                        if (repeatArray && typeof repeatArray == 'object' && 'length' in repeatArray) {\n                            repeatCount = repeatArray.length || 0;\n                        } else {\n                            repeatCount = repeatArray || 0;\n                            repeatArray = null;\n                        }\n                    }\n                    // If a count value is provided (>0), always output that number of items\n                    if ('count' in repeatParam)\n                        repeatCount = ko_unwrap(repeatParam.count) || repeatCount;\n                    // If a limit is provided, don't output more than the limit\n                    if ('limit' in repeatParam)\n                        repeatCount = Math.min(repeatCount, ko_unwrap(repeatParam.limit)) || repeatCount;\n                }\n                arrayObservable = repeatArray && ko.isObservable(paramObservable) ? paramObservable : null;\n            } else {\n                repeatCount = repeatParam || 0;\n            }\n\n            // Remove nodes from end if array is shorter\n            for (; lastRepeatCount > repeatCount; lastRepeatCount-=repeatStep) {\n                ko.removeNode(repeatReversed ? placeholder.nextSibling : placeholder.previousSibling);\n            }\n\n            // Notify existing nodes of change\n            notificationObservable.notifySubscribers();\n\n            // Add nodes to end if array is longer (also initially populates nodes)\n            for (; lastRepeatCount < repeatCount; lastRepeatCount+=repeatStep) {\n                // Clone node and add to document\n                var newNode = cleanNode.cloneNode(true);\n                parent.insertBefore(newNode, repeatReversed ? placeholder.nextSibling : placeholder);\n                newNode.setAttribute('data-repeat-index', lastRepeatCount);\n\n                // Apply bindings to inserted node\n                if (repeatArray && repeatData == '$data') {\n                    var newContext = bindingContext.createChildContext(makeArrayItemAccessor(lastRepeatCount));\n                } else {\n                    var newContext = bindingContext.extend();\n                    if (repeatArray)\n                        newContext[repeatData] = makeArrayItemAccessor(lastRepeatCount);\n                }\n                newContext[repeatIndex] = lastRepeatCount;\n                if (repeatBind) {\n                    var result = ko.applyBindingsToNode(newNode, makeBinding(newContext[repeatData], lastRepeatCount, newContext), newContext, true),\n                        shouldBindDescendants = result && result.shouldBindDescendants;\n                }\n                if (!repeatBind || (result && shouldBindDescendants !== false)) {\n                    ko.applyBindings(newContext, newNode);\n                }\n            }\n            if (repeatUpdate) {\n                repeatUpdate(parent);\n            }\n        }, null, {disposeWhenNodeIsRemoved: placeholder});\n\n        return { controlsDescendantBindings: true, subscribable: subscribable };\n    }\n};\n});","knockoutjs/knockout.js":"/*!\n * Knockout JavaScript library v3.5.1\n * (c) The Knockout.js team - http://knockoutjs.com/\n * License: MIT (http://www.opensource.org/licenses/mit-license.php)\n */\n\n(function(){\n    var DEBUG=true;\n    (function(undefined){\n        // (0, eval)('this') is a robust way of getting a reference to the global object\n        // For details, see http://stackoverflow.com/questions/14119988/return-this-0-evalthis/14120023#14120023\n        var window = this || (0, eval)('this'),\n            document = window['document'],\n            navigator = window['navigator'],\n            jQueryInstance = window[\"jQuery\"],\n            JSON = window[\"JSON\"];\n\n        if (!jQueryInstance && typeof jQuery !== \"undefined\") {\n            jQueryInstance = jQuery;\n        }\n        (function(factory) {\n            // Support three module loading scenarios\n            if (typeof define === 'function' && define['amd']) {\n                // [1] AMD anonymous module\n                define(['exports', 'require'], factory);\n            } else if (typeof exports === 'object' && typeof module === 'object') {\n                // [2] CommonJS/Node.js\n                factory(module['exports'] || exports);  // module.exports is for Node.js\n            } else {\n                // [3] No module loader (plain <script> tag) - put directly in global namespace\n                factory(window['ko'] = {});\n            }\n        }(function(koExports, amdRequire){\n// Internally, all KO objects are attached to koExports (even the non-exported ones whose names will be minified by the closure compiler).\n// In the future, the following \"ko\" variable may be made distinct from \"koExports\" so that private objects are not externally reachable.\n            var ko = typeof koExports !== 'undefined' ? koExports : {};\n// Google Closure Compiler helpers (used only to make the minified file smaller)\n            ko.exportSymbol = function(koPath, object) {\n                var tokens = koPath.split(\".\");\n\n                // In the future, \"ko\" may become distinct from \"koExports\" (so that non-exported objects are not reachable)\n                // At that point, \"target\" would be set to: (typeof koExports !== \"undefined\" ? koExports : ko)\n                var target = ko;\n\n                for (var i = 0; i < tokens.length - 1; i++)\n                    target = target[tokens[i]];\n                target[tokens[tokens.length - 1]] = object;\n            };\n            ko.exportProperty = function(owner, publicName, object) {\n                owner[publicName] = object;\n            };\n            ko.version = \"3.5.1\";\n\n            ko.exportSymbol('version', ko.version);\n// For any options that may affect various areas of Knockout and aren't directly associated with data binding.\n            ko.options = {\n                'deferUpdates': false,\n                'useOnlyNativeEvents': false,\n                'foreachHidesDestroyed': false\n            };\n\n//ko.exportSymbol('options', ko.options);   // 'options' isn't minified\n            ko.utils = (function () {\n                var hasOwnProperty = Object.prototype.hasOwnProperty;\n\n                function objectForEach(obj, action) {\n                    for (var prop in obj) {\n                        if (hasOwnProperty.call(obj, prop)) {\n                            action(prop, obj[prop]);\n                        }\n                    }\n                }\n\n                function extend(target, source) {\n                    if (source) {\n                        for(var prop in source) {\n                            if(hasOwnProperty.call(source, prop)) {\n                                target[prop] = source[prop];\n                            }\n                        }\n                    }\n                    return target;\n                }\n\n                function setPrototypeOf(obj, proto) {\n                    obj.__proto__ = proto;\n                    return obj;\n                }\n\n                var canSetPrototype = ({ __proto__: [] } instanceof Array);\n                var canUseSymbols = !DEBUG && typeof Symbol === 'function';\n\n                // Represent the known event types in a compact way, then at runtime transform it into a hash with event name as key (for fast lookup)\n                var knownEvents = {}, knownEventTypesByEventName = {};\n                var keyEventTypeName = (navigator && /Firefox\\/2/i.test(navigator.userAgent)) ? 'KeyboardEvent' : 'UIEvents';\n                knownEvents[keyEventTypeName] = ['keyup', 'keydown', 'keypress'];\n                knownEvents['MouseEvents'] = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave'];\n                objectForEach(knownEvents, function(eventType, knownEventsForType) {\n                    if (knownEventsForType.length) {\n                        for (var i = 0, j = knownEventsForType.length; i < j; i++)\n                            knownEventTypesByEventName[knownEventsForType[i]] = eventType;\n                    }\n                });\n                var eventsThatMustBeRegisteredUsingAttachEvent = { 'propertychange': true }; // Workaround for an IE9 issue - https://github.com/SteveSanderson/knockout/issues/406\n\n                // Detect IE versions for bug workarounds (uses IE conditionals, not UA string, for robustness)\n                // Note that, since IE 10 does not support conditional comments, the following logic only detects IE < 10.\n                // Currently this is by design, since IE 10+ behaves correctly when treated as a standard browser.\n                // If there is a future need to detect specific versions of IE10+, we will amend this.\n                var ieVersion = document && (function() {\n                    var version = 3, div = document.createElement('div'), iElems = div.getElementsByTagName('i');\n\n                    // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment\n                    while (\n                        div.innerHTML = '<!--[if gt IE ' + (++version) + ']><i></i><![endif]-->',\n                            iElems[0]\n                        ) {}\n                    return version > 4 ? version : undefined;\n                }());\n                var isIe6 = ieVersion === 6,\n                    isIe7 = ieVersion === 7;\n\n                function isClickOnCheckableElement(element, eventType) {\n                    if ((ko.utils.tagNameLower(element) !== \"input\") || !element.type) return false;\n                    if (eventType.toLowerCase() != \"click\") return false;\n                    var inputType = element.type;\n                    return (inputType == \"checkbox\") || (inputType == \"radio\");\n                }\n\n                // For details on the pattern for changing node classes\n                // see: https://github.com/knockout/knockout/issues/1597\n                var cssClassNameRegex = /\\S+/g;\n\n                var jQueryEventAttachName;\n\n                function toggleDomNodeCssClass(node, classNames, shouldHaveClass) {\n                    var addOrRemoveFn;\n                    if (classNames) {\n                        if (typeof node.classList === 'object') {\n                            addOrRemoveFn = node.classList[shouldHaveClass ? 'add' : 'remove'];\n                            ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {\n                                addOrRemoveFn.call(node.classList, className);\n                            });\n                        } else if (typeof node.className['baseVal'] === 'string') {\n                            // SVG tag .classNames is an SVGAnimatedString instance\n                            toggleObjectClassPropertyString(node.className, 'baseVal', classNames, shouldHaveClass);\n                        } else {\n                            // node.className ought to be a string.\n                            toggleObjectClassPropertyString(node, 'className', classNames, shouldHaveClass);\n                        }\n                    }\n                }\n\n                function toggleObjectClassPropertyString(obj, prop, classNames, shouldHaveClass) {\n                    // obj/prop is either a node/'className' or a SVGAnimatedString/'baseVal'.\n                    var currentClassNames = obj[prop].match(cssClassNameRegex) || [];\n                    ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {\n                        ko.utils.addOrRemoveItem(currentClassNames, className, shouldHaveClass);\n                    });\n                    obj[prop] = currentClassNames.join(\" \");\n                }\n\n                return {\n                    fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],\n\n                    arrayForEach: function (array, action, actionOwner) {\n                        for (var i = 0, j = array.length; i < j; i++) {\n                            action.call(actionOwner, array[i], i, array);\n                        }\n                    },\n\n                    arrayIndexOf: typeof Array.prototype.indexOf == \"function\"\n                        ? function (array, item) {\n                            return Array.prototype.indexOf.call(array, item);\n                        }\n                        : function (array, item) {\n                            for (var i = 0, j = array.length; i < j; i++) {\n                                if (array[i] === item)\n                                    return i;\n                            }\n                            return -1;\n                        },\n\n                    arrayFirst: function (array, predicate, predicateOwner) {\n                        for (var i = 0, j = array.length; i < j; i++) {\n                            if (predicate.call(predicateOwner, array[i], i, array))\n                                return array[i];\n                        }\n                        return undefined;\n                    },\n\n                    arrayRemoveItem: function (array, itemToRemove) {\n                        var index = ko.utils.arrayIndexOf(array, itemToRemove);\n                        if (index > 0) {\n                            array.splice(index, 1);\n                        }\n                        else if (index === 0) {\n                            array.shift();\n                        }\n                    },\n\n                    arrayGetDistinctValues: function (array) {\n                        var result = [];\n                        if (array) {\n                            ko.utils.arrayForEach(array, function(item) {\n                                if (ko.utils.arrayIndexOf(result, item) < 0)\n                                    result.push(item);\n                            });\n                        }\n                        return result;\n                    },\n\n                    arrayMap: function (array, mapping, mappingOwner) {\n                        var result = [];\n                        if (array) {\n                            for (var i = 0, j = array.length; i < j; i++)\n                                result.push(mapping.call(mappingOwner, array[i], i));\n                        }\n                        return result;\n                    },\n\n                    arrayFilter: function (array, predicate, predicateOwner) {\n                        var result = [];\n                        if (array) {\n                            for (var i = 0, j = array.length; i < j; i++)\n                                if (predicate.call(predicateOwner, array[i], i))\n                                    result.push(array[i]);\n                        }\n                        return result;\n                    },\n\n                    arrayPushAll: function (array, valuesToPush) {\n                        if (valuesToPush instanceof Array)\n                            array.push.apply(array, valuesToPush);\n                        else\n                            for (var i = 0, j = valuesToPush.length; i < j; i++)\n                                array.push(valuesToPush[i]);\n                        return array;\n                    },\n\n                    addOrRemoveItem: function(array, value, included) {\n                        var existingEntryIndex = ko.utils.arrayIndexOf(ko.utils.peekObservable(array), value);\n                        if (existingEntryIndex < 0) {\n                            if (included)\n                                array.push(value);\n                        } else {\n                            if (!included)\n                                array.splice(existingEntryIndex, 1);\n                        }\n                    },\n\n                    canSetPrototype: canSetPrototype,\n\n                    extend: extend,\n\n                    setPrototypeOf: setPrototypeOf,\n\n                    setPrototypeOfOrExtend: canSetPrototype ? setPrototypeOf : extend,\n\n                    objectForEach: objectForEach,\n\n                    objectMap: function(source, mapping, mappingOwner) {\n                        if (!source)\n                            return source;\n                        var target = {};\n                        for (var prop in source) {\n                            if (hasOwnProperty.call(source, prop)) {\n                                target[prop] = mapping.call(mappingOwner, source[prop], prop, source);\n                            }\n                        }\n                        return target;\n                    },\n\n                    emptyDomNode: function (domNode) {\n                        while (domNode.firstChild) {\n                            ko.removeNode(domNode.firstChild);\n                        }\n                    },\n\n                    moveCleanedNodesToContainerElement: function(nodes) {\n                        // Ensure it's a real array, as we're about to reparent the nodes and\n                        // we don't want the underlying collection to change while we're doing that.\n                        var nodesArray = ko.utils.makeArray(nodes);\n                        var templateDocument = (nodesArray[0] && nodesArray[0].ownerDocument) || document;\n\n                        var container = templateDocument.createElement('div');\n                        for (var i = 0, j = nodesArray.length; i < j; i++) {\n                            container.appendChild(ko.cleanNode(nodesArray[i]));\n                        }\n                        return container;\n                    },\n\n                    cloneNodes: function (nodesArray, shouldCleanNodes) {\n                        for (var i = 0, j = nodesArray.length, newNodesArray = []; i < j; i++) {\n                            var clonedNode = nodesArray[i].cloneNode(true);\n                            newNodesArray.push(shouldCleanNodes ? ko.cleanNode(clonedNode) : clonedNode);\n                        }\n                        return newNodesArray;\n                    },\n\n                    setDomNodeChildren: function (domNode, childNodes) {\n                        ko.utils.emptyDomNode(domNode);\n                        if (childNodes) {\n                            for (var i = 0, j = childNodes.length; i < j; i++)\n                                domNode.appendChild(childNodes[i]);\n                        }\n                    },\n\n                    replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {\n                        var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;\n                        if (nodesToReplaceArray.length > 0) {\n                            var insertionPoint = nodesToReplaceArray[0];\n                            var parent = insertionPoint.parentNode;\n                            for (var i = 0, j = newNodesArray.length; i < j; i++)\n                                parent.insertBefore(newNodesArray[i], insertionPoint);\n                            for (var i = 0, j = nodesToReplaceArray.length; i < j; i++) {\n                                ko.removeNode(nodesToReplaceArray[i]);\n                            }\n                        }\n                    },\n\n                    fixUpContinuousNodeArray: function(continuousNodeArray, parentNode) {\n                        // Before acting on a set of nodes that were previously outputted by a template function, we have to reconcile\n                        // them against what is in the DOM right now. It may be that some of the nodes have already been removed, or that\n                        // new nodes might have been inserted in the middle, for example by a binding. Also, there may previously have been\n                        // leading comment nodes (created by rewritten string-based templates) that have since been removed during binding.\n                        // So, this function translates the old \"map\" output array into its best guess of the set of current DOM nodes.\n                        //\n                        // Rules:\n                        //   [A] Any leading nodes that have been removed should be ignored\n                        //       These most likely correspond to memoization nodes that were already removed during binding\n                        //       See https://github.com/knockout/knockout/pull/440\n                        //   [B] Any trailing nodes that have been remove should be ignored\n                        //       This prevents the code here from adding unrelated nodes to the array while processing rule [C]\n                        //       See https://github.com/knockout/knockout/pull/1903\n                        //   [C] We want to output a continuous series of nodes. So, ignore any nodes that have already been removed,\n                        //       and include any nodes that have been inserted among the previous collection\n\n                        if (continuousNodeArray.length) {\n                            // The parent node can be a virtual element; so get the real parent node\n                            parentNode = (parentNode.nodeType === 8 && parentNode.parentNode) || parentNode;\n\n                            // Rule [A]\n                            while (continuousNodeArray.length && continuousNodeArray[0].parentNode !== parentNode)\n                                continuousNodeArray.splice(0, 1);\n\n                            // Rule [B]\n                            while (continuousNodeArray.length > 1 && continuousNodeArray[continuousNodeArray.length - 1].parentNode !== parentNode)\n                                continuousNodeArray.length--;\n\n                            // Rule [C]\n                            if (continuousNodeArray.length > 1) {\n                                var current = continuousNodeArray[0], last = continuousNodeArray[continuousNodeArray.length - 1];\n                                // Replace with the actual new continuous node set\n                                continuousNodeArray.length = 0;\n                                while (current !== last) {\n                                    continuousNodeArray.push(current);\n                                    current = current.nextSibling;\n                                }\n                                continuousNodeArray.push(last);\n                            }\n                        }\n                        return continuousNodeArray;\n                    },\n\n                    setOptionNodeSelectionState: function (optionNode, isSelected) {\n                        // IE6 sometimes throws \"unknown error\" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser.\n                        if (ieVersion < 7)\n                            optionNode.setAttribute(\"selected\", isSelected);\n                        else\n                            optionNode.selected = isSelected;\n                    },\n\n                    stringTrim: function (string) {\n                        return string === null || string === undefined ? '' :\n                            string.trim ?\n                                string.trim() :\n                                string.toString().replace(/^[\\s\\xa0]+|[\\s\\xa0]+$/g, '');\n                    },\n\n                    stringStartsWith: function (string, startsWith) {\n                        string = string || \"\";\n                        if (startsWith.length > string.length)\n                            return false;\n                        return string.substring(0, startsWith.length) === startsWith;\n                    },\n\n                    domNodeIsContainedBy: function (node, containedByNode) {\n                        if (node === containedByNode)\n                            return true;\n                        if (node.nodeType === 11)\n                            return false; // Fixes issue #1162 - can't use node.contains for document fragments on IE8\n                        if (containedByNode.contains)\n                            return containedByNode.contains(node.nodeType !== 1 ? node.parentNode : node);\n                        if (containedByNode.compareDocumentPosition)\n                            return (containedByNode.compareDocumentPosition(node) & 16) == 16;\n                        while (node && node != containedByNode) {\n                            node = node.parentNode;\n                        }\n                        return !!node;\n                    },\n\n                    domNodeIsAttachedToDocument: function (node) {\n                        return ko.utils.domNodeIsContainedBy(node, node.ownerDocument.documentElement);\n                    },\n\n                    anyDomNodeIsAttachedToDocument: function(nodes) {\n                        return !!ko.utils.arrayFirst(nodes, ko.utils.domNodeIsAttachedToDocument);\n                    },\n\n                    tagNameLower: function(element) {\n                        // For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.\n                        // Possible future optimization: If we know it's an element from an XHTML document (not HTML),\n                        // we don't need to do the .toLowerCase() as it will always be lower case anyway.\n                        return element && element.tagName && element.tagName.toLowerCase();\n                    },\n\n                    catchFunctionErrors: function (delegate) {\n                        return ko['onError'] ? function () {\n                            try {\n                                return delegate.apply(this, arguments);\n                            } catch (e) {\n                                ko['onError'] && ko['onError'](e);\n                                throw e;\n                            }\n                        } : delegate;\n                    },\n\n                    setTimeout: function (handler, timeout) {\n                        return setTimeout(ko.utils.catchFunctionErrors(handler), timeout);\n                    },\n\n                    deferError: function (error) {\n                        setTimeout(function () {\n                            ko['onError'] && ko['onError'](error);\n                            throw error;\n                        }, 0);\n                    },\n\n                    registerEventHandler: function (element, eventType, handler) {\n                        var wrappedHandler = ko.utils.catchFunctionErrors(handler);\n\n                        var mustUseAttachEvent = eventsThatMustBeRegisteredUsingAttachEvent[eventType];\n                        if (!ko.options['useOnlyNativeEvents'] && !mustUseAttachEvent && jQueryInstance) {\n                            if (!jQueryEventAttachName) {\n                                jQueryEventAttachName = (typeof jQueryInstance(element)['on'] == 'function') ? 'on' : 'bind';\n                            }\n                            jQueryInstance(element)[jQueryEventAttachName](eventType, wrappedHandler);\n                        } else if (!mustUseAttachEvent && typeof element.addEventListener == \"function\")\n                            element.addEventListener(eventType, wrappedHandler, false);\n                        else if (typeof element.attachEvent != \"undefined\") {\n                            var attachEventHandler = function (event) { wrappedHandler.call(element, event); },\n                                attachEventName = \"on\" + eventType;\n                            element.attachEvent(attachEventName, attachEventHandler);\n\n                            // IE does not dispose attachEvent handlers automatically (unlike with addEventListener)\n                            // so to avoid leaks, we have to remove them manually. See bug #856\n                            ko.utils.domNodeDisposal.addDisposeCallback(element, function() {\n                                element.detachEvent(attachEventName, attachEventHandler);\n                            });\n                        } else\n                            throw new Error(\"Browser doesn't support addEventListener or attachEvent\");\n                    },\n\n                    triggerEvent: function (element, eventType) {\n                        if (!(element && element.nodeType))\n                            throw new Error(\"element must be a DOM node when calling triggerEvent\");\n\n                        // For click events on checkboxes and radio buttons, jQuery toggles the element checked state *after* the\n                        // event handler runs instead of *before*. (This was fixed in 1.9 for checkboxes but not for radio buttons.)\n                        // IE doesn't change the checked state when you trigger the click event using \"fireEvent\".\n                        // In both cases, we'll use the click method instead.\n                        var useClickWorkaround = isClickOnCheckableElement(element, eventType);\n\n                        if (!ko.options['useOnlyNativeEvents'] && jQueryInstance && !useClickWorkaround) {\n                            jQueryInstance(element)['trigger'](eventType);\n                        } else if (typeof document.createEvent == \"function\") {\n                            if (typeof element.dispatchEvent == \"function\") {\n                                var eventCategory = knownEventTypesByEventName[eventType] || \"HTMLEvents\";\n                                var event = document.createEvent(eventCategory);\n                                event.initEvent(eventType, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element);\n                                element.dispatchEvent(event);\n                            }\n                            else\n                                throw new Error(\"The supplied element doesn't support dispatchEvent\");\n                        } else if (useClickWorkaround && element.click) {\n                            element.click();\n                        } else if (typeof element.fireEvent != \"undefined\") {\n                            element.fireEvent(\"on\" + eventType);\n                        } else {\n                            throw new Error(\"Browser doesn't support triggering events\");\n                        }\n                    },\n\n                    unwrapObservable: function (value) {\n                        return ko.isObservable(value) ? value() : value;\n                    },\n\n                    peekObservable: function (value) {\n                        return ko.isObservable(value) ? value.peek() : value;\n                    },\n\n                    toggleDomNodeCssClass: toggleDomNodeCssClass,\n\n                    setTextContent: function(element, textContent) {\n                        var value = ko.utils.unwrapObservable(textContent);\n                        if ((value === null) || (value === undefined))\n                            value = \"\";\n\n                        // We need there to be exactly one child: a text node.\n                        // If there are no children, more than one, or if it's not a text node,\n                        // we'll clear everything and create a single text node.\n                        var innerTextNode = ko.virtualElements.firstChild(element);\n                        if (!innerTextNode || innerTextNode.nodeType != 3 || ko.virtualElements.nextSibling(innerTextNode)) {\n                            ko.virtualElements.setDomNodeChildren(element, [element.ownerDocument.createTextNode(value)]);\n                        } else {\n                            innerTextNode.data = value;\n                        }\n\n                        ko.utils.forceRefresh(element);\n                    },\n\n                    setElementName: function(element, name) {\n                        element.name = name;\n\n                        // Workaround IE 6/7 issue\n                        // - https://github.com/SteveSanderson/knockout/issues/197\n                        // - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/\n                        if (ieVersion <= 7) {\n                            try {\n                                var escapedName = element.name.replace(/[&<>'\"]/g, function(r){ return \"&#\" + r.charCodeAt(0) + \";\"; });\n                                element.mergeAttributes(document.createElement(\"<input name='\" + escapedName + \"'/>\"), false);\n                            }\n                            catch(e) {} // For IE9 with doc mode \"IE9 Standards\" and browser mode \"IE9 Compatibility View\"\n                        }\n                    },\n\n                    forceRefresh: function(node) {\n                        // Workaround for an IE9 rendering bug - https://github.com/SteveSanderson/knockout/issues/209\n                        if (ieVersion >= 9) {\n                            // For text nodes and comment nodes (most likely virtual elements), we will have to refresh the container\n                            var elem = node.nodeType == 1 ? node : node.parentNode;\n                            if (elem.style)\n                                elem.style.zoom = elem.style.zoom;\n                        }\n                    },\n\n                    ensureSelectElementIsRenderedCorrectly: function(selectElement) {\n                        // Workaround for IE9 rendering bug - it doesn't reliably display all the text in dynamically-added select boxes unless you force it to re-render by updating the width.\n                        // (See https://github.com/SteveSanderson/knockout/issues/312, http://stackoverflow.com/questions/5908494/select-only-shows-first-char-of-selected-option)\n                        // Also fixes IE7 and IE8 bug that causes selects to be zero width if enclosed by 'if' or 'with'. (See issue #839)\n                        if (ieVersion) {\n                            var originalWidth = selectElement.style.width;\n                            selectElement.style.width = 0;\n                            selectElement.style.width = originalWidth;\n                        }\n                    },\n\n                    range: function (min, max) {\n                        min = ko.utils.unwrapObservable(min);\n                        max = ko.utils.unwrapObservable(max);\n                        var result = [];\n                        for (var i = min; i <= max; i++)\n                            result.push(i);\n                        return result;\n                    },\n\n                    makeArray: function(arrayLikeObject) {\n                        var result = [];\n                        for (var i = 0, j = arrayLikeObject.length; i < j; i++) {\n                            result.push(arrayLikeObject[i]);\n                        };\n                        return result;\n                    },\n\n                    createSymbolOrString: function(identifier) {\n                        return canUseSymbols ? Symbol(identifier) : identifier;\n                    },\n\n                    isIe6 : isIe6,\n                    isIe7 : isIe7,\n                    ieVersion : ieVersion,\n\n                    getFormFields: function(form, fieldName) {\n                        var fields = ko.utils.makeArray(form.getElementsByTagName(\"input\")).concat(ko.utils.makeArray(form.getElementsByTagName(\"textarea\")));\n                        var isMatchingField = (typeof fieldName == 'string')\n                            ? function(field) { return field.name === fieldName }\n                            : function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate\n                        var matches = [];\n                        for (var i = fields.length - 1; i >= 0; i--) {\n                            if (isMatchingField(fields[i]))\n                                matches.push(fields[i]);\n                        };\n                        return matches;\n                    },\n\n                    parseJson: function (jsonString) {\n                        if (typeof jsonString == \"string\") {\n                            jsonString = ko.utils.stringTrim(jsonString);\n                            if (jsonString) {\n                                if (JSON && JSON.parse) // Use native parsing where available\n                                    return JSON.parse(jsonString);\n                                return (new Function(\"return \" + jsonString))(); // Fallback on less safe parsing for older browsers\n                            }\n                        }\n                        return null;\n                    },\n\n                    stringifyJson: function (data, replacer, space) {   // replacer and space are optional\n                        if (!JSON || !JSON.stringify)\n                            throw new Error(\"Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js\");\n                        return JSON.stringify(ko.utils.unwrapObservable(data), replacer, space);\n                    },\n\n                    postJson: function (urlOrForm, data, options) {\n                        options = options || {};\n                        var params = options['params'] || {};\n                        var includeFields = options['includeFields'] || this.fieldsIncludedWithJsonPost;\n                        var url = urlOrForm;\n\n                        // If we were given a form, use its 'action' URL and pick out any requested field values\n                        if((typeof urlOrForm == 'object') && (ko.utils.tagNameLower(urlOrForm) === \"form\")) {\n                            var originalForm = urlOrForm;\n                            url = originalForm.action;\n                            for (var i = includeFields.length - 1; i >= 0; i--) {\n                                var fields = ko.utils.getFormFields(originalForm, includeFields[i]);\n                                for (var j = fields.length - 1; j >= 0; j--)\n                                    params[fields[j].name] = fields[j].value;\n                            }\n                        }\n\n                        data = ko.utils.unwrapObservable(data);\n                        var form = document.createElement(\"form\");\n                        form.style.display = \"none\";\n                        form.action = url;\n                        form.method = \"post\";\n                        for (var key in data) {\n                            // Since 'data' this is a model object, we include all properties including those inherited from its prototype\n                            var input = document.createElement(\"input\");\n                            input.type = \"hidden\";\n                            input.name = key;\n                            input.value = ko.utils.stringifyJson(ko.utils.unwrapObservable(data[key]));\n                            form.appendChild(input);\n                        }\n                        objectForEach(params, function(key, value) {\n                            var input = document.createElement(\"input\");\n                            input.type = \"hidden\";\n                            input.name = key;\n                            input.value = value;\n                            form.appendChild(input);\n                        });\n                        document.body.appendChild(form);\n                        options['submitter'] ? options['submitter'](form) : form.submit();\n                        setTimeout(function () { form.parentNode.removeChild(form); }, 0);\n                    }\n                }\n            }());\n\n            ko.exportSymbol('utils', ko.utils);\n            ko.exportSymbol('utils.arrayForEach', ko.utils.arrayForEach);\n            ko.exportSymbol('utils.arrayFirst', ko.utils.arrayFirst);\n            ko.exportSymbol('utils.arrayFilter', ko.utils.arrayFilter);\n            ko.exportSymbol('utils.arrayGetDistinctValues', ko.utils.arrayGetDistinctValues);\n            ko.exportSymbol('utils.arrayIndexOf', ko.utils.arrayIndexOf);\n            ko.exportSymbol('utils.arrayMap', ko.utils.arrayMap);\n            ko.exportSymbol('utils.arrayPushAll', ko.utils.arrayPushAll);\n            ko.exportSymbol('utils.arrayRemoveItem', ko.utils.arrayRemoveItem);\n            ko.exportSymbol('utils.cloneNodes', ko.utils.cloneNodes);\n            ko.exportSymbol('utils.createSymbolOrString', ko.utils.createSymbolOrString);\n            ko.exportSymbol('utils.extend', ko.utils.extend);\n            ko.exportSymbol('utils.fieldsIncludedWithJsonPost', ko.utils.fieldsIncludedWithJsonPost);\n            ko.exportSymbol('utils.getFormFields', ko.utils.getFormFields);\n            ko.exportSymbol('utils.objectMap', ko.utils.objectMap);\n            ko.exportSymbol('utils.peekObservable', ko.utils.peekObservable);\n            ko.exportSymbol('utils.postJson', ko.utils.postJson);\n            ko.exportSymbol('utils.parseJson', ko.utils.parseJson);\n            ko.exportSymbol('utils.registerEventHandler', ko.utils.registerEventHandler);\n            ko.exportSymbol('utils.stringifyJson', ko.utils.stringifyJson);\n            ko.exportSymbol('utils.range', ko.utils.range);\n            ko.exportSymbol('utils.toggleDomNodeCssClass', ko.utils.toggleDomNodeCssClass);\n            ko.exportSymbol('utils.triggerEvent', ko.utils.triggerEvent);\n            ko.exportSymbol('utils.unwrapObservable', ko.utils.unwrapObservable);\n            ko.exportSymbol('utils.objectForEach', ko.utils.objectForEach);\n            ko.exportSymbol('utils.addOrRemoveItem', ko.utils.addOrRemoveItem);\n            ko.exportSymbol('utils.setTextContent', ko.utils.setTextContent);\n            ko.exportSymbol('unwrap', ko.utils.unwrapObservable); // Convenient shorthand, because this is used so commonly\n\n            if (!Function.prototype['bind']) {\n                // Function.prototype.bind is a standard part of ECMAScript 5th Edition (December 2009, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf)\n                // In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js\n                Function.prototype['bind'] = function (object) {\n                    var originalFunction = this;\n                    if (arguments.length === 1) {\n                        return function () {\n                            return originalFunction.apply(object, arguments);\n                        };\n                    } else {\n                        var partialArgs = Array.prototype.slice.call(arguments, 1);\n                        return function () {\n                            var args = partialArgs.slice(0);\n                            args.push.apply(args, arguments);\n                            return originalFunction.apply(object, args);\n                        };\n                    }\n                };\n            }\n\n            ko.utils.domData = new (function () {\n                var uniqueId = 0;\n                var dataStoreKeyExpandoPropertyName = \"__ko__\" + (new Date).getTime();\n                var dataStore = {};\n\n                var getDataForNode, clear;\n                if (!ko.utils.ieVersion) {\n                    // We considered using WeakMap, but it has a problem in IE 11 and Edge that prevents using\n                    // it cross-window, so instead we just store the data directly on the node.\n                    // See https://github.com/knockout/knockout/issues/2141\n                    getDataForNode = function (node, createIfNotFound) {\n                        var dataForNode = node[dataStoreKeyExpandoPropertyName];\n                        if (!dataForNode && createIfNotFound) {\n                            dataForNode = node[dataStoreKeyExpandoPropertyName] = {};\n                        }\n                        return dataForNode;\n                    };\n                    clear = function (node) {\n                        if (node[dataStoreKeyExpandoPropertyName]) {\n                            delete node[dataStoreKeyExpandoPropertyName];\n                            return true; // Exposing \"did clean\" flag purely so specs can infer whether things have been cleaned up as intended\n                        }\n                        return false;\n                    };\n                } else {\n                    // Old IE versions have memory issues if you store objects on the node, so we use a\n                    // separate data storage and link to it from the node using a string key.\n                    getDataForNode = function (node, createIfNotFound) {\n                        var dataStoreKey = node[dataStoreKeyExpandoPropertyName];\n                        var hasExistingDataStore = dataStoreKey && (dataStoreKey !== \"null\") && dataStore[dataStoreKey];\n                        if (!hasExistingDataStore) {\n                            if (!createIfNotFound)\n                                return undefined;\n                            dataStoreKey = node[dataStoreKeyExpandoPropertyName] = \"ko\" + uniqueId++;\n                            dataStore[dataStoreKey] = {};\n                        }\n                        return dataStore[dataStoreKey];\n                    };\n                    clear = function (node) {\n                        var dataStoreKey = node[dataStoreKeyExpandoPropertyName];\n                        if (dataStoreKey) {\n                            delete dataStore[dataStoreKey];\n                            node[dataStoreKeyExpandoPropertyName] = null;\n                            return true; // Exposing \"did clean\" flag purely so specs can infer whether things have been cleaned up as intended\n                        }\n                        return false;\n                    };\n                }\n\n                return {\n                    get: function (node, key) {\n                        var dataForNode = getDataForNode(node, false);\n                        return dataForNode && dataForNode[key];\n                    },\n                    set: function (node, key, value) {\n                        // Make sure we don't actually create a new domData key if we are actually deleting a value\n                        var dataForNode = getDataForNode(node, value !== undefined /* createIfNotFound */);\n                        dataForNode && (dataForNode[key] = value);\n                    },\n                    getOrSet: function (node, key, value) {\n                        var dataForNode = getDataForNode(node, true /* createIfNotFound */);\n                        return dataForNode[key] || (dataForNode[key] = value);\n                    },\n                    clear: clear,\n\n                    nextKey: function () {\n                        return (uniqueId++) + dataStoreKeyExpandoPropertyName;\n                    }\n                };\n            })();\n\n            ko.exportSymbol('utils.domData', ko.utils.domData);\n            ko.exportSymbol('utils.domData.clear', ko.utils.domData.clear); // Exporting only so specs can clear up after themselves fully\n\n            ko.utils.domNodeDisposal = new (function () {\n                var domDataKey = ko.utils.domData.nextKey();\n                var cleanableNodeTypes = { 1: true, 8: true, 9: true };       // Element, Comment, Document\n                var cleanableNodeTypesWithDescendants = { 1: true, 9: true }; // Element, Document\n\n                function getDisposeCallbacksCollection(node, createIfNotFound) {\n                    var allDisposeCallbacks = ko.utils.domData.get(node, domDataKey);\n                    if ((allDisposeCallbacks === undefined) && createIfNotFound) {\n                        allDisposeCallbacks = [];\n                        ko.utils.domData.set(node, domDataKey, allDisposeCallbacks);\n                    }\n                    return allDisposeCallbacks;\n                }\n                function destroyCallbacksCollection(node) {\n                    ko.utils.domData.set(node, domDataKey, undefined);\n                }\n\n                function cleanSingleNode(node) {\n                    // Run all the dispose callbacks\n                    var callbacks = getDisposeCallbacksCollection(node, false);\n                    if (callbacks) {\n                        callbacks = callbacks.slice(0); // Clone, as the array may be modified during iteration (typically, callbacks will remove themselves)\n                        for (var i = 0; i < callbacks.length; i++)\n                            callbacks[i](node);\n                    }\n\n                    // Erase the DOM data\n                    ko.utils.domData.clear(node);\n\n                    // Perform cleanup needed by external libraries (currently only jQuery, but can be extended)\n                    ko.utils.domNodeDisposal[\"cleanExternalData\"](node);\n\n                    // Clear any immediate-child comment nodes, as these wouldn't have been found by\n                    // node.getElementsByTagName(\"*\") in cleanNode() (comment nodes aren't elements)\n                    if (cleanableNodeTypesWithDescendants[node.nodeType]) {\n                        cleanNodesInList(node.childNodes, true/*onlyComments*/);\n                    }\n                }\n\n                function cleanNodesInList(nodeList, onlyComments) {\n                    var cleanedNodes = [], lastCleanedNode;\n                    for (var i = 0; i < nodeList.length; i++) {\n                        if (!onlyComments || nodeList[i].nodeType === 8) {\n                            cleanSingleNode(cleanedNodes[cleanedNodes.length] = lastCleanedNode = nodeList[i]);\n                            if (nodeList[i] !== lastCleanedNode) {\n                                while (i-- && ko.utils.arrayIndexOf(cleanedNodes, nodeList[i]) == -1) {}\n                            }\n                        }\n                    }\n                }\n\n                return {\n                    addDisposeCallback : function(node, callback) {\n                        if (typeof callback != \"function\")\n                            throw new Error(\"Callback must be a function\");\n                        getDisposeCallbacksCollection(node, true).push(callback);\n                    },\n\n                    removeDisposeCallback : function(node, callback) {\n                        var callbacksCollection = getDisposeCallbacksCollection(node, false);\n                        if (callbacksCollection) {\n                            ko.utils.arrayRemoveItem(callbacksCollection, callback);\n                            if (callbacksCollection.length == 0)\n                                destroyCallbacksCollection(node);\n                        }\n                    },\n\n                    cleanNode : function(node) {\n                        ko.dependencyDetection.ignore(function () {\n                            // First clean this node, where applicable\n                            if (cleanableNodeTypes[node.nodeType]) {\n                                cleanSingleNode(node);\n\n                                // ... then its descendants, where applicable\n                                if (cleanableNodeTypesWithDescendants[node.nodeType]) {\n                                    cleanNodesInList(node.getElementsByTagName(\"*\"));\n                                }\n                            }\n                        });\n\n                        return node;\n                    },\n\n                    removeNode : function(node) {\n                        ko.cleanNode(node);\n                        if (node.parentNode)\n                            node.parentNode.removeChild(node);\n                    },\n\n                    \"cleanExternalData\" : function (node) {\n                        // Special support for jQuery here because it's so commonly used.\n                        // Many jQuery plugins (including jquery.tmpl) store data using jQuery's equivalent of domData\n                        // so notify it to tear down any resources associated with the node & descendants here.\n                        if (jQueryInstance && (typeof jQueryInstance['cleanData'] == \"function\"))\n                            jQueryInstance['cleanData']([node]);\n                    }\n                };\n            })();\n            ko.cleanNode = ko.utils.domNodeDisposal.cleanNode; // Shorthand name for convenience\n            ko.removeNode = ko.utils.domNodeDisposal.removeNode; // Shorthand name for convenience\n            ko.exportSymbol('cleanNode', ko.cleanNode);\n            ko.exportSymbol('removeNode', ko.removeNode);\n            ko.exportSymbol('utils.domNodeDisposal', ko.utils.domNodeDisposal);\n            ko.exportSymbol('utils.domNodeDisposal.addDisposeCallback', ko.utils.domNodeDisposal.addDisposeCallback);\n            ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeDisposal.removeDisposeCallback);\n            (function () {\n                var none = [0, \"\", \"\"],\n                    table = [1, \"<table>\", \"</table>\"],\n                    tbody = [2, \"<table><tbody>\", \"</tbody></table>\"],\n                    tr = [3, \"<table><tbody><tr>\", \"</tr></tbody></table>\"],\n                    select = [1, \"<select multiple='multiple'>\", \"</select>\"],\n                    lookup = {\n                        'thead': table,\n                        'tbody': table,\n                        'tfoot': table,\n                        'tr': tbody,\n                        'td': tr,\n                        'th': tr,\n                        'option': select,\n                        'optgroup': select\n                    },\n\n                    // This is needed for old IE if you're *not* using either jQuery or innerShiv. Doesn't affect other cases.\n                    mayRequireCreateElementHack = ko.utils.ieVersion <= 8;\n\n                function getWrap(tags) {\n                    var m = tags.match(/^(?:<!--.*?-->\\s*?)*?<([a-z]+)[\\s>]/);\n                    return (m && lookup[m[1]]) || none;\n                }\n\n                function simpleHtmlParse(html, documentContext) {\n                    documentContext || (documentContext = document);\n                    var windowContext = documentContext['parentWindow'] || documentContext['defaultView'] || window;\n\n                    // Based on jQuery's \"clean\" function, but only accounting for table-related elements.\n                    // If you have referenced jQuery, this won't be used anyway - KO will use jQuery's \"clean\" function directly\n\n                    // Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of\n                    // a descendant node. For example: \"<div><!-- mycomment -->abc</div>\" will get parsed as \"<div>abc</div>\"\n                    // This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node\n                    // (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.\n\n                    // Trim whitespace, otherwise indexOf won't work as expected\n                    var tags = ko.utils.stringTrim(html).toLowerCase(), div = documentContext.createElement(\"div\"),\n                        wrap = getWrap(tags),\n                        depth = wrap[0];\n\n                    // Go to html and back, then peel off extra wrappers\n                    // Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.\n                    var markup = \"ignored<div>\" + wrap[1] + html + wrap[2] + \"</div>\";\n                    if (typeof windowContext['innerShiv'] == \"function\") {\n                        // Note that innerShiv is deprecated in favour of html5shiv. We should consider adding\n                        // support for html5shiv (except if no explicit support is needed, e.g., if html5shiv\n                        // somehow shims the native APIs so it just works anyway)\n                        div.appendChild(windowContext['innerShiv'](markup));\n                    } else {\n                        if (mayRequireCreateElementHack) {\n                            // The document.createElement('my-element') trick to enable custom elements in IE6-8\n                            // only works if we assign innerHTML on an element associated with that document.\n                            documentContext.body.appendChild(div);\n                        }\n\n                        div.innerHTML = markup;\n\n                        if (mayRequireCreateElementHack) {\n                            div.parentNode.removeChild(div);\n                        }\n                    }\n\n                    // Move to the right depth\n                    while (depth--)\n                        div = div.lastChild;\n\n                    return ko.utils.makeArray(div.lastChild.childNodes);\n                }\n\n                function jQueryHtmlParse(html, documentContext) {\n                    // jQuery's \"parseHTML\" function was introduced in jQuery 1.8.0 and is a documented public API.\n                    if (jQueryInstance['parseHTML']) {\n                        return jQueryInstance['parseHTML'](html, documentContext) || []; // Ensure we always return an array and never null\n                    } else {\n                        // For jQuery < 1.8.0, we fall back on the undocumented internal \"clean\" function.\n                        var elems = jQueryInstance['clean']([html], documentContext);\n\n                        // As of jQuery 1.7.1, jQuery parses the HTML by appending it to some dummy parent nodes held in an in-memory document fragment.\n                        // Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.\n                        // Fix this by finding the top-most dummy parent element, and detaching it from its owner fragment.\n                        if (elems && elems[0]) {\n                            // Find the top-most parent element that's a direct child of a document fragment\n                            var elem = elems[0];\n                            while (elem.parentNode && elem.parentNode.nodeType !== 11 /* i.e., DocumentFragment */)\n                                elem = elem.parentNode;\n                            // ... then detach it\n                            if (elem.parentNode)\n                                elem.parentNode.removeChild(elem);\n                        }\n\n                        return elems;\n                    }\n                }\n\n                ko.utils.parseHtmlFragment = function(html, documentContext) {\n                    return jQueryInstance ?\n                        jQueryHtmlParse(html, documentContext) :   // As below, benefit from jQuery's optimisations where possible\n                        simpleHtmlParse(html, documentContext);  // ... otherwise, this simple logic will do in most common cases.\n                };\n\n                ko.utils.parseHtmlForTemplateNodes = function(html, documentContext) {\n                    var nodes = ko.utils.parseHtmlFragment(html, documentContext);\n                    return (nodes.length && nodes[0].parentElement) || ko.utils.moveCleanedNodesToContainerElement(nodes);\n                };\n\n                ko.utils.setHtml = function(node, html) {\n                    ko.utils.emptyDomNode(node);\n\n                    // There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it\n                    html = ko.utils.unwrapObservable(html);\n\n                    if ((html !== null) && (html !== undefined)) {\n                        if (typeof html != 'string')\n                            html = html.toString();\n\n                        // jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,\n                        // for example <tr> elements which are not normally allowed to exist on their own.\n                        // If you've referenced jQuery we'll use that rather than duplicating its code.\n                        if (jQueryInstance) {\n                            jQueryInstance(node)['html'](html);\n                        } else {\n                            // ... otherwise, use KO's own parsing logic.\n                            var parsedNodes = ko.utils.parseHtmlFragment(html, node.ownerDocument);\n                            for (var i = 0; i < parsedNodes.length; i++)\n                                node.appendChild(parsedNodes[i]);\n                        }\n                    }\n                };\n            })();\n\n            ko.exportSymbol('utils.parseHtmlFragment', ko.utils.parseHtmlFragment);\n            ko.exportSymbol('utils.setHtml', ko.utils.setHtml);\n\n            ko.memoization = (function () {\n                var memos = {};\n\n                function randomMax8HexChars() {\n                    return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);\n                }\n                function generateRandomId() {\n                    return randomMax8HexChars() + randomMax8HexChars();\n                }\n                function findMemoNodes(rootNode, appendToArray) {\n                    if (!rootNode)\n                        return;\n                    if (rootNode.nodeType == 8) {\n                        var memoId = ko.memoization.parseMemoText(rootNode.nodeValue);\n                        if (memoId != null)\n                            appendToArray.push({ domNode: rootNode, memoId: memoId });\n                    } else if (rootNode.nodeType == 1) {\n                        for (var i = 0, childNodes = rootNode.childNodes, j = childNodes.length; i < j; i++)\n                            findMemoNodes(childNodes[i], appendToArray);\n                    }\n                }\n\n                return {\n                    memoize: function (callback) {\n                        if (typeof callback != \"function\")\n                            throw new Error(\"You can only pass a function to ko.memoization.memoize()\");\n                        var memoId = generateRandomId();\n                        memos[memoId] = callback;\n                        return \"<!--[ko_memo:\" + memoId + \"]-->\";\n                    },\n\n                    unmemoize: function (memoId, callbackParams) {\n                        var callback = memos[memoId];\n                        if (callback === undefined)\n                            throw new Error(\"Couldn't find any memo with ID \" + memoId + \". Perhaps it's already been unmemoized.\");\n                        try {\n                            callback.apply(null, callbackParams || []);\n                            return true;\n                        }\n                        finally { delete memos[memoId]; }\n                    },\n\n                    unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {\n                        var memos = [];\n                        findMemoNodes(domNode, memos);\n                        for (var i = 0, j = memos.length; i < j; i++) {\n                            var node = memos[i].domNode;\n                            var combinedParams = [node];\n                            if (extraCallbackParamsArray)\n                                ko.utils.arrayPushAll(combinedParams, extraCallbackParamsArray);\n                            ko.memoization.unmemoize(memos[i].memoId, combinedParams);\n                            node.nodeValue = \"\"; // Neuter this node so we don't try to unmemoize it again\n                            if (node.parentNode)\n                                node.parentNode.removeChild(node); // If possible, erase it totally (not always possible - someone else might just hold a reference to it then call unmemoizeDomNodeAndDescendants again)\n                        }\n                    },\n\n                    parseMemoText: function (memoText) {\n                        var match = memoText.match(/^\\[ko_memo\\:(.*?)\\]$/);\n                        return match ? match[1] : null;\n                    }\n                };\n            })();\n\n            ko.exportSymbol('memoization', ko.memoization);\n            ko.exportSymbol('memoization.memoize', ko.memoization.memoize);\n            ko.exportSymbol('memoization.unmemoize', ko.memoization.unmemoize);\n            ko.exportSymbol('memoization.parseMemoText', ko.memoization.parseMemoText);\n            ko.exportSymbol('memoization.unmemoizeDomNodeAndDescendants', ko.memoization.unmemoizeDomNodeAndDescendants);\n            ko.tasks = (function () {\n                var scheduler,\n                    taskQueue = [],\n                    taskQueueLength = 0,\n                    nextHandle = 1,\n                    nextIndexToProcess = 0;\n\n                if (window['MutationObserver']) {\n                    // Chrome 27+, Firefox 14+, IE 11+, Opera 15+, Safari 6.1+\n                    // From https://github.com/petkaantonov/bluebird * Copyright (c) 2014 Petka Antonov * License: MIT\n                    scheduler = (function (callback) {\n                        var div = document.createElement(\"div\");\n                        new MutationObserver(callback).observe(div, {attributes: true});\n                        return function () { div.classList.toggle(\"foo\"); };\n                    })(scheduledProcess);\n                } else if (document && \"onreadystatechange\" in document.createElement(\"script\")) {\n                    // IE 6-10\n                    // From https://github.com/YuzuJS/setImmediate * Copyright (c) 2012 Barnesandnoble.com, llc, Donavon West, and Domenic Denicola * License: MIT\n                    scheduler = function (callback) {\n                        var script = document.createElement(\"script\");\n                        script.onreadystatechange = function () {\n                            script.onreadystatechange = null;\n                            document.documentElement.removeChild(script);\n                            script = null;\n                            callback();\n                        };\n                        document.documentElement.appendChild(script);\n                    };\n                } else {\n                    scheduler = function (callback) {\n                        setTimeout(callback, 0);\n                    };\n                }\n\n                function processTasks() {\n                    if (taskQueueLength) {\n                        // Each mark represents the end of a logical group of tasks and the number of these groups is\n                        // limited to prevent unchecked recursion.\n                        var mark = taskQueueLength, countMarks = 0;\n\n                        // nextIndexToProcess keeps track of where we are in the queue; processTasks can be called recursively without issue\n                        for (var task; nextIndexToProcess < taskQueueLength; ) {\n                            if (task = taskQueue[nextIndexToProcess++]) {\n                                if (nextIndexToProcess > mark) {\n                                    if (++countMarks >= 5000) {\n                                        nextIndexToProcess = taskQueueLength;   // skip all tasks remaining in the queue since any of them could be causing the recursion\n                                        ko.utils.deferError(Error(\"'Too much recursion' after processing \" + countMarks + \" task groups.\"));\n                                        break;\n                                    }\n                                    mark = taskQueueLength;\n                                }\n                                try {\n                                    task();\n                                } catch (ex) {\n                                    ko.utils.deferError(ex);\n                                }\n                            }\n                        }\n                    }\n                }\n\n                function scheduledProcess() {\n                    processTasks();\n\n                    // Reset the queue\n                    nextIndexToProcess = taskQueueLength = taskQueue.length = 0;\n                }\n\n                function scheduleTaskProcessing() {\n                    ko.tasks['scheduler'](scheduledProcess);\n                }\n\n                var tasks = {\n                    'scheduler': scheduler,     // Allow overriding the scheduler\n\n                    schedule: function (func) {\n                        if (!taskQueueLength) {\n                            scheduleTaskProcessing();\n                        }\n\n                        taskQueue[taskQueueLength++] = func;\n                        return nextHandle++;\n                    },\n\n                    cancel: function (handle) {\n                        var index = handle - (nextHandle - taskQueueLength);\n                        if (index >= nextIndexToProcess && index < taskQueueLength) {\n                            taskQueue[index] = null;\n                        }\n                    },\n\n                    // For testing only: reset the queue and return the previous queue length\n                    'resetForTesting': function () {\n                        var length = taskQueueLength - nextIndexToProcess;\n                        nextIndexToProcess = taskQueueLength = taskQueue.length = 0;\n                        return length;\n                    },\n\n                    runEarly: processTasks\n                };\n\n                return tasks;\n            })();\n\n            ko.exportSymbol('tasks', ko.tasks);\n            ko.exportSymbol('tasks.schedule', ko.tasks.schedule);\n//ko.exportSymbol('tasks.cancel', ko.tasks.cancel);  \"cancel\" isn't minified\n            ko.exportSymbol('tasks.runEarly', ko.tasks.runEarly);\n            ko.extenders = {\n                'throttle': function(target, timeout) {\n                    // Throttling means two things:\n\n                    // (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies\n                    //     notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate\n                    target['throttleEvaluation'] = timeout;\n\n                    // (2) For writable targets (observables, or writable dependent observables), we throttle *writes*\n                    //     so the target cannot change value synchronously or faster than a certain rate\n                    var writeTimeoutInstance = null;\n                    return ko.dependentObservable({\n                        'read': target,\n                        'write': function(value) {\n                            clearTimeout(writeTimeoutInstance);\n                            writeTimeoutInstance = ko.utils.setTimeout(function() {\n                                target(value);\n                            }, timeout);\n                        }\n                    });\n                },\n\n                'rateLimit': function(target, options) {\n                    var timeout, method, limitFunction;\n\n                    if (typeof options == 'number') {\n                        timeout = options;\n                    } else {\n                        timeout = options['timeout'];\n                        method = options['method'];\n                    }\n\n                    // rateLimit supersedes deferred updates\n                    target._deferUpdates = false;\n\n                    limitFunction = typeof method == 'function' ? method : method == 'notifyWhenChangesStop' ?  debounce : throttle;\n                    target.limit(function(callback) {\n                        return limitFunction(callback, timeout, options);\n                    });\n                },\n\n                'deferred': function(target, options) {\n                    if (options !== true) {\n                        throw new Error('The \\'deferred\\' extender only accepts the value \\'true\\', because it is not supported to turn deferral off once enabled.')\n                    }\n\n                    if (!target._deferUpdates) {\n                        target._deferUpdates = true;\n                        target.limit(function (callback) {\n                            var handle,\n                                ignoreUpdates = false;\n                            return function () {\n                                if (!ignoreUpdates) {\n                                    ko.tasks.cancel(handle);\n                                    handle = ko.tasks.schedule(callback);\n\n                                    try {\n                                        ignoreUpdates = true;\n                                        target['notifySubscribers'](undefined, 'dirty');\n                                    } finally {\n                                        ignoreUpdates = false;\n                                    }\n                                }\n                            };\n                        });\n                    }\n                },\n\n                'notify': function(target, notifyWhen) {\n                    target[\"equalityComparer\"] = notifyWhen == \"always\" ?\n                        null :  // null equalityComparer means to always notify\n                        valuesArePrimitiveAndEqual;\n                }\n            };\n\n            var primitiveTypes = { 'undefined':1, 'boolean':1, 'number':1, 'string':1 };\n            function valuesArePrimitiveAndEqual(a, b) {\n                var oldValueIsPrimitive = (a === null) || (typeof(a) in primitiveTypes);\n                return oldValueIsPrimitive ? (a === b) : false;\n            }\n\n            function throttle(callback, timeout) {\n                var timeoutInstance;\n                return function () {\n                    if (!timeoutInstance) {\n                        timeoutInstance = ko.utils.setTimeout(function () {\n                            timeoutInstance = undefined;\n                            callback();\n                        }, timeout);\n                    }\n                };\n            }\n\n            function debounce(callback, timeout) {\n                var timeoutInstance;\n                return function () {\n                    clearTimeout(timeoutInstance);\n                    timeoutInstance = ko.utils.setTimeout(callback, timeout);\n                };\n            }\n\n            function applyExtenders(requestedExtenders) {\n                var target = this;\n                if (requestedExtenders) {\n                    ko.utils.objectForEach(requestedExtenders, function(key, value) {\n                        var extenderHandler = ko.extenders[key];\n                        if (typeof extenderHandler == 'function') {\n                            target = extenderHandler(target, value) || target;\n                        }\n                    });\n                }\n                return target;\n            }\n\n            ko.exportSymbol('extenders', ko.extenders);\n\n            ko.subscription = function (target, callback, disposeCallback) {\n                this._target = target;\n                this._callback = callback;\n                this._disposeCallback = disposeCallback;\n                this._isDisposed = false;\n                this._node = null;\n                this._domNodeDisposalCallback = null;\n                ko.exportProperty(this, 'dispose', this.dispose);\n                ko.exportProperty(this, 'disposeWhenNodeIsRemoved', this.disposeWhenNodeIsRemoved);\n            };\n            ko.subscription.prototype.dispose = function () {\n                var self = this;\n                if (!self._isDisposed) {\n                    if (self._domNodeDisposalCallback) {\n                        ko.utils.domNodeDisposal.removeDisposeCallback(self._node, self._domNodeDisposalCallback);\n                    }\n                    self._isDisposed = true;\n                    self._disposeCallback();\n\n                    self._target = self._callback = self._disposeCallback = self._node = self._domNodeDisposalCallback = null;\n                }\n            };\n            ko.subscription.prototype.disposeWhenNodeIsRemoved = function (node) {\n                this._node = node;\n                ko.utils.domNodeDisposal.addDisposeCallback(node, this._domNodeDisposalCallback = this.dispose.bind(this));\n            };\n\n            ko.subscribable = function () {\n                ko.utils.setPrototypeOfOrExtend(this, ko_subscribable_fn);\n                ko_subscribable_fn.init(this);\n            }\n\n            var defaultEvent = \"change\";\n\n// Moved out of \"limit\" to avoid the extra closure\n            function limitNotifySubscribers(value, event) {\n                if (!event || event === defaultEvent) {\n                    this._limitChange(value);\n                } else if (event === 'beforeChange') {\n                    this._limitBeforeChange(value);\n                } else {\n                    this._origNotifySubscribers(value, event);\n                }\n            }\n\n            var ko_subscribable_fn = {\n                init: function(instance) {\n                    instance._subscriptions = { \"change\": [] };\n                    instance._versionNumber = 1;\n                },\n\n                subscribe: function (callback, callbackTarget, event) {\n                    var self = this;\n\n                    event = event || defaultEvent;\n                    var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;\n\n                    var subscription = new ko.subscription(self, boundCallback, function () {\n                        ko.utils.arrayRemoveItem(self._subscriptions[event], subscription);\n                        if (self.afterSubscriptionRemove)\n                            self.afterSubscriptionRemove(event);\n                    });\n\n                    if (self.beforeSubscriptionAdd)\n                        self.beforeSubscriptionAdd(event);\n\n                    if (!self._subscriptions[event])\n                        self._subscriptions[event] = [];\n                    self._subscriptions[event].push(subscription);\n\n                    return subscription;\n                },\n\n                \"notifySubscribers\": function (valueToNotify, event) {\n                    event = event || defaultEvent;\n                    if (event === defaultEvent) {\n                        this.updateVersion();\n                    }\n                    if (this.hasSubscriptionsForEvent(event)) {\n                        var subs = event === defaultEvent && this._changeSubscriptions || this._subscriptions[event].slice(0);\n                        try {\n                            ko.dependencyDetection.begin(); // Begin suppressing dependency detection (by setting the top frame to undefined)\n                            for (var i = 0, subscription; subscription = subs[i]; ++i) {\n                                // In case a subscription was disposed during the arrayForEach cycle, check\n                                // for isDisposed on each subscription before invoking its callback\n                                if (!subscription._isDisposed)\n                                    subscription._callback(valueToNotify);\n                            }\n                        } finally {\n                            ko.dependencyDetection.end(); // End suppressing dependency detection\n                        }\n                    }\n                },\n\n                getVersion: function () {\n                    return this._versionNumber;\n                },\n\n                hasChanged: function (versionToCheck) {\n                    return this.getVersion() !== versionToCheck;\n                },\n\n                updateVersion: function () {\n                    ++this._versionNumber;\n                },\n\n                limit: function(limitFunction) {\n                    var self = this, selfIsObservable = ko.isObservable(self),\n                        ignoreBeforeChange, notifyNextChange, previousValue, pendingValue, didUpdate,\n                        beforeChange = 'beforeChange';\n\n                    if (!self._origNotifySubscribers) {\n                        self._origNotifySubscribers = self[\"notifySubscribers\"];\n                        self[\"notifySubscribers\"] = limitNotifySubscribers;\n                    }\n\n                    var finish = limitFunction(function() {\n                        self._notificationIsPending = false;\n\n                        // If an observable provided a reference to itself, access it to get the latest value.\n                        // This allows computed observables to delay calculating their value until needed.\n                        if (selfIsObservable && pendingValue === self) {\n                            pendingValue = self._evalIfChanged ? self._evalIfChanged() : self();\n                        }\n                        var shouldNotify = notifyNextChange || (didUpdate && self.isDifferent(previousValue, pendingValue));\n\n                        didUpdate = notifyNextChange = ignoreBeforeChange = false;\n\n                        if (shouldNotify) {\n                            self._origNotifySubscribers(previousValue = pendingValue);\n                        }\n                    });\n\n                    self._limitChange = function(value, isDirty) {\n                        if (!isDirty || !self._notificationIsPending) {\n                            didUpdate = !isDirty;\n                        }\n                        self._changeSubscriptions = self._subscriptions[defaultEvent].slice(0);\n                        self._notificationIsPending = ignoreBeforeChange = true;\n                        pendingValue = value;\n                        finish();\n                    };\n                    self._limitBeforeChange = function(value) {\n                        if (!ignoreBeforeChange) {\n                            previousValue = value;\n                            self._origNotifySubscribers(value, beforeChange);\n                        }\n                    };\n                    self._recordUpdate = function() {\n                        didUpdate = true;\n                    };\n                    self._notifyNextChangeIfValueIsDifferent = function() {\n                        if (self.isDifferent(previousValue, self.peek(true /*evaluate*/))) {\n                            notifyNextChange = true;\n                        }\n                    };\n                },\n\n                hasSubscriptionsForEvent: function(event) {\n                    return this._subscriptions[event] && this._subscriptions[event].length;\n                },\n\n                getSubscriptionsCount: function (event) {\n                    if (event) {\n                        return this._subscriptions[event] && this._subscriptions[event].length || 0;\n                    } else {\n                        var total = 0;\n                        ko.utils.objectForEach(this._subscriptions, function(eventName, subscriptions) {\n                            if (eventName !== 'dirty')\n                                total += subscriptions.length;\n                        });\n                        return total;\n                    }\n                },\n\n                isDifferent: function(oldValue, newValue) {\n                    return !this['equalityComparer'] || !this['equalityComparer'](oldValue, newValue);\n                },\n\n                toString: function() {\n                    return '[object Object]'\n                },\n\n                extend: applyExtenders\n            };\n\n            ko.exportProperty(ko_subscribable_fn, 'init', ko_subscribable_fn.init);\n            ko.exportProperty(ko_subscribable_fn, 'subscribe', ko_subscribable_fn.subscribe);\n            ko.exportProperty(ko_subscribable_fn, 'extend', ko_subscribable_fn.extend);\n            ko.exportProperty(ko_subscribable_fn, 'getSubscriptionsCount', ko_subscribable_fn.getSubscriptionsCount);\n\n// For browsers that support proto assignment, we overwrite the prototype of each\n// observable instance. Since observables are functions, we need Function.prototype\n// to still be in the prototype chain.\n            if (ko.utils.canSetPrototype) {\n                ko.utils.setPrototypeOf(ko_subscribable_fn, Function.prototype);\n            }\n\n            ko.subscribable['fn'] = ko_subscribable_fn;\n\n\n            ko.isSubscribable = function (instance) {\n                return instance != null && typeof instance.subscribe == \"function\" && typeof instance[\"notifySubscribers\"] == \"function\";\n            };\n\n            ko.exportSymbol('subscribable', ko.subscribable);\n            ko.exportSymbol('isSubscribable', ko.isSubscribable);\n\n            ko.computedContext = ko.dependencyDetection = (function () {\n                var outerFrames = [],\n                    currentFrame,\n                    lastId = 0;\n\n                // Return a unique ID that can be assigned to an observable for dependency tracking.\n                // Theoretically, you could eventually overflow the number storage size, resulting\n                // in duplicate IDs. But in JavaScript, the largest exact integral value is 2^53\n                // or 9,007,199,254,740,992. If you created 1,000,000 IDs per second, it would\n                // take over 285 years to reach that number.\n                // Reference http://blog.vjeux.com/2010/javascript/javascript-max_int-number-limits.html\n                function getId() {\n                    return ++lastId;\n                }\n\n                function begin(options) {\n                    outerFrames.push(currentFrame);\n                    currentFrame = options;\n                }\n\n                function end() {\n                    currentFrame = outerFrames.pop();\n                }\n\n                return {\n                    begin: begin,\n\n                    end: end,\n\n                    registerDependency: function (subscribable) {\n                        if (currentFrame) {\n                            if (!ko.isSubscribable(subscribable))\n                                throw new Error(\"Only subscribable things can act as dependencies\");\n                            currentFrame.callback.call(currentFrame.callbackTarget, subscribable, subscribable._id || (subscribable._id = getId()));\n                        }\n                    },\n\n                    ignore: function (callback, callbackTarget, callbackArgs) {\n                        try {\n                            begin();\n                            return callback.apply(callbackTarget, callbackArgs || []);\n                        } finally {\n                            end();\n                        }\n                    },\n\n                    getDependenciesCount: function () {\n                        if (currentFrame)\n                            return currentFrame.computed.getDependenciesCount();\n                    },\n\n                    getDependencies: function () {\n                        if (currentFrame)\n                            return currentFrame.computed.getDependencies();\n                    },\n\n                    isInitial: function() {\n                        if (currentFrame)\n                            return currentFrame.isInitial;\n                    },\n\n                    computed: function() {\n                        if (currentFrame)\n                            return currentFrame.computed;\n                    }\n                };\n            })();\n\n            ko.exportSymbol('computedContext', ko.computedContext);\n            ko.exportSymbol('computedContext.getDependenciesCount', ko.computedContext.getDependenciesCount);\n            ko.exportSymbol('computedContext.getDependencies', ko.computedContext.getDependencies);\n            ko.exportSymbol('computedContext.isInitial', ko.computedContext.isInitial);\n            ko.exportSymbol('computedContext.registerDependency', ko.computedContext.registerDependency);\n\n            ko.exportSymbol('ignoreDependencies', ko.ignoreDependencies = ko.dependencyDetection.ignore);\n            var observableLatestValue = ko.utils.createSymbolOrString('_latestValue');\n\n            ko.observable = function (initialValue) {\n                function observable() {\n                    if (arguments.length > 0) {\n                        // Write\n\n                        // Ignore writes if the value hasn't changed\n                        if (observable.isDifferent(observable[observableLatestValue], arguments[0])) {\n                            observable.valueWillMutate();\n                            observable[observableLatestValue] = arguments[0];\n                            observable.valueHasMutated();\n                        }\n                        return this; // Permits chained assignments\n                    }\n                    else {\n                        // Read\n                        ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a \"read\" operation\n                        return observable[observableLatestValue];\n                    }\n                }\n\n                observable[observableLatestValue] = initialValue;\n\n                // Inherit from 'subscribable'\n                if (!ko.utils.canSetPrototype) {\n                    // 'subscribable' won't be on the prototype chain unless we put it there directly\n                    ko.utils.extend(observable, ko.subscribable['fn']);\n                }\n                ko.subscribable['fn'].init(observable);\n\n                // Inherit from 'observable'\n                ko.utils.setPrototypeOfOrExtend(observable, observableFn);\n\n                if (ko.options['deferUpdates']) {\n                    ko.extenders['deferred'](observable, true);\n                }\n\n                return observable;\n            }\n\n// Define prototype for observables\n            var observableFn = {\n                'equalityComparer': valuesArePrimitiveAndEqual,\n                peek: function() { return this[observableLatestValue]; },\n                valueHasMutated: function () {\n                    this['notifySubscribers'](this[observableLatestValue], 'spectate');\n                    this['notifySubscribers'](this[observableLatestValue]);\n                },\n                valueWillMutate: function () { this['notifySubscribers'](this[observableLatestValue], 'beforeChange'); }\n            };\n\n// Note that for browsers that don't support proto assignment, the\n// inheritance chain is created manually in the ko.observable constructor\n            if (ko.utils.canSetPrototype) {\n                ko.utils.setPrototypeOf(observableFn, ko.subscribable['fn']);\n            }\n\n            var protoProperty = ko.observable.protoProperty = '__ko_proto__';\n            observableFn[protoProperty] = ko.observable;\n\n            ko.isObservable = function (instance) {\n                var proto = typeof instance == 'function' && instance[protoProperty];\n                if (proto && proto !== observableFn[protoProperty] && proto !== ko.computed['fn'][protoProperty]) {\n                    throw Error(\"Invalid object that looks like an observable; possibly from another Knockout instance\");\n                }\n                return !!proto;\n            };\n\n            ko.isWriteableObservable = function (instance) {\n                return (typeof instance == 'function' && (\n                    (instance[protoProperty] === observableFn[protoProperty]) ||  // Observable\n                    (instance[protoProperty] === ko.computed['fn'][protoProperty] && instance.hasWriteFunction)));   // Writable computed observable\n            };\n\n            ko.exportSymbol('observable', ko.observable);\n            ko.exportSymbol('isObservable', ko.isObservable);\n            ko.exportSymbol('isWriteableObservable', ko.isWriteableObservable);\n            ko.exportSymbol('isWritableObservable', ko.isWriteableObservable);\n            ko.exportSymbol('observable.fn', observableFn);\n            ko.exportProperty(observableFn, 'peek', observableFn.peek);\n            ko.exportProperty(observableFn, 'valueHasMutated', observableFn.valueHasMutated);\n            ko.exportProperty(observableFn, 'valueWillMutate', observableFn.valueWillMutate);\n            ko.observableArray = function (initialValues) {\n                initialValues = initialValues || [];\n\n                if (typeof initialValues != 'object' || !('length' in initialValues))\n                    throw new Error(\"The argument passed when initializing an observable array must be an array, or null, or undefined.\");\n\n                var result = ko.observable(initialValues);\n                ko.utils.setPrototypeOfOrExtend(result, ko.observableArray['fn']);\n                return result.extend({'trackArrayChanges':true});\n            };\n\n            ko.observableArray['fn'] = {\n                'remove': function (valueOrPredicate) {\n                    var underlyingArray = this.peek();\n                    var removedValues = [];\n                    var predicate = typeof valueOrPredicate == \"function\" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };\n                    for (var i = 0; i < underlyingArray.length; i++) {\n                        var value = underlyingArray[i];\n                        if (predicate(value)) {\n                            if (removedValues.length === 0) {\n                                this.valueWillMutate();\n                            }\n                            if (underlyingArray[i] !== value) {\n                                throw Error(\"Array modified during remove; cannot remove item\");\n                            }\n                            removedValues.push(value);\n                            underlyingArray.splice(i, 1);\n                            i--;\n                        }\n                    }\n                    if (removedValues.length) {\n                        this.valueHasMutated();\n                    }\n                    return removedValues;\n                },\n\n                'removeAll': function (arrayOfValues) {\n                    // If you passed zero args, we remove everything\n                    if (arrayOfValues === undefined) {\n                        var underlyingArray = this.peek();\n                        var allValues = underlyingArray.slice(0);\n                        this.valueWillMutate();\n                        underlyingArray.splice(0, underlyingArray.length);\n                        this.valueHasMutated();\n                        return allValues;\n                    }\n                    // If you passed an arg, we interpret it as an array of entries to remove\n                    if (!arrayOfValues)\n                        return [];\n                    return this['remove'](function (value) {\n                        return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;\n                    });\n                },\n\n                'destroy': function (valueOrPredicate) {\n                    var underlyingArray = this.peek();\n                    var predicate = typeof valueOrPredicate == \"function\" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };\n                    this.valueWillMutate();\n                    for (var i = underlyingArray.length - 1; i >= 0; i--) {\n                        var value = underlyingArray[i];\n                        if (predicate(value))\n                            value[\"_destroy\"] = true;\n                    }\n                    this.valueHasMutated();\n                },\n\n                'destroyAll': function (arrayOfValues) {\n                    // If you passed zero args, we destroy everything\n                    if (arrayOfValues === undefined)\n                        return this['destroy'](function() { return true });\n\n                    // If you passed an arg, we interpret it as an array of entries to destroy\n                    if (!arrayOfValues)\n                        return [];\n                    return this['destroy'](function (value) {\n                        return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;\n                    });\n                },\n\n                'indexOf': function (item) {\n                    var underlyingArray = this();\n                    return ko.utils.arrayIndexOf(underlyingArray, item);\n                },\n\n                'replace': function(oldItem, newItem) {\n                    var index = this['indexOf'](oldItem);\n                    if (index >= 0) {\n                        this.valueWillMutate();\n                        this.peek()[index] = newItem;\n                        this.valueHasMutated();\n                    }\n                },\n\n                'sorted': function (compareFunction) {\n                    var arrayCopy = this().slice(0);\n                    return compareFunction ? arrayCopy.sort(compareFunction) : arrayCopy.sort();\n                },\n\n                'reversed': function () {\n                    return this().slice(0).reverse();\n                }\n            };\n\n// Note that for browsers that don't support proto assignment, the\n// inheritance chain is created manually in the ko.observableArray constructor\n            if (ko.utils.canSetPrototype) {\n                ko.utils.setPrototypeOf(ko.observableArray['fn'], ko.observable['fn']);\n            }\n\n// Populate ko.observableArray.fn with read/write functions from native arrays\n// Important: Do not add any additional functions here that may reasonably be used to *read* data from the array\n// because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale\n            ko.utils.arrayForEach([\"pop\", \"push\", \"reverse\", \"shift\", \"sort\", \"splice\", \"unshift\"], function (methodName) {\n                ko.observableArray['fn'][methodName] = function () {\n                    // Use \"peek\" to avoid creating a subscription in any computed that we're executing in the context of\n                    // (for consistency with mutating regular observables)\n                    var underlyingArray = this.peek();\n                    this.valueWillMutate();\n                    this.cacheDiffForKnownOperation(underlyingArray, methodName, arguments);\n                    var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);\n                    this.valueHasMutated();\n                    // The native sort and reverse methods return a reference to the array, but it makes more sense to return the observable array instead.\n                    return methodCallResult === underlyingArray ? this : methodCallResult;\n                };\n            });\n\n// Populate ko.observableArray.fn with read-only functions from native arrays\n            ko.utils.arrayForEach([\"slice\"], function (methodName) {\n                ko.observableArray['fn'][methodName] = function () {\n                    var underlyingArray = this();\n                    return underlyingArray[methodName].apply(underlyingArray, arguments);\n                };\n            });\n\n            ko.isObservableArray = function (instance) {\n                return ko.isObservable(instance)\n                    && typeof instance[\"remove\"] == \"function\"\n                    && typeof instance[\"push\"] == \"function\";\n            };\n\n            ko.exportSymbol('observableArray', ko.observableArray);\n            ko.exportSymbol('isObservableArray', ko.isObservableArray);\n            var arrayChangeEventName = 'arrayChange';\n            ko.extenders['trackArrayChanges'] = function(target, options) {\n                // Use the provided options--each call to trackArrayChanges overwrites the previously set options\n                target.compareArrayOptions = {};\n                if (options && typeof options == \"object\") {\n                    ko.utils.extend(target.compareArrayOptions, options);\n                }\n                target.compareArrayOptions['sparse'] = true;\n\n                // Only modify the target observable once\n                if (target.cacheDiffForKnownOperation) {\n                    return;\n                }\n                var trackingChanges = false,\n                    cachedDiff = null,\n                    changeSubscription,\n                    spectateSubscription,\n                    pendingChanges = 0,\n                    previousContents,\n                    underlyingBeforeSubscriptionAddFunction = target.beforeSubscriptionAdd,\n                    underlyingAfterSubscriptionRemoveFunction = target.afterSubscriptionRemove;\n\n                // Watch \"subscribe\" calls, and for array change events, ensure change tracking is enabled\n                target.beforeSubscriptionAdd = function (event) {\n                    if (underlyingBeforeSubscriptionAddFunction) {\n                        underlyingBeforeSubscriptionAddFunction.call(target, event);\n                    }\n                    if (event === arrayChangeEventName) {\n                        trackChanges();\n                    }\n                };\n                // Watch \"dispose\" calls, and for array change events, ensure change tracking is disabled when all are disposed\n                target.afterSubscriptionRemove = function (event) {\n                    if (underlyingAfterSubscriptionRemoveFunction) {\n                        underlyingAfterSubscriptionRemoveFunction.call(target, event);\n                    }\n                    if (event === arrayChangeEventName && !target.hasSubscriptionsForEvent(arrayChangeEventName)) {\n                        if (changeSubscription) {\n                            changeSubscription.dispose();\n                        }\n                        if (spectateSubscription) {\n                            spectateSubscription.dispose();\n                        }\n                        spectateSubscription = changeSubscription = null;\n                        trackingChanges = false;\n                        previousContents = undefined;\n                    }\n                };\n\n                function trackChanges() {\n                    if (trackingChanges) {\n                        // Whenever there's a new subscription and there are pending notifications, make sure all previous\n                        // subscriptions are notified of the change so that all subscriptions are in sync.\n                        notifyChanges();\n                        return;\n                    }\n\n                    trackingChanges = true;\n\n                    // Track how many times the array actually changed value\n                    spectateSubscription = target.subscribe(function () {\n                        ++pendingChanges;\n                    }, null, \"spectate\");\n\n                    // Each time the array changes value, capture a clone so that on the next\n                    // change it's possible to produce a diff\n                    previousContents = [].concat(target.peek() || []);\n                    cachedDiff = null;\n                    changeSubscription = target.subscribe(notifyChanges);\n\n                    function notifyChanges() {\n                        if (pendingChanges) {\n                            // Make a copy of the current contents and ensure it's an array\n                            var currentContents = [].concat(target.peek() || []), changes;\n\n                            // Compute the diff and issue notifications, but only if someone is listening\n                            if (target.hasSubscriptionsForEvent(arrayChangeEventName)) {\n                                changes = getChanges(previousContents, currentContents);\n                            }\n\n                            // Eliminate references to the old, removed items, so they can be GCed\n                            previousContents = currentContents;\n                            cachedDiff = null;\n                            pendingChanges = 0;\n\n                            if (changes && changes.length) {\n                                target['notifySubscribers'](changes, arrayChangeEventName);\n                            }\n                        }\n                    }\n                }\n\n                function getChanges(previousContents, currentContents) {\n                    // We try to re-use cached diffs.\n                    // The scenarios where pendingChanges > 1 are when using rate limiting or deferred updates,\n                    // which without this check would not be compatible with arrayChange notifications. Normally,\n                    // notifications are issued immediately so we wouldn't be queueing up more than one.\n                    if (!cachedDiff || pendingChanges > 1) {\n                        cachedDiff = ko.utils.compareArrays(previousContents, currentContents, target.compareArrayOptions);\n                    }\n\n                    return cachedDiff;\n                }\n\n                target.cacheDiffForKnownOperation = function(rawArray, operationName, args) {\n                    // Only run if we're currently tracking changes for this observable array\n                    // and there aren't any pending deferred notifications.\n                    if (!trackingChanges || pendingChanges) {\n                        return;\n                    }\n                    var diff = [],\n                        arrayLength = rawArray.length,\n                        argsLength = args.length,\n                        offset = 0;\n\n                    function pushDiff(status, value, index) {\n                        return diff[diff.length] = { 'status': status, 'value': value, 'index': index };\n                    }\n                    switch (operationName) {\n                        case 'push':\n                            offset = arrayLength;\n                        case 'unshift':\n                            for (var index = 0; index < argsLength; index++) {\n                                pushDiff('added', args[index], offset + index);\n                            }\n                            break;\n\n                        case 'pop':\n                            offset = arrayLength - 1;\n                        case 'shift':\n                            if (arrayLength) {\n                                pushDiff('deleted', rawArray[offset], offset);\n                            }\n                            break;\n\n                        case 'splice':\n                            // Negative start index means 'from end of array'. After that we clamp to [0...arrayLength].\n                            // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice\n                            var startIndex = Math.min(Math.max(0, args[0] < 0 ? arrayLength + args[0] : args[0]), arrayLength),\n                                endDeleteIndex = argsLength === 1 ? arrayLength : Math.min(startIndex + (args[1] || 0), arrayLength),\n                                endAddIndex = startIndex + argsLength - 2,\n                                endIndex = Math.max(endDeleteIndex, endAddIndex),\n                                additions = [], deletions = [];\n                            for (var index = startIndex, argsIndex = 2; index < endIndex; ++index, ++argsIndex) {\n                                if (index < endDeleteIndex)\n                                    deletions.push(pushDiff('deleted', rawArray[index], index));\n                                if (index < endAddIndex)\n                                    additions.push(pushDiff('added', args[argsIndex], index));\n                            }\n                            ko.utils.findMovesInArrayComparison(deletions, additions);\n                            break;\n\n                        default:\n                            return;\n                    }\n                    cachedDiff = diff;\n                };\n            };\n            var computedState = ko.utils.createSymbolOrString('_state');\n\n            ko.computed = ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) {\n                if (typeof evaluatorFunctionOrOptions === \"object\") {\n                    // Single-parameter syntax - everything is on this \"options\" param\n                    options = evaluatorFunctionOrOptions;\n                } else {\n                    // Multi-parameter syntax - construct the options according to the params passed\n                    options = options || {};\n                    if (evaluatorFunctionOrOptions) {\n                        options[\"read\"] = evaluatorFunctionOrOptions;\n                    }\n                }\n                if (typeof options[\"read\"] != \"function\")\n                    throw Error(\"Pass a function that returns the value of the ko.computed\");\n\n                var writeFunction = options[\"write\"];\n                var state = {\n                    latestValue: undefined,\n                    isStale: true,\n                    isDirty: true,\n                    isBeingEvaluated: false,\n                    suppressDisposalUntilDisposeWhenReturnsFalse: false,\n                    isDisposed: false,\n                    pure: false,\n                    isSleeping: false,\n                    readFunction: options[\"read\"],\n                    evaluatorFunctionTarget: evaluatorFunctionTarget || options[\"owner\"],\n                    disposeWhenNodeIsRemoved: options[\"disposeWhenNodeIsRemoved\"] || options.disposeWhenNodeIsRemoved || null,\n                    disposeWhen: options[\"disposeWhen\"] || options.disposeWhen,\n                    domNodeDisposalCallback: null,\n                    dependencyTracking: {},\n                    dependenciesCount: 0,\n                    evaluationTimeoutInstance: null\n                };\n\n                function computedObservable() {\n                    if (arguments.length > 0) {\n                        if (typeof writeFunction === \"function\") {\n                            // Writing a value\n                            writeFunction.apply(state.evaluatorFunctionTarget, arguments);\n                        } else {\n                            throw new Error(\"Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.\");\n                        }\n                        return this; // Permits chained assignments\n                    } else {\n                        // Reading the value\n                        if (!state.isDisposed) {\n                            ko.dependencyDetection.registerDependency(computedObservable);\n                        }\n                        if (state.isDirty || (state.isSleeping && computedObservable.haveDependenciesChanged())) {\n                            computedObservable.evaluateImmediate();\n                        }\n                        return state.latestValue;\n                    }\n                }\n\n                computedObservable[computedState] = state;\n                computedObservable.hasWriteFunction = typeof writeFunction === \"function\";\n\n                // Inherit from 'subscribable'\n                if (!ko.utils.canSetPrototype) {\n                    // 'subscribable' won't be on the prototype chain unless we put it there directly\n                    ko.utils.extend(computedObservable, ko.subscribable['fn']);\n                }\n                ko.subscribable['fn'].init(computedObservable);\n\n                // Inherit from 'computed'\n                ko.utils.setPrototypeOfOrExtend(computedObservable, computedFn);\n\n                if (options['pure']) {\n                    state.pure = true;\n                    state.isSleeping = true;     // Starts off sleeping; will awake on the first subscription\n                    ko.utils.extend(computedObservable, pureComputedOverrides);\n                } else if (options['deferEvaluation']) {\n                    ko.utils.extend(computedObservable, deferEvaluationOverrides);\n                }\n\n                if (ko.options['deferUpdates']) {\n                    ko.extenders['deferred'](computedObservable, true);\n                }\n\n                if (DEBUG) {\n                    // #1731 - Aid debugging by exposing the computed's options\n                    computedObservable[\"_options\"] = options;\n                }\n\n                if (state.disposeWhenNodeIsRemoved) {\n                    // Since this computed is associated with a DOM node, and we don't want to dispose the computed\n                    // until the DOM node is *removed* from the document (as opposed to never having been in the document),\n                    // we'll prevent disposal until \"disposeWhen\" first returns false.\n                    state.suppressDisposalUntilDisposeWhenReturnsFalse = true;\n\n                    // disposeWhenNodeIsRemoved: true can be used to opt into the \"only dispose after first false result\"\n                    // behaviour even if there's no specific node to watch. In that case, clear the option so we don't try\n                    // to watch for a non-node's disposal. This technique is intended for KO's internal use only and shouldn't\n                    // be documented or used by application code, as it's likely to change in a future version of KO.\n                    if (!state.disposeWhenNodeIsRemoved.nodeType) {\n                        state.disposeWhenNodeIsRemoved = null;\n                    }\n                }\n\n                // Evaluate, unless sleeping or deferEvaluation is true\n                if (!state.isSleeping && !options['deferEvaluation']) {\n                    computedObservable.evaluateImmediate();\n                }\n\n                // Attach a DOM node disposal callback so that the computed will be proactively disposed as soon as the node is\n                // removed using ko.removeNode. But skip if isActive is false (there will never be any dependencies to dispose).\n                if (state.disposeWhenNodeIsRemoved && computedObservable.isActive()) {\n                    ko.utils.domNodeDisposal.addDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback = function () {\n                        computedObservable.dispose();\n                    });\n                }\n\n                return computedObservable;\n            };\n\n// Utility function that disposes a given dependencyTracking entry\n            function computedDisposeDependencyCallback(id, entryToDispose) {\n                if (entryToDispose !== null && entryToDispose.dispose) {\n                    entryToDispose.dispose();\n                }\n            }\n\n// This function gets called each time a dependency is detected while evaluating a computed.\n// It's factored out as a shared function to avoid creating unnecessary function instances during evaluation.\n            function computedBeginDependencyDetectionCallback(subscribable, id) {\n                var computedObservable = this.computedObservable,\n                    state = computedObservable[computedState];\n                if (!state.isDisposed) {\n                    if (this.disposalCount && this.disposalCandidates[id]) {\n                        // Don't want to dispose this subscription, as it's still being used\n                        computedObservable.addDependencyTracking(id, subscribable, this.disposalCandidates[id]);\n                        this.disposalCandidates[id] = null; // No need to actually delete the property - disposalCandidates is a transient object anyway\n                        --this.disposalCount;\n                    } else if (!state.dependencyTracking[id]) {\n                        // Brand new subscription - add it\n                        computedObservable.addDependencyTracking(id, subscribable, state.isSleeping ? { _target: subscribable } : computedObservable.subscribeToDependency(subscribable));\n                    }\n                    // If the observable we've accessed has a pending notification, ensure we get notified of the actual final value (bypass equality checks)\n                    if (subscribable._notificationIsPending) {\n                        subscribable._notifyNextChangeIfValueIsDifferent();\n                    }\n                }\n            }\n\n            var computedFn = {\n                \"equalityComparer\": valuesArePrimitiveAndEqual,\n                getDependenciesCount: function () {\n                    return this[computedState].dependenciesCount;\n                },\n                getDependencies: function () {\n                    var dependencyTracking = this[computedState].dependencyTracking, dependentObservables = [];\n\n                    ko.utils.objectForEach(dependencyTracking, function (id, dependency) {\n                        dependentObservables[dependency._order] = dependency._target;\n                    });\n\n                    return dependentObservables;\n                },\n                hasAncestorDependency: function (obs) {\n                    if (!this[computedState].dependenciesCount) {\n                        return false;\n                    }\n                    var dependencies = this.getDependencies();\n                    if (ko.utils.arrayIndexOf(dependencies, obs) !== -1) {\n                        return true;\n                    }\n                    return !!ko.utils.arrayFirst(dependencies, function (dep) {\n                        return dep.hasAncestorDependency && dep.hasAncestorDependency(obs);\n                    });\n                },\n                addDependencyTracking: function (id, target, trackingObj) {\n                    if (this[computedState].pure && target === this) {\n                        throw Error(\"A 'pure' computed must not be called recursively\");\n                    }\n\n                    this[computedState].dependencyTracking[id] = trackingObj;\n                    trackingObj._order = this[computedState].dependenciesCount++;\n                    trackingObj._version = target.getVersion();\n                },\n                haveDependenciesChanged: function () {\n                    var id, dependency, dependencyTracking = this[computedState].dependencyTracking;\n                    for (id in dependencyTracking) {\n                        if (Object.prototype.hasOwnProperty.call(dependencyTracking, id)) {\n                            dependency = dependencyTracking[id];\n                            if ((this._evalDelayed && dependency._target._notificationIsPending) || dependency._target.hasChanged(dependency._version)) {\n                                return true;\n                            }\n                        }\n                    }\n                },\n                markDirty: function () {\n                    // Process \"dirty\" events if we can handle delayed notifications\n                    if (this._evalDelayed && !this[computedState].isBeingEvaluated) {\n                        this._evalDelayed(false /*isChange*/);\n                    }\n                },\n                isActive: function () {\n                    var state = this[computedState];\n                    return state.isDirty || state.dependenciesCount > 0;\n                },\n                respondToChange: function () {\n                    // Ignore \"change\" events if we've already scheduled a delayed notification\n                    if (!this._notificationIsPending) {\n                        this.evaluatePossiblyAsync();\n                    } else if (this[computedState].isDirty) {\n                        this[computedState].isStale = true;\n                    }\n                },\n                subscribeToDependency: function (target) {\n                    if (target._deferUpdates) {\n                        var dirtySub = target.subscribe(this.markDirty, this, 'dirty'),\n                            changeSub = target.subscribe(this.respondToChange, this);\n                        return {\n                            _target: target,\n                            dispose: function () {\n                                dirtySub.dispose();\n                                changeSub.dispose();\n                            }\n                        };\n                    } else {\n                        return target.subscribe(this.evaluatePossiblyAsync, this);\n                    }\n                },\n                evaluatePossiblyAsync: function () {\n                    var computedObservable = this,\n                        throttleEvaluationTimeout = computedObservable['throttleEvaluation'];\n                    if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {\n                        clearTimeout(this[computedState].evaluationTimeoutInstance);\n                        this[computedState].evaluationTimeoutInstance = ko.utils.setTimeout(function () {\n                            computedObservable.evaluateImmediate(true /*notifyChange*/);\n                        }, throttleEvaluationTimeout);\n                    } else if (computedObservable._evalDelayed) {\n                        computedObservable._evalDelayed(true /*isChange*/);\n                    } else {\n                        computedObservable.evaluateImmediate(true /*notifyChange*/);\n                    }\n                },\n                evaluateImmediate: function (notifyChange) {\n                    var computedObservable = this,\n                        state = computedObservable[computedState],\n                        disposeWhen = state.disposeWhen,\n                        changed = false;\n\n                    if (state.isBeingEvaluated) {\n                        // If the evaluation of a ko.computed causes side effects, it's possible that it will trigger its own re-evaluation.\n                        // This is not desirable (it's hard for a developer to realise a chain of dependencies might cause this, and they almost\n                        // certainly didn't intend infinite re-evaluations). So, for predictability, we simply prevent ko.computeds from causing\n                        // their own re-evaluation. Further discussion at https://github.com/SteveSanderson/knockout/pull/387\n                        return;\n                    }\n\n                    // Do not evaluate (and possibly capture new dependencies) if disposed\n                    if (state.isDisposed) {\n                        return;\n                    }\n\n                    if (state.disposeWhenNodeIsRemoved && !ko.utils.domNodeIsAttachedToDocument(state.disposeWhenNodeIsRemoved) || disposeWhen && disposeWhen()) {\n                        // See comment above about suppressDisposalUntilDisposeWhenReturnsFalse\n                        if (!state.suppressDisposalUntilDisposeWhenReturnsFalse) {\n                            computedObservable.dispose();\n                            return;\n                        }\n                    } else {\n                        // It just did return false, so we can stop suppressing now\n                        state.suppressDisposalUntilDisposeWhenReturnsFalse = false;\n                    }\n\n                    state.isBeingEvaluated = true;\n                    try {\n                        changed = this.evaluateImmediate_CallReadWithDependencyDetection(notifyChange);\n                    } finally {\n                        state.isBeingEvaluated = false;\n                    }\n\n                    return changed;\n                },\n                evaluateImmediate_CallReadWithDependencyDetection: function (notifyChange) {\n                    // This function is really just part of the evaluateImmediate logic. You would never call it from anywhere else.\n                    // Factoring it out into a separate function means it can be independent of the try/catch block in evaluateImmediate,\n                    // which contributes to saving about 40% off the CPU overhead of computed evaluation (on V8 at least).\n\n                    var computedObservable = this,\n                        state = computedObservable[computedState],\n                        changed = false;\n\n                    // Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).\n                    // Then, during evaluation, we cross off any that are in fact still being used.\n                    var isInitial = state.pure ? undefined : !state.dependenciesCount,   // If we're evaluating when there are no previous dependencies, it must be the first time\n                        dependencyDetectionContext = {\n                            computedObservable: computedObservable,\n                            disposalCandidates: state.dependencyTracking,\n                            disposalCount: state.dependenciesCount\n                        };\n\n                    ko.dependencyDetection.begin({\n                        callbackTarget: dependencyDetectionContext,\n                        callback: computedBeginDependencyDetectionCallback,\n                        computed: computedObservable,\n                        isInitial: isInitial\n                    });\n\n                    state.dependencyTracking = {};\n                    state.dependenciesCount = 0;\n\n                    var newValue = this.evaluateImmediate_CallReadThenEndDependencyDetection(state, dependencyDetectionContext);\n\n                    if (!state.dependenciesCount) {\n                        computedObservable.dispose();\n                        changed = true; // When evaluation causes a disposal, make sure all dependent computeds get notified so they'll see the new state\n                    } else {\n                        changed = computedObservable.isDifferent(state.latestValue, newValue);\n                    }\n\n                    if (changed) {\n                        if (!state.isSleeping) {\n                            computedObservable[\"notifySubscribers\"](state.latestValue, \"beforeChange\");\n                        } else {\n                            computedObservable.updateVersion();\n                        }\n\n                        state.latestValue = newValue;\n                        if (DEBUG) computedObservable._latestValue = newValue;\n\n                        computedObservable[\"notifySubscribers\"](state.latestValue, \"spectate\");\n\n                        if (!state.isSleeping && notifyChange) {\n                            computedObservable[\"notifySubscribers\"](state.latestValue);\n                        }\n                        if (computedObservable._recordUpdate) {\n                            computedObservable._recordUpdate();\n                        }\n                    }\n\n                    if (isInitial) {\n                        computedObservable[\"notifySubscribers\"](state.latestValue, \"awake\");\n                    }\n\n                    return changed;\n                },\n                evaluateImmediate_CallReadThenEndDependencyDetection: function (state, dependencyDetectionContext) {\n                    // This function is really part of the evaluateImmediate_CallReadWithDependencyDetection logic.\n                    // You'd never call it from anywhere else. Factoring it out means that evaluateImmediate_CallReadWithDependencyDetection\n                    // can be independent of try/finally blocks, which contributes to saving about 40% off the CPU\n                    // overhead of computed evaluation (on V8 at least).\n\n                    try {\n                        var readFunction = state.readFunction;\n                        return state.evaluatorFunctionTarget ? readFunction.call(state.evaluatorFunctionTarget) : readFunction();\n                    } finally {\n                        ko.dependencyDetection.end();\n\n                        // For each subscription no longer being used, remove it from the active subscriptions list and dispose it\n                        if (dependencyDetectionContext.disposalCount && !state.isSleeping) {\n                            ko.utils.objectForEach(dependencyDetectionContext.disposalCandidates, computedDisposeDependencyCallback);\n                        }\n\n                        state.isStale = state.isDirty = false;\n                    }\n                },\n                peek: function (evaluate) {\n                    // By default, peek won't re-evaluate, except while the computed is sleeping or to get the initial value when \"deferEvaluation\" is set.\n                    // Pass in true to evaluate if needed.\n                    var state = this[computedState];\n                    if ((state.isDirty && (evaluate || !state.dependenciesCount)) || (state.isSleeping && this.haveDependenciesChanged())) {\n                        this.evaluateImmediate();\n                    }\n                    return state.latestValue;\n                },\n                limit: function (limitFunction) {\n                    // Override the limit function with one that delays evaluation as well\n                    ko.subscribable['fn'].limit.call(this, limitFunction);\n                    this._evalIfChanged = function () {\n                        if (!this[computedState].isSleeping) {\n                            if (this[computedState].isStale) {\n                                this.evaluateImmediate();\n                            } else {\n                                this[computedState].isDirty = false;\n                            }\n                        }\n                        return this[computedState].latestValue;\n                    };\n                    this._evalDelayed = function (isChange) {\n                        this._limitBeforeChange(this[computedState].latestValue);\n\n                        // Mark as dirty\n                        this[computedState].isDirty = true;\n                        if (isChange) {\n                            this[computedState].isStale = true;\n                        }\n\n                        // Pass the observable to the \"limit\" code, which will evaluate it when\n                        // it's time to do the notification.\n                        this._limitChange(this, !isChange /* isDirty */);\n                    };\n                },\n                dispose: function () {\n                    var state = this[computedState];\n                    if (!state.isSleeping && state.dependencyTracking) {\n                        ko.utils.objectForEach(state.dependencyTracking, function (id, dependency) {\n                            if (dependency.dispose)\n                                dependency.dispose();\n                        });\n                    }\n                    if (state.disposeWhenNodeIsRemoved && state.domNodeDisposalCallback) {\n                        ko.utils.domNodeDisposal.removeDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback);\n                    }\n                    state.dependencyTracking = undefined;\n                    state.dependenciesCount = 0;\n                    state.isDisposed = true;\n                    state.isStale = false;\n                    state.isDirty = false;\n                    state.isSleeping = false;\n                    state.disposeWhenNodeIsRemoved = undefined;\n                    state.disposeWhen = undefined;\n                    state.readFunction = undefined;\n                    if (!this.hasWriteFunction) {\n                        state.evaluatorFunctionTarget = undefined;\n                    }\n                }\n            };\n\n            var pureComputedOverrides = {\n                beforeSubscriptionAdd: function (event) {\n                    // If asleep, wake up the computed by subscribing to any dependencies.\n                    var computedObservable = this,\n                        state = computedObservable[computedState];\n                    if (!state.isDisposed && state.isSleeping && event == 'change') {\n                        state.isSleeping = false;\n                        if (state.isStale || computedObservable.haveDependenciesChanged()) {\n                            state.dependencyTracking = null;\n                            state.dependenciesCount = 0;\n                            if (computedObservable.evaluateImmediate()) {\n                                computedObservable.updateVersion();\n                            }\n                        } else {\n                            // First put the dependencies in order\n                            var dependenciesOrder = [];\n                            ko.utils.objectForEach(state.dependencyTracking, function (id, dependency) {\n                                dependenciesOrder[dependency._order] = id;\n                            });\n                            // Next, subscribe to each one\n                            ko.utils.arrayForEach(dependenciesOrder, function (id, order) {\n                                var dependency = state.dependencyTracking[id],\n                                    subscription = computedObservable.subscribeToDependency(dependency._target);\n                                subscription._order = order;\n                                subscription._version = dependency._version;\n                                state.dependencyTracking[id] = subscription;\n                            });\n                            // Waking dependencies may have triggered effects\n                            if (computedObservable.haveDependenciesChanged()) {\n                                if (computedObservable.evaluateImmediate()) {\n                                    computedObservable.updateVersion();\n                                }\n                            }\n                        }\n\n                        if (!state.isDisposed) {     // test since evaluating could trigger disposal\n                            computedObservable[\"notifySubscribers\"](state.latestValue, \"awake\");\n                        }\n                    }\n                },\n                afterSubscriptionRemove: function (event) {\n                    var state = this[computedState];\n                    if (!state.isDisposed && event == 'change' && !this.hasSubscriptionsForEvent('change')) {\n                        ko.utils.objectForEach(state.dependencyTracking, function (id, dependency) {\n                            if (dependency.dispose) {\n                                state.dependencyTracking[id] = {\n                                    _target: dependency._target,\n                                    _order: dependency._order,\n                                    _version: dependency._version\n                                };\n                                dependency.dispose();\n                            }\n                        });\n                        state.isSleeping = true;\n                        this[\"notifySubscribers\"](undefined, \"asleep\");\n                    }\n                },\n                getVersion: function () {\n                    // Because a pure computed is not automatically updated while it is sleeping, we can't\n                    // simply return the version number. Instead, we check if any of the dependencies have\n                    // changed and conditionally re-evaluate the computed observable.\n                    var state = this[computedState];\n                    if (state.isSleeping && (state.isStale || this.haveDependenciesChanged())) {\n                        this.evaluateImmediate();\n                    }\n                    return ko.subscribable['fn'].getVersion.call(this);\n                }\n            };\n\n            var deferEvaluationOverrides = {\n                beforeSubscriptionAdd: function (event) {\n                    // This will force a computed with deferEvaluation to evaluate when the first subscription is registered.\n                    if (event == 'change' || event == 'beforeChange') {\n                        this.peek();\n                    }\n                }\n            };\n\n// Note that for browsers that don't support proto assignment, the\n// inheritance chain is created manually in the ko.computed constructor\n            if (ko.utils.canSetPrototype) {\n                ko.utils.setPrototypeOf(computedFn, ko.subscribable['fn']);\n            }\n\n// Set the proto values for ko.computed\n            var protoProp = ko.observable.protoProperty; // == \"__ko_proto__\"\n            computedFn[protoProp] = ko.computed;\n\n            ko.isComputed = function (instance) {\n                return (typeof instance == 'function' && instance[protoProp] === computedFn[protoProp]);\n            };\n\n            ko.isPureComputed = function (instance) {\n                return ko.isComputed(instance) && instance[computedState] && instance[computedState].pure;\n            };\n\n            ko.exportSymbol('computed', ko.computed);\n            ko.exportSymbol('dependentObservable', ko.computed);    // export ko.dependentObservable for backwards compatibility (1.x)\n            ko.exportSymbol('isComputed', ko.isComputed);\n            ko.exportSymbol('isPureComputed', ko.isPureComputed);\n            ko.exportSymbol('computed.fn', computedFn);\n            ko.exportProperty(computedFn, 'peek', computedFn.peek);\n            ko.exportProperty(computedFn, 'dispose', computedFn.dispose);\n            ko.exportProperty(computedFn, 'isActive', computedFn.isActive);\n            ko.exportProperty(computedFn, 'getDependenciesCount', computedFn.getDependenciesCount);\n            ko.exportProperty(computedFn, 'getDependencies', computedFn.getDependencies);\n\n            ko.pureComputed = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget) {\n                if (typeof evaluatorFunctionOrOptions === 'function') {\n                    return ko.computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget, {'pure':true});\n                } else {\n                    evaluatorFunctionOrOptions = ko.utils.extend({}, evaluatorFunctionOrOptions);   // make a copy of the parameter object\n                    evaluatorFunctionOrOptions['pure'] = true;\n                    return ko.computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget);\n                }\n            }\n            ko.exportSymbol('pureComputed', ko.pureComputed);\n\n            (function() {\n                var maxNestedObservableDepth = 10; // Escape the (unlikely) pathological case where an observable's current value is itself (or similar reference cycle)\n\n                ko.toJS = function(rootObject) {\n                    if (arguments.length == 0)\n                        throw new Error(\"When calling ko.toJS, pass the object you want to convert.\");\n\n                    // We just unwrap everything at every level in the object graph\n                    return mapJsObjectGraph(rootObject, function(valueToMap) {\n                        // Loop because an observable's value might in turn be another observable wrapper\n                        for (var i = 0; ko.isObservable(valueToMap) && (i < maxNestedObservableDepth); i++)\n                            valueToMap = valueToMap();\n                        return valueToMap;\n                    });\n                };\n\n                ko.toJSON = function(rootObject, replacer, space) {     // replacer and space are optional\n                    var plainJavaScriptObject = ko.toJS(rootObject);\n                    return ko.utils.stringifyJson(plainJavaScriptObject, replacer, space);\n                };\n\n                function mapJsObjectGraph(rootObject, mapInputCallback, visitedObjects) {\n                    visitedObjects = visitedObjects || new objectLookup();\n\n                    rootObject = mapInputCallback(rootObject);\n                    var canHaveProperties = (typeof rootObject == \"object\") && (rootObject !== null) && (rootObject !== undefined) && (!(rootObject instanceof RegExp)) && (!(rootObject instanceof Date)) && (!(rootObject instanceof String)) && (!(rootObject instanceof Number)) && (!(rootObject instanceof Boolean));\n                    if (!canHaveProperties)\n                        return rootObject;\n\n                    var outputProperties = rootObject instanceof Array ? [] : {};\n                    visitedObjects.save(rootObject, outputProperties);\n\n                    visitPropertiesOrArrayEntries(rootObject, function(indexer) {\n                        var propertyValue = mapInputCallback(rootObject[indexer]);\n\n                        switch (typeof propertyValue) {\n                            case \"boolean\":\n                            case \"number\":\n                            case \"string\":\n                            case \"function\":\n                                outputProperties[indexer] = propertyValue;\n                                break;\n                            case \"object\":\n                            case \"undefined\":\n                                var previouslyMappedValue = visitedObjects.get(propertyValue);\n                                outputProperties[indexer] = (previouslyMappedValue !== undefined)\n                                    ? previouslyMappedValue\n                                    : mapJsObjectGraph(propertyValue, mapInputCallback, visitedObjects);\n                                break;\n                        }\n                    });\n\n                    return outputProperties;\n                }\n\n                function visitPropertiesOrArrayEntries(rootObject, visitorCallback) {\n                    if (rootObject instanceof Array) {\n                        for (var i = 0; i < rootObject.length; i++)\n                            visitorCallback(i);\n\n                        // For arrays, also respect toJSON property for custom mappings (fixes #278)\n                        if (typeof rootObject['toJSON'] == 'function')\n                            visitorCallback('toJSON');\n                    } else {\n                        for (var propertyName in rootObject) {\n                            visitorCallback(propertyName);\n                        }\n                    }\n                };\n\n                function objectLookup() {\n                    this.keys = [];\n                    this.values = [];\n                };\n\n                objectLookup.prototype = {\n                    constructor: objectLookup,\n                    save: function(key, value) {\n                        var existingIndex = ko.utils.arrayIndexOf(this.keys, key);\n                        if (existingIndex >= 0)\n                            this.values[existingIndex] = value;\n                        else {\n                            this.keys.push(key);\n                            this.values.push(value);\n                        }\n                    },\n                    get: function(key) {\n                        var existingIndex = ko.utils.arrayIndexOf(this.keys, key);\n                        return (existingIndex >= 0) ? this.values[existingIndex] : undefined;\n                    }\n                };\n            })();\n\n            ko.exportSymbol('toJS', ko.toJS);\n            ko.exportSymbol('toJSON', ko.toJSON);\n            ko.when = function(predicate, callback, context) {\n                function kowhen (resolve) {\n                    var observable = ko.pureComputed(predicate, context).extend({notify:'always'});\n                    var subscription = observable.subscribe(function(value) {\n                        if (value) {\n                            subscription.dispose();\n                            resolve(value);\n                        }\n                    });\n                    // In case the initial value is true, process it right away\n                    observable['notifySubscribers'](observable.peek());\n\n                    return subscription;\n                }\n                if (typeof Promise === \"function\" && !callback) {\n                    return new Promise(kowhen);\n                } else {\n                    return kowhen(callback.bind(context));\n                }\n            };\n\n            ko.exportSymbol('when', ko.when);\n            (function () {\n                var hasDomDataExpandoProperty = '__ko__hasDomDataOptionValue__';\n\n                // Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values\n                // are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values\n                // that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.\n                ko.selectExtensions = {\n                    readValue : function(element) {\n                        switch (ko.utils.tagNameLower(element)) {\n                            case 'option':\n                                if (element[hasDomDataExpandoProperty] === true)\n                                    return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);\n                                return ko.utils.ieVersion <= 7\n                                    ? (element.getAttributeNode('value') && element.getAttributeNode('value').specified ? element.value : element.text)\n                                    : element.value;\n                            case 'select':\n                                return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;\n                            default:\n                                return element.value;\n                        }\n                    },\n\n                    writeValue: function(element, value, allowUnset) {\n                        switch (ko.utils.tagNameLower(element)) {\n                            case 'option':\n                                if (typeof value === \"string\") {\n                                    ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);\n                                    if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node\n                                        delete element[hasDomDataExpandoProperty];\n                                    }\n                                    element.value = value;\n                                }\n                                else {\n                                    // Store arbitrary object using DomData\n                                    ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);\n                                    element[hasDomDataExpandoProperty] = true;\n\n                                    // Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.\n                                    element.value = typeof value === \"number\" ? value : \"\";\n                                }\n                                break;\n                            case 'select':\n                                if (value === \"\" || value === null)       // A blank string or null value will select the caption\n                                    value = undefined;\n                                var selection = -1;\n                                for (var i = 0, n = element.options.length, optionValue; i < n; ++i) {\n                                    optionValue = ko.selectExtensions.readValue(element.options[i]);\n                                    // Include special check to handle selecting a caption with a blank string value\n                                    if (optionValue == value || (optionValue === \"\" && value === undefined)) {\n                                        selection = i;\n                                        break;\n                                    }\n                                }\n                                if (allowUnset || selection >= 0 || (value === undefined && element.size > 1)) {\n                                    element.selectedIndex = selection;\n                                    if (ko.utils.ieVersion === 6) {\n                                        // Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread\n                                        // right after you've changed the set of OPTION nodes on it. So for that node type, we'll schedule a second thread\n                                        // to apply the value as well.\n                                        ko.utils.setTimeout(function () {\n                                            element.selectedIndex = selection;\n                                        }, 0);\n                                    }\n                                }\n                                break;\n                            default:\n                                if ((value === null) || (value === undefined))\n                                    value = \"\";\n                                element.value = value;\n                                break;\n                        }\n                    }\n                };\n            })();\n\n            ko.exportSymbol('selectExtensions', ko.selectExtensions);\n            ko.exportSymbol('selectExtensions.readValue', ko.selectExtensions.readValue);\n            ko.exportSymbol('selectExtensions.writeValue', ko.selectExtensions.writeValue);\n            ko.expressionRewriting = (function () {\n                var javaScriptReservedWords = [\"true\", \"false\", \"null\", \"undefined\"];\n\n                // Matches something that can be assigned to--either an isolated identifier or something ending with a property accessor\n                // This is designed to be simple and avoid false negatives, but could produce false positives (e.g., a+b.c).\n                // This also will not properly handle nested brackets (e.g., obj1[obj2['prop']]; see #911).\n                var javaScriptAssignmentTarget = /^(?:[$_a-z][$\\w]*|(.+)(\\.\\s*[$_a-z][$\\w]*|\\[.+\\]))$/i;\n\n                function getWriteableValue(expression) {\n                    if (ko.utils.arrayIndexOf(javaScriptReservedWords, expression) >= 0)\n                        return false;\n                    var match = expression.match(javaScriptAssignmentTarget);\n                    return match === null ? false : match[1] ? ('Object(' + match[1] + ')' + match[2]) : expression;\n                }\n\n                // The following regular expressions will be used to split an object-literal string into tokens\n\n                var specials = ',\"\\'`{}()/:[\\\\]',    // These characters have special meaning to the parser and must not appear in the middle of a token, except as part of a string.\n                    // Create the actual regular expression by or-ing the following regex strings. The order is important.\n                    bindingToken = RegExp([\n                        // These match strings, either with double quotes, single quotes, or backticks\n                        '\"(?:\\\\\\\\.|[^\"])*\"',\n                        \"'(?:\\\\\\\\.|[^'])*'\",\n                        \"`(?:\\\\\\\\.|[^`])*`\",\n                        // Match C style comments\n                        \"/\\\\*(?:[^*]|\\\\*+[^*/])*\\\\*+/\",\n                        // Match C++ style comments\n                        \"//.*\\n\",\n                        // Match a regular expression (text enclosed by slashes), but will also match sets of divisions\n                        // as a regular expression (this is handled by the parsing loop below).\n                        '/(?:\\\\\\\\.|[^/])+/\\w*',\n                        // Match text (at least two characters) that does not contain any of the above special characters,\n                        // although some of the special characters are allowed to start it (all but the colon and comma).\n                        // The text can contain spaces, but leading or trailing spaces are skipped.\n                        '[^\\\\s:,/][^' + specials + ']*[^\\\\s' + specials + ']',\n                        // Match any non-space character not matched already. This will match colons and commas, since they're\n                        // not matched by \"everyThingElse\", but will also match any other single character that wasn't already\n                        // matched (for example: in \"a: 1, b: 2\", each of the non-space characters will be matched by oneNotSpace).\n                        '[^\\\\s]'\n                    ].join('|'), 'g'),\n\n                    // Match end of previous token to determine whether a slash is a division or regex.\n                    divisionLookBehind = /[\\])\"'A-Za-z0-9_$]+$/,\n                    keywordRegexLookBehind = {'in':1,'return':1,'typeof':1};\n\n                function parseObjectLiteral(objectLiteralString) {\n                    // Trim leading and trailing spaces from the string\n                    var str = ko.utils.stringTrim(objectLiteralString);\n\n                    // Trim braces '{' surrounding the whole object literal\n                    if (str.charCodeAt(0) === 123) str = str.slice(1, -1);\n\n                    // Add a newline to correctly match a C++ style comment at the end of the string and\n                    // add a comma so that we don't need a separate code block to deal with the last item\n                    str += \"\\n,\";\n\n                    // Split into tokens\n                    var result = [], toks = str.match(bindingToken), key, values = [], depth = 0;\n\n                    if (toks.length > 1) {\n                        for (var i = 0, tok; tok = toks[i]; ++i) {\n                            var c = tok.charCodeAt(0);\n                            // A comma signals the end of a key/value pair if depth is zero\n                            if (c === 44) { // \",\"\n                                if (depth <= 0) {\n                                    result.push((key && values.length) ? {key: key, value: values.join('')} : {'unknown': key || values.join('')});\n                                    key = depth = 0;\n                                    values = [];\n                                    continue;\n                                }\n                                // Simply skip the colon that separates the name and value\n                            } else if (c === 58) { // \":\"\n                                if (!depth && !key && values.length === 1) {\n                                    key = values.pop();\n                                    continue;\n                                }\n                                // Comments: skip them\n                            } else if (c === 47 && tok.length > 1 && (tok.charCodeAt(1) === 47 || tok.charCodeAt(1) === 42)) {  // \"//\" or \"/*\"\n                                continue;\n                                // A set of slashes is initially matched as a regular expression, but could be division\n                            } else if (c === 47 && i && tok.length > 1) {  // \"/\"\n                                // Look at the end of the previous token to determine if the slash is actually division\n                                var match = toks[i-1].match(divisionLookBehind);\n                                if (match && !keywordRegexLookBehind[match[0]]) {\n                                    // The slash is actually a division punctuator; re-parse the remainder of the string (not including the slash)\n                                    str = str.substr(str.indexOf(tok) + 1);\n                                    toks = str.match(bindingToken);\n                                    i = -1;\n                                    // Continue with just the slash\n                                    tok = '/';\n                                }\n                                // Increment depth for parentheses, braces, and brackets so that interior commas are ignored\n                            } else if (c === 40 || c === 123 || c === 91) { // '(', '{', '['\n                                ++depth;\n                            } else if (c === 41 || c === 125 || c === 93) { // ')', '}', ']'\n                                --depth;\n                                // The key will be the first token; if it's a string, trim the quotes\n                            } else if (!key && !values.length && (c === 34 || c === 39)) { // '\"', \"'\"\n                                tok = tok.slice(1, -1);\n                            }\n                            values.push(tok);\n                        }\n                        if (depth > 0) {\n                            throw Error(\"Unbalanced parentheses, braces, or brackets\");\n                        }\n                    }\n                    return result;\n                }\n\n                // Two-way bindings include a write function that allow the handler to update the value even if it's not an observable.\n                var twoWayBindings = {};\n\n                function preProcessBindings(bindingsStringOrKeyValueArray, bindingOptions) {\n                    bindingOptions = bindingOptions || {};\n\n                    function processKeyValue(key, val) {\n                        var writableVal;\n                        function callPreprocessHook(obj) {\n                            return (obj && obj['preprocess']) ? (val = obj['preprocess'](val, key, processKeyValue)) : true;\n                        }\n                        if (!bindingParams) {\n                            if (!callPreprocessHook(ko['getBindingHandler'](key)))\n                                return;\n\n                            if (twoWayBindings[key] && (writableVal = getWriteableValue(val))) {\n                                // For two-way bindings, provide a write method in case the value\n                                // isn't a writable observable.\n                                var writeKey = typeof twoWayBindings[key] == 'string' ? twoWayBindings[key] : key;\n                                propertyAccessorResultStrings.push(\"'\" + writeKey + \"':function(_z){\" + writableVal + \"=_z}\");\n                            }\n                        }\n                        // Values are wrapped in a function so that each value can be accessed independently\n                        if (makeValueAccessors) {\n                            val = 'function(){return ' + val + ' }';\n                        }\n                        resultStrings.push(\"'\" + key + \"':\" + val);\n                    }\n\n                    var resultStrings = [],\n                        propertyAccessorResultStrings = [],\n                        makeValueAccessors = bindingOptions['valueAccessors'],\n                        bindingParams = bindingOptions['bindingParams'],\n                        keyValueArray = typeof bindingsStringOrKeyValueArray === \"string\" ?\n                            parseObjectLiteral(bindingsStringOrKeyValueArray) : bindingsStringOrKeyValueArray;\n\n                    ko.utils.arrayForEach(keyValueArray, function(keyValue) {\n                        processKeyValue(keyValue.key || keyValue['unknown'], keyValue.value);\n                    });\n\n                    if (propertyAccessorResultStrings.length)\n                        processKeyValue('_ko_property_writers', \"{\" + propertyAccessorResultStrings.join(\",\") + \" }\");\n\n                    return resultStrings.join(\",\");\n                }\n\n                return {\n                    bindingRewriteValidators: [],\n\n                    twoWayBindings: twoWayBindings,\n\n                    parseObjectLiteral: parseObjectLiteral,\n\n                    preProcessBindings: preProcessBindings,\n\n                    keyValueArrayContainsKey: function(keyValueArray, key) {\n                        for (var i = 0; i < keyValueArray.length; i++)\n                            if (keyValueArray[i]['key'] == key)\n                                return true;\n                        return false;\n                    },\n\n                    // Internal, private KO utility for updating model properties from within bindings\n                    // property:            If the property being updated is (or might be) an observable, pass it here\n                    //                      If it turns out to be a writable observable, it will be written to directly\n                    // allBindings:         An object with a get method to retrieve bindings in the current execution context.\n                    //                      This will be searched for a '_ko_property_writers' property in case you're writing to a non-observable\n                    // key:                 The key identifying the property to be written. Example: for { hasFocus: myValue }, write to 'myValue' by specifying the key 'hasFocus'\n                    // value:               The value to be written\n                    // checkIfDifferent:    If true, and if the property being written is a writable observable, the value will only be written if\n                    //                      it is !== existing value on that writable observable\n                    writeValueToProperty: function(property, allBindings, key, value, checkIfDifferent) {\n                        if (!property || !ko.isObservable(property)) {\n                            var propWriters = allBindings.get('_ko_property_writers');\n                            if (propWriters && propWriters[key])\n                                propWriters[key](value);\n                        } else if (ko.isWriteableObservable(property) && (!checkIfDifferent || property.peek() !== value)) {\n                            property(value);\n                        }\n                    }\n                };\n            })();\n\n            ko.exportSymbol('expressionRewriting', ko.expressionRewriting);\n            ko.exportSymbol('expressionRewriting.bindingRewriteValidators', ko.expressionRewriting.bindingRewriteValidators);\n            ko.exportSymbol('expressionRewriting.parseObjectLiteral', ko.expressionRewriting.parseObjectLiteral);\n            ko.exportSymbol('expressionRewriting.preProcessBindings', ko.expressionRewriting.preProcessBindings);\n\n// Making bindings explicitly declare themselves as \"two way\" isn't ideal in the long term (it would be better if\n// all bindings could use an official 'property writer' API without needing to declare that they might). However,\n// since this is not, and has never been, a public API (_ko_property_writers was never documented), it's acceptable\n// as an internal implementation detail in the short term.\n// For those developers who rely on _ko_property_writers in their custom bindings, we expose _twoWayBindings as an\n// undocumented feature that makes it relatively easy to upgrade to KO 3.0. However, this is still not an official\n// public API, and we reserve the right to remove it at any time if we create a real public property writers API.\n            ko.exportSymbol('expressionRewriting._twoWayBindings', ko.expressionRewriting.twoWayBindings);\n\n// For backward compatibility, define the following aliases. (Previously, these function names were misleading because\n// they referred to JSON specifically, even though they actually work with arbitrary JavaScript object literal expressions.)\n            ko.exportSymbol('jsonExpressionRewriting', ko.expressionRewriting);\n            ko.exportSymbol('jsonExpressionRewriting.insertPropertyAccessorsIntoJson', ko.expressionRewriting.preProcessBindings);\n            (function() {\n                // \"Virtual elements\" is an abstraction on top of the usual DOM API which understands the notion that comment nodes\n                // may be used to represent hierarchy (in addition to the DOM's natural hierarchy).\n                // If you call the DOM-manipulating functions on ko.virtualElements, you will be able to read and write the state\n                // of that virtual hierarchy\n                //\n                // The point of all this is to support containerless templates (e.g., <!-- ko foreach:someCollection -->blah<!-- /ko -->)\n                // without having to scatter special cases all over the binding and templating code.\n\n                // IE 9 cannot reliably read the \"nodeValue\" property of a comment node (see https://github.com/SteveSanderson/knockout/issues/186)\n                // but it does give them a nonstandard alternative property called \"text\" that it can read reliably. Other browsers don't have that property.\n                // So, use node.text where available, and node.nodeValue elsewhere\n                var commentNodesHaveTextProperty = document && document.createComment(\"test\").text === \"<!--test-->\";\n\n                var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\\s*ko(?:\\s+([\\s\\S]+))?\\s*-->$/ : /^\\s*ko(?:\\s+([\\s\\S]+))?\\s*$/;\n                var endCommentRegex =   commentNodesHaveTextProperty ? /^<!--\\s*\\/ko\\s*-->$/ : /^\\s*\\/ko\\s*$/;\n                var htmlTagsWithOptionallyClosingChildren = { 'ul': true, 'ol': true };\n\n                function isStartComment(node) {\n                    return (node.nodeType == 8) && startCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);\n                }\n\n                function isEndComment(node) {\n                    return (node.nodeType == 8) && endCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);\n                }\n\n                function isUnmatchedEndComment(node) {\n                    return isEndComment(node) && !(ko.utils.domData.get(node, matchedEndCommentDataKey));\n                }\n\n                var matchedEndCommentDataKey = \"__ko_matchedEndComment__\"\n\n                function getVirtualChildren(startComment, allowUnbalanced) {\n                    var currentNode = startComment;\n                    var depth = 1;\n                    var children = [];\n                    while (currentNode = currentNode.nextSibling) {\n                        if (isEndComment(currentNode)) {\n                            ko.utils.domData.set(currentNode, matchedEndCommentDataKey, true);\n                            depth--;\n                            if (depth === 0)\n                                return children;\n                        }\n\n                        children.push(currentNode);\n\n                        if (isStartComment(currentNode))\n                            depth++;\n                    }\n                    if (!allowUnbalanced)\n                        throw new Error(\"Cannot find closing comment tag to match: \" + startComment.nodeValue);\n                    return null;\n                }\n\n                function getMatchingEndComment(startComment, allowUnbalanced) {\n                    var allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced);\n                    if (allVirtualChildren) {\n                        if (allVirtualChildren.length > 0)\n                            return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;\n                        return startComment.nextSibling;\n                    } else\n                        return null; // Must have no matching end comment, and allowUnbalanced is true\n                }\n\n                function getUnbalancedChildTags(node) {\n                    // e.g., from <div>OK</div><!-- ko blah --><span>Another</span>, returns: <!-- ko blah --><span>Another</span>\n                    //       from <div>OK</div><!-- /ko --><!-- /ko -->,             returns: <!-- /ko --><!-- /ko -->\n                    var childNode = node.firstChild, captureRemaining = null;\n                    if (childNode) {\n                        do {\n                            if (captureRemaining)                   // We already hit an unbalanced node and are now just scooping up all subsequent nodes\n                                captureRemaining.push(childNode);\n                            else if (isStartComment(childNode)) {\n                                var matchingEndComment = getMatchingEndComment(childNode, /* allowUnbalanced: */ true);\n                                if (matchingEndComment)             // It's a balanced tag, so skip immediately to the end of this virtual set\n                                    childNode = matchingEndComment;\n                                else\n                                    captureRemaining = [childNode]; // It's unbalanced, so start capturing from this point\n                            } else if (isEndComment(childNode)) {\n                                captureRemaining = [childNode];     // It's unbalanced (if it wasn't, we'd have skipped over it already), so start capturing\n                            }\n                        } while (childNode = childNode.nextSibling);\n                    }\n                    return captureRemaining;\n                }\n\n                ko.virtualElements = {\n                    allowedBindings: {},\n\n                    childNodes: function(node) {\n                        return isStartComment(node) ? getVirtualChildren(node) : node.childNodes;\n                    },\n\n                    emptyNode: function(node) {\n                        if (!isStartComment(node))\n                            ko.utils.emptyDomNode(node);\n                        else {\n                            var virtualChildren = ko.virtualElements.childNodes(node);\n                            for (var i = 0, j = virtualChildren.length; i < j; i++)\n                                ko.removeNode(virtualChildren[i]);\n                        }\n                    },\n\n                    setDomNodeChildren: function(node, childNodes) {\n                        if (!isStartComment(node))\n                            ko.utils.setDomNodeChildren(node, childNodes);\n                        else {\n                            ko.virtualElements.emptyNode(node);\n                            var endCommentNode = node.nextSibling; // Must be the next sibling, as we just emptied the children\n                            for (var i = 0, j = childNodes.length; i < j; i++)\n                                endCommentNode.parentNode.insertBefore(childNodes[i], endCommentNode);\n                        }\n                    },\n\n                    prepend: function(containerNode, nodeToPrepend) {\n                        var insertBeforeNode;\n\n                        if (isStartComment(containerNode)) {\n                            // Start comments must always have a parent and at least one following sibling (the end comment)\n                            insertBeforeNode = containerNode.nextSibling;\n                            containerNode = containerNode.parentNode;\n                        } else {\n                            insertBeforeNode = containerNode.firstChild;\n                        }\n\n                        if (!insertBeforeNode) {\n                            containerNode.appendChild(nodeToPrepend);\n                        } else if (nodeToPrepend !== insertBeforeNode) {       // IE will sometimes crash if you try to insert a node before itself\n                            containerNode.insertBefore(nodeToPrepend, insertBeforeNode);\n                        }\n                    },\n\n                    insertAfter: function(containerNode, nodeToInsert, insertAfterNode) {\n                        if (!insertAfterNode) {\n                            ko.virtualElements.prepend(containerNode, nodeToInsert);\n                        } else {\n                            // Children of start comments must always have a parent and at least one following sibling (the end comment)\n                            var insertBeforeNode = insertAfterNode.nextSibling;\n\n                            if (isStartComment(containerNode)) {\n                                containerNode = containerNode.parentNode;\n                            }\n\n                            if (!insertBeforeNode) {\n                                containerNode.appendChild(nodeToInsert);\n                            } else if (nodeToInsert !== insertBeforeNode) {       // IE will sometimes crash if you try to insert a node before itself\n                                containerNode.insertBefore(nodeToInsert, insertBeforeNode);\n                            }\n                        }\n                    },\n\n                    firstChild: function(node) {\n                        if (!isStartComment(node)) {\n                            if (node.firstChild && isEndComment(node.firstChild)) {\n                                throw new Error(\"Found invalid end comment, as the first child of \" + node);\n                            }\n                            return node.firstChild;\n                        } else if (!node.nextSibling || isEndComment(node.nextSibling)) {\n                            return null;\n                        } else {\n                            return node.nextSibling;\n                        }\n                    },\n\n                    nextSibling: function(node) {\n                        if (isStartComment(node)) {\n                            node = getMatchingEndComment(node);\n                        }\n\n                        if (node.nextSibling && isEndComment(node.nextSibling)) {\n                            if (isUnmatchedEndComment(node.nextSibling)) {\n                                throw Error(\"Found end comment without a matching opening comment, as child of \" + node);\n                            } else {\n                                return null;\n                            }\n                        } else {\n                            return node.nextSibling;\n                        }\n                    },\n\n                    hasBindingValue: isStartComment,\n\n                    virtualNodeBindingValue: function(node) {\n                        var regexMatch = (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(startCommentRegex);\n                        return regexMatch ? regexMatch[1] : null;\n                    },\n\n                    normaliseVirtualElementDomStructure: function(elementVerified) {\n                        // Workaround for https://github.com/SteveSanderson/knockout/issues/155\n                        // (IE <= 8 or IE 9 quirks mode parses your HTML weirdly, treating closing </li> tags as if they don't exist, thereby moving comment nodes\n                        // that are direct descendants of <ul> into the preceding <li>)\n                        if (!htmlTagsWithOptionallyClosingChildren[ko.utils.tagNameLower(elementVerified)])\n                            return;\n\n                        // Scan immediate children to see if they contain unbalanced comment tags. If they do, those comment tags\n                        // must be intended to appear *after* that child, so move them there.\n                        var childNode = elementVerified.firstChild;\n                        if (childNode) {\n                            do {\n                                if (childNode.nodeType === 1) {\n                                    var unbalancedTags = getUnbalancedChildTags(childNode);\n                                    if (unbalancedTags) {\n                                        // Fix up the DOM by moving the unbalanced tags to where they most likely were intended to be placed - *after* the child\n                                        var nodeToInsertBefore = childNode.nextSibling;\n                                        for (var i = 0; i < unbalancedTags.length; i++) {\n                                            if (nodeToInsertBefore)\n                                                elementVerified.insertBefore(unbalancedTags[i], nodeToInsertBefore);\n                                            else\n                                                elementVerified.appendChild(unbalancedTags[i]);\n                                        }\n                                    }\n                                }\n                            } while (childNode = childNode.nextSibling);\n                        }\n                    }\n                };\n            })();\n            ko.exportSymbol('virtualElements', ko.virtualElements);\n            ko.exportSymbol('virtualElements.allowedBindings', ko.virtualElements.allowedBindings);\n            ko.exportSymbol('virtualElements.emptyNode', ko.virtualElements.emptyNode);\n//ko.exportSymbol('virtualElements.firstChild', ko.virtualElements.firstChild);     // firstChild is not minified\n            ko.exportSymbol('virtualElements.insertAfter', ko.virtualElements.insertAfter);\n//ko.exportSymbol('virtualElements.nextSibling', ko.virtualElements.nextSibling);   // nextSibling is not minified\n            ko.exportSymbol('virtualElements.prepend', ko.virtualElements.prepend);\n            ko.exportSymbol('virtualElements.setDomNodeChildren', ko.virtualElements.setDomNodeChildren);\n            (function() {\n                var defaultBindingAttributeName = \"data-bind\";\n\n                ko.bindingProvider = function() {\n                    this.bindingCache = {};\n                };\n\n                ko.utils.extend(ko.bindingProvider.prototype, {\n                    'nodeHasBindings': function(node) {\n                        switch (node.nodeType) {\n                            case 1: // Element\n                                return node.getAttribute(defaultBindingAttributeName) != null\n                                    || ko.components['getComponentNameForNode'](node);\n                            case 8: // Comment node\n                                return ko.virtualElements.hasBindingValue(node);\n                            default: return false;\n                        }\n                    },\n\n                    'getBindings': function(node, bindingContext) {\n                        var bindingsString = this['getBindingsString'](node, bindingContext),\n                            parsedBindings = bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node) : null;\n                        return ko.components.addBindingsForCustomElement(parsedBindings, node, bindingContext, /* valueAccessors */ false);\n                    },\n\n                    'getBindingAccessors': function(node, bindingContext) {\n                        var bindingsString = this['getBindingsString'](node, bindingContext),\n                            parsedBindings = bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node, { 'valueAccessors': true }) : null;\n                        return ko.components.addBindingsForCustomElement(parsedBindings, node, bindingContext, /* valueAccessors */ true);\n                    },\n\n                    // The following function is only used internally by this default provider.\n                    // It's not part of the interface definition for a general binding provider.\n                    'getBindingsString': function(node, bindingContext) {\n                        switch (node.nodeType) {\n                            case 1: return node.getAttribute(defaultBindingAttributeName);   // Element\n                            case 8: return ko.virtualElements.virtualNodeBindingValue(node); // Comment node\n                            default: return null;\n                        }\n                    },\n\n                    // The following function is only used internally by this default provider.\n                    // It's not part of the interface definition for a general binding provider.\n                    'parseBindingsString': function(bindingsString, bindingContext, node, options) {\n                        try {\n                            var bindingFunction = createBindingsStringEvaluatorViaCache(bindingsString, this.bindingCache, options);\n                            return bindingFunction(bindingContext, node);\n                        } catch (ex) {\n                            ex.message = \"Unable to parse bindings.\\nBindings value: \" + bindingsString + \"\\nMessage: \" + ex.message;\n                            throw ex;\n                        }\n                    }\n                });\n\n                ko.bindingProvider['instance'] = new ko.bindingProvider();\n\n                function createBindingsStringEvaluatorViaCache(bindingsString, cache, options) {\n                    var cacheKey = bindingsString + (options && options['valueAccessors'] || '');\n                    return cache[cacheKey]\n                        || (cache[cacheKey] = createBindingsStringEvaluator(bindingsString, options));\n                }\n\n                function createBindingsStringEvaluator(bindingsString, options) {\n                    // Build the source for a function that evaluates \"expression\"\n                    // For each scope variable, add an extra level of \"with\" nesting\n                    // Example result: with(sc1) { with(sc0) { return (expression) } }\n                    var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString, options),\n                        functionBody = \"with($context){with($data||{}){return{\" + rewrittenBindings + \"}}}\";\n                    return new Function(\"$context\", \"$element\", functionBody);\n                }\n            })();\n\n            ko.exportSymbol('bindingProvider', ko.bindingProvider);\n            (function () {\n                // Hide or don't minify context properties, see https://github.com/knockout/knockout/issues/2294\n                var contextSubscribable = ko.utils.createSymbolOrString('_subscribable');\n                var contextAncestorBindingInfo = ko.utils.createSymbolOrString('_ancestorBindingInfo');\n                var contextDataDependency = ko.utils.createSymbolOrString('_dataDependency');\n\n                ko.bindingHandlers = {};\n\n                // The following element types will not be recursed into during binding.\n                var bindingDoesNotRecurseIntoElementTypes = {\n                    // Don't want bindings that operate on text nodes to mutate <script> and <textarea> contents,\n                    // because it's unexpected and a potential XSS issue.\n                    // Also bindings should not operate on <template> elements since this breaks in Internet Explorer\n                    // and because such elements' contents are always intended to be bound in a different context\n                    // from where they appear in the document.\n                    'script': true,\n                    'textarea': true,\n                    'template': true\n                };\n\n                // Use an overridable method for retrieving binding handlers so that plugins may support dynamically created handlers\n                ko['getBindingHandler'] = function(bindingKey) {\n                    return ko.bindingHandlers[bindingKey];\n                };\n\n                var inheritParentVm = {};\n\n                // The ko.bindingContext constructor is only called directly to create the root context. For child\n                // contexts, use bindingContext.createChildContext or bindingContext.extend.\n                ko.bindingContext = function(dataItemOrAccessor, parentContext, dataItemAlias, extendCallback, options) {\n\n                    // The binding context object includes static properties for the current, parent, and root view models.\n                    // If a view model is actually stored in an observable, the corresponding binding context object, and\n                    // any child contexts, must be updated when the view model is changed.\n                    function updateContext() {\n                        // Most of the time, the context will directly get a view model object, but if a function is given,\n                        // we call the function to retrieve the view model. If the function accesses any observables or returns\n                        // an observable, the dependency is tracked, and those observables can later cause the binding\n                        // context to be updated.\n                        var dataItemOrObservable = isFunc ? realDataItemOrAccessor() : realDataItemOrAccessor,\n                            dataItem = ko.utils.unwrapObservable(dataItemOrObservable);\n\n                        if (parentContext) {\n                            // Copy $root and any custom properties from the parent context\n                            ko.utils.extend(self, parentContext);\n\n                            // Copy Symbol properties\n                            if (contextAncestorBindingInfo in parentContext) {\n                                self[contextAncestorBindingInfo] = parentContext[contextAncestorBindingInfo];\n                            }\n                        } else {\n                            self['$parents'] = [];\n                            self['$root'] = dataItem;\n\n                            // Export 'ko' in the binding context so it will be available in bindings and templates\n                            // even if 'ko' isn't exported as a global, such as when using an AMD loader.\n                            // See https://github.com/SteveSanderson/knockout/issues/490\n                            self['ko'] = ko;\n                        }\n\n                        self[contextSubscribable] = subscribable;\n\n                        if (shouldInheritData) {\n                            dataItem = self['$data'];\n                        } else {\n                            self['$rawData'] = dataItemOrObservable;\n                            self['$data'] = dataItem;\n                        }\n\n                        if (dataItemAlias)\n                            self[dataItemAlias] = dataItem;\n\n                        // The extendCallback function is provided when creating a child context or extending a context.\n                        // It handles the specific actions needed to finish setting up the binding context. Actions in this\n                        // function could also add dependencies to this binding context.\n                        if (extendCallback)\n                            extendCallback(self, parentContext, dataItem);\n\n                        // When a \"parent\" context is given and we don't already have a dependency on its context, register a dependency on it.\n                        // Thus whenever the parent context is updated, this context will also be updated.\n                        if (parentContext && parentContext[contextSubscribable] && !ko.computedContext.computed().hasAncestorDependency(parentContext[contextSubscribable])) {\n                            parentContext[contextSubscribable]();\n                        }\n\n                        if (dataDependency) {\n                            self[contextDataDependency] = dataDependency;\n                        }\n\n                        return self['$data'];\n                    }\n\n                    var self = this,\n                        shouldInheritData = dataItemOrAccessor === inheritParentVm,\n                        realDataItemOrAccessor = shouldInheritData ? undefined : dataItemOrAccessor,\n                        isFunc = typeof(realDataItemOrAccessor) == \"function\" && !ko.isObservable(realDataItemOrAccessor),\n                        nodes,\n                        subscribable,\n                        dataDependency = options && options['dataDependency'];\n\n                    if (options && options['exportDependencies']) {\n                        // The \"exportDependencies\" option means that the calling code will track any dependencies and re-create\n                        // the binding context when they change.\n                        updateContext();\n                    } else {\n                        subscribable = ko.pureComputed(updateContext);\n                        subscribable.peek();\n\n                        // At this point, the binding context has been initialized, and the \"subscribable\" computed observable is\n                        // subscribed to any observables that were accessed in the process. If there is nothing to track, the\n                        // computed will be inactive, and we can safely throw it away. If it's active, the computed is stored in\n                        // the context object.\n                        if (subscribable.isActive()) {\n                            // Always notify because even if the model ($data) hasn't changed, other context properties might have changed\n                            subscribable['equalityComparer'] = null;\n                        } else {\n                            self[contextSubscribable] = undefined;\n                        }\n                    }\n                }\n\n                // Extend the binding context hierarchy with a new view model object. If the parent context is watching\n                // any observables, the new child context will automatically get a dependency on the parent context.\n                // But this does not mean that the $data value of the child context will also get updated. If the child\n                // view model also depends on the parent view model, you must provide a function that returns the correct\n                // view model on each update.\n                ko.bindingContext.prototype['createChildContext'] = function (dataItemOrAccessor, dataItemAlias, extendCallback, options) {\n                    if (!options && dataItemAlias && typeof dataItemAlias == \"object\") {\n                        options = dataItemAlias;\n                        dataItemAlias = options['as'];\n                        extendCallback = options['extend'];\n                    }\n\n                    if (dataItemAlias && options && options['noChildContext']) {\n                        var isFunc = typeof(dataItemOrAccessor) == \"function\" && !ko.isObservable(dataItemOrAccessor);\n                        return new ko.bindingContext(inheritParentVm, this, null, function (self) {\n                            if (extendCallback)\n                                extendCallback(self);\n                            self[dataItemAlias] = isFunc ? dataItemOrAccessor() : dataItemOrAccessor;\n                        }, options);\n                    }\n\n                    return new ko.bindingContext(dataItemOrAccessor, this, dataItemAlias, function (self, parentContext) {\n                        // Extend the context hierarchy by setting the appropriate pointers\n                        self['$parentContext'] = parentContext;\n                        self['$parent'] = parentContext['$data'];\n                        self['$parents'] = (parentContext['$parents'] || []).slice(0);\n                        self['$parents'].unshift(self['$parent']);\n                        if (extendCallback)\n                            extendCallback(self);\n                    }, options);\n                };\n\n                // Extend the binding context with new custom properties. This doesn't change the context hierarchy.\n                // Similarly to \"child\" contexts, provide a function here to make sure that the correct values are set\n                // when an observable view model is updated.\n                ko.bindingContext.prototype['extend'] = function(properties, options) {\n                    return new ko.bindingContext(inheritParentVm, this, null, function(self, parentContext) {\n                        ko.utils.extend(self, typeof(properties) == \"function\" ? properties(self) : properties);\n                    }, options);\n                };\n\n                var boundElementDomDataKey = ko.utils.domData.nextKey();\n\n                function asyncContextDispose(node) {\n                    var bindingInfo = ko.utils.domData.get(node, boundElementDomDataKey),\n                        asyncContext = bindingInfo && bindingInfo.asyncContext;\n                    if (asyncContext) {\n                        bindingInfo.asyncContext = null;\n                        asyncContext.notifyAncestor();\n                    }\n                }\n                function AsyncCompleteContext(node, bindingInfo, ancestorBindingInfo) {\n                    this.node = node;\n                    this.bindingInfo = bindingInfo;\n                    this.asyncDescendants = [];\n                    this.childrenComplete = false;\n\n                    if (!bindingInfo.asyncContext) {\n                        ko.utils.domNodeDisposal.addDisposeCallback(node, asyncContextDispose);\n                    }\n\n                    if (ancestorBindingInfo && ancestorBindingInfo.asyncContext) {\n                        ancestorBindingInfo.asyncContext.asyncDescendants.push(node);\n                        this.ancestorBindingInfo = ancestorBindingInfo;\n                    }\n                }\n                AsyncCompleteContext.prototype.notifyAncestor = function () {\n                    if (this.ancestorBindingInfo && this.ancestorBindingInfo.asyncContext) {\n                        this.ancestorBindingInfo.asyncContext.descendantComplete(this.node);\n                    }\n                };\n                AsyncCompleteContext.prototype.descendantComplete = function (node) {\n                    ko.utils.arrayRemoveItem(this.asyncDescendants, node);\n                    if (!this.asyncDescendants.length && this.childrenComplete) {\n                        this.completeChildren();\n                    }\n                };\n                AsyncCompleteContext.prototype.completeChildren = function () {\n                    this.childrenComplete = true;\n                    if (this.bindingInfo.asyncContext && !this.asyncDescendants.length) {\n                        this.bindingInfo.asyncContext = null;\n                        ko.utils.domNodeDisposal.removeDisposeCallback(this.node, asyncContextDispose);\n                        ko.bindingEvent.notify(this.node, ko.bindingEvent.descendantsComplete);\n                        this.notifyAncestor();\n                    }\n                };\n\n                ko.bindingEvent = {\n                    childrenComplete: \"childrenComplete\",\n                    descendantsComplete : \"descendantsComplete\",\n\n                    subscribe: function (node, event, callback, context, options) {\n                        var bindingInfo = ko.utils.domData.getOrSet(node, boundElementDomDataKey, {});\n                        if (!bindingInfo.eventSubscribable) {\n                            bindingInfo.eventSubscribable = new ko.subscribable;\n                        }\n                        if (options && options['notifyImmediately'] && bindingInfo.notifiedEvents[event]) {\n                            ko.dependencyDetection.ignore(callback, context, [node]);\n                        }\n                        return bindingInfo.eventSubscribable.subscribe(callback, context, event);\n                    },\n\n                    notify: function (node, event) {\n                        var bindingInfo = ko.utils.domData.get(node, boundElementDomDataKey);\n                        if (bindingInfo) {\n                            bindingInfo.notifiedEvents[event] = true;\n                            if (bindingInfo.eventSubscribable) {\n                                bindingInfo.eventSubscribable['notifySubscribers'](node, event);\n                            }\n                            if (event == ko.bindingEvent.childrenComplete) {\n                                if (bindingInfo.asyncContext) {\n                                    bindingInfo.asyncContext.completeChildren();\n                                } else if (bindingInfo.asyncContext === undefined && bindingInfo.eventSubscribable && bindingInfo.eventSubscribable.hasSubscriptionsForEvent(ko.bindingEvent.descendantsComplete)) {\n                                    // It's currently an error to register a descendantsComplete handler for a node that was never registered as completing asynchronously.\n                                    // That's because without the asyncContext, we don't have a way to know that all descendants have completed.\n                                    throw new Error(\"descendantsComplete event not supported for bindings on this node\");\n                                }\n                            }\n                        }\n                    },\n\n                    startPossiblyAsyncContentBinding: function (node, bindingContext) {\n                        var bindingInfo = ko.utils.domData.getOrSet(node, boundElementDomDataKey, {});\n\n                        if (!bindingInfo.asyncContext) {\n                            bindingInfo.asyncContext = new AsyncCompleteContext(node, bindingInfo, bindingContext[contextAncestorBindingInfo]);\n                        }\n\n                        // If the provided context was already extended with this node's binding info, just return the extended context\n                        if (bindingContext[contextAncestorBindingInfo] == bindingInfo) {\n                            return bindingContext;\n                        }\n\n                        return bindingContext['extend'](function (ctx) {\n                            ctx[contextAncestorBindingInfo] = bindingInfo;\n                        });\n                    }\n                };\n\n                // Returns the valueAccessor function for a binding value\n                function makeValueAccessor(value) {\n                    return function() {\n                        return value;\n                    };\n                }\n\n                // Returns the value of a valueAccessor function\n                function evaluateValueAccessor(valueAccessor) {\n                    return valueAccessor();\n                }\n\n                // Given a function that returns bindings, create and return a new object that contains\n                // binding value-accessors functions. Each accessor function calls the original function\n                // so that it always gets the latest value and all dependencies are captured. This is used\n                // by ko.applyBindingsToNode and getBindingsAndMakeAccessors.\n                function makeAccessorsFromFunction(callback) {\n                    return ko.utils.objectMap(ko.dependencyDetection.ignore(callback), function(value, key) {\n                        return function() {\n                            return callback()[key];\n                        };\n                    });\n                }\n\n                // Given a bindings function or object, create and return a new object that contains\n                // binding value-accessors functions. This is used by ko.applyBindingsToNode.\n                function makeBindingAccessors(bindings, context, node) {\n                    if (typeof bindings === 'function') {\n                        return makeAccessorsFromFunction(bindings.bind(null, context, node));\n                    } else {\n                        return ko.utils.objectMap(bindings, makeValueAccessor);\n                    }\n                }\n\n                // This function is used if the binding provider doesn't include a getBindingAccessors function.\n                // It must be called with 'this' set to the provider instance.\n                function getBindingsAndMakeAccessors(node, context) {\n                    return makeAccessorsFromFunction(this['getBindings'].bind(this, node, context));\n                }\n\n                function validateThatBindingIsAllowedForVirtualElements(bindingName) {\n                    var validator = ko.virtualElements.allowedBindings[bindingName];\n                    if (!validator)\n                        throw new Error(\"The binding '\" + bindingName + \"' cannot be used with virtual elements\")\n                }\n\n                function applyBindingsToDescendantsInternal(bindingContext, elementOrVirtualElement) {\n                    var nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);\n\n                    if (nextInQueue) {\n                        var currentChild,\n                            provider = ko.bindingProvider['instance'],\n                            preprocessNode = provider['preprocessNode'];\n\n                        // Preprocessing allows a binding provider to mutate a node before bindings are applied to it. For example it's\n                        // possible to insert new siblings after it, and/or replace the node with a different one. This can be used to\n                        // implement custom binding syntaxes, such as {{ value }} for string interpolation, or custom element types that\n                        // trigger insertion of <template> contents at that point in the document.\n                        if (preprocessNode) {\n                            while (currentChild = nextInQueue) {\n                                nextInQueue = ko.virtualElements.nextSibling(currentChild);\n                                preprocessNode.call(provider, currentChild);\n                            }\n                            // Reset nextInQueue for the next loop\n                            nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);\n                        }\n\n                        while (currentChild = nextInQueue) {\n                            // Keep a record of the next child *before* applying bindings, in case the binding removes the current child from its position\n                            nextInQueue = ko.virtualElements.nextSibling(currentChild);\n                            applyBindingsToNodeAndDescendantsInternal(bindingContext, currentChild);\n                        }\n                    }\n                    ko.bindingEvent.notify(elementOrVirtualElement, ko.bindingEvent.childrenComplete);\n                }\n\n                function applyBindingsToNodeAndDescendantsInternal(bindingContext, nodeVerified) {\n                    var bindingContextForDescendants = bindingContext;\n\n                    var isElement = (nodeVerified.nodeType === 1);\n                    if (isElement) // Workaround IE <= 8 HTML parsing weirdness\n                        ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);\n\n                    // Perf optimisation: Apply bindings only if...\n                    // (1) We need to store the binding info for the node (all element nodes)\n                    // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)\n                    var shouldApplyBindings = isElement || ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified);\n                    if (shouldApplyBindings)\n                        bindingContextForDescendants = applyBindingsToNodeInternal(nodeVerified, null, bindingContext)['bindingContextForDescendants'];\n\n                    if (bindingContextForDescendants && !bindingDoesNotRecurseIntoElementTypes[ko.utils.tagNameLower(nodeVerified)]) {\n                        applyBindingsToDescendantsInternal(bindingContextForDescendants, nodeVerified);\n                    }\n                }\n\n                function topologicalSortBindings(bindings) {\n                    // Depth-first sort\n                    var result = [],                // The list of key/handler pairs that we will return\n                        bindingsConsidered = {},    // A temporary record of which bindings are already in 'result'\n                        cyclicDependencyStack = []; // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it\n                    ko.utils.objectForEach(bindings, function pushBinding(bindingKey) {\n                        if (!bindingsConsidered[bindingKey]) {\n                            var binding = ko['getBindingHandler'](bindingKey);\n                            if (binding) {\n                                // First add dependencies (if any) of the current binding\n                                if (binding['after']) {\n                                    cyclicDependencyStack.push(bindingKey);\n                                    ko.utils.arrayForEach(binding['after'], function(bindingDependencyKey) {\n                                        if (bindings[bindingDependencyKey]) {\n                                            if (ko.utils.arrayIndexOf(cyclicDependencyStack, bindingDependencyKey) !== -1) {\n                                                throw Error(\"Cannot combine the following bindings, because they have a cyclic dependency: \" + cyclicDependencyStack.join(\", \"));\n                                            } else {\n                                                pushBinding(bindingDependencyKey);\n                                            }\n                                        }\n                                    });\n                                    cyclicDependencyStack.length--;\n                                }\n                                // Next add the current binding\n                                result.push({ key: bindingKey, handler: binding });\n                            }\n                            bindingsConsidered[bindingKey] = true;\n                        }\n                    });\n\n                    return result;\n                }\n\n                function applyBindingsToNodeInternal(node, sourceBindings, bindingContext) {\n                    var bindingInfo = ko.utils.domData.getOrSet(node, boundElementDomDataKey, {});\n\n                    // Prevent multiple applyBindings calls for the same node, except when a binding value is specified\n                    var alreadyBound = bindingInfo.alreadyBound;\n                    if (!sourceBindings) {\n                        if (alreadyBound) {\n                            throw Error(\"You cannot apply bindings multiple times to the same element.\");\n                        }\n                        bindingInfo.alreadyBound = true;\n                    }\n                    if (!alreadyBound) {\n                        bindingInfo.context = bindingContext;\n                    }\n                    if (!bindingInfo.notifiedEvents) {\n                        bindingInfo.notifiedEvents = {};\n                    }\n\n                    // Use bindings if given, otherwise fall back on asking the bindings provider to give us some bindings\n                    var bindings;\n                    if (sourceBindings && typeof sourceBindings !== 'function') {\n                        bindings = sourceBindings;\n                    } else {\n                        var provider = ko.bindingProvider['instance'],\n                            getBindings = provider['getBindingAccessors'] || getBindingsAndMakeAccessors;\n\n                        // Get the binding from the provider within a computed observable so that we can update the bindings whenever\n                        // the binding context is updated or if the binding provider accesses observables.\n                        var bindingsUpdater = ko.dependentObservable(\n                            function() {\n                                bindings = sourceBindings ? sourceBindings(bindingContext, node) : getBindings.call(provider, node, bindingContext);\n                                // Register a dependency on the binding context to support observable view models.\n                                if (bindings) {\n                                    if (bindingContext[contextSubscribable]) {\n                                        bindingContext[contextSubscribable]();\n                                    }\n                                    if (bindingContext[contextDataDependency]) {\n                                        bindingContext[contextDataDependency]();\n                                    }\n                                }\n                                return bindings;\n                            },\n                            null, { disposeWhenNodeIsRemoved: node }\n                        );\n\n                        if (!bindings || !bindingsUpdater.isActive())\n                            bindingsUpdater = null;\n                    }\n\n                    var contextToExtend = bindingContext;\n                    var bindingHandlerThatControlsDescendantBindings;\n                    if (bindings) {\n                        // Return the value accessor for a given binding. When bindings are static (won't be updated because of a binding\n                        // context update), just return the value accessor from the binding. Otherwise, return a function that always gets\n                        // the latest binding value and registers a dependency on the binding updater.\n                        var getValueAccessor = bindingsUpdater\n                            ? function(bindingKey) {\n                                return function() {\n                                    return evaluateValueAccessor(bindingsUpdater()[bindingKey]);\n                                };\n                            } : function(bindingKey) {\n                                return bindings[bindingKey];\n                            };\n\n                        // Use of allBindings as a function is maintained for backwards compatibility, but its use is deprecated\n                        function allBindings() {\n                            return ko.utils.objectMap(bindingsUpdater ? bindingsUpdater() : bindings, evaluateValueAccessor);\n                        }\n                        // The following is the 3.x allBindings API\n                        allBindings['get'] = function(key) {\n                            return bindings[key] && evaluateValueAccessor(getValueAccessor(key));\n                        };\n                        allBindings['has'] = function(key) {\n                            return key in bindings;\n                        };\n\n                        if (ko.bindingEvent.childrenComplete in bindings) {\n                            ko.bindingEvent.subscribe(node, ko.bindingEvent.childrenComplete, function () {\n                                var callback = evaluateValueAccessor(bindings[ko.bindingEvent.childrenComplete]);\n                                if (callback) {\n                                    var nodes = ko.virtualElements.childNodes(node);\n                                    if (nodes.length) {\n                                        callback(nodes, ko.dataFor(nodes[0]));\n                                    }\n                                }\n                            });\n                        }\n\n                        if (ko.bindingEvent.descendantsComplete in bindings) {\n                            contextToExtend = ko.bindingEvent.startPossiblyAsyncContentBinding(node, bindingContext);\n                            ko.bindingEvent.subscribe(node, ko.bindingEvent.descendantsComplete, function () {\n                                var callback = evaluateValueAccessor(bindings[ko.bindingEvent.descendantsComplete]);\n                                if (callback && ko.virtualElements.firstChild(node)) {\n                                    callback(node);\n                                }\n                            });\n                        }\n\n                        // First put the bindings into the right order\n                        var orderedBindings = topologicalSortBindings(bindings);\n\n                        // Go through the sorted bindings, calling init and update for each\n                        ko.utils.arrayForEach(orderedBindings, function(bindingKeyAndHandler) {\n                            // Note that topologicalSortBindings has already filtered out any nonexistent binding handlers,\n                            // so bindingKeyAndHandler.handler will always be nonnull.\n                            var handlerInitFn = bindingKeyAndHandler.handler[\"init\"],\n                                handlerUpdateFn = bindingKeyAndHandler.handler[\"update\"],\n                                bindingKey = bindingKeyAndHandler.key;\n\n                            if (node.nodeType === 8) {\n                                validateThatBindingIsAllowedForVirtualElements(bindingKey);\n                            }\n\n                            try {\n                                // Run init, ignoring any dependencies\n                                if (typeof handlerInitFn == \"function\") {\n                                    ko.dependencyDetection.ignore(function() {\n                                        var initResult = handlerInitFn(node, getValueAccessor(bindingKey), allBindings, contextToExtend['$data'], contextToExtend);\n\n                                        // If this binding handler claims to control descendant bindings, make a note of this\n                                        if (initResult && initResult['controlsDescendantBindings']) {\n                                            if (bindingHandlerThatControlsDescendantBindings !== undefined)\n                                                throw new Error(\"Multiple bindings (\" + bindingHandlerThatControlsDescendantBindings + \" and \" + bindingKey + \") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.\");\n                                            bindingHandlerThatControlsDescendantBindings = bindingKey;\n                                        }\n                                    });\n                                }\n\n                                // Run update in its own computed wrapper\n                                if (typeof handlerUpdateFn == \"function\") {\n                                    ko.dependentObservable(\n                                        function() {\n                                            handlerUpdateFn(node, getValueAccessor(bindingKey), allBindings, contextToExtend['$data'], contextToExtend);\n                                        },\n                                        null,\n                                        { disposeWhenNodeIsRemoved: node }\n                                    );\n                                }\n                            } catch (ex) {\n                                ex.message = \"Unable to process binding \\\"\" + bindingKey + \": \" + bindings[bindingKey] + \"\\\"\\nMessage: \" + ex.message;\n                                throw ex;\n                            }\n                        });\n                    }\n\n                    var shouldBindDescendants = bindingHandlerThatControlsDescendantBindings === undefined;\n                    return {\n                        'shouldBindDescendants': shouldBindDescendants,\n                        'bindingContextForDescendants': shouldBindDescendants && contextToExtend\n                    };\n                };\n\n                ko.storedBindingContextForNode = function (node) {\n                    var bindingInfo = ko.utils.domData.get(node, boundElementDomDataKey);\n                    return bindingInfo && bindingInfo.context;\n                }\n\n                function getBindingContext(viewModelOrBindingContext, extendContextCallback) {\n                    return viewModelOrBindingContext && (viewModelOrBindingContext instanceof ko.bindingContext)\n                        ? viewModelOrBindingContext\n                        : new ko.bindingContext(viewModelOrBindingContext, undefined, undefined, extendContextCallback);\n                }\n\n                ko.applyBindingAccessorsToNode = function (node, bindings, viewModelOrBindingContext) {\n                    if (node.nodeType === 1) // If it's an element, workaround IE <= 8 HTML parsing weirdness\n                        ko.virtualElements.normaliseVirtualElementDomStructure(node);\n                    return applyBindingsToNodeInternal(node, bindings, getBindingContext(viewModelOrBindingContext));\n                };\n\n                ko.applyBindingsToNode = function (node, bindings, viewModelOrBindingContext) {\n                    var context = getBindingContext(viewModelOrBindingContext);\n                    return ko.applyBindingAccessorsToNode(node, makeBindingAccessors(bindings, context, node), context);\n                };\n\n                ko.applyBindingsToDescendants = function(viewModelOrBindingContext, rootNode) {\n                    if (rootNode.nodeType === 1 || rootNode.nodeType === 8)\n                        applyBindingsToDescendantsInternal(getBindingContext(viewModelOrBindingContext), rootNode);\n                };\n\n                ko.applyBindings = function (viewModelOrBindingContext, rootNode, extendContextCallback) {\n                    // If jQuery is loaded after Knockout, we won't initially have access to it. So save it here.\n                    if (!jQueryInstance && window['jQuery']) {\n                        jQueryInstance = window['jQuery'];\n                    }\n\n                    if (arguments.length < 2) {\n                        rootNode = document.body;\n                        if (!rootNode) {\n                            throw Error(\"ko.applyBindings: could not find document.body; has the document been loaded?\");\n                        }\n                    } else if (!rootNode || (rootNode.nodeType !== 1 && rootNode.nodeType !== 8)) {\n                        throw Error(\"ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node\");\n                    }\n\n                    applyBindingsToNodeAndDescendantsInternal(getBindingContext(viewModelOrBindingContext, extendContextCallback), rootNode);\n                };\n\n                // Retrieving binding context from arbitrary nodes\n                ko.contextFor = function(node) {\n                    // We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)\n                    if (node && (node.nodeType === 1 || node.nodeType === 8)) {\n                        return ko.storedBindingContextForNode(node);\n                    }\n                    return undefined;\n                };\n                ko.dataFor = function(node) {\n                    var context = ko.contextFor(node);\n                    return context ? context['$data'] : undefined;\n                };\n\n                ko.exportSymbol('bindingHandlers', ko.bindingHandlers);\n                ko.exportSymbol('bindingEvent', ko.bindingEvent);\n                ko.exportSymbol('bindingEvent.subscribe', ko.bindingEvent.subscribe);\n                ko.exportSymbol('bindingEvent.startPossiblyAsyncContentBinding', ko.bindingEvent.startPossiblyAsyncContentBinding);\n                ko.exportSymbol('applyBindings', ko.applyBindings);\n                ko.exportSymbol('applyBindingsToDescendants', ko.applyBindingsToDescendants);\n                ko.exportSymbol('applyBindingAccessorsToNode', ko.applyBindingAccessorsToNode);\n                ko.exportSymbol('applyBindingsToNode', ko.applyBindingsToNode);\n                ko.exportSymbol('contextFor', ko.contextFor);\n                ko.exportSymbol('dataFor', ko.dataFor);\n            })();\n            (function(undefined) {\n                var loadingSubscribablesCache = {}, // Tracks component loads that are currently in flight\n                    loadedDefinitionsCache = {};    // Tracks component loads that have already completed\n\n                ko.components = {\n                    get: function(componentName, callback) {\n                        var cachedDefinition = getObjectOwnProperty(loadedDefinitionsCache, componentName);\n                        if (cachedDefinition) {\n                            // It's already loaded and cached. Reuse the same definition object.\n                            // Note that for API consistency, even cache hits complete asynchronously by default.\n                            // You can bypass this by putting synchronous:true on your component config.\n                            if (cachedDefinition.isSynchronousComponent) {\n                                ko.dependencyDetection.ignore(function() { // See comment in loaderRegistryBehaviors.js for reasoning\n                                    callback(cachedDefinition.definition);\n                                });\n                            } else {\n                                ko.tasks.schedule(function() { callback(cachedDefinition.definition); });\n                            }\n                        } else {\n                            // Join the loading process that is already underway, or start a new one.\n                            loadComponentAndNotify(componentName, callback);\n                        }\n                    },\n\n                    clearCachedDefinition: function(componentName) {\n                        delete loadedDefinitionsCache[componentName];\n                    },\n\n                    _getFirstResultFromLoaders: getFirstResultFromLoaders\n                };\n\n                function getObjectOwnProperty(obj, propName) {\n                    return Object.prototype.hasOwnProperty.call(obj, propName) ? obj[propName] : undefined;\n                }\n\n                function loadComponentAndNotify(componentName, callback) {\n                    var subscribable = getObjectOwnProperty(loadingSubscribablesCache, componentName),\n                        completedAsync;\n                    if (!subscribable) {\n                        // It's not started loading yet. Start loading, and when it's done, move it to loadedDefinitionsCache.\n                        subscribable = loadingSubscribablesCache[componentName] = new ko.subscribable();\n                        subscribable.subscribe(callback);\n\n                        beginLoadingComponent(componentName, function(definition, config) {\n                            var isSynchronousComponent = !!(config && config['synchronous']);\n                            loadedDefinitionsCache[componentName] = { definition: definition, isSynchronousComponent: isSynchronousComponent };\n                            delete loadingSubscribablesCache[componentName];\n\n                            // For API consistency, all loads complete asynchronously. However we want to avoid\n                            // adding an extra task schedule if it's unnecessary (i.e., the completion is already\n                            // async).\n                            //\n                            // You can bypass the 'always asynchronous' feature by putting the synchronous:true\n                            // flag on your component configuration when you register it.\n                            if (completedAsync || isSynchronousComponent) {\n                                // Note that notifySubscribers ignores any dependencies read within the callback.\n                                // See comment in loaderRegistryBehaviors.js for reasoning\n                                subscribable['notifySubscribers'](definition);\n                            } else {\n                                ko.tasks.schedule(function() {\n                                    subscribable['notifySubscribers'](definition);\n                                });\n                            }\n                        });\n                        completedAsync = true;\n                    } else {\n                        subscribable.subscribe(callback);\n                    }\n                }\n\n                function beginLoadingComponent(componentName, callback) {\n                    getFirstResultFromLoaders('getConfig', [componentName], function(config) {\n                        if (config) {\n                            // We have a config, so now load its definition\n                            getFirstResultFromLoaders('loadComponent', [componentName, config], function(definition) {\n                                callback(definition, config);\n                            });\n                        } else {\n                            // The component has no config - it's unknown to all the loaders.\n                            // Note that this is not an error (e.g., a module loading error) - that would abort the\n                            // process and this callback would not run. For this callback to run, all loaders must\n                            // have confirmed they don't know about this component.\n                            callback(null, null);\n                        }\n                    });\n                }\n\n                function getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders) {\n                    // On the first call in the stack, start with the full set of loaders\n                    if (!candidateLoaders) {\n                        candidateLoaders = ko.components['loaders'].slice(0); // Use a copy, because we'll be mutating this array\n                    }\n\n                    // Try the next candidate\n                    var currentCandidateLoader = candidateLoaders.shift();\n                    if (currentCandidateLoader) {\n                        var methodInstance = currentCandidateLoader[methodName];\n                        if (methodInstance) {\n                            var wasAborted = false,\n                                synchronousReturnValue = methodInstance.apply(currentCandidateLoader, argsExceptCallback.concat(function(result) {\n                                    if (wasAborted) {\n                                        callback(null);\n                                    } else if (result !== null) {\n                                        // This candidate returned a value. Use it.\n                                        callback(result);\n                                    } else {\n                                        // Try the next candidate\n                                        getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders);\n                                    }\n                                }));\n\n                            // Currently, loaders may not return anything synchronously. This leaves open the possibility\n                            // that we'll extend the API to support synchronous return values in the future. It won't be\n                            // a breaking change, because currently no loader is allowed to return anything except undefined.\n                            if (synchronousReturnValue !== undefined) {\n                                wasAborted = true;\n\n                                // Method to suppress exceptions will remain undocumented. This is only to keep\n                                // KO's specs running tidily, since we can observe the loading got aborted without\n                                // having exceptions cluttering up the console too.\n                                if (!currentCandidateLoader['suppressLoaderExceptions']) {\n                                    throw new Error('Component loaders must supply values by invoking the callback, not by returning values synchronously.');\n                                }\n                            }\n                        } else {\n                            // This candidate doesn't have the relevant handler. Synchronously move on to the next one.\n                            getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders);\n                        }\n                    } else {\n                        // No candidates returned a value\n                        callback(null);\n                    }\n                }\n\n                // Reference the loaders via string name so it's possible for developers\n                // to replace the whole array by assigning to ko.components.loaders\n                ko.components['loaders'] = [];\n\n                ko.exportSymbol('components', ko.components);\n                ko.exportSymbol('components.get', ko.components.get);\n                ko.exportSymbol('components.clearCachedDefinition', ko.components.clearCachedDefinition);\n            })();\n            (function(undefined) {\n\n                // The default loader is responsible for two things:\n                // 1. Maintaining the default in-memory registry of component configuration objects\n                //    (i.e., the thing you're writing to when you call ko.components.register(someName, ...))\n                // 2. Answering requests for components by fetching configuration objects\n                //    from that default in-memory registry and resolving them into standard\n                //    component definition objects (of the form { createViewModel: ..., template: ... })\n                // Custom loaders may override either of these facilities, i.e.,\n                // 1. To supply configuration objects from some other source (e.g., conventions)\n                // 2. Or, to resolve configuration objects by loading viewmodels/templates via arbitrary logic.\n\n                var defaultConfigRegistry = {};\n\n                ko.components.register = function(componentName, config) {\n                    if (!config) {\n                        throw new Error('Invalid configuration for ' + componentName);\n                    }\n\n                    if (ko.components.isRegistered(componentName)) {\n                        throw new Error('Component ' + componentName + ' is already registered');\n                    }\n\n                    defaultConfigRegistry[componentName] = config;\n                };\n\n                ko.components.isRegistered = function(componentName) {\n                    return Object.prototype.hasOwnProperty.call(defaultConfigRegistry, componentName);\n                };\n\n                ko.components.unregister = function(componentName) {\n                    delete defaultConfigRegistry[componentName];\n                    ko.components.clearCachedDefinition(componentName);\n                };\n\n                ko.components.defaultLoader = {\n                    'getConfig': function(componentName, callback) {\n                        var result = ko.components.isRegistered(componentName)\n                            ? defaultConfigRegistry[componentName]\n                            : null;\n                        callback(result);\n                    },\n\n                    'loadComponent': function(componentName, config, callback) {\n                        var errorCallback = makeErrorCallback(componentName);\n                        possiblyGetConfigFromAmd(errorCallback, config, function(loadedConfig) {\n                            resolveConfig(componentName, errorCallback, loadedConfig, callback);\n                        });\n                    },\n\n                    'loadTemplate': function(componentName, templateConfig, callback) {\n                        resolveTemplate(makeErrorCallback(componentName), templateConfig, callback);\n                    },\n\n                    'loadViewModel': function(componentName, viewModelConfig, callback) {\n                        resolveViewModel(makeErrorCallback(componentName), viewModelConfig, callback);\n                    }\n                };\n\n                var createViewModelKey = 'createViewModel';\n\n                // Takes a config object of the form { template: ..., viewModel: ... }, and asynchronously convert it\n                // into the standard component definition format:\n                //    { template: <ArrayOfDomNodes>, createViewModel: function(params, componentInfo) { ... } }.\n                // Since both template and viewModel may need to be resolved asynchronously, both tasks are performed\n                // in parallel, and the results joined when both are ready. We don't depend on any promises infrastructure,\n                // so this is implemented manually below.\n                function resolveConfig(componentName, errorCallback, config, callback) {\n                    var result = {},\n                        makeCallBackWhenZero = 2,\n                        tryIssueCallback = function() {\n                            if (--makeCallBackWhenZero === 0) {\n                                callback(result);\n                            }\n                        },\n                        templateConfig = config['template'],\n                        viewModelConfig = config['viewModel'];\n\n                    if (templateConfig) {\n                        possiblyGetConfigFromAmd(errorCallback, templateConfig, function(loadedConfig) {\n                            ko.components._getFirstResultFromLoaders('loadTemplate', [componentName, loadedConfig], function(resolvedTemplate) {\n                                result['template'] = resolvedTemplate;\n                                tryIssueCallback();\n                            });\n                        });\n                    } else {\n                        tryIssueCallback();\n                    }\n\n                    if (viewModelConfig) {\n                        possiblyGetConfigFromAmd(errorCallback, viewModelConfig, function(loadedConfig) {\n                            ko.components._getFirstResultFromLoaders('loadViewModel', [componentName, loadedConfig], function(resolvedViewModel) {\n                                result[createViewModelKey] = resolvedViewModel;\n                                tryIssueCallback();\n                            });\n                        });\n                    } else {\n                        tryIssueCallback();\n                    }\n                }\n\n                function resolveTemplate(errorCallback, templateConfig, callback) {\n                    if (typeof templateConfig === 'string') {\n                        // Markup - parse it\n                        callback(ko.utils.parseHtmlFragment(templateConfig));\n                    } else if (templateConfig instanceof Array) {\n                        // Assume already an array of DOM nodes - pass through unchanged\n                        callback(templateConfig);\n                    } else if (isDocumentFragment(templateConfig)) {\n                        // Document fragment - use its child nodes\n                        callback(ko.utils.makeArray(templateConfig.childNodes));\n                    } else if (templateConfig['element']) {\n                        var element = templateConfig['element'];\n                        if (isDomElement(element)) {\n                            // Element instance - copy its child nodes\n                            callback(cloneNodesFromTemplateSourceElement(element));\n                        } else if (typeof element === 'string') {\n                            // Element ID - find it, then copy its child nodes\n                            var elemInstance = document.getElementById(element);\n                            if (elemInstance) {\n                                callback(cloneNodesFromTemplateSourceElement(elemInstance));\n                            } else {\n                                errorCallback('Cannot find element with ID ' + element);\n                            }\n                        } else {\n                            errorCallback('Unknown element type: ' + element);\n                        }\n                    } else {\n                        errorCallback('Unknown template value: ' + templateConfig);\n                    }\n                }\n\n                function resolveViewModel(errorCallback, viewModelConfig, callback) {\n                    if (typeof viewModelConfig === 'function') {\n                        // Constructor - convert to standard factory function format\n                        // By design, this does *not* supply componentInfo to the constructor, as the intent is that\n                        // componentInfo contains non-viewmodel data (e.g., the component's element) that should only\n                        // be used in factory functions, not viewmodel constructors.\n                        callback(function (params /*, componentInfo */) {\n                            return new viewModelConfig(params);\n                        });\n                    } else if (typeof viewModelConfig[createViewModelKey] === 'function') {\n                        // Already a factory function - use it as-is\n                        callback(viewModelConfig[createViewModelKey]);\n                    } else if ('instance' in viewModelConfig) {\n                        // Fixed object instance - promote to createViewModel format for API consistency\n                        var fixedInstance = viewModelConfig['instance'];\n                        callback(function (params, componentInfo) {\n                            return fixedInstance;\n                        });\n                    } else if ('viewModel' in viewModelConfig) {\n                        // Resolved AMD module whose value is of the form { viewModel: ... }\n                        resolveViewModel(errorCallback, viewModelConfig['viewModel'], callback);\n                    } else {\n                        errorCallback('Unknown viewModel value: ' + viewModelConfig);\n                    }\n                }\n\n                function cloneNodesFromTemplateSourceElement(elemInstance) {\n                    switch (ko.utils.tagNameLower(elemInstance)) {\n                        case 'script':\n                            return ko.utils.parseHtmlFragment(elemInstance.text);\n                        case 'textarea':\n                            return ko.utils.parseHtmlFragment(elemInstance.value);\n                        case 'template':\n                            // For browsers with proper <template> element support (i.e., where the .content property\n                            // gives a document fragment), use that document fragment.\n                            if (isDocumentFragment(elemInstance.content)) {\n                                return ko.utils.cloneNodes(elemInstance.content.childNodes);\n                            }\n                    }\n\n                    // Regular elements such as <div>, and <template> elements on old browsers that don't really\n                    // understand <template> and just treat it as a regular container\n                    return ko.utils.cloneNodes(elemInstance.childNodes);\n                }\n\n                function isDomElement(obj) {\n                    if (window['HTMLElement']) {\n                        return obj instanceof HTMLElement;\n                    } else {\n                        return obj && obj.tagName && obj.nodeType === 1;\n                    }\n                }\n\n                function isDocumentFragment(obj) {\n                    if (window['DocumentFragment']) {\n                        return obj instanceof DocumentFragment;\n                    } else {\n                        return obj && obj.nodeType === 11;\n                    }\n                }\n\n                function possiblyGetConfigFromAmd(errorCallback, config, callback) {\n                    if (typeof config['require'] === 'string') {\n                        // The config is the value of an AMD module\n                        if (amdRequire || window['require']) {\n                            (amdRequire || window['require'])([config['require']], function (module) {\n                                if (module && typeof module === 'object' && module.__esModule && module.default) {\n                                    module = module.default;\n                                }\n                                callback(module);\n                            });\n                        } else {\n                            errorCallback('Uses require, but no AMD loader is present');\n                        }\n                    } else {\n                        callback(config);\n                    }\n                }\n\n                function makeErrorCallback(componentName) {\n                    return function (message) {\n                        throw new Error('Component \\'' + componentName + '\\': ' + message);\n                    };\n                }\n\n                ko.exportSymbol('components.register', ko.components.register);\n                ko.exportSymbol('components.isRegistered', ko.components.isRegistered);\n                ko.exportSymbol('components.unregister', ko.components.unregister);\n\n                // Expose the default loader so that developers can directly ask it for configuration\n                // or to resolve configuration\n                ko.exportSymbol('components.defaultLoader', ko.components.defaultLoader);\n\n                // By default, the default loader is the only registered component loader\n                ko.components['loaders'].push(ko.components.defaultLoader);\n\n                // Privately expose the underlying config registry for use in old-IE shim\n                ko.components._allRegisteredComponents = defaultConfigRegistry;\n            })();\n            (function (undefined) {\n                // Overridable API for determining which component name applies to a given node. By overriding this,\n                // you can for example map specific tagNames to components that are not preregistered.\n                ko.components['getComponentNameForNode'] = function(node) {\n                    var tagNameLower = ko.utils.tagNameLower(node);\n                    if (ko.components.isRegistered(tagNameLower)) {\n                        // Try to determine that this node can be considered a *custom* element; see https://github.com/knockout/knockout/issues/1603\n                        if (tagNameLower.indexOf('-') != -1 || ('' + node) == \"[object HTMLUnknownElement]\" || (ko.utils.ieVersion <= 8 && node.tagName === tagNameLower)) {\n                            return tagNameLower;\n                        }\n                    }\n                };\n\n                ko.components.addBindingsForCustomElement = function(allBindings, node, bindingContext, valueAccessors) {\n                    // Determine if it's really a custom element matching a component\n                    if (node.nodeType === 1) {\n                        var componentName = ko.components['getComponentNameForNode'](node);\n                        if (componentName) {\n                            // It does represent a component, so add a component binding for it\n                            allBindings = allBindings || {};\n\n                            if (allBindings['component']) {\n                                // Avoid silently overwriting some other 'component' binding that may already be on the element\n                                throw new Error('Cannot use the \"component\" binding on a custom element matching a component');\n                            }\n\n                            var componentBindingValue = { 'name': componentName, 'params': getComponentParamsFromCustomElement(node, bindingContext) };\n\n                            allBindings['component'] = valueAccessors\n                                ? function() { return componentBindingValue; }\n                                : componentBindingValue;\n                        }\n                    }\n\n                    return allBindings;\n                }\n\n                var nativeBindingProviderInstance = new ko.bindingProvider();\n\n                function getComponentParamsFromCustomElement(elem, bindingContext) {\n                    var paramsAttribute = elem.getAttribute('params');\n\n                    if (paramsAttribute) {\n                        var params = nativeBindingProviderInstance['parseBindingsString'](paramsAttribute, bindingContext, elem, { 'valueAccessors': true, 'bindingParams': true }),\n                            rawParamComputedValues = ko.utils.objectMap(params, function(paramValue, paramName) {\n                                return ko.computed(paramValue, null, { disposeWhenNodeIsRemoved: elem });\n                            }),\n                            result = ko.utils.objectMap(rawParamComputedValues, function(paramValueComputed, paramName) {\n                                var paramValue = paramValueComputed.peek();\n                                // Does the evaluation of the parameter value unwrap any observables?\n                                if (!paramValueComputed.isActive()) {\n                                    // No it doesn't, so there's no need for any computed wrapper. Just pass through the supplied value directly.\n                                    // Example: \"someVal: firstName, age: 123\" (whether or not firstName is an observable/computed)\n                                    return paramValue;\n                                } else {\n                                    // Yes it does. Supply a computed property that unwraps both the outer (binding expression)\n                                    // level of observability, and any inner (resulting model value) level of observability.\n                                    // This means the component doesn't have to worry about multiple unwrapping. If the value is a\n                                    // writable observable, the computed will also be writable and pass the value on to the observable.\n                                    return ko.computed({\n                                        'read': function() {\n                                            return ko.utils.unwrapObservable(paramValueComputed());\n                                        },\n                                        'write': ko.isWriteableObservable(paramValue) && function(value) {\n                                            paramValueComputed()(value);\n                                        },\n                                        disposeWhenNodeIsRemoved: elem\n                                    });\n                                }\n                            });\n\n                        // Give access to the raw computeds, as long as that wouldn't overwrite any custom param also called '$raw'\n                        // This is in case the developer wants to react to outer (binding) observability separately from inner\n                        // (model value) observability, or in case the model value observable has subobservables.\n                        if (!Object.prototype.hasOwnProperty.call(result, '$raw')) {\n                            result['$raw'] = rawParamComputedValues;\n                        }\n\n                        return result;\n                    } else {\n                        // For consistency, absence of a \"params\" attribute is treated the same as the presence of\n                        // any empty one. Otherwise component viewmodels need special code to check whether or not\n                        // 'params' or 'params.$raw' is null/undefined before reading subproperties, which is annoying.\n                        return { '$raw': {} };\n                    }\n                }\n\n                // --------------------------------------------------------------------------------\n                // Compatibility code for older (pre-HTML5) IE browsers\n\n                if (ko.utils.ieVersion < 9) {\n                    // Whenever you preregister a component, enable it as a custom element in the current document\n                    ko.components['register'] = (function(originalFunction) {\n                        return function(componentName) {\n                            document.createElement(componentName); // Allows IE<9 to parse markup containing the custom element\n                            return originalFunction.apply(this, arguments);\n                        }\n                    })(ko.components['register']);\n\n                    // Whenever you create a document fragment, enable all preregistered component names as custom elements\n                    // This is needed to make innerShiv/jQuery HTML parsing correctly handle the custom elements\n                    document.createDocumentFragment = (function(originalFunction) {\n                        return function() {\n                            var newDocFrag = originalFunction(),\n                                allComponents = ko.components._allRegisteredComponents;\n                            for (var componentName in allComponents) {\n                                if (Object.prototype.hasOwnProperty.call(allComponents, componentName)) {\n                                    newDocFrag.createElement(componentName);\n                                }\n                            }\n                            return newDocFrag;\n                        };\n                    })(document.createDocumentFragment);\n                }\n            })();(function(undefined) {\n                var componentLoadingOperationUniqueId = 0;\n\n                ko.bindingHandlers['component'] = {\n                    'init': function(element, valueAccessor, ignored1, ignored2, bindingContext) {\n                        var currentViewModel,\n                            currentLoadingOperationId,\n                            afterRenderSub,\n                            disposeAssociatedComponentViewModel = function () {\n                                var currentViewModelDispose = currentViewModel && currentViewModel['dispose'];\n                                if (typeof currentViewModelDispose === 'function') {\n                                    currentViewModelDispose.call(currentViewModel);\n                                }\n                                if (afterRenderSub) {\n                                    afterRenderSub.dispose();\n                                }\n                                afterRenderSub = null;\n                                currentViewModel = null;\n                                // Any in-flight loading operation is no longer relevant, so make sure we ignore its completion\n                                currentLoadingOperationId = null;\n                            },\n                            originalChildNodes = ko.utils.makeArray(ko.virtualElements.childNodes(element));\n\n                        ko.virtualElements.emptyNode(element);\n                        ko.utils.domNodeDisposal.addDisposeCallback(element, disposeAssociatedComponentViewModel);\n\n                        ko.computed(function () {\n                            var value = ko.utils.unwrapObservable(valueAccessor()),\n                                componentName, componentParams;\n\n                            if (typeof value === 'string') {\n                                componentName = value;\n                            } else {\n                                componentName = ko.utils.unwrapObservable(value['name']);\n                                componentParams = ko.utils.unwrapObservable(value['params']);\n                            }\n\n                            if (!componentName) {\n                                throw new Error('No component name specified');\n                            }\n\n                            var asyncContext = ko.bindingEvent.startPossiblyAsyncContentBinding(element, bindingContext);\n\n                            var loadingOperationId = currentLoadingOperationId = ++componentLoadingOperationUniqueId;\n                            ko.components.get(componentName, function(componentDefinition) {\n                                // If this is not the current load operation for this element, ignore it.\n                                if (currentLoadingOperationId !== loadingOperationId) {\n                                    return;\n                                }\n\n                                // Clean up previous state\n                                disposeAssociatedComponentViewModel();\n\n                                // Instantiate and bind new component. Implicitly this cleans any old DOM nodes.\n                                if (!componentDefinition) {\n                                    throw new Error('Unknown component \\'' + componentName + '\\'');\n                                }\n                                cloneTemplateIntoElement(componentName, componentDefinition, element);\n\n                                var componentInfo = {\n                                    'element': element,\n                                    'templateNodes': originalChildNodes\n                                };\n\n                                var componentViewModel = createViewModel(componentDefinition, componentParams, componentInfo),\n                                    childBindingContext = asyncContext['createChildContext'](componentViewModel, {\n                                        'extend': function(ctx) {\n                                            ctx['$component'] = componentViewModel;\n                                            ctx['$componentTemplateNodes'] = originalChildNodes;\n                                        }\n                                    });\n\n                                if (componentViewModel && componentViewModel['koDescendantsComplete']) {\n                                    afterRenderSub = ko.bindingEvent.subscribe(element, ko.bindingEvent.descendantsComplete, componentViewModel['koDescendantsComplete'], componentViewModel);\n                                }\n\n                                currentViewModel = componentViewModel;\n                                ko.applyBindingsToDescendants(childBindingContext, element);\n                            });\n                        }, null, { disposeWhenNodeIsRemoved: element });\n\n                        return { 'controlsDescendantBindings': true };\n                    }\n                };\n\n                ko.virtualElements.allowedBindings['component'] = true;\n\n                function cloneTemplateIntoElement(componentName, componentDefinition, element) {\n                    var template = componentDefinition['template'];\n                    if (!template) {\n                        throw new Error('Component \\'' + componentName + '\\' has no template');\n                    }\n\n                    var clonedNodesArray = ko.utils.cloneNodes(template);\n                    ko.virtualElements.setDomNodeChildren(element, clonedNodesArray);\n                }\n\n                function createViewModel(componentDefinition, componentParams, componentInfo) {\n                    var componentViewModelFactory = componentDefinition['createViewModel'];\n                    return componentViewModelFactory\n                        ? componentViewModelFactory.call(componentDefinition, componentParams, componentInfo)\n                        : componentParams; // Template-only component\n                }\n\n            })();\n            var attrHtmlToJavaScriptMap = { 'class': 'className', 'for': 'htmlFor' };\n            ko.bindingHandlers['attr'] = {\n                'update': function(element, valueAccessor, allBindings) {\n                    var value = ko.utils.unwrapObservable(valueAccessor()) || {};\n                    ko.utils.objectForEach(value, function(attrName, attrValue) {\n                        attrValue = ko.utils.unwrapObservable(attrValue);\n\n                        // Find the namespace of this attribute, if any.\n                        var prefixLen = attrName.indexOf(':');\n                        var namespace = \"lookupNamespaceURI\" in element && prefixLen > 0 && element.lookupNamespaceURI(attrName.substr(0, prefixLen));\n\n                        // To cover cases like \"attr: { checked:someProp }\", we want to remove the attribute entirely\n                        // when someProp is a \"no value\"-like value (strictly null, false, or undefined)\n                        // (because the absence of the \"checked\" attr is how to mark an element as not checked, etc.)\n                        var toRemove = (attrValue === false) || (attrValue === null) || (attrValue === undefined);\n                        if (toRemove) {\n                            namespace ? element.removeAttributeNS(namespace, attrName) : element.removeAttribute(attrName);\n                        } else {\n                            attrValue = attrValue.toString();\n                        }\n\n                        // In IE <= 7 and IE8 Quirks Mode, you have to use the JavaScript property name instead of the\n                        // HTML attribute name for certain attributes. IE8 Standards Mode supports the correct behavior,\n                        // but instead of figuring out the mode, we'll just set the attribute through the JavaScript\n                        // property for IE <= 8.\n                        if (ko.utils.ieVersion <= 8 && attrName in attrHtmlToJavaScriptMap) {\n                            attrName = attrHtmlToJavaScriptMap[attrName];\n                            if (toRemove)\n                                element.removeAttribute(attrName);\n                            else\n                                element[attrName] = attrValue;\n                        } else if (!toRemove) {\n                            namespace ? element.setAttributeNS(namespace, attrName, attrValue) : element.setAttribute(attrName, attrValue);\n                        }\n\n                        // Treat \"name\" specially - although you can think of it as an attribute, it also needs\n                        // special handling on older versions of IE (https://github.com/SteveSanderson/knockout/pull/333)\n                        // Deliberately being case-sensitive here because XHTML would regard \"Name\" as a different thing\n                        // entirely, and there's no strong reason to allow for such casing in HTML.\n                        if (attrName === \"name\") {\n                            ko.utils.setElementName(element, toRemove ? \"\" : attrValue);\n                        }\n                    });\n                }\n            };\n            (function() {\n\n                ko.bindingHandlers['checked'] = {\n                    'after': ['value', 'attr'],\n                    'init': function (element, valueAccessor, allBindings) {\n                        var checkedValue = ko.pureComputed(function() {\n                            // Treat \"value\" like \"checkedValue\" when it is included with \"checked\" binding\n                            if (allBindings['has']('checkedValue')) {\n                                return ko.utils.unwrapObservable(allBindings.get('checkedValue'));\n                            } else if (useElementValue) {\n                                if (allBindings['has']('value')) {\n                                    return ko.utils.unwrapObservable(allBindings.get('value'));\n                                } else {\n                                    return element.value;\n                                }\n                            }\n                        });\n\n                        function updateModel() {\n                            // This updates the model value from the view value.\n                            // It runs in response to DOM events (click) and changes in checkedValue.\n                            var isChecked = element.checked,\n                                elemValue = checkedValue();\n\n                            // When we're first setting up this computed, don't change any model state.\n                            if (ko.computedContext.isInitial()) {\n                                return;\n                            }\n\n                            // We can ignore unchecked radio buttons, because some other radio\n                            // button will be checked, and that one can take care of updating state.\n                            // Also ignore value changes to an already unchecked checkbox.\n                            if (!isChecked && (isRadio || ko.computedContext.getDependenciesCount())) {\n                                return;\n                            }\n\n                            var modelValue = ko.dependencyDetection.ignore(valueAccessor);\n                            if (valueIsArray) {\n                                var writableValue = rawValueIsNonArrayObservable ? modelValue.peek() : modelValue,\n                                    saveOldValue = oldElemValue;\n                                oldElemValue = elemValue;\n\n                                if (saveOldValue !== elemValue) {\n                                    // When we're responding to the checkedValue changing, and the element is\n                                    // currently checked, replace the old elem value with the new elem value\n                                    // in the model array.\n                                    if (isChecked) {\n                                        ko.utils.addOrRemoveItem(writableValue, elemValue, true);\n                                        ko.utils.addOrRemoveItem(writableValue, saveOldValue, false);\n                                    }\n                                } else {\n                                    // When we're responding to the user having checked/unchecked a checkbox,\n                                    // add/remove the element value to the model array.\n                                    ko.utils.addOrRemoveItem(writableValue, elemValue, isChecked);\n                                }\n\n                                if (rawValueIsNonArrayObservable && ko.isWriteableObservable(modelValue)) {\n                                    modelValue(writableValue);\n                                }\n                            } else {\n                                if (isCheckbox) {\n                                    if (elemValue === undefined) {\n                                        elemValue = isChecked;\n                                    } else if (!isChecked) {\n                                        elemValue = undefined;\n                                    }\n                                }\n                                ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'checked', elemValue, true);\n                            }\n                        };\n\n                        function updateView() {\n                            // This updates the view value from the model value.\n                            // It runs in response to changes in the bound (checked) value.\n                            var modelValue = ko.utils.unwrapObservable(valueAccessor()),\n                                elemValue = checkedValue();\n\n                            if (valueIsArray) {\n                                // When a checkbox is bound to an array, being checked represents its value being present in that array\n                                element.checked = ko.utils.arrayIndexOf(modelValue, elemValue) >= 0;\n                                oldElemValue = elemValue;\n                            } else if (isCheckbox && elemValue === undefined) {\n                                // When a checkbox is bound to any other value (not an array) and \"checkedValue\" is not defined,\n                                // being checked represents the value being trueish\n                                element.checked = !!modelValue;\n                            } else {\n                                // Otherwise, being checked means that the checkbox or radio button's value corresponds to the model value\n                                element.checked = (checkedValue() === modelValue);\n                            }\n                        };\n\n                        var isCheckbox = element.type == \"checkbox\",\n                            isRadio = element.type == \"radio\";\n\n                        // Only bind to check boxes and radio buttons\n                        if (!isCheckbox && !isRadio) {\n                            return;\n                        }\n\n                        var rawValue = valueAccessor(),\n                            valueIsArray = isCheckbox && (ko.utils.unwrapObservable(rawValue) instanceof Array),\n                            rawValueIsNonArrayObservable = !(valueIsArray && rawValue.push && rawValue.splice),\n                            useElementValue = isRadio || valueIsArray,\n                            oldElemValue = valueIsArray ? checkedValue() : undefined;\n\n                        // IE 6 won't allow radio buttons to be selected unless they have a name\n                        if (isRadio && !element.name)\n                            ko.bindingHandlers['uniqueName']['init'](element, function() { return true });\n\n                        // Set up two computeds to update the binding:\n\n                        // The first responds to changes in the checkedValue value and to element clicks\n                        ko.computed(updateModel, null, { disposeWhenNodeIsRemoved: element });\n                        ko.utils.registerEventHandler(element, \"click\", updateModel);\n\n                        // The second responds to changes in the model value (the one associated with the checked binding)\n                        ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element });\n\n                        rawValue = undefined;\n                    }\n                };\n                ko.expressionRewriting.twoWayBindings['checked'] = true;\n\n                ko.bindingHandlers['checkedValue'] = {\n                    'update': function (element, valueAccessor) {\n                        element.value = ko.utils.unwrapObservable(valueAccessor());\n                    }\n                };\n\n            })();var classesWrittenByBindingKey = '__ko__cssValue';\n            ko.bindingHandlers['class'] = {\n                'update': function (element, valueAccessor) {\n                    var value = ko.utils.stringTrim(ko.utils.unwrapObservable(valueAccessor()));\n                    ko.utils.toggleDomNodeCssClass(element, element[classesWrittenByBindingKey], false);\n                    element[classesWrittenByBindingKey] = value;\n                    ko.utils.toggleDomNodeCssClass(element, value, true);\n                }\n            };\n\n            ko.bindingHandlers['css'] = {\n                'update': function (element, valueAccessor) {\n                    var value = ko.utils.unwrapObservable(valueAccessor());\n                    if (value !== null && typeof value == \"object\") {\n                        ko.utils.objectForEach(value, function(className, shouldHaveClass) {\n                            shouldHaveClass = ko.utils.unwrapObservable(shouldHaveClass);\n                            ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);\n                        });\n                    } else {\n                        ko.bindingHandlers['class']['update'](element, valueAccessor);\n                    }\n                }\n            };\n            ko.bindingHandlers['enable'] = {\n                'update': function (element, valueAccessor) {\n                    var value = ko.utils.unwrapObservable(valueAccessor());\n                    if (value && element.disabled)\n                        element.removeAttribute(\"disabled\");\n                    else if ((!value) && (!element.disabled))\n                        element.disabled = true;\n                }\n            };\n\n            ko.bindingHandlers['disable'] = {\n                'update': function (element, valueAccessor) {\n                    ko.bindingHandlers['enable']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });\n                }\n            };\n// For certain common events (currently just 'click'), allow a simplified data-binding syntax\n// e.g. click:handler instead of the usual full-length event:{click:handler}\n            function makeEventHandlerShortcut(eventName) {\n                ko.bindingHandlers[eventName] = {\n                    'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                        var newValueAccessor = function () {\n                            var result = {};\n                            result[eventName] = valueAccessor();\n                            return result;\n                        };\n                        return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindings, viewModel, bindingContext);\n                    }\n                }\n            }\n\n            ko.bindingHandlers['event'] = {\n                'init' : function (element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    var eventsToHandle = valueAccessor() || {};\n                    ko.utils.objectForEach(eventsToHandle, function(eventName) {\n                        if (typeof eventName == \"string\") {\n                            ko.utils.registerEventHandler(element, eventName, function (event) {\n                                var handlerReturnValue;\n                                var handlerFunction = valueAccessor()[eventName];\n                                if (!handlerFunction)\n                                    return;\n\n                                try {\n                                    // Take all the event args, and prefix with the viewmodel\n                                    var argsForHandler = ko.utils.makeArray(arguments);\n                                    viewModel = bindingContext['$data'];\n                                    argsForHandler.unshift(viewModel);\n                                    handlerReturnValue = handlerFunction.apply(viewModel, argsForHandler);\n                                } finally {\n                                    if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.\n                                        if (event.preventDefault)\n                                            event.preventDefault();\n                                        else\n                                            event.returnValue = false;\n                                    }\n                                }\n\n                                var bubble = allBindings.get(eventName + 'Bubble') !== false;\n                                if (!bubble) {\n                                    event.cancelBubble = true;\n                                    if (event.stopPropagation)\n                                        event.stopPropagation();\n                                }\n                            });\n                        }\n                    });\n                }\n            };\n// \"foreach: someExpression\" is equivalent to \"template: { foreach: someExpression }\"\n// \"foreach: { data: someExpression, afterAdd: myfn }\" is equivalent to \"template: { foreach: someExpression, afterAdd: myfn }\"\n            ko.bindingHandlers['foreach'] = {\n                makeTemplateValueAccessor: function(valueAccessor) {\n                    return function() {\n                        var modelValue = valueAccessor(),\n                            unwrappedValue = ko.utils.peekObservable(modelValue);    // Unwrap without setting a dependency here\n\n                        // If unwrappedValue is the array, pass in the wrapped value on its own\n                        // The value will be unwrapped and tracked within the template binding\n                        // (See https://github.com/SteveSanderson/knockout/issues/523)\n                        if ((!unwrappedValue) || typeof unwrappedValue.length == \"number\")\n                            return { 'foreach': modelValue, 'templateEngine': ko.nativeTemplateEngine.instance };\n\n                        // If unwrappedValue.data is the array, preserve all relevant options and unwrap again value so we get updates\n                        ko.utils.unwrapObservable(modelValue);\n                        return {\n                            'foreach': unwrappedValue['data'],\n                            'as': unwrappedValue['as'],\n                            'noChildContext': unwrappedValue['noChildContext'],\n                            'includeDestroyed': unwrappedValue['includeDestroyed'],\n                            'afterAdd': unwrappedValue['afterAdd'],\n                            'beforeRemove': unwrappedValue['beforeRemove'],\n                            'afterRender': unwrappedValue['afterRender'],\n                            'beforeMove': unwrappedValue['beforeMove'],\n                            'afterMove': unwrappedValue['afterMove'],\n                            'templateEngine': ko.nativeTemplateEngine.instance\n                        };\n                    };\n                },\n                'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    return ko.bindingHandlers['template']['init'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor));\n                },\n                'update': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    return ko.bindingHandlers['template']['update'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor), allBindings, viewModel, bindingContext);\n                }\n            };\n            ko.expressionRewriting.bindingRewriteValidators['foreach'] = false; // Can't rewrite control flow bindings\n            ko.virtualElements.allowedBindings['foreach'] = true;\n            var hasfocusUpdatingProperty = '__ko_hasfocusUpdating';\n            var hasfocusLastValue = '__ko_hasfocusLastValue';\n            ko.bindingHandlers['hasfocus'] = {\n                'init': function(element, valueAccessor, allBindings) {\n                    var handleElementFocusChange = function(isFocused) {\n                        // Where possible, ignore which event was raised and determine focus state using activeElement,\n                        // as this avoids phantom focus/blur events raised when changing tabs in modern browsers.\n                        // However, not all KO-targeted browsers (Firefox 2) support activeElement. For those browsers,\n                        // prevent a loss of focus when changing tabs/windows by setting a flag that prevents hasfocus\n                        // from calling 'blur()' on the element when it loses focus.\n                        // Discussion at https://github.com/SteveSanderson/knockout/pull/352\n                        element[hasfocusUpdatingProperty] = true;\n                        var ownerDoc = element.ownerDocument;\n                        if (\"activeElement\" in ownerDoc) {\n                            var active;\n                            try {\n                                active = ownerDoc.activeElement;\n                            } catch(e) {\n                                // IE9 throws if you access activeElement during page load (see issue #703)\n                                active = ownerDoc.body;\n                            }\n                            isFocused = (active === element);\n                        }\n                        var modelValue = valueAccessor();\n                        ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'hasfocus', isFocused, true);\n\n                        //cache the latest value, so we can avoid unnecessarily calling focus/blur in the update function\n                        element[hasfocusLastValue] = isFocused;\n                        element[hasfocusUpdatingProperty] = false;\n                    };\n                    var handleElementFocusIn = handleElementFocusChange.bind(null, true);\n                    var handleElementFocusOut = handleElementFocusChange.bind(null, false);\n\n                    ko.utils.registerEventHandler(element, \"focus\", handleElementFocusIn);\n                    ko.utils.registerEventHandler(element, \"focusin\", handleElementFocusIn); // For IE\n                    ko.utils.registerEventHandler(element, \"blur\",  handleElementFocusOut);\n                    ko.utils.registerEventHandler(element, \"focusout\",  handleElementFocusOut); // For IE\n\n                    // Assume element is not focused (prevents \"blur\" being called initially)\n                    element[hasfocusLastValue] = false;\n                },\n                'update': function(element, valueAccessor) {\n                    var value = !!ko.utils.unwrapObservable(valueAccessor());\n\n                    if (!element[hasfocusUpdatingProperty] && element[hasfocusLastValue] !== value) {\n                        value ? element.focus() : element.blur();\n\n                        // In IE, the blur method doesn't always cause the element to lose focus (for example, if the window is not in focus).\n                        // Setting focus to the body element does seem to be reliable in IE, but should only be used if we know that the current\n                        // element was focused already.\n                        if (!value && element[hasfocusLastValue]) {\n                            element.ownerDocument.body.focus();\n                        }\n\n                        // For IE, which doesn't reliably fire \"focus\" or \"blur\" events synchronously\n                        ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, value ? \"focusin\" : \"focusout\"]);\n                    }\n                }\n            };\n            ko.expressionRewriting.twoWayBindings['hasfocus'] = true;\n\n            ko.bindingHandlers['hasFocus'] = ko.bindingHandlers['hasfocus']; // Make \"hasFocus\" an alias\n            ko.expressionRewriting.twoWayBindings['hasFocus'] = 'hasfocus';\n            ko.bindingHandlers['html'] = {\n                'init': function() {\n                    // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)\n                    return { 'controlsDescendantBindings': true };\n                },\n                'update': function (element, valueAccessor) {\n                    // setHtml will unwrap the value if needed\n                    ko.utils.setHtml(element, valueAccessor());\n                }\n            };\n            (function () {\n\n// Makes a binding like with or if\n                function makeWithIfBinding(bindingKey, isWith, isNot) {\n                    ko.bindingHandlers[bindingKey] = {\n                        'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                            var didDisplayOnLastUpdate, savedNodes, contextOptions = {}, completeOnRender, needAsyncContext, renderOnEveryChange;\n\n                            if (isWith) {\n                                var as = allBindings.get('as'), noChildContext = allBindings.get('noChildContext');\n                                renderOnEveryChange = !(as && noChildContext);\n                                contextOptions = { 'as': as, 'noChildContext': noChildContext, 'exportDependencies': renderOnEveryChange };\n                            }\n\n                            completeOnRender = allBindings.get(\"completeOn\") == \"render\";\n                            needAsyncContext = completeOnRender || allBindings['has'](ko.bindingEvent.descendantsComplete);\n\n                            ko.computed(function() {\n                                var value = ko.utils.unwrapObservable(valueAccessor()),\n                                    shouldDisplay = !isNot !== !value, // equivalent to isNot ? !value : !!value,\n                                    isInitial = !savedNodes,\n                                    childContext;\n\n                                if (!renderOnEveryChange && shouldDisplay === didDisplayOnLastUpdate) {\n                                    return;\n                                }\n\n                                if (needAsyncContext) {\n                                    bindingContext = ko.bindingEvent.startPossiblyAsyncContentBinding(element, bindingContext);\n                                }\n\n                                if (shouldDisplay) {\n                                    if (!isWith || renderOnEveryChange) {\n                                        contextOptions['dataDependency'] = ko.computedContext.computed();\n                                    }\n\n                                    if (isWith) {\n                                        childContext = bindingContext['createChildContext'](typeof value == \"function\" ? value : valueAccessor, contextOptions);\n                                    } else if (ko.computedContext.getDependenciesCount()) {\n                                        childContext = bindingContext['extend'](null, contextOptions);\n                                    } else {\n                                        childContext = bindingContext;\n                                    }\n                                }\n\n                                // Save a copy of the inner nodes on the initial update, but only if we have dependencies.\n                                if (isInitial && ko.computedContext.getDependenciesCount()) {\n                                    savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element), true /* shouldCleanNodes */);\n                                }\n\n                                if (shouldDisplay) {\n                                    if (!isInitial) {\n                                        ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(savedNodes));\n                                    }\n\n                                    ko.applyBindingsToDescendants(childContext, element);\n                                } else {\n                                    ko.virtualElements.emptyNode(element);\n\n                                    if (!completeOnRender) {\n                                        ko.bindingEvent.notify(element, ko.bindingEvent.childrenComplete);\n                                    }\n                                }\n\n                                didDisplayOnLastUpdate = shouldDisplay;\n\n                            }, null, { disposeWhenNodeIsRemoved: element });\n\n                            return { 'controlsDescendantBindings': true };\n                        }\n                    };\n                    ko.expressionRewriting.bindingRewriteValidators[bindingKey] = false; // Can't rewrite control flow bindings\n                    ko.virtualElements.allowedBindings[bindingKey] = true;\n                }\n\n// Construct the actual binding handlers\n                makeWithIfBinding('if');\n                makeWithIfBinding('ifnot', false /* isWith */, true /* isNot */);\n                makeWithIfBinding('with', true /* isWith */);\n\n            })();ko.bindingHandlers['let'] = {\n                'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    // Make a modified binding context, with extra properties, and apply it to descendant elements\n                    var innerContext = bindingContext['extend'](valueAccessor);\n                    ko.applyBindingsToDescendants(innerContext, element);\n\n                    return { 'controlsDescendantBindings': true };\n                }\n            };\n            ko.virtualElements.allowedBindings['let'] = true;\n            var captionPlaceholder = {};\n            ko.bindingHandlers['options'] = {\n                'init': function(element) {\n                    if (ko.utils.tagNameLower(element) !== \"select\")\n                        throw new Error(\"options binding applies only to SELECT elements\");\n\n                    // Remove all existing <option>s.\n                    while (element.length > 0) {\n                        element.remove(0);\n                    }\n\n                    // Ensures that the binding processor doesn't try to bind the options\n                    return { 'controlsDescendantBindings': true };\n                },\n                'update': function (element, valueAccessor, allBindings) {\n                    function selectedOptions() {\n                        return ko.utils.arrayFilter(element.options, function (node) { return node.selected; });\n                    }\n\n                    var selectWasPreviouslyEmpty = element.length == 0,\n                        multiple = element.multiple,\n                        previousScrollTop = (!selectWasPreviouslyEmpty && multiple) ? element.scrollTop : null,\n                        unwrappedArray = ko.utils.unwrapObservable(valueAccessor()),\n                        valueAllowUnset = allBindings.get('valueAllowUnset') && allBindings['has']('value'),\n                        includeDestroyed = allBindings.get('optionsIncludeDestroyed'),\n                        arrayToDomNodeChildrenOptions = {},\n                        captionValue,\n                        filteredArray,\n                        previousSelectedValues = [];\n\n                    if (!valueAllowUnset) {\n                        if (multiple) {\n                            previousSelectedValues = ko.utils.arrayMap(selectedOptions(), ko.selectExtensions.readValue);\n                        } else if (element.selectedIndex >= 0) {\n                            previousSelectedValues.push(ko.selectExtensions.readValue(element.options[element.selectedIndex]));\n                        }\n                    }\n\n                    if (unwrappedArray) {\n                        if (typeof unwrappedArray.length == \"undefined\") // Coerce single value into array\n                            unwrappedArray = [unwrappedArray];\n\n                        // Filter out any entries marked as destroyed\n                        filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {\n                            return includeDestroyed || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);\n                        });\n\n                        // If caption is included, add it to the array\n                        if (allBindings['has']('optionsCaption')) {\n                            captionValue = ko.utils.unwrapObservable(allBindings.get('optionsCaption'));\n                            // If caption value is null or undefined, don't show a caption\n                            if (captionValue !== null && captionValue !== undefined) {\n                                filteredArray.unshift(captionPlaceholder);\n                            }\n                        }\n                    } else {\n                        // If a falsy value is provided (e.g. null), we'll simply empty the select element\n                    }\n\n                    function applyToObject(object, predicate, defaultValue) {\n                        var predicateType = typeof predicate;\n                        if (predicateType == \"function\")    // Given a function; run it against the data value\n                            return predicate(object);\n                        else if (predicateType == \"string\") // Given a string; treat it as a property name on the data value\n                            return object[predicate];\n                        else                                // Given no optionsText arg; use the data value itself\n                            return defaultValue;\n                    }\n\n                    // The following functions can run at two different times:\n                    // The first is when the whole array is being updated directly from this binding handler.\n                    // The second is when an observable value for a specific array entry is updated.\n                    // oldOptions will be empty in the first case, but will be filled with the previously generated option in the second.\n                    var itemUpdate = false;\n                    function optionForArrayItem(arrayEntry, index, oldOptions) {\n                        if (oldOptions.length) {\n                            previousSelectedValues = !valueAllowUnset && oldOptions[0].selected ? [ ko.selectExtensions.readValue(oldOptions[0]) ] : [];\n                            itemUpdate = true;\n                        }\n                        var option = element.ownerDocument.createElement(\"option\");\n                        if (arrayEntry === captionPlaceholder) {\n                            ko.utils.setTextContent(option, allBindings.get('optionsCaption'));\n                            ko.selectExtensions.writeValue(option, undefined);\n                        } else {\n                            // Apply a value to the option element\n                            var optionValue = applyToObject(arrayEntry, allBindings.get('optionsValue'), arrayEntry);\n                            ko.selectExtensions.writeValue(option, ko.utils.unwrapObservable(optionValue));\n\n                            // Apply some text to the option element\n                            var optionText = applyToObject(arrayEntry, allBindings.get('optionsText'), optionValue);\n                            ko.utils.setTextContent(option, optionText);\n                        }\n                        return [option];\n                    }\n\n                    // By using a beforeRemove callback, we delay the removal until after new items are added. This fixes a selection\n                    // problem in IE<=8 and Firefox. See https://github.com/knockout/knockout/issues/1208\n                    arrayToDomNodeChildrenOptions['beforeRemove'] =\n                        function (option) {\n                            element.removeChild(option);\n                        };\n\n                    function setSelectionCallback(arrayEntry, newOptions) {\n                        if (itemUpdate && valueAllowUnset) {\n                            // The model value is authoritative, so make sure its value is the one selected\n                            ko.bindingEvent.notify(element, ko.bindingEvent.childrenComplete);\n                        } else if (previousSelectedValues.length) {\n                            // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.\n                            // That's why we first added them without selection. Now it's time to set the selection.\n                            var isSelected = ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[0])) >= 0;\n                            ko.utils.setOptionNodeSelectionState(newOptions[0], isSelected);\n\n                            // If this option was changed from being selected during a single-item update, notify the change\n                            if (itemUpdate && !isSelected) {\n                                ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, \"change\"]);\n                            }\n                        }\n                    }\n\n                    var callback = setSelectionCallback;\n                    if (allBindings['has']('optionsAfterRender') && typeof allBindings.get('optionsAfterRender') == \"function\") {\n                        callback = function(arrayEntry, newOptions) {\n                            setSelectionCallback(arrayEntry, newOptions);\n                            ko.dependencyDetection.ignore(allBindings.get('optionsAfterRender'), null, [newOptions[0], arrayEntry !== captionPlaceholder ? arrayEntry : undefined]);\n                        }\n                    }\n\n                    ko.utils.setDomNodeChildrenFromArrayMapping(element, filteredArray, optionForArrayItem, arrayToDomNodeChildrenOptions, callback);\n\n                    if (!valueAllowUnset) {\n                        // Determine if the selection has changed as a result of updating the options list\n                        var selectionChanged;\n                        if (multiple) {\n                            // For a multiple-select box, compare the new selection count to the previous one\n                            // But if nothing was selected before, the selection can't have changed\n                            selectionChanged = previousSelectedValues.length && selectedOptions().length < previousSelectedValues.length;\n                        } else {\n                            // For a single-select box, compare the current value to the previous value\n                            // But if nothing was selected before or nothing is selected now, just look for a change in selection\n                            selectionChanged = (previousSelectedValues.length && element.selectedIndex >= 0)\n                                ? (ko.selectExtensions.readValue(element.options[element.selectedIndex]) !== previousSelectedValues[0])\n                                : (previousSelectedValues.length || element.selectedIndex >= 0);\n                        }\n\n                        // Ensure consistency between model value and selected option.\n                        // If the dropdown was changed so that selection is no longer the same,\n                        // notify the value or selectedOptions binding.\n                        if (selectionChanged) {\n                            ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, \"change\"]);\n                        }\n                    }\n\n                    if (valueAllowUnset || ko.computedContext.isInitial()) {\n                        ko.bindingEvent.notify(element, ko.bindingEvent.childrenComplete);\n                    }\n\n                    // Workaround for IE bug\n                    ko.utils.ensureSelectElementIsRenderedCorrectly(element);\n\n                    if (previousScrollTop && Math.abs(previousScrollTop - element.scrollTop) > 20)\n                        element.scrollTop = previousScrollTop;\n                }\n            };\n            ko.bindingHandlers['options'].optionValueDomDataKey = ko.utils.domData.nextKey();\n            ko.bindingHandlers['selectedOptions'] = {\n                'init': function (element, valueAccessor, allBindings) {\n                    function updateFromView() {\n                        var value = valueAccessor(), valueToWrite = [];\n                        ko.utils.arrayForEach(element.getElementsByTagName(\"option\"), function(node) {\n                            if (node.selected)\n                                valueToWrite.push(ko.selectExtensions.readValue(node));\n                        });\n                        ko.expressionRewriting.writeValueToProperty(value, allBindings, 'selectedOptions', valueToWrite);\n                    }\n\n                    function updateFromModel() {\n                        var newValue = ko.utils.unwrapObservable(valueAccessor()),\n                            previousScrollTop = element.scrollTop;\n\n                        if (newValue && typeof newValue.length == \"number\") {\n                            ko.utils.arrayForEach(element.getElementsByTagName(\"option\"), function(node) {\n                                var isSelected = ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0;\n                                if (node.selected != isSelected) {      // This check prevents flashing of the select element in IE\n                                    ko.utils.setOptionNodeSelectionState(node, isSelected);\n                                }\n                            });\n                        }\n\n                        element.scrollTop = previousScrollTop;\n                    }\n\n                    if (ko.utils.tagNameLower(element) != \"select\") {\n                        throw new Error(\"selectedOptions binding applies only to SELECT elements\");\n                    }\n\n                    var updateFromModelComputed;\n                    ko.bindingEvent.subscribe(element, ko.bindingEvent.childrenComplete, function () {\n                        if (!updateFromModelComputed) {\n                            ko.utils.registerEventHandler(element, \"change\", updateFromView);\n                            updateFromModelComputed = ko.computed(updateFromModel, null, { disposeWhenNodeIsRemoved: element });\n                        } else {\n                            updateFromView();\n                        }\n                    }, null, { 'notifyImmediately': true });\n                },\n                'update': function() {} // Keep for backwards compatibility with code that may have wrapped binding\n            };\n            ko.expressionRewriting.twoWayBindings['selectedOptions'] = true;\n            ko.bindingHandlers['style'] = {\n                'update': function (element, valueAccessor) {\n                    var value = ko.utils.unwrapObservable(valueAccessor() || {});\n                    ko.utils.objectForEach(value, function(styleName, styleValue) {\n                        styleValue = ko.utils.unwrapObservable(styleValue);\n\n                        if (styleValue === null || styleValue === undefined || styleValue === false) {\n                            // Empty string removes the value, whereas null/undefined have no effect\n                            styleValue = \"\";\n                        }\n\n                        if (jQueryInstance) {\n                            jQueryInstance(element)['css'](styleName, styleValue);\n                        } else if (/^--/.test(styleName)) {\n                            // Is styleName a custom CSS property?\n                            element.style.setProperty(styleName, styleValue);\n                        } else {\n                            styleName = styleName.replace(/-(\\w)/g, function (all, letter) {\n                                return letter.toUpperCase();\n                            });\n\n                            var previousStyle = element.style[styleName];\n                            element.style[styleName] = styleValue;\n\n                            if (styleValue !== previousStyle && element.style[styleName] == previousStyle && !isNaN(styleValue)) {\n                                element.style[styleName] = styleValue + \"px\";\n                            }\n                        }\n                    });\n                }\n            };\n            ko.bindingHandlers['submit'] = {\n                'init': function (element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    if (typeof valueAccessor() != \"function\")\n                        throw new Error(\"The value for a submit binding must be a function\");\n                    ko.utils.registerEventHandler(element, \"submit\", function (event) {\n                        var handlerReturnValue;\n                        var value = valueAccessor();\n                        try { handlerReturnValue = value.call(bindingContext['$data'], element); }\n                        finally {\n                            if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.\n                                if (event.preventDefault)\n                                    event.preventDefault();\n                                else\n                                    event.returnValue = false;\n                            }\n                        }\n                    });\n                }\n            };\n            ko.bindingHandlers['text'] = {\n                'init': function() {\n                    // Prevent binding on the dynamically-injected text node (as developers are unlikely to expect that, and it has security implications).\n                    // It should also make things faster, as we no longer have to consider whether the text node might be bindable.\n                    return { 'controlsDescendantBindings': true };\n                },\n                'update': function (element, valueAccessor) {\n                    ko.utils.setTextContent(element, valueAccessor());\n                }\n            };\n            ko.virtualElements.allowedBindings['text'] = true;\n            (function () {\n\n                if (window && window.navigator) {\n                    var parseVersion = function (matches) {\n                        if (matches) {\n                            return parseFloat(matches[1]);\n                        }\n                    };\n\n                    // Detect various browser versions because some old versions don't fully support the 'input' event\n                    var userAgent = window.navigator.userAgent,\n                        operaVersion, chromeVersion, safariVersion, firefoxVersion, ieVersion, edgeVersion;\n\n                    (operaVersion = window.opera && window.opera.version && parseInt(window.opera.version()))\n                    || (edgeVersion = parseVersion(userAgent.match(/Edge\\/([^ ]+)$/)))\n                    || (chromeVersion = parseVersion(userAgent.match(/Chrome\\/([^ ]+)/)))\n                    || (safariVersion = parseVersion(userAgent.match(/Version\\/([^ ]+) Safari/)))\n                    || (firefoxVersion = parseVersion(userAgent.match(/Firefox\\/([^ ]+)/)))\n                    || (ieVersion = ko.utils.ieVersion || parseVersion(userAgent.match(/MSIE ([^ ]+)/)))      // Detects up to IE 10\n                    || (ieVersion = parseVersion(userAgent.match(/rv:([^ )]+)/)));      // Detects IE 11\n                }\n\n// IE 8 and 9 have bugs that prevent the normal events from firing when the value changes.\n// But it does fire the 'selectionchange' event on many of those, presumably because the\n// cursor is moving and that counts as the selection changing. The 'selectionchange' event is\n// fired at the document level only and doesn't directly indicate which element changed. We\n// set up just one event handler for the document and use 'activeElement' to determine which\n// element was changed.\n                if (ieVersion >= 8 && ieVersion < 10) {\n                    var selectionChangeRegisteredName = ko.utils.domData.nextKey(),\n                        selectionChangeHandlerName = ko.utils.domData.nextKey();\n                    var selectionChangeHandler = function(event) {\n                        var target = this.activeElement,\n                            handler = target && ko.utils.domData.get(target, selectionChangeHandlerName);\n                        if (handler) {\n                            handler(event);\n                        }\n                    };\n                    var registerForSelectionChangeEvent = function (element, handler) {\n                        var ownerDoc = element.ownerDocument;\n                        if (!ko.utils.domData.get(ownerDoc, selectionChangeRegisteredName)) {\n                            ko.utils.domData.set(ownerDoc, selectionChangeRegisteredName, true);\n                            ko.utils.registerEventHandler(ownerDoc, 'selectionchange', selectionChangeHandler);\n                        }\n                        ko.utils.domData.set(element, selectionChangeHandlerName, handler);\n                    };\n                }\n\n                ko.bindingHandlers['textInput'] = {\n                    'init': function (element, valueAccessor, allBindings) {\n\n                        var previousElementValue = element.value,\n                            timeoutHandle,\n                            elementValueBeforeEvent;\n\n                        var updateModel = function (event) {\n                            clearTimeout(timeoutHandle);\n                            elementValueBeforeEvent = timeoutHandle = undefined;\n\n                            var elementValue = element.value;\n                            if (previousElementValue !== elementValue) {\n                                // Provide a way for tests to know exactly which event was processed\n                                if (DEBUG && event) element['_ko_textInputProcessedEvent'] = event.type;\n                                previousElementValue = elementValue;\n                                ko.expressionRewriting.writeValueToProperty(valueAccessor(), allBindings, 'textInput', elementValue);\n                            }\n                        };\n\n                        var deferUpdateModel = function (event) {\n                            if (!timeoutHandle) {\n                                // The elementValueBeforeEvent variable is set *only* during the brief gap between an\n                                // event firing and the updateModel function running. This allows us to ignore model\n                                // updates that are from the previous state of the element, usually due to techniques\n                                // such as rateLimit. Such updates, if not ignored, can cause keystrokes to be lost.\n                                elementValueBeforeEvent = element.value;\n                                var handler = DEBUG ? updateModel.bind(element, {type: event.type}) : updateModel;\n                                timeoutHandle = ko.utils.setTimeout(handler, 4);\n                            }\n                        };\n\n                        // IE9 will mess up the DOM if you handle events synchronously which results in DOM changes (such as other bindings);\n                        // so we'll make sure all updates are asynchronous\n                        var ieUpdateModel = ko.utils.ieVersion == 9 ? deferUpdateModel : updateModel,\n                            ourUpdate = false;\n\n                        var updateView = function () {\n                            var modelValue = ko.utils.unwrapObservable(valueAccessor());\n\n                            if (modelValue === null || modelValue === undefined) {\n                                modelValue = '';\n                            }\n\n                            if (elementValueBeforeEvent !== undefined && modelValue === elementValueBeforeEvent) {\n                                ko.utils.setTimeout(updateView, 4);\n                                return;\n                            }\n\n                            // Update the element only if the element and model are different. On some browsers, updating the value\n                            // will move the cursor to the end of the input, which would be bad while the user is typing.\n                            if (element.value !== modelValue) {\n                                ourUpdate = true;  // Make sure we ignore events (propertychange) that result from updating the value\n                                element.value = modelValue;\n                                ourUpdate = false;\n                                previousElementValue = element.value; // In case the browser changes the value (see #2281)\n                            }\n                        };\n\n                        var onEvent = function (event, handler) {\n                            ko.utils.registerEventHandler(element, event, handler);\n                        };\n\n                        if (DEBUG && ko.bindingHandlers['textInput']['_forceUpdateOn']) {\n                            // Provide a way for tests to specify exactly which events are bound\n                            ko.utils.arrayForEach(ko.bindingHandlers['textInput']['_forceUpdateOn'], function(eventName) {\n                                if (eventName.slice(0,5) == 'after') {\n                                    onEvent(eventName.slice(5), deferUpdateModel);\n                                } else {\n                                    onEvent(eventName, updateModel);\n                                }\n                            });\n                        } else {\n                            if (ieVersion) {\n                                // All versions (including 11) of Internet Explorer have a bug that they don't generate an input or propertychange event when ESC is pressed\n                                onEvent('keypress', updateModel);\n                            }\n                            if (ieVersion < 11) {\n                                // Internet Explorer <= 8 doesn't support the 'input' event, but does include 'propertychange' that fires whenever\n                                // any property of an element changes. Unlike 'input', it also fires if a property is changed from JavaScript code,\n                                // but that's an acceptable compromise for this binding. IE 9 and 10 support 'input', but since they don't always\n                                // fire it when using autocomplete, we'll use 'propertychange' for them also.\n                                onEvent('propertychange', function(event) {\n                                    if (!ourUpdate && event.propertyName === 'value') {\n                                        ieUpdateModel(event);\n                                    }\n                                });\n                            }\n                            if (ieVersion == 8) {\n                                // IE 8 has a bug where it fails to fire 'propertychange' on the first update following a value change from\n                                // JavaScript code. It also doesn't fire if you clear the entire value. To fix this, we bind to the following\n                                // events too.\n                                onEvent('keyup', updateModel);      // A single keystoke\n                                onEvent('keydown', updateModel);    // The first character when a key is held down\n                            }\n                            if (registerForSelectionChangeEvent) {\n                                // Internet Explorer 9 doesn't fire the 'input' event when deleting text, including using\n                                // the backspace, delete, or ctrl-x keys, clicking the 'x' to clear the input, dragging text\n                                // out of the field, and cutting or deleting text using the context menu. 'selectionchange'\n                                // can detect all of those except dragging text out of the field, for which we use 'dragend'.\n                                // These are also needed in IE8 because of the bug described above.\n                                registerForSelectionChangeEvent(element, ieUpdateModel);  // 'selectionchange' covers cut, paste, drop, delete, etc.\n                                onEvent('dragend', deferUpdateModel);\n                            }\n\n                            if (!ieVersion || ieVersion >= 9) {\n                                // All other supported browsers support the 'input' event, which fires whenever the content of the element is changed\n                                // through the user interface.\n                                onEvent('input', ieUpdateModel);\n                            }\n\n                            if (safariVersion < 5 && ko.utils.tagNameLower(element) === \"textarea\") {\n                                // Safari <5 doesn't fire the 'input' event for <textarea> elements (it does fire 'textInput'\n                                // but only when typing). So we'll just catch as much as we can with keydown, cut, and paste.\n                                onEvent('keydown', deferUpdateModel);\n                                onEvent('paste', deferUpdateModel);\n                                onEvent('cut', deferUpdateModel);\n                            } else if (operaVersion < 11) {\n                                // Opera 10 doesn't always fire the 'input' event for cut, paste, undo & drop operations.\n                                // We can try to catch some of those using 'keydown'.\n                                onEvent('keydown', deferUpdateModel);\n                            } else if (firefoxVersion < 4.0) {\n                                // Firefox <= 3.6 doesn't fire the 'input' event when text is filled in through autocomplete\n                                onEvent('DOMAutoComplete', updateModel);\n\n                                // Firefox <=3.5 doesn't fire the 'input' event when text is dropped into the input.\n                                onEvent('dragdrop', updateModel);       // <3.5\n                                onEvent('drop', updateModel);           // 3.5\n                            } else if (edgeVersion && element.type === \"number\") {\n                                // Microsoft Edge doesn't fire 'input' or 'change' events for number inputs when\n                                // the value is changed via the up / down arrow keys\n                                onEvent('keydown', deferUpdateModel);\n                            }\n                        }\n\n                        // Bind to the change event so that we can catch programmatic updates of the value that fire this event.\n                        onEvent('change', updateModel);\n\n                        // To deal with browsers that don't notify any kind of event for some changes (IE, Safari, etc.)\n                        onEvent('blur', updateModel);\n\n                        ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element });\n                    }\n                };\n                ko.expressionRewriting.twoWayBindings['textInput'] = true;\n\n// textinput is an alias for textInput\n                ko.bindingHandlers['textinput'] = {\n                    // preprocess is the only way to set up a full alias\n                    'preprocess': function (value, name, addBinding) {\n                        addBinding('textInput', value);\n                    }\n                };\n\n            })();ko.bindingHandlers['uniqueName'] = {\n                'init': function (element, valueAccessor) {\n                    if (valueAccessor()) {\n                        var name = \"ko_unique_\" + (++ko.bindingHandlers['uniqueName'].currentIndex);\n                        ko.utils.setElementName(element, name);\n                    }\n                }\n            };\n            ko.bindingHandlers['uniqueName'].currentIndex = 0;\n            ko.bindingHandlers['using'] = {\n                'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    var options;\n\n                    if (allBindings['has']('as')) {\n                        options = { 'as': allBindings.get('as'), 'noChildContext': allBindings.get('noChildContext') };\n                    }\n\n                    var innerContext = bindingContext['createChildContext'](valueAccessor, options);\n                    ko.applyBindingsToDescendants(innerContext, element);\n\n                    return { 'controlsDescendantBindings': true };\n                }\n            };\n            ko.virtualElements.allowedBindings['using'] = true;\n            ko.bindingHandlers['value'] = {\n                'init': function (element, valueAccessor, allBindings) {\n                    var tagName = ko.utils.tagNameLower(element),\n                        isInputElement = tagName == \"input\";\n\n                    // If the value binding is placed on a radio/checkbox, then just pass through to checkedValue and quit\n                    if (isInputElement && (element.type == \"checkbox\" || element.type == \"radio\")) {\n                        ko.applyBindingAccessorsToNode(element, { 'checkedValue': valueAccessor });\n                        return;\n                    }\n\n                    var eventsToCatch = [];\n                    var requestedEventsToCatch = allBindings.get(\"valueUpdate\");\n                    var propertyChangedFired = false;\n                    var elementValueBeforeEvent = null;\n\n                    if (requestedEventsToCatch) {\n                        // Allow both individual event names, and arrays of event names\n                        if (typeof requestedEventsToCatch == \"string\") {\n                            eventsToCatch = [requestedEventsToCatch];\n                        } else {\n                            eventsToCatch = ko.utils.arrayGetDistinctValues(requestedEventsToCatch);\n                        }\n                        ko.utils.arrayRemoveItem(eventsToCatch, \"change\");  // We'll subscribe to \"change\" events later\n                    }\n\n                    var valueUpdateHandler = function() {\n                        elementValueBeforeEvent = null;\n                        propertyChangedFired = false;\n                        var modelValue = valueAccessor();\n                        var elementValue = ko.selectExtensions.readValue(element);\n                        ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'value', elementValue);\n                    }\n\n                    // Workaround for https://github.com/SteveSanderson/knockout/issues/122\n                    // IE doesn't fire \"change\" events on textboxes if the user selects a value from its autocomplete list\n                    var ieAutoCompleteHackNeeded = ko.utils.ieVersion && isInputElement && element.type == \"text\"\n                        && element.autocomplete != \"off\" && (!element.form || element.form.autocomplete != \"off\");\n                    if (ieAutoCompleteHackNeeded && ko.utils.arrayIndexOf(eventsToCatch, \"propertychange\") == -1) {\n                        ko.utils.registerEventHandler(element, \"propertychange\", function () { propertyChangedFired = true });\n                        ko.utils.registerEventHandler(element, \"focus\", function () { propertyChangedFired = false });\n                        ko.utils.registerEventHandler(element, \"blur\", function() {\n                            if (propertyChangedFired) {\n                                valueUpdateHandler();\n                            }\n                        });\n                    }\n\n                    ko.utils.arrayForEach(eventsToCatch, function(eventName) {\n                        // The syntax \"after<eventname>\" means \"run the handler asynchronously after the event\"\n                        // This is useful, for example, to catch \"keydown\" events after the browser has updated the control\n                        // (otherwise, ko.selectExtensions.readValue(this) will receive the control's value *before* the key event)\n                        var handler = valueUpdateHandler;\n                        if (ko.utils.stringStartsWith(eventName, \"after\")) {\n                            handler = function() {\n                                // The elementValueBeforeEvent variable is non-null *only* during the brief gap between\n                                // a keyX event firing and the valueUpdateHandler running, which is scheduled to happen\n                                // at the earliest asynchronous opportunity. We store this temporary information so that\n                                // if, between keyX and valueUpdateHandler, the underlying model value changes separately,\n                                // we can overwrite that model value change with the value the user just typed. Otherwise,\n                                // techniques like rateLimit can trigger model changes at critical moments that will\n                                // override the user's inputs, causing keystrokes to be lost.\n                                elementValueBeforeEvent = ko.selectExtensions.readValue(element);\n                                ko.utils.setTimeout(valueUpdateHandler, 0);\n                            };\n                            eventName = eventName.substring(\"after\".length);\n                        }\n                        ko.utils.registerEventHandler(element, eventName, handler);\n                    });\n\n                    var updateFromModel;\n\n                    if (isInputElement && element.type == \"file\") {\n                        // For file input elements, can only write the empty string\n                        updateFromModel = function () {\n                            var newValue = ko.utils.unwrapObservable(valueAccessor());\n                            if (newValue === null || newValue === undefined || newValue === \"\") {\n                                element.value = \"\";\n                            } else {\n                                ko.dependencyDetection.ignore(valueUpdateHandler);  // reset the model to match the element\n                            }\n                        }\n                    } else {\n                        updateFromModel = function () {\n                            var newValue = ko.utils.unwrapObservable(valueAccessor());\n                            var elementValue = ko.selectExtensions.readValue(element);\n\n                            if (elementValueBeforeEvent !== null && newValue === elementValueBeforeEvent) {\n                                ko.utils.setTimeout(updateFromModel, 0);\n                                return;\n                            }\n\n                            var valueHasChanged = newValue !== elementValue;\n\n                            if (valueHasChanged || elementValue === undefined) {\n                                if (tagName === \"select\") {\n                                    var allowUnset = allBindings.get('valueAllowUnset');\n                                    ko.selectExtensions.writeValue(element, newValue, allowUnset);\n                                    if (!allowUnset && newValue !== ko.selectExtensions.readValue(element)) {\n                                        // If you try to set a model value that can't be represented in an already-populated dropdown, reject that change,\n                                        // because you're not allowed to have a model value that disagrees with a visible UI selection.\n                                        ko.dependencyDetection.ignore(valueUpdateHandler);\n                                    }\n                                } else {\n                                    ko.selectExtensions.writeValue(element, newValue);\n                                }\n                            }\n                        };\n                    }\n\n                    if (tagName === \"select\") {\n                        var updateFromModelComputed;\n                        ko.bindingEvent.subscribe(element, ko.bindingEvent.childrenComplete, function () {\n                            if (!updateFromModelComputed) {\n                                ko.utils.registerEventHandler(element, \"change\", valueUpdateHandler);\n                                updateFromModelComputed = ko.computed(updateFromModel, null, { disposeWhenNodeIsRemoved: element });\n                            } else if (allBindings.get('valueAllowUnset')) {\n                                updateFromModel();\n                            } else {\n                                valueUpdateHandler();\n                            }\n                        }, null, { 'notifyImmediately': true });\n                    } else {\n                        ko.utils.registerEventHandler(element, \"change\", valueUpdateHandler);\n                        ko.computed(updateFromModel, null, { disposeWhenNodeIsRemoved: element });\n                    }\n                },\n                'update': function() {} // Keep for backwards compatibility with code that may have wrapped value binding\n            };\n            ko.expressionRewriting.twoWayBindings['value'] = true;\n            ko.bindingHandlers['visible'] = {\n                'update': function (element, valueAccessor) {\n                    var value = ko.utils.unwrapObservable(valueAccessor());\n                    var isCurrentlyVisible = !(element.style.display == \"none\");\n                    if (value && !isCurrentlyVisible)\n                        element.style.display = \"\";\n                    else if ((!value) && isCurrentlyVisible)\n                        element.style.display = \"none\";\n                }\n            };\n\n            ko.bindingHandlers['hidden'] = {\n                'update': function (element, valueAccessor) {\n                    ko.bindingHandlers['visible']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });\n                }\n            };\n// 'click' is just a shorthand for the usual full-length event:{click:handler}\n            makeEventHandlerShortcut('click');\n// If you want to make a custom template engine,\n//\n// [1] Inherit from this class (like ko.nativeTemplateEngine does)\n// [2] Override 'renderTemplateSource', supplying a function with this signature:\n//\n//        function (templateSource, bindingContext, options) {\n//            // - templateSource.text() is the text of the template you should render\n//            // - bindingContext.$data is the data you should pass into the template\n//            //   - you might also want to make bindingContext.$parent, bindingContext.$parents,\n//            //     and bindingContext.$root available in the template too\n//            // - options gives you access to any other properties set on \"data-bind: { template: options }\"\n//            // - templateDocument is the document object of the template\n//            //\n//            // Return value: an array of DOM nodes\n//        }\n//\n// [3] Override 'createJavaScriptEvaluatorBlock', supplying a function with this signature:\n//\n//        function (script) {\n//            // Return value: Whatever syntax means \"Evaluate the JavaScript statement 'script' and output the result\"\n//            //               For example, the jquery.tmpl template engine converts 'someScript' to '${ someScript }'\n//        }\n//\n//     This is only necessary if you want to allow data-bind attributes to reference arbitrary template variables.\n//     If you don't want to allow that, you can set the property 'allowTemplateRewriting' to false (like ko.nativeTemplateEngine does)\n//     and then you don't need to override 'createJavaScriptEvaluatorBlock'.\n\n            ko.templateEngine = function () { };\n\n            ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options, templateDocument) {\n                throw new Error(\"Override renderTemplateSource\");\n            };\n\n            ko.templateEngine.prototype['createJavaScriptEvaluatorBlock'] = function (script) {\n                throw new Error(\"Override createJavaScriptEvaluatorBlock\");\n            };\n\n            ko.templateEngine.prototype['makeTemplateSource'] = function(template, templateDocument) {\n                // Named template\n                if (typeof template == \"string\") {\n                    templateDocument = templateDocument || document;\n                    var elem = templateDocument.getElementById(template);\n                    if (!elem)\n                        throw new Error(\"Cannot find template with ID \" + template);\n                    return new ko.templateSources.domElement(elem);\n                } else if ((template.nodeType == 1) || (template.nodeType == 8)) {\n                    // Anonymous template\n                    return new ko.templateSources.anonymousTemplate(template);\n                } else\n                    throw new Error(\"Unknown template type: \" + template);\n            };\n\n            ko.templateEngine.prototype['renderTemplate'] = function (template, bindingContext, options, templateDocument) {\n                var templateSource = this['makeTemplateSource'](template, templateDocument);\n                return this['renderTemplateSource'](templateSource, bindingContext, options, templateDocument);\n            };\n\n            ko.templateEngine.prototype['isTemplateRewritten'] = function (template, templateDocument) {\n                // Skip rewriting if requested\n                if (this['allowTemplateRewriting'] === false)\n                    return true;\n                return this['makeTemplateSource'](template, templateDocument)['data'](\"isRewritten\");\n            };\n\n            ko.templateEngine.prototype['rewriteTemplate'] = function (template, rewriterCallback, templateDocument) {\n                var templateSource = this['makeTemplateSource'](template, templateDocument);\n                var rewritten = rewriterCallback(templateSource['text']());\n                templateSource['text'](rewritten);\n                templateSource['data'](\"isRewritten\", true);\n            };\n\n            ko.exportSymbol('templateEngine', ko.templateEngine);\n\n            ko.templateRewriting = (function () {\n                var memoizeDataBindingAttributeSyntaxRegex = /(<([a-z]+\\d*)(?:\\s+(?!data-bind\\s*=\\s*)[a-z0-9\\-]+(?:=(?:\\\"[^\\\"]*\\\"|\\'[^\\']*\\'|[^>]*))?)*\\s+)data-bind\\s*=\\s*([\"'])([\\s\\S]*?)\\3/gi;\n                var memoizeVirtualContainerBindingSyntaxRegex = /<!--\\s*ko\\b\\s*([\\s\\S]*?)\\s*-->/g;\n\n                function validateDataBindValuesForRewriting(keyValueArray) {\n                    var allValidators = ko.expressionRewriting.bindingRewriteValidators;\n                    for (var i = 0; i < keyValueArray.length; i++) {\n                        var key = keyValueArray[i]['key'];\n                        if (Object.prototype.hasOwnProperty.call(allValidators, key)) {\n                            var validator = allValidators[key];\n\n                            if (typeof validator === \"function\") {\n                                var possibleErrorMessage = validator(keyValueArray[i]['value']);\n                                if (possibleErrorMessage)\n                                    throw new Error(possibleErrorMessage);\n                            } else if (!validator) {\n                                throw new Error(\"This template engine does not support the '\" + key + \"' binding within its templates\");\n                            }\n                        }\n                    }\n                }\n\n                function constructMemoizedTagReplacement(dataBindAttributeValue, tagToRetain, nodeName, templateEngine) {\n                    var dataBindKeyValueArray = ko.expressionRewriting.parseObjectLiteral(dataBindAttributeValue);\n                    validateDataBindValuesForRewriting(dataBindKeyValueArray);\n                    var rewrittenDataBindAttributeValue = ko.expressionRewriting.preProcessBindings(dataBindKeyValueArray, {'valueAccessors':true});\n\n                    // For no obvious reason, Opera fails to evaluate rewrittenDataBindAttributeValue unless it's wrapped in an additional\n                    // anonymous function, even though Opera's built-in debugger can evaluate it anyway. No other browser requires this\n                    // extra indirection.\n                    var applyBindingsToNextSiblingScript =\n                        \"ko.__tr_ambtns(function($context,$element){return(function(){return{ \" + rewrittenDataBindAttributeValue + \" } })()},'\" + nodeName.toLowerCase() + \"')\";\n                    return templateEngine['createJavaScriptEvaluatorBlock'](applyBindingsToNextSiblingScript) + tagToRetain;\n                }\n\n                return {\n                    ensureTemplateIsRewritten: function (template, templateEngine, templateDocument) {\n                        if (!templateEngine['isTemplateRewritten'](template, templateDocument))\n                            templateEngine['rewriteTemplate'](template, function (htmlString) {\n                                return ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine);\n                            }, templateDocument);\n                    },\n\n                    memoizeBindingAttributeSyntax: function (htmlString, templateEngine) {\n                        return htmlString.replace(memoizeDataBindingAttributeSyntaxRegex, function () {\n                            return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[4], /* tagToRetain: */ arguments[1], /* nodeName: */ arguments[2], templateEngine);\n                        }).replace(memoizeVirtualContainerBindingSyntaxRegex, function() {\n                            return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[1], /* tagToRetain: */ \"<!-- ko -->\", /* nodeName: */ \"#comment\", templateEngine);\n                        });\n                    },\n\n                    applyMemoizedBindingsToNextSibling: function (bindings, nodeName) {\n                        return ko.memoization.memoize(function (domNode, bindingContext) {\n                            var nodeToBind = domNode.nextSibling;\n                            if (nodeToBind && nodeToBind.nodeName.toLowerCase() === nodeName) {\n                                ko.applyBindingAccessorsToNode(nodeToBind, bindings, bindingContext);\n                            }\n                        });\n                    }\n                }\n            })();\n\n\n// Exported only because it has to be referenced by string lookup from within rewritten template\n            ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextSibling);\n            (function() {\n                // A template source represents a read/write way of accessing a template. This is to eliminate the need for template loading/saving\n                // logic to be duplicated in every template engine (and means they can all work with anonymous templates, etc.)\n                //\n                // Two are provided by default:\n                //  1. ko.templateSources.domElement       - reads/writes the text content of an arbitrary DOM element\n                //  2. ko.templateSources.anonymousElement - uses ko.utils.domData to read/write text *associated* with the DOM element, but\n                //                                           without reading/writing the actual element text content, since it will be overwritten\n                //                                           with the rendered template output.\n                // You can implement your own template source if you want to fetch/store templates somewhere other than in DOM elements.\n                // Template sources need to have the following functions:\n                //   text() \t\t\t- returns the template text from your storage location\n                //   text(value)\t\t- writes the supplied template text to your storage location\n                //   data(key)\t\t\t- reads values stored using data(key, value) - see below\n                //   data(key, value)\t- associates \"value\" with this template and the key \"key\". Is used to store information like \"isRewritten\".\n                //\n                // Optionally, template sources can also have the following functions:\n                //   nodes()            - returns a DOM element containing the nodes of this template, where available\n                //   nodes(value)       - writes the given DOM element to your storage location\n                // If a DOM element is available for a given template source, template engines are encouraged to use it in preference over text()\n                // for improved speed. However, all templateSources must supply text() even if they don't supply nodes().\n                //\n                // Once you've implemented a templateSource, make your template engine use it by subclassing whatever template engine you were\n                // using and overriding \"makeTemplateSource\" to return an instance of your custom template source.\n\n                ko.templateSources = {};\n\n                // ---- ko.templateSources.domElement -----\n\n                // template types\n                var templateScript = 1,\n                    templateTextArea = 2,\n                    templateTemplate = 3,\n                    templateElement = 4;\n\n                ko.templateSources.domElement = function(element) {\n                    this.domElement = element;\n\n                    if (element) {\n                        var tagNameLower = ko.utils.tagNameLower(element);\n                        this.templateType =\n                            tagNameLower === \"script\" ? templateScript :\n                                tagNameLower === \"textarea\" ? templateTextArea :\n                                    // For browsers with proper <template> element support, where the .content property gives a document fragment\n                                    tagNameLower == \"template\" && element.content && element.content.nodeType === 11 ? templateTemplate :\n                                        templateElement;\n                    }\n                }\n\n                ko.templateSources.domElement.prototype['text'] = function(/* valueToWrite */) {\n                    var elemContentsProperty = this.templateType === templateScript ? \"text\"\n                        : this.templateType === templateTextArea ? \"value\"\n                            : \"innerHTML\";\n\n                    if (arguments.length == 0) {\n                        return this.domElement[elemContentsProperty];\n                    } else {\n                        var valueToWrite = arguments[0];\n                        if (elemContentsProperty === \"innerHTML\")\n                            ko.utils.setHtml(this.domElement, valueToWrite);\n                        else\n                            this.domElement[elemContentsProperty] = valueToWrite;\n                    }\n                };\n\n                var dataDomDataPrefix = ko.utils.domData.nextKey() + \"_\";\n                ko.templateSources.domElement.prototype['data'] = function(key /*, valueToWrite */) {\n                    if (arguments.length === 1) {\n                        return ko.utils.domData.get(this.domElement, dataDomDataPrefix + key);\n                    } else {\n                        ko.utils.domData.set(this.domElement, dataDomDataPrefix + key, arguments[1]);\n                    }\n                };\n\n                var templatesDomDataKey = ko.utils.domData.nextKey();\n                function getTemplateDomData(element) {\n                    return ko.utils.domData.get(element, templatesDomDataKey) || {};\n                }\n                function setTemplateDomData(element, data) {\n                    ko.utils.domData.set(element, templatesDomDataKey, data);\n                }\n\n                ko.templateSources.domElement.prototype['nodes'] = function(/* valueToWrite */) {\n                    var element = this.domElement;\n                    if (arguments.length == 0) {\n                        var templateData = getTemplateDomData(element),\n                            nodes = templateData.containerData || (\n                                this.templateType === templateTemplate ? element.content :\n                                    this.templateType === templateElement ? element :\n                                        undefined);\n                        if (!nodes || templateData.alwaysCheckText) {\n                            // If the template is associated with an element that stores the template as text,\n                            // parse and cache the nodes whenever there's new text content available. This allows\n                            // the user to update the template content by updating the text of template node.\n                            var text = this['text']();\n                            if (text && text !== templateData.textData) {\n                                nodes = ko.utils.parseHtmlForTemplateNodes(text, element.ownerDocument);\n                                setTemplateDomData(element, {containerData: nodes, textData: text, alwaysCheckText: true});\n                            }\n                        }\n                        return nodes;\n                    } else {\n                        var valueToWrite = arguments[0];\n                        if (this.templateType !== undefined) {\n                            this['text'](\"\");   // clear the text from the node\n                        }\n                        setTemplateDomData(element, {containerData: valueToWrite});\n                    }\n                };\n\n                // ---- ko.templateSources.anonymousTemplate -----\n                // Anonymous templates are normally saved/retrieved as DOM nodes through \"nodes\".\n                // For compatibility, you can also read \"text\"; it will be serialized from the nodes on demand.\n                // Writing to \"text\" is still supported, but then the template data will not be available as DOM nodes.\n\n                ko.templateSources.anonymousTemplate = function(element) {\n                    this.domElement = element;\n                }\n                ko.templateSources.anonymousTemplate.prototype = new ko.templateSources.domElement();\n                ko.templateSources.anonymousTemplate.prototype.constructor = ko.templateSources.anonymousTemplate;\n                ko.templateSources.anonymousTemplate.prototype['text'] = function(/* valueToWrite */) {\n                    if (arguments.length == 0) {\n                        var templateData = getTemplateDomData(this.domElement);\n                        if (templateData.textData === undefined && templateData.containerData)\n                            templateData.textData = templateData.containerData.innerHTML;\n                        return templateData.textData;\n                    } else {\n                        var valueToWrite = arguments[0];\n                        setTemplateDomData(this.domElement, {textData: valueToWrite});\n                    }\n                };\n\n                ko.exportSymbol('templateSources', ko.templateSources);\n                ko.exportSymbol('templateSources.domElement', ko.templateSources.domElement);\n                ko.exportSymbol('templateSources.anonymousTemplate', ko.templateSources.anonymousTemplate);\n            })();\n            (function () {\n                var _templateEngine;\n                ko.setTemplateEngine = function (templateEngine) {\n                    if ((templateEngine != undefined) && !(templateEngine instanceof ko.templateEngine))\n                        throw new Error(\"templateEngine must inherit from ko.templateEngine\");\n                    _templateEngine = templateEngine;\n                }\n\n                function invokeForEachNodeInContinuousRange(firstNode, lastNode, action) {\n                    var node, nextInQueue = firstNode, firstOutOfRangeNode = ko.virtualElements.nextSibling(lastNode);\n                    while (nextInQueue && ((node = nextInQueue) !== firstOutOfRangeNode)) {\n                        nextInQueue = ko.virtualElements.nextSibling(node);\n                        action(node, nextInQueue);\n                    }\n                }\n\n                function activateBindingsOnContinuousNodeArray(continuousNodeArray, bindingContext) {\n                    // To be used on any nodes that have been rendered by a template and have been inserted into some parent element\n                    // Walks through continuousNodeArray (which *must* be continuous, i.e., an uninterrupted sequence of sibling nodes, because\n                    // the algorithm for walking them relies on this), and for each top-level item in the virtual-element sense,\n                    // (1) Does a regular \"applyBindings\" to associate bindingContext with this node and to activate any non-memoized bindings\n                    // (2) Unmemoizes any memos in the DOM subtree (e.g., to activate bindings that had been memoized during template rewriting)\n\n                    if (continuousNodeArray.length) {\n                        var firstNode = continuousNodeArray[0],\n                            lastNode = continuousNodeArray[continuousNodeArray.length - 1],\n                            parentNode = firstNode.parentNode,\n                            provider = ko.bindingProvider['instance'],\n                            preprocessNode = provider['preprocessNode'];\n\n                        if (preprocessNode) {\n                            invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node, nextNodeInRange) {\n                                var nodePreviousSibling = node.previousSibling;\n                                var newNodes = preprocessNode.call(provider, node);\n                                if (newNodes) {\n                                    if (node === firstNode)\n                                        firstNode = newNodes[0] || nextNodeInRange;\n                                    if (node === lastNode)\n                                        lastNode = newNodes[newNodes.length - 1] || nodePreviousSibling;\n                                }\n                            });\n\n                            // Because preprocessNode can change the nodes, including the first and last nodes, update continuousNodeArray to match.\n                            // We need the full set, including inner nodes, because the unmemoize step might remove the first node (and so the real\n                            // first node needs to be in the array).\n                            continuousNodeArray.length = 0;\n                            if (!firstNode) { // preprocessNode might have removed all the nodes, in which case there's nothing left to do\n                                return;\n                            }\n                            if (firstNode === lastNode) {\n                                continuousNodeArray.push(firstNode);\n                            } else {\n                                continuousNodeArray.push(firstNode, lastNode);\n                                ko.utils.fixUpContinuousNodeArray(continuousNodeArray, parentNode);\n                            }\n                        }\n\n                        // Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)\n                        // whereas a regular applyBindings won't introduce new memoized nodes\n                        invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {\n                            if (node.nodeType === 1 || node.nodeType === 8)\n                                ko.applyBindings(bindingContext, node);\n                        });\n                        invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {\n                            if (node.nodeType === 1 || node.nodeType === 8)\n                                ko.memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]);\n                        });\n\n                        // Make sure any changes done by applyBindings or unmemoize are reflected in the array\n                        ko.utils.fixUpContinuousNodeArray(continuousNodeArray, parentNode);\n                    }\n                }\n\n                function getFirstNodeFromPossibleArray(nodeOrNodeArray) {\n                    return nodeOrNodeArray.nodeType ? nodeOrNodeArray\n                        : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0]\n                            : null;\n                }\n\n                function executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options) {\n                    options = options || {};\n                    var firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray);\n                    var templateDocument = (firstTargetNode || template || {}).ownerDocument;\n                    var templateEngineToUse = (options['templateEngine'] || _templateEngine);\n                    ko.templateRewriting.ensureTemplateIsRewritten(template, templateEngineToUse, templateDocument);\n                    var renderedNodesArray = templateEngineToUse['renderTemplate'](template, bindingContext, options, templateDocument);\n\n                    // Loosely check result is an array of DOM nodes\n                    if ((typeof renderedNodesArray.length != \"number\") || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType != \"number\"))\n                        throw new Error(\"Template engine must return an array of DOM nodes\");\n\n                    var haveAddedNodesToParent = false;\n                    switch (renderMode) {\n                        case \"replaceChildren\":\n                            ko.virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray);\n                            haveAddedNodesToParent = true;\n                            break;\n                        case \"replaceNode\":\n                            ko.utils.replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray);\n                            haveAddedNodesToParent = true;\n                            break;\n                        case \"ignoreTargetNode\": break;\n                        default:\n                            throw new Error(\"Unknown renderMode: \" + renderMode);\n                    }\n\n                    if (haveAddedNodesToParent) {\n                        activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext);\n                        if (options['afterRender']) {\n                            ko.dependencyDetection.ignore(options['afterRender'], null, [renderedNodesArray, bindingContext[options['as'] || '$data']]);\n                        }\n                        if (renderMode == \"replaceChildren\") {\n                            ko.bindingEvent.notify(targetNodeOrNodeArray, ko.bindingEvent.childrenComplete);\n                        }\n                    }\n\n                    return renderedNodesArray;\n                }\n\n                function resolveTemplateName(template, data, context) {\n                    // The template can be specified as:\n                    if (ko.isObservable(template)) {\n                        // 1. An observable, with string value\n                        return template();\n                    } else if (typeof template === 'function') {\n                        // 2. A function of (data, context) returning a string\n                        return template(data, context);\n                    } else {\n                        // 3. A string\n                        return template;\n                    }\n                }\n\n                ko.renderTemplate = function (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode) {\n                    options = options || {};\n                    if ((options['templateEngine'] || _templateEngine) == undefined)\n                        throw new Error(\"Set a template engine before calling renderTemplate\");\n                    renderMode = renderMode || \"replaceChildren\";\n\n                    if (targetNodeOrNodeArray) {\n                        var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);\n\n                        var whenToDispose = function () { return (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); }; // Passive disposal (on next evaluation)\n                        var activelyDisposeWhenNodeIsRemoved = (firstTargetNode && renderMode == \"replaceNode\") ? firstTargetNode.parentNode : firstTargetNode;\n\n                        return ko.dependentObservable( // So the DOM is automatically updated when any dependency changes\n                            function () {\n                                // Ensure we've got a proper binding context to work with\n                                var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof ko.bindingContext))\n                                    ? dataOrBindingContext\n                                    : new ko.bindingContext(dataOrBindingContext, null, null, null, { \"exportDependencies\": true });\n\n                                var templateName = resolveTemplateName(template, bindingContext['$data'], bindingContext),\n                                    renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, templateName, bindingContext, options);\n\n                                if (renderMode == \"replaceNode\") {\n                                    targetNodeOrNodeArray = renderedNodesArray;\n                                    firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);\n                                }\n                            },\n                            null,\n                            { disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }\n                        );\n                    } else {\n                        // We don't yet have a DOM node to evaluate, so use a memo and render the template later when there is a DOM node\n                        return ko.memoization.memoize(function (domNode) {\n                            ko.renderTemplate(template, dataOrBindingContext, options, domNode, \"replaceNode\");\n                        });\n                    }\n                };\n\n                ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode, parentBindingContext) {\n                    // Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then\n                    // activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.\n                    var arrayItemContext, asName = options['as'];\n\n                    // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode\n                    var executeTemplateForArrayItem = function (arrayValue, index) {\n                        // Support selecting template as a function of the data being rendered\n                        arrayItemContext = parentBindingContext['createChildContext'](arrayValue, {\n                            'as': asName,\n                            'noChildContext': options['noChildContext'],\n                            'extend': function(context) {\n                                context['$index'] = index;\n                                if (asName) {\n                                    context[asName + \"Index\"] = index;\n                                }\n                            }\n                        });\n\n                        var templateName = resolveTemplateName(template, arrayValue, arrayItemContext);\n                        return executeTemplate(targetNode, \"ignoreTargetNode\", templateName, arrayItemContext, options);\n                    };\n\n                    // This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode\n                    var activateBindingsCallback = function(arrayValue, addedNodesArray, index) {\n                        activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext);\n                        if (options['afterRender'])\n                            options['afterRender'](addedNodesArray, arrayValue);\n\n                        // release the \"cache\" variable, so that it can be collected by\n                        // the GC when its value isn't used from within the bindings anymore.\n                        arrayItemContext = null;\n                    };\n\n                    var setDomNodeChildrenFromArrayMapping = function (newArray, changeList) {\n                        // Call setDomNodeChildrenFromArrayMapping, ignoring any observables unwrapped within (most likely from a callback function).\n                        // If the array items are observables, though, they will be unwrapped in executeTemplateForArrayItem and managed within setDomNodeChildrenFromArrayMapping.\n                        ko.dependencyDetection.ignore(ko.utils.setDomNodeChildrenFromArrayMapping, null, [targetNode, newArray, executeTemplateForArrayItem, options, activateBindingsCallback, changeList]);\n                        ko.bindingEvent.notify(targetNode, ko.bindingEvent.childrenComplete);\n                    };\n\n                    var shouldHideDestroyed = (options['includeDestroyed'] === false) || (ko.options['foreachHidesDestroyed'] && !options['includeDestroyed']);\n\n                    if (!shouldHideDestroyed && !options['beforeRemove'] && ko.isObservableArray(arrayOrObservableArray)) {\n                        setDomNodeChildrenFromArrayMapping(arrayOrObservableArray.peek());\n\n                        var subscription = arrayOrObservableArray.subscribe(function (changeList) {\n                            setDomNodeChildrenFromArrayMapping(arrayOrObservableArray(), changeList);\n                        }, null, \"arrayChange\");\n                        subscription.disposeWhenNodeIsRemoved(targetNode);\n\n                        return subscription;\n                    } else {\n                        return ko.dependentObservable(function () {\n                            var unwrappedArray = ko.utils.unwrapObservable(arrayOrObservableArray) || [];\n                            if (typeof unwrappedArray.length == \"undefined\") // Coerce single value into array\n                                unwrappedArray = [unwrappedArray];\n\n                            if (shouldHideDestroyed) {\n                                // Filter out any entries marked as destroyed\n                                unwrappedArray = ko.utils.arrayFilter(unwrappedArray, function(item) {\n                                    return item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);\n                                });\n                            }\n                            setDomNodeChildrenFromArrayMapping(unwrappedArray);\n\n                        }, null, { disposeWhenNodeIsRemoved: targetNode });\n                    }\n                };\n\n                var templateComputedDomDataKey = ko.utils.domData.nextKey();\n                function disposeOldComputedAndStoreNewOne(element, newComputed) {\n                    var oldComputed = ko.utils.domData.get(element, templateComputedDomDataKey);\n                    if (oldComputed && (typeof(oldComputed.dispose) == 'function'))\n                        oldComputed.dispose();\n                    ko.utils.domData.set(element, templateComputedDomDataKey, (newComputed && (!newComputed.isActive || newComputed.isActive())) ? newComputed : undefined);\n                }\n\n                var cleanContainerDomDataKey = ko.utils.domData.nextKey();\n                ko.bindingHandlers['template'] = {\n                    'init': function(element, valueAccessor) {\n                        // Support anonymous templates\n                        var bindingValue = ko.utils.unwrapObservable(valueAccessor());\n                        if (typeof bindingValue == \"string\" || 'name' in bindingValue) {\n                            // It's a named template - clear the element\n                            ko.virtualElements.emptyNode(element);\n                        } else if ('nodes' in bindingValue) {\n                            // We've been given an array of DOM nodes. Save them as the template source.\n                            // There is no known use case for the node array being an observable array (if the output\n                            // varies, put that behavior *into* your template - that's what templates are for), and\n                            // the implementation would be a mess, so assert that it's not observable.\n                            var nodes = bindingValue['nodes'] || [];\n                            if (ko.isObservable(nodes)) {\n                                throw new Error('The \"nodes\" option must be a plain, non-observable array.');\n                            }\n\n                            // If the nodes are already attached to a KO-generated container, we reuse that container without moving the\n                            // elements to a new one (we check only the first node, as the nodes are always moved together)\n                            var container = nodes[0] && nodes[0].parentNode;\n                            if (!container || !ko.utils.domData.get(container, cleanContainerDomDataKey)) {\n                                container = ko.utils.moveCleanedNodesToContainerElement(nodes);\n                                ko.utils.domData.set(container, cleanContainerDomDataKey, true);\n                            }\n\n                            new ko.templateSources.anonymousTemplate(element)['nodes'](container);\n                        } else {\n                            // It's an anonymous template - store the element contents, then clear the element\n                            var templateNodes = ko.virtualElements.childNodes(element);\n                            if (templateNodes.length > 0) {\n                                var container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent\n                                new ko.templateSources.anonymousTemplate(element)['nodes'](container);\n                            } else {\n                                throw new Error(\"Anonymous template defined, but no template content was provided\");\n                            }\n                        }\n                        return { 'controlsDescendantBindings': true };\n                    },\n                    'update': function (element, valueAccessor, allBindings, viewModel, bindingContext) {\n                        var value = valueAccessor(),\n                            options = ko.utils.unwrapObservable(value),\n                            shouldDisplay = true,\n                            templateComputed = null,\n                            template;\n\n                        if (typeof options == \"string\") {\n                            template = value;\n                            options = {};\n                        } else {\n                            template = 'name' in options ? options['name'] : element;\n\n                            // Support \"if\"/\"ifnot\" conditions\n                            if ('if' in options)\n                                shouldDisplay = ko.utils.unwrapObservable(options['if']);\n                            if (shouldDisplay && 'ifnot' in options)\n                                shouldDisplay = !ko.utils.unwrapObservable(options['ifnot']);\n\n                            // Don't show anything if an empty name is given (see #2446)\n                            if (shouldDisplay && !template) {\n                                shouldDisplay = false;\n                            }\n                        }\n\n                        if ('foreach' in options) {\n                            // Render once for each data point (treating data set as empty if shouldDisplay==false)\n                            var dataArray = (shouldDisplay && options['foreach']) || [];\n                            templateComputed = ko.renderTemplateForEach(template, dataArray, options, element, bindingContext);\n                        } else if (!shouldDisplay) {\n                            ko.virtualElements.emptyNode(element);\n                        } else {\n                            // Render once for this single data point (or use the viewModel if no data was provided)\n                            var innerBindingContext = bindingContext;\n                            if ('data' in options) {\n                                innerBindingContext = bindingContext['createChildContext'](options['data'], {\n                                    'as': options['as'],\n                                    'noChildContext': options['noChildContext'],\n                                    'exportDependencies': true\n                                });\n                            }\n                            templateComputed = ko.renderTemplate(template, innerBindingContext, options, element);\n                        }\n\n                        // It only makes sense to have a single template computed per element (otherwise which one should have its output displayed?)\n                        disposeOldComputedAndStoreNewOne(element, templateComputed);\n                    }\n                };\n\n                // Anonymous templates can't be rewritten. Give a nice error message if you try to do it.\n                ko.expressionRewriting.bindingRewriteValidators['template'] = function(bindingValue) {\n                    var parsedBindingValue = ko.expressionRewriting.parseObjectLiteral(bindingValue);\n\n                    if ((parsedBindingValue.length == 1) && parsedBindingValue[0]['unknown'])\n                        return null; // It looks like a string literal, not an object literal, so treat it as a named template (which is allowed for rewriting)\n\n                    if (ko.expressionRewriting.keyValueArrayContainsKey(parsedBindingValue, \"name\"))\n                        return null; // Named templates can be rewritten, so return \"no error\"\n                    return \"This template engine does not support anonymous templates nested within its templates\";\n                };\n\n                ko.virtualElements.allowedBindings['template'] = true;\n            })();\n\n            ko.exportSymbol('setTemplateEngine', ko.setTemplateEngine);\n            ko.exportSymbol('renderTemplate', ko.renderTemplate);\n// Go through the items that have been added and deleted and try to find matches between them.\n            ko.utils.findMovesInArrayComparison = function (left, right, limitFailedCompares) {\n                if (left.length && right.length) {\n                    var failedCompares, l, r, leftItem, rightItem;\n                    for (failedCompares = l = 0; (!limitFailedCompares || failedCompares < limitFailedCompares) && (leftItem = left[l]); ++l) {\n                        for (r = 0; rightItem = right[r]; ++r) {\n                            if (leftItem['value'] === rightItem['value']) {\n                                leftItem['moved'] = rightItem['index'];\n                                rightItem['moved'] = leftItem['index'];\n                                right.splice(r, 1);         // This item is marked as moved; so remove it from right list\n                                failedCompares = r = 0;     // Reset failed compares count because we're checking for consecutive failures\n                                break;\n                            }\n                        }\n                        failedCompares += r;\n                    }\n                }\n            };\n\n            ko.utils.compareArrays = (function () {\n                var statusNotInOld = 'added', statusNotInNew = 'deleted';\n\n                // Simple calculation based on Levenshtein distance.\n                function compareArrays(oldArray, newArray, options) {\n                    // For backward compatibility, if the third arg is actually a bool, interpret\n                    // it as the old parameter 'dontLimitMoves'. Newer code should use { dontLimitMoves: true }.\n                    options = (typeof options === 'boolean') ? { 'dontLimitMoves': options } : (options || {});\n                    oldArray = oldArray || [];\n                    newArray = newArray || [];\n\n                    if (oldArray.length < newArray.length)\n                        return compareSmallArrayToBigArray(oldArray, newArray, statusNotInOld, statusNotInNew, options);\n                    else\n                        return compareSmallArrayToBigArray(newArray, oldArray, statusNotInNew, statusNotInOld, options);\n                }\n\n                function compareSmallArrayToBigArray(smlArray, bigArray, statusNotInSml, statusNotInBig, options) {\n                    var myMin = Math.min,\n                        myMax = Math.max,\n                        editDistanceMatrix = [],\n                        smlIndex, smlIndexMax = smlArray.length,\n                        bigIndex, bigIndexMax = bigArray.length,\n                        compareRange = (bigIndexMax - smlIndexMax) || 1,\n                        maxDistance = smlIndexMax + bigIndexMax + 1,\n                        thisRow, lastRow,\n                        bigIndexMaxForRow, bigIndexMinForRow;\n\n                    for (smlIndex = 0; smlIndex <= smlIndexMax; smlIndex++) {\n                        lastRow = thisRow;\n                        editDistanceMatrix.push(thisRow = []);\n                        bigIndexMaxForRow = myMin(bigIndexMax, smlIndex + compareRange);\n                        bigIndexMinForRow = myMax(0, smlIndex - 1);\n                        for (bigIndex = bigIndexMinForRow; bigIndex <= bigIndexMaxForRow; bigIndex++) {\n                            if (!bigIndex)\n                                thisRow[bigIndex] = smlIndex + 1;\n                            else if (!smlIndex)  // Top row - transform empty array into new array via additions\n                                thisRow[bigIndex] = bigIndex + 1;\n                            else if (smlArray[smlIndex - 1] === bigArray[bigIndex - 1])\n                                thisRow[bigIndex] = lastRow[bigIndex - 1];                  // copy value (no edit)\n                            else {\n                                var northDistance = lastRow[bigIndex] || maxDistance;       // not in big (deletion)\n                                var westDistance = thisRow[bigIndex - 1] || maxDistance;    // not in small (addition)\n                                thisRow[bigIndex] = myMin(northDistance, westDistance) + 1;\n                            }\n                        }\n                    }\n\n                    var editScript = [], meMinusOne, notInSml = [], notInBig = [];\n                    for (smlIndex = smlIndexMax, bigIndex = bigIndexMax; smlIndex || bigIndex;) {\n                        meMinusOne = editDistanceMatrix[smlIndex][bigIndex] - 1;\n                        if (bigIndex && meMinusOne === editDistanceMatrix[smlIndex][bigIndex-1]) {\n                            notInSml.push(editScript[editScript.length] = {     // added\n                                'status': statusNotInSml,\n                                'value': bigArray[--bigIndex],\n                                'index': bigIndex });\n                        } else if (smlIndex && meMinusOne === editDistanceMatrix[smlIndex - 1][bigIndex]) {\n                            notInBig.push(editScript[editScript.length] = {     // deleted\n                                'status': statusNotInBig,\n                                'value': smlArray[--smlIndex],\n                                'index': smlIndex });\n                        } else {\n                            --bigIndex;\n                            --smlIndex;\n                            if (!options['sparse']) {\n                                editScript.push({\n                                    'status': \"retained\",\n                                    'value': bigArray[bigIndex] });\n                            }\n                        }\n                    }\n\n                    // Set a limit on the number of consecutive non-matching comparisons; having it a multiple of\n                    // smlIndexMax keeps the time complexity of this algorithm linear.\n                    ko.utils.findMovesInArrayComparison(notInBig, notInSml, !options['dontLimitMoves'] && smlIndexMax * 10);\n\n                    return editScript.reverse();\n                }\n\n                return compareArrays;\n            })();\n\n            ko.exportSymbol('utils.compareArrays', ko.utils.compareArrays);\n            (function () {\n                // Objective:\n                // * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,\n                //   map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node\n                // * Next time we're given the same combination of things (with the array possibly having mutated), update the container DOM node\n                //   so that its children is again the concatenation of the mappings of the array elements, but don't re-map any array elements that we\n                //   previously mapped - retain those nodes, and just insert/delete other ones\n\n                // \"callbackAfterAddingNodes\" will be invoked after any \"mapping\"-generated nodes are inserted into the container node\n                // You can use this, for example, to activate bindings on those nodes.\n\n                function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {\n                    // Map this array value inside a dependentObservable so we re-map when any dependency changes\n                    var mappedNodes = [];\n                    var dependentObservable = ko.dependentObservable(function() {\n                        var newMappedNodes = mapping(valueToMap, index, ko.utils.fixUpContinuousNodeArray(mappedNodes, containerNode)) || [];\n\n                        // On subsequent evaluations, just replace the previously-inserted DOM nodes\n                        if (mappedNodes.length > 0) {\n                            ko.utils.replaceDomNodes(mappedNodes, newMappedNodes);\n                            if (callbackAfterAddingNodes)\n                                ko.dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]);\n                        }\n\n                        // Replace the contents of the mappedNodes array, thereby updating the record\n                        // of which nodes would be deleted if valueToMap was itself later removed\n                        mappedNodes.length = 0;\n                        ko.utils.arrayPushAll(mappedNodes, newMappedNodes);\n                    }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() { return !ko.utils.anyDomNodeIsAttachedToDocument(mappedNodes); } });\n                    return { mappedNodes : mappedNodes, dependentObservable : (dependentObservable.isActive() ? dependentObservable : undefined) };\n                }\n\n                var lastMappingResultDomDataKey = ko.utils.domData.nextKey(),\n                    deletedItemDummyValue = ko.utils.domData.nextKey();\n\n                ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options, callbackAfterAddingNodes, editScript) {\n                    array = array || [];\n                    if (typeof array.length == \"undefined\") // Coerce single value into array\n                        array = [array];\n\n                    options = options || {};\n                    var lastMappingResult = ko.utils.domData.get(domNode, lastMappingResultDomDataKey);\n                    var isFirstExecution = !lastMappingResult;\n\n                    // Build the new mapping result\n                    var newMappingResult = [];\n                    var lastMappingResultIndex = 0;\n                    var currentArrayIndex = 0;\n\n                    var nodesToDelete = [];\n                    var itemsToMoveFirstIndexes = [];\n                    var itemsForBeforeRemoveCallbacks = [];\n                    var itemsForMoveCallbacks = [];\n                    var itemsForAfterAddCallbacks = [];\n                    var mapData;\n                    var countWaitingForRemove = 0;\n\n                    function itemAdded(value) {\n                        mapData = { arrayEntry: value, indexObservable: ko.observable(currentArrayIndex++) };\n                        newMappingResult.push(mapData);\n                        if (!isFirstExecution) {\n                            itemsForAfterAddCallbacks.push(mapData);\n                        }\n                    }\n\n                    function itemMovedOrRetained(oldPosition) {\n                        mapData = lastMappingResult[oldPosition];\n                        if (currentArrayIndex !== mapData.indexObservable.peek())\n                            itemsForMoveCallbacks.push(mapData);\n                        // Since updating the index might change the nodes, do so before calling fixUpContinuousNodeArray\n                        mapData.indexObservable(currentArrayIndex++);\n                        ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode);\n                        newMappingResult.push(mapData);\n                    }\n\n                    function callCallback(callback, items) {\n                        if (callback) {\n                            for (var i = 0, n = items.length; i < n; i++) {\n                                ko.utils.arrayForEach(items[i].mappedNodes, function(node) {\n                                    callback(node, i, items[i].arrayEntry);\n                                });\n                            }\n                        }\n                    }\n\n                    if (isFirstExecution) {\n                        ko.utils.arrayForEach(array, itemAdded);\n                    } else {\n                        if (!editScript || (lastMappingResult && lastMappingResult['_countWaitingForRemove'])) {\n                            // Compare the provided array against the previous one\n                            var lastArray = ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; }),\n                                compareOptions = {\n                                    'dontLimitMoves': options['dontLimitMoves'],\n                                    'sparse': true\n                                };\n                            editScript = ko.utils.compareArrays(lastArray, array, compareOptions);\n                        }\n\n                        for (var i = 0, editScriptItem, movedIndex, itemIndex; editScriptItem = editScript[i]; i++) {\n                            movedIndex = editScriptItem['moved'];\n                            itemIndex = editScriptItem['index'];\n                            switch (editScriptItem['status']) {\n                                case \"deleted\":\n                                    while (lastMappingResultIndex < itemIndex) {\n                                        itemMovedOrRetained(lastMappingResultIndex++);\n                                    }\n                                    if (movedIndex === undefined) {\n                                        mapData = lastMappingResult[lastMappingResultIndex];\n\n                                        // Stop tracking changes to the mapping for these nodes\n                                        if (mapData.dependentObservable) {\n                                            mapData.dependentObservable.dispose();\n                                            mapData.dependentObservable = undefined;\n                                        }\n\n                                        // Queue these nodes for later removal\n                                        if (ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode).length) {\n                                            if (options['beforeRemove']) {\n                                                newMappingResult.push(mapData);\n                                                countWaitingForRemove++;\n                                                if (mapData.arrayEntry === deletedItemDummyValue) {\n                                                    mapData = null;\n                                                } else {\n                                                    itemsForBeforeRemoveCallbacks.push(mapData);\n                                                }\n                                            }\n                                            if (mapData) {\n                                                nodesToDelete.push.apply(nodesToDelete, mapData.mappedNodes);\n                                            }\n                                        }\n                                    }\n                                    lastMappingResultIndex++;\n                                    break;\n\n                                case \"added\":\n                                    while (currentArrayIndex < itemIndex) {\n                                        itemMovedOrRetained(lastMappingResultIndex++);\n                                    }\n                                    if (movedIndex !== undefined) {\n                                        itemsToMoveFirstIndexes.push(newMappingResult.length);\n                                        itemMovedOrRetained(movedIndex);\n                                    } else {\n                                        itemAdded(editScriptItem['value']);\n                                    }\n                                    break;\n                            }\n                        }\n\n                        while (currentArrayIndex < array.length) {\n                            itemMovedOrRetained(lastMappingResultIndex++);\n                        }\n\n                        // Record that the current view may still contain deleted items\n                        // because it means we won't be able to use a provided editScript.\n                        newMappingResult['_countWaitingForRemove'] = countWaitingForRemove;\n                    }\n\n                    // Store a copy of the array items we just considered so we can difference it next time\n                    ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult);\n\n                    // Call beforeMove first before any changes have been made to the DOM\n                    callCallback(options['beforeMove'], itemsForMoveCallbacks);\n\n                    // Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)\n                    ko.utils.arrayForEach(nodesToDelete, options['beforeRemove'] ? ko.cleanNode : ko.removeNode);\n\n                    var i, j, lastNode, nodeToInsert, mappedNodes, activeElement;\n\n                    // Since most browsers remove the focus from an element when it's moved to another location,\n                    // save the focused element and try to restore it later.\n                    try {\n                        activeElement = domNode.ownerDocument.activeElement;\n                    } catch(e) {\n                        // IE9 throws if you access activeElement during page load (see issue #703)\n                    }\n\n                    // Try to reduce overall moved nodes by first moving the ones that were marked as moved by the edit script\n                    if (itemsToMoveFirstIndexes.length) {\n                        while ((i = itemsToMoveFirstIndexes.shift()) != undefined) {\n                            mapData = newMappingResult[i];\n                            for (lastNode = undefined; i; ) {\n                                if ((mappedNodes = newMappingResult[--i].mappedNodes) && mappedNodes.length) {\n                                    lastNode = mappedNodes[mappedNodes.length-1];\n                                    break;\n                                }\n                            }\n                            for (j = 0; nodeToInsert = mapData.mappedNodes[j]; lastNode = nodeToInsert, j++) {\n                                ko.virtualElements.insertAfter(domNode, nodeToInsert, lastNode);\n                            }\n                        }\n                    }\n\n                    // Next add/reorder the remaining items (will include deleted items if there's a beforeRemove callback)\n                    for (i = 0; mapData = newMappingResult[i]; i++) {\n                        // Get nodes for newly added items\n                        if (!mapData.mappedNodes)\n                            ko.utils.extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));\n\n                        // Put nodes in the right place if they aren't there already\n                        for (j = 0; nodeToInsert = mapData.mappedNodes[j]; lastNode = nodeToInsert, j++) {\n                            ko.virtualElements.insertAfter(domNode, nodeToInsert, lastNode);\n                        }\n\n                        // Run the callbacks for newly added nodes (for example, to apply bindings, etc.)\n                        if (!mapData.initialized && callbackAfterAddingNodes) {\n                            callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable);\n                            mapData.initialized = true;\n                            lastNode = mapData.mappedNodes[mapData.mappedNodes.length - 1];     // get the last node again since it may have been changed by a preprocessor\n                        }\n                    }\n\n                    // Restore the focused element if it had lost focus\n                    if (activeElement && domNode.ownerDocument.activeElement != activeElement) {\n                        activeElement.focus();\n                    }\n\n                    // If there's a beforeRemove callback, call it after reordering.\n                    // Note that we assume that the beforeRemove callback will usually be used to remove the nodes using\n                    // some sort of animation, which is why we first reorder the nodes that will be removed. If the\n                    // callback instead removes the nodes right away, it would be more efficient to skip reordering them.\n                    // Perhaps we'll make that change in the future if this scenario becomes more common.\n                    callCallback(options['beforeRemove'], itemsForBeforeRemoveCallbacks);\n\n                    // Replace the stored values of deleted items with a dummy value. This provides two benefits: it marks this item\n                    // as already \"removed\" so we won't call beforeRemove for it again, and it ensures that the item won't match up\n                    // with an actual item in the array and appear as \"retained\" or \"moved\".\n                    for (i = 0; i < itemsForBeforeRemoveCallbacks.length; ++i) {\n                        itemsForBeforeRemoveCallbacks[i].arrayEntry = deletedItemDummyValue;\n                    }\n\n                    // Finally call afterMove and afterAdd callbacks\n                    callCallback(options['afterMove'], itemsForMoveCallbacks);\n                    callCallback(options['afterAdd'], itemsForAfterAddCallbacks);\n                }\n            })();\n\n            ko.exportSymbol('utils.setDomNodeChildrenFromArrayMapping', ko.utils.setDomNodeChildrenFromArrayMapping);\n            ko.nativeTemplateEngine = function () {\n                this['allowTemplateRewriting'] = false;\n            }\n\n            ko.nativeTemplateEngine.prototype = new ko.templateEngine();\n            ko.nativeTemplateEngine.prototype.constructor = ko.nativeTemplateEngine;\n            ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options, templateDocument) {\n                var useNodesIfAvailable = !(ko.utils.ieVersion < 9), // IE<9 cloneNode doesn't work properly\n                    templateNodesFunc = useNodesIfAvailable ? templateSource['nodes'] : null,\n                    templateNodes = templateNodesFunc ? templateSource['nodes']() : null;\n\n                if (templateNodes) {\n                    return ko.utils.makeArray(templateNodes.cloneNode(true).childNodes);\n                } else {\n                    var templateText = templateSource['text']();\n                    return ko.utils.parseHtmlFragment(templateText, templateDocument);\n                }\n            };\n\n            ko.nativeTemplateEngine.instance = new ko.nativeTemplateEngine();\n            ko.setTemplateEngine(ko.nativeTemplateEngine.instance);\n\n            ko.exportSymbol('nativeTemplateEngine', ko.nativeTemplateEngine);\n            (function() {\n                ko.jqueryTmplTemplateEngine = function () {\n                    // Detect which version of jquery-tmpl you're using. Unfortunately jquery-tmpl\n                    // doesn't expose a version number, so we have to infer it.\n                    // Note that as of Knockout 1.3, we only support jQuery.tmpl 1.0.0pre and later,\n                    // which KO internally refers to as version \"2\", so older versions are no longer detected.\n                    var jQueryTmplVersion = this.jQueryTmplVersion = (function() {\n                        if (!jQueryInstance || !(jQueryInstance['tmpl']))\n                            return 0;\n                        // Since it exposes no official version number, we use our own numbering system. To be updated as jquery-tmpl evolves.\n                        try {\n                            if (jQueryInstance['tmpl']['tag']['tmpl']['open'].toString().indexOf('__') >= 0) {\n                                // Since 1.0.0pre, custom tags should append markup to an array called \"__\"\n                                return 2; // Final version of jquery.tmpl\n                            }\n                        } catch(ex) { /* Apparently not the version we were looking for */ }\n\n                        return 1; // Any older version that we don't support\n                    })();\n\n                    function ensureHasReferencedJQueryTemplates() {\n                        if (jQueryTmplVersion < 2)\n                            throw new Error(\"Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.\");\n                    }\n\n                    function executeTemplate(compiledTemplate, data, jQueryTemplateOptions) {\n                        return jQueryInstance['tmpl'](compiledTemplate, data, jQueryTemplateOptions);\n                    }\n\n                    this['renderTemplateSource'] = function(templateSource, bindingContext, options, templateDocument) {\n                        templateDocument = templateDocument || document;\n                        options = options || {};\n                        ensureHasReferencedJQueryTemplates();\n\n                        // Ensure we have stored a precompiled version of this template (don't want to reparse on every render)\n                        var precompiled = templateSource['data']('precompiled');\n                        if (!precompiled) {\n                            var templateText = templateSource['text']() || \"\";\n                            // Wrap in \"with($whatever.koBindingContext) { ... }\"\n                            templateText = \"{{ko_with $item.koBindingContext}}\" + templateText + \"{{/ko_with}}\";\n\n                            precompiled = jQueryInstance['template'](null, templateText);\n                            templateSource['data']('precompiled', precompiled);\n                        }\n\n                        var data = [bindingContext['$data']]; // Prewrap the data in an array to stop jquery.tmpl from trying to unwrap any arrays\n                        var jQueryTemplateOptions = jQueryInstance['extend']({ 'koBindingContext': bindingContext }, options['templateOptions']);\n\n                        var resultNodes = executeTemplate(precompiled, data, jQueryTemplateOptions);\n                        resultNodes['appendTo'](templateDocument.createElement(\"div\")); // Using \"appendTo\" forces jQuery/jQuery.tmpl to perform necessary cleanup work\n\n                        jQueryInstance['fragments'] = {}; // Clear jQuery's fragment cache to avoid a memory leak after a large number of template renders\n                        return resultNodes;\n                    };\n\n                    this['createJavaScriptEvaluatorBlock'] = function(script) {\n                        return \"{{ko_code ((function() { return \" + script + \" })()) }}\";\n                    };\n\n                    this['addTemplate'] = function(templateName, templateMarkup) {\n                        document.write(\"<script type='text/html' id='\" + templateName + \"'>\" + templateMarkup + \"<\" + \"/script>\");\n                    };\n\n                    if (jQueryTmplVersion > 0) {\n                        jQueryInstance['tmpl']['tag']['ko_code'] = {\n                            open: \"__.push($1 || '');\"\n                        };\n                        jQueryInstance['tmpl']['tag']['ko_with'] = {\n                            open: \"with($1) {\",\n                            close: \"} \"\n                        };\n                    }\n                };\n\n                ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine();\n                ko.jqueryTmplTemplateEngine.prototype.constructor = ko.jqueryTmplTemplateEngine;\n\n                // Use this one by default *only if jquery.tmpl is referenced*\n                var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine();\n                if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0)\n                    ko.setTemplateEngine(jqueryTmplTemplateEngineInstance);\n\n                ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine);\n            })();\n        }));\n    }());\n})();\n","knockoutjs/knockout-fast-foreach.js":"/*!\n  Knockout Fast Foreach v0.4.1 (2015-07-17T14:06:15.974Z)\n  By: Brian M Hunt (C) 2015\n  License: MIT\n\n  Adds `fastForEach` to `ko.bindingHandlers`.\n*/\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    define(['knockout'], factory);\n  } else if (typeof exports === 'object') {\n    module.exports = factory(require('knockout'));\n  } else {\n    root.KnockoutFastForeach = factory(root.ko);\n  }\n}(this, function (ko) {\n  \"use strict\";\n// index.js\n// --------\n// Fast For Each\n//\n// Employing sound techniques to make a faster Knockout foreach binding.\n// --------\n\n//      Utilities\n\n// from https://github.com/jonschlinkert/is-plain-object\nfunction isPlainObject(o) {\n  return !!o && typeof o === 'object' && o.constructor === Object;\n}\n\n// From knockout/src/virtualElements.js\nvar commentNodesHaveTextProperty = document && document.createComment(\"test\").text === \"<!--test-->\";\nvar startCommentRegex = commentNodesHaveTextProperty ? /^<!--\\s*ko(?:\\s+([\\s\\S]+))?\\s*-->$/ : /^\\s*ko(?:\\s+([\\s\\S]+))?\\s*$/;\nvar supportsDocumentFragment = document && typeof document.createDocumentFragment === \"function\";\nfunction isVirtualNode(node) {\n  return (node.nodeType === 8) && startCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);\n}\n\n\n// Get a copy of the (possibly virtual) child nodes of the given element,\n// put them into a container, then empty the given node.\nfunction makeTemplateNode(sourceNode) {\n  var container = document.createElement(\"div\");\n  var parentNode;\n  if (sourceNode.content) {\n    // For e.g. <template> tags\n    parentNode = sourceNode.content;\n  } else if (sourceNode.tagName === 'SCRIPT') {\n    parentNode = document.createElement(\"div\");\n    parentNode.innerHTML = sourceNode.text;\n  } else {\n    // Anything else e.g. <div>\n    parentNode = sourceNode;\n  }\n  ko.utils.arrayForEach(ko.virtualElements.childNodes(parentNode), function (child) {\n    // FIXME - This cloneNode could be expensive; we may prefer to iterate over the\n    // parentNode children in reverse (so as not to foul the indexes as childNodes are\n    // removed from parentNode when inserted into the container)\n    if (child) {\n      container.insertBefore(child.cloneNode(true), null);\n    }\n  });\n  return container;\n}\n\nfunction insertAllAfter(containerNode, nodeOrNodeArrayToInsert, insertAfterNode) {\n  var frag, len, i;\n  // poor man's node and array check, should be enough for this\n  if (typeof nodeOrNodeArrayToInsert.nodeType !== \"undefined\" && typeof nodeOrNodeArrayToInsert.length === \"undefined\") {\n    throw new Error(\"Expected a single node or a node array\");\n  }\n\n  if (typeof nodeOrNodeArrayToInsert.nodeType !== \"undefined\") {\n    ko.virtualElements.insertAfter(containerNode, nodeOrNodeArrayToInsert, insertAfterNode);\n    return;\n  }\n\n  if (nodeOrNodeArrayToInsert.length === 1) {\n    ko.virtualElements.insertAfter(containerNode, nodeOrNodeArrayToInsert[0], insertAfterNode);\n    return;\n  }\n\n  if (supportsDocumentFragment) {\n    frag = document.createDocumentFragment();\n\n    for (i = 0, len = nodeOrNodeArrayToInsert.length; i !== len; ++i) {\n      frag.appendChild(nodeOrNodeArrayToInsert[i]);\n    }\n    ko.virtualElements.insertAfter(containerNode, frag, insertAfterNode);\n  } else {\n    // Nodes are inserted in reverse order - pushed down immediately after\n    // the last node for the previous item or as the first node of element.\n    for (i = nodeOrNodeArrayToInsert.length - 1; i >= 0; --i) {\n      var child = nodeOrNodeArrayToInsert[i];\n      if (!child) {\n        return;\n      }\n      ko.virtualElements.insertAfter(containerNode, child, insertAfterNode);\n    }\n  }\n}\n\n// Mimic a KO change item 'add'\nfunction valueToChangeAddItem(value, index) {\n  return {\n    status: 'added',\n    value: value,\n    index: index\n  };\n}\n\nfunction isAdditionAdjacentToLast(changeIndex, arrayChanges) {\n  return changeIndex > 0 &&\n    changeIndex < arrayChanges.length &&\n    arrayChanges[changeIndex].status === \"added\" &&\n    arrayChanges[changeIndex - 1].status === \"added\" &&\n    arrayChanges[changeIndex - 1].index === arrayChanges[changeIndex].index - 1;\n}\n\nfunction FastForEach(spec) {\n  this.element = spec.element;\n  this.container = isVirtualNode(this.element) ?\n                   this.element.parentNode : this.element;\n  this.$context = spec.$context;\n  this.data = spec.data;\n  this.as = spec.as;\n  this.noContext = spec.noContext;\n  this.templateNode = makeTemplateNode(\n    spec.name ? document.getElementById(spec.name).cloneNode(true) : spec.element\n  );\n  this.afterQueueFlush = spec.afterQueueFlush;\n  this.beforeQueueFlush = spec.beforeQueueFlush;\n  this.changeQueue = [];\n  this.lastNodesList = [];\n  this.indexesToDelete = [];\n  this.rendering_queued = false;\n\n  // Remove existing content.\n  ko.virtualElements.emptyNode(this.element);\n\n  // Prime content\n  var primeData = ko.unwrap(this.data);\n  if (primeData.map) {\n    this.onArrayChange(primeData.map(valueToChangeAddItem));\n  }\n\n  // Watch for changes\n  if (ko.isObservable(this.data)) {\n    if (!this.data.indexOf) {\n      // Make sure the observable is trackable.\n      this.data = this.data.extend({trackArrayChanges: true});\n    }\n    this.changeSubs = this.data.subscribe(this.onArrayChange, this, 'arrayChange');\n  }\n}\n\n\nFastForEach.animateFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame ||\n  window.mozRequestAnimationFrame || window.msRequestAnimationFrame ||\n  function(cb) { return window.setTimeout(cb, 1000 / 60); };\n\n\nFastForEach.prototype.dispose = function () {\n  if (this.changeSubs) {\n    this.changeSubs.dispose();\n  }\n};\n\n\n// If the array changes we register the change.\nFastForEach.prototype.onArrayChange = function (changeSet) {\n  var self = this;\n  var changeMap = {\n    added: [],\n    deleted: []\n  };\n  for (var i = 0, len = changeSet.length; i < len; i++) {\n    // the change is appended to a last change info object when both are 'added' and have indexes next to each other\n    // here I presume that ko is sending changes in monotonic order (in index variable) which happens to be true, tested with push and splice with multiple pushed values\n    if (isAdditionAdjacentToLast(i, changeSet)) {\n      var batchValues = changeMap.added[changeMap.added.length - 1].values;\n      if (!batchValues) {\n        // transform the last addition into a batch addition object\n        var lastAddition = changeMap.added.pop();\n        var batchAddition = {\n          isBatch: true,\n          status: 'added',\n          index: lastAddition.index,\n          values: [lastAddition.value]\n        };\n        batchValues = batchAddition.values;\n        changeMap.added.push(batchAddition);\n      }\n      batchValues.push(changeSet[i].value);\n    } else {\n      changeMap[changeSet[i].status].push(changeSet[i]);\n    }\n  }\n  if (changeMap.deleted.length > 0) {\n    this.changeQueue.push.apply(this.changeQueue, changeMap.deleted);\n    this.changeQueue.push({status: 'clearDeletedIndexes'});\n  }\n  this.changeQueue.push.apply(this.changeQueue, changeMap.added);\n  // Once a change is registered, the ticking count-down starts for the processQueue.\n  if (this.changeQueue.length > 0 && !this.rendering_queued) {\n    this.rendering_queued = true;\n    FastForEach.animateFrame.call(window, function () { self.processQueue(); });\n  }\n};\n\n\n// Reflect all the changes in the queue in the DOM, then wipe the queue.\nFastForEach.prototype.processQueue = function () {\n  var self = this;\n\n  // Callback so folks can do things before the queue flush.\n  if (typeof this.beforeQueueFlush === 'function') {\n    this.beforeQueueFlush(this.changeQueue);\n  }\n\n  ko.utils.arrayForEach(this.changeQueue, function (changeItem) {\n    // console.log(self.data(), \"CI\", JSON.stringify(changeItem, null, 2), JSON.stringify($(self.element).text()))\n    self[changeItem.status](changeItem);\n    // console.log(\"  ==> \", JSON.stringify($(self.element).text()))\n  });\n  this.rendering_queued = false;\n  // Callback so folks can do things.\n  if (typeof this.afterQueueFlush === 'function') {\n    this.afterQueueFlush(this.changeQueue);\n  }\n  this.changeQueue = [];\n};\n\n\n// Process a changeItem with {status: 'added', ...}\nFastForEach.prototype.added = function (changeItem) {\n  var index = changeItem.index;\n  var valuesToAdd = changeItem.isBatch ? changeItem.values : [changeItem.value];\n  var referenceElement = this.lastNodesList[index - 1] || null;\n  // gather all childnodes for a possible batch insertion\n  var allChildNodes = [];\n\n  for (var i = 0, len = valuesToAdd.length; i < len; ++i) {\n    var templateClone = this.templateNode.cloneNode(true);\n    var childContext;\n\n    if (this.noContext) {\n      childContext = this.$context.extend({\n        '$item': valuesToAdd[i]\n      });\n    } else {\n      childContext = this.$context.createChildContext(valuesToAdd[i], this.as || null);\n    }\n\n    // apply bindings first, and then process child nodes, because bindings can add childnodes\n    ko.applyBindingsToDescendants(childContext, templateClone);\n\n    var childNodes = ko.virtualElements.childNodes(templateClone);\n    // Note discussion at https://github.com/angular/angular.js/issues/7851\n    allChildNodes.push.apply(allChildNodes, Array.prototype.slice.call(childNodes));\n    this.lastNodesList.splice(index + i, 0, childNodes[childNodes.length - 1]);\n  }\n\n  insertAllAfter(this.element, allChildNodes, referenceElement);\n};\n\n\n// Process a changeItem with {status: 'deleted', ...}\nFastForEach.prototype.deleted = function (changeItem) {\n  var index = changeItem.index;\n  var ptr = this.lastNodesList[index],\n      // We use this.element because that will be the last previous node\n      // for virtual element lists.\n      lastNode = this.lastNodesList[index - 1] || this.element;\n  do {\n    ptr = ptr.previousSibling;\n    ko.removeNode((ptr && ptr.nextSibling) || ko.virtualElements.firstChild(this.element));\n  } while (ptr && ptr !== lastNode);\n  // The \"last node\" in the DOM from which we begin our delets of the next adjacent node is\n  // now the sibling that preceded the first node of this item.\n  this.lastNodesList[index] = this.lastNodesList[index - 1];\n  this.indexesToDelete.push(index);\n};\n\n\n// We batch our deletion of item indexes in our parallel array.\n// See brianmhunt/knockout-fast-foreach#6/#8\nFastForEach.prototype.clearDeletedIndexes = function () {\n  // We iterate in reverse on the presumption (following the unit tests) that KO's diff engine\n  // processes diffs (esp. deletes) monotonically ascending i.e. from index 0 -> N.\n  for (var i = this.indexesToDelete.length - 1; i >= 0; --i) {\n    this.lastNodesList.splice(this.indexesToDelete[i], 1);\n  }\n  this.indexesToDelete = [];\n};\n\n\nko.bindingHandlers.fastForEach = {\n  // Valid valueAccessors:\n  //    []\n  //    ko.observable([])\n  //    ko.observableArray([])\n  //    ko.computed\n  //    {data: array, name: string, as: string}\n  init: function init(element, valueAccessor, bindings, vm, context) {\n    var value = valueAccessor(),\n        ffe;\n    if (isPlainObject(value)) {\n      value.element = value.element || element;\n      value.$context = context;\n      ffe = new FastForEach(value);\n    } else {\n      ffe = new FastForEach({\n        element: element,\n        data: ko.unwrap(context.$rawData) === value ? context.$rawData : value,\n        $context: context\n      });\n    }\n    ko.utils.domNodeDisposal.addDisposeCallback(element, function () {\n      ffe.dispose();\n    });\n    return {controlsDescendantBindings: true};\n  },\n\n  // Export for testing, debugging, and overloading.\n  FastForEach: FastForEach\n};\n\nko.virtualElements.allowedBindings.fastForEach = true;\n}));","knockoutjs/knockout-es5.js":"/*!\n * Knockout ES5 plugin - https://github.com/SteveSanderson/knockout-es5\n * Copyright (c) Steve Sanderson\n * MIT license\n */\n\n(function(global, undefined) {\n  'use strict';\n\n  var ko;\n\n  // Model tracking\n  // --------------\n  //\n  // This is the central feature of Knockout-ES5. We augment model objects by converting properties\n  // into ES5 getter/setter pairs that read/write an underlying Knockout observable. This means you can\n  // use plain JavaScript syntax to read/write the property while still getting the full benefits of\n  // Knockout's automatic dependency detection and notification triggering.\n  //\n  // For comparison, here's Knockout ES3-compatible syntax:\n  //\n  //     var firstNameLength = myModel.user().firstName().length; // Read\n  //     myModel.user().firstName('Bert'); // Write\n  //\n  // ... versus Knockout-ES5 syntax:\n  //\n  //     var firstNameLength = myModel.user.firstName.length; // Read\n  //     myModel.user.firstName = 'Bert'; // Write\n\n  // `ko.track(model)` converts each property on the given model object into a getter/setter pair that\n  // wraps a Knockout observable. Optionally specify an array of property names to wrap; otherwise we\n  // wrap all properties. If any of the properties are already observables, we replace them with\n  // ES5 getter/setter pairs that wrap your original observable instances. In the case of readonly\n  // ko.computed properties, we simply do not define a setter (so attempted writes will be ignored,\n  // which is how ES5 readonly properties normally behave).\n  //\n  // By design, this does *not* recursively walk child object properties, because making literally\n  // everything everywhere independently observable is usually unhelpful. When you do want to track\n  // child object properties independently, define your own class for those child objects and put\n  // a separate ko.track call into its constructor --- this gives you far more control.\n  /**\n   * @param {object} obj\n   * @param {object|array.<string>} propertyNamesOrSettings\n   * @param {boolean} propertyNamesOrSettings.deep Use deep track.\n   * @param {array.<string>} propertyNamesOrSettings.fields Array of property names to wrap.\n   * todo: @param {array.<string>} propertyNamesOrSettings.exclude Array of exclude property names to wrap.\n   * todo: @param {function(string, *):boolean} propertyNamesOrSettings.filter Function to filter property \n   *   names to wrap. A function that takes ... params\n   * @return {object}\n   */\n  function track(obj, propertyNamesOrSettings) {\n    if (!obj || typeof obj !== 'object') {\n      throw new Error('When calling ko.track, you must pass an object as the first parameter.');\n    }\n\n    var propertyNames;\n\n    if ( isPlainObject(propertyNamesOrSettings) ) {\n      // defaults\n      propertyNamesOrSettings.deep = propertyNamesOrSettings.deep || false;\n      propertyNamesOrSettings.fields = propertyNamesOrSettings.fields || Object.getOwnPropertyNames(obj);\n      propertyNamesOrSettings.lazy = propertyNamesOrSettings.lazy || false;\n\n      wrap(obj, propertyNamesOrSettings.fields, propertyNamesOrSettings);\n    } else {\n      propertyNames = propertyNamesOrSettings || Object.getOwnPropertyNames(obj);\n      wrap(obj, propertyNames, {});\n    }\n\n    return obj;\n  }\n\n  // fix for ie\n  var rFunctionName = /^function\\s*([^\\s(]+)/;\n  function getFunctionName( ctor ){\n    if (ctor.name) {\n      return ctor.name;\n    }\n    return (ctor.toString().trim().match( rFunctionName ) || [])[1];\n  }\n\n  function canTrack(obj) {\n    return obj && typeof obj === 'object' && getFunctionName(obj.constructor) === 'Object';\n  }\n\n  function createPropertyDescriptor(originalValue, prop, map) {\n    var isObservable = ko.isObservable(originalValue);\n    var isArray = !isObservable && Array.isArray(originalValue);\n    var observable = isObservable ? originalValue\n        : isArray ? ko.observableArray(originalValue)\n        : ko.observable(originalValue);\n\n    map[prop] = function () { return observable; };\n\n    // add check in case the object is already an observable array\n    if (isArray || (isObservable && 'push' in observable)) {\n      notifyWhenPresentOrFutureArrayValuesMutate(ko, observable);\n    }\n\n    return {\n      configurable: true,\n      enumerable: true,\n      get: observable,\n      set: ko.isWriteableObservable(observable) ? observable : undefined\n    };\n  }\n\n  function createLazyPropertyDescriptor(originalValue, prop, map) {\n    if (ko.isObservable(originalValue)) {\n      // no need to be lazy if we already have an observable\n      return createPropertyDescriptor(originalValue, prop, map);\n    }\n\n    var observable;\n\n    function getOrCreateObservable(value, writing) {\n      if (observable) {\n        return writing ? observable(value) : observable;\n      }\n\n      if (Array.isArray(value)) {\n        observable = ko.observableArray(value);\n        notifyWhenPresentOrFutureArrayValuesMutate(ko, observable);\n        return observable;\n      }\n\n      return (observable = ko.observable(value));\n    }\n\n    map[prop] = function () { return getOrCreateObservable(originalValue); };\n    return {\n      configurable: true,\n      enumerable: true,\n      get: function () { return getOrCreateObservable(originalValue)(); },\n      set: function (value) { getOrCreateObservable(value, true); }\n    };\n  }\n\n  function wrap(obj, props, options) {\n    if (!props.length) {\n      return;\n    }\n\n    var allObservablesForObject = getAllObservablesForObject(obj, true);\n    var descriptors = {};\n\n    props.forEach(function (prop) {\n      // Skip properties that are already tracked\n      if (prop in allObservablesForObject) {\n        return;\n      }\n\n      // Skip properties where descriptor can't be redefined\n      if (Object.getOwnPropertyDescriptor(obj, prop).configurable === false){\n        return;\n      }\n\n      var originalValue = obj[prop];\n      descriptors[prop] = (options.lazy ? createLazyPropertyDescriptor : createPropertyDescriptor)\n        (originalValue, prop, allObservablesForObject);\n\n      if (options.deep && canTrack(originalValue)) {\n        wrap(originalValue, Object.keys(originalValue), options);\n      }\n    });\n\n    Object.defineProperties(obj, descriptors);\n  }\n\n  function isPlainObject( obj ){\n    return !!obj && typeof obj === 'object' && obj.constructor === Object;\n  }\n\n  // Lazily created by `getAllObservablesForObject` below. Has to be created lazily because the\n  // WeakMap factory isn't available until the module has finished loading (may be async).\n  var objectToObservableMap;\n\n  // Gets or creates the hidden internal key-value collection of observables corresponding to\n  // properties on the model object.\n  function getAllObservablesForObject(obj, createIfNotDefined) {\n    if (!objectToObservableMap) {\n      objectToObservableMap = weakMapFactory();\n    }\n\n    var result = objectToObservableMap.get(obj);\n    if (!result && createIfNotDefined) {\n      result = {};\n      objectToObservableMap.set(obj, result);\n    }\n    return result;\n  }\n\n  // Removes the internal references to observables mapped to the specified properties\n  // or the entire object reference if no properties are passed in. This allows the\n  // observables to be replaced and tracked again.\n  function untrack(obj, propertyNames) {\n    if (!objectToObservableMap) {\n      return;\n    }\n\n    if (arguments.length === 1) {\n      objectToObservableMap['delete'](obj);\n    } else {\n      var allObservablesForObject = getAllObservablesForObject(obj, false);\n      if (allObservablesForObject) {\n        propertyNames.forEach(function(propertyName) {\n          delete allObservablesForObject[propertyName];\n        });\n      }\n    }\n  }\n\n  // Computed properties\n  // -------------------\n  //\n  // The preceding code is already sufficient to upgrade ko.computed model properties to ES5\n  // getter/setter pairs (or in the case of readonly ko.computed properties, just a getter).\n  // These then behave like a regular property with a getter function, except they are smarter:\n  // your evaluator is only invoked when one of its dependencies changes. The result is cached\n  // and used for all evaluations until the next time a dependency changes).\n  //\n  // However, instead of forcing developers to declare a ko.computed property explicitly, it's\n  // nice to offer a utility function that declares a computed getter directly.\n\n  // Implements `ko.defineProperty`\n  function defineComputedProperty(obj, propertyName, evaluatorOrOptions) {\n    var ko = this,\n      computedOptions = { owner: obj, deferEvaluation: true };\n\n    if (typeof evaluatorOrOptions === 'function') {\n      computedOptions.read = evaluatorOrOptions;\n    } else {\n      if ('value' in evaluatorOrOptions) {\n        throw new Error('For ko.defineProperty, you must not specify a \"value\" for the property. ' +\n                        'You must provide a \"get\" function.');\n      }\n\n      if (typeof evaluatorOrOptions.get !== 'function') {\n        throw new Error('For ko.defineProperty, the third parameter must be either an evaluator function, ' +\n                        'or an options object containing a function called \"get\".');\n      }\n\n      computedOptions.read = evaluatorOrOptions.get;\n      computedOptions.write = evaluatorOrOptions.set;\n    }\n\n    obj[propertyName] = ko.computed(computedOptions);\n    track.call(ko, obj, [propertyName]);\n    return obj;\n  }\n\n  // Array handling\n  // --------------\n  //\n  // Arrays are special, because unlike other property types, they have standard mutator functions\n  // (`push`/`pop`/`splice`/etc.) and it's desirable to trigger a change notification whenever one of\n  // those mutator functions is invoked.\n  //\n  // Traditionally, Knockout handles this by putting special versions of `push`/`pop`/etc. on observable\n  // arrays that mutate the underlying array and then trigger a notification. That approach doesn't\n  // work for Knockout-ES5 because properties now return the underlying arrays, so the mutator runs\n  // in the context of the underlying array, not any particular observable:\n  //\n  //     // Operates on the underlying array value\n  //     myModel.someCollection.push('New value');\n  //\n  // To solve this, Knockout-ES5 detects array values, and modifies them as follows:\n  //  1. Associates a hidden subscribable with each array instance that it encounters\n  //  2. Intercepts standard mutators (`push`/`pop`/etc.) and makes them trigger the subscribable\n  // Then, for model properties whose values are arrays, the property's underlying observable\n  // subscribes to the array subscribable, so it can trigger a change notification after mutation.\n\n  // Given an observable that underlies a model property, watch for any array value that might\n  // be assigned as the property value, and hook into its change events\n  function notifyWhenPresentOrFutureArrayValuesMutate(ko, observable) {\n    var watchingArraySubscription = null;\n    ko.computed(function () {\n      // Unsubscribe to any earlier array instance\n      if (watchingArraySubscription) {\n        watchingArraySubscription.dispose();\n        watchingArraySubscription = null;\n      }\n\n      // Subscribe to the new array instance\n      var newArrayInstance = observable();\n      if (newArrayInstance instanceof Array) {\n        watchingArraySubscription = startWatchingArrayInstance(ko, observable, newArrayInstance);\n      }\n    });\n  }\n\n  // Listens for array mutations, and when they happen, cause the observable to fire notifications.\n  // This is used to make model properties of type array fire notifications when the array changes.\n  // Returns a subscribable that can later be disposed.\n  function startWatchingArrayInstance(ko, observable, arrayInstance) {\n    var subscribable = getSubscribableForArray(ko, arrayInstance);\n    return subscribable.subscribe(observable);\n  }\n\n  // Lazily created by `getSubscribableForArray` below. Has to be created lazily because the\n  // WeakMap factory isn't available until the module has finished loading (may be async).\n  var arraySubscribablesMap;\n\n  // Gets or creates a subscribable that fires after each array mutation\n  function getSubscribableForArray(ko, arrayInstance) {\n    if (!arraySubscribablesMap) {\n      arraySubscribablesMap = weakMapFactory();\n    }\n\n    var subscribable = arraySubscribablesMap.get(arrayInstance);\n    if (!subscribable) {\n      subscribable = new ko.subscribable();\n      arraySubscribablesMap.set(arrayInstance, subscribable);\n\n      var notificationPauseSignal = {};\n      wrapStandardArrayMutators(arrayInstance, subscribable, notificationPauseSignal);\n      addKnockoutArrayMutators(ko, arrayInstance, subscribable, notificationPauseSignal);\n    }\n\n    return subscribable;\n  }\n\n  // After each array mutation, fires a notification on the given subscribable\n  function wrapStandardArrayMutators(arrayInstance, subscribable, notificationPauseSignal) {\n    ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'].forEach(function(fnName) {\n      var origMutator = arrayInstance[fnName];\n      arrayInstance[fnName] = function() {\n        var result = origMutator.apply(this, arguments);\n        if (notificationPauseSignal.pause !== true) {\n          subscribable.notifySubscribers(this);\n        }\n        return result;\n      };\n    });\n  }\n\n  // Adds Knockout's additional array mutation functions to the array\n  function addKnockoutArrayMutators(ko, arrayInstance, subscribable, notificationPauseSignal) {\n    ['remove', 'removeAll', 'destroy', 'destroyAll', 'replace'].forEach(function(fnName) {\n      // Make it a non-enumerable property for consistency with standard Array functions\n      Object.defineProperty(arrayInstance, fnName, {\n        enumerable: false,\n        value: function() {\n          var result;\n\n          // These additional array mutators are built using the underlying push/pop/etc.\n          // mutators, which are wrapped to trigger notifications. But we don't want to\n          // trigger multiple notifications, so pause the push/pop/etc. wrappers and\n          // delivery only one notification at the end of the process.\n          notificationPauseSignal.pause = true;\n          try {\n            // Creates a temporary observableArray that can perform the operation.\n            result = ko.observableArray.fn[fnName].apply(ko.observableArray(arrayInstance), arguments);\n          }\n          finally {\n            notificationPauseSignal.pause = false;\n          }\n          subscribable.notifySubscribers(arrayInstance);\n          return result;\n        }\n      });\n    });\n  }\n\n  // Static utility functions\n  // ------------------------\n  //\n  // Since Knockout-ES5 sets up properties that return values, not observables, you can't\n  // trivially subscribe to the underlying observables (e.g., `someProperty.subscribe(...)`),\n  // or tell them that object values have mutated, etc. To handle this, we set up some\n  // extra utility functions that can return or work with the underlying observables.\n\n  // Returns the underlying observable associated with a model property (or `null` if the\n  // model or property doesn't exist, or isn't associated with an observable). This means\n  // you can subscribe to the property, e.g.:\n  //\n  //     ko.getObservable(model, 'propertyName')\n  //       .subscribe(function(newValue) { ... });\n  function getObservable(obj, propertyName) {\n    if (!obj || typeof obj !== 'object') {\n      return null;\n    }\n\n    var allObservablesForObject = getAllObservablesForObject(obj, false);\n    if (allObservablesForObject && propertyName in allObservablesForObject) {\n      return allObservablesForObject[propertyName]();\n    }\n\n    return null;\n  }\n  \n  // Returns a boolean indicating whether the property on the object has an underlying\n  // observables. This does the check in a way not to create an observable if the\n  // object was created with lazily created observables\n  function isTracked(obj, propertyName) {\n    if (!obj || typeof obj !== 'object') {\n      return false;\n    }\n    \n    var allObservablesForObject = getAllObservablesForObject(obj, false);\n    return !!allObservablesForObject && propertyName in allObservablesForObject;\n  }\n\n  // Causes a property's associated observable to fire a change notification. Useful when\n  // the property value is a complex object and you've modified a child property.\n  function valueHasMutated(obj, propertyName) {\n    var observable = getObservable(obj, propertyName);\n\n    if (observable) {\n      observable.valueHasMutated();\n    }\n  }\n\n  // Module initialisation\n  // ---------------------\n  //\n  // When this script is first evaluated, it works out what kind of module loading scenario\n  // it is in (Node.js or a browser `<script>` tag), stashes a reference to its dependencies\n  // (currently that's just the WeakMap shim), and then finally attaches itself to whichever\n  // instance of Knockout.js it can find.\n\n  // A function that returns a new ES6-compatible WeakMap instance (using ES5 shim if needed).\n  // Instantiated by prepareExports, accounting for which module loader is being used.\n  var weakMapFactory;\n\n  // Extends a Knockout instance with Knockout-ES5 functionality\n  function attachToKo(ko) {\n    ko.track = track;\n    ko.untrack = untrack;\n    ko.getObservable = getObservable;\n    ko.valueHasMutated = valueHasMutated;\n    ko.defineProperty = defineComputedProperty;\n\n    // todo: test it, maybe added it to ko. directly\n    ko.es5 = {\n      getAllObservablesForObject: getAllObservablesForObject,\n      notifyWhenPresentOrFutureArrayValuesMutate: notifyWhenPresentOrFutureArrayValuesMutate,\n      isTracked: isTracked\n    };\n  }\n\n  // Determines which module loading scenario we're in, grabs dependencies, and attaches to KO\n  function prepareExports() {\n    if (typeof exports === 'object' && typeof module === 'object') {\n      // Node.js case - load KO and WeakMap modules synchronously\n      ko = require('knockout');\n      var WM = require('../lib/weakmap');\n      attachToKo(ko);\n      weakMapFactory = function() { return new WM(); };\n      module.exports = ko;\n    } else if (typeof define === 'function' && define.amd) {\n      define(['knockout'], function(koModule) {\n        ko = koModule;\n        attachToKo(koModule);\n        weakMapFactory = function() { return new global.WeakMap(); };\n        return koModule;\n      });\n    } else if ('ko' in global) {\n      // Non-module case - attach to the global instance, and assume a global WeakMap constructor\n      ko = global.ko;\n      attachToKo(global.ko);\n      weakMapFactory = function() { return new global.WeakMap(); };\n    }\n  }\n\n  prepareExports();\n\n})(this);","vimeo/vimeo-wrapper.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'vimeo'\n], function (Player) {\n    'use strict';\n\n    window.Vimeo = window.Vimeo || {\n        'Player': Player\n    };\n});\n","vimeo/player.js":"/*! @vimeo/player v2.16.4 | (c) 2022 Vimeo | MIT License | https://github.com/vimeo/player.js */\n(function (global, factory) {\n  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n  typeof define === 'function' && define.amd ? define(factory) :\n  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, (global.Vimeo = global.Vimeo || {}, global.Vimeo.Player = factory()));\n}(this, (function () { 'use strict';\n\n  function _classCallCheck(instance, Constructor) {\n    if (!(instance instanceof Constructor)) {\n      throw new TypeError(\"Cannot call a class as a function\");\n    }\n  }\n\n  function _defineProperties(target, props) {\n    for (var i = 0; i < props.length; i++) {\n      var descriptor = props[i];\n      descriptor.enumerable = descriptor.enumerable || false;\n      descriptor.configurable = true;\n      if (\"value\" in descriptor) descriptor.writable = true;\n      Object.defineProperty(target, descriptor.key, descriptor);\n    }\n  }\n\n  function _createClass(Constructor, protoProps, staticProps) {\n    if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n    if (staticProps) _defineProperties(Constructor, staticProps);\n    return Constructor;\n  }\n\n  /**\n   * @module lib/functions\n   */\n\n  /**\n   * Check to see this is a node environment.\n   * @type {Boolean}\n   */\n\n  /* global global */\n  var isNode = typeof global !== 'undefined' && {}.toString.call(global) === '[object global]';\n  /**\n   * Get the name of the method for a given getter or setter.\n   *\n   * @param {string} prop The name of the property.\n   * @param {string} type Either \u201cget\u201d or \u201cset\u201d.\n   * @return {string}\n   */\n\n  function getMethodName(prop, type) {\n    if (prop.indexOf(type.toLowerCase()) === 0) {\n      return prop;\n    }\n\n    return \"\".concat(type.toLowerCase()).concat(prop.substr(0, 1).toUpperCase()).concat(prop.substr(1));\n  }\n  /**\n   * Check to see if the object is a DOM Element.\n   *\n   * @param {*} element The object to check.\n   * @return {boolean}\n   */\n\n  function isDomElement(element) {\n    return Boolean(element && element.nodeType === 1 && 'nodeName' in element && element.ownerDocument && element.ownerDocument.defaultView);\n  }\n  /**\n   * Check to see whether the value is a number.\n   *\n   * @see http://dl.dropboxusercontent.com/u/35146/js/tests/isNumber.html\n   * @param {*} value The value to check.\n   * @param {boolean} integer Check if the value is an integer.\n   * @return {boolean}\n   */\n\n  function isInteger(value) {\n    // eslint-disable-next-line eqeqeq\n    return !isNaN(parseFloat(value)) && isFinite(value) && Math.floor(value) == value;\n  }\n  /**\n   * Check to see if the URL is a Vimeo url.\n   *\n   * @param {string} url The url string.\n   * @return {boolean}\n   */\n\n  function isVimeoUrl(url) {\n    return /^(https?:)?\\/\\/((player|www)\\.)?vimeo\\.com(?=$|\\/)/.test(url);\n  }\n  /**\n   * Get the Vimeo URL from an element.\n   * The element must have either a data-vimeo-id or data-vimeo-url attribute.\n   *\n   * @param {object} oEmbedParameters The oEmbed parameters.\n   * @return {string}\n   */\n\n  function getVimeoUrl() {\n    var oEmbedParameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n    var id = oEmbedParameters.id;\n    var url = oEmbedParameters.url;\n    var idOrUrl = id || url;\n\n    if (!idOrUrl) {\n      throw new Error('An id or url must be passed, either in an options object or as a data-vimeo-id or data-vimeo-url attribute.');\n    }\n\n    if (isInteger(idOrUrl)) {\n      return \"https://vimeo.com/\".concat(idOrUrl);\n    }\n\n    if (isVimeoUrl(idOrUrl)) {\n      return idOrUrl.replace('http:', 'https:');\n    }\n\n    if (id) {\n      throw new TypeError(\"\\u201C\".concat(id, \"\\u201D is not a valid video id.\"));\n    }\n\n    throw new TypeError(\"\\u201C\".concat(idOrUrl, \"\\u201D is not a vimeo.com url.\"));\n  }\n\n  var arrayIndexOfSupport = typeof Array.prototype.indexOf !== 'undefined';\n  var postMessageSupport = typeof window !== 'undefined' && typeof window.postMessage !== 'undefined';\n\n  if (!isNode && (!arrayIndexOfSupport || !postMessageSupport)) {\n    throw new Error('Sorry, the Vimeo Player API is not available in this browser.');\n  }\n\n  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};\n\n  function createCommonjsModule(fn, module) {\n  \treturn module = { exports: {} }, fn(module, module.exports), module.exports;\n  }\n\n  /*!\n   * weakmap-polyfill v2.0.1 - ECMAScript6 WeakMap polyfill\n   * https://github.com/polygonplanet/weakmap-polyfill\n   * Copyright (c) 2015-2020 Polygon Planet <polygon.planet.aqua@gmail.com>\n   * @license MIT\n   */\n  (function (self) {\n\n    if (self.WeakMap) {\n      return;\n    }\n\n    var hasOwnProperty = Object.prototype.hasOwnProperty;\n\n    var defineProperty = function (object, name, value) {\n      if (Object.defineProperty) {\n        Object.defineProperty(object, name, {\n          configurable: true,\n          writable: true,\n          value: value\n        });\n      } else {\n        object[name] = value;\n      }\n    };\n\n    self.WeakMap = function () {\n      // ECMA-262 23.3 WeakMap Objects\n      function WeakMap() {\n        if (this === void 0) {\n          throw new TypeError(\"Constructor WeakMap requires 'new'\");\n        }\n\n        defineProperty(this, '_id', genId('_WeakMap')); // ECMA-262 23.3.1.1 WeakMap([iterable])\n\n        if (arguments.length > 0) {\n          // Currently, WeakMap `iterable` argument is not supported\n          throw new TypeError('WeakMap iterable is not supported');\n        }\n      } // ECMA-262 23.3.3.2 WeakMap.prototype.delete(key)\n\n\n      defineProperty(WeakMap.prototype, 'delete', function (key) {\n        checkInstance(this, 'delete');\n\n        if (!isObject(key)) {\n          return false;\n        }\n\n        var entry = key[this._id];\n\n        if (entry && entry[0] === key) {\n          delete key[this._id];\n          return true;\n        }\n\n        return false;\n      }); // ECMA-262 23.3.3.3 WeakMap.prototype.get(key)\n\n      defineProperty(WeakMap.prototype, 'get', function (key) {\n        checkInstance(this, 'get');\n\n        if (!isObject(key)) {\n          return void 0;\n        }\n\n        var entry = key[this._id];\n\n        if (entry && entry[0] === key) {\n          return entry[1];\n        }\n\n        return void 0;\n      }); // ECMA-262 23.3.3.4 WeakMap.prototype.has(key)\n\n      defineProperty(WeakMap.prototype, 'has', function (key) {\n        checkInstance(this, 'has');\n\n        if (!isObject(key)) {\n          return false;\n        }\n\n        var entry = key[this._id];\n\n        if (entry && entry[0] === key) {\n          return true;\n        }\n\n        return false;\n      }); // ECMA-262 23.3.3.5 WeakMap.prototype.set(key, value)\n\n      defineProperty(WeakMap.prototype, 'set', function (key, value) {\n        checkInstance(this, 'set');\n\n        if (!isObject(key)) {\n          throw new TypeError('Invalid value used as weak map key');\n        }\n\n        var entry = key[this._id];\n\n        if (entry && entry[0] === key) {\n          entry[1] = value;\n          return this;\n        }\n\n        defineProperty(key, this._id, [key, value]);\n        return this;\n      });\n\n      function checkInstance(x, methodName) {\n        if (!isObject(x) || !hasOwnProperty.call(x, '_id')) {\n          throw new TypeError(methodName + ' method called on incompatible receiver ' + typeof x);\n        }\n      }\n\n      function genId(prefix) {\n        return prefix + '_' + rand() + '.' + rand();\n      }\n\n      function rand() {\n        return Math.random().toString().substring(2);\n      }\n\n      defineProperty(WeakMap, '_polyfill', true);\n      return WeakMap;\n    }();\n\n    function isObject(x) {\n      return Object(x) === x;\n    }\n  })(typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : commonjsGlobal);\n\n  var npo_src = createCommonjsModule(function (module) {\n  /*! Native Promise Only\n      v0.8.1 (c) Kyle Simpson\n      MIT License: http://getify.mit-license.org\n  */\n  (function UMD(name, context, definition) {\n    // special form of UMD for polyfilling across evironments\n    context[name] = context[name] || definition();\n\n    if (module.exports) {\n      module.exports = context[name];\n    }\n  })(\"Promise\", typeof commonjsGlobal != \"undefined\" ? commonjsGlobal : commonjsGlobal, function DEF() {\n\n    var builtInProp,\n        cycle,\n        scheduling_queue,\n        ToString = Object.prototype.toString,\n        timer = typeof setImmediate != \"undefined\" ? function timer(fn) {\n      return setImmediate(fn);\n    } : setTimeout; // dammit, IE8.\n\n    try {\n      Object.defineProperty({}, \"x\", {});\n\n      builtInProp = function builtInProp(obj, name, val, config) {\n        return Object.defineProperty(obj, name, {\n          value: val,\n          writable: true,\n          configurable: config !== false\n        });\n      };\n    } catch (err) {\n      builtInProp = function builtInProp(obj, name, val) {\n        obj[name] = val;\n        return obj;\n      };\n    } // Note: using a queue instead of array for efficiency\n\n\n    scheduling_queue = function Queue() {\n      var first, last, item;\n\n      function Item(fn, self) {\n        this.fn = fn;\n        this.self = self;\n        this.next = void 0;\n      }\n\n      return {\n        add: function add(fn, self) {\n          item = new Item(fn, self);\n\n          if (last) {\n            last.next = item;\n          } else {\n            first = item;\n          }\n\n          last = item;\n          item = void 0;\n        },\n        drain: function drain() {\n          var f = first;\n          first = last = cycle = void 0;\n\n          while (f) {\n            f.fn.call(f.self);\n            f = f.next;\n          }\n        }\n      };\n    }();\n\n    function schedule(fn, self) {\n      scheduling_queue.add(fn, self);\n\n      if (!cycle) {\n        cycle = timer(scheduling_queue.drain);\n      }\n    } // promise duck typing\n\n\n    function isThenable(o) {\n      var _then,\n          o_type = typeof o;\n\n      if (o != null && (o_type == \"object\" || o_type == \"function\")) {\n        _then = o.then;\n      }\n\n      return typeof _then == \"function\" ? _then : false;\n    }\n\n    function notify() {\n      for (var i = 0; i < this.chain.length; i++) {\n        notifyIsolated(this, this.state === 1 ? this.chain[i].success : this.chain[i].failure, this.chain[i]);\n      }\n\n      this.chain.length = 0;\n    } // NOTE: This is a separate function to isolate\n    // the `try..catch` so that other code can be\n    // optimized better\n\n\n    function notifyIsolated(self, cb, chain) {\n      var ret, _then;\n\n      try {\n        if (cb === false) {\n          chain.reject(self.msg);\n        } else {\n          if (cb === true) {\n            ret = self.msg;\n          } else {\n            ret = cb.call(void 0, self.msg);\n          }\n\n          if (ret === chain.promise) {\n            chain.reject(TypeError(\"Promise-chain cycle\"));\n          } else if (_then = isThenable(ret)) {\n            _then.call(ret, chain.resolve, chain.reject);\n          } else {\n            chain.resolve(ret);\n          }\n        }\n      } catch (err) {\n        chain.reject(err);\n      }\n    }\n\n    function resolve(msg) {\n      var _then,\n          self = this; // already triggered?\n\n\n      if (self.triggered) {\n        return;\n      }\n\n      self.triggered = true; // unwrap\n\n      if (self.def) {\n        self = self.def;\n      }\n\n      try {\n        if (_then = isThenable(msg)) {\n          schedule(function () {\n            var def_wrapper = new MakeDefWrapper(self);\n\n            try {\n              _then.call(msg, function $resolve$() {\n                resolve.apply(def_wrapper, arguments);\n              }, function $reject$() {\n                reject.apply(def_wrapper, arguments);\n              });\n            } catch (err) {\n              reject.call(def_wrapper, err);\n            }\n          });\n        } else {\n          self.msg = msg;\n          self.state = 1;\n\n          if (self.chain.length > 0) {\n            schedule(notify, self);\n          }\n        }\n      } catch (err) {\n        reject.call(new MakeDefWrapper(self), err);\n      }\n    }\n\n    function reject(msg) {\n      var self = this; // already triggered?\n\n      if (self.triggered) {\n        return;\n      }\n\n      self.triggered = true; // unwrap\n\n      if (self.def) {\n        self = self.def;\n      }\n\n      self.msg = msg;\n      self.state = 2;\n\n      if (self.chain.length > 0) {\n        schedule(notify, self);\n      }\n    }\n\n    function iteratePromises(Constructor, arr, resolver, rejecter) {\n      for (var idx = 0; idx < arr.length; idx++) {\n        (function IIFE(idx) {\n          Constructor.resolve(arr[idx]).then(function $resolver$(msg) {\n            resolver(idx, msg);\n          }, rejecter);\n        })(idx);\n      }\n    }\n\n    function MakeDefWrapper(self) {\n      this.def = self;\n      this.triggered = false;\n    }\n\n    function MakeDef(self) {\n      this.promise = self;\n      this.state = 0;\n      this.triggered = false;\n      this.chain = [];\n      this.msg = void 0;\n    }\n\n    function Promise(executor) {\n      if (typeof executor != \"function\") {\n        throw TypeError(\"Not a function\");\n      }\n\n      if (this.__NPO__ !== 0) {\n        throw TypeError(\"Not a promise\");\n      } // instance shadowing the inherited \"brand\"\n      // to signal an already \"initialized\" promise\n\n\n      this.__NPO__ = 1;\n      var def = new MakeDef(this);\n\n      this[\"then\"] = function then(success, failure) {\n        var o = {\n          success: typeof success == \"function\" ? success : true,\n          failure: typeof failure == \"function\" ? failure : false\n        }; // Note: `then(..)` itself can be borrowed to be used against\n        // a different promise constructor for making the chained promise,\n        // by substituting a different `this` binding.\n\n        o.promise = new this.constructor(function extractChain(resolve, reject) {\n          if (typeof resolve != \"function\" || typeof reject != \"function\") {\n            throw TypeError(\"Not a function\");\n          }\n\n          o.resolve = resolve;\n          o.reject = reject;\n        });\n        def.chain.push(o);\n\n        if (def.state !== 0) {\n          schedule(notify, def);\n        }\n\n        return o.promise;\n      };\n\n      this[\"catch\"] = function $catch$(failure) {\n        return this.then(void 0, failure);\n      };\n\n      try {\n        executor.call(void 0, function publicResolve(msg) {\n          resolve.call(def, msg);\n        }, function publicReject(msg) {\n          reject.call(def, msg);\n        });\n      } catch (err) {\n        reject.call(def, err);\n      }\n    }\n\n    var PromisePrototype = builtInProp({}, \"constructor\", Promise,\n    /*configurable=*/\n    false); // Note: Android 4 cannot use `Object.defineProperty(..)` here\n\n    Promise.prototype = PromisePrototype; // built-in \"brand\" to signal an \"uninitialized\" promise\n\n    builtInProp(PromisePrototype, \"__NPO__\", 0,\n    /*configurable=*/\n    false);\n    builtInProp(Promise, \"resolve\", function Promise$resolve(msg) {\n      var Constructor = this; // spec mandated checks\n      // note: best \"isPromise\" check that's practical for now\n\n      if (msg && typeof msg == \"object\" && msg.__NPO__ === 1) {\n        return msg;\n      }\n\n      return new Constructor(function executor(resolve, reject) {\n        if (typeof resolve != \"function\" || typeof reject != \"function\") {\n          throw TypeError(\"Not a function\");\n        }\n\n        resolve(msg);\n      });\n    });\n    builtInProp(Promise, \"reject\", function Promise$reject(msg) {\n      return new this(function executor(resolve, reject) {\n        if (typeof resolve != \"function\" || typeof reject != \"function\") {\n          throw TypeError(\"Not a function\");\n        }\n\n        reject(msg);\n      });\n    });\n    builtInProp(Promise, \"all\", function Promise$all(arr) {\n      var Constructor = this; // spec mandated checks\n\n      if (ToString.call(arr) != \"[object Array]\") {\n        return Constructor.reject(TypeError(\"Not an array\"));\n      }\n\n      if (arr.length === 0) {\n        return Constructor.resolve([]);\n      }\n\n      return new Constructor(function executor(resolve, reject) {\n        if (typeof resolve != \"function\" || typeof reject != \"function\") {\n          throw TypeError(\"Not a function\");\n        }\n\n        var len = arr.length,\n            msgs = Array(len),\n            count = 0;\n        iteratePromises(Constructor, arr, function resolver(idx, msg) {\n          msgs[idx] = msg;\n\n          if (++count === len) {\n            resolve(msgs);\n          }\n        }, reject);\n      });\n    });\n    builtInProp(Promise, \"race\", function Promise$race(arr) {\n      var Constructor = this; // spec mandated checks\n\n      if (ToString.call(arr) != \"[object Array]\") {\n        return Constructor.reject(TypeError(\"Not an array\"));\n      }\n\n      return new Constructor(function executor(resolve, reject) {\n        if (typeof resolve != \"function\" || typeof reject != \"function\") {\n          throw TypeError(\"Not a function\");\n        }\n\n        iteratePromises(Constructor, arr, function resolver(idx, msg) {\n          resolve(msg);\n        }, reject);\n      });\n    });\n    return Promise;\n  });\n  });\n\n  /**\n   * @module lib/callbacks\n   */\n  var callbackMap = new WeakMap();\n  /**\n   * Store a callback for a method or event for a player.\n   *\n   * @param {Player} player The player object.\n   * @param {string} name The method or event name.\n   * @param {(function(this:Player, *): void|{resolve: function, reject: function})} callback\n   *        The callback to call or an object with resolve and reject functions for a promise.\n   * @return {void}\n   */\n\n  function storeCallback(player, name, callback) {\n    var playerCallbacks = callbackMap.get(player.element) || {};\n\n    if (!(name in playerCallbacks)) {\n      playerCallbacks[name] = [];\n    }\n\n    playerCallbacks[name].push(callback);\n    callbackMap.set(player.element, playerCallbacks);\n  }\n  /**\n   * Get the callbacks for a player and event or method.\n   *\n   * @param {Player} player The player object.\n   * @param {string} name The method or event name\n   * @return {function[]}\n   */\n\n  function getCallbacks(player, name) {\n    var playerCallbacks = callbackMap.get(player.element) || {};\n    return playerCallbacks[name] || [];\n  }\n  /**\n   * Remove a stored callback for a method or event for a player.\n   *\n   * @param {Player} player The player object.\n   * @param {string} name The method or event name\n   * @param {function} [callback] The specific callback to remove.\n   * @return {boolean} Was this the last callback?\n   */\n\n  function removeCallback(player, name, callback) {\n    var playerCallbacks = callbackMap.get(player.element) || {};\n\n    if (!playerCallbacks[name]) {\n      return true;\n    } // If no callback is passed, remove all callbacks for the event\n\n\n    if (!callback) {\n      playerCallbacks[name] = [];\n      callbackMap.set(player.element, playerCallbacks);\n      return true;\n    }\n\n    var index = playerCallbacks[name].indexOf(callback);\n\n    if (index !== -1) {\n      playerCallbacks[name].splice(index, 1);\n    }\n\n    callbackMap.set(player.element, playerCallbacks);\n    return playerCallbacks[name] && playerCallbacks[name].length === 0;\n  }\n  /**\n   * Return the first stored callback for a player and event or method.\n   *\n   * @param {Player} player The player object.\n   * @param {string} name The method or event name.\n   * @return {function} The callback, or false if there were none\n   */\n\n  function shiftCallbacks(player, name) {\n    var playerCallbacks = getCallbacks(player, name);\n\n    if (playerCallbacks.length < 1) {\n      return false;\n    }\n\n    var callback = playerCallbacks.shift();\n    removeCallback(player, name, callback);\n    return callback;\n  }\n  /**\n   * Move callbacks associated with an element to another element.\n   *\n   * @param {HTMLElement} oldElement The old element.\n   * @param {HTMLElement} newElement The new element.\n   * @return {void}\n   */\n\n  function swapCallbacks(oldElement, newElement) {\n    var playerCallbacks = callbackMap.get(oldElement);\n    callbackMap.set(newElement, playerCallbacks);\n    callbackMap.delete(oldElement);\n  }\n\n  /**\n   * @module lib/embed\n   */\n  var oEmbedParameters = ['autopause', 'autoplay', 'background', 'byline', 'color', 'controls', 'dnt', 'height', 'id', 'interactive_params', 'keyboard', 'loop', 'maxheight', 'maxwidth', 'muted', 'playsinline', 'portrait', 'responsive', 'speed', 'texttrack', 'title', 'transparent', 'url', 'width'];\n  /**\n   * Get the 'data-vimeo'-prefixed attributes from an element as an object.\n   *\n   * @param {HTMLElement} element The element.\n   * @param {Object} [defaults={}] The default values to use.\n   * @return {Object<string, string>}\n   */\n\n  function getOEmbedParameters(element) {\n    var defaults = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n    return oEmbedParameters.reduce(function (params, param) {\n      var value = element.getAttribute(\"data-vimeo-\".concat(param));\n\n      if (value || value === '') {\n        params[param] = value === '' ? 1 : value;\n      }\n\n      return params;\n    }, defaults);\n  }\n  /**\n   * Create an embed from oEmbed data inside an element.\n   *\n   * @param {object} data The oEmbed data.\n   * @param {HTMLElement} element The element to put the iframe in.\n   * @return {HTMLIFrameElement} The iframe embed.\n   */\n\n  function createEmbed(_ref, element) {\n    var html = _ref.html;\n\n    if (!element) {\n      throw new TypeError('An element must be provided');\n    }\n\n    if (element.getAttribute('data-vimeo-initialized') !== null) {\n      return element.querySelector('iframe');\n    }\n\n    var div = document.createElement('div');\n    div.innerHTML = html;\n    element.appendChild(div.firstChild);\n    element.setAttribute('data-vimeo-initialized', 'true');\n    return element.querySelector('iframe');\n  }\n  /**\n   * Make an oEmbed call for the specified URL.\n   *\n   * @param {string} videoUrl The vimeo.com url for the video.\n   * @param {Object} [params] Parameters to pass to oEmbed.\n   * @param {HTMLElement} element The element.\n   * @return {Promise}\n   */\n\n  function getOEmbedData(videoUrl) {\n    var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n    var element = arguments.length > 2 ? arguments[2] : undefined;\n    return new Promise(function (resolve, reject) {\n      if (!isVimeoUrl(videoUrl)) {\n        throw new TypeError(\"\\u201C\".concat(videoUrl, \"\\u201D is not a vimeo.com url.\"));\n      }\n\n      var url = \"https://vimeo.com/api/oembed.json?url=\".concat(encodeURIComponent(videoUrl));\n\n      for (var param in params) {\n        if (params.hasOwnProperty(param)) {\n          url += \"&\".concat(param, \"=\").concat(encodeURIComponent(params[param]));\n        }\n      }\n\n      var xhr = 'XDomainRequest' in window ? new XDomainRequest() : new XMLHttpRequest();\n      xhr.open('GET', url, true);\n\n      xhr.onload = function () {\n        if (xhr.status === 404) {\n          reject(new Error(\"\\u201C\".concat(videoUrl, \"\\u201D was not found.\")));\n          return;\n        }\n\n        if (xhr.status === 403) {\n          reject(new Error(\"\\u201C\".concat(videoUrl, \"\\u201D is not embeddable.\")));\n          return;\n        }\n\n        try {\n          var json = JSON.parse(xhr.responseText); // Check api response for 403 on oembed\n\n          if (json.domain_status_code === 403) {\n            // We still want to create the embed to give users visual feedback\n            createEmbed(json, element);\n            reject(new Error(\"\\u201C\".concat(videoUrl, \"\\u201D is not embeddable.\")));\n            return;\n          }\n\n          resolve(json);\n        } catch (error) {\n          reject(error);\n        }\n      };\n\n      xhr.onerror = function () {\n        var status = xhr.status ? \" (\".concat(xhr.status, \")\") : '';\n        reject(new Error(\"There was an error fetching the embed code from Vimeo\".concat(status, \".\")));\n      };\n\n      xhr.send();\n    });\n  }\n  /**\n   * Initialize all embeds within a specific element\n   *\n   * @param {HTMLElement} [parent=document] The parent element.\n   * @return {void}\n   */\n\n  function initializeEmbeds() {\n    var parent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : document;\n    var elements = [].slice.call(parent.querySelectorAll('[data-vimeo-id], [data-vimeo-url]'));\n\n    var handleError = function handleError(error) {\n      if ('console' in window && console.error) {\n        console.error(\"There was an error creating an embed: \".concat(error));\n      }\n    };\n\n    elements.forEach(function (element) {\n      try {\n        // Skip any that have data-vimeo-defer\n        if (element.getAttribute('data-vimeo-defer') !== null) {\n          return;\n        }\n\n        var params = getOEmbedParameters(element);\n        var url = getVimeoUrl(params);\n        getOEmbedData(url, params, element).then(function (data) {\n          return createEmbed(data, element);\n        }).catch(handleError);\n      } catch (error) {\n        handleError(error);\n      }\n    });\n  }\n  /**\n   * Resize embeds when messaged by the player.\n   *\n   * @param {HTMLElement} [parent=document] The parent element.\n   * @return {void}\n   */\n\n  function resizeEmbeds() {\n    var parent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : document;\n\n    // Prevent execution if users include the player.js script multiple times.\n    if (window.VimeoPlayerResizeEmbeds_) {\n      return;\n    }\n\n    window.VimeoPlayerResizeEmbeds_ = true;\n\n    var onMessage = function onMessage(event) {\n      if (!isVimeoUrl(event.origin)) {\n        return;\n      } // 'spacechange' is fired only on embeds with cards\n\n\n      if (!event.data || event.data.event !== 'spacechange') {\n        return;\n      }\n\n      var iframes = parent.querySelectorAll('iframe');\n\n      for (var i = 0; i < iframes.length; i++) {\n        if (iframes[i].contentWindow !== event.source) {\n          continue;\n        } // Change padding-bottom of the enclosing div to accommodate\n        // card carousel without distorting aspect ratio\n\n\n        var space = iframes[i].parentElement;\n        space.style.paddingBottom = \"\".concat(event.data.data[0].bottom, \"px\");\n        break;\n      }\n    };\n\n    window.addEventListener('message', onMessage);\n  }\n\n  /**\n   * @module lib/postmessage\n   */\n  /**\n   * Parse a message received from postMessage.\n   *\n   * @param {*} data The data received from postMessage.\n   * @return {object}\n   */\n\n  function parseMessageData(data) {\n    if (typeof data === 'string') {\n      try {\n        data = JSON.parse(data);\n      } catch (error) {\n        // If the message cannot be parsed, throw the error as a warning\n        console.warn(error);\n        return {};\n      }\n    }\n\n    return data;\n  }\n  /**\n   * Post a message to the specified target.\n   *\n   * @param {Player} player The player object to use.\n   * @param {string} method The API method to call.\n   * @param {object} params The parameters to send to the player.\n   * @return {void}\n   */\n\n  function postMessage(player, method, params) {\n    if (!player.element.contentWindow || !player.element.contentWindow.postMessage) {\n      return;\n    }\n\n    var message = {\n      method: method\n    };\n\n    if (params !== undefined) {\n      message.value = params;\n    } // IE 8 and 9 do not support passing messages, so stringify them\n\n\n    var ieVersion = parseFloat(navigator.userAgent.toLowerCase().replace(/^.*msie (\\d+).*$/, '$1'));\n\n    if (ieVersion >= 8 && ieVersion < 10) {\n      message = JSON.stringify(message);\n    }\n\n    player.element.contentWindow.postMessage(message, player.origin);\n  }\n  /**\n   * Parse the data received from a message event.\n   *\n   * @param {Player} player The player that received the message.\n   * @param {(Object|string)} data The message data. Strings will be parsed into JSON.\n   * @return {void}\n   */\n\n  function processData(player, data) {\n    data = parseMessageData(data);\n    var callbacks = [];\n    var param;\n\n    if (data.event) {\n      if (data.event === 'error') {\n        var promises = getCallbacks(player, data.data.method);\n        promises.forEach(function (promise) {\n          var error = new Error(data.data.message);\n          error.name = data.data.name;\n          promise.reject(error);\n          removeCallback(player, data.data.method, promise);\n        });\n      }\n\n      callbacks = getCallbacks(player, \"event:\".concat(data.event));\n      param = data.data;\n    } else if (data.method) {\n      var callback = shiftCallbacks(player, data.method);\n\n      if (callback) {\n        callbacks.push(callback);\n        param = data.value;\n      }\n    }\n\n    callbacks.forEach(function (callback) {\n      try {\n        if (typeof callback === 'function') {\n          callback.call(player, param);\n          return;\n        }\n\n        callback.resolve(param);\n      } catch (e) {// empty\n      }\n    });\n  }\n\n  /* MIT License\n\n  Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n  Terms */\n  function initializeScreenfull() {\n    var fn = function () {\n      var val;\n      var fnMap = [['requestFullscreen', 'exitFullscreen', 'fullscreenElement', 'fullscreenEnabled', 'fullscreenchange', 'fullscreenerror'], // New WebKit\n      ['webkitRequestFullscreen', 'webkitExitFullscreen', 'webkitFullscreenElement', 'webkitFullscreenEnabled', 'webkitfullscreenchange', 'webkitfullscreenerror'], // Old WebKit\n      ['webkitRequestFullScreen', 'webkitCancelFullScreen', 'webkitCurrentFullScreenElement', 'webkitCancelFullScreen', 'webkitfullscreenchange', 'webkitfullscreenerror'], ['mozRequestFullScreen', 'mozCancelFullScreen', 'mozFullScreenElement', 'mozFullScreenEnabled', 'mozfullscreenchange', 'mozfullscreenerror'], ['msRequestFullscreen', 'msExitFullscreen', 'msFullscreenElement', 'msFullscreenEnabled', 'MSFullscreenChange', 'MSFullscreenError']];\n      var i = 0;\n      var l = fnMap.length;\n      var ret = {};\n\n      for (; i < l; i++) {\n        val = fnMap[i];\n\n        if (val && val[1] in document) {\n          for (i = 0; i < val.length; i++) {\n            ret[fnMap[0][i]] = val[i];\n          }\n\n          return ret;\n        }\n      }\n\n      return false;\n    }();\n\n    var eventNameMap = {\n      fullscreenchange: fn.fullscreenchange,\n      fullscreenerror: fn.fullscreenerror\n    };\n    var screenfull = {\n      request: function request(element) {\n        return new Promise(function (resolve, reject) {\n          var onFullScreenEntered = function onFullScreenEntered() {\n            screenfull.off('fullscreenchange', onFullScreenEntered);\n            resolve();\n          };\n\n          screenfull.on('fullscreenchange', onFullScreenEntered);\n          element = element || document.documentElement;\n          var returnPromise = element[fn.requestFullscreen]();\n\n          if (returnPromise instanceof Promise) {\n            returnPromise.then(onFullScreenEntered).catch(reject);\n          }\n        });\n      },\n      exit: function exit() {\n        return new Promise(function (resolve, reject) {\n          if (!screenfull.isFullscreen) {\n            resolve();\n            return;\n          }\n\n          var onFullScreenExit = function onFullScreenExit() {\n            screenfull.off('fullscreenchange', onFullScreenExit);\n            resolve();\n          };\n\n          screenfull.on('fullscreenchange', onFullScreenExit);\n          var returnPromise = document[fn.exitFullscreen]();\n\n          if (returnPromise instanceof Promise) {\n            returnPromise.then(onFullScreenExit).catch(reject);\n          }\n        });\n      },\n      on: function on(event, callback) {\n        var eventName = eventNameMap[event];\n\n        if (eventName) {\n          document.addEventListener(eventName, callback);\n        }\n      },\n      off: function off(event, callback) {\n        var eventName = eventNameMap[event];\n\n        if (eventName) {\n          document.removeEventListener(eventName, callback);\n        }\n      }\n    };\n    Object.defineProperties(screenfull, {\n      isFullscreen: {\n        get: function get() {\n          return Boolean(document[fn.fullscreenElement]);\n        }\n      },\n      element: {\n        enumerable: true,\n        get: function get() {\n          return document[fn.fullscreenElement];\n        }\n      },\n      isEnabled: {\n        enumerable: true,\n        get: function get() {\n          // Coerce to boolean in case of old WebKit\n          return Boolean(document[fn.fullscreenEnabled]);\n        }\n      }\n    });\n    return screenfull;\n  }\n\n  var playerMap = new WeakMap();\n  var readyMap = new WeakMap();\n  var screenfull = {};\n\n  var Player = /*#__PURE__*/function () {\n    /**\n     * Create a Player.\n     *\n     * @param {(HTMLIFrameElement|HTMLElement|string|jQuery)} element A reference to the Vimeo\n     *        player iframe, and id, or a jQuery object.\n     * @param {object} [options] oEmbed parameters to use when creating an embed in the element.\n     * @return {Player}\n     */\n    function Player(element) {\n      var _this = this;\n\n      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n      _classCallCheck(this, Player);\n\n      /* global jQuery */\n      if (window.jQuery && element instanceof jQuery) {\n        if (element.length > 1 && window.console && console.warn) {\n          console.warn('A jQuery object with multiple elements was passed, using the first element.');\n        }\n\n        element = element[0];\n      } // Find an element by ID\n\n\n      if (typeof document !== 'undefined' && typeof element === 'string') {\n        element = document.getElementById(element);\n      } // Not an element!\n\n\n      if (!isDomElement(element)) {\n        throw new TypeError('You must pass either a valid element or a valid id.');\n      } // Already initialized an embed in this div, so grab the iframe\n\n\n      if (element.nodeName !== 'IFRAME') {\n        var iframe = element.querySelector('iframe');\n\n        if (iframe) {\n          element = iframe;\n        }\n      } // iframe url is not a Vimeo url\n\n\n      if (element.nodeName === 'IFRAME' && !isVimeoUrl(element.getAttribute('src') || '')) {\n        throw new Error('The player element passed isn\u2019t a Vimeo embed.');\n      } // If there is already a player object in the map, return that\n\n\n      if (playerMap.has(element)) {\n        return playerMap.get(element);\n      }\n\n      this._window = element.ownerDocument.defaultView;\n      this.element = element;\n      this.origin = '*';\n      var readyPromise = new npo_src(function (resolve, reject) {\n        _this._onMessage = function (event) {\n          if (!isVimeoUrl(event.origin) || _this.element.contentWindow !== event.source) {\n            return;\n          }\n\n          if (_this.origin === '*') {\n            _this.origin = event.origin;\n          }\n\n          var data = parseMessageData(event.data);\n          var isError = data && data.event === 'error';\n          var isReadyError = isError && data.data && data.data.method === 'ready';\n\n          if (isReadyError) {\n            var error = new Error(data.data.message);\n            error.name = data.data.name;\n            reject(error);\n            return;\n          }\n\n          var isReadyEvent = data && data.event === 'ready';\n          var isPingResponse = data && data.method === 'ping';\n\n          if (isReadyEvent || isPingResponse) {\n            _this.element.setAttribute('data-ready', 'true');\n\n            resolve();\n            return;\n          }\n\n          processData(_this, data);\n        };\n\n        _this._window.addEventListener('message', _this._onMessage);\n\n        if (_this.element.nodeName !== 'IFRAME') {\n          var params = getOEmbedParameters(element, options);\n          var url = getVimeoUrl(params);\n          getOEmbedData(url, params, element).then(function (data) {\n            var iframe = createEmbed(data, element); // Overwrite element with the new iframe,\n            // but store reference to the original element\n\n            _this.element = iframe;\n            _this._originalElement = element;\n            swapCallbacks(element, iframe);\n            playerMap.set(_this.element, _this);\n            return data;\n          }).catch(reject);\n        }\n      }); // Store a copy of this Player in the map\n\n      readyMap.set(this, readyPromise);\n      playerMap.set(this.element, this); // Send a ping to the iframe so the ready promise will be resolved if\n      // the player is already ready.\n\n      if (this.element.nodeName === 'IFRAME') {\n        postMessage(this, 'ping');\n      }\n\n      if (screenfull.isEnabled) {\n        var exitFullscreen = function exitFullscreen() {\n          return screenfull.exit();\n        };\n\n        this.fullscreenchangeHandler = function () {\n          if (screenfull.isFullscreen) {\n            storeCallback(_this, 'event:exitFullscreen', exitFullscreen);\n          } else {\n            removeCallback(_this, 'event:exitFullscreen', exitFullscreen);\n          } // eslint-disable-next-line\n\n\n          _this.ready().then(function () {\n            postMessage(_this, 'fullscreenchange', screenfull.isFullscreen);\n          });\n        };\n\n        screenfull.on('fullscreenchange', this.fullscreenchangeHandler);\n      }\n\n      return this;\n    }\n    /**\n     * Get a promise for a method.\n     *\n     * @param {string} name The API method to call.\n     * @param {Object} [args={}] Arguments to send via postMessage.\n     * @return {Promise}\n     */\n\n\n    _createClass(Player, [{\n      key: \"callMethod\",\n      value: function callMethod(name) {\n        var _this2 = this;\n\n        var args = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n        return new npo_src(function (resolve, reject) {\n          // We are storing the resolve/reject handlers to call later, so we\n          // can\u2019t return here.\n          // eslint-disable-next-line promise/always-return\n          return _this2.ready().then(function () {\n            storeCallback(_this2, name, {\n              resolve: resolve,\n              reject: reject\n            });\n            postMessage(_this2, name, args);\n          }).catch(reject);\n        });\n      }\n      /**\n       * Get a promise for the value of a player property.\n       *\n       * @param {string} name The property name\n       * @return {Promise}\n       */\n\n    }, {\n      key: \"get\",\n      value: function get(name) {\n        var _this3 = this;\n\n        return new npo_src(function (resolve, reject) {\n          name = getMethodName(name, 'get'); // We are storing the resolve/reject handlers to call later, so we\n          // can\u2019t return here.\n          // eslint-disable-next-line promise/always-return\n\n          return _this3.ready().then(function () {\n            storeCallback(_this3, name, {\n              resolve: resolve,\n              reject: reject\n            });\n            postMessage(_this3, name);\n          }).catch(reject);\n        });\n      }\n      /**\n       * Get a promise for setting the value of a player property.\n       *\n       * @param {string} name The API method to call.\n       * @param {mixed} value The value to set.\n       * @return {Promise}\n       */\n\n    }, {\n      key: \"set\",\n      value: function set(name, value) {\n        var _this4 = this;\n\n        return new npo_src(function (resolve, reject) {\n          name = getMethodName(name, 'set');\n\n          if (value === undefined || value === null) {\n            throw new TypeError('There must be a value to set.');\n          } // We are storing the resolve/reject handlers to call later, so we\n          // can\u2019t return here.\n          // eslint-disable-next-line promise/always-return\n\n\n          return _this4.ready().then(function () {\n            storeCallback(_this4, name, {\n              resolve: resolve,\n              reject: reject\n            });\n            postMessage(_this4, name, value);\n          }).catch(reject);\n        });\n      }\n      /**\n       * Add an event listener for the specified event. Will call the\n       * callback with a single parameter, `data`, that contains the data for\n       * that event.\n       *\n       * @param {string} eventName The name of the event.\n       * @param {function(*)} callback The function to call when the event fires.\n       * @return {void}\n       */\n\n    }, {\n      key: \"on\",\n      value: function on(eventName, callback) {\n        if (!eventName) {\n          throw new TypeError('You must pass an event name.');\n        }\n\n        if (!callback) {\n          throw new TypeError('You must pass a callback function.');\n        }\n\n        if (typeof callback !== 'function') {\n          throw new TypeError('The callback must be a function.');\n        }\n\n        var callbacks = getCallbacks(this, \"event:\".concat(eventName));\n\n        if (callbacks.length === 0) {\n          this.callMethod('addEventListener', eventName).catch(function () {// Ignore the error. There will be an error event fired that\n            // will trigger the error callback if they are listening.\n          });\n        }\n\n        storeCallback(this, \"event:\".concat(eventName), callback);\n      }\n      /**\n       * Remove an event listener for the specified event. Will remove all\n       * listeners for that event if a `callback` isn\u2019t passed, or only that\n       * specific callback if it is passed.\n       *\n       * @param {string} eventName The name of the event.\n       * @param {function} [callback] The specific callback to remove.\n       * @return {void}\n       */\n\n    }, {\n      key: \"off\",\n      value: function off(eventName, callback) {\n        if (!eventName) {\n          throw new TypeError('You must pass an event name.');\n        }\n\n        if (callback && typeof callback !== 'function') {\n          throw new TypeError('The callback must be a function.');\n        }\n\n        var lastCallback = removeCallback(this, \"event:\".concat(eventName), callback); // If there are no callbacks left, remove the listener\n\n        if (lastCallback) {\n          this.callMethod('removeEventListener', eventName).catch(function (e) {// Ignore the error. There will be an error event fired that\n            // will trigger the error callback if they are listening.\n          });\n        }\n      }\n      /**\n       * A promise to load a new video.\n       *\n       * @promise LoadVideoPromise\n       * @fulfill {number} The video with this id or url successfully loaded.\n       * @reject {TypeError} The id was not a number.\n       */\n\n      /**\n       * Load a new video into this embed. The promise will be resolved if\n       * the video is successfully loaded, or it will be rejected if it could\n       * not be loaded.\n       *\n       * @param {number|string|object} options The id of the video, the url of the video, or an object with embed options.\n       * @return {LoadVideoPromise}\n       */\n\n    }, {\n      key: \"loadVideo\",\n      value: function loadVideo(options) {\n        return this.callMethod('loadVideo', options);\n      }\n      /**\n       * A promise to perform an action when the Player is ready.\n       *\n       * @todo document errors\n       * @promise LoadVideoPromise\n       * @fulfill {void}\n       */\n\n      /**\n       * Trigger a function when the player iframe has initialized. You do not\n       * need to wait for `ready` to trigger to begin adding event listeners\n       * or calling other methods.\n       *\n       * @return {ReadyPromise}\n       */\n\n    }, {\n      key: \"ready\",\n      value: function ready() {\n        var readyPromise = readyMap.get(this) || new npo_src(function (resolve, reject) {\n          reject(new Error('Unknown player. Probably unloaded.'));\n        });\n        return npo_src.resolve(readyPromise);\n      }\n      /**\n       * A promise to add a cue point to the player.\n       *\n       * @promise AddCuePointPromise\n       * @fulfill {string} The id of the cue point to use for removeCuePoint.\n       * @reject {RangeError} the time was less than 0 or greater than the\n       *         video\u2019s duration.\n       * @reject {UnsupportedError} Cue points are not supported with the current\n       *         player or browser.\n       */\n\n      /**\n       * Add a cue point to the player.\n       *\n       * @param {number} time The time for the cue point.\n       * @param {object} [data] Arbitrary data to be returned with the cue point.\n       * @return {AddCuePointPromise}\n       */\n\n    }, {\n      key: \"addCuePoint\",\n      value: function addCuePoint(time) {\n        var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n        return this.callMethod('addCuePoint', {\n          time: time,\n          data: data\n        });\n      }\n      /**\n       * A promise to remove a cue point from the player.\n       *\n       * @promise AddCuePointPromise\n       * @fulfill {string} The id of the cue point that was removed.\n       * @reject {InvalidCuePoint} The cue point with the specified id was not\n       *         found.\n       * @reject {UnsupportedError} Cue points are not supported with the current\n       *         player or browser.\n       */\n\n      /**\n       * Remove a cue point from the video.\n       *\n       * @param {string} id The id of the cue point to remove.\n       * @return {RemoveCuePointPromise}\n       */\n\n    }, {\n      key: \"removeCuePoint\",\n      value: function removeCuePoint(id) {\n        return this.callMethod('removeCuePoint', id);\n      }\n      /**\n       * A representation of a text track on a video.\n       *\n       * @typedef {Object} VimeoTextTrack\n       * @property {string} language The ISO language code.\n       * @property {string} kind The kind of track it is (captions or subtitles).\n       * @property {string} label The human\u2010readable label for the track.\n       */\n\n      /**\n       * A promise to enable a text track.\n       *\n       * @promise EnableTextTrackPromise\n       * @fulfill {VimeoTextTrack} The text track that was enabled.\n       * @reject {InvalidTrackLanguageError} No track was available with the\n       *         specified language.\n       * @reject {InvalidTrackError} No track was available with the specified\n       *         language and kind.\n       */\n\n      /**\n       * Enable the text track with the specified language, and optionally the\n       * specified kind (captions or subtitles).\n       *\n       * When set via the API, the track language will not change the viewer\u2019s\n       * stored preference.\n       *\n       * @param {string} language The two\u2010letter language code.\n       * @param {string} [kind] The kind of track to enable (captions or subtitles).\n       * @return {EnableTextTrackPromise}\n       */\n\n    }, {\n      key: \"enableTextTrack\",\n      value: function enableTextTrack(language, kind) {\n        if (!language) {\n          throw new TypeError('You must pass a language.');\n        }\n\n        return this.callMethod('enableTextTrack', {\n          language: language,\n          kind: kind\n        });\n      }\n      /**\n       * A promise to disable the active text track.\n       *\n       * @promise DisableTextTrackPromise\n       * @fulfill {void} The track was disabled.\n       */\n\n      /**\n       * Disable the currently-active text track.\n       *\n       * @return {DisableTextTrackPromise}\n       */\n\n    }, {\n      key: \"disableTextTrack\",\n      value: function disableTextTrack() {\n        return this.callMethod('disableTextTrack');\n      }\n      /**\n       * A promise to pause the video.\n       *\n       * @promise PausePromise\n       * @fulfill {void} The video was paused.\n       */\n\n      /**\n       * Pause the video if it\u2019s playing.\n       *\n       * @return {PausePromise}\n       */\n\n    }, {\n      key: \"pause\",\n      value: function pause() {\n        return this.callMethod('pause');\n      }\n      /**\n       * A promise to play the video.\n       *\n       * @promise PlayPromise\n       * @fulfill {void} The video was played.\n       */\n\n      /**\n       * Play the video if it\u2019s paused. **Note:** on iOS and some other\n       * mobile devices, you cannot programmatically trigger play. Once the\n       * viewer has tapped on the play button in the player, however, you\n       * will be able to use this function.\n       *\n       * @return {PlayPromise}\n       */\n\n    }, {\n      key: \"play\",\n      value: function play() {\n        return this.callMethod('play');\n      }\n      /**\n       * Request that the player enters fullscreen.\n       * @return {Promise}\n       */\n\n    }, {\n      key: \"requestFullscreen\",\n      value: function requestFullscreen() {\n        if (screenfull.isEnabled) {\n          return screenfull.request(this.element);\n        }\n\n        return this.callMethod('requestFullscreen');\n      }\n      /**\n       * Request that the player exits fullscreen.\n       * @return {Promise}\n       */\n\n    }, {\n      key: \"exitFullscreen\",\n      value: function exitFullscreen() {\n        if (screenfull.isEnabled) {\n          return screenfull.exit();\n        }\n\n        return this.callMethod('exitFullscreen');\n      }\n      /**\n       * Returns true if the player is currently fullscreen.\n       * @return {Promise}\n       */\n\n    }, {\n      key: \"getFullscreen\",\n      value: function getFullscreen() {\n        if (screenfull.isEnabled) {\n          return npo_src.resolve(screenfull.isFullscreen);\n        }\n\n        return this.get('fullscreen');\n      }\n      /**\n       * Request that the player enters picture-in-picture.\n       * @return {Promise}\n       */\n\n    }, {\n      key: \"requestPictureInPicture\",\n      value: function requestPictureInPicture() {\n        return this.callMethod('requestPictureInPicture');\n      }\n      /**\n       * Request that the player exits picture-in-picture.\n       * @return {Promise}\n       */\n\n    }, {\n      key: \"exitPictureInPicture\",\n      value: function exitPictureInPicture() {\n        return this.callMethod('exitPictureInPicture');\n      }\n      /**\n       * Returns true if the player is currently picture-in-picture.\n       * @return {Promise}\n       */\n\n    }, {\n      key: \"getPictureInPicture\",\n      value: function getPictureInPicture() {\n        return this.get('pictureInPicture');\n      }\n      /**\n       * A promise to unload the video.\n       *\n       * @promise UnloadPromise\n       * @fulfill {void} The video was unloaded.\n       */\n\n      /**\n       * Return the player to its initial state.\n       *\n       * @return {UnloadPromise}\n       */\n\n    }, {\n      key: \"unload\",\n      value: function unload() {\n        return this.callMethod('unload');\n      }\n      /**\n       * Cleanup the player and remove it from the DOM\n       *\n       * It won't be usable and a new one should be constructed\n       *  in order to do any operations.\n       *\n       * @return {Promise}\n       */\n\n    }, {\n      key: \"destroy\",\n      value: function destroy() {\n        var _this5 = this;\n\n        return new npo_src(function (resolve) {\n          readyMap.delete(_this5);\n          playerMap.delete(_this5.element);\n\n          if (_this5._originalElement) {\n            playerMap.delete(_this5._originalElement);\n\n            _this5._originalElement.removeAttribute('data-vimeo-initialized');\n          }\n\n          if (_this5.element && _this5.element.nodeName === 'IFRAME' && _this5.element.parentNode) {\n            // If we've added an additional wrapper div, remove that from the DOM.\n            // If not, just remove the iframe element.\n            if (_this5.element.parentNode.parentNode && _this5._originalElement && _this5._originalElement !== _this5.element.parentNode) {\n              _this5.element.parentNode.parentNode.removeChild(_this5.element.parentNode);\n            } else {\n              _this5.element.parentNode.removeChild(_this5.element);\n            }\n          } // If the clip is private there is a case where the element stays the\n          // div element. Destroy should reset the div and remove the iframe child.\n\n\n          if (_this5.element && _this5.element.nodeName === 'DIV' && _this5.element.parentNode) {\n            _this5.element.removeAttribute('data-vimeo-initialized');\n\n            var iframe = _this5.element.querySelector('iframe');\n\n            if (iframe && iframe.parentNode) {\n              // If we've added an additional wrapper div, remove that from the DOM.\n              // If not, just remove the iframe element.\n              if (iframe.parentNode.parentNode && _this5._originalElement && _this5._originalElement !== iframe.parentNode) {\n                iframe.parentNode.parentNode.removeChild(iframe.parentNode);\n              } else {\n                iframe.parentNode.removeChild(iframe);\n              }\n            }\n          }\n\n          _this5._window.removeEventListener('message', _this5._onMessage);\n\n          if (screenfull.isEnabled) {\n            screenfull.off('fullscreenchange', _this5.fullscreenchangeHandler);\n          }\n\n          resolve();\n        });\n      }\n      /**\n       * A promise to get the autopause behavior of the video.\n       *\n       * @promise GetAutopausePromise\n       * @fulfill {boolean} Whether autopause is turned on or off.\n       * @reject {UnsupportedError} Autopause is not supported with the current\n       *         player or browser.\n       */\n\n      /**\n       * Get the autopause behavior for this player.\n       *\n       * @return {GetAutopausePromise}\n       */\n\n    }, {\n      key: \"getAutopause\",\n      value: function getAutopause() {\n        return this.get('autopause');\n      }\n      /**\n       * A promise to set the autopause behavior of the video.\n       *\n       * @promise SetAutopausePromise\n       * @fulfill {boolean} Whether autopause is turned on or off.\n       * @reject {UnsupportedError} Autopause is not supported with the current\n       *         player or browser.\n       */\n\n      /**\n       * Enable or disable the autopause behavior of this player.\n       *\n       * By default, when another video is played in the same browser, this\n       * player will automatically pause. Unless you have a specific reason\n       * for doing so, we recommend that you leave autopause set to the\n       * default (`true`).\n       *\n       * @param {boolean} autopause\n       * @return {SetAutopausePromise}\n       */\n\n    }, {\n      key: \"setAutopause\",\n      value: function setAutopause(autopause) {\n        return this.set('autopause', autopause);\n      }\n      /**\n       * A promise to get the buffered property of the video.\n       *\n       * @promise GetBufferedPromise\n       * @fulfill {Array} Buffered Timeranges converted to an Array.\n       */\n\n      /**\n       * Get the buffered property of the video.\n       *\n       * @return {GetBufferedPromise}\n       */\n\n    }, {\n      key: \"getBuffered\",\n      value: function getBuffered() {\n        return this.get('buffered');\n      }\n      /**\n       * @typedef {Object} CameraProperties\n       * @prop {number} props.yaw - Number between 0 and 360.\n       * @prop {number} props.pitch - Number between -90 and 90.\n       * @prop {number} props.roll - Number between -180 and 180.\n       * @prop {number} props.fov - The field of view in degrees.\n       */\n\n      /**\n       * A promise to get the camera properties of the player.\n       *\n       * @promise GetCameraPromise\n       * @fulfill {CameraProperties} The camera properties.\n       */\n\n      /**\n       * For 360\u00b0 videos get the camera properties for this player.\n       *\n       * @return {GetCameraPromise}\n       */\n\n    }, {\n      key: \"getCameraProps\",\n      value: function getCameraProps() {\n        return this.get('cameraProps');\n      }\n      /**\n       * A promise to set the camera properties of the player.\n       *\n       * @promise SetCameraPromise\n       * @fulfill {Object} The camera was successfully set.\n       * @reject {RangeError} The range was out of bounds.\n       */\n\n      /**\n       * For 360\u00b0 videos set the camera properties for this player.\n       *\n       * @param {CameraProperties} camera The camera properties\n       * @return {SetCameraPromise}\n       */\n\n    }, {\n      key: \"setCameraProps\",\n      value: function setCameraProps(camera) {\n        return this.set('cameraProps', camera);\n      }\n      /**\n       * A representation of a chapter.\n       *\n       * @typedef {Object} VimeoChapter\n       * @property {number} startTime The start time of the chapter.\n       * @property {object} title The title of the chapter.\n       * @property {number} index The place in the order of Chapters. Starts at 1.\n       */\n\n      /**\n       * A promise to get chapters for the video.\n       *\n       * @promise GetChaptersPromise\n       * @fulfill {VimeoChapter[]} The chapters for the video.\n       */\n\n      /**\n       * Get an array of all the chapters for the video.\n       *\n       * @return {GetChaptersPromise}\n       */\n\n    }, {\n      key: \"getChapters\",\n      value: function getChapters() {\n        return this.get('chapters');\n      }\n      /**\n       * A promise to get the currently active chapter.\n       *\n       * @promise GetCurrentChaptersPromise\n       * @fulfill {VimeoChapter|undefined} The current chapter for the video.\n       */\n\n      /**\n       * Get the currently active chapter for the video.\n       *\n       * @return {GetCurrentChaptersPromise}\n       */\n\n    }, {\n      key: \"getCurrentChapter\",\n      value: function getCurrentChapter() {\n        return this.get('currentChapter');\n      }\n      /**\n       * A promise to get the color of the player.\n       *\n       * @promise GetColorPromise\n       * @fulfill {string} The hex color of the player.\n       */\n\n      /**\n       * Get the color for this player.\n       *\n       * @return {GetColorPromise}\n       */\n\n    }, {\n      key: \"getColor\",\n      value: function getColor() {\n        return this.get('color');\n      }\n      /**\n       * A promise to set the color of the player.\n       *\n       * @promise SetColorPromise\n       * @fulfill {string} The color was successfully set.\n       * @reject {TypeError} The string was not a valid hex or rgb color.\n       * @reject {ContrastError} The color was set, but the contrast is\n       *         outside of the acceptable range.\n       * @reject {EmbedSettingsError} The owner of the player has chosen to\n       *         use a specific color.\n       */\n\n      /**\n       * Set the color of this player to a hex or rgb string. Setting the\n       * color may fail if the owner of the video has set their embed\n       * preferences to force a specific color.\n       *\n       * @param {string} color The hex or rgb color string to set.\n       * @return {SetColorPromise}\n       */\n\n    }, {\n      key: \"setColor\",\n      value: function setColor(color) {\n        return this.set('color', color);\n      }\n      /**\n       * A representation of a cue point.\n       *\n       * @typedef {Object} VimeoCuePoint\n       * @property {number} time The time of the cue point.\n       * @property {object} data The data passed when adding the cue point.\n       * @property {string} id The unique id for use with removeCuePoint.\n       */\n\n      /**\n       * A promise to get the cue points of a video.\n       *\n       * @promise GetCuePointsPromise\n       * @fulfill {VimeoCuePoint[]} The cue points added to the video.\n       * @reject {UnsupportedError} Cue points are not supported with the current\n       *         player or browser.\n       */\n\n      /**\n       * Get an array of the cue points added to the video.\n       *\n       * @return {GetCuePointsPromise}\n       */\n\n    }, {\n      key: \"getCuePoints\",\n      value: function getCuePoints() {\n        return this.get('cuePoints');\n      }\n      /**\n       * A promise to get the current time of the video.\n       *\n       * @promise GetCurrentTimePromise\n       * @fulfill {number} The current time in seconds.\n       */\n\n      /**\n       * Get the current playback position in seconds.\n       *\n       * @return {GetCurrentTimePromise}\n       */\n\n    }, {\n      key: \"getCurrentTime\",\n      value: function getCurrentTime() {\n        return this.get('currentTime');\n      }\n      /**\n       * A promise to set the current time of the video.\n       *\n       * @promise SetCurrentTimePromise\n       * @fulfill {number} The actual current time that was set.\n       * @reject {RangeError} the time was less than 0 or greater than the\n       *         video\u2019s duration.\n       */\n\n      /**\n       * Set the current playback position in seconds. If the player was\n       * paused, it will remain paused. Likewise, if the player was playing,\n       * it will resume playing once the video has buffered.\n       *\n       * You can provide an accurate time and the player will attempt to seek\n       * to as close to that time as possible. The exact time will be the\n       * fulfilled value of the promise.\n       *\n       * @param {number} currentTime\n       * @return {SetCurrentTimePromise}\n       */\n\n    }, {\n      key: \"setCurrentTime\",\n      value: function setCurrentTime(currentTime) {\n        return this.set('currentTime', currentTime);\n      }\n      /**\n       * A promise to get the duration of the video.\n       *\n       * @promise GetDurationPromise\n       * @fulfill {number} The duration in seconds.\n       */\n\n      /**\n       * Get the duration of the video in seconds. It will be rounded to the\n       * nearest second before playback begins, and to the nearest thousandth\n       * of a second after playback begins.\n       *\n       * @return {GetDurationPromise}\n       */\n\n    }, {\n      key: \"getDuration\",\n      value: function getDuration() {\n        return this.get('duration');\n      }\n      /**\n       * A promise to get the ended state of the video.\n       *\n       * @promise GetEndedPromise\n       * @fulfill {boolean} Whether or not the video has ended.\n       */\n\n      /**\n       * Get the ended state of the video. The video has ended if\n       * `currentTime === duration`.\n       *\n       * @return {GetEndedPromise}\n       */\n\n    }, {\n      key: \"getEnded\",\n      value: function getEnded() {\n        return this.get('ended');\n      }\n      /**\n       * A promise to get the loop state of the player.\n       *\n       * @promise GetLoopPromise\n       * @fulfill {boolean} Whether or not the player is set to loop.\n       */\n\n      /**\n       * Get the loop state of the player.\n       *\n       * @return {GetLoopPromise}\n       */\n\n    }, {\n      key: \"getLoop\",\n      value: function getLoop() {\n        return this.get('loop');\n      }\n      /**\n       * A promise to set the loop state of the player.\n       *\n       * @promise SetLoopPromise\n       * @fulfill {boolean} The loop state that was set.\n       */\n\n      /**\n       * Set the loop state of the player. When set to `true`, the player\n       * will start over immediately once playback ends.\n       *\n       * @param {boolean} loop\n       * @return {SetLoopPromise}\n       */\n\n    }, {\n      key: \"setLoop\",\n      value: function setLoop(loop) {\n        return this.set('loop', loop);\n      }\n      /**\n       * A promise to set the muted state of the player.\n       *\n       * @promise SetMutedPromise\n       * @fulfill {boolean} The muted state that was set.\n       */\n\n      /**\n       * Set the muted state of the player. When set to `true`, the player\n       * volume will be muted.\n       *\n       * @param {boolean} muted\n       * @return {SetMutedPromise}\n       */\n\n    }, {\n      key: \"setMuted\",\n      value: function setMuted(muted) {\n        return this.set('muted', muted);\n      }\n      /**\n       * A promise to get the muted state of the player.\n       *\n       * @promise GetMutedPromise\n       * @fulfill {boolean} Whether or not the player is muted.\n       */\n\n      /**\n       * Get the muted state of the player.\n       *\n       * @return {GetMutedPromise}\n       */\n\n    }, {\n      key: \"getMuted\",\n      value: function getMuted() {\n        return this.get('muted');\n      }\n      /**\n       * A promise to get the paused state of the player.\n       *\n       * @promise GetLoopPromise\n       * @fulfill {boolean} Whether or not the video is paused.\n       */\n\n      /**\n       * Get the paused state of the player.\n       *\n       * @return {GetLoopPromise}\n       */\n\n    }, {\n      key: \"getPaused\",\n      value: function getPaused() {\n        return this.get('paused');\n      }\n      /**\n       * A promise to get the playback rate of the player.\n       *\n       * @promise GetPlaybackRatePromise\n       * @fulfill {number} The playback rate of the player on a scale from 0.5 to 2.\n       */\n\n      /**\n       * Get the playback rate of the player on a scale from `0.5` to `2`.\n       *\n       * @return {GetPlaybackRatePromise}\n       */\n\n    }, {\n      key: \"getPlaybackRate\",\n      value: function getPlaybackRate() {\n        return this.get('playbackRate');\n      }\n      /**\n       * A promise to set the playbackrate of the player.\n       *\n       * @promise SetPlaybackRatePromise\n       * @fulfill {number} The playback rate was set.\n       * @reject {RangeError} The playback rate was less than 0.5 or greater than 2.\n       */\n\n      /**\n       * Set the playback rate of the player on a scale from `0.5` to `2`. When set\n       * via the API, the playback rate will not be synchronized to other\n       * players or stored as the viewer's preference.\n       *\n       * @param {number} playbackRate\n       * @return {SetPlaybackRatePromise}\n       */\n\n    }, {\n      key: \"setPlaybackRate\",\n      value: function setPlaybackRate(playbackRate) {\n        return this.set('playbackRate', playbackRate);\n      }\n      /**\n       * A promise to get the played property of the video.\n       *\n       * @promise GetPlayedPromise\n       * @fulfill {Array} Played Timeranges converted to an Array.\n       */\n\n      /**\n       * Get the played property of the video.\n       *\n       * @return {GetPlayedPromise}\n       */\n\n    }, {\n      key: \"getPlayed\",\n      value: function getPlayed() {\n        return this.get('played');\n      }\n      /**\n       * A promise to get the qualities available of the current video.\n       *\n       * @promise GetQualitiesPromise\n       * @fulfill {Array} The qualities of the video.\n       */\n\n      /**\n       * Get the qualities of the current video.\n       *\n       * @return {GetQualitiesPromise}\n       */\n\n    }, {\n      key: \"getQualities\",\n      value: function getQualities() {\n        return this.get('qualities');\n      }\n      /**\n       * A promise to get the current set quality of the video.\n       *\n       * @promise GetQualityPromise\n       * @fulfill {string} The current set quality.\n       */\n\n      /**\n       * Get the current set quality of the video.\n       *\n       * @return {GetQualityPromise}\n       */\n\n    }, {\n      key: \"getQuality\",\n      value: function getQuality() {\n        return this.get('quality');\n      }\n      /**\n       * A promise to set the video quality.\n       *\n       * @promise SetQualityPromise\n       * @fulfill {number} The quality was set.\n       * @reject {RangeError} The quality is not available.\n       */\n\n      /**\n       * Set a video quality.\n       *\n       * @param {string} quality\n       * @return {SetQualityPromise}\n       */\n\n    }, {\n      key: \"setQuality\",\n      value: function setQuality(quality) {\n        return this.set('quality', quality);\n      }\n      /**\n       * A promise to get the seekable property of the video.\n       *\n       * @promise GetSeekablePromise\n       * @fulfill {Array} Seekable Timeranges converted to an Array.\n       */\n\n      /**\n       * Get the seekable property of the video.\n       *\n       * @return {GetSeekablePromise}\n       */\n\n    }, {\n      key: \"getSeekable\",\n      value: function getSeekable() {\n        return this.get('seekable');\n      }\n      /**\n       * A promise to get the seeking property of the player.\n       *\n       * @promise GetSeekingPromise\n       * @fulfill {boolean} Whether or not the player is currently seeking.\n       */\n\n      /**\n       * Get if the player is currently seeking.\n       *\n       * @return {GetSeekingPromise}\n       */\n\n    }, {\n      key: \"getSeeking\",\n      value: function getSeeking() {\n        return this.get('seeking');\n      }\n      /**\n       * A promise to get the text tracks of a video.\n       *\n       * @promise GetTextTracksPromise\n       * @fulfill {VimeoTextTrack[]} The text tracks associated with the video.\n       */\n\n      /**\n       * Get an array of the text tracks that exist for the video.\n       *\n       * @return {GetTextTracksPromise}\n       */\n\n    }, {\n      key: \"getTextTracks\",\n      value: function getTextTracks() {\n        return this.get('textTracks');\n      }\n      /**\n       * A promise to get the embed code for the video.\n       *\n       * @promise GetVideoEmbedCodePromise\n       * @fulfill {string} The `<iframe>` embed code for the video.\n       */\n\n      /**\n       * Get the `<iframe>` embed code for the video.\n       *\n       * @return {GetVideoEmbedCodePromise}\n       */\n\n    }, {\n      key: \"getVideoEmbedCode\",\n      value: function getVideoEmbedCode() {\n        return this.get('videoEmbedCode');\n      }\n      /**\n       * A promise to get the id of the video.\n       *\n       * @promise GetVideoIdPromise\n       * @fulfill {number} The id of the video.\n       */\n\n      /**\n       * Get the id of the video.\n       *\n       * @return {GetVideoIdPromise}\n       */\n\n    }, {\n      key: \"getVideoId\",\n      value: function getVideoId() {\n        return this.get('videoId');\n      }\n      /**\n       * A promise to get the title of the video.\n       *\n       * @promise GetVideoTitlePromise\n       * @fulfill {number} The title of the video.\n       */\n\n      /**\n       * Get the title of the video.\n       *\n       * @return {GetVideoTitlePromise}\n       */\n\n    }, {\n      key: \"getVideoTitle\",\n      value: function getVideoTitle() {\n        return this.get('videoTitle');\n      }\n      /**\n       * A promise to get the native width of the video.\n       *\n       * @promise GetVideoWidthPromise\n       * @fulfill {number} The native width of the video.\n       */\n\n      /**\n       * Get the native width of the currently\u2010playing video. The width of\n       * the highest\u2010resolution available will be used before playback begins.\n       *\n       * @return {GetVideoWidthPromise}\n       */\n\n    }, {\n      key: \"getVideoWidth\",\n      value: function getVideoWidth() {\n        return this.get('videoWidth');\n      }\n      /**\n       * A promise to get the native height of the video.\n       *\n       * @promise GetVideoHeightPromise\n       * @fulfill {number} The native height of the video.\n       */\n\n      /**\n       * Get the native height of the currently\u2010playing video. The height of\n       * the highest\u2010resolution available will be used before playback begins.\n       *\n       * @return {GetVideoHeightPromise}\n       */\n\n    }, {\n      key: \"getVideoHeight\",\n      value: function getVideoHeight() {\n        return this.get('videoHeight');\n      }\n      /**\n       * A promise to get the vimeo.com url for the video.\n       *\n       * @promise GetVideoUrlPromise\n       * @fulfill {number} The vimeo.com url for the video.\n       * @reject {PrivacyError} The url isn\u2019t available because of the video\u2019s privacy setting.\n       */\n\n      /**\n       * Get the vimeo.com url for the video.\n       *\n       * @return {GetVideoUrlPromise}\n       */\n\n    }, {\n      key: \"getVideoUrl\",\n      value: function getVideoUrl() {\n        return this.get('videoUrl');\n      }\n      /**\n       * A promise to get the volume level of the player.\n       *\n       * @promise GetVolumePromise\n       * @fulfill {number} The volume level of the player on a scale from 0 to 1.\n       */\n\n      /**\n       * Get the current volume level of the player on a scale from `0` to `1`.\n       *\n       * Most mobile devices do not support an independent volume from the\n       * system volume. In those cases, this method will always return `1`.\n       *\n       * @return {GetVolumePromise}\n       */\n\n    }, {\n      key: \"getVolume\",\n      value: function getVolume() {\n        return this.get('volume');\n      }\n      /**\n       * A promise to set the volume level of the player.\n       *\n       * @promise SetVolumePromise\n       * @fulfill {number} The volume was set.\n       * @reject {RangeError} The volume was less than 0 or greater than 1.\n       */\n\n      /**\n       * Set the volume of the player on a scale from `0` to `1`. When set\n       * via the API, the volume level will not be synchronized to other\n       * players or stored as the viewer\u2019s preference.\n       *\n       * Most mobile devices do not support setting the volume. An error will\n       * *not* be triggered in that situation.\n       *\n       * @param {number} volume\n       * @return {SetVolumePromise}\n       */\n\n    }, {\n      key: \"setVolume\",\n      value: function setVolume(volume) {\n        return this.set('volume', volume);\n      }\n    }]);\n\n    return Player;\n  }(); // Setup embed only if this is not a node environment\n\n\n  if (!isNode) {\n    screenfull = initializeScreenfull();\n    initializeEmbeds();\n    resizeEmbeds();\n  }\n\n  return Player;\n\n})));\n\n//# sourceMappingURL=player.js.map","vimeo/player.min.js":"/*! @vimeo/player v2.16.4 | (c) 2022 Vimeo | MIT License | https://github.com/vimeo/player.js */\n!function(e,t){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=t():\"function\"==typeof define&&define.amd?define(t):((e=\"undefined\"!=typeof globalThis?globalThis:e||self).Vimeo=e.Vimeo||{},e.Vimeo.Player=t())}(this,function(){\"use strict\";function r(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,\"value\"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}var e=\"undefined\"!=typeof global&&\"[object global]\"==={}.toString.call(global);function i(e,t){return 0===e.indexOf(t.toLowerCase())?e:\"\".concat(t.toLowerCase()).concat(e.substr(0,1).toUpperCase()).concat(e.substr(1))}function l(e){return/^(https?:)?\\/\\/((player|www)\\.)?vimeo\\.com(?=$|\\/)/.test(e)}function u(e){var t=0<arguments.length&&void 0!==e?e:{},n=t.id,e=t.url,t=n||e;if(!t)throw new Error(\"An id or url must be passed, either in an options object or as a data-vimeo-id or data-vimeo-url attribute.\");if(e=t,!isNaN(parseFloat(e))&&isFinite(e)&&Math.floor(e)==e)return\"https://vimeo.com/\".concat(t);if(l(t))return t.replace(\"http:\",\"https:\");if(n)throw new TypeError(\"\u201c\".concat(n,\"\u201d is not a valid video id.\"));throw new TypeError(\"\u201c\".concat(t,\"\u201d is not a vimeo.com url.\"))}var t=void 0!==Array.prototype.indexOf,Player=\"undefined\"!=typeof window&&void 0!==window.postMessage;if(!(e||t&&Player))throw new Error(\"Sorry, the Vimeo Player API is not available in this browser.\");var n,o,a=\"undefined\"!=typeof globalThis?globalThis:\"undefined\"!=typeof window?window:\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:{};function c(){if(void 0===this)throw new TypeError(\"Constructor WeakMap requires 'new'\");if(o(this,\"_id\",\"_WeakMap_\"+f()+\".\"+f()),0<arguments.length)throw new TypeError(\"WeakMap iterable is not supported\")}function s(e,t){if(!d(e)||!n.call(e,\"_id\"))throw new TypeError(t+\" method called on incompatible receiver \"+typeof e)}function f(){return Math.random().toString().substring(2)}function d(e){return Object(e)===e}(Player=\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:a).WeakMap||(n=Object.prototype.hasOwnProperty,Player.WeakMap=((o=function(e,t,n){Object.defineProperty?Object.defineProperty(e,t,{configurable:!0,writable:!0,value:n}):e[t]=n})(c.prototype,\"delete\",function(e){if(s(this,\"delete\"),!d(e))return!1;var t=e[this._id];return!(!t||t[0]!==e)&&(delete e[this._id],!0)}),o(c.prototype,\"get\",function(e){if(s(this,\"get\"),d(e)){var t=e[this._id];return t&&t[0]===e?t[1]:void 0}}),o(c.prototype,\"has\",function(e){if(s(this,\"has\"),!d(e))return!1;var t=e[this._id];return!(!t||t[0]!==e)}),o(c.prototype,\"set\",function(e,t){if(s(this,\"set\"),!d(e))throw new TypeError(\"Invalid value used as weak map key\");var n=e[this._id];return n&&n[0]===e?n[1]=t:o(e,this._id,[e,t]),this}),o(c,\"_polyfill\",!0),c));var h,m=(function(e){var t,n,r;r=function(){var t,n,r,o,i,e=Object.prototype.toString,a=\"undefined\"!=typeof setImmediate?function(e){return setImmediate(e)}:setTimeout;try{Object.defineProperty({},\"x\",{}),t=function(e,t,n,r){return Object.defineProperty(e,t,{value:n,writable:!0,configurable:!1!==r})}}catch(e){t=function(e,t,n){return e[t]=n,e}}function u(e,t){this.fn=e,this.self=t,this.next=void 0}function l(e,t){y.add(e,t),n=n||a(y.drain)}function c(e){var t,n=typeof e;return\"function\"==typeof(t=null!=e&&(\"object\"==n||\"function\"==n)?e.then:t)&&t}function s(){for(var e=0;e<this.chain.length;e++)!function(e,t,n){var r,o;try{!1===t?n.reject(e.msg):(r=!0===t?e.msg:t.call(void 0,e.msg))===n.promise?n.reject(TypeError(\"Promise-chain cycle\")):(o=c(r))?o.call(r,n.resolve,n.reject):n.resolve(r)}catch(e){n.reject(e)}}(this,1===this.state?this.chain[e].success:this.chain[e].failure,this.chain[e]);this.chain.length=0}function f(e){var n,r=this;if(!r.triggered){r.triggered=!0,r.def&&(r=r.def);try{(n=c(e))?l(function(){var t=new m(r);try{n.call(e,function(){f.apply(t,arguments)},function(){d.apply(t,arguments)})}catch(e){d.call(t,e)}}):(r.msg=e,r.state=1,0<r.chain.length&&l(s,r))}catch(e){d.call(new m(r),e)}}}function d(e){var t=this;t.triggered||(t.triggered=!0,(t=t.def?t.def:t).msg=e,t.state=2,0<t.chain.length&&l(s,t))}function h(e,n,r,o){for(var t=0;t<n.length;t++)!function(t){e.resolve(n[t]).then(function(e){r(t,e)},o)}(t)}function m(e){this.def=e,this.triggered=!1}function v(e){this.promise=e,this.state=0,this.triggered=!1,this.chain=[],this.msg=void 0}function p(e){if(\"function\"!=typeof e)throw TypeError(\"Not a function\");if(0!==this.__NPO__)throw TypeError(\"Not a promise\");this.__NPO__=1;var r=new v(this);this.then=function(e,t){var n={success:\"function\"!=typeof e||e,failure:\"function\"==typeof t&&t};return n.promise=new this.constructor(function(e,t){if(\"function\"!=typeof e||\"function\"!=typeof t)throw TypeError(\"Not a function\");n.resolve=e,n.reject=t}),r.chain.push(n),0!==r.state&&l(s,r),n.promise},this.catch=function(e){return this.then(void 0,e)};try{e.call(void 0,function(e){f.call(r,e)},function(e){d.call(r,e)})}catch(e){d.call(r,e)}}var y={add:function(e,t){i=new u(e,t),o?o.next=i:r=i,o=i,i=void 0},drain:function(){var e=r;for(r=o=n=void 0;e;)e.fn.call(e.self),e=e.next}},g=t({},\"constructor\",p,!1);return t(p.prototype=g,\"__NPO__\",0,!1),t(p,\"resolve\",function(n){return n&&\"object\"==typeof n&&1===n.__NPO__?n:new this(function(e,t){if(\"function\"!=typeof e||\"function\"!=typeof t)throw TypeError(\"Not a function\");e(n)})}),t(p,\"reject\",function(n){return new this(function(e,t){if(\"function\"!=typeof e||\"function\"!=typeof t)throw TypeError(\"Not a function\");t(n)})}),t(p,\"all\",function(t){var a=this;return\"[object Array]\"!=e.call(t)?a.reject(TypeError(\"Not an array\")):0===t.length?a.resolve([]):new a(function(n,e){if(\"function\"!=typeof n||\"function\"!=typeof e)throw TypeError(\"Not a function\");var r=t.length,o=Array(r),i=0;h(a,t,function(e,t){o[e]=t,++i===r&&n(o)},e)})}),t(p,\"race\",function(t){var r=this;return\"[object Array]\"!=e.call(t)?r.reject(TypeError(\"Not an array\")):new r(function(n,e){if(\"function\"!=typeof n||\"function\"!=typeof e)throw TypeError(\"Not a function\");h(r,t,function(e,t){n(t)},e)})}),p},(n=a)[t=\"Promise\"]=n[t]||r(),e.exports&&(e.exports=n[t])}(h={exports:{}}),h.exports),v=new WeakMap;function p(e,t,n){var r=v.get(e.element)||{};t in r||(r[t]=[]),r[t].push(n),v.set(e.element,r)}function y(e,t){return(v.get(e.element)||{})[t]||[]}function g(e,t,n){var r=v.get(e.element)||{};if(!r[t])return!0;if(!n)return r[t]=[],v.set(e.element,r),!0;n=r[t].indexOf(n);return-1!==n&&r[t].splice(n,1),v.set(e.element,r),r[t]&&0===r[t].length}var w=[\"autopause\",\"autoplay\",\"background\",\"byline\",\"color\",\"controls\",\"dnt\",\"height\",\"id\",\"interactive_params\",\"keyboard\",\"loop\",\"maxheight\",\"maxwidth\",\"muted\",\"playsinline\",\"portrait\",\"responsive\",\"speed\",\"texttrack\",\"title\",\"transparent\",\"url\",\"width\"];function b(r,e){return w.reduce(function(e,t){var n=r.getAttribute(\"data-vimeo-\".concat(t));return!n&&\"\"!==n||(e[t]=\"\"===n?1:n),e},1<arguments.length&&void 0!==e?e:{})}function k(e,t){var n=e.html;if(!t)throw new TypeError(\"An element must be provided\");if(null!==t.getAttribute(\"data-vimeo-initialized\"))return t.querySelector(\"iframe\");e=document.createElement(\"div\");return e.innerHTML=n,t.appendChild(e.firstChild),t.setAttribute(\"data-vimeo-initialized\",\"true\"),t.querySelector(\"iframe\")}function E(i,e,t){var a=1<arguments.length&&void 0!==e?e:{},u=2<arguments.length?t:void 0;return new Promise(function(t,n){if(!l(i))throw new TypeError(\"\u201c\".concat(i,\"\u201d is not a vimeo.com url.\"));var e,r=\"https://vimeo.com/api/oembed.json?url=\".concat(encodeURIComponent(i));for(e in a)a.hasOwnProperty(e)&&(r+=\"&\".concat(e,\"=\").concat(encodeURIComponent(a[e])));var o=new(\"XDomainRequest\"in window?XDomainRequest:XMLHttpRequest);o.open(\"GET\",r,!0),o.onload=function(){if(404!==o.status)if(403!==o.status)try{var e=JSON.parse(o.responseText);if(403===e.domain_status_code)return k(e,u),void n(new Error(\"\u201c\".concat(i,\"\u201d is not embeddable.\")));t(e)}catch(e){n(e)}else n(new Error(\"\u201c\".concat(i,\"\u201d is not embeddable.\")));else n(new Error(\"\u201c\".concat(i,\"\u201d was not found.\")))},o.onerror=function(){var e=o.status?\" (\".concat(o.status,\")\"):\"\";n(new Error(\"There was an error fetching the embed code from Vimeo\".concat(e,\".\")))},o.send()})}function T(e){function n(e){\"console\"in window&&console.error&&console.error(\"There was an error creating an embed: \".concat(e))}e=0<arguments.length&&void 0!==e?e:document,e=[].slice.call(e.querySelectorAll(\"[data-vimeo-id], [data-vimeo-url]\"));e.forEach(function(t){try{if(null!==t.getAttribute(\"data-vimeo-defer\"))return;var e=b(t);E(u(e),e,t).then(function(e){return k(e,t)}).catch(n)}catch(e){n(e)}})}function P(e){if(\"string\"==typeof e)try{e=JSON.parse(e)}catch(e){return console.warn(e),{}}return e}function _(e,t,n){e.element.contentWindow&&e.element.contentWindow.postMessage&&(t={method:t},void 0!==n&&(t.value=n),8<=(n=parseFloat(navigator.userAgent.toLowerCase().replace(/^.*msie (\\d+).*$/,\"$1\")))&&n<10&&(t=JSON.stringify(t)),e.element.contentWindow.postMessage(t,e.origin))}function M(n,r){var t,e,o,i,a=[];(r=P(r)).event?(\"error\"===r.event&&y(n,r.data.method).forEach(function(e){var t=new Error(r.data.message);t.name=r.data.name,e.reject(t),g(n,r.data.method,e)}),a=y(n,\"event:\".concat(r.event)),t=r.data):r.method&&(e=n,o=r.method,(i=!((i=y(e,o)).length<1)&&(i=i.shift(),g(e,o,i),i))&&(a.push(i),t=r.value)),a.forEach(function(e){try{if(\"function\"==typeof e)return void e.call(n,t);e.resolve(t)}catch(e){}})}var N,F,x,C=new WeakMap,j=new WeakMap,A={},Player=function(){function Player(i){var e,a=this,t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};if(!function(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}(this,Player),window.jQuery&&i instanceof jQuery&&(1<i.length&&window.console&&console.warn&&console.warn(\"A jQuery object with multiple elements was passed, using the first element.\"),i=i[0]),\"undefined\"!=typeof document&&\"string\"==typeof i&&(i=document.getElementById(i)),e=i,!Boolean(e&&1===e.nodeType&&\"nodeName\"in e&&e.ownerDocument&&e.ownerDocument.defaultView))throw new TypeError(\"You must pass either a valid element or a valid id.\");if(\"IFRAME\"===i.nodeName||(r=i.querySelector(\"iframe\"))&&(i=r),\"IFRAME\"===i.nodeName&&!l(i.getAttribute(\"src\")||\"\"))throw new Error(\"The player element passed isn\u2019t a Vimeo embed.\");if(C.has(i))return C.get(i);this._window=i.ownerDocument.defaultView,this.element=i,this.origin=\"*\";var n,r=new m(function(r,o){var e;a._onMessage=function(e){if(l(e.origin)&&a.element.contentWindow===e.source){\"*\"===a.origin&&(a.origin=e.origin);var t=P(e.data);if(t&&\"error\"===t.event&&t.data&&\"ready\"===t.data.method){var n=new Error(t.data.message);return n.name=t.data.name,void o(n)}e=t&&\"ready\"===t.event,n=t&&\"ping\"===t.method;if(e||n)return a.element.setAttribute(\"data-ready\",\"true\"),void r();M(a,t)}},a._window.addEventListener(\"message\",a._onMessage),\"IFRAME\"!==a.element.nodeName&&E(u(e=b(i,t)),e,i).then(function(e){var t,n,r=k(e,i);return a.element=r,a._originalElement=i,t=i,n=r,r=v.get(t),v.set(n,r),v.delete(t),C.set(a.element,a),e}).catch(o)});return j.set(this,r),C.set(this.element,this),\"IFRAME\"===this.element.nodeName&&_(this,\"ping\"),A.isEnabled&&(n=function(){return A.exit()},this.fullscreenchangeHandler=function(){(A.isFullscreen?p:g)(a,\"event:exitFullscreen\",n),a.ready().then(function(){_(a,\"fullscreenchange\",A.isFullscreen)})},A.on(\"fullscreenchange\",this.fullscreenchangeHandler)),this}var e,t,n;return e=Player,(t=[{key:\"callMethod\",value:function(n){var r=this,o=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};return new m(function(e,t){return r.ready().then(function(){p(r,n,{resolve:e,reject:t}),_(r,n,o)}).catch(t)})}},{key:\"get\",value:function(n){var r=this;return new m(function(e,t){return n=i(n,\"get\"),r.ready().then(function(){p(r,n,{resolve:e,reject:t}),_(r,n)}).catch(t)})}},{key:\"set\",value:function(n,r){var o=this;return new m(function(e,t){if(n=i(n,\"set\"),null==r)throw new TypeError(\"There must be a value to set.\");return o.ready().then(function(){p(o,n,{resolve:e,reject:t}),_(o,n,r)}).catch(t)})}},{key:\"on\",value:function(e,t){if(!e)throw new TypeError(\"You must pass an event name.\");if(!t)throw new TypeError(\"You must pass a callback function.\");if(\"function\"!=typeof t)throw new TypeError(\"The callback must be a function.\");0===y(this,\"event:\".concat(e)).length&&this.callMethod(\"addEventListener\",e).catch(function(){}),p(this,\"event:\".concat(e),t)}},{key:\"off\",value:function(e,t){if(!e)throw new TypeError(\"You must pass an event name.\");if(t&&\"function\"!=typeof t)throw new TypeError(\"The callback must be a function.\");g(this,\"event:\".concat(e),t)&&this.callMethod(\"removeEventListener\",e).catch(function(e){})}},{key:\"loadVideo\",value:function(e){return this.callMethod(\"loadVideo\",e)}},{key:\"ready\",value:function(){var e=j.get(this)||new m(function(e,t){t(new Error(\"Unknown player. Probably unloaded.\"))});return m.resolve(e)}},{key:\"addCuePoint\",value:function(e){return this.callMethod(\"addCuePoint\",{time:e,data:1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}})}},{key:\"removeCuePoint\",value:function(e){return this.callMethod(\"removeCuePoint\",e)}},{key:\"enableTextTrack\",value:function(e,t){if(!e)throw new TypeError(\"You must pass a language.\");return this.callMethod(\"enableTextTrack\",{language:e,kind:t})}},{key:\"disableTextTrack\",value:function(){return this.callMethod(\"disableTextTrack\")}},{key:\"pause\",value:function(){return this.callMethod(\"pause\")}},{key:\"play\",value:function(){return this.callMethod(\"play\")}},{key:\"requestFullscreen\",value:function(){return A.isEnabled?A.request(this.element):this.callMethod(\"requestFullscreen\")}},{key:\"exitFullscreen\",value:function(){return A.isEnabled?A.exit():this.callMethod(\"exitFullscreen\")}},{key:\"getFullscreen\",value:function(){return A.isEnabled?m.resolve(A.isFullscreen):this.get(\"fullscreen\")}},{key:\"requestPictureInPicture\",value:function(){return this.callMethod(\"requestPictureInPicture\")}},{key:\"exitPictureInPicture\",value:function(){return this.callMethod(\"exitPictureInPicture\")}},{key:\"getPictureInPicture\",value:function(){return this.get(\"pictureInPicture\")}},{key:\"unload\",value:function(){return this.callMethod(\"unload\")}},{key:\"destroy\",value:function(){var n=this;return new m(function(e){var t;j.delete(n),C.delete(n.element),n._originalElement&&(C.delete(n._originalElement),n._originalElement.removeAttribute(\"data-vimeo-initialized\")),n.element&&\"IFRAME\"===n.element.nodeName&&n.element.parentNode&&(n.element.parentNode.parentNode&&n._originalElement&&n._originalElement!==n.element.parentNode?n.element.parentNode.parentNode.removeChild(n.element.parentNode):n.element.parentNode.removeChild(n.element)),n.element&&\"DIV\"===n.element.nodeName&&n.element.parentNode&&(n.element.removeAttribute(\"data-vimeo-initialized\"),(t=n.element.querySelector(\"iframe\"))&&t.parentNode&&(t.parentNode.parentNode&&n._originalElement&&n._originalElement!==t.parentNode?t.parentNode.parentNode.removeChild(t.parentNode):t.parentNode.removeChild(t))),n._window.removeEventListener(\"message\",n._onMessage),A.isEnabled&&A.off(\"fullscreenchange\",n.fullscreenchangeHandler),e()})}},{key:\"getAutopause\",value:function(){return this.get(\"autopause\")}},{key:\"setAutopause\",value:function(e){return this.set(\"autopause\",e)}},{key:\"getBuffered\",value:function(){return this.get(\"buffered\")}},{key:\"getCameraProps\",value:function(){return this.get(\"cameraProps\")}},{key:\"setCameraProps\",value:function(e){return this.set(\"cameraProps\",e)}},{key:\"getChapters\",value:function(){return this.get(\"chapters\")}},{key:\"getCurrentChapter\",value:function(){return this.get(\"currentChapter\")}},{key:\"getColor\",value:function(){return this.get(\"color\")}},{key:\"setColor\",value:function(e){return this.set(\"color\",e)}},{key:\"getCuePoints\",value:function(){return this.get(\"cuePoints\")}},{key:\"getCurrentTime\",value:function(){return this.get(\"currentTime\")}},{key:\"setCurrentTime\",value:function(e){return this.set(\"currentTime\",e)}},{key:\"getDuration\",value:function(){return this.get(\"duration\")}},{key:\"getEnded\",value:function(){return this.get(\"ended\")}},{key:\"getLoop\",value:function(){return this.get(\"loop\")}},{key:\"setLoop\",value:function(e){return this.set(\"loop\",e)}},{key:\"setMuted\",value:function(e){return this.set(\"muted\",e)}},{key:\"getMuted\",value:function(){return this.get(\"muted\")}},{key:\"getPaused\",value:function(){return this.get(\"paused\")}},{key:\"getPlaybackRate\",value:function(){return this.get(\"playbackRate\")}},{key:\"setPlaybackRate\",value:function(e){return this.set(\"playbackRate\",e)}},{key:\"getPlayed\",value:function(){return this.get(\"played\")}},{key:\"getQualities\",value:function(){return this.get(\"qualities\")}},{key:\"getQuality\",value:function(){return this.get(\"quality\")}},{key:\"setQuality\",value:function(e){return this.set(\"quality\",e)}},{key:\"getSeekable\",value:function(){return this.get(\"seekable\")}},{key:\"getSeeking\",value:function(){return this.get(\"seeking\")}},{key:\"getTextTracks\",value:function(){return this.get(\"textTracks\")}},{key:\"getVideoEmbedCode\",value:function(){return this.get(\"videoEmbedCode\")}},{key:\"getVideoId\",value:function(){return this.get(\"videoId\")}},{key:\"getVideoTitle\",value:function(){return this.get(\"videoTitle\")}},{key:\"getVideoWidth\",value:function(){return this.get(\"videoWidth\")}},{key:\"getVideoHeight\",value:function(){return this.get(\"videoHeight\")}},{key:\"getVideoUrl\",value:function(){return this.get(\"videoUrl\")}},{key:\"getVolume\",value:function(){return this.get(\"volume\")}},{key:\"setVolume\",value:function(e){return this.set(\"volume\",e)}}])&&r(e.prototype,t),n&&r(e,n),Player}();return e||(N=function(){for(var e,t=[[\"requestFullscreen\",\"exitFullscreen\",\"fullscreenElement\",\"fullscreenEnabled\",\"fullscreenchange\",\"fullscreenerror\"],[\"webkitRequestFullscreen\",\"webkitExitFullscreen\",\"webkitFullscreenElement\",\"webkitFullscreenEnabled\",\"webkitfullscreenchange\",\"webkitfullscreenerror\"],[\"webkitRequestFullScreen\",\"webkitCancelFullScreen\",\"webkitCurrentFullScreenElement\",\"webkitCancelFullScreen\",\"webkitfullscreenchange\",\"webkitfullscreenerror\"],[\"mozRequestFullScreen\",\"mozCancelFullScreen\",\"mozFullScreenElement\",\"mozFullScreenEnabled\",\"mozfullscreenchange\",\"mozfullscreenerror\"],[\"msRequestFullscreen\",\"msExitFullscreen\",\"msFullscreenElement\",\"msFullscreenEnabled\",\"MSFullscreenChange\",\"MSFullscreenError\"]],n=0,r=t.length,o={};n<r;n++)if((e=t[n])&&e[1]in document){for(n=0;n<e.length;n++)o[t[0][n]]=e[n];return o}return!1}(),F={fullscreenchange:N.fullscreenchange,fullscreenerror:N.fullscreenerror},x={request:function(o){return new Promise(function(e,t){function n(){x.off(\"fullscreenchange\",n),e()}x.on(\"fullscreenchange\",n);var r=(o=o||document.documentElement)[N.requestFullscreen]();r instanceof Promise&&r.then(n).catch(t)})},exit:function(){return new Promise(function(t,e){var n,r;x.isFullscreen?(n=function e(){x.off(\"fullscreenchange\",e),t()},x.on(\"fullscreenchange\",n),(r=document[N.exitFullscreen]())instanceof Promise&&r.then(n).catch(e)):t()})},on:function(e,t){e=F[e];e&&document.addEventListener(e,t)},off:function(e,t){e=F[e];e&&document.removeEventListener(e,t)}},Object.defineProperties(x,{isFullscreen:{get:function(){return Boolean(document[N.fullscreenElement])}},element:{enumerable:!0,get:function(){return document[N.fullscreenElement]}},isEnabled:{enumerable:!0,get:function(){return Boolean(document[N.fullscreenEnabled])}}}),A=x,T(),function(e){var r=0<arguments.length&&void 0!==e?e:document;window.VimeoPlayerResizeEmbeds_||(window.VimeoPlayerResizeEmbeds_=!0,window.addEventListener(\"message\",function(e){if(l(e.origin)&&e.data&&\"spacechange\"===e.data.event)for(var t=r.querySelectorAll(\"iframe\"),n=0;n<t.length;n++)if(t[n].contentWindow===e.source){t[n].parentElement.style.paddingBottom=\"\".concat(e.data.data[0].bottom,\"px\");break}}))}()),Player});\n","jquery/jquery.metadata.js":"/*\n * Metadata - jQuery plugin for parsing metadata from elements\n *\n * Copyright (c) 2006 John Resig, Yehuda Katz, J\u00ef\u00bf\u00bd\u00c3\u00b6rn Zaefferer, Paul McLanahan\n *\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n *\n * Revision: $Id: jquery.metadata.js 3640 2007-10-11 18:34:38Z pmclanahan $\n *\n */\n\n/**\n * Sets the type of metadata to use. Metadata is encoded in JSON, and each property\n * in the JSON will become a property of the element itself.\n *\n * There are four supported types of metadata storage:\n *\n *   attr:  Inside an attribute. The name parameter indicates *which* attribute.\n *\n *   class: Inside the class attribute, wrapped in curly braces: { }\n *\n *   elem:  Inside a child element (e.g. a script tag). The\n *          name parameter indicates *which* element.\n *   html5: Values are stored in data-* attributes.\n *\n * The metadata for an element is loaded the first time the element is accessed via jQuery.\n *\n * As a result, you can define the metadata type, use $(expr) to load the metadata into the elements\n * matched by expr, then redefine the metadata type and run another $(expr) for other elements.\n *\n * @name $.metadata.setType\n *\n * @example <p id=\"one\" class=\"some_class {item_id: 1, item_label: 'Label'}\">This is a p</p>\n * @before $.metadata.setType(\"class\")\n * @after $(\"#one\").metadata().item_id == 1; $(\"#one\").metadata().item_label == \"Label\"\n * @desc Reads metadata from the class attribute\n *\n * @example <p id=\"one\" class=\"some_class\" data=\"{item_id: 1, item_label: 'Label'}\">This is a p</p>\n * @before $.metadata.setType(\"attr\", \"data\")\n * @after $(\"#one\").metadata().item_id == 1; $(\"#one\").metadata().item_label == \"Label\"\n * @desc Reads metadata from a \"data\" attribute\n *\n * @example <p id=\"one\" class=\"some_class\"><script>{item_id: 1, item_label: 'Label'}</script>This is a p</p>\n * @before $.metadata.setType(\"elem\", \"script\")\n * @after $(\"#one\").metadata().item_id == 1; $(\"#one\").metadata().item_label == \"Label\"\n * @desc Reads metadata from a nested script element\n *\n * @example <p id=\"one\" class=\"some_class\" data-item_id=\"1\" data-item_label=\"Label\">This is a p</p>\n * @before $.metadata.setType(\"html5\")\n * @after $(\"#one\").metadata().item_id == 1; $(\"#one\").metadata().item_label == \"Label\"\n * @desc Reads metadata from a series of data-* attributes\n *\n * @param String type The encoding type\n * @param String name The name of the attribute to be used to get metadata (optional)\n * @cat Plugins/Metadata\n * @descr Sets the type of encoding to be used when loading metadata for the first time\n * @type undefined\n * @see metadata()\n */\n(function (factory) {\n    if (typeof define === 'function' && define.amd) {\n        define([\"jquery\"], factory);\n    } else {\n        factory(jQuery);\n    }\n}(function ($) {\n\n\n    $.extend({\n        metadata : {\n            defaults : {\n                type: 'class',\n                name: 'metadata',\n                cre: /({.*})/,\n                single: 'metadata',\n                meta:'validate'\n            },\n            setType: function( type, name ){\n                this.defaults.type = type;\n                this.defaults.name = name;\n            },\n            get: function( elem, opts ){\n                var settings = $.extend({},this.defaults,opts);\n                // check for empty string in single property\n                if (!settings.single.length) {\n                    settings.single = 'metadata';\n                }\n                if (!settings.meta.length) {\n                    settings.meta = 'validate';\n                }\n\n                var data = $.data(elem, settings.single);\n                // returned cached data if it already exists\n                if ( data ) return data;\n\n                data = \"{}\";\n\n                var getData = function(data) {\n                    if(typeof data != \"string\") return data;\n\n                    if( data.indexOf('{') < 0 ) {\n                        data = eval(\"(\" + data + \")\");\n                    }\n                }\n\n                var getObject = function(data) {\n                    if(typeof data != \"string\") return data;\n\n                    data = eval(\"(\" + data + \")\");\n                    return data;\n                }\n\n                if ( settings.type == \"html5\" ) {\n                    var object = {};\n                    $( elem.attributes ).each(function() {\n                        var name = this.nodeName;\n                        if (name.indexOf('data-' + settings.meta) === 0) {\n                            name = name.replace(/^data-/, '');\n                        }\n                        else {\n                            return true;\n                        }\n                        object[name] = getObject(this.value);\n                    });\n                } else {\n                    if ( settings.type == \"class\" ) {\n                        var m = settings.cre.exec( elem.className );\n                        if ( m )\n                            data = m[1];\n                    } else if ( settings.type == \"elem\" ) {\n                        if( !elem.getElementsByTagName ) return;\n                        var e = elem.getElementsByTagName(settings.name);\n                        if ( e.length )\n                            data = $.trim(e[0].innerHTML);\n                    } else if ( elem.getAttribute != undefined ) {\n                        var attr = elem.getAttribute( settings.name );\n                        if ( attr )\n                            data = attr;\n                    }\n                    object = getObject(data.indexOf(\"{\") < 0 ? \"{\" + data + \"}\" : data);\n                }\n\n                $.data( elem, settings.single, object );\n                return object;\n            }\n        }\n    });\n\n    /**\n     * Returns the metadata object for the first member of the jQuery object.\n     *\n     * @name metadata\n     * @descr Returns element's metadata object\n     * @param Object opts An object contianing settings to override the defaults\n     * @type jQuery\n     * @cat Plugins/Metadata\n     */\n    $.fn.metadata = function( opts ){\n        return $.metadata.get( this[0], opts );\n    };\n\n}));","jquery/timepicker.js":"/*! jQuery Timepicker Addon - v1.6.3 - 2016-04-20\n* http://trentrichardson.com/examples/timepicker\n* Copyright (c) 2016 Trent Richardson; Licensed MIT */\n(function (factory) {\n    if (typeof define === 'function' && define.amd) {\n        define(['jquery', 'jquery-ui-modules/datepicker', 'jquery-ui-modules/slider'], factory);\n    } else {\n        factory(jQuery);\n    }\n}(function ($) {\n\n    /*\n    * Lets not redefine timepicker, Prevent \"Uncaught RangeError: Maximum call stack size exceeded\"\n    */\n    $.ui.timepicker = $.ui.timepicker || {};\n    if ($.ui.timepicker.version) {\n        return;\n    }\n\n    /*\n    * Extend jQueryUI, get it started with our version number\n    */\n    $.extend($.ui, {\n        timepicker: {\n            version: \"1.6.3\"\n        }\n    });\n\n    /*\n    * Timepicker manager.\n    * Use the singleton instance of this class, $.timepicker, to interact with the time picker.\n    * Settings for (groups of) time pickers are maintained in an instance object,\n    * allowing multiple different settings on the same page.\n    */\n    var Timepicker = function () {\n        this.regional = []; // Available regional settings, indexed by language code\n        this.regional[''] = { // Default regional settings\n            currentText: 'Now',\n            closeText: 'Done',\n            amNames: ['AM', 'A'],\n            pmNames: ['PM', 'P'],\n            timeFormat: 'HH:mm',\n            timeSuffix: '',\n            timeOnlyTitle: 'Choose Time',\n            timeText: 'Time',\n            hourText: 'Hour',\n            minuteText: 'Minute',\n            secondText: 'Second',\n            millisecText: 'Millisecond',\n            microsecText: 'Microsecond',\n            timezoneText: 'Time Zone',\n            isRTL: false\n        };\n        this._defaults = { // Global defaults for all the datetime picker instances\n            showButtonPanel: true,\n            timeOnly: false,\n            timeOnlyShowDate: false,\n            showHour: null,\n            showMinute: null,\n            showSecond: null,\n            showMillisec: null,\n            showMicrosec: null,\n            showTimezone: null,\n            showTime: true,\n            stepHour: 1,\n            stepMinute: 1,\n            stepSecond: 1,\n            stepMillisec: 1,\n            stepMicrosec: 1,\n            hour: 0,\n            minute: 0,\n            second: 0,\n            millisec: 0,\n            microsec: 0,\n            timezone: null,\n            hourMin: 0,\n            minuteMin: 0,\n            secondMin: 0,\n            millisecMin: 0,\n            microsecMin: 0,\n            hourMax: 23,\n            minuteMax: 59,\n            secondMax: 59,\n            millisecMax: 999,\n            microsecMax: 999,\n            minDateTime: null,\n            maxDateTime: null,\n            maxTime: null,\n            minTime: null,\n            onSelect: null,\n            hourGrid: 0,\n            minuteGrid: 0,\n            secondGrid: 0,\n            millisecGrid: 0,\n            microsecGrid: 0,\n            alwaysSetTime: true,\n            separator: ' ',\n            altFieldTimeOnly: true,\n            altTimeFormat: null,\n            altSeparator: null,\n            altTimeSuffix: null,\n            altRedirectFocus: true,\n            pickerTimeFormat: null,\n            pickerTimeSuffix: null,\n            showTimepicker: true,\n            timezoneList: null,\n            addSliderAccess: false,\n            sliderAccessArgs: null,\n            controlType: 'slider',\n            oneLine: false,\n            defaultValue: null,\n            parse: 'strict',\n            afterInject: null\n        };\n        $.extend(this._defaults, this.regional['']);\n    };\n\n    $.extend(Timepicker.prototype, {\n        $input: null,\n        $altInput: null,\n        $timeObj: null,\n        inst: null,\n        hour_slider: null,\n        minute_slider: null,\n        second_slider: null,\n        millisec_slider: null,\n        microsec_slider: null,\n        timezone_select: null,\n        maxTime: null,\n        minTime: null,\n        hour: 0,\n        minute: 0,\n        second: 0,\n        millisec: 0,\n        microsec: 0,\n        timezone: null,\n        hourMinOriginal: null,\n        minuteMinOriginal: null,\n        secondMinOriginal: null,\n        millisecMinOriginal: null,\n        microsecMinOriginal: null,\n        hourMaxOriginal: null,\n        minuteMaxOriginal: null,\n        secondMaxOriginal: null,\n        millisecMaxOriginal: null,\n        microsecMaxOriginal: null,\n        ampm: '',\n        formattedDate: '',\n        formattedTime: '',\n        formattedDateTime: '',\n        timezoneList: null,\n        units: ['hour', 'minute', 'second', 'millisec', 'microsec'],\n        support: {},\n        control: null,\n\n        /*\n        * Override the default settings for all instances of the time picker.\n        * @param  {Object} settings  object - the new settings to use as defaults (anonymous object)\n        * @return {Object} the manager object\n        */\n        setDefaults: function (settings) {\n            extendRemove(this._defaults, settings || {});\n            return this;\n        },\n\n        /*\n        * Create a new Timepicker instance\n        */\n        _newInst: function ($input, opts) {\n            var tp_inst = new Timepicker(),\n                inlineSettings = {},\n                fns = {},\n                overrides, i;\n\n            for (var attrName in this._defaults) {\n                if (this._defaults.hasOwnProperty(attrName)) {\n                    var attrValue = $input.attr('time:' + attrName);\n                    if (attrValue) {\n                        try {\n                            inlineSettings[attrName] = eval(attrValue);\n                        } catch (err) {\n                            inlineSettings[attrName] = attrValue;\n                        }\n                    }\n                }\n            }\n\n            overrides = {\n                beforeShow: function (input, dp_inst) {\n                    if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) {\n                        return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst);\n                    }\n                },\n                onChangeMonthYear: function (year, month, dp_inst) {\n                    // Update the time as well : this prevents the time from disappearing from the $input field.\n                    // tp_inst._updateDateTime(dp_inst);\n                    if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) {\n                        tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);\n                    }\n                },\n                onClose: function (dateText, dp_inst) {\n                    if (tp_inst.timeDefined === true && $input.val() !== '') {\n                        tp_inst._updateDateTime(dp_inst);\n                    }\n                    if ($.isFunction(tp_inst._defaults.evnts.onClose)) {\n                        tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst);\n                    }\n                }\n            };\n            for (i in overrides) {\n                if (overrides.hasOwnProperty(i)) {\n                    fns[i] = opts[i] || this._defaults[i] || null;\n                }\n            }\n\n            tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, opts, overrides, {\n                evnts: fns,\n                timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');\n            });\n            tp_inst.amNames = $.map(tp_inst._defaults.amNames, function (val) {\n                return val.toUpperCase();\n            });\n            tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function (val) {\n                return val.toUpperCase();\n            });\n\n            // detect which units are supported\n            tp_inst.support = detectSupport(\n                tp_inst._defaults.timeFormat +\n                (tp_inst._defaults.pickerTimeFormat ? tp_inst._defaults.pickerTimeFormat : '') +\n                (tp_inst._defaults.altTimeFormat ? tp_inst._defaults.altTimeFormat : ''));\n\n            // controlType is string - key to our this._controls\n            if (typeof(tp_inst._defaults.controlType) === 'string') {\n                if (tp_inst._defaults.controlType === 'slider' && typeof($.ui.slider) === 'undefined') {\n                    tp_inst._defaults.controlType = 'select';\n                }\n                tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType];\n            }\n            // controlType is an object and must implement create, options, value methods\n            else {\n                tp_inst.control = tp_inst._defaults.controlType;\n            }\n\n            // prep the timezone options\n            var timezoneList = [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270, -240, -210, -180, -120, -60,\n                0, 60, 120, 180, 210, 240, 270, 300, 330, 345, 360, 390, 420, 480, 525, 540, 570, 600, 630, 660, 690, 720, 765, 780, 840];\n            if (tp_inst._defaults.timezoneList !== null) {\n                timezoneList = tp_inst._defaults.timezoneList;\n            }\n            var tzl = timezoneList.length, tzi = 0, tzv = null;\n            if (tzl > 0 && typeof timezoneList[0] !== 'object') {\n                for (; tzi < tzl; tzi++) {\n                    tzv = timezoneList[tzi];\n                    timezoneList[tzi] = { value: tzv, label: $.timepicker.timezoneOffsetString(tzv, tp_inst.support.iso8601) };\n                }\n            }\n            tp_inst._defaults.timezoneList = timezoneList;\n\n            // set the default units\n            tp_inst.timezone = tp_inst._defaults.timezone !== null ? $.timepicker.timezoneOffsetNumber(tp_inst._defaults.timezone) :\n                ((new Date()).getTimezoneOffset() * -1);\n            tp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin ? tp_inst._defaults.hourMin :\n                tp_inst._defaults.hour > tp_inst._defaults.hourMax ? tp_inst._defaults.hourMax : tp_inst._defaults.hour;\n            tp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin ? tp_inst._defaults.minuteMin :\n                tp_inst._defaults.minute > tp_inst._defaults.minuteMax ? tp_inst._defaults.minuteMax : tp_inst._defaults.minute;\n            tp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin ? tp_inst._defaults.secondMin :\n                tp_inst._defaults.second > tp_inst._defaults.secondMax ? tp_inst._defaults.secondMax : tp_inst._defaults.second;\n            tp_inst.millisec = tp_inst._defaults.millisec < tp_inst._defaults.millisecMin ? tp_inst._defaults.millisecMin :\n                tp_inst._defaults.millisec > tp_inst._defaults.millisecMax ? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec;\n            tp_inst.microsec = tp_inst._defaults.microsec < tp_inst._defaults.microsecMin ? tp_inst._defaults.microsecMin :\n                tp_inst._defaults.microsec > tp_inst._defaults.microsecMax ? tp_inst._defaults.microsecMax : tp_inst._defaults.microsec;\n            tp_inst.ampm = '';\n            tp_inst.$input = $input;\n\n            if (tp_inst._defaults.altField) {\n                tp_inst.$altInput = $(tp_inst._defaults.altField);\n                if (tp_inst._defaults.altRedirectFocus === true) {\n                    tp_inst.$altInput.css({\n                        cursor: 'pointer'\n                    }).focus(function () {\n                        $input.trigger(\"focus\");\n                    });\n                }\n            }\n\n            if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) {\n                tp_inst._defaults.minDate = new Date();\n            }\n            if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) {\n                tp_inst._defaults.maxDate = new Date();\n            }\n\n            // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..\n            if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) {\n                tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());\n            }\n            if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) {\n                tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());\n            }\n            if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) {\n                tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());\n            }\n            if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) {\n                tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());\n            }\n            tp_inst.$input.bind('focus', function () {\n                tp_inst._onFocus();\n            });\n\n            return tp_inst;\n        },\n\n        /*\n        * add our sliders to the calendar\n        */\n        _addTimePicker: function (dp_inst) {\n            var currDT = $.trim((this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val());\n\n            this.timeDefined = this._parseTime(currDT);\n            this._limitMinMaxDateTime(dp_inst, false);\n            this._injectTimePicker();\n            this._afterInject();\n        },\n\n        /*\n        * parse the time string from input value or _setTime\n        */\n        _parseTime: function (timeString, withDate) {\n            if (!this.inst) {\n                this.inst = $.datepicker._getInst(this.$input[0]);\n            }\n\n            if (withDate || !this._defaults.timeOnly) {\n                var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');\n                try {\n                    var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);\n                    if (!parseRes.timeObj) {\n                        return false;\n                    }\n                    $.extend(this, parseRes.timeObj);\n                } catch (err) {\n                    $.timepicker.log(\"Error parsing the date/time string: \" + err +\n                        \"\\ndate/time string = \" + timeString +\n                        \"\\ntimeFormat = \" + this._defaults.timeFormat +\n                        \"\\ndateFormat = \" + dp_dateFormat);\n                    return false;\n                }\n                return true;\n            } else {\n                var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);\n                if (!timeObj) {\n                    return false;\n                }\n                $.extend(this, timeObj);\n                return true;\n            }\n        },\n\n        /*\n        * Handle callback option after injecting timepicker\n        */\n        _afterInject: function() {\n            var o = this.inst.settings;\n            if ($.isFunction(o.afterInject)) {\n                o.afterInject.call(this);\n            }\n        },\n\n        /*\n        * generate and inject html for timepicker into ui datepicker\n        */\n        _injectTimePicker: function () {\n            var $dp = this.inst.dpDiv,\n                o = this.inst.settings,\n                tp_inst = this,\n                litem = '',\n                uitem = '',\n                show = null,\n                max = {},\n                gridSize = {},\n                size = null,\n                i = 0,\n                l = 0;\n\n            // Prevent displaying twice\n            if ($dp.find(\"div.ui-timepicker-div\").length === 0 && o.showTimepicker) {\n                var noDisplay = ' ui_tpicker_unit_hide',\n                    html = '<div class=\"ui-timepicker-div' + (o.isRTL ? ' ui-timepicker-rtl' : '') + (o.oneLine && o.controlType === 'select' ? ' ui-timepicker-oneLine' : '') + '\"><dl>' + '<dt class=\"ui_tpicker_time_label' + ((o.showTime) ? '' : noDisplay) + '\">' + o.timeText + '</dt>' +\n                        '<dd class=\"ui_tpicker_time '+ ((o.showTime) ? '' : noDisplay) + '\"><input class=\"ui_tpicker_time_input\" ' + (o.timeInput ? '' : 'disabled') + '/></dd>';\n\n                // Create the markup\n                for (i = 0, l = this.units.length; i < l; i++) {\n                    litem = this.units[i];\n                    uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);\n                    show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];\n\n                    // Added by Peter Medeiros:\n                    // - Figure out what the hour/minute/second max should be based on the step values.\n                    // - Example: if stepMinute is 15, then minMax is 45.\n                    max[litem] = parseInt((o[litem + 'Max'] - ((o[litem + 'Max'] - o[litem + 'Min']) % o['step' + uitem])), 10);\n                    gridSize[litem] = 0;\n\n                    html += '<dt class=\"ui_tpicker_' + litem + '_label' + (show ? '' : noDisplay) + '\">' + o[litem + 'Text'] + '</dt>' +\n                        '<dd class=\"ui_tpicker_' + litem + (show ? '' : noDisplay) + '\"><div class=\"ui_tpicker_' + litem + '_slider' + (show ? '' : noDisplay) + '\"></div>';\n\n                    if (show && o[litem + 'Grid'] > 0) {\n                        html += '<div style=\"padding-left: 1px\"><table class=\"ui-tpicker-grid-label\"><tr>';\n\n                        if (litem === 'hour') {\n                            for (var h = o[litem + 'Min']; h <= max[litem]; h += parseInt(o[litem + 'Grid'], 10)) {\n                                gridSize[litem]++;\n                                var tmph = $.datepicker.formatTime(this.support.ampm ? 'hht' : 'HH', {hour: h}, o);\n                                html += '<td data-for=\"' + litem + '\">' + tmph + '</td>';\n                            }\n                        }\n                        else {\n                            for (var m = o[litem + 'Min']; m <= max[litem]; m += parseInt(o[litem + 'Grid'], 10)) {\n                                gridSize[litem]++;\n                                html += '<td data-for=\"' + litem + '\">' + ((m < 10) ? '0' : '') + m + '</td>';\n                            }\n                        }\n\n                        html += '</tr></table></div>';\n                    }\n                    html += '</dd>';\n                }\n\n                // Timezone\n                var showTz = o.showTimezone !== null ? o.showTimezone : this.support.timezone;\n                html += '<dt class=\"ui_tpicker_timezone_label' + (showTz ? '' : noDisplay) + '\">' + o.timezoneText + '</dt>';\n                html += '<dd class=\"ui_tpicker_timezone' + (showTz ? '' : noDisplay) + '\"></dd>';\n\n                // Create the elements from string\n                html += '</dl></div>';\n                var $tp = $(html);\n\n                // if we only want time picker...\n                if (o.timeOnly === true) {\n                    $tp.prepend('<div class=\"ui-widget-header ui-helper-clearfix ui-corner-all\">' + '<div class=\"ui-datepicker-title\">' + o.timeOnlyTitle + '</div>' + '</div>');\n                    $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();\n                }\n\n                // add sliders, adjust grids, add events\n                for (i = 0, l = tp_inst.units.length; i < l; i++) {\n                    litem = tp_inst.units[i];\n                    uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);\n                    show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];\n\n                    // add the slider\n                    tp_inst[litem + '_slider'] = tp_inst.control.create(tp_inst, $tp.find('.ui_tpicker_' + litem + '_slider'), litem, tp_inst[litem], o[litem + 'Min'], max[litem], o['step' + uitem]);\n\n                    // adjust the grid and add click event\n                    if (show && o[litem + 'Grid'] > 0) {\n                        size = 100 * gridSize[litem] * o[litem + 'Grid'] / (max[litem] - o[litem + 'Min']);\n                        $tp.find('.ui_tpicker_' + litem + ' table').css({\n                            width: size + \"%\",\n                            marginLeft: o.isRTL ? '0' : ((size / (-2 * gridSize[litem])) + \"%\"),\n                            marginRight: o.isRTL ? ((size / (-2 * gridSize[litem])) + \"%\") : '0',\n                            borderCollapse: 'collapse'\n                        }).find(\"td\").click(function (e) {\n                            var $t = $(this),\n                                h = $t.html(),\n                                n = parseInt(h.replace(/[^0-9]/g), 10),\n                                ap = h.replace(/[^apm]/ig),\n                                f = $t.data('for'); // loses scope, so we use data-for\n\n                            if (f === 'hour') {\n                                if (ap.indexOf('p') !== -1 && n < 12) {\n                                    n += 12;\n                                }\n                                else {\n                                    if (ap.indexOf('a') !== -1 && n === 12) {\n                                        n = 0;\n                                    }\n                                }\n                            }\n\n                            tp_inst.control.value(tp_inst, tp_inst[f + '_slider'], litem, n);\n\n                            tp_inst._onTimeChange();\n                            tp_inst._onSelectHandler();\n                        }).css({\n                            cursor: 'pointer',\n                            width: (100 / gridSize[litem]) + '%',\n                            textAlign: 'center',\n                            overflow: 'hidden'\n                        });\n                    } // end if grid > 0\n                } // end for loop\n\n                // Add timezone options\n                this.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find(\"select\");\n                $.fn.append.apply(this.timezone_select,\n                    $.map(o.timezoneList, function (val, idx) {\n                        return $(\"<option />\").val(typeof val === \"object\" ? val.value : val).text(typeof val === \"object\" ? val.label : val);\n                    }));\n                if (typeof(this.timezone) !== \"undefined\" && this.timezone !== null && this.timezone !== \"\") {\n                    var local_timezone = (new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12)).getTimezoneOffset() * -1;\n                    if (local_timezone === this.timezone) {\n                        selectLocalTimezone(tp_inst);\n                    } else {\n                        this.timezone_select.val(this.timezone);\n                    }\n                } else {\n                    if (typeof(this.hour) !== \"undefined\" && this.hour !== null && this.hour !== \"\") {\n                        this.timezone_select.val(o.timezone);\n                    } else {\n                        selectLocalTimezone(tp_inst);\n                    }\n                }\n                this.timezone_select.change(function () {\n                    tp_inst._onTimeChange();\n                    tp_inst._onSelectHandler();\n                    tp_inst._afterInject();\n                });\n                // End timezone options\n\n                // inject timepicker into datepicker\n                var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');\n                if ($buttonPanel.length) {\n                    $buttonPanel.before($tp);\n                } else {\n                    $dp.append($tp);\n                }\n\n                this.$timeObj = $tp.find('.ui_tpicker_time_input');\n                this.$timeObj.change(function () {\n                    var timeFormat = tp_inst.inst.settings.timeFormat;\n                    var parsedTime = $.datepicker.parseTime(timeFormat, this.value);\n                    var update = new Date();\n                    if (parsedTime) {\n                        update.setHours(parsedTime.hour);\n                        update.setMinutes(parsedTime.minute);\n                        update.setSeconds(parsedTime.second);\n                        $.datepicker._setTime(tp_inst.inst, update);\n                    } else {\n                        this.value = tp_inst.formattedTime;\n                        this.blur();\n                    }\n                });\n\n                if (this.inst !== null) {\n                    var timeDefined = this.timeDefined;\n                    this._onTimeChange();\n                    this.timeDefined = timeDefined;\n                }\n\n                // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/\n                if (this._defaults.addSliderAccess) {\n                    var sliderAccessArgs = this._defaults.sliderAccessArgs,\n                        rtl = this._defaults.isRTL;\n                    sliderAccessArgs.isRTL = rtl;\n\n                    setTimeout(function () { // fix for inline mode\n                        if ($tp.find('.ui-slider-access').length === 0) {\n                            $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);\n\n                            // fix any grids since sliders are shorter\n                            var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);\n                            if (sliderAccessWidth) {\n                                $tp.find('table:visible').each(function () {\n                                    var $g = $(this),\n                                        oldWidth = $g.outerWidth(),\n                                        oldMarginLeft = $g.css(rtl ? 'marginRight' : 'marginLeft').toString().replace('%', ''),\n                                        newWidth = oldWidth - sliderAccessWidth,\n                                        newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%',\n                                        css = { width: newWidth, marginRight: 0, marginLeft: 0 };\n                                    css[rtl ? 'marginRight' : 'marginLeft'] = newMarginLeft;\n                                    $g.css(css);\n                                });\n                            }\n                        }\n                    }, 10);\n                }\n                // end slideAccess integration\n\n                tp_inst._limitMinMaxDateTime(this.inst, true);\n            }\n        },\n\n        /*\n        * This function tries to limit the ability to go outside the\n        * min/max date range\n        */\n        _limitMinMaxDateTime: function (dp_inst, adjustSliders) {\n            var o = this._defaults,\n                dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);\n\n            if (!this._defaults.showTimepicker) {\n                return;\n            } // No time so nothing to check here\n\n            if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) {\n                var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),\n                    minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);\n\n                if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null || this.microsecMinOriginal === null) {\n                    this.hourMinOriginal = o.hourMin;\n                    this.minuteMinOriginal = o.minuteMin;\n                    this.secondMinOriginal = o.secondMin;\n                    this.millisecMinOriginal = o.millisecMin;\n                    this.microsecMinOriginal = o.microsecMin;\n                }\n\n                if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() === dp_date.getTime()) {\n                    this._defaults.hourMin = minDateTime.getHours();\n                    if (this.hour <= this._defaults.hourMin) {\n                        this.hour = this._defaults.hourMin;\n                        this._defaults.minuteMin = minDateTime.getMinutes();\n                        if (this.minute <= this._defaults.minuteMin) {\n                            this.minute = this._defaults.minuteMin;\n                            this._defaults.secondMin = minDateTime.getSeconds();\n                            if (this.second <= this._defaults.secondMin) {\n                                this.second = this._defaults.secondMin;\n                                this._defaults.millisecMin = minDateTime.getMilliseconds();\n                                if (this.millisec <= this._defaults.millisecMin) {\n                                    this.millisec = this._defaults.millisecMin;\n                                    this._defaults.microsecMin = minDateTime.getMicroseconds();\n                                } else {\n                                    if (this.microsec < this._defaults.microsecMin) {\n                                        this.microsec = this._defaults.microsecMin;\n                                    }\n                                    this._defaults.microsecMin = this.microsecMinOriginal;\n                                }\n                            } else {\n                                this._defaults.millisecMin = this.millisecMinOriginal;\n                                this._defaults.microsecMin = this.microsecMinOriginal;\n                            }\n                        } else {\n                            this._defaults.secondMin = this.secondMinOriginal;\n                            this._defaults.millisecMin = this.millisecMinOriginal;\n                            this._defaults.microsecMin = this.microsecMinOriginal;\n                        }\n                    } else {\n                        this._defaults.minuteMin = this.minuteMinOriginal;\n                        this._defaults.secondMin = this.secondMinOriginal;\n                        this._defaults.millisecMin = this.millisecMinOriginal;\n                        this._defaults.microsecMin = this.microsecMinOriginal;\n                    }\n                } else {\n                    this._defaults.hourMin = this.hourMinOriginal;\n                    this._defaults.minuteMin = this.minuteMinOriginal;\n                    this._defaults.secondMin = this.secondMinOriginal;\n                    this._defaults.millisecMin = this.millisecMinOriginal;\n                    this._defaults.microsecMin = this.microsecMinOriginal;\n                }\n            }\n\n            if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) {\n                var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),\n                    maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);\n\n                if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null || this.millisecMaxOriginal === null) {\n                    this.hourMaxOriginal = o.hourMax;\n                    this.minuteMaxOriginal = o.minuteMax;\n                    this.secondMaxOriginal = o.secondMax;\n                    this.millisecMaxOriginal = o.millisecMax;\n                    this.microsecMaxOriginal = o.microsecMax;\n                }\n\n                if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() === dp_date.getTime()) {\n                    this._defaults.hourMax = maxDateTime.getHours();\n                    if (this.hour >= this._defaults.hourMax) {\n                        this.hour = this._defaults.hourMax;\n                        this._defaults.minuteMax = maxDateTime.getMinutes();\n                        if (this.minute >= this._defaults.minuteMax) {\n                            this.minute = this._defaults.minuteMax;\n                            this._defaults.secondMax = maxDateTime.getSeconds();\n                            if (this.second >= this._defaults.secondMax) {\n                                this.second = this._defaults.secondMax;\n                                this._defaults.millisecMax = maxDateTime.getMilliseconds();\n                                if (this.millisec >= this._defaults.millisecMax) {\n                                    this.millisec = this._defaults.millisecMax;\n                                    this._defaults.microsecMax = maxDateTime.getMicroseconds();\n                                } else {\n                                    if (this.microsec > this._defaults.microsecMax) {\n                                        this.microsec = this._defaults.microsecMax;\n                                    }\n                                    this._defaults.microsecMax = this.microsecMaxOriginal;\n                                }\n                            } else {\n                                this._defaults.millisecMax = this.millisecMaxOriginal;\n                                this._defaults.microsecMax = this.microsecMaxOriginal;\n                            }\n                        } else {\n                            this._defaults.secondMax = this.secondMaxOriginal;\n                            this._defaults.millisecMax = this.millisecMaxOriginal;\n                            this._defaults.microsecMax = this.microsecMaxOriginal;\n                        }\n                    } else {\n                        this._defaults.minuteMax = this.minuteMaxOriginal;\n                        this._defaults.secondMax = this.secondMaxOriginal;\n                        this._defaults.millisecMax = this.millisecMaxOriginal;\n                        this._defaults.microsecMax = this.microsecMaxOriginal;\n                    }\n                } else {\n                    this._defaults.hourMax = this.hourMaxOriginal;\n                    this._defaults.minuteMax = this.minuteMaxOriginal;\n                    this._defaults.secondMax = this.secondMaxOriginal;\n                    this._defaults.millisecMax = this.millisecMaxOriginal;\n                    this._defaults.microsecMax = this.microsecMaxOriginal;\n                }\n            }\n\n            if (dp_inst.settings.minTime!==null) {\n                var tempMinTime=new Date(\"01/01/1970 \" + dp_inst.settings.minTime);\n                if (this.hour<tempMinTime.getHours()) {\n                    this.hour=this._defaults.hourMin=tempMinTime.getHours();\n                    this.minute=this._defaults.minuteMin=tempMinTime.getMinutes();\n                } else if (this.hour===tempMinTime.getHours() && this.minute<tempMinTime.getMinutes()) {\n                    this.minute=this._defaults.minuteMin=tempMinTime.getMinutes();\n                } else {\n                    if (this._defaults.hourMin<tempMinTime.getHours()) {\n                        this._defaults.hourMin=tempMinTime.getHours();\n                        this._defaults.minuteMin=tempMinTime.getMinutes();\n                    } else if (this._defaults.hourMin===tempMinTime.getHours()===this.hour && this._defaults.minuteMin<tempMinTime.getMinutes()) {\n                        this._defaults.minuteMin=tempMinTime.getMinutes();\n                    } else {\n                        this._defaults.minuteMin=0;\n                    }\n                }\n            }\n\n            if (dp_inst.settings.maxTime!==null) {\n                var tempMaxTime=new Date(\"01/01/1970 \" + dp_inst.settings.maxTime);\n                if (this.hour>tempMaxTime.getHours()) {\n                    this.hour=this._defaults.hourMax=tempMaxTime.getHours();\n                    this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();\n                } else if (this.hour===tempMaxTime.getHours() && this.minute>tempMaxTime.getMinutes()) {\n                    this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();\n                } else {\n                    if (this._defaults.hourMax>tempMaxTime.getHours()) {\n                        this._defaults.hourMax=tempMaxTime.getHours();\n                        this._defaults.minuteMax=tempMaxTime.getMinutes();\n                    } else if (this._defaults.hourMax===tempMaxTime.getHours()===this.hour && this._defaults.minuteMax>tempMaxTime.getMinutes()) {\n                        this._defaults.minuteMax=tempMaxTime.getMinutes();\n                    } else {\n                        this._defaults.minuteMax=59;\n                    }\n                }\n            }\n\n            if (adjustSliders !== undefined && adjustSliders === true) {\n                var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10),\n                    minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10),\n                    secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10),\n                    millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10),\n                    microsecMax = parseInt((this._defaults.microsecMax - ((this._defaults.microsecMax - this._defaults.microsecMin) % this._defaults.stepMicrosec)), 10);\n\n                if (this.hour_slider) {\n                    this.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax, step: this._defaults.stepHour });\n                    this.control.value(this, this.hour_slider, 'hour', this.hour - (this.hour % this._defaults.stepHour));\n                }\n                if (this.minute_slider) {\n                    this.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax, step: this._defaults.stepMinute });\n                    this.control.value(this, this.minute_slider, 'minute', this.minute - (this.minute % this._defaults.stepMinute));\n                }\n                if (this.second_slider) {\n                    this.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax, step: this._defaults.stepSecond });\n                    this.control.value(this, this.second_slider, 'second', this.second - (this.second % this._defaults.stepSecond));\n                }\n                if (this.millisec_slider) {\n                    this.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax, step: this._defaults.stepMillisec });\n                    this.control.value(this, this.millisec_slider, 'millisec', this.millisec - (this.millisec % this._defaults.stepMillisec));\n                }\n                if (this.microsec_slider) {\n                    this.control.options(this, this.microsec_slider, 'microsec', { min: this._defaults.microsecMin, max: microsecMax, step: this._defaults.stepMicrosec });\n                    this.control.value(this, this.microsec_slider, 'microsec', this.microsec - (this.microsec % this._defaults.stepMicrosec));\n                }\n            }\n\n        },\n\n        /*\n        * when a slider moves, set the internal time...\n        * on time change is also called when the time is updated in the text field\n        */\n        _onTimeChange: function () {\n            if (!this._defaults.showTimepicker) {\n                return;\n            }\n            var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false,\n                minute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false,\n                second = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false,\n                millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false,\n                microsec = (this.microsec_slider) ? this.control.value(this, this.microsec_slider, 'microsec') : false,\n                timezone = (this.timezone_select) ? this.timezone_select.val() : false,\n                o = this._defaults,\n                pickerTimeFormat = o.pickerTimeFormat || o.timeFormat,\n                pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;\n\n            if (typeof(hour) === 'object') {\n                hour = false;\n            }\n            if (typeof(minute) === 'object') {\n                minute = false;\n            }\n            if (typeof(second) === 'object') {\n                second = false;\n            }\n            if (typeof(millisec) === 'object') {\n                millisec = false;\n            }\n            if (typeof(microsec) === 'object') {\n                microsec = false;\n            }\n            if (typeof(timezone) === 'object') {\n                timezone = false;\n            }\n\n            if (hour !== false) {\n                hour = parseInt(hour, 10);\n            }\n            if (minute !== false) {\n                minute = parseInt(minute, 10);\n            }\n            if (second !== false) {\n                second = parseInt(second, 10);\n            }\n            if (millisec !== false) {\n                millisec = parseInt(millisec, 10);\n            }\n            if (microsec !== false) {\n                microsec = parseInt(microsec, 10);\n            }\n            if (timezone !== false) {\n                timezone = timezone.toString();\n            }\n\n            var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];\n\n            // If the update was done in the input field, the input field should not be updated.\n            // If the update was done using the sliders, update the input field.\n            var hasChanged = (\n                hour !== parseInt(this.hour,10) || // sliders should all be numeric\n                minute !== parseInt(this.minute,10) ||\n                second !== parseInt(this.second,10) ||\n                millisec !== parseInt(this.millisec,10) ||\n                microsec !== parseInt(this.microsec,10) ||\n                (this.ampm.length > 0 && (hour < 12) !== ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1)) ||\n                (this.timezone !== null && timezone !== this.timezone.toString()) // could be numeric or \"EST\" format, so use toString()\n            );\n\n            if (hasChanged) {\n\n                if (hour !== false) {\n                    this.hour = hour;\n                }\n                if (minute !== false) {\n                    this.minute = minute;\n                }\n                if (second !== false) {\n                    this.second = second;\n                }\n                if (millisec !== false) {\n                    this.millisec = millisec;\n                }\n                if (microsec !== false) {\n                    this.microsec = microsec;\n                }\n                if (timezone !== false) {\n                    this.timezone = timezone;\n                }\n\n                if (!this.inst) {\n                    this.inst = $.datepicker._getInst(this.$input[0]);\n                }\n\n                this._limitMinMaxDateTime(this.inst, true);\n            }\n            if (this.support.ampm) {\n                this.ampm = ampm;\n            }\n\n            // Updates the time within the timepicker\n            this.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o);\n            if (this.$timeObj) {\n                if (pickerTimeFormat === o.timeFormat) {\n                    this.$timeObj.val(this.formattedTime + pickerTimeSuffix);\n                }\n                else {\n                    this.$timeObj.val($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix);\n                }\n                if (this.$timeObj[0].setSelectionRange) {\n                    var sPos = this.$timeObj[0].selectionStart;\n                    var ePos = this.$timeObj[0].selectionEnd;\n                    this.$timeObj[0].setSelectionRange(sPos, ePos);\n                }\n            }\n\n            this.timeDefined = true;\n            if (hasChanged) {\n                this._updateDateTime();\n                //this.$input.focus(); // may automatically open the picker on setDate\n            }\n        },\n\n        /*\n        * call custom onSelect.\n        * bind to sliders slidestop, and grid click.\n        */\n        _onSelectHandler: function () {\n            var onSelect = this._defaults.onSelect || this.inst.settings.onSelect;\n            var inputEl = this.$input ? this.$input[0] : null;\n            if (onSelect && inputEl) {\n                onSelect.apply(inputEl, [this.formattedDateTime, this]);\n            }\n        },\n\n        /*\n        * update our input with the new date time..\n        */\n        _updateDateTime: function (dp_inst) {\n            dp_inst = this.inst || dp_inst;\n            var dtTmp = (dp_inst.currentYear > 0?\n                new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay) :\n                new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),\n                dt = $.datepicker._daylightSavingAdjust(dtTmp),\n                //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),\n                //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay)),\n                dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),\n                formatCfg = $.datepicker._getFormatConfig(dp_inst),\n                timeAvailable = dt !== null && this.timeDefined;\n            this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);\n            var formattedDateTime = this.formattedDate;\n\n            // if a slider was changed but datepicker doesn't have a value yet, set it\n            if (dp_inst.lastVal === \"\") {\n                dp_inst.currentYear = dp_inst.selectedYear;\n                dp_inst.currentMonth = dp_inst.selectedMonth;\n                dp_inst.currentDay = dp_inst.selectedDay;\n            }\n\n            /*\n            * remove following lines to force every changes in date picker to change the input value\n            * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker.\n            * If the user manually empty the value in the input field, the date picker will never change selected value.\n            */\n            //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {\n            //\treturn;\n            //}\n\n            if (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === false) {\n                formattedDateTime = this.formattedTime;\n            } else if ((this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) || (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === true)) {\n                formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;\n            }\n\n            this.formattedDateTime = formattedDateTime;\n\n            if (!this._defaults.showTimepicker) {\n                this.$input.val(this.formattedDate);\n            } else if (this.$altInput && this._defaults.timeOnly === false && this._defaults.altFieldTimeOnly === true) {\n                this.$altInput.val(this.formattedTime);\n                this.$input.val(this.formattedDate);\n            } else if (this.$altInput) {\n                this.$input.val(formattedDateTime);\n                var altFormattedDateTime = '',\n                    altSeparator = this._defaults.altSeparator !== null ? this._defaults.altSeparator : this._defaults.separator,\n                    altTimeSuffix = this._defaults.altTimeSuffix !== null ? this._defaults.altTimeSuffix : this._defaults.timeSuffix;\n\n                if (!this._defaults.timeOnly) {\n                    if (this._defaults.altFormat) {\n                        altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg);\n                    }\n                    else {\n                        altFormattedDateTime = this.formattedDate;\n                    }\n\n                    if (altFormattedDateTime) {\n                        altFormattedDateTime += altSeparator;\n                    }\n                }\n\n                if (this._defaults.altTimeFormat !== null) {\n                    altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix;\n                }\n                else {\n                    altFormattedDateTime += this.formattedTime + altTimeSuffix;\n                }\n                this.$altInput.val(altFormattedDateTime);\n            } else {\n                this.$input.val(formattedDateTime);\n            }\n\n            this.$input.trigger(\"change\");\n        },\n\n        _onFocus: function () {\n            if (!this.$input.val() && this._defaults.defaultValue) {\n                this.$input.val(this._defaults.defaultValue);\n                var inst = $.datepicker._getInst(this.$input.get(0)),\n                    tp_inst = $.datepicker._get(inst, 'timepicker');\n                if (tp_inst) {\n                    if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {\n                        try {\n                            $.datepicker._updateDatepicker(inst);\n                        } catch (err) {\n                            $.timepicker.log(err);\n                        }\n                    }\n                }\n            }\n        },\n\n        /*\n        * Small abstraction to control types\n        * We can add more, just be sure to follow the pattern: create, options, value\n        */\n        _controls: {\n            // slider methods\n            slider: {\n                create: function (tp_inst, obj, unit, val, min, max, step) {\n                    var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60\n                    return obj.prop('slide', null).slider({\n                        orientation: \"horizontal\",\n                        value: rtl ? val * -1 : val,\n                        min: rtl ? max * -1 : min,\n                        max: rtl ? min * -1 : max,\n                        step: step,\n                        slide: function (event, ui) {\n                            tp_inst.control.value(tp_inst, $(this), unit, rtl ? ui.value * -1 : ui.value);\n                            tp_inst._onTimeChange();\n                        },\n                        stop: function (event, ui) {\n                            tp_inst._onSelectHandler();\n                        }\n                    });\n                },\n                options: function (tp_inst, obj, unit, opts, val) {\n                    if (tp_inst._defaults.isRTL) {\n                        if (typeof(opts) === 'string') {\n                            if (opts === 'min' || opts === 'max') {\n                                if (val !== undefined) {\n                                    return obj.slider(opts, val * -1);\n                                }\n                                return Math.abs(obj.slider(opts));\n                            }\n                            return obj.slider(opts);\n                        }\n                        var min = opts.min,\n                            max = opts.max;\n                        opts.min = opts.max = null;\n                        if (min !== undefined) {\n                            opts.max = min * -1;\n                        }\n                        if (max !== undefined) {\n                            opts.min = max * -1;\n                        }\n                        return obj.slider(opts);\n                    }\n                    if (typeof(opts) === 'string' && val !== undefined) {\n                        return obj.slider(opts, val);\n                    }\n                    return obj.slider(opts);\n                },\n                value: function (tp_inst, obj, unit, val) {\n                    if (tp_inst._defaults.isRTL) {\n                        if (val !== undefined) {\n                            return obj.slider('value', val * -1);\n                        }\n                        return Math.abs(obj.slider('value'));\n                    }\n                    if (val !== undefined) {\n                        return obj.slider('value', val);\n                    }\n                    return obj.slider('value');\n                }\n            },\n            // select methods\n            select: {\n                create: function (tp_inst, obj, unit, val, min, max, step) {\n                    var sel = '<select class=\"ui-timepicker-select ui-state-default ui-corner-all\" data-unit=\"' + unit + '\" data-min=\"' + min + '\" data-max=\"' + max + '\" data-step=\"' + step + '\">',\n                        format = tp_inst._defaults.pickerTimeFormat || tp_inst._defaults.timeFormat;\n\n                    for (var i = min; i <= max; i += step) {\n                        sel += '<option value=\"' + i + '\"' + (i === val ? ' selected' : '') + '>';\n                        if (unit === 'hour') {\n                            sel += $.datepicker.formatTime($.trim(format.replace(/[^ht ]/ig, '')), {hour: i}, tp_inst._defaults);\n                        }\n                        else if (unit === 'millisec' || unit === 'microsec' || i >= 10) { sel += i; }\n                        else {sel += '0' + i.toString(); }\n                        sel += '</option>';\n                    }\n                    sel += '</select>';\n\n                    obj.children('select').remove();\n\n                    $(sel).appendTo(obj).change(function (e) {\n                        tp_inst._onTimeChange();\n                        tp_inst._onSelectHandler();\n                        tp_inst._afterInject();\n                    });\n\n                    return obj;\n                },\n                options: function (tp_inst, obj, unit, opts, val) {\n                    var o = {},\n                        $t = obj.children('select');\n                    if (typeof(opts) === 'string') {\n                        if (val === undefined) {\n                            return $t.data(opts);\n                        }\n                        o[opts] = val;\n                    }\n                    else { o = opts; }\n                    return tp_inst.control.create(tp_inst, obj, $t.data('unit'), $t.val(), o.min>=0 ? o.min : $t.data('min'), o.max || $t.data('max'), o.step || $t.data('step'));\n                },\n                value: function (tp_inst, obj, unit, val) {\n                    var $t = obj.children('select');\n                    if (val !== undefined) {\n                        return $t.val(val);\n                    }\n                    return $t.val();\n                }\n            }\n        } // end _controls\n\n    });\n\n    $.fn.extend({\n        /*\n        * shorthand just to use timepicker.\n        */\n        timepicker: function (o) {\n            o = o || {};\n            var tmp_args = Array.prototype.slice.call(arguments);\n\n            if (typeof o === 'object') {\n                tmp_args[0] = $.extend(o, {\n                    timeOnly: true\n                });\n            }\n\n            return $(this).each(function () {\n                $.fn.datetimepicker.apply($(this), tmp_args);\n            });\n        },\n\n        /*\n        * extend timepicker to datepicker\n        */\n        datetimepicker: function (o) {\n            o = o || {};\n            var tmp_args = arguments;\n\n            if (typeof(o) === 'string') {\n                if (o === 'getDate'  || (o === 'option' && tmp_args.length === 2 && typeof (tmp_args[1]) === 'string')) {\n                    return $.fn.datepicker.apply($(this[0]), tmp_args);\n                } else {\n                    return this.each(function () {\n                        var $t = $(this);\n                        $t.datepicker.apply($t, tmp_args);\n                    });\n                }\n            } else {\n                return this.each(function () {\n                    var $t = $(this);\n                    $t.datepicker($.timepicker._newInst($t, o)._defaults);\n                });\n            }\n        }\n    });\n\n    /*\n    * Public Utility to parse date and time\n    */\n    $.datepicker.parseDateTime = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {\n        var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings);\n        if (parseRes.timeObj) {\n            var t = parseRes.timeObj;\n            parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec);\n            parseRes.date.setMicroseconds(t.microsec);\n        }\n\n        return parseRes.date;\n    };\n\n    /*\n    * Public utility to parse time\n    */\n    $.datepicker.parseTime = function (timeFormat, timeString, options) {\n        var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {}),\n            iso8601 = (timeFormat.replace(/\\'.*?\\'/g, '').indexOf('Z') !== -1);\n\n        // Strict parse requires the timeString to match the timeFormat exactly\n        var strictParse = function (f, s, o) {\n\n            // pattern for standard and localized AM/PM markers\n            var getPatternAmpm = function (amNames, pmNames) {\n                var markers = [];\n                if (amNames) {\n                    $.merge(markers, amNames);\n                }\n                if (pmNames) {\n                    $.merge(markers, pmNames);\n                }\n                markers = $.map(markers, function (val) {\n                    return val.replace(/[.*+?|()\\[\\]{}\\\\]/g, '\\\\$&');\n                });\n                return '(' + markers.join('|') + ')?';\n            };\n\n            // figure out position of time elements.. cause js cant do named captures\n            var getFormatPositions = function (timeFormat) {\n                var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|c{1}|t{1,2}|z|'.*?')/g),\n                    orders = {\n                        h: -1,\n                        m: -1,\n                        s: -1,\n                        l: -1,\n                        c: -1,\n                        t: -1,\n                        z: -1\n                    };\n\n                if (finds) {\n                    for (var i = 0; i < finds.length; i++) {\n                        if (orders[finds[i].toString().charAt(0)] === -1) {\n                            orders[finds[i].toString().charAt(0)] = i + 1;\n                        }\n                    }\n                }\n                return orders;\n            };\n\n            var regstr = '^' + f.toString()\n                    .replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {\n                        var ml = match.length;\n                        switch (match.charAt(0).toLowerCase()) {\n                            case 'h':\n                                return ml === 1 ? '(\\\\d?\\\\d)' : '(\\\\d{' + ml + '})';\n                            case 'm':\n                                return ml === 1 ? '(\\\\d?\\\\d)' : '(\\\\d{' + ml + '})';\n                            case 's':\n                                return ml === 1 ? '(\\\\d?\\\\d)' : '(\\\\d{' + ml + '})';\n                            case 'l':\n                                return '(\\\\d?\\\\d?\\\\d)';\n                            case 'c':\n                                return '(\\\\d?\\\\d?\\\\d)';\n                            case 'z':\n                                return '(z|[-+]\\\\d\\\\d:?\\\\d\\\\d|\\\\S+)?';\n                            case 't':\n                                return getPatternAmpm(o.amNames, o.pmNames);\n                            default:    // literal escaped in quotes\n                                return '(' + match.replace(/\\'/g, \"\").replace(/(\\.|\\$|\\^|\\\\|\\/|\\(|\\)|\\[|\\]|\\?|\\+|\\*)/g, function (m) { return \"\\\\\" + m; }) + ')?';\n                        }\n                    })\n                    .replace(/\\s/g, '\\\\s?') +\n                o.timeSuffix + '$',\n                order = getFormatPositions(f),\n                ampm = '',\n                treg;\n\n            treg = s.match(new RegExp(regstr, 'i'));\n\n            var resTime = {\n                hour: 0,\n                minute: 0,\n                second: 0,\n                millisec: 0,\n                microsec: 0\n            };\n\n            if (treg) {\n                if (order.t !== -1) {\n                    if (treg[order.t] === undefined || treg[order.t].length === 0) {\n                        ampm = '';\n                        resTime.ampm = '';\n                    } else {\n                        ampm = $.inArray(treg[order.t].toUpperCase(), $.map(o.amNames, function (x,i) { return x.toUpperCase(); })) !== -1 ? 'AM' : 'PM';\n                        resTime.ampm = o[ampm === 'AM' ? 'amNames' : 'pmNames'][0];\n                    }\n                }\n\n                if (order.h !== -1) {\n                    if (ampm === 'AM' && treg[order.h] === '12') {\n                        resTime.hour = 0; // 12am = 0 hour\n                    } else {\n                        if (ampm === 'PM' && treg[order.h] !== '12') {\n                            resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12\n                        } else {\n                            resTime.hour = Number(treg[order.h]);\n                        }\n                    }\n                }\n\n                if (order.m !== -1) {\n                    resTime.minute = Number(treg[order.m]);\n                }\n                if (order.s !== -1) {\n                    resTime.second = Number(treg[order.s]);\n                }\n                if (order.l !== -1) {\n                    resTime.millisec = Number(treg[order.l]);\n                }\n                if (order.c !== -1) {\n                    resTime.microsec = Number(treg[order.c]);\n                }\n                if (order.z !== -1 && treg[order.z] !== undefined) {\n                    resTime.timezone = $.timepicker.timezoneOffsetNumber(treg[order.z]);\n                }\n\n\n                return resTime;\n            }\n            return false;\n        };// end strictParse\n\n        // First try JS Date, if that fails, use strictParse\n        var looseParse = function (f, s, o) {\n            try {\n                var d = new Date('2012-01-01 ' + s);\n                if (isNaN(d.getTime())) {\n                    d = new Date('2012-01-01T' + s);\n                    if (isNaN(d.getTime())) {\n                        d = new Date('01/01/2012 ' + s);\n                        if (isNaN(d.getTime())) {\n                            throw \"Unable to parse time with native Date: \" + s;\n                        }\n                    }\n                }\n\n                return {\n                    hour: d.getHours(),\n                    minute: d.getMinutes(),\n                    second: d.getSeconds(),\n                    millisec: d.getMilliseconds(),\n                    microsec: d.getMicroseconds(),\n                    timezone: d.getTimezoneOffset() * -1\n                };\n            }\n            catch (err) {\n                try {\n                    return strictParse(f, s, o);\n                }\n                catch (err2) {\n                    $.timepicker.log(\"Unable to parse \\ntimeString: \" + s + \"\\ntimeFormat: \" + f);\n                }\n            }\n            return false;\n        }; // end looseParse\n\n        if (typeof o.parse === \"function\") {\n            return o.parse(timeFormat, timeString, o);\n        }\n        if (o.parse === 'loose') {\n            return looseParse(timeFormat, timeString, o);\n        }\n        return strictParse(timeFormat, timeString, o);\n    };\n\n    /**\n     * Public utility to format the time\n     * @param {string} format format of the time\n     * @param {Object} time Object not a Date for timezones\n     * @param {Object} [options] essentially the regional[].. amNames, pmNames, ampm\n     * @returns {string} the formatted time\n     */\n    $.datepicker.formatTime = function (format, time, options) {\n        options = options || {};\n        options = $.extend({}, $.timepicker._defaults, options);\n        time = $.extend({\n            hour: 0,\n            minute: 0,\n            second: 0,\n            millisec: 0,\n            microsec: 0,\n            timezone: null\n        }, time);\n\n        var tmptime = format,\n            ampmName = options.amNames[0],\n            hour = parseInt(time.hour, 10);\n\n        if (hour > 11) {\n            ampmName = options.pmNames[0];\n        }\n\n        tmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {\n            switch (match) {\n                case 'HH':\n                    return ('0' + hour).slice(-2);\n                case 'H':\n                    return hour;\n                case 'hh':\n                    return ('0' + convert24to12(hour)).slice(-2);\n                case 'h':\n                    return convert24to12(hour);\n                case 'mm':\n                    return ('0' + time.minute).slice(-2);\n                case 'm':\n                    return time.minute;\n                case 'ss':\n                    return ('0' + time.second).slice(-2);\n                case 's':\n                    return time.second;\n                case 'l':\n                    return ('00' + time.millisec).slice(-3);\n                case 'c':\n                    return ('00' + time.microsec).slice(-3);\n                case 'z':\n                    return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, false);\n                case 'Z':\n                    return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, true);\n                case 'T':\n                    return ampmName.charAt(0).toUpperCase();\n                case 'TT':\n                    return ampmName.toUpperCase();\n                case 't':\n                    return ampmName.charAt(0).toLowerCase();\n                case 'tt':\n                    return ampmName.toLowerCase();\n                default:\n                    return match.replace(/'/g, \"\");\n            }\n        });\n\n        return tmptime;\n    };\n\n    /*\n    * the bad hack :/ override datepicker so it doesn't close on select\n    // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378\n    */\n    $.datepicker._base_selectDate = $.datepicker._selectDate;\n    $.datepicker._selectDate = function (id, dateStr) {\n        var inst = this._getInst($(id)[0]),\n            tp_inst = this._get(inst, 'timepicker'),\n            was_inline;\n\n        if (tp_inst && inst.settings.showTimepicker) {\n            tp_inst._limitMinMaxDateTime(inst, true);\n            was_inline = inst.inline;\n            inst.inline = inst.stay_open = true;\n            //This way the onSelect handler called from calendarpicker get the full dateTime\n            this._base_selectDate(id, dateStr);\n            inst.inline = was_inline;\n            inst.stay_open = false;\n            this._notifyChange(inst);\n            this._updateDatepicker(inst);\n        } else {\n            this._base_selectDate(id, dateStr);\n        }\n    };\n\n    /*\n    * second bad hack :/ override datepicker so it triggers an event when changing the input field\n    * and does not redraw the datepicker on every selectDate event\n    */\n    $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;\n    $.datepicker._updateDatepicker = function (inst) {\n\n        // don't popup the datepicker if there is another instance already opened\n        var input = inst.input[0];\n        if ($.datepicker._curInst && $.datepicker._curInst !== inst && $.datepicker._datepickerShowing && $.datepicker._lastInput !== input) {\n            return;\n        }\n\n        if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {\n\n            this._base_updateDatepicker(inst);\n\n            // Reload the time control when changing something in the input text field.\n            var tp_inst = this._get(inst, 'timepicker');\n            if (tp_inst) {\n                tp_inst._addTimePicker(inst);\n            }\n        }\n    };\n\n    /*\n    * third bad hack :/ override datepicker so it allows spaces and colon in the input field\n    */\n    $.datepicker._base_doKeyPress = $.datepicker._doKeyPress;\n    $.datepicker._doKeyPress = function (event) {\n        var inst = $.datepicker._getInst(event.target),\n            tp_inst = $.datepicker._get(inst, 'timepicker');\n\n        if (tp_inst) {\n            if ($.datepicker._get(inst, 'constrainInput')) {\n                var ampm = tp_inst.support.ampm,\n                    tz = tp_inst._defaults.showTimezone !== null ? tp_inst._defaults.showTimezone : tp_inst.support.timezone,\n                    dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),\n                    datetimeChars = tp_inst._defaults.timeFormat.toString()\n                            .replace(/[hms]/g, '')\n                            .replace(/TT/g, ampm ? 'APM' : '')\n                            .replace(/Tt/g, ampm ? 'AaPpMm' : '')\n                            .replace(/tT/g, ampm ? 'AaPpMm' : '')\n                            .replace(/T/g, ampm ? 'AP' : '')\n                            .replace(/tt/g, ampm ? 'apm' : '')\n                            .replace(/t/g, ampm ? 'ap' : '') +\n                        \" \" + tp_inst._defaults.separator +\n                        tp_inst._defaults.timeSuffix +\n                        (tz ? tp_inst._defaults.timezoneList.join('') : '') +\n                        (tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) +\n                        dateChars,\n                    chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);\n                return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);\n            }\n        }\n\n        return $.datepicker._base_doKeyPress(event);\n    };\n\n    /*\n    * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField\n    * Update any alternate field to synchronise with the main field.\n    */\n    $.datepicker._base_updateAlternate = $.datepicker._updateAlternate;\n    $.datepicker._updateAlternate = function (inst) {\n        var tp_inst = this._get(inst, 'timepicker');\n        if (tp_inst) {\n            var altField = tp_inst._defaults.altField;\n            if (altField) { // update alternate field too\n                var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat,\n                    date = this._getDate(inst),\n                    formatCfg = $.datepicker._getFormatConfig(inst),\n                    altFormattedDateTime = '',\n                    altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator,\n                    altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix,\n                    altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat;\n\n                altFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix;\n                if (!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly && date !== null) {\n                    if (tp_inst._defaults.altFormat) {\n                        altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, date, formatCfg) + altSeparator + altFormattedDateTime;\n                    }\n                    else {\n                        altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime;\n                    }\n                }\n                $(altField).val( inst.input.val() ? altFormattedDateTime : \"\");\n            }\n        }\n        else {\n            $.datepicker._base_updateAlternate(inst);\n        }\n    };\n\n    /*\n    * Override key up event to sync manual input changes.\n    */\n    $.datepicker._base_doKeyUp = $.datepicker._doKeyUp;\n    $.datepicker._doKeyUp = function (event) {\n        var inst = $.datepicker._getInst(event.target),\n            tp_inst = $.datepicker._get(inst, 'timepicker');\n\n        if (tp_inst) {\n            if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {\n                try {\n                    $.datepicker._updateDatepicker(inst);\n                } catch (err) {\n                    $.timepicker.log(err);\n                }\n            }\n        }\n\n        return $.datepicker._base_doKeyUp(event);\n    };\n\n    /*\n    * override \"Today\" button to also grab the time and set it to input field.\n    */\n    $.datepicker._base_gotoToday = $.datepicker._gotoToday;\n    $.datepicker._gotoToday = function (id) {\n        var inst = this._getInst($(id)[0]);\n        this._base_gotoToday(id);\n        var tp_inst = this._get(inst, 'timepicker');\n        if (!tp_inst) {\n            return;\n        }\n\n        var tzoffset = $.timepicker.timezoneOffsetNumber(tp_inst.timezone);\n        var now = new Date();\n        now.setMinutes(now.getMinutes() + now.getTimezoneOffset() + parseInt(tzoffset, 10));\n        this._setTime(inst, now);\n        this._setDate(inst, now);\n        tp_inst._onSelectHandler();\n    };\n\n    /*\n    * Disable & enable the Time in the datetimepicker\n    */\n    $.datepicker._disableTimepickerDatepicker = function (target) {\n        var inst = this._getInst(target);\n        if (!inst) {\n            return;\n        }\n\n        var tp_inst = this._get(inst, 'timepicker');\n        $(target).datepicker('getDate'); // Init selected[Year|Month|Day]\n        if (tp_inst) {\n            inst.settings.showTimepicker = false;\n            tp_inst._defaults.showTimepicker = false;\n            tp_inst._updateDateTime(inst);\n        }\n    };\n\n    $.datepicker._enableTimepickerDatepicker = function (target) {\n        var inst = this._getInst(target);\n        if (!inst) {\n            return;\n        }\n\n        var tp_inst = this._get(inst, 'timepicker');\n        $(target).datepicker('getDate'); // Init selected[Year|Month|Day]\n        if (tp_inst) {\n            inst.settings.showTimepicker = true;\n            tp_inst._defaults.showTimepicker = true;\n            tp_inst._addTimePicker(inst); // Could be disabled on page load\n            tp_inst._updateDateTime(inst);\n        }\n    };\n\n    /*\n    * Create our own set time function\n    */\n    $.datepicker._setTime = function (inst, date) {\n        var tp_inst = this._get(inst, 'timepicker');\n        if (tp_inst) {\n            var defaults = tp_inst._defaults;\n\n            // calling _setTime with no date sets time to defaults\n            tp_inst.hour = date ? date.getHours() : defaults.hour;\n            tp_inst.minute = date ? date.getMinutes() : defaults.minute;\n            tp_inst.second = date ? date.getSeconds() : defaults.second;\n            tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec;\n            tp_inst.microsec = date ? date.getMicroseconds() : defaults.microsec;\n\n            //check if within min/max times..\n            tp_inst._limitMinMaxDateTime(inst, true);\n\n            tp_inst._onTimeChange();\n            tp_inst._updateDateTime(inst);\n        }\n    };\n\n    /*\n    * Create new public method to set only time, callable as $().datepicker('setTime', date)\n    */\n    $.datepicker._setTimeDatepicker = function (target, date, withDate) {\n        var inst = this._getInst(target);\n        if (!inst) {\n            return;\n        }\n\n        var tp_inst = this._get(inst, 'timepicker');\n\n        if (tp_inst) {\n            this._setDateFromField(inst);\n            var tp_date;\n            if (date) {\n                if (typeof date === \"string\") {\n                    tp_inst._parseTime(date, withDate);\n                    tp_date = new Date();\n                    tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);\n                    tp_date.setMicroseconds(tp_inst.microsec);\n                } else {\n                    tp_date = new Date(date.getTime());\n                    tp_date.setMicroseconds(date.getMicroseconds());\n                }\n                if (tp_date.toString() === 'Invalid Date') {\n                    tp_date = undefined;\n                }\n                this._setTime(inst, tp_date);\n            }\n        }\n\n    };\n\n    /*\n    * override setDate() to allow setting time too within Date object\n    */\n    $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;\n    $.datepicker._setDateDatepicker = function (target, _date) {\n        var inst = this._getInst(target);\n        var date = _date;\n        if (!inst) {\n            return;\n        }\n\n        if (typeof(_date) === 'string') {\n            date = new Date(_date);\n            if (!date.getTime()) {\n                this._base_setDateDatepicker.apply(this, arguments);\n                date = $(target).datepicker('getDate');\n            }\n        }\n\n        var tp_inst = this._get(inst, 'timepicker');\n        var tp_date;\n        if (date instanceof Date) {\n            tp_date = new Date(date.getTime());\n            tp_date.setMicroseconds(date.getMicroseconds());\n        } else {\n            tp_date = date;\n        }\n\n        // This is important if you are using the timezone option, javascript's Date\n        // object will only return the timezone offset for the current locale, so we\n        // adjust it accordingly.  If not using timezone option this won't matter..\n        // If a timezone is different in tp, keep the timezone as is\n        if (tp_inst && tp_date) {\n            // look out for DST if tz wasn't specified\n            if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {\n                tp_inst.timezone = tp_date.getTimezoneOffset() * -1;\n            }\n            date = $.timepicker.timezoneAdjust(date, $.timepicker.timezoneOffsetString(-date.getTimezoneOffset()), tp_inst.timezone);\n            tp_date = $.timepicker.timezoneAdjust(tp_date, $.timepicker.timezoneOffsetString(-tp_date.getTimezoneOffset()), tp_inst.timezone);\n        }\n\n        this._updateDatepicker(inst);\n        this._base_setDateDatepicker.apply(this, arguments);\n        this._setTimeDatepicker(target, tp_date, true);\n    };\n\n    /*\n    * override getDate() to allow getting time too within Date object\n    */\n    $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;\n    $.datepicker._getDateDatepicker = function (target, noDefault) {\n        var inst = this._getInst(target);\n        if (!inst) {\n            return;\n        }\n\n        var tp_inst = this._get(inst, 'timepicker');\n\n        if (tp_inst) {\n            // if it hasn't yet been defined, grab from field\n            if (inst.lastVal === undefined) {\n                this._setDateFromField(inst, noDefault);\n            }\n\n            var date = this._getDate(inst);\n\n            var currDT = null;\n\n            if (tp_inst.$altInput && tp_inst._defaults.altFieldTimeOnly) {\n                currDT = tp_inst.$input.val() + ' ' + tp_inst.$altInput.val();\n            }\n            else if (tp_inst.$input.get(0).tagName !== 'INPUT' && tp_inst.$altInput) {\n                /**\n                 * in case the datetimepicker has been applied to a non-input tag for inline UI,\n                 * and the user has not configured the plugin to display only time in altInput,\n                 * pick current date time from the altInput (and hope for the best, for now, until \"ER1\" is applied)\n                 *\n                 * @todo ER1. Since altInput can have a totally difference format, convert it to standard format by reading input format from \"altFormat\" and \"altTimeFormat\" option values\n                 */\n                currDT = tp_inst.$altInput.val();\n            }\n            else {\n                currDT = tp_inst.$input.val();\n            }\n\n            if (date && tp_inst._parseTime(currDT, !inst.settings.timeOnly)) {\n                date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);\n                date.setMicroseconds(tp_inst.microsec);\n\n                // This is important if you are using the timezone option, javascript's Date\n                // object will only return the timezone offset for the current locale, so we\n                // adjust it accordingly.  If not using timezone option this won't matter..\n                if (tp_inst.timezone != null) {\n                    // look out for DST if tz wasn't specified\n                    if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {\n                        tp_inst.timezone = date.getTimezoneOffset() * -1;\n                    }\n                    date = $.timepicker.timezoneAdjust(date, tp_inst.timezone, $.timepicker.timezoneOffsetString(-date.getTimezoneOffset()));\n                }\n            }\n            return date;\n        }\n        return this._base_getDateDatepicker(target, noDefault);\n    };\n\n    /*\n    * override parseDate() because UI 1.8.14 throws an error about \"Extra characters\"\n    * An option in datapicker to ignore extra format characters would be nicer.\n    */\n    $.datepicker._base_parseDate = $.datepicker.parseDate;\n    $.datepicker.parseDate = function (format, value, settings) {\n        var date;\n        try {\n            date = this._base_parseDate(format, value, settings);\n        } catch (err) {\n            // Hack!  The error message ends with a colon, a space, and\n            // the \"extra\" characters.  We rely on that instead of\n            // attempting to perfectly reproduce the parsing algorithm.\n            if (err.indexOf(\":\") >= 0) {\n                date = this._base_parseDate(format, value.substring(0, value.length - (err.length - err.indexOf(':') - 2)), settings);\n                $.timepicker.log(\"Error parsing the date string: \" + err + \"\\ndate string = \" + value + \"\\ndate format = \" + format);\n            } else {\n                throw err;\n            }\n        }\n        return date;\n    };\n\n    /*\n    * override formatDate to set date with time to the input\n    */\n    $.datepicker._base_formatDate = $.datepicker._formatDate;\n    $.datepicker._formatDate = function (inst, day, month, year) {\n        var tp_inst = this._get(inst, 'timepicker');\n        if (tp_inst) {\n            tp_inst._updateDateTime(inst);\n            return tp_inst.$input.val();\n        }\n        return this._base_formatDate(inst);\n    };\n\n    /*\n    * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate\n    */\n    $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;\n    $.datepicker._optionDatepicker = function (target, name, value) {\n        var inst = this._getInst(target),\n            name_clone;\n        if (!inst) {\n            return null;\n        }\n\n        var tp_inst = this._get(inst, 'timepicker');\n        if (tp_inst) {\n            var min = null,\n                max = null,\n                onselect = null,\n                overrides = tp_inst._defaults.evnts,\n                fns = {},\n                prop,\n                ret,\n                oldVal,\n                $target;\n            if (typeof name === 'string') { // if min/max was set with the string\n                if (name === 'minDate' || name === 'minDateTime') {\n                    min = value;\n                } else if (name === 'maxDate' || name === 'maxDateTime') {\n                    max = value;\n                } else if (name === 'onSelect') {\n                    onselect = value;\n                } else if (overrides.hasOwnProperty(name)) {\n                    if (typeof (value) === 'undefined') {\n                        return overrides[name];\n                    }\n                    fns[name] = value;\n                    name_clone = {}; //empty results in exiting function after overrides updated\n                }\n            } else if (typeof name === 'object') { //if min/max was set with the JSON\n                if (name.minDate) {\n                    min = name.minDate;\n                } else if (name.minDateTime) {\n                    min = name.minDateTime;\n                } else if (name.maxDate) {\n                    max = name.maxDate;\n                } else if (name.maxDateTime) {\n                    max = name.maxDateTime;\n                }\n                for (prop in overrides) {\n                    if (overrides.hasOwnProperty(prop) && name[prop]) {\n                        fns[prop] = name[prop];\n                    }\n                }\n            }\n            for (prop in fns) {\n                if (fns.hasOwnProperty(prop)) {\n                    overrides[prop] = fns[prop];\n                    if (!name_clone) { name_clone = $.extend({}, name); }\n                    delete name_clone[prop];\n                }\n            }\n            if (name_clone && isEmptyObject(name_clone)) { return; }\n            if (min) { //if min was set\n                if (min === 0) {\n                    min = new Date();\n                } else {\n                    min = new Date(min);\n                }\n                tp_inst._defaults.minDate = min;\n                tp_inst._defaults.minDateTime = min;\n            } else if (max) { //if max was set\n                if (max === 0) {\n                    max = new Date();\n                } else {\n                    max = new Date(max);\n                }\n                tp_inst._defaults.maxDate = max;\n                tp_inst._defaults.maxDateTime = max;\n            } else if (onselect) {\n                tp_inst._defaults.onSelect = onselect;\n            }\n\n            // Datepicker will override our date when we call _base_optionDatepicker when\n            // calling minDate/maxDate, so we will first grab the value, call\n            // _base_optionDatepicker, then set our value back.\n            if(min || max){\n                $target = $(target);\n                oldVal = $target.datetimepicker('getDate');\n                ret = this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);\n                $target.datetimepicker('setDate', oldVal);\n                return ret;\n            }\n        }\n        if (value === undefined) {\n            return this._base_optionDatepicker.call($.datepicker, target, name);\n        }\n        return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);\n    };\n\n    /*\n    * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,\n    * it will return false for all objects\n    */\n    var isEmptyObject = function (obj) {\n        var prop;\n        for (prop in obj) {\n            if (obj.hasOwnProperty(prop)) {\n                return false;\n            }\n        }\n        return true;\n    };\n\n    /*\n    * jQuery extend now ignores nulls!\n    */\n    var extendRemove = function (target, props) {\n        $.extend(target, props);\n        for (var name in props) {\n            if (props[name] === null || props[name] === undefined) {\n                target[name] = props[name];\n            }\n        }\n        return target;\n    };\n\n    /*\n    * Determine by the time format which units are supported\n    * Returns an object of booleans for each unit\n    */\n    var detectSupport = function (timeFormat) {\n        var tf = timeFormat.replace(/'.*?'/g, '').toLowerCase(), // removes literals\n            isIn = function (f, t) { // does the format contain the token?\n                return f.indexOf(t) !== -1 ? true : false;\n            };\n        return {\n            hour: isIn(tf, 'h'),\n            minute: isIn(tf, 'm'),\n            second: isIn(tf, 's'),\n            millisec: isIn(tf, 'l'),\n            microsec: isIn(tf, 'c'),\n            timezone: isIn(tf, 'z'),\n            ampm: isIn(tf, 't') && isIn(timeFormat, 'h'),\n            iso8601: isIn(timeFormat, 'Z')\n        };\n    };\n\n    /*\n    * Converts 24 hour format into 12 hour\n    * Returns 12 hour without leading 0\n    */\n    var convert24to12 = function (hour) {\n        hour %= 12;\n\n        if (hour === 0) {\n            hour = 12;\n        }\n\n        return String(hour);\n    };\n\n    var computeEffectiveSetting = function (settings, property) {\n        return settings && settings[property] ? settings[property] : $.timepicker._defaults[property];\n    };\n\n    /*\n    * Splits datetime string into date and time substrings.\n    * Throws exception when date can't be parsed\n    * Returns {dateString: dateString, timeString: timeString}\n    */\n    var splitDateTime = function (dateTimeString, timeSettings) {\n        // The idea is to get the number separator occurrences in datetime and the time format requested (since time has\n        // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.\n        var separator = computeEffectiveSetting(timeSettings, 'separator'),\n            format = computeEffectiveSetting(timeSettings, 'timeFormat'),\n            timeParts = format.split(separator), // how many occurrences of separator may be in our format?\n            timePartsLen = timeParts.length,\n            allParts = dateTimeString.split(separator),\n            allPartsLen = allParts.length;\n\n        if (allPartsLen > 1) {\n            return {\n                dateString: allParts.splice(0, allPartsLen - timePartsLen).join(separator),\n                timeString: allParts.splice(0, timePartsLen).join(separator)\n            };\n        }\n\n        return {\n            dateString: dateTimeString,\n            timeString: ''\n        };\n    };\n\n    /*\n    * Internal function to parse datetime interval\n    * Returns: {date: Date, timeObj: Object}, where\n    *   date - parsed date without time (type Date)\n    *   timeObj = {hour: , minute: , second: , millisec: , microsec: } - parsed time. Optional\n    */\n    var parseDateTimeInternal = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {\n        var date,\n            parts,\n            parsedTime;\n\n        parts = splitDateTime(dateTimeString, timeSettings);\n        date = $.datepicker._base_parseDate(dateFormat, parts.dateString, dateSettings);\n\n        if (parts.timeString === '') {\n            return {\n                date: date\n            };\n        }\n\n        parsedTime = $.datepicker.parseTime(timeFormat, parts.timeString, timeSettings);\n\n        if (!parsedTime) {\n            throw 'Wrong time format';\n        }\n\n        return {\n            date: date,\n            timeObj: parsedTime\n        };\n    };\n\n    /*\n    * Internal function to set timezone_select to the local timezone\n    */\n    var selectLocalTimezone = function (tp_inst, date) {\n        if (tp_inst && tp_inst.timezone_select) {\n            var now = date || new Date();\n            tp_inst.timezone_select.val(-now.getTimezoneOffset());\n        }\n    };\n\n    /*\n    * Create a Singleton Instance\n    */\n    $.timepicker = new Timepicker();\n\n    /**\n     * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)\n     * @param {number} tzMinutes if not a number, less than -720 (-1200), or greater than 840 (+1400) this value is returned\n     * @param {boolean} iso8601 if true formats in accordance to iso8601 \"+12:45\"\n     * @return {string}\n     */\n    $.timepicker.timezoneOffsetString = function (tzMinutes, iso8601) {\n        if (isNaN(tzMinutes) || tzMinutes > 840 || tzMinutes < -720) {\n            return tzMinutes;\n        }\n\n        var off = tzMinutes,\n            minutes = off % 60,\n            hours = (off - minutes) / 60,\n            iso = iso8601 ? ':' : '',\n            tz = (off >= 0 ? '+' : '-') + ('0' + Math.abs(hours)).slice(-2) + iso + ('0' + Math.abs(minutes)).slice(-2);\n\n        if (tz === '+00:00') {\n            return 'Z';\n        }\n        return tz;\n    };\n\n    /**\n     * Get the number in minutes that represents a timezone string\n     * @param  {string} tzString formatted like \"+0500\", \"-1245\", \"Z\"\n     * @return {number} the offset minutes or the original string if it doesn't match expectations\n     */\n    $.timepicker.timezoneOffsetNumber = function (tzString) {\n        var normalized = tzString.toString().replace(':', ''); // excuse any iso8601, end up with \"+1245\"\n\n        if (normalized.toUpperCase() === 'Z') { // if iso8601 with Z, its 0 minute offset\n            return 0;\n        }\n\n        if (!/^(\\-|\\+)\\d{4}$/.test(normalized)) { // possibly a user defined tz, so just give it back\n            return parseInt(tzString, 10);\n        }\n\n        return ((normalized.substr(0, 1) === '-' ? -1 : 1) * // plus or minus\n            ((parseInt(normalized.substr(1, 2), 10) * 60) + // hours (converted to minutes)\n                parseInt(normalized.substr(3, 2), 10))); // minutes\n    };\n\n    /**\n     * No way to set timezone in js Date, so we must adjust the minutes to compensate. (think setDate, getDate)\n     * @param  {Date} date\n     * @param  {string} fromTimezone formatted like \"+0500\", \"-1245\"\n     * @param  {string} toTimezone formatted like \"+0500\", \"-1245\"\n     * @return {Date}\n     */\n    $.timepicker.timezoneAdjust = function (date, fromTimezone, toTimezone) {\n        var fromTz = $.timepicker.timezoneOffsetNumber(fromTimezone);\n        var toTz = $.timepicker.timezoneOffsetNumber(toTimezone);\n        if (!isNaN(toTz)) {\n            date.setMinutes(date.getMinutes() + (-fromTz) - (-toTz));\n        }\n        return date;\n    };\n\n    /**\n     * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to\n     * enforce date range limits.\n     * n.b. The input value must be correctly formatted (reformatting is not supported)\n     * @param  {Element} startTime\n     * @param  {Element} endTime\n     * @param  {Object} options Options for the timepicker() call\n     * @return {jQuery}\n     */\n    $.timepicker.timeRange = function (startTime, endTime, options) {\n        return $.timepicker.handleRange('timepicker', startTime, endTime, options);\n    };\n\n    /**\n     * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to\n     * enforce date range limits.\n     * @param  {Element} startTime\n     * @param  {Element} endTime\n     * @param  {Object} options Options for the `timepicker()` call. Also supports `reformat`,\n     *   a boolean value that can be used to reformat the input values to the `dateFormat`.\n     * @param  {string} method Can be used to specify the type of picker to be added\n     * @return {jQuery}\n     */\n    $.timepicker.datetimeRange = function (startTime, endTime, options) {\n        $.timepicker.handleRange('datetimepicker', startTime, endTime, options);\n    };\n\n    /**\n     * Calls `datepicker` on the `startTime` and `endTime` elements, and configures them to\n     * enforce date range limits.\n     * @param  {Element} startTime\n     * @param  {Element} endTime\n     * @param  {Object} options Options for the `timepicker()` call. Also supports `reformat`,\n     *   a boolean value that can be used to reformat the input values to the `dateFormat`.\n     * @return {jQuery}\n     */\n    $.timepicker.dateRange = function (startTime, endTime, options) {\n        $.timepicker.handleRange('datepicker', startTime, endTime, options);\n    };\n\n    /**\n     * Calls `method` on the `startTime` and `endTime` elements, and configures them to\n     * enforce date range limits.\n     * @param  {string} method Can be used to specify the type of picker to be added\n     * @param  {Element} startTime\n     * @param  {Element} endTime\n     * @param  {Object} options Options for the `timepicker()` call. Also supports `reformat`,\n     *   a boolean value that can be used to reformat the input values to the `dateFormat`.\n     * @return {jQuery}\n     */\n    $.timepicker.handleRange = function (method, startTime, endTime, options) {\n        options = $.extend({}, {\n            minInterval: 0, // min allowed interval in milliseconds\n            maxInterval: 0, // max allowed interval in milliseconds\n            start: {},      // options for start picker\n            end: {}         // options for end picker\n        }, options);\n\n        // for the mean time this fixes an issue with calling getDate with timepicker()\n        var timeOnly = false;\n        if(method === 'timepicker'){\n            timeOnly = true;\n            method = 'datetimepicker';\n        }\n\n        function checkDates(changed, other) {\n            var startdt = startTime[method]('getDate'),\n                enddt = endTime[method]('getDate'),\n                changeddt = changed[method]('getDate');\n\n            if (startdt !== null) {\n                var minDate = new Date(startdt.getTime()),\n                    maxDate = new Date(startdt.getTime());\n\n                minDate.setMilliseconds(minDate.getMilliseconds() + options.minInterval);\n                maxDate.setMilliseconds(maxDate.getMilliseconds() + options.maxInterval);\n\n                if (options.minInterval > 0 && minDate > enddt) { // minInterval check\n                    endTime[method]('setDate', minDate);\n                }\n                else if (options.maxInterval > 0 && maxDate < enddt) { // max interval check\n                    endTime[method]('setDate', maxDate);\n                }\n                else if (startdt > enddt) {\n                    other[method]('setDate', changeddt);\n                }\n            }\n        }\n\n        function selected(changed, other, option) {\n            if (!changed.val()) {\n                return;\n            }\n            var date = changed[method].call(changed, 'getDate');\n            if (date !== null && options.minInterval > 0) {\n                if (option === 'minDate') {\n                    date.setMilliseconds(date.getMilliseconds() + options.minInterval);\n                }\n                if (option === 'maxDate') {\n                    date.setMilliseconds(date.getMilliseconds() - options.minInterval);\n                }\n            }\n\n            if (date.getTime) {\n                other[method].call(other, 'option', option, date);\n            }\n        }\n\n        $.fn[method].call(startTime, $.extend({\n            timeOnly: timeOnly,\n            onClose: function (dateText, inst) {\n                checkDates($(this), endTime);\n            },\n            onSelect: function (selectedDateTime) {\n                selected($(this), endTime, 'minDate');\n            }\n        }, options, options.start));\n        $.fn[method].call(endTime, $.extend({\n            timeOnly: timeOnly,\n            onClose: function (dateText, inst) {\n                checkDates($(this), startTime);\n            },\n            onSelect: function (selectedDateTime) {\n                selected($(this), startTime, 'maxDate');\n            }\n        }, options, options.end));\n\n        checkDates(startTime, endTime);\n\n        selected(startTime, endTime, 'minDate');\n        selected(endTime, startTime, 'maxDate');\n\n        return $([startTime.get(0), endTime.get(0)]);\n    };\n\n    /**\n     * Log error or data to the console during error or debugging\n     * @param  {Object} err pass any type object to log to the console during error or debugging\n     * @return {void}\n     */\n    $.timepicker.log = function () {\n        // Older IE (9, maybe 10) throw error on accessing `window.console.log.apply`, so check first.\n        if (window.console && window.console.log && window.console.log.apply) {\n            window.console.log.apply(window.console, Array.prototype.slice.call(arguments));\n        }\n    };\n\n    /*\n     * Add util object to allow access to private methods for testability.\n     */\n    $.timepicker._util = {\n        _extendRemove: extendRemove,\n        _isEmptyObject: isEmptyObject,\n        _convert24to12: convert24to12,\n        _detectSupport: detectSupport,\n        _selectLocalTimezone: selectLocalTimezone,\n        _computeEffectiveSetting: computeEffectiveSetting,\n        _splitDateTime: splitDateTime,\n        _parseDateTimeInternal: parseDateTimeInternal\n    };\n\n    /*\n    * Microsecond support\n    */\n    if (!Date.prototype.getMicroseconds) {\n        Date.prototype.microseconds = 0;\n        Date.prototype.getMicroseconds = function () { return this.microseconds; };\n        Date.prototype.setMicroseconds = function (m) {\n            this.setMilliseconds(this.getMilliseconds() + Math.floor(m / 1000));\n            this.microseconds = m % 1000;\n            return this;\n        };\n    }\n\n    /*\n    * Keep up with the version\n    */\n    $.timepicker.version = \"1.6.3\";\n\n}));\n","jquery/jquery.tabs.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    \"jquery\",\n    \"jquery/bootstrap/tab\",\n    \"jquery/bootstrap/collapse\",\n], function () {\n\n});\n","jquery/z-index.js":"/*!\n * zIndex plugin from jQuery UI Core - v1.10.4\n * http://jqueryui.com\n *\n * Copyright 2014 jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n *\n * http://api.jqueryui.com/category/ui-core/\n */\ndefine([\n    'jquery'\n], function ($, undefined) {\n\n// plugins\n    $.fn.extend({\n        zIndex: function (zIndex) {\n            if (zIndex !== undefined) {\n                return this.css(\"zIndex\", zIndex);\n            }\n\n            if (this.length) {\n                var elem = $(this[0]), position, value;\n                while (elem.length && elem[0] !== document) {\n                    // Ignore z-index if position is set to a value where z-index is ignored by the browser\n                    // This makes behavior of this function consistent across browsers\n                    // WebKit always returns auto if the element is positioned\n                    position = elem.css(\"position\");\n                    if (position === \"absolute\" || position === \"relative\" || position === \"fixed\") {\n                        // IE returns 0 when zIndex is not specified\n                        // other browsers return a string\n                        // we ignore the case of nested elements with an explicit value of 0\n                        // <div style=\"z-index: -10;\"><div style=\"z-index: 0;\"></div></div>\n                        value = parseInt(elem.css(\"zIndex\"), 10);\n                        if (!isNaN(value) && value !== 0) {\n                            return value;\n                        }\n                    }\n                    elem = elem.parent();\n                }\n            }\n\n            return 0;\n        }\n    });\n});\n","jquery/jquery.parsequery.js":"/**\n * Copyright (c) 2010 Conrad Irwin <conrad@rapportive.com> MIT license.\n * Based loosely on original: Copyright (c) 2008 mkmanning MIT license.\n *\n * Parses CGI query strings into javascript objects.\n *\n * See the README for details.\n **/\ndefine([\n    \"jquery\"\n], function($){\n    $.parseQuery = function (options) {\n\n        var config = {query: window.location.search || \"\"},\n            params = {};\n\n        if (typeof options === 'string') {\n            options = {query: options};\n        }\n        $.extend(config, $.parseQuery, options);\n        config.query = config.query.replace(/^\\?/, '');\n\n        if (config.query.length > 0) {\n            $.each(config.query.split(config.separator), function (i, param) {\n                var pair = param.split('='),\n                    key = config.decode(pair.shift(), null).toString(),\n                    value = config.decode(pair.length ? pair.join('=') : null, key);\n\n                if (config.array_keys.test ? config.array_keys.test(key) : config.array_keys(key)) {\n                    params[key] = params[key] || [];\n                    params[key].push(value);\n                } else {\n                    params[key] = value;\n                }\n            });\n        }\n        return params;\n    };\n    $.parseQuery.decode = $.parseQuery.default_decode = function (string) {\n        return decodeURIComponent((string || \"\").replace(/\\+/g, ' '));\n    };\n    $.parseQuery.array_keys = function () {\n        return false;\n    };\n    $.parseQuery.separator = \"&\";\n});\n","jquery/jquery.validate.js":"/*!\n * jQuery Validation Plugin v1.19.5\n *\n * https://jqueryvalidation.org/\n *\n * Copyright (c) 2022 J\u00f6rn Zaefferer\n * Released under the MIT license\n */\n(function( factory ) {\n    if ( typeof define === \"function\" && define.amd ) {\n        define( [\"jquery\", \"jquery/jquery.metadata\"], factory );\n    } else if (typeof module === \"object\" && module.exports) {\n        module.exports = factory( require( \"jquery\" ) );\n    } else {\n        factory( jQuery );\n    }\n}(function( $ ) {\n\n    $.extend( $.fn, {\n\n        // https://jqueryvalidation.org/validate/\n        validate: function( options ) {\n\n            // If nothing is selected, return nothing; can't chain anyway\n            if ( !this.length ) {\n                if ( options && options.debug && window.console ) {\n                    console.warn( \"Nothing selected, can't validate, returning nothing.\" );\n                }\n                return;\n            }\n\n            // Check if a validator for this form was already created\n            var validator = $.data( this[ 0 ], \"validator\" );\n            if ( validator ) {\n                return validator;\n            }\n\n            // Add novalidate tag if HTML5.\n            this.attr( \"novalidate\", \"novalidate\" );\n\n            validator = new $.validator( options, this[ 0 ] );\n            $.data( this[ 0 ], \"validator\", validator );\n\n            if ( validator.settings.onsubmit ) {\n\n                this.on( \"click.validate\", \":submit\", function( event ) {\n\n                    // Track the used submit button to properly handle scripted\n                    // submits later.\n                    validator.submitButton = event.currentTarget;\n\n                    // Allow suppressing validation by adding a cancel class to the submit button\n                    if ( $( this ).hasClass( \"cancel\" ) ) {\n                        validator.cancelSubmit = true;\n                    }\n\n                    // Allow suppressing validation by adding the html5 formnovalidate attribute to the submit button\n                    if ( $( this ).attr( \"formnovalidate\" ) !== undefined ) {\n                        validator.cancelSubmit = true;\n                    }\n                } );\n\n                // Validate the form on submit\n                this.on( \"submit.validate\", function( event ) {\n                    if ( validator.settings.debug ) {\n\n                        // Prevent form submit to be able to see console output\n                        event.preventDefault();\n                    }\n\n                    function handle() {\n                        var hidden, result;\n\n                        // Insert a hidden input as a replacement for the missing submit button\n                        // The hidden input is inserted in two cases:\n                        //   - A user defined a `submitHandler`\n                        //   - There was a pending request due to `remote` method and `stopRequest()`\n                        //     was called to submit the form in case it's valid\n                        if ( validator.submitButton && ( validator.settings.submitHandler || validator.formSubmitted ) ) {\n                            hidden = $( \"<input type='hidden'/>\" )\n                                .attr( \"name\", validator.submitButton.name )\n                                .val( $( validator.submitButton ).val() )\n                                .appendTo( validator.currentForm );\n                        }\n\n                        if ( validator.settings.submitHandler && !validator.settings.debug ) {\n                            result = validator.settings.submitHandler.call( validator, validator.currentForm, event );\n                            if ( hidden ) {\n\n                                // And clean up afterwards; thanks to no-block-scope, hidden can be referenced\n                                hidden.remove();\n                            }\n                            if ( result !== undefined ) {\n                                return result;\n                            }\n                            return false;\n                        }\n                        return true;\n                    }\n\n                    // Prevent submit for invalid forms or custom submit handlers\n                    if ( validator.cancelSubmit ) {\n                        validator.cancelSubmit = false;\n                        return handle();\n                    }\n                    if ( validator.form() ) {\n                        if ( validator.pendingRequest ) {\n                            validator.formSubmitted = true;\n                            return false;\n                        }\n                        return handle();\n                    } else {\n                        validator.focusInvalid();\n                        return false;\n                    }\n                } );\n            }\n\n            return validator;\n        },\n\n        // https://jqueryvalidation.org/valid/\n        valid: function() {\n            var valid, validator, errorList;\n\n            if ( $( this[ 0 ] ).is( \"form\" ) ) {\n                valid = this.validate().form();\n            } else {\n                errorList = [];\n                valid = true;\n                validator = $( this[ 0 ].form ).validate();\n                this.each( function() {\n                    valid = validator.element( this ) && valid;\n                    if ( !valid ) {\n                        errorList = errorList.concat( validator.errorList );\n                    }\n                } );\n                validator.errorList = errorList;\n            }\n            return valid;\n        },\n\n        // https://jqueryvalidation.org/rules/\n        rules: function( command, argument ) {\n            var element = this[ 0 ],\n                isContentEditable = typeof this.attr( \"contenteditable\" ) !== \"undefined\" && this.attr( \"contenteditable\" ) !== \"false\",\n                settings, staticRules, existingRules, data, param, filtered;\n\n            // If nothing is selected, return empty object; can't chain anyway\n            if ( element == null ) {\n                return;\n            }\n\n            if ( !element.form && isContentEditable ) {\n                element.form = this.closest( \"form\" )[ 0 ];\n                element.name = this.attr( \"name\" );\n            }\n\n            if ( element.form == null ) {\n                return;\n            }\n\n            if ( command ) {\n                settings = $.data( element.form, \"validator\" ).settings;\n                staticRules = settings.rules;\n                existingRules = $.validator.staticRules( element );\n                switch ( command ) {\n                    case \"add\":\n                        $.extend( existingRules, $.validator.normalizeRule( argument ) );\n\n                        // Remove messages from rules, but allow them to be set separately\n                        delete existingRules.messages;\n                        staticRules[ element.name ] = existingRules;\n                        if ( argument.messages ) {\n                            settings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages );\n                        }\n                        break;\n                    case \"remove\":\n                        if ( !argument ) {\n                            delete staticRules[ element.name ];\n                            return existingRules;\n                        }\n                        filtered = {};\n                        $.each( argument.split( /\\s/ ), function( index, method ) {\n                            filtered[ method ] = existingRules[ method ];\n                            delete existingRules[ method ];\n                        } );\n                        return filtered;\n                }\n            }\n\n            data = $.validator.normalizeRules(\n                $.extend(\n                    {},\n                    $.validator.metadataRules(element),\n                    $.validator.classRules( element ),\n                    $.validator.attributeRules( element ),\n                    $.validator.dataRules( element ),\n                    $.validator.staticRules( element )\n                ), element );\n\n            // Make sure required is at front\n            if ( data.required ) {\n                param = data.required;\n                delete data.required;\n                data = $.extend( { required: param }, data );\n            }\n\n            // Make sure remote is at back\n            if ( data.remote ) {\n                param = data.remote;\n                delete data.remote;\n                data = $.extend( data, { remote: param } );\n            }\n\n            return data;\n        }\n    } );\n\n// JQuery trim is deprecated, provide a trim method based on String.prototype.trim\n    var trim = function( str ) {\n\n        // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim#Polyfill\n        return str.replace( /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, \"\" );\n    };\n\n// Custom selectors\n    $.extend( $.expr.pseudos || $.expr[ \":\" ], {\t\t// '|| $.expr[ \":\" ]' here enables backwards compatibility to jQuery 1.7. Can be removed when dropping jQ 1.7.x support\n\n        // https://jqueryvalidation.org/blank-selector/\n        blank: function( a ) {\n            return !trim( \"\" + $( a ).val() );\n        },\n\n        // https://jqueryvalidation.org/filled-selector/\n        filled: function( a ) {\n            var val = $( a ).val();\n            return val !== null && !!trim( \"\" + val );\n        },\n\n        // https://jqueryvalidation.org/unchecked-selector/\n        unchecked: function( a ) {\n            return !$( a ).prop( \"checked\" );\n        }\n    } );\n\n// Constructor for validator\n    $.validator = function( options, form ) {\n        this.settings = $.extend( true, {}, $.validator.defaults, options );\n        this.currentForm = form;\n        this.init();\n    };\n\n// https://jqueryvalidation.org/jQuery.validator.format/\n    $.validator.format = function( source, params ) {\n        if ( arguments.length === 1 ) {\n            return function() {\n                var args = $.makeArray( arguments );\n                args.unshift( source );\n                return $.validator.format.apply( this, args );\n            };\n        }\n        if ( params === undefined ) {\n            return source;\n        }\n        if ( arguments.length > 2 && params.constructor !== Array  ) {\n            params = $.makeArray( arguments ).slice( 1 );\n        }\n        if ( params.constructor !== Array ) {\n            params = [ params ];\n        }\n        $.each( params, function( i, n ) {\n            source = source.replace( new RegExp( \"\\\\{\" + i + \"\\\\}\", \"g\" ), function() {\n                return n;\n            } );\n        } );\n        return source;\n    };\n\n    $.extend( $.validator, {\n\n        defaults: {\n            messages: {},\n            groups: {},\n            rules: {},\n            errorClass: \"error\",\n            pendingClass: \"pending\",\n            validClass: \"valid\",\n            errorElement: \"label\",\n            focusCleanup: false,\n            focusInvalid: true,\n            errorContainer: $( [] ),\n            errorLabelContainer: $( [] ),\n            onsubmit: true,\n            ignore: \":hidden\",\n            ignoreTitle: false,\n            onfocusin: function( element ) {\n                this.lastActive = element;\n\n                // Hide error label and remove error class on focus if enabled\n                if ( this.settings.focusCleanup ) {\n                    if ( this.settings.unhighlight ) {\n                        this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );\n                    }\n                    this.hideThese( this.errorsFor( element ) );\n                }\n            },\n            onfocusout: function( element ) {\n                if ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) {\n                    this.element( element );\n                }\n            },\n            onkeyup: function( element, event ) {\n\n                // Avoid revalidate the field when pressing one of the following keys\n                // Shift       => 16\n                // Ctrl        => 17\n                // Alt         => 18\n                // Caps lock   => 20\n                // End         => 35\n                // Home        => 36\n                // Left arrow  => 37\n                // Up arrow    => 38\n                // Right arrow => 39\n                // Down arrow  => 40\n                // Insert      => 45\n                // Num lock    => 144\n                // AltGr key   => 225\n                var excludedKeys = [\n                    16, 17, 18, 20, 35, 36, 37,\n                    38, 39, 40, 45, 144, 225\n                ];\n\n                if ( event.which === 9 && this.elementValue( element ) === \"\" || $.inArray( event.keyCode, excludedKeys ) !== -1 ) {\n                    return;\n                } else if ( element.name in this.submitted || element.name in this.invalid ) {\n                    this.element( element );\n                }\n            },\n            onclick: function( element ) {\n\n                // Click on selects, radiobuttons and checkboxes\n                if ( element.name in this.submitted ) {\n                    this.element( element );\n\n                    // Or option elements, check parent select in that case\n                } else if ( element.parentNode.name in this.submitted ) {\n                    this.element( element.parentNode );\n                }\n            },\n            highlight: function( element, errorClass, validClass ) {\n                if ( element.type === \"radio\" ) {\n                    this.findByName( element.name ).addClass( errorClass ).removeClass( validClass );\n                } else {\n                    $( element ).addClass( errorClass ).removeClass( validClass );\n                }\n            },\n            unhighlight: function( element, errorClass, validClass ) {\n                if ( element.type === \"radio\" ) {\n                    this.findByName( element.name ).removeClass( errorClass ).addClass( validClass );\n                } else {\n                    $( element ).removeClass( errorClass ).addClass( validClass );\n                }\n            }\n        },\n\n        // https://jqueryvalidation.org/jQuery.validator.setDefaults/\n        setDefaults: function( settings ) {\n            $.extend( $.validator.defaults, settings );\n        },\n\n        messages: {\n            required: \"This field is required.\",\n            remote: \"Please fix this field.\",\n            email: \"Please enter a valid email address.\",\n            url: \"Please enter a valid URL.\",\n            date: \"Please enter a valid date.\",\n            dateISO: \"Please enter a valid date (ISO).\",\n            number: \"Please enter a valid number.\",\n            digits: \"Please enter only digits.\",\n            equalTo: \"Please enter the same value again.\",\n            maxlength: $.validator.format( \"Please enter no more than {0} characters.\" ),\n            minlength: $.validator.format( \"Please enter at least {0} characters.\" ),\n            rangelength: $.validator.format( \"Please enter a value between {0} and {1} characters long.\" ),\n            range: $.validator.format( \"Please enter a value between {0} and {1}.\" ),\n            max: $.validator.format( \"Please enter a value less than or equal to {0}.\" ),\n            min: $.validator.format( \"Please enter a value greater than or equal to {0}.\" ),\n            step: $.validator.format( \"Please enter a multiple of {0}.\" )\n        },\n\n        autoCreateRanges: false,\n\n        prototype: {\n\n            init: function() {\n                this.labelContainer = $( this.settings.errorLabelContainer );\n                this.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm );\n                this.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer );\n                this.submitted = {};\n                this.valueCache = {};\n                this.pendingRequest = 0;\n                this.pending = {};\n                this.invalid = {};\n                this.reset();\n\n                var currentForm = this.currentForm,\n                    groups = ( this.groups = {} ),\n                    rules;\n                $.each( this.settings.groups, function( key, value ) {\n                    if ( typeof value === \"string\" ) {\n                        value = value.split( /\\s/ );\n                    }\n                    $.each( value, function( index, name ) {\n                        groups[ name ] = key;\n                    } );\n                } );\n                rules = this.settings.rules;\n                $.each( rules, function( key, value ) {\n                    rules[ key ] = $.validator.normalizeRule( value );\n                } );\n\n                function delegate( event ) {\n                    var isContentEditable = typeof $( this ).attr( \"contenteditable\" ) !== \"undefined\" && $( this ).attr( \"contenteditable\" ) !== \"false\";\n\n                    // Set form expando on contenteditable\n                    if ( !this.form && isContentEditable ) {\n                        this.form = $( this ).closest( \"form\" )[ 0 ];\n                        this.name = $( this ).attr( \"name\" );\n                    }\n\n                    // Ignore the element if it belongs to another form. This will happen mainly\n                    // when setting the `form` attribute of an input to the id of another form.\n                    if ( currentForm !== this.form ) {\n                        return;\n                    }\n\n                    var validator = $.data( this.form, \"validator\" ),\n                        eventType = \"on\" + event.type.replace( /^validate/, \"\" ),\n                        settings = validator.settings;\n                    if ( settings[ eventType ] && !$( this ).is( settings.ignore ) ) {\n                        settings[ eventType ].call( validator, this, event );\n                    }\n                }\n\n                $( this.currentForm )\n                    .on( \"focusin.validate focusout.validate keyup.validate\",\n                        \":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], \" +\n                        \"[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], \" +\n                        \"[type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], \" +\n                        \"[type='radio'], [type='checkbox'], [contenteditable], [type='button']\", delegate )\n\n                    // Support: Chrome, oldIE\n                    // \"select\" is provided as event.target when clicking a option\n                    .on( \"click.validate\", \"select, option, [type='radio'], [type='checkbox']\", delegate );\n\n                if ( this.settings.invalidHandler ) {\n                    $( this.currentForm ).on( \"invalid-form.validate\", this.settings.invalidHandler );\n                }\n            },\n\n            // https://jqueryvalidation.org/Validator.form/\n            form: function() {\n                this.checkForm();\n                $.extend( this.submitted, this.errorMap );\n                this.invalid = $.extend( {}, this.errorMap );\n                if ( !this.valid() ) {\n                    $( this.currentForm ).triggerHandler( \"invalid-form\", [ this ] );\n                }\n                this.showErrors();\n                return this.valid();\n            },\n\n            checkForm: function() {\n                this.prepareForm();\n                for ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) {\n                    this.check( elements[ i ] );\n                }\n                return this.valid();\n            },\n\n            // https://jqueryvalidation.org/Validator.element/\n            element: function( element ) {\n                var cleanElement = this.clean( element ),\n                    checkElement = this.validationTargetFor( cleanElement ),\n                    v = this,\n                    result = true,\n                    rs, group;\n\n                if ( checkElement === undefined ) {\n                    delete this.invalid[ cleanElement.name ];\n                } else {\n                    this.prepareElement( checkElement );\n                    this.currentElements = $( checkElement );\n\n                    // If this element is grouped, then validate all group elements already\n                    // containing a value\n                    group = this.groups[ checkElement.name ];\n                    if ( group ) {\n                        $.each( this.groups, function( name, testgroup ) {\n                            if ( testgroup === group && name !== checkElement.name ) {\n                                cleanElement = v.validationTargetFor( v.clean( v.findByName( name ) ) );\n                                if ( cleanElement && cleanElement.name in v.invalid ) {\n                                    v.currentElements.push( cleanElement );\n                                    result = v.check( cleanElement ) && result;\n                                }\n                            }\n                        } );\n                    }\n\n                    rs = this.check( checkElement ) !== false;\n                    result = result && rs;\n                    if ( rs ) {\n                        this.invalid[ checkElement.name ] = false;\n                    } else {\n                        this.invalid[ checkElement.name ] = true;\n                    }\n\n                    if ( !this.numberOfInvalids() ) {\n\n                        // Hide error containers on last error\n                        this.toHide = this.toHide.add( this.containers );\n                    }\n                    this.showErrors();\n\n                    // Add aria-invalid status for screen readers\n                    $( element ).attr( \"aria-invalid\", !rs );\n                }\n\n                return result;\n            },\n\n            // https://jqueryvalidation.org/Validator.showErrors/\n            showErrors: function( errors ) {\n                if ( errors ) {\n                    var validator = this;\n\n                    // Add items to error list and map\n                    $.extend( this.errorMap, errors );\n                    this.errorList = $.map( this.errorMap, function( message, name ) {\n                        return {\n                            message: message,\n                            element: validator.findByName( name )[ 0 ]\n                        };\n                    } );\n\n                    // Remove items from success list\n                    this.successList = $.grep( this.successList, function( element ) {\n                        return !( element.name in errors );\n                    } );\n                }\n                if ( this.settings.showErrors ) {\n                    this.settings.showErrors.call( this, this.errorMap, this.errorList );\n                } else {\n                    this.defaultShowErrors();\n                }\n            },\n\n            // https://jqueryvalidation.org/Validator.resetForm/\n            resetForm: function() {\n                if ( $.fn.resetForm ) {\n                    $( this.currentForm ).resetForm();\n                }\n                this.invalid = {};\n                this.submitted = {};\n                this.prepareForm();\n                this.hideErrors();\n                var elements = this.elements()\n                    .removeData( \"previousValue\" )\n                    .removeAttr( \"aria-invalid\" );\n\n                this.resetElements( elements );\n            },\n\n            resetElements: function( elements ) {\n                var i;\n\n                if ( this.settings.unhighlight ) {\n                    for ( i = 0; elements[ i ]; i++ ) {\n                        this.settings.unhighlight.call( this, elements[ i ],\n                            this.settings.errorClass, \"\" );\n                        this.findByName( elements[ i ].name ).removeClass( this.settings.validClass );\n                    }\n                } else {\n                    elements\n                        .removeClass( this.settings.errorClass )\n                        .removeClass( this.settings.validClass );\n                }\n            },\n\n            numberOfInvalids: function() {\n                return this.objectLength( this.invalid );\n            },\n\n            objectLength: function( obj ) {\n                /* jshint unused: false */\n                var count = 0,\n                    i;\n                for ( i in obj ) {\n\n                    // This check allows counting elements with empty error\n                    // message as invalid elements\n                    if ( obj[ i ] !== undefined && obj[ i ] !== null && obj[ i ] !== false ) {\n                        count++;\n                    }\n                }\n                return count;\n            },\n\n            hideErrors: function() {\n                this.hideThese( this.toHide );\n            },\n\n            hideThese: function( errors ) {\n                errors.not( this.containers ).text( \"\" );\n                this.addWrapper( errors ).hide();\n            },\n\n            valid: function() {\n                return this.size() === 0;\n            },\n\n            size: function() {\n                return this.errorList.length;\n            },\n\n            focusInvalid: function() {\n                if ( this.settings.focusInvalid ) {\n                    try {\n                        $( this.findLastActive() || this.errorList.length && this.errorList[ 0 ].element || [] )\n                            .filter( \":visible\" )\n                            .trigger( \"focus\" )\n\n                            // Manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find\n                            .trigger( \"focusin\" );\n                    } catch ( e ) {\n\n                        // Ignore IE throwing errors when focusing hidden elements\n                    }\n                }\n            },\n\n            findLastActive: function() {\n                var lastActive = this.lastActive;\n                return lastActive && $.grep( this.errorList, function( n ) {\n                    return n.element.name === lastActive.name;\n                } ).length === 1 && lastActive;\n            },\n\n            elements: function() {\n                var validator = this,\n                    rulesCache = {};\n\n                // Select all valid inputs inside the form (no submit or reset buttons)\n                return $( this.currentForm )\n                    .find( \"input, select, textarea, [contenteditable]\" )\n                    .not( \":submit, :reset, :image, :disabled\" )\n                    .not( this.settings.ignore )\n                    .filter( function() {\n                        var name = this.name || $( this ).attr( \"name\" ); // For contenteditable\n                        var isContentEditable = typeof $( this ).attr( \"contenteditable\" ) !== \"undefined\" && $( this ).attr( \"contenteditable\" ) !== \"false\";\n\n                        if ( !name && validator.settings.debug && window.console ) {\n                            console.error( \"%o has no name assigned\", this );\n                        }\n\n                        // Set form expando on contenteditable\n                        if ( isContentEditable ) {\n                            this.form = $( this ).closest( \"form\" )[ 0 ];\n                            this.name = name;\n                        }\n\n                        // Ignore elements that belong to other/nested forms\n                        if ( this.form !== validator.currentForm ) {\n                            return false;\n                        }\n\n                        // Select only the first element for each name, and only those with rules specified\n                        if ( name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {\n                            return false;\n                        }\n\n                        rulesCache[ name ] = true;\n                        return true;\n                    } );\n            },\n\n            clean: function( selector ) {\n                return $( selector )[ 0 ];\n            },\n\n            errors: function() {\n                var errorClass = this.settings.errorClass.split( \" \" ).join( \".\" );\n                return $( this.settings.errorElement + \".\" + errorClass, this.errorContext );\n            },\n\n            resetInternals: function() {\n                this.successList = [];\n                this.errorList = [];\n                this.errorMap = {};\n                this.toShow = $( [] );\n                this.toHide = $( [] );\n            },\n\n            reset: function() {\n                this.resetInternals();\n                this.currentElements = $( [] );\n            },\n\n            prepareForm: function() {\n                this.reset();\n                this.toHide = this.errors().add( this.containers );\n            },\n\n            prepareElement: function( element ) {\n                this.reset();\n                this.toHide = this.errorsFor( element );\n            },\n\n            elementValue: function( element ) {\n                var $element = $( element ),\n                    type = element.type,\n                    isContentEditable = typeof $element.attr( \"contenteditable\" ) !== \"undefined\" && $element.attr( \"contenteditable\" ) !== \"false\",\n                    val, idx;\n\n                if ( type === \"radio\" || type === \"checkbox\" ) {\n                    return this.findByName( element.name ).filter( \":checked\" ).val();\n                } else if ( type === \"number\" && typeof element.validity !== \"undefined\" ) {\n                    return element.validity.badInput ? \"NaN\" : $element.val();\n                }\n\n                if ( isContentEditable ) {\n                    val = $element.text();\n                } else {\n                    val = $element.val();\n                }\n\n                if ( type === \"file\" ) {\n\n                    // Modern browser (chrome & safari)\n                    if ( val.substr( 0, 12 ) === \"C:\\\\fakepath\\\\\" ) {\n                        return val.substr( 12 );\n                    }\n\n                    // Legacy browsers\n                    // Unix-based path\n                    idx = val.lastIndexOf( \"/\" );\n                    if ( idx >= 0 ) {\n                        return val.substr( idx + 1 );\n                    }\n\n                    // Windows-based path\n                    idx = val.lastIndexOf( \"\\\\\" );\n                    if ( idx >= 0 ) {\n                        return val.substr( idx + 1 );\n                    }\n\n                    // Just the file name\n                    return val;\n                }\n\n                if ( typeof val === \"string\" ) {\n                    return val.replace( /\\r/g, \"\" );\n                }\n                return val;\n            },\n\n            check: function( element ) {\n                element = this.validationTargetFor( this.clean( element ) );\n\n                var rules = $( element ).rules(),\n                    rulesCount = $.map( rules, function( n, i ) {\n                        return i;\n                    } ).length,\n                    dependencyMismatch = false,\n                    val = this.elementValue( element ),\n                    result, method, rule, normalizer;\n\n                // Prioritize the local normalizer defined for this element over the global one\n                // if the former exists, otherwise user the global one in case it exists.\n                if ( typeof rules.normalizer === \"function\" ) {\n                    normalizer = rules.normalizer;\n                } else if (\ttypeof this.settings.normalizer === \"function\" ) {\n                    normalizer = this.settings.normalizer;\n                }\n\n                // If normalizer is defined, then call it to the changed value instead\n                // of using the real one.\n                // Note that `this` in the normalizer is `element`.\n                if ( normalizer ) {\n                    val = normalizer.call( element, val );\n\n                    // Delete the normalizer from rules to avoid treating it as a pre-defined method.\n                    delete rules.normalizer;\n                }\n\n                for ( method in rules ) {\n                    rule = { method: method, parameters: rules[ method ] };\n                    try {\n                        result = $.validator.methods[ method ].call( this, val, element, rule.parameters );\n\n                        // If a method indicates that the field is optional and therefore valid,\n                        // don't mark it as valid when there are no other rules\n                        if ( result === \"dependency-mismatch\" && rulesCount === 1 ) {\n                            dependencyMismatch = true;\n                            continue;\n                        }\n                        dependencyMismatch = false;\n\n                        if ( result === \"pending\" ) {\n                            this.toHide = this.toHide.not( this.errorsFor( element ) );\n                            return;\n                        }\n\n                        if ( !result ) {\n                            this.formatAndAdd( element, rule );\n                            return false;\n                        }\n                    } catch ( e ) {\n                        if ( this.settings.debug && window.console ) {\n                            console.log( \"Exception occurred when checking element \" + element.id + \", check the '\" + rule.method + \"' method.\", e );\n                        }\n                        if ( e instanceof TypeError ) {\n                            e.message += \".  Exception occurred when checking element \" + element.id + \", check the '\" + rule.method + \"' method.\";\n                        }\n\n                        throw e;\n                    }\n                }\n                if ( dependencyMismatch ) {\n                    return;\n                }\n                if ( this.objectLength( rules ) ) {\n                    this.successList.push( element );\n                }\n                return true;\n            },\n\n            // Return the custom message for the given element and validation method\n            // specified in the element's HTML5 data attribute\n            // return the generic message if present and no method specific message is present\n            customDataMessage: function( element, method ) {\n                return $( element ).data( \"msg\" + method.charAt( 0 ).toUpperCase() +\n                    method.substring( 1 ).toLowerCase() ) || $( element ).data( \"msg\" );\n            },\n\n            // Return the custom message for the given element name and validation method\n            customMessage: function( name, method ) {\n                var m = this.settings.messages[ name ];\n                return m && ( m.constructor === String ? m : m[ method ] );\n            },\n\n            // Return the first defined argument, allowing empty strings\n            findDefined: function() {\n                for ( var i = 0; i < arguments.length; i++ ) {\n                    if ( arguments[ i ] !== undefined ) {\n                        return arguments[ i ];\n                    }\n                }\n                return undefined;\n            },\n\n            // The second parameter 'rule' used to be a string, and extended to an object literal\n            // of the following form:\n            // rule = {\n            //     method: \"method name\",\n            //     parameters: \"the given method parameters\"\n            // }\n            //\n            // The old behavior still supported, kept to maintain backward compatibility with\n            // old code, and will be removed in the next major release.\n            defaultMessage: function( element, rule ) {\n                if ( typeof rule === \"string\" ) {\n                    rule = { method: rule };\n                }\n\n                var message = this.findDefined(\n                        this.customMessage( element.name, rule.method ),\n                        this.customDataMessage( element, rule.method ),\n\n                        // 'title' is never undefined, so handle empty string as undefined\n                        !this.settings.ignoreTitle && element.title || undefined,\n                        $.validator.messages[ rule.method ],\n                        \"<strong>Warning: No message defined for \" + element.name + \"</strong>\"\n                    ),\n                    theregex = /\\$?\\{(\\d+)\\}/g;\n                if ( typeof message === \"function\" ) {\n                    message = message.call( this, rule.parameters, element );\n                } else if ( theregex.test( message ) ) {\n                    message = $.validator.format( message.replace( theregex, \"{$1}\" ), rule.parameters );\n                }\n\n                return message;\n            },\n\n            formatAndAdd: function( element, rule ) {\n                var message = this.defaultMessage( element, rule );\n\n                this.errorList.push( {\n                    message: message,\n                    element: element,\n                    method: rule.method\n                } );\n\n                this.errorMap[ element.name ] = message;\n                this.submitted[ element.name ] = message;\n            },\n\n            addWrapper: function( toToggle ) {\n                if ( this.settings.wrapper ) {\n                    toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );\n                }\n                return toToggle;\n            },\n\n            defaultShowErrors: function() {\n                var i, elements, error;\n                for ( i = 0; this.errorList[ i ]; i++ ) {\n                    error = this.errorList[ i ];\n                    if ( this.settings.highlight ) {\n                        this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );\n                    }\n                    this.showLabel( error.element, error.message );\n                }\n                if ( this.errorList.length ) {\n                    this.toShow = this.toShow.add( this.containers );\n                }\n                if ( this.settings.success ) {\n                    for ( i = 0; this.successList[ i ]; i++ ) {\n                        this.showLabel( this.successList[ i ] );\n                    }\n                }\n                if ( this.settings.unhighlight ) {\n                    for ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) {\n                        this.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass );\n                    }\n                }\n                this.toHide = this.toHide.not( this.toShow );\n                this.hideErrors();\n                this.addWrapper( this.toShow ).show();\n            },\n\n            validElements: function() {\n                return this.currentElements.not( this.invalidElements() );\n            },\n\n            invalidElements: function() {\n                return $( this.errorList ).map( function() {\n                    return this.element;\n                } );\n            },\n\n            showLabel: function( element, message ) {\n                var place, group, errorID, v,\n                    error = this.errorsFor( element ),\n                    elementID = this.idOrName( element ),\n                    describedBy = $( element ).attr( \"aria-describedby\" );\n\n                if ( error.length ) {\n\n                    // Refresh error/success class\n                    error.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );\n\n                    // Replace message on existing label\n                    error.html( message );\n                } else {\n\n                    // Create error element\n                    error = $( \"<\" + this.settings.errorElement + \">\" )\n                        .attr( \"id\", elementID + \"-error\" )\n                        .addClass( this.settings.errorClass )\n                        .html( message || \"\" );\n\n                    // Maintain reference to the element to be placed into the DOM\n                    place = error;\n                    if ( this.settings.wrapper ) {\n\n                        // Make sure the element is visible, even in IE\n                        // actually showing the wrapped element is handled elsewhere\n                        place = error.hide().show().wrap( \"<\" + this.settings.wrapper + \"/>\" ).parent();\n                    }\n                    if ( this.labelContainer.length ) {\n                        this.labelContainer.append( place );\n                    } else if ( this.settings.errorPlacement ) {\n                        this.settings.errorPlacement.call( this, place, $( element ) );\n                    } else {\n                        place.insertAfter( element );\n                    }\n\n                    // Link error back to the element\n                    if ( error.is( \"label\" ) ) {\n\n                        // If the error is a label, then associate using 'for'\n                        error.attr( \"for\", elementID );\n\n                        // If the element is not a child of an associated label, then it's necessary\n                        // to explicitly apply aria-describedby\n                    } else if ( error.parents( \"label[for='\" + this.escapeCssMeta( elementID ) + \"']\" ).length === 0 ) {\n                        errorID = error.attr( \"id\" );\n\n                        // Respect existing non-error aria-describedby\n                        if ( !describedBy ) {\n                            describedBy = errorID;\n                        } else if ( !describedBy.match( new RegExp( \"\\\\b\" + this.escapeCssMeta( errorID ) + \"\\\\b\" ) ) ) {\n\n                            // Add to end of list if not already present\n                            describedBy += \" \" + errorID;\n                        }\n                        $( element ).attr( \"aria-describedby\", describedBy );\n\n                        // If this element is grouped, then assign to all elements in the same group\n                        group = this.groups[ element.name ];\n                        if ( group ) {\n                            v = this;\n                            $.each( v.groups, function( name, testgroup ) {\n                                if ( testgroup === group ) {\n                                    $( \"[name='\" + v.escapeCssMeta( name ) + \"']\", v.currentForm )\n                                        .attr( \"aria-describedby\", error.attr( \"id\" ) );\n                                }\n                            } );\n                        }\n                    }\n                }\n                if ( !message && this.settings.success ) {\n                    error.text( \"\" );\n                    if ( typeof this.settings.success === \"string\" ) {\n                        error.addClass( this.settings.success );\n                    } else {\n                        this.settings.success( error, element );\n                    }\n                }\n                this.toShow = this.toShow.add( error );\n            },\n\n            errorsFor: function( element ) {\n                var name = this.escapeCssMeta( this.idOrName( element ) ),\n                    describer = $( element ).attr( \"aria-describedby\" ),\n                    selector = \"label[for='\" + name + \"'], label[for='\" + name + \"'] *\";\n\n                // 'aria-describedby' should directly reference the error element\n                if ( describer ) {\n                    selector = selector + \", #\" + this.escapeCssMeta( describer )\n                        .replace( /\\s+/g, \", #\" ) + \":visible\";\n                }\n\n                return this\n                    .errors()\n                    .filter( selector );\n            },\n\n            // See https://api.jquery.com/category/selectors/, for CSS\n            // meta-characters that should be escaped in order to be used with JQuery\n            // as a literal part of a name/id or any selector.\n            escapeCssMeta: function( string ) {\n                if ( string === undefined ) {\n                    return \"\";\n                }\n\n                return string.replace( /([\\\\!\"#$%&'()*+,./:;<=>?@\\[\\]^`{|}~])/g, \"\\\\$1\" );\n            },\n\n            idOrName: function( element ) {\n                return this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.id || element.name );\n            },\n\n            validationTargetFor: function( element ) {\n\n                // If radio/checkbox, validate first element in group instead\n                if ( this.checkable( element ) ) {\n                    element = this.findByName( element.name );\n                }\n\n                // Always apply ignore filter\n                return $( element ).not( this.settings.ignore )[ 0 ];\n            },\n\n            checkable: function( element ) {\n                return ( /radio|checkbox/i ).test( element.type );\n            },\n\n            findByName: function( name ) {\n                return $( this.currentForm ).find( \"[name='\" + this.escapeCssMeta( name ) + \"']\" );\n            },\n\n            getLength: function( value, element ) {\n                switch ( element.nodeName.toLowerCase() ) {\n                    case \"select\":\n                        return $( \"option:selected\", element ).length;\n                    case \"input\":\n                        if ( this.checkable( element ) ) {\n                            return this.findByName( element.name ).filter( \":checked\" ).length;\n                        }\n                }\n                return value.length;\n            },\n\n            depend: function( param, element ) {\n                return this.dependTypes[ typeof param ] ? this.dependTypes[ typeof param ]( param, element ) : true;\n            },\n\n            dependTypes: {\n                \"boolean\": function( param ) {\n                    return param;\n                },\n                \"string\": function( param, element ) {\n                    return !!$( param, element.form ).length;\n                },\n                \"function\": function( param, element ) {\n                    return param( element );\n                }\n            },\n\n            optional: function( element ) {\n                var val = this.elementValue( element );\n                return !$.validator.methods.required.call( this, val, element ) && \"dependency-mismatch\";\n            },\n\n            startRequest: function( element ) {\n                if ( !this.pending[ element.name ] ) {\n                    this.pendingRequest++;\n                    $( element ).addClass( this.settings.pendingClass );\n                    this.pending[ element.name ] = true;\n                }\n            },\n\n            stopRequest: function( element, valid ) {\n                this.pendingRequest--;\n\n                // Sometimes synchronization fails, make sure pendingRequest is never < 0\n                if ( this.pendingRequest < 0 ) {\n                    this.pendingRequest = 0;\n                }\n                delete this.pending[ element.name ];\n                $( element ).removeClass( this.settings.pendingClass );\n                if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() && this.pendingRequest === 0 ) {\n                    $( this.currentForm ).trigger( \"submit\" );\n\n                    // Remove the hidden input that was used as a replacement for the\n                    // missing submit button. The hidden input is added by `handle()`\n                    // to ensure that the value of the used submit button is passed on\n                    // for scripted submits triggered by this method\n                    if ( this.submitButton ) {\n                        $( \"input:hidden[name='\" + this.submitButton.name + \"']\", this.currentForm ).remove();\n                    }\n\n                    this.formSubmitted = false;\n                } else if ( !valid && this.pendingRequest === 0 && this.formSubmitted ) {\n                    $( this.currentForm ).triggerHandler( \"invalid-form\", [ this ] );\n                    this.formSubmitted = false;\n                }\n            },\n\n            previousValue: function( element, method ) {\n                method = typeof method === \"string\" && method || \"remote\";\n\n                return $.data( element, \"previousValue\" ) || $.data( element, \"previousValue\", {\n                    old: null,\n                    valid: true,\n                    message: this.defaultMessage( element, { method: method } )\n                } );\n            },\n\n            // Cleans up all forms and elements, removes validator-specific events\n            destroy: function() {\n                this.resetForm();\n\n                $( this.currentForm )\n                    .off( \".validate\" )\n                    .removeData( \"validator\" )\n                    .find( \".validate-equalTo-blur\" )\n                    .off( \".validate-equalTo\" )\n                    .removeClass( \"validate-equalTo-blur\" )\n                    .find( \".validate-lessThan-blur\" )\n                    .off( \".validate-lessThan\" )\n                    .removeClass( \"validate-lessThan-blur\" )\n                    .find( \".validate-lessThanEqual-blur\" )\n                    .off( \".validate-lessThanEqual\" )\n                    .removeClass( \"validate-lessThanEqual-blur\" )\n                    .find( \".validate-greaterThanEqual-blur\" )\n                    .off( \".validate-greaterThanEqual\" )\n                    .removeClass( \"validate-greaterThanEqual-blur\" )\n                    .find( \".validate-greaterThan-blur\" )\n                    .off( \".validate-greaterThan\" )\n                    .removeClass( \"validate-greaterThan-blur\" );\n            }\n\n        },\n\n        classRuleSettings: {\n            required: { required: true },\n            email: { email: true },\n            url: { url: true },\n            date: { date: true },\n            dateISO: { dateISO: true },\n            number: { number: true },\n            digits: { digits: true },\n            creditcard: { creditcard: true }\n        },\n\n        addClassRules: function( className, rules ) {\n            if ( className.constructor === String ) {\n                this.classRuleSettings[ className ] = rules;\n            } else {\n                $.extend( this.classRuleSettings, className );\n            }\n        },\n\n        classRules: function( element ) {\n            var rules = {},\n                classes = $( element ).attr( \"class\" );\n\n            if ( classes ) {\n                $.each( classes.split( \" \" ), function() {\n                    if ( this in $.validator.classRuleSettings ) {\n                        $.extend( rules, $.validator.classRuleSettings[ this ] );\n                    }\n                } );\n            }\n            return rules;\n        },\n\n        normalizeAttributeRule: function( rules, type, method, value ) {\n\n            // Convert the value to a number for number inputs, and for text for backwards compability\n            // allows type=\"date\" and others to be compared as strings\n            if ( /min|max|step/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {\n                value = Number( value );\n\n                // Support Opera Mini, which returns NaN for undefined minlength\n                if ( isNaN( value ) ) {\n                    value = undefined;\n                }\n            }\n\n            if ( value || value === 0 ) {\n                rules[ method ] = value;\n            } else if ( type === method && type !== \"range\" ) {\n\n                // Exception: the jquery validate 'range' method\n                // does not test for the html5 'range' type\n                rules[ type === \"date\" ? \"dateISO\" : method ] = true;\n            }\n        },\n\n        attributeRules: function( element ) {\n            var rules = {},\n                $element = $( element ),\n                type = element.getAttribute( \"type\" ),\n                method, value;\n\n            for ( method in $.validator.methods ) {\n\n                // Support for <input required> in both html5 and older browsers\n                if ( method === \"required\" ) {\n                    value = element.getAttribute( method );\n\n                    // Some browsers return an empty string for the required attribute\n                    // and non-HTML5 browsers might have required=\"\" markup\n                    if ( value === \"\" ) {\n                        value = true;\n                    }\n\n                    // Force non-HTML5 browsers to return bool\n                    value = !!value;\n                } else {\n                    value = $element.attr( method );\n                }\n\n                this.normalizeAttributeRule( rules, type, method, value );\n            }\n\n            // 'maxlength' may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs\n            if ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) {\n                delete rules.maxlength;\n            }\n\n            return rules;\n        },\n\n        metadataRules: function (element) {\n            if (!$.metadata) {\n                return {};\n            }\n\n            var meta = $.data(element.form, 'validator').settings.meta;\n            return meta ?\n                $(element).metadata()[meta] :\n                $(element).metadata();\n        },\n\n        dataRules: function( element ) {\n            var rules = {},\n                $element = $( element ),\n                type = element.getAttribute( \"type\" ),\n                method, value;\n\n            for ( method in $.validator.methods ) {\n                value = $element.data( \"rule\" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() );\n\n                // Cast empty attributes like `data-rule-required` to `true`\n                if ( value === \"\" ) {\n                    value = true;\n                }\n\n                this.normalizeAttributeRule( rules, type, method, value );\n            }\n            return rules;\n        },\n\n        staticRules: function( element ) {\n            var rules = {},\n                validator = $.data( element.form, \"validator\" );\n\n            if ( validator.settings.rules ) {\n                rules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {};\n            }\n            return rules;\n        },\n\n        normalizeRules: function( rules, element ) {\n\n            // Handle dependency check\n            $.each( rules, function( prop, val ) {\n\n                // Ignore rule when param is explicitly false, eg. required:false\n                if ( val === false ) {\n                    delete rules[ prop ];\n                    return;\n                }\n                if ( val.param || val.depends ) {\n                    var keepRule = true;\n                    switch ( typeof val.depends ) {\n                        case \"string\":\n                            keepRule = !!$( val.depends, element.form ).length;\n                            break;\n                        case \"function\":\n                            keepRule = val.depends.call( element, element );\n                            break;\n                    }\n                    if ( keepRule ) {\n                        rules[ prop ] = val.param !== undefined ? val.param : true;\n                    } else {\n                        $.data( element.form, \"validator\" ).resetElements( $( element ) );\n                        delete rules[ prop ];\n                    }\n                }\n            } );\n\n            // Evaluate parameters\n            $.each( rules, function( rule, parameter ) {\n                rules[ rule ] = typeof parameter === \"function\" && rule !== \"normalizer\" ? parameter( element ) : parameter;\n            } );\n\n            // Clean number parameters\n            $.each( [ \"minlength\", \"maxlength\" ], function() {\n                if ( rules[ this ] ) {\n                    rules[ this ] = Number( rules[ this ] );\n                }\n            } );\n            $.each( [ \"rangelength\", \"range\" ], function() {\n                var parts;\n                if ( rules[ this ] ) {\n                    if ( Array.isArray( rules[ this ] ) ) {\n                        rules[ this ] = [ Number( rules[ this ][ 0 ] ), Number( rules[ this ][ 1 ] ) ];\n                    } else if ( typeof rules[ this ] === \"string\" ) {\n                        parts = rules[ this ].replace( /[\\[\\]]/g, \"\" ).split( /[\\s,]+/ );\n                        rules[ this ] = [ Number( parts[ 0 ] ), Number( parts[ 1 ] ) ];\n                    }\n                }\n            } );\n\n            if ( $.validator.autoCreateRanges ) {\n\n                // Auto-create ranges\n                if ( rules.min != null && rules.max != null ) {\n                    rules.range = [ rules.min, rules.max ];\n                    delete rules.min;\n                    delete rules.max;\n                }\n                if ( rules.minlength != null && rules.maxlength != null ) {\n                    rules.rangelength = [ rules.minlength, rules.maxlength ];\n                    delete rules.minlength;\n                    delete rules.maxlength;\n                }\n            }\n\n            return rules;\n        },\n\n        // Converts a simple string to a {string: true} rule, e.g., \"required\" to {required:true}\n        normalizeRule: function( data ) {\n            if ( typeof data === \"string\" ) {\n                var transformed = {};\n                $.each( data.split( /\\s/ ), function() {\n                    transformed[ this ] = true;\n                } );\n                data = transformed;\n            }\n            return data;\n        },\n\n        // https://jqueryvalidation.org/jQuery.validator.addMethod/\n        addMethod: function( name, method, message ) {\n            $.validator.methods[ name ] = method;\n            $.validator.messages[ name ] = message !== undefined ? message : $.validator.messages[ name ];\n            if ( method.length < 3 ) {\n                $.validator.addClassRules( name, $.validator.normalizeRule( name ) );\n            }\n        },\n\n        // https://jqueryvalidation.org/jQuery.validator.methods/\n        methods: {\n\n            // https://jqueryvalidation.org/required-method/\n            required: function( value, element, param ) {\n\n                // Check if dependency is met\n                if ( !this.depend( param, element ) ) {\n                    return \"dependency-mismatch\";\n                }\n                if ( element.nodeName.toLowerCase() === \"select\" ) {\n\n                    // Could be an array for select-multiple or a string, both are fine this way\n                    var val = $( element ).val();\n                    return val && val.length > 0;\n                }\n                if ( this.checkable( element ) ) {\n                    return this.getLength( value, element ) > 0;\n                }\n                return value !== undefined && value !== null && value.length > 0;\n            },\n\n            // https://jqueryvalidation.org/email-method/\n            email: function( value, element ) {\n\n                // From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address\n                // Retrieved 2014-01-14\n                // If you have a problem with this implementation, report a bug against the above spec\n                // Or use custom methods to implement your own email validation\n                return this.optional( element ) || /^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test( value );\n            },\n\n            // https://jqueryvalidation.org/url-method/\n            url: function( value, element ) {\n\n                // Copyright (c) 2010-2013 Diego Perini, MIT licensed\n                // https://gist.github.com/dperini/729294\n                // see also https://mathiasbynens.be/demo/url-regex\n                // modified to allow protocol-relative URLs\n                return this.optional( element ) || /^(?:(?:(?:https?|ftp):)?\\/\\/)(?:(?:[^\\]\\[?\\/<~#`!@$^&*()+=}|:\";',>{ ]|%[0-9A-Fa-f]{2})+(?::(?:[^\\]\\[?\\/<~#`!@$^&*()+=}|:\";',>{ ]|%[0-9A-Fa-f]{2})*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z0-9\\u00a1-\\uffff][a-z0-9\\u00a1-\\uffff_-]{0,62})?[a-z0-9\\u00a1-\\uffff]\\.)+(?:[a-z\\u00a1-\\uffff]{2,}\\.?))(?::\\d{2,5})?(?:[/?#]\\S*)?$/i.test( value );\n            },\n\n            // https://jqueryvalidation.org/date-method/\n            date: ( function() {\n                var called = false;\n\n                return function( value, element ) {\n                    if ( !called ) {\n                        called = true;\n                        if ( this.settings.debug && window.console ) {\n                            console.warn(\n                                \"The `date` method is deprecated and will be removed in version '2.0.0'.\\n\" +\n                                \"Please don't use it, since it relies on the Date constructor, which\\n\" +\n                                \"behaves very differently across browsers and locales. Use `dateISO`\\n\" +\n                                \"instead or one of the locale specific methods in `localizations/`\\n\" +\n                                \"and `additional-methods.js`.\"\n                            );\n                        }\n                    }\n\n                    return this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() );\n                };\n            }() ),\n\n            // https://jqueryvalidation.org/dateISO-method/\n            dateISO: function( value, element ) {\n                return this.optional( element ) || /^\\d{4}[\\/\\-](0?[1-9]|1[012])[\\/\\-](0?[1-9]|[12][0-9]|3[01])$/.test( value );\n            },\n\n            // https://jqueryvalidation.org/number-method/\n            number: function( value, element ) {\n                return this.optional( element ) || /^(?:-?\\d+|-?\\d{1,3}(?:,\\d{3})+)?(?:\\.\\d+)?$/.test( value );\n            },\n\n            // https://jqueryvalidation.org/digits-method/\n            digits: function( value, element ) {\n                return this.optional( element ) || /^\\d+$/.test( value );\n            },\n\n            // https://jqueryvalidation.org/minlength-method/\n            minlength: function( value, element, param ) {\n                var length = Array.isArray( value ) ? value.length : this.getLength( value, element );\n                return this.optional( element ) || length >= param;\n            },\n\n            // https://jqueryvalidation.org/maxlength-method/\n            maxlength: function( value, element, param ) {\n                var length = Array.isArray( value ) ? value.length : this.getLength( value, element );\n                return this.optional( element ) || length <= param;\n            },\n\n            // https://jqueryvalidation.org/rangelength-method/\n            rangelength: function( value, element, param ) {\n                var length = Array.isArray( value ) ? value.length : this.getLength( value, element );\n                return this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] );\n            },\n\n            // https://jqueryvalidation.org/min-method/\n            min: function( value, element, param ) {\n                return this.optional( element ) || value >= param;\n            },\n\n            // https://jqueryvalidation.org/max-method/\n            max: function( value, element, param ) {\n                return this.optional( element ) || value <= param;\n            },\n\n            // https://jqueryvalidation.org/range-method/\n            range: function( value, element, param ) {\n                return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );\n            },\n\n            // https://jqueryvalidation.org/step-method/\n            step: function( value, element, param ) {\n                var type = $( element ).attr( \"type\" ),\n                    errorMessage = \"Step attribute on input type \" + type + \" is not supported.\",\n                    supportedTypes = [ \"text\", \"number\", \"range\" ],\n                    re = new RegExp( \"\\\\b\" + type + \"\\\\b\" ),\n                    notSupported = type && !re.test( supportedTypes.join() ),\n                    decimalPlaces = function( num ) {\n                        var match = ( \"\" + num ).match( /(?:\\.(\\d+))?$/ );\n                        if ( !match ) {\n                            return 0;\n                        }\n\n                        // Number of digits right of decimal point.\n                        return match[ 1 ] ? match[ 1 ].length : 0;\n                    },\n                    toInt = function( num ) {\n                        return Math.round( num * Math.pow( 10, decimals ) );\n                    },\n                    valid = true,\n                    decimals;\n\n                // Works only for text, number and range input types\n                // TODO find a way to support input types date, datetime, datetime-local, month, time and week\n                if ( notSupported ) {\n                    throw new Error( errorMessage );\n                }\n\n                decimals = decimalPlaces( param );\n\n                // Value can't have too many decimals\n                if ( decimalPlaces( value ) > decimals || toInt( value ) % toInt( param ) !== 0 ) {\n                    valid = false;\n                }\n\n                return this.optional( element ) || valid;\n            },\n\n            // https://jqueryvalidation.org/equalTo-method/\n            equalTo: function( value, element, param ) {\n\n                // Bind to the blur event of the target in order to revalidate whenever the target field is updated\n                var target = $( param );\n                if ( this.settings.onfocusout && target.not( \".validate-equalTo-blur\" ).length ) {\n                    target.addClass( \"validate-equalTo-blur\" ).on( \"blur.validate-equalTo\", function() {\n                        $( element ).valid();\n                    } );\n                }\n                return value === target.val();\n            },\n\n            // https://jqueryvalidation.org/remote-method/\n            remote: function( value, element, param, method ) {\n                if ( this.optional( element ) ) {\n                    return \"dependency-mismatch\";\n                }\n\n                method = typeof method === \"string\" && method || \"remote\";\n\n                var previous = this.previousValue( element, method ),\n                    validator, data, optionDataString;\n\n                if ( !this.settings.messages[ element.name ] ) {\n                    this.settings.messages[ element.name ] = {};\n                }\n                previous.originalMessage = previous.originalMessage || this.settings.messages[ element.name ][ method ];\n                this.settings.messages[ element.name ][ method ] = previous.message;\n\n                param = typeof param === \"string\" && { url: param } || param;\n                optionDataString = $.param( $.extend( { data: value }, param.data ) );\n                if ( previous.old === optionDataString ) {\n                    return previous.valid;\n                }\n\n                previous.old = optionDataString;\n                validator = this;\n                this.startRequest( element );\n                data = {};\n                data[ element.name ] = value;\n                $.ajax( $.extend( true, {\n                    mode: \"abort\",\n                    port: \"validate\" + element.name,\n                    dataType: \"json\",\n                    data: data,\n                    context: validator.currentForm,\n                    success: function( response ) {\n                        var valid = response === true || response === \"true\",\n                            errors, message, submitted;\n\n                        validator.settings.messages[ element.name ][ method ] = previous.originalMessage;\n                        if ( valid ) {\n                            submitted = validator.formSubmitted;\n                            validator.resetInternals();\n                            validator.toHide = validator.errorsFor( element );\n                            validator.formSubmitted = submitted;\n                            validator.successList.push( element );\n                            validator.invalid[ element.name ] = false;\n                            validator.showErrors();\n                        } else {\n                            errors = {};\n                            message = response || validator.defaultMessage( element, { method: method, parameters: value } );\n                            errors[ element.name ] = previous.message = message;\n                            validator.invalid[ element.name ] = true;\n                            validator.showErrors( errors );\n                        }\n                        previous.valid = valid;\n                        validator.stopRequest( element, valid );\n                    }\n                }, param ) );\n                return \"pending\";\n            }\n        }\n\n    } );\n\n// Ajax mode: abort\n// usage: $.ajax({ mode: \"abort\"[, port: \"uniqueport\"]});\n// if mode:\"abort\" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()\n\n    var pendingRequests = {},\n        ajax;\n\n// Use a prefilter if available (1.5+)\n    if ( $.ajaxPrefilter ) {\n        $.ajaxPrefilter( function( settings, _, xhr ) {\n            var port = settings.port;\n            if ( settings.mode === \"abort\" ) {\n                if ( pendingRequests[ port ] ) {\n                    pendingRequests[ port ].abort();\n                }\n                pendingRequests[ port ] = xhr;\n            }\n        } );\n    } else {\n\n        // Proxy ajax\n        ajax = $.ajax;\n        $.ajax = function( settings ) {\n            var mode = ( \"mode\" in settings ? settings : $.ajaxSettings ).mode,\n                port = ( \"port\" in settings ? settings : $.ajaxSettings ).port;\n            if ( mode === \"abort\" ) {\n                if ( pendingRequests[ port ] ) {\n                    pendingRequests[ port ].abort();\n                }\n                pendingRequests[ port ] = ajax.apply( this, arguments );\n                return pendingRequests[ port ];\n            }\n            return ajax.apply( this, arguments );\n        };\n    }\n    return $;\n}));\n","jquery/jquery-ui-timepicker-addon.js":"/*! jQuery Timepicker Addon - v1.6.3 - 2016-04-20\n* http://trentrichardson.com/examples/timepicker\n* Copyright (c) 2016 Trent Richardson; Licensed MIT */\n(function (factory) {\n    if (typeof define === 'function' && define.amd) {\n        define(['jquery', 'jquery/ui'], factory);\n    } else {\n        factory(jQuery);\n    }\n}(function ($) {\n\n    /*\n    * Lets not redefine timepicker, Prevent \"Uncaught RangeError: Maximum call stack size exceeded\"\n    */\n    $.ui.timepicker = $.ui.timepicker || {};\n    if ($.ui.timepicker.version) {\n        return;\n    }\n\n    /*\n    * Extend jQueryUI, get it started with our version number\n    */\n    $.extend($.ui, {\n        timepicker: {\n            version: \"1.6.3\"\n        }\n    });\n\n    /*\n    * Timepicker manager.\n    * Use the singleton instance of this class, $.timepicker, to interact with the time picker.\n    * Settings for (groups of) time pickers are maintained in an instance object,\n    * allowing multiple different settings on the same page.\n    */\n    var Timepicker = function () {\n        this.regional = []; // Available regional settings, indexed by language code\n        this.regional[''] = { // Default regional settings\n            currentText: 'Now',\n            closeText: 'Done',\n            amNames: ['AM', 'A'],\n            pmNames: ['PM', 'P'],\n            timeFormat: 'HH:mm',\n            timeSuffix: '',\n            timeOnlyTitle: 'Choose Time',\n            timeText: 'Time',\n            hourText: 'Hour',\n            minuteText: 'Minute',\n            secondText: 'Second',\n            millisecText: 'Millisecond',\n            microsecText: 'Microsecond',\n            timezoneText: 'Time Zone',\n            isRTL: false\n        };\n        this._defaults = { // Global defaults for all the datetime picker instances\n            showButtonPanel: true,\n            timeOnly: false,\n            timeOnlyShowDate: false,\n            showHour: null,\n            showMinute: null,\n            showSecond: null,\n            showMillisec: null,\n            showMicrosec: null,\n            showTimezone: null,\n            showTime: true,\n            stepHour: 1,\n            stepMinute: 1,\n            stepSecond: 1,\n            stepMillisec: 1,\n            stepMicrosec: 1,\n            hour: 0,\n            minute: 0,\n            second: 0,\n            millisec: 0,\n            microsec: 0,\n            timezone: null,\n            hourMin: 0,\n            minuteMin: 0,\n            secondMin: 0,\n            millisecMin: 0,\n            microsecMin: 0,\n            hourMax: 23,\n            minuteMax: 59,\n            secondMax: 59,\n            millisecMax: 999,\n            microsecMax: 999,\n            minDateTime: null,\n            maxDateTime: null,\n            maxTime: null,\n            minTime: null,\n            onSelect: null,\n            hourGrid: 0,\n            minuteGrid: 0,\n            secondGrid: 0,\n            millisecGrid: 0,\n            microsecGrid: 0,\n            alwaysSetTime: true,\n            separator: ' ',\n            altFieldTimeOnly: true,\n            altTimeFormat: null,\n            altSeparator: null,\n            altTimeSuffix: null,\n            altRedirectFocus: true,\n            pickerTimeFormat: null,\n            pickerTimeSuffix: null,\n            showTimepicker: true,\n            timezoneList: null,\n            addSliderAccess: false,\n            sliderAccessArgs: null,\n            controlType: 'slider',\n            oneLine: false,\n            defaultValue: null,\n            parse: 'strict',\n            afterInject: null\n        };\n        $.extend(this._defaults, this.regional['']);\n    };\n\n    $.extend(Timepicker.prototype, {\n        $input: null,\n        $altInput: null,\n        $timeObj: null,\n        inst: null,\n        hour_slider: null,\n        minute_slider: null,\n        second_slider: null,\n        millisec_slider: null,\n        microsec_slider: null,\n        timezone_select: null,\n        maxTime: null,\n        minTime: null,\n        hour: 0,\n        minute: 0,\n        second: 0,\n        millisec: 0,\n        microsec: 0,\n        timezone: null,\n        hourMinOriginal: null,\n        minuteMinOriginal: null,\n        secondMinOriginal: null,\n        millisecMinOriginal: null,\n        microsecMinOriginal: null,\n        hourMaxOriginal: null,\n        minuteMaxOriginal: null,\n        secondMaxOriginal: null,\n        millisecMaxOriginal: null,\n        microsecMaxOriginal: null,\n        ampm: '',\n        formattedDate: '',\n        formattedTime: '',\n        formattedDateTime: '',\n        timezoneList: null,\n        units: ['hour', 'minute', 'second', 'millisec', 'microsec'],\n        support: {},\n        control: null,\n\n        /*\n        * Override the default settings for all instances of the time picker.\n        * @param  {Object} settings  object - the new settings to use as defaults (anonymous object)\n        * @return {Object} the manager object\n        */\n        setDefaults: function (settings) {\n            extendRemove(this._defaults, settings || {});\n            return this;\n        },\n\n        /*\n        * Create a new Timepicker instance\n        */\n        _newInst: function ($input, opts) {\n            var tp_inst = new Timepicker(),\n                inlineSettings = {},\n                fns = {},\n                overrides, i;\n\n            for (var attrName in this._defaults) {\n                if (this._defaults.hasOwnProperty(attrName)) {\n                    var attrValue = $input.attr('time:' + attrName);\n                    if (attrValue) {\n                        try {\n                            inlineSettings[attrName] = eval(attrValue);\n                        } catch (err) {\n                            inlineSettings[attrName] = attrValue;\n                        }\n                    }\n                }\n            }\n\n            overrides = {\n                beforeShow: function (input, dp_inst) {\n                    if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) {\n                        return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst);\n                    }\n                },\n                onChangeMonthYear: function (year, month, dp_inst) {\n                    // Update the time as well : this prevents the time from disappearing from the $input field.\n                    // tp_inst._updateDateTime(dp_inst);\n                    if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) {\n                        tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);\n                    }\n                },\n                onClose: function (dateText, dp_inst) {\n                    if (tp_inst.timeDefined === true && $input.val() !== '') {\n                        tp_inst._updateDateTime(dp_inst);\n                    }\n                    if ($.isFunction(tp_inst._defaults.evnts.onClose)) {\n                        tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst);\n                    }\n                }\n            };\n            for (i in overrides) {\n                if (overrides.hasOwnProperty(i)) {\n                    fns[i] = opts[i] || this._defaults[i] || null;\n                }\n            }\n\n            tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, opts, overrides, {\n                evnts: fns,\n                timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');\n            });\n            tp_inst.amNames = $.map(tp_inst._defaults.amNames, function (val) {\n                return val.toUpperCase();\n            });\n            tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function (val) {\n                return val.toUpperCase();\n            });\n\n            // detect which units are supported\n            tp_inst.support = detectSupport(\n                tp_inst._defaults.timeFormat +\n                (tp_inst._defaults.pickerTimeFormat ? tp_inst._defaults.pickerTimeFormat : '') +\n                (tp_inst._defaults.altTimeFormat ? tp_inst._defaults.altTimeFormat : ''));\n\n            // controlType is string - key to our this._controls\n            if (typeof(tp_inst._defaults.controlType) === 'string') {\n                if (tp_inst._defaults.controlType === 'slider' && typeof($.ui.slider) === 'undefined') {\n                    tp_inst._defaults.controlType = 'select';\n                }\n                tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType];\n            }\n            // controlType is an object and must implement create, options, value methods\n            else {\n                tp_inst.control = tp_inst._defaults.controlType;\n            }\n\n            // prep the timezone options\n            var timezoneList = [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270, -240, -210, -180, -120, -60,\n                0, 60, 120, 180, 210, 240, 270, 300, 330, 345, 360, 390, 420, 480, 525, 540, 570, 600, 630, 660, 690, 720, 765, 780, 840];\n            if (tp_inst._defaults.timezoneList !== null) {\n                timezoneList = tp_inst._defaults.timezoneList;\n            }\n            var tzl = timezoneList.length, tzi = 0, tzv = null;\n            if (tzl > 0 && typeof timezoneList[0] !== 'object') {\n                for (; tzi < tzl; tzi++) {\n                    tzv = timezoneList[tzi];\n                    timezoneList[tzi] = { value: tzv, label: $.timepicker.timezoneOffsetString(tzv, tp_inst.support.iso8601) };\n                }\n            }\n            tp_inst._defaults.timezoneList = timezoneList;\n\n            // set the default units\n            tp_inst.timezone = tp_inst._defaults.timezone !== null ? $.timepicker.timezoneOffsetNumber(tp_inst._defaults.timezone) :\n                ((new Date()).getTimezoneOffset() * -1);\n            tp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin ? tp_inst._defaults.hourMin :\n                tp_inst._defaults.hour > tp_inst._defaults.hourMax ? tp_inst._defaults.hourMax : tp_inst._defaults.hour;\n            tp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin ? tp_inst._defaults.minuteMin :\n                tp_inst._defaults.minute > tp_inst._defaults.minuteMax ? tp_inst._defaults.minuteMax : tp_inst._defaults.minute;\n            tp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin ? tp_inst._defaults.secondMin :\n                tp_inst._defaults.second > tp_inst._defaults.secondMax ? tp_inst._defaults.secondMax : tp_inst._defaults.second;\n            tp_inst.millisec = tp_inst._defaults.millisec < tp_inst._defaults.millisecMin ? tp_inst._defaults.millisecMin :\n                tp_inst._defaults.millisec > tp_inst._defaults.millisecMax ? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec;\n            tp_inst.microsec = tp_inst._defaults.microsec < tp_inst._defaults.microsecMin ? tp_inst._defaults.microsecMin :\n                tp_inst._defaults.microsec > tp_inst._defaults.microsecMax ? tp_inst._defaults.microsecMax : tp_inst._defaults.microsec;\n            tp_inst.ampm = '';\n            tp_inst.$input = $input;\n\n            if (tp_inst._defaults.altField) {\n                tp_inst.$altInput = $(tp_inst._defaults.altField);\n                if (tp_inst._defaults.altRedirectFocus === true) {\n                    tp_inst.$altInput.css({\n                        cursor: 'pointer'\n                    }).focus(function () {\n                        $input.trigger(\"focus\");\n                    });\n                }\n            }\n\n            if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) {\n                tp_inst._defaults.minDate = new Date();\n            }\n            if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) {\n                tp_inst._defaults.maxDate = new Date();\n            }\n\n            // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..\n            if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) {\n                tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());\n            }\n            if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) {\n                tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());\n            }\n            if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) {\n                tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());\n            }\n            if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) {\n                tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());\n            }\n            tp_inst.$input.bind('focus', function () {\n                tp_inst._onFocus();\n            });\n\n            return tp_inst;\n        },\n\n        /*\n        * add our sliders to the calendar\n        */\n        _addTimePicker: function (dp_inst) {\n            var currDT = $.trim((this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val());\n\n            this.timeDefined = this._parseTime(currDT);\n            this._limitMinMaxDateTime(dp_inst, false);\n            this._injectTimePicker();\n            this._afterInject();\n        },\n\n        /*\n        * parse the time string from input value or _setTime\n        */\n        _parseTime: function (timeString, withDate) {\n            if (!this.inst) {\n                this.inst = $.datepicker._getInst(this.$input[0]);\n            }\n\n            if (withDate || !this._defaults.timeOnly) {\n                var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');\n                try {\n                    var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);\n                    if (!parseRes.timeObj) {\n                        return false;\n                    }\n                    $.extend(this, parseRes.timeObj);\n                } catch (err) {\n                    $.timepicker.log(\"Error parsing the date/time string: \" + err +\n                        \"\\ndate/time string = \" + timeString +\n                        \"\\ntimeFormat = \" + this._defaults.timeFormat +\n                        \"\\ndateFormat = \" + dp_dateFormat);\n                    return false;\n                }\n                return true;\n            } else {\n                var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);\n                if (!timeObj) {\n                    return false;\n                }\n                $.extend(this, timeObj);\n                return true;\n            }\n        },\n\n        /*\n        * Handle callback option after injecting timepicker\n        */\n        _afterInject: function() {\n            var o = this.inst.settings;\n            if ($.isFunction(o.afterInject)) {\n                o.afterInject.call(this);\n            }\n        },\n\n        /*\n        * generate and inject html for timepicker into ui datepicker\n        */\n        _injectTimePicker: function () {\n            var $dp = this.inst.dpDiv,\n                o = this.inst.settings,\n                tp_inst = this,\n                litem = '',\n                uitem = '',\n                show = null,\n                max = {},\n                gridSize = {},\n                size = null,\n                i = 0,\n                l = 0;\n\n            // Prevent displaying twice\n            if ($dp.find(\"div.ui-timepicker-div\").length === 0 && o.showTimepicker) {\n                var noDisplay = ' ui_tpicker_unit_hide',\n                    html = '<div class=\"ui-timepicker-div' + (o.isRTL ? ' ui-timepicker-rtl' : '') + (o.oneLine && o.controlType === 'select' ? ' ui-timepicker-oneLine' : '') + '\"><dl>' + '<dt class=\"ui_tpicker_time_label' + ((o.showTime) ? '' : noDisplay) + '\">' + o.timeText + '</dt>' +\n                        '<dd class=\"ui_tpicker_time '+ ((o.showTime) ? '' : noDisplay) + '\"><input class=\"ui_tpicker_time_input\" ' + (o.timeInput ? '' : 'disabled') + '/></dd>';\n\n                // Create the markup\n                for (i = 0, l = this.units.length; i < l; i++) {\n                    litem = this.units[i];\n                    uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);\n                    show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];\n\n                    // Added by Peter Medeiros:\n                    // - Figure out what the hour/minute/second max should be based on the step values.\n                    // - Example: if stepMinute is 15, then minMax is 45.\n                    max[litem] = parseInt((o[litem + 'Max'] - ((o[litem + 'Max'] - o[litem + 'Min']) % o['step' + uitem])), 10);\n                    gridSize[litem] = 0;\n\n                    html += '<dt class=\"ui_tpicker_' + litem + '_label' + (show ? '' : noDisplay) + '\">' + o[litem + 'Text'] + '</dt>' +\n                        '<dd class=\"ui_tpicker_' + litem + (show ? '' : noDisplay) + '\"><div class=\"ui_tpicker_' + litem + '_slider' + (show ? '' : noDisplay) + '\"></div>';\n\n                    if (show && o[litem + 'Grid'] > 0) {\n                        html += '<div style=\"padding-left: 1px\"><table class=\"ui-tpicker-grid-label\"><tr>';\n\n                        if (litem === 'hour') {\n                            for (var h = o[litem + 'Min']; h <= max[litem]; h += parseInt(o[litem + 'Grid'], 10)) {\n                                gridSize[litem]++;\n                                var tmph = $.datepicker.formatTime(this.support.ampm ? 'hht' : 'HH', {hour: h}, o);\n                                html += '<td data-for=\"' + litem + '\">' + tmph + '</td>';\n                            }\n                        }\n                        else {\n                            for (var m = o[litem + 'Min']; m <= max[litem]; m += parseInt(o[litem + 'Grid'], 10)) {\n                                gridSize[litem]++;\n                                html += '<td data-for=\"' + litem + '\">' + ((m < 10) ? '0' : '') + m + '</td>';\n                            }\n                        }\n\n                        html += '</tr></table></div>';\n                    }\n                    html += '</dd>';\n                }\n\n                // Timezone\n                var showTz = o.showTimezone !== null ? o.showTimezone : this.support.timezone;\n                html += '<dt class=\"ui_tpicker_timezone_label' + (showTz ? '' : noDisplay) + '\">' + o.timezoneText + '</dt>';\n                html += '<dd class=\"ui_tpicker_timezone' + (showTz ? '' : noDisplay) + '\"></dd>';\n\n                // Create the elements from string\n                html += '</dl></div>';\n                var $tp = $(html);\n\n                // if we only want time picker...\n                if (o.timeOnly === true) {\n                    $tp.prepend('<div class=\"ui-widget-header ui-helper-clearfix ui-corner-all\">' + '<div class=\"ui-datepicker-title\">' + o.timeOnlyTitle + '</div>' + '</div>');\n                    $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();\n                }\n\n                // add sliders, adjust grids, add events\n                for (i = 0, l = tp_inst.units.length; i < l; i++) {\n                    litem = tp_inst.units[i];\n                    uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);\n                    show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];\n\n                    // add the slider\n                    tp_inst[litem + '_slider'] = tp_inst.control.create(tp_inst, $tp.find('.ui_tpicker_' + litem + '_slider'), litem, tp_inst[litem], o[litem + 'Min'], max[litem], o['step' + uitem]);\n\n                    // adjust the grid and add click event\n                    if (show && o[litem + 'Grid'] > 0) {\n                        size = 100 * gridSize[litem] * o[litem + 'Grid'] / (max[litem] - o[litem + 'Min']);\n                        $tp.find('.ui_tpicker_' + litem + ' table').css({\n                            width: size + \"%\",\n                            marginLeft: o.isRTL ? '0' : ((size / (-2 * gridSize[litem])) + \"%\"),\n                            marginRight: o.isRTL ? ((size / (-2 * gridSize[litem])) + \"%\") : '0',\n                            borderCollapse: 'collapse'\n                        }).find(\"td\").click(function (e) {\n                            var $t = $(this),\n                                h = $t.html(),\n                                n = parseInt(h.replace(/[^0-9]/g), 10),\n                                ap = h.replace(/[^apm]/ig),\n                                f = $t.data('for'); // loses scope, so we use data-for\n\n                            if (f === 'hour') {\n                                if (ap.indexOf('p') !== -1 && n < 12) {\n                                    n += 12;\n                                }\n                                else {\n                                    if (ap.indexOf('a') !== -1 && n === 12) {\n                                        n = 0;\n                                    }\n                                }\n                            }\n\n                            tp_inst.control.value(tp_inst, tp_inst[f + '_slider'], litem, n);\n\n                            tp_inst._onTimeChange();\n                            tp_inst._onSelectHandler();\n                        }).css({\n                            cursor: 'pointer',\n                            width: (100 / gridSize[litem]) + '%',\n                            textAlign: 'center',\n                            overflow: 'hidden'\n                        });\n                    } // end if grid > 0\n                } // end for loop\n\n                // Add timezone options\n                this.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find(\"select\");\n                $.fn.append.apply(this.timezone_select,\n                    $.map(o.timezoneList, function (val, idx) {\n                        return $(\"<option />\").val(typeof val === \"object\" ? val.value : val).text(typeof val === \"object\" ? val.label : val);\n                    }));\n                if (typeof(this.timezone) !== \"undefined\" && this.timezone !== null && this.timezone !== \"\") {\n                    var local_timezone = (new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12)).getTimezoneOffset() * -1;\n                    if (local_timezone === this.timezone) {\n                        selectLocalTimezone(tp_inst);\n                    } else {\n                        this.timezone_select.val(this.timezone);\n                    }\n                } else {\n                    if (typeof(this.hour) !== \"undefined\" && this.hour !== null && this.hour !== \"\") {\n                        this.timezone_select.val(o.timezone);\n                    } else {\n                        selectLocalTimezone(tp_inst);\n                    }\n                }\n                this.timezone_select.change(function () {\n                    tp_inst._onTimeChange();\n                    tp_inst._onSelectHandler();\n                    tp_inst._afterInject();\n                });\n                // End timezone options\n\n                // inject timepicker into datepicker\n                var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');\n                if ($buttonPanel.length) {\n                    $buttonPanel.before($tp);\n                } else {\n                    $dp.append($tp);\n                }\n\n                this.$timeObj = $tp.find('.ui_tpicker_time_input');\n                this.$timeObj.change(function () {\n                    var timeFormat = tp_inst.inst.settings.timeFormat;\n                    var parsedTime = $.datepicker.parseTime(timeFormat, this.value);\n                    var update = new Date();\n                    if (parsedTime) {\n                        update.setHours(parsedTime.hour);\n                        update.setMinutes(parsedTime.minute);\n                        update.setSeconds(parsedTime.second);\n                        $.datepicker._setTime(tp_inst.inst, update);\n                    } else {\n                        this.value = tp_inst.formattedTime;\n                        this.blur();\n                    }\n                });\n\n                if (this.inst !== null) {\n                    var timeDefined = this.timeDefined;\n                    this._onTimeChange();\n                    this.timeDefined = timeDefined;\n                }\n\n                // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/\n                if (this._defaults.addSliderAccess) {\n                    var sliderAccessArgs = this._defaults.sliderAccessArgs,\n                        rtl = this._defaults.isRTL;\n                    sliderAccessArgs.isRTL = rtl;\n\n                    setTimeout(function () { // fix for inline mode\n                        if ($tp.find('.ui-slider-access').length === 0) {\n                            $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);\n\n                            // fix any grids since sliders are shorter\n                            var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);\n                            if (sliderAccessWidth) {\n                                $tp.find('table:visible').each(function () {\n                                    var $g = $(this),\n                                        oldWidth = $g.outerWidth(),\n                                        oldMarginLeft = $g.css(rtl ? 'marginRight' : 'marginLeft').toString().replace('%', ''),\n                                        newWidth = oldWidth - sliderAccessWidth,\n                                        newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%',\n                                        css = { width: newWidth, marginRight: 0, marginLeft: 0 };\n                                    css[rtl ? 'marginRight' : 'marginLeft'] = newMarginLeft;\n                                    $g.css(css);\n                                });\n                            }\n                        }\n                    }, 10);\n                }\n                // end slideAccess integration\n\n                tp_inst._limitMinMaxDateTime(this.inst, true);\n            }\n        },\n\n        /*\n        * This function tries to limit the ability to go outside the\n        * min/max date range\n        */\n        _limitMinMaxDateTime: function (dp_inst, adjustSliders) {\n            var o = this._defaults,\n                dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);\n\n            if (!this._defaults.showTimepicker) {\n                return;\n            } // No time so nothing to check here\n\n            if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) {\n                var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),\n                    minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);\n\n                if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null || this.microsecMinOriginal === null) {\n                    this.hourMinOriginal = o.hourMin;\n                    this.minuteMinOriginal = o.minuteMin;\n                    this.secondMinOriginal = o.secondMin;\n                    this.millisecMinOriginal = o.millisecMin;\n                    this.microsecMinOriginal = o.microsecMin;\n                }\n\n                if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() === dp_date.getTime()) {\n                    this._defaults.hourMin = minDateTime.getHours();\n                    if (this.hour <= this._defaults.hourMin) {\n                        this.hour = this._defaults.hourMin;\n                        this._defaults.minuteMin = minDateTime.getMinutes();\n                        if (this.minute <= this._defaults.minuteMin) {\n                            this.minute = this._defaults.minuteMin;\n                            this._defaults.secondMin = minDateTime.getSeconds();\n                            if (this.second <= this._defaults.secondMin) {\n                                this.second = this._defaults.secondMin;\n                                this._defaults.millisecMin = minDateTime.getMilliseconds();\n                                if (this.millisec <= this._defaults.millisecMin) {\n                                    this.millisec = this._defaults.millisecMin;\n                                    this._defaults.microsecMin = minDateTime.getMicroseconds();\n                                } else {\n                                    if (this.microsec < this._defaults.microsecMin) {\n                                        this.microsec = this._defaults.microsecMin;\n                                    }\n                                    this._defaults.microsecMin = this.microsecMinOriginal;\n                                }\n                            } else {\n                                this._defaults.millisecMin = this.millisecMinOriginal;\n                                this._defaults.microsecMin = this.microsecMinOriginal;\n                            }\n                        } else {\n                            this._defaults.secondMin = this.secondMinOriginal;\n                            this._defaults.millisecMin = this.millisecMinOriginal;\n                            this._defaults.microsecMin = this.microsecMinOriginal;\n                        }\n                    } else {\n                        this._defaults.minuteMin = this.minuteMinOriginal;\n                        this._defaults.secondMin = this.secondMinOriginal;\n                        this._defaults.millisecMin = this.millisecMinOriginal;\n                        this._defaults.microsecMin = this.microsecMinOriginal;\n                    }\n                } else {\n                    this._defaults.hourMin = this.hourMinOriginal;\n                    this._defaults.minuteMin = this.minuteMinOriginal;\n                    this._defaults.secondMin = this.secondMinOriginal;\n                    this._defaults.millisecMin = this.millisecMinOriginal;\n                    this._defaults.microsecMin = this.microsecMinOriginal;\n                }\n            }\n\n            if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) {\n                var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),\n                    maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);\n\n                if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null || this.millisecMaxOriginal === null) {\n                    this.hourMaxOriginal = o.hourMax;\n                    this.minuteMaxOriginal = o.minuteMax;\n                    this.secondMaxOriginal = o.secondMax;\n                    this.millisecMaxOriginal = o.millisecMax;\n                    this.microsecMaxOriginal = o.microsecMax;\n                }\n\n                if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() === dp_date.getTime()) {\n                    this._defaults.hourMax = maxDateTime.getHours();\n                    if (this.hour >= this._defaults.hourMax) {\n                        this.hour = this._defaults.hourMax;\n                        this._defaults.minuteMax = maxDateTime.getMinutes();\n                        if (this.minute >= this._defaults.minuteMax) {\n                            this.minute = this._defaults.minuteMax;\n                            this._defaults.secondMax = maxDateTime.getSeconds();\n                            if (this.second >= this._defaults.secondMax) {\n                                this.second = this._defaults.secondMax;\n                                this._defaults.millisecMax = maxDateTime.getMilliseconds();\n                                if (this.millisec >= this._defaults.millisecMax) {\n                                    this.millisec = this._defaults.millisecMax;\n                                    this._defaults.microsecMax = maxDateTime.getMicroseconds();\n                                } else {\n                                    if (this.microsec > this._defaults.microsecMax) {\n                                        this.microsec = this._defaults.microsecMax;\n                                    }\n                                    this._defaults.microsecMax = this.microsecMaxOriginal;\n                                }\n                            } else {\n                                this._defaults.millisecMax = this.millisecMaxOriginal;\n                                this._defaults.microsecMax = this.microsecMaxOriginal;\n                            }\n                        } else {\n                            this._defaults.secondMax = this.secondMaxOriginal;\n                            this._defaults.millisecMax = this.millisecMaxOriginal;\n                            this._defaults.microsecMax = this.microsecMaxOriginal;\n                        }\n                    } else {\n                        this._defaults.minuteMax = this.minuteMaxOriginal;\n                        this._defaults.secondMax = this.secondMaxOriginal;\n                        this._defaults.millisecMax = this.millisecMaxOriginal;\n                        this._defaults.microsecMax = this.microsecMaxOriginal;\n                    }\n                } else {\n                    this._defaults.hourMax = this.hourMaxOriginal;\n                    this._defaults.minuteMax = this.minuteMaxOriginal;\n                    this._defaults.secondMax = this.secondMaxOriginal;\n                    this._defaults.millisecMax = this.millisecMaxOriginal;\n                    this._defaults.microsecMax = this.microsecMaxOriginal;\n                }\n            }\n\n            if (dp_inst.settings.minTime!==null) {\n                var tempMinTime=new Date(\"01/01/1970 \" + dp_inst.settings.minTime);\n                if (this.hour<tempMinTime.getHours()) {\n                    this.hour=this._defaults.hourMin=tempMinTime.getHours();\n                    this.minute=this._defaults.minuteMin=tempMinTime.getMinutes();\n                } else if (this.hour===tempMinTime.getHours() && this.minute<tempMinTime.getMinutes()) {\n                    this.minute=this._defaults.minuteMin=tempMinTime.getMinutes();\n                } else {\n                    if (this._defaults.hourMin<tempMinTime.getHours()) {\n                        this._defaults.hourMin=tempMinTime.getHours();\n                        this._defaults.minuteMin=tempMinTime.getMinutes();\n                    } else if (this._defaults.hourMin===tempMinTime.getHours()===this.hour && this._defaults.minuteMin<tempMinTime.getMinutes()) {\n                        this._defaults.minuteMin=tempMinTime.getMinutes();\n                    } else {\n                        this._defaults.minuteMin=0;\n                    }\n                }\n            }\n\n            if (dp_inst.settings.maxTime!==null) {\n                var tempMaxTime=new Date(\"01/01/1970 \" + dp_inst.settings.maxTime);\n                if (this.hour>tempMaxTime.getHours()) {\n                    this.hour=this._defaults.hourMax=tempMaxTime.getHours();\n                    this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();\n                } else if (this.hour===tempMaxTime.getHours() && this.minute>tempMaxTime.getMinutes()) {\n                    this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();\n                } else {\n                    if (this._defaults.hourMax>tempMaxTime.getHours()) {\n                        this._defaults.hourMax=tempMaxTime.getHours();\n                        this._defaults.minuteMax=tempMaxTime.getMinutes();\n                    } else if (this._defaults.hourMax===tempMaxTime.getHours()===this.hour && this._defaults.minuteMax>tempMaxTime.getMinutes()) {\n                        this._defaults.minuteMax=tempMaxTime.getMinutes();\n                    } else {\n                        this._defaults.minuteMax=59;\n                    }\n                }\n            }\n\n            if (adjustSliders !== undefined && adjustSliders === true) {\n                var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10),\n                    minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10),\n                    secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10),\n                    millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10),\n                    microsecMax = parseInt((this._defaults.microsecMax - ((this._defaults.microsecMax - this._defaults.microsecMin) % this._defaults.stepMicrosec)), 10);\n\n                if (this.hour_slider) {\n                    this.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax, step: this._defaults.stepHour });\n                    this.control.value(this, this.hour_slider, 'hour', this.hour - (this.hour % this._defaults.stepHour));\n                }\n                if (this.minute_slider) {\n                    this.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax, step: this._defaults.stepMinute });\n                    this.control.value(this, this.minute_slider, 'minute', this.minute - (this.minute % this._defaults.stepMinute));\n                }\n                if (this.second_slider) {\n                    this.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax, step: this._defaults.stepSecond });\n                    this.control.value(this, this.second_slider, 'second', this.second - (this.second % this._defaults.stepSecond));\n                }\n                if (this.millisec_slider) {\n                    this.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax, step: this._defaults.stepMillisec });\n                    this.control.value(this, this.millisec_slider, 'millisec', this.millisec - (this.millisec % this._defaults.stepMillisec));\n                }\n                if (this.microsec_slider) {\n                    this.control.options(this, this.microsec_slider, 'microsec', { min: this._defaults.microsecMin, max: microsecMax, step: this._defaults.stepMicrosec });\n                    this.control.value(this, this.microsec_slider, 'microsec', this.microsec - (this.microsec % this._defaults.stepMicrosec));\n                }\n            }\n\n        },\n\n        /*\n        * when a slider moves, set the internal time...\n        * on time change is also called when the time is updated in the text field\n        */\n        _onTimeChange: function () {\n            if (!this._defaults.showTimepicker) {\n                return;\n            }\n            var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false,\n                minute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false,\n                second = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false,\n                millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false,\n                microsec = (this.microsec_slider) ? this.control.value(this, this.microsec_slider, 'microsec') : false,\n                timezone = (this.timezone_select) ? this.timezone_select.val() : false,\n                o = this._defaults,\n                pickerTimeFormat = o.pickerTimeFormat || o.timeFormat,\n                pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;\n\n            if (typeof(hour) === 'object') {\n                hour = false;\n            }\n            if (typeof(minute) === 'object') {\n                minute = false;\n            }\n            if (typeof(second) === 'object') {\n                second = false;\n            }\n            if (typeof(millisec) === 'object') {\n                millisec = false;\n            }\n            if (typeof(microsec) === 'object') {\n                microsec = false;\n            }\n            if (typeof(timezone) === 'object') {\n                timezone = false;\n            }\n\n            if (hour !== false) {\n                hour = parseInt(hour, 10);\n            }\n            if (minute !== false) {\n                minute = parseInt(minute, 10);\n            }\n            if (second !== false) {\n                second = parseInt(second, 10);\n            }\n            if (millisec !== false) {\n                millisec = parseInt(millisec, 10);\n            }\n            if (microsec !== false) {\n                microsec = parseInt(microsec, 10);\n            }\n            if (timezone !== false) {\n                timezone = timezone.toString();\n            }\n\n            var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];\n\n            // If the update was done in the input field, the input field should not be updated.\n            // If the update was done using the sliders, update the input field.\n            var hasChanged = (\n                hour !== parseInt(this.hour,10) || // sliders should all be numeric\n                minute !== parseInt(this.minute,10) ||\n                second !== parseInt(this.second,10) ||\n                millisec !== parseInt(this.millisec,10) ||\n                microsec !== parseInt(this.microsec,10) ||\n                (this.ampm.length > 0 && (hour < 12) !== ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1)) ||\n                (this.timezone !== null && timezone !== this.timezone.toString()) // could be numeric or \"EST\" format, so use toString()\n            );\n\n            if (hasChanged) {\n\n                if (hour !== false) {\n                    this.hour = hour;\n                }\n                if (minute !== false) {\n                    this.minute = minute;\n                }\n                if (second !== false) {\n                    this.second = second;\n                }\n                if (millisec !== false) {\n                    this.millisec = millisec;\n                }\n                if (microsec !== false) {\n                    this.microsec = microsec;\n                }\n                if (timezone !== false) {\n                    this.timezone = timezone;\n                }\n\n                if (!this.inst) {\n                    this.inst = $.datepicker._getInst(this.$input[0]);\n                }\n\n                this._limitMinMaxDateTime(this.inst, true);\n            }\n            if (this.support.ampm) {\n                this.ampm = ampm;\n            }\n\n            // Updates the time within the timepicker\n            this.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o);\n            if (this.$timeObj) {\n                if (pickerTimeFormat === o.timeFormat) {\n                    this.$timeObj.val(this.formattedTime + pickerTimeSuffix);\n                }\n                else {\n                    this.$timeObj.val($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix);\n                }\n                if (this.$timeObj[0].setSelectionRange) {\n                    var sPos = this.$timeObj[0].selectionStart;\n                    var ePos = this.$timeObj[0].selectionEnd;\n                    this.$timeObj[0].setSelectionRange(sPos, ePos);\n                }\n            }\n\n            this.timeDefined = true;\n            if (hasChanged) {\n                this._updateDateTime();\n                //this.$input.focus(); // may automatically open the picker on setDate\n            }\n        },\n\n        /*\n        * call custom onSelect.\n        * bind to sliders slidestop, and grid click.\n        */\n        _onSelectHandler: function () {\n            var onSelect = this._defaults.onSelect || this.inst.settings.onSelect;\n            var inputEl = this.$input ? this.$input[0] : null;\n            if (onSelect && inputEl) {\n                onSelect.apply(inputEl, [this.formattedDateTime, this]);\n            }\n        },\n\n        /*\n        * update our input with the new date time..\n        */\n        _updateDateTime: function (dp_inst) {\n            dp_inst = this.inst || dp_inst;\n            var dtTmp = (dp_inst.currentYear > 0?\n                new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay) :\n                new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),\n                dt = $.datepicker._daylightSavingAdjust(dtTmp),\n                //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),\n                //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay)),\n                dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),\n                formatCfg = $.datepicker._getFormatConfig(dp_inst),\n                timeAvailable = dt !== null && this.timeDefined;\n            this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);\n            var formattedDateTime = this.formattedDate;\n\n            // if a slider was changed but datepicker doesn't have a value yet, set it\n            if (dp_inst.lastVal === \"\") {\n                dp_inst.currentYear = dp_inst.selectedYear;\n                dp_inst.currentMonth = dp_inst.selectedMonth;\n                dp_inst.currentDay = dp_inst.selectedDay;\n            }\n\n            /*\n            * remove following lines to force every changes in date picker to change the input value\n            * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker.\n            * If the user manually empty the value in the input field, the date picker will never change selected value.\n            */\n            //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {\n            //\treturn;\n            //}\n\n            if (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === false) {\n                formattedDateTime = this.formattedTime;\n            } else if ((this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) || (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === true)) {\n                formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;\n            }\n\n            this.formattedDateTime = formattedDateTime;\n\n            if (!this._defaults.showTimepicker) {\n                this.$input.val(this.formattedDate);\n            } else if (this.$altInput && this._defaults.timeOnly === false && this._defaults.altFieldTimeOnly === true) {\n                this.$altInput.val(this.formattedTime);\n                this.$input.val(this.formattedDate);\n            } else if (this.$altInput) {\n                this.$input.val(formattedDateTime);\n                var altFormattedDateTime = '',\n                    altSeparator = this._defaults.altSeparator !== null ? this._defaults.altSeparator : this._defaults.separator,\n                    altTimeSuffix = this._defaults.altTimeSuffix !== null ? this._defaults.altTimeSuffix : this._defaults.timeSuffix;\n\n                if (!this._defaults.timeOnly) {\n                    if (this._defaults.altFormat) {\n                        altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg);\n                    }\n                    else {\n                        altFormattedDateTime = this.formattedDate;\n                    }\n\n                    if (altFormattedDateTime) {\n                        altFormattedDateTime += altSeparator;\n                    }\n                }\n\n                if (this._defaults.altTimeFormat !== null) {\n                    altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix;\n                }\n                else {\n                    altFormattedDateTime += this.formattedTime + altTimeSuffix;\n                }\n                this.$altInput.val(altFormattedDateTime);\n            } else {\n                this.$input.val(formattedDateTime);\n            }\n\n            this.$input.trigger(\"change\");\n        },\n\n        _onFocus: function () {\n            if (!this.$input.val() && this._defaults.defaultValue) {\n                this.$input.val(this._defaults.defaultValue);\n                var inst = $.datepicker._getInst(this.$input.get(0)),\n                    tp_inst = $.datepicker._get(inst, 'timepicker');\n                if (tp_inst) {\n                    if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {\n                        try {\n                            $.datepicker._updateDatepicker(inst);\n                        } catch (err) {\n                            $.timepicker.log(err);\n                        }\n                    }\n                }\n            }\n        },\n\n        /*\n        * Small abstraction to control types\n        * We can add more, just be sure to follow the pattern: create, options, value\n        */\n        _controls: {\n            // slider methods\n            slider: {\n                create: function (tp_inst, obj, unit, val, min, max, step) {\n                    var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60\n                    return obj.prop('slide', null).slider({\n                        orientation: \"horizontal\",\n                        value: rtl ? val * -1 : val,\n                        min: rtl ? max * -1 : min,\n                        max: rtl ? min * -1 : max,\n                        step: step,\n                        slide: function (event, ui) {\n                            tp_inst.control.value(tp_inst, $(this), unit, rtl ? ui.value * -1 : ui.value);\n                            tp_inst._onTimeChange();\n                        },\n                        stop: function (event, ui) {\n                            tp_inst._onSelectHandler();\n                        }\n                    });\n                },\n                options: function (tp_inst, obj, unit, opts, val) {\n                    if (tp_inst._defaults.isRTL) {\n                        if (typeof(opts) === 'string') {\n                            if (opts === 'min' || opts === 'max') {\n                                if (val !== undefined) {\n                                    return obj.slider(opts, val * -1);\n                                }\n                                return Math.abs(obj.slider(opts));\n                            }\n                            return obj.slider(opts);\n                        }\n                        var min = opts.min,\n                            max = opts.max;\n                        opts.min = opts.max = null;\n                        if (min !== undefined) {\n                            opts.max = min * -1;\n                        }\n                        if (max !== undefined) {\n                            opts.min = max * -1;\n                        }\n                        return obj.slider(opts);\n                    }\n                    if (typeof(opts) === 'string' && val !== undefined) {\n                        return obj.slider(opts, val);\n                    }\n                    return obj.slider(opts);\n                },\n                value: function (tp_inst, obj, unit, val) {\n                    if (tp_inst._defaults.isRTL) {\n                        if (val !== undefined) {\n                            return obj.slider('value', val * -1);\n                        }\n                        return Math.abs(obj.slider('value'));\n                    }\n                    if (val !== undefined) {\n                        return obj.slider('value', val);\n                    }\n                    return obj.slider('value');\n                }\n            },\n            // select methods\n            select: {\n                create: function (tp_inst, obj, unit, val, min, max, step) {\n                    var sel = '<select class=\"ui-timepicker-select ui-state-default ui-corner-all\" data-unit=\"' + unit + '\" data-min=\"' + min + '\" data-max=\"' + max + '\" data-step=\"' + step + '\">',\n                        format = tp_inst._defaults.pickerTimeFormat || tp_inst._defaults.timeFormat;\n\n                    for (var i = min; i <= max; i += step) {\n                        sel += '<option value=\"' + i + '\"' + (i === val ? ' selected' : '') + '>';\n                        if (unit === 'hour') {\n                            sel += $.datepicker.formatTime($.trim(format.replace(/[^ht ]/ig, '')), {hour: i}, tp_inst._defaults);\n                        }\n                        else if (unit === 'millisec' || unit === 'microsec' || i >= 10) { sel += i; }\n                        else {sel += '0' + i.toString(); }\n                        sel += '</option>';\n                    }\n                    sel += '</select>';\n\n                    obj.children('select').remove();\n\n                    $(sel).appendTo(obj).change(function (e) {\n                        tp_inst._onTimeChange();\n                        tp_inst._onSelectHandler();\n                        tp_inst._afterInject();\n                    });\n\n                    return obj;\n                },\n                options: function (tp_inst, obj, unit, opts, val) {\n                    var o = {},\n                        $t = obj.children('select');\n                    if (typeof(opts) === 'string') {\n                        if (val === undefined) {\n                            return $t.data(opts);\n                        }\n                        o[opts] = val;\n                    }\n                    else { o = opts; }\n                    return tp_inst.control.create(tp_inst, obj, $t.data('unit'), $t.val(), o.min>=0 ? o.min : $t.data('min'), o.max || $t.data('max'), o.step || $t.data('step'));\n                },\n                value: function (tp_inst, obj, unit, val) {\n                    var $t = obj.children('select');\n                    if (val !== undefined) {\n                        return $t.val(val);\n                    }\n                    return $t.val();\n                }\n            }\n        } // end _controls\n\n    });\n\n    $.fn.extend({\n        /*\n        * shorthand just to use timepicker.\n        */\n        timepicker: function (o) {\n            o = o || {};\n            var tmp_args = Array.prototype.slice.call(arguments);\n\n            if (typeof o === 'object') {\n                tmp_args[0] = $.extend(o, {\n                    timeOnly: true\n                });\n            }\n\n            return $(this).each(function () {\n                $.fn.datetimepicker.apply($(this), tmp_args);\n            });\n        },\n\n        /*\n        * extend timepicker to datepicker\n        */\n        datetimepicker: function (o) {\n            o = o || {};\n            var tmp_args = arguments;\n\n            if (typeof(o) === 'string') {\n                if (o === 'getDate'  || (o === 'option' && tmp_args.length === 2 && typeof (tmp_args[1]) === 'string')) {\n                    return $.fn.datepicker.apply($(this[0]), tmp_args);\n                } else {\n                    return this.each(function () {\n                        var $t = $(this);\n                        $t.datepicker.apply($t, tmp_args);\n                    });\n                }\n            } else {\n                return this.each(function () {\n                    var $t = $(this);\n                    $t.datepicker($.timepicker._newInst($t, o)._defaults);\n                });\n            }\n        }\n    });\n\n    /*\n    * Public Utility to parse date and time\n    */\n    $.datepicker.parseDateTime = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {\n        var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings);\n        if (parseRes.timeObj) {\n            var t = parseRes.timeObj;\n            parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec);\n            parseRes.date.setMicroseconds(t.microsec);\n        }\n\n        return parseRes.date;\n    };\n\n    /*\n    * Public utility to parse time\n    */\n    $.datepicker.parseTime = function (timeFormat, timeString, options) {\n        var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {}),\n            iso8601 = (timeFormat.replace(/\\'.*?\\'/g, '').indexOf('Z') !== -1);\n\n        // Strict parse requires the timeString to match the timeFormat exactly\n        var strictParse = function (f, s, o) {\n\n            // pattern for standard and localized AM/PM markers\n            var getPatternAmpm = function (amNames, pmNames) {\n                var markers = [];\n                if (amNames) {\n                    $.merge(markers, amNames);\n                }\n                if (pmNames) {\n                    $.merge(markers, pmNames);\n                }\n                markers = $.map(markers, function (val) {\n                    return val.replace(/[.*+?|()\\[\\]{}\\\\]/g, '\\\\$&');\n                });\n                return '(' + markers.join('|') + ')?';\n            };\n\n            // figure out position of time elements.. cause js cant do named captures\n            var getFormatPositions = function (timeFormat) {\n                var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|c{1}|t{1,2}|z|'.*?')/g),\n                    orders = {\n                        h: -1,\n                        m: -1,\n                        s: -1,\n                        l: -1,\n                        c: -1,\n                        t: -1,\n                        z: -1\n                    };\n\n                if (finds) {\n                    for (var i = 0; i < finds.length; i++) {\n                        if (orders[finds[i].toString().charAt(0)] === -1) {\n                            orders[finds[i].toString().charAt(0)] = i + 1;\n                        }\n                    }\n                }\n                return orders;\n            };\n\n            var regstr = '^' + f.toString()\n                    .replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {\n                        var ml = match.length;\n                        switch (match.charAt(0).toLowerCase()) {\n                            case 'h':\n                                return ml === 1 ? '(\\\\d?\\\\d)' : '(\\\\d{' + ml + '})';\n                            case 'm':\n                                return ml === 1 ? '(\\\\d?\\\\d)' : '(\\\\d{' + ml + '})';\n                            case 's':\n                                return ml === 1 ? '(\\\\d?\\\\d)' : '(\\\\d{' + ml + '})';\n                            case 'l':\n                                return '(\\\\d?\\\\d?\\\\d)';\n                            case 'c':\n                                return '(\\\\d?\\\\d?\\\\d)';\n                            case 'z':\n                                return '(z|[-+]\\\\d\\\\d:?\\\\d\\\\d|\\\\S+)?';\n                            case 't':\n                                return getPatternAmpm(o.amNames, o.pmNames);\n                            default:    // literal escaped in quotes\n                                return '(' + match.replace(/\\'/g, \"\").replace(/(\\.|\\$|\\^|\\\\|\\/|\\(|\\)|\\[|\\]|\\?|\\+|\\*)/g, function (m) { return \"\\\\\" + m; }) + ')?';\n                        }\n                    })\n                    .replace(/\\s/g, '\\\\s?') +\n                o.timeSuffix + '$',\n                order = getFormatPositions(f),\n                ampm = '',\n                treg;\n\n            treg = s.match(new RegExp(regstr, 'i'));\n\n            var resTime = {\n                hour: 0,\n                minute: 0,\n                second: 0,\n                millisec: 0,\n                microsec: 0\n            };\n\n            if (treg) {\n                if (order.t !== -1) {\n                    if (treg[order.t] === undefined || treg[order.t].length === 0) {\n                        ampm = '';\n                        resTime.ampm = '';\n                    } else {\n                        ampm = $.inArray(treg[order.t].toUpperCase(), $.map(o.amNames, function (x,i) { return x.toUpperCase(); })) !== -1 ? 'AM' : 'PM';\n                        resTime.ampm = o[ampm === 'AM' ? 'amNames' : 'pmNames'][0];\n                    }\n                }\n\n                if (order.h !== -1) {\n                    if (ampm === 'AM' && treg[order.h] === '12') {\n                        resTime.hour = 0; // 12am = 0 hour\n                    } else {\n                        if (ampm === 'PM' && treg[order.h] !== '12') {\n                            resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12\n                        } else {\n                            resTime.hour = Number(treg[order.h]);\n                        }\n                    }\n                }\n\n                if (order.m !== -1) {\n                    resTime.minute = Number(treg[order.m]);\n                }\n                if (order.s !== -1) {\n                    resTime.second = Number(treg[order.s]);\n                }\n                if (order.l !== -1) {\n                    resTime.millisec = Number(treg[order.l]);\n                }\n                if (order.c !== -1) {\n                    resTime.microsec = Number(treg[order.c]);\n                }\n                if (order.z !== -1 && treg[order.z] !== undefined) {\n                    resTime.timezone = $.timepicker.timezoneOffsetNumber(treg[order.z]);\n                }\n\n\n                return resTime;\n            }\n            return false;\n        };// end strictParse\n\n        // First try JS Date, if that fails, use strictParse\n        var looseParse = function (f, s, o) {\n            try {\n                var d = new Date('2012-01-01 ' + s);\n                if (isNaN(d.getTime())) {\n                    d = new Date('2012-01-01T' + s);\n                    if (isNaN(d.getTime())) {\n                        d = new Date('01/01/2012 ' + s);\n                        if (isNaN(d.getTime())) {\n                            throw \"Unable to parse time with native Date: \" + s;\n                        }\n                    }\n                }\n\n                return {\n                    hour: d.getHours(),\n                    minute: d.getMinutes(),\n                    second: d.getSeconds(),\n                    millisec: d.getMilliseconds(),\n                    microsec: d.getMicroseconds(),\n                    timezone: d.getTimezoneOffset() * -1\n                };\n            }\n            catch (err) {\n                try {\n                    return strictParse(f, s, o);\n                }\n                catch (err2) {\n                    $.timepicker.log(\"Unable to parse \\ntimeString: \" + s + \"\\ntimeFormat: \" + f);\n                }\n            }\n            return false;\n        }; // end looseParse\n\n        if (typeof o.parse === \"function\") {\n            return o.parse(timeFormat, timeString, o);\n        }\n        if (o.parse === 'loose') {\n            return looseParse(timeFormat, timeString, o);\n        }\n        return strictParse(timeFormat, timeString, o);\n    };\n\n    /**\n     * Public utility to format the time\n     * @param {string} format format of the time\n     * @param {Object} time Object not a Date for timezones\n     * @param {Object} [options] essentially the regional[].. amNames, pmNames, ampm\n     * @returns {string} the formatted time\n     */\n    $.datepicker.formatTime = function (format, time, options) {\n        options = options || {};\n        options = $.extend({}, $.timepicker._defaults, options);\n        time = $.extend({\n            hour: 0,\n            minute: 0,\n            second: 0,\n            millisec: 0,\n            microsec: 0,\n            timezone: null\n        }, time);\n\n        var tmptime = format,\n            ampmName = options.amNames[0],\n            hour = parseInt(time.hour, 10);\n\n        if (hour > 11) {\n            ampmName = options.pmNames[0];\n        }\n\n        tmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {\n            switch (match) {\n                case 'HH':\n                    return ('0' + hour).slice(-2);\n                case 'H':\n                    return hour;\n                case 'hh':\n                    return ('0' + convert24to12(hour)).slice(-2);\n                case 'h':\n                    return convert24to12(hour);\n                case 'mm':\n                    return ('0' + time.minute).slice(-2);\n                case 'm':\n                    return time.minute;\n                case 'ss':\n                    return ('0' + time.second).slice(-2);\n                case 's':\n                    return time.second;\n                case 'l':\n                    return ('00' + time.millisec).slice(-3);\n                case 'c':\n                    return ('00' + time.microsec).slice(-3);\n                case 'z':\n                    return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, false);\n                case 'Z':\n                    return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, true);\n                case 'T':\n                    return ampmName.charAt(0).toUpperCase();\n                case 'TT':\n                    return ampmName.toUpperCase();\n                case 't':\n                    return ampmName.charAt(0).toLowerCase();\n                case 'tt':\n                    return ampmName.toLowerCase();\n                default:\n                    return match.replace(/'/g, \"\");\n            }\n        });\n\n        return tmptime;\n    };\n\n    /*\n    * the bad hack :/ override datepicker so it doesn't close on select\n    // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378\n    */\n    $.datepicker._base_selectDate = $.datepicker._selectDate;\n    $.datepicker._selectDate = function (id, dateStr) {\n        var inst = this._getInst($(id)[0]),\n            tp_inst = this._get(inst, 'timepicker'),\n            was_inline;\n\n        if (tp_inst && inst.settings.showTimepicker) {\n            tp_inst._limitMinMaxDateTime(inst, true);\n            was_inline = inst.inline;\n            inst.inline = inst.stay_open = true;\n            //This way the onSelect handler called from calendarpicker get the full dateTime\n            this._base_selectDate(id, dateStr);\n            inst.inline = was_inline;\n            inst.stay_open = false;\n            this._notifyChange(inst);\n            this._updateDatepicker(inst);\n        } else {\n            this._base_selectDate(id, dateStr);\n        }\n    };\n\n    /*\n    * second bad hack :/ override datepicker so it triggers an event when changing the input field\n    * and does not redraw the datepicker on every selectDate event\n    */\n    $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;\n    $.datepicker._updateDatepicker = function (inst) {\n\n        // don't popup the datepicker if there is another instance already opened\n        var input = inst.input[0];\n        if ($.datepicker._curInst && $.datepicker._curInst !== inst && $.datepicker._datepickerShowing && $.datepicker._lastInput !== input) {\n            return;\n        }\n\n        if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {\n\n            this._base_updateDatepicker(inst);\n\n            // Reload the time control when changing something in the input text field.\n            var tp_inst = this._get(inst, 'timepicker');\n            if (tp_inst) {\n                tp_inst._addTimePicker(inst);\n            }\n        }\n    };\n\n    /*\n    * third bad hack :/ override datepicker so it allows spaces and colon in the input field\n    */\n    $.datepicker._base_doKeyPress = $.datepicker._doKeyPress;\n    $.datepicker._doKeyPress = function (event) {\n        var inst = $.datepicker._getInst(event.target),\n            tp_inst = $.datepicker._get(inst, 'timepicker');\n\n        if (tp_inst) {\n            if ($.datepicker._get(inst, 'constrainInput')) {\n                var ampm = tp_inst.support.ampm,\n                    tz = tp_inst._defaults.showTimezone !== null ? tp_inst._defaults.showTimezone : tp_inst.support.timezone,\n                    dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),\n                    datetimeChars = tp_inst._defaults.timeFormat.toString()\n                            .replace(/[hms]/g, '')\n                            .replace(/TT/g, ampm ? 'APM' : '')\n                            .replace(/Tt/g, ampm ? 'AaPpMm' : '')\n                            .replace(/tT/g, ampm ? 'AaPpMm' : '')\n                            .replace(/T/g, ampm ? 'AP' : '')\n                            .replace(/tt/g, ampm ? 'apm' : '')\n                            .replace(/t/g, ampm ? 'ap' : '') +\n                        \" \" + tp_inst._defaults.separator +\n                        tp_inst._defaults.timeSuffix +\n                        (tz ? tp_inst._defaults.timezoneList.join('') : '') +\n                        (tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) +\n                        dateChars,\n                    chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);\n                return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);\n            }\n        }\n\n        return $.datepicker._base_doKeyPress(event);\n    };\n\n    /*\n    * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField\n    * Update any alternate field to synchronise with the main field.\n    */\n    $.datepicker._base_updateAlternate = $.datepicker._updateAlternate;\n    $.datepicker._updateAlternate = function (inst) {\n        var tp_inst = this._get(inst, 'timepicker');\n        if (tp_inst) {\n            var altField = tp_inst._defaults.altField;\n            if (altField) { // update alternate field too\n                var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat,\n                    date = this._getDate(inst),\n                    formatCfg = $.datepicker._getFormatConfig(inst),\n                    altFormattedDateTime = '',\n                    altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator,\n                    altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix,\n                    altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat;\n\n                altFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix;\n                if (!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly && date !== null) {\n                    if (tp_inst._defaults.altFormat) {\n                        altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, date, formatCfg) + altSeparator + altFormattedDateTime;\n                    }\n                    else {\n                        altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime;\n                    }\n                }\n                $(altField).val( inst.input.val() ? altFormattedDateTime : \"\");\n            }\n        }\n        else {\n            $.datepicker._base_updateAlternate(inst);\n        }\n    };\n\n    /*\n    * Override key up event to sync manual input changes.\n    */\n    $.datepicker._base_doKeyUp = $.datepicker._doKeyUp;\n    $.datepicker._doKeyUp = function (event) {\n        var inst = $.datepicker._getInst(event.target),\n            tp_inst = $.datepicker._get(inst, 'timepicker');\n\n        if (tp_inst) {\n            if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {\n                try {\n                    $.datepicker._updateDatepicker(inst);\n                } catch (err) {\n                    $.timepicker.log(err);\n                }\n            }\n        }\n\n        return $.datepicker._base_doKeyUp(event);\n    };\n\n    /*\n    * override \"Today\" button to also grab the time and set it to input field.\n    */\n    $.datepicker._base_gotoToday = $.datepicker._gotoToday;\n    $.datepicker._gotoToday = function (id) {\n        var inst = this._getInst($(id)[0]);\n        this._base_gotoToday(id);\n        var tp_inst = this._get(inst, 'timepicker');\n        if (!tp_inst) {\n            return;\n        }\n\n        var tzoffset = $.timepicker.timezoneOffsetNumber(tp_inst.timezone);\n        var now = new Date();\n        now.setMinutes(now.getMinutes() + now.getTimezoneOffset() + parseInt(tzoffset, 10));\n        this._setTime(inst, now);\n        this._setDate(inst, now);\n        tp_inst._onSelectHandler();\n    };\n\n    /*\n    * Disable & enable the Time in the datetimepicker\n    */\n    $.datepicker._disableTimepickerDatepicker = function (target) {\n        var inst = this._getInst(target);\n        if (!inst) {\n            return;\n        }\n\n        var tp_inst = this._get(inst, 'timepicker');\n        $(target).datepicker('getDate'); // Init selected[Year|Month|Day]\n        if (tp_inst) {\n            inst.settings.showTimepicker = false;\n            tp_inst._defaults.showTimepicker = false;\n            tp_inst._updateDateTime(inst);\n        }\n    };\n\n    $.datepicker._enableTimepickerDatepicker = function (target) {\n        var inst = this._getInst(target);\n        if (!inst) {\n            return;\n        }\n\n        var tp_inst = this._get(inst, 'timepicker');\n        $(target).datepicker('getDate'); // Init selected[Year|Month|Day]\n        if (tp_inst) {\n            inst.settings.showTimepicker = true;\n            tp_inst._defaults.showTimepicker = true;\n            tp_inst._addTimePicker(inst); // Could be disabled on page load\n            tp_inst._updateDateTime(inst);\n        }\n    };\n\n    /*\n    * Create our own set time function\n    */\n    $.datepicker._setTime = function (inst, date) {\n        var tp_inst = this._get(inst, 'timepicker');\n        if (tp_inst) {\n            var defaults = tp_inst._defaults;\n\n            // calling _setTime with no date sets time to defaults\n            tp_inst.hour = date ? date.getHours() : defaults.hour;\n            tp_inst.minute = date ? date.getMinutes() : defaults.minute;\n            tp_inst.second = date ? date.getSeconds() : defaults.second;\n            tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec;\n            tp_inst.microsec = date ? date.getMicroseconds() : defaults.microsec;\n\n            //check if within min/max times..\n            tp_inst._limitMinMaxDateTime(inst, true);\n\n            tp_inst._onTimeChange();\n            tp_inst._updateDateTime(inst);\n        }\n    };\n\n    /*\n    * Create new public method to set only time, callable as $().datepicker('setTime', date)\n    */\n    $.datepicker._setTimeDatepicker = function (target, date, withDate) {\n        var inst = this._getInst(target);\n        if (!inst) {\n            return;\n        }\n\n        var tp_inst = this._get(inst, 'timepicker');\n\n        if (tp_inst) {\n            this._setDateFromField(inst);\n            var tp_date;\n            if (date) {\n                if (typeof date === \"string\") {\n                    tp_inst._parseTime(date, withDate);\n                    tp_date = new Date();\n                    tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);\n                    tp_date.setMicroseconds(tp_inst.microsec);\n                } else {\n                    tp_date = new Date(date.getTime());\n                    tp_date.setMicroseconds(date.getMicroseconds());\n                }\n                if (tp_date.toString() === 'Invalid Date') {\n                    tp_date = undefined;\n                }\n                this._setTime(inst, tp_date);\n            }\n        }\n\n    };\n\n    /*\n    * override setDate() to allow setting time too within Date object\n    */\n    $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;\n    $.datepicker._setDateDatepicker = function (target, _date) {\n        var inst = this._getInst(target);\n        var date = _date;\n        if (!inst) {\n            return;\n        }\n\n        if (typeof(_date) === 'string') {\n            date = new Date(_date);\n            if (!date.getTime()) {\n                this._base_setDateDatepicker.apply(this, arguments);\n                date = $(target).datepicker('getDate');\n            }\n        }\n\n        var tp_inst = this._get(inst, 'timepicker');\n        var tp_date;\n        if (date instanceof Date) {\n            tp_date = new Date(date.getTime());\n            tp_date.setMicroseconds(date.getMicroseconds());\n        } else {\n            tp_date = date;\n        }\n\n        // This is important if you are using the timezone option, javascript's Date\n        // object will only return the timezone offset for the current locale, so we\n        // adjust it accordingly.  If not using timezone option this won't matter..\n        // If a timezone is different in tp, keep the timezone as is\n        if (tp_inst && tp_date) {\n            // look out for DST if tz wasn't specified\n            if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {\n                tp_inst.timezone = tp_date.getTimezoneOffset() * -1;\n            }\n            date = $.timepicker.timezoneAdjust(date, $.timepicker.timezoneOffsetString(-date.getTimezoneOffset()), tp_inst.timezone);\n            tp_date = $.timepicker.timezoneAdjust(tp_date, $.timepicker.timezoneOffsetString(-tp_date.getTimezoneOffset()), tp_inst.timezone);\n        }\n\n        this._updateDatepicker(inst);\n        this._base_setDateDatepicker.apply(this, arguments);\n        this._setTimeDatepicker(target, tp_date, true);\n    };\n\n    /*\n    * override getDate() to allow getting time too within Date object\n    */\n    $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;\n    $.datepicker._getDateDatepicker = function (target, noDefault) {\n        var inst = this._getInst(target);\n        if (!inst) {\n            return;\n        }\n\n        var tp_inst = this._get(inst, 'timepicker');\n\n        if (tp_inst) {\n            // if it hasn't yet been defined, grab from field\n            if (inst.lastVal === undefined) {\n                this._setDateFromField(inst, noDefault);\n            }\n\n            var date = this._getDate(inst);\n\n            var currDT = null;\n\n            if (tp_inst.$altInput && tp_inst._defaults.altFieldTimeOnly) {\n                currDT = tp_inst.$input.val() + ' ' + tp_inst.$altInput.val();\n            }\n            else if (tp_inst.$input.get(0).tagName !== 'INPUT' && tp_inst.$altInput) {\n                /**\n                 * in case the datetimepicker has been applied to a non-input tag for inline UI,\n                 * and the user has not configured the plugin to display only time in altInput,\n                 * pick current date time from the altInput (and hope for the best, for now, until \"ER1\" is applied)\n                 *\n                 * @todo ER1. Since altInput can have a totally difference format, convert it to standard format by reading input format from \"altFormat\" and \"altTimeFormat\" option values\n                 */\n                currDT = tp_inst.$altInput.val();\n            }\n            else {\n                currDT = tp_inst.$input.val();\n            }\n\n            if (date && tp_inst._parseTime(currDT, !inst.settings.timeOnly)) {\n                date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);\n                date.setMicroseconds(tp_inst.microsec);\n\n                // This is important if you are using the timezone option, javascript's Date\n                // object will only return the timezone offset for the current locale, so we\n                // adjust it accordingly.  If not using timezone option this won't matter..\n                if (tp_inst.timezone != null) {\n                    // look out for DST if tz wasn't specified\n                    if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {\n                        tp_inst.timezone = date.getTimezoneOffset() * -1;\n                    }\n                    date = $.timepicker.timezoneAdjust(date, tp_inst.timezone, $.timepicker.timezoneOffsetString(-date.getTimezoneOffset()));\n                }\n            }\n            return date;\n        }\n        return this._base_getDateDatepicker(target, noDefault);\n    };\n\n    /*\n    * override parseDate() because UI 1.8.14 throws an error about \"Extra characters\"\n    * An option in datapicker to ignore extra format characters would be nicer.\n    */\n    $.datepicker._base_parseDate = $.datepicker.parseDate;\n    $.datepicker.parseDate = function (format, value, settings) {\n        var date;\n        try {\n            date = this._base_parseDate(format, value, settings);\n        } catch (err) {\n            // Hack!  The error message ends with a colon, a space, and\n            // the \"extra\" characters.  We rely on that instead of\n            // attempting to perfectly reproduce the parsing algorithm.\n            if (err.indexOf(\":\") >= 0) {\n                date = this._base_parseDate(format, value.substring(0, value.length - (err.length - err.indexOf(':') - 2)), settings);\n                $.timepicker.log(\"Error parsing the date string: \" + err + \"\\ndate string = \" + value + \"\\ndate format = \" + format);\n            } else {\n                throw err;\n            }\n        }\n        return date;\n    };\n\n    /*\n    * override formatDate to set date with time to the input\n    */\n    $.datepicker._base_formatDate = $.datepicker._formatDate;\n    $.datepicker._formatDate = function (inst, day, month, year) {\n        var tp_inst = this._get(inst, 'timepicker');\n        if (tp_inst) {\n            tp_inst._updateDateTime(inst);\n            return tp_inst.$input.val();\n        }\n        return this._base_formatDate(inst);\n    };\n\n    /*\n    * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate\n    */\n    $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;\n    $.datepicker._optionDatepicker = function (target, name, value) {\n        var inst = this._getInst(target),\n            name_clone;\n        if (!inst) {\n            return null;\n        }\n\n        var tp_inst = this._get(inst, 'timepicker');\n        if (tp_inst) {\n            var min = null,\n                max = null,\n                onselect = null,\n                overrides = tp_inst._defaults.evnts,\n                fns = {},\n                prop,\n                ret,\n                oldVal,\n                $target;\n            if (typeof name === 'string') { // if min/max was set with the string\n                if (name === 'minDate' || name === 'minDateTime') {\n                    min = value;\n                } else if (name === 'maxDate' || name === 'maxDateTime') {\n                    max = value;\n                } else if (name === 'onSelect') {\n                    onselect = value;\n                } else if (overrides.hasOwnProperty(name)) {\n                    if (typeof (value) === 'undefined') {\n                        return overrides[name];\n                    }\n                    fns[name] = value;\n                    name_clone = {}; //empty results in exiting function after overrides updated\n                }\n            } else if (typeof name === 'object') { //if min/max was set with the JSON\n                if (name.minDate) {\n                    min = name.minDate;\n                } else if (name.minDateTime) {\n                    min = name.minDateTime;\n                } else if (name.maxDate) {\n                    max = name.maxDate;\n                } else if (name.maxDateTime) {\n                    max = name.maxDateTime;\n                }\n                for (prop in overrides) {\n                    if (overrides.hasOwnProperty(prop) && name[prop]) {\n                        fns[prop] = name[prop];\n                    }\n                }\n            }\n            for (prop in fns) {\n                if (fns.hasOwnProperty(prop)) {\n                    overrides[prop] = fns[prop];\n                    if (!name_clone) { name_clone = $.extend({}, name); }\n                    delete name_clone[prop];\n                }\n            }\n            if (name_clone && isEmptyObject(name_clone)) { return; }\n            if (min) { //if min was set\n                if (min === 0) {\n                    min = new Date();\n                } else {\n                    min = new Date(min);\n                }\n                tp_inst._defaults.minDate = min;\n                tp_inst._defaults.minDateTime = min;\n            } else if (max) { //if max was set\n                if (max === 0) {\n                    max = new Date();\n                } else {\n                    max = new Date(max);\n                }\n                tp_inst._defaults.maxDate = max;\n                tp_inst._defaults.maxDateTime = max;\n            } else if (onselect) {\n                tp_inst._defaults.onSelect = onselect;\n            }\n\n            // Datepicker will override our date when we call _base_optionDatepicker when\n            // calling minDate/maxDate, so we will first grab the value, call\n            // _base_optionDatepicker, then set our value back.\n            if(min || max){\n                $target = $(target);\n                oldVal = $target.datetimepicker('getDate');\n                ret = this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);\n                $target.datetimepicker('setDate', oldVal);\n                return ret;\n            }\n        }\n        if (value === undefined) {\n            return this._base_optionDatepicker.call($.datepicker, target, name);\n        }\n        return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);\n    };\n\n    /*\n    * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,\n    * it will return false for all objects\n    */\n    var isEmptyObject = function (obj) {\n        var prop;\n        for (prop in obj) {\n            if (obj.hasOwnProperty(prop)) {\n                return false;\n            }\n        }\n        return true;\n    };\n\n    /*\n    * jQuery extend now ignores nulls!\n    */\n    var extendRemove = function (target, props) {\n        $.extend(target, props);\n        for (var name in props) {\n            if (props[name] === null || props[name] === undefined) {\n                target[name] = props[name];\n            }\n        }\n        return target;\n    };\n\n    /*\n    * Determine by the time format which units are supported\n    * Returns an object of booleans for each unit\n    */\n    var detectSupport = function (timeFormat) {\n        var tf = timeFormat.replace(/'.*?'/g, '').toLowerCase(), // removes literals\n            isIn = function (f, t) { // does the format contain the token?\n                return f.indexOf(t) !== -1 ? true : false;\n            };\n        return {\n            hour: isIn(tf, 'h'),\n            minute: isIn(tf, 'm'),\n            second: isIn(tf, 's'),\n            millisec: isIn(tf, 'l'),\n            microsec: isIn(tf, 'c'),\n            timezone: isIn(tf, 'z'),\n            ampm: isIn(tf, 't') && isIn(timeFormat, 'h'),\n            iso8601: isIn(timeFormat, 'Z')\n        };\n    };\n\n    /*\n    * Converts 24 hour format into 12 hour\n    * Returns 12 hour without leading 0\n    */\n    var convert24to12 = function (hour) {\n        hour %= 12;\n\n        if (hour === 0) {\n            hour = 12;\n        }\n\n        return String(hour);\n    };\n\n    var computeEffectiveSetting = function (settings, property) {\n        return settings && settings[property] ? settings[property] : $.timepicker._defaults[property];\n    };\n\n    /*\n    * Splits datetime string into date and time substrings.\n    * Throws exception when date can't be parsed\n    * Returns {dateString: dateString, timeString: timeString}\n    */\n    var splitDateTime = function (dateTimeString, timeSettings) {\n        // The idea is to get the number separator occurrences in datetime and the time format requested (since time has\n        // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.\n        var separator = computeEffectiveSetting(timeSettings, 'separator'),\n            format = computeEffectiveSetting(timeSettings, 'timeFormat'),\n            timeParts = format.split(separator), // how many occurrences of separator may be in our format?\n            timePartsLen = timeParts.length,\n            allParts = dateTimeString.split(separator),\n            allPartsLen = allParts.length;\n\n        if (allPartsLen > 1) {\n            return {\n                dateString: allParts.splice(0, allPartsLen - timePartsLen).join(separator),\n                timeString: allParts.splice(0, timePartsLen).join(separator)\n            };\n        }\n\n        return {\n            dateString: dateTimeString,\n            timeString: ''\n        };\n    };\n\n    /*\n    * Internal function to parse datetime interval\n    * Returns: {date: Date, timeObj: Object}, where\n    *   date - parsed date without time (type Date)\n    *   timeObj = {hour: , minute: , second: , millisec: , microsec: } - parsed time. Optional\n    */\n    var parseDateTimeInternal = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {\n        var date,\n            parts,\n            parsedTime;\n\n        parts = splitDateTime(dateTimeString, timeSettings);\n        date = $.datepicker._base_parseDate(dateFormat, parts.dateString, dateSettings);\n\n        if (parts.timeString === '') {\n            return {\n                date: date\n            };\n        }\n\n        parsedTime = $.datepicker.parseTime(timeFormat, parts.timeString, timeSettings);\n\n        if (!parsedTime) {\n            throw 'Wrong time format';\n        }\n\n        return {\n            date: date,\n            timeObj: parsedTime\n        };\n    };\n\n    /*\n    * Internal function to set timezone_select to the local timezone\n    */\n    var selectLocalTimezone = function (tp_inst, date) {\n        if (tp_inst && tp_inst.timezone_select) {\n            var now = date || new Date();\n            tp_inst.timezone_select.val(-now.getTimezoneOffset());\n        }\n    };\n\n    /*\n    * Create a Singleton Instance\n    */\n    $.timepicker = new Timepicker();\n\n    /**\n     * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)\n     * @param {number} tzMinutes if not a number, less than -720 (-1200), or greater than 840 (+1400) this value is returned\n     * @param {boolean} iso8601 if true formats in accordance to iso8601 \"+12:45\"\n     * @return {string}\n     */\n    $.timepicker.timezoneOffsetString = function (tzMinutes, iso8601) {\n        if (isNaN(tzMinutes) || tzMinutes > 840 || tzMinutes < -720) {\n            return tzMinutes;\n        }\n\n        var off = tzMinutes,\n            minutes = off % 60,\n            hours = (off - minutes) / 60,\n            iso = iso8601 ? ':' : '',\n            tz = (off >= 0 ? '+' : '-') + ('0' + Math.abs(hours)).slice(-2) + iso + ('0' + Math.abs(minutes)).slice(-2);\n\n        if (tz === '+00:00') {\n            return 'Z';\n        }\n        return tz;\n    };\n\n    /**\n     * Get the number in minutes that represents a timezone string\n     * @param  {string} tzString formatted like \"+0500\", \"-1245\", \"Z\"\n     * @return {number} the offset minutes or the original string if it doesn't match expectations\n     */\n    $.timepicker.timezoneOffsetNumber = function (tzString) {\n        var normalized = tzString.toString().replace(':', ''); // excuse any iso8601, end up with \"+1245\"\n\n        if (normalized.toUpperCase() === 'Z') { // if iso8601 with Z, its 0 minute offset\n            return 0;\n        }\n\n        if (!/^(\\-|\\+)\\d{4}$/.test(normalized)) { // possibly a user defined tz, so just give it back\n            return parseInt(tzString, 10);\n        }\n\n        return ((normalized.substr(0, 1) === '-' ? -1 : 1) * // plus or minus\n            ((parseInt(normalized.substr(1, 2), 10) * 60) + // hours (converted to minutes)\n                parseInt(normalized.substr(3, 2), 10))); // minutes\n    };\n\n    /**\n     * No way to set timezone in js Date, so we must adjust the minutes to compensate. (think setDate, getDate)\n     * @param  {Date} date\n     * @param  {string} fromTimezone formatted like \"+0500\", \"-1245\"\n     * @param  {string} toTimezone formatted like \"+0500\", \"-1245\"\n     * @return {Date}\n     */\n    $.timepicker.timezoneAdjust = function (date, fromTimezone, toTimezone) {\n        var fromTz = $.timepicker.timezoneOffsetNumber(fromTimezone);\n        var toTz = $.timepicker.timezoneOffsetNumber(toTimezone);\n        if (!isNaN(toTz)) {\n            date.setMinutes(date.getMinutes() + (-fromTz) - (-toTz));\n        }\n        return date;\n    };\n\n    /**\n     * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to\n     * enforce date range limits.\n     * n.b. The input value must be correctly formatted (reformatting is not supported)\n     * @param  {Element} startTime\n     * @param  {Element} endTime\n     * @param  {Object} options Options for the timepicker() call\n     * @return {jQuery}\n     */\n    $.timepicker.timeRange = function (startTime, endTime, options) {\n        return $.timepicker.handleRange('timepicker', startTime, endTime, options);\n    };\n\n    /**\n     * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to\n     * enforce date range limits.\n     * @param  {Element} startTime\n     * @param  {Element} endTime\n     * @param  {Object} options Options for the `timepicker()` call. Also supports `reformat`,\n     *   a boolean value that can be used to reformat the input values to the `dateFormat`.\n     * @param  {string} method Can be used to specify the type of picker to be added\n     * @return {jQuery}\n     */\n    $.timepicker.datetimeRange = function (startTime, endTime, options) {\n        $.timepicker.handleRange('datetimepicker', startTime, endTime, options);\n    };\n\n    /**\n     * Calls `datepicker` on the `startTime` and `endTime` elements, and configures them to\n     * enforce date range limits.\n     * @param  {Element} startTime\n     * @param  {Element} endTime\n     * @param  {Object} options Options for the `timepicker()` call. Also supports `reformat`,\n     *   a boolean value that can be used to reformat the input values to the `dateFormat`.\n     * @return {jQuery}\n     */\n    $.timepicker.dateRange = function (startTime, endTime, options) {\n        $.timepicker.handleRange('datepicker', startTime, endTime, options);\n    };\n\n    /**\n     * Calls `method` on the `startTime` and `endTime` elements, and configures them to\n     * enforce date range limits.\n     * @param  {string} method Can be used to specify the type of picker to be added\n     * @param  {Element} startTime\n     * @param  {Element} endTime\n     * @param  {Object} options Options for the `timepicker()` call. Also supports `reformat`,\n     *   a boolean value that can be used to reformat the input values to the `dateFormat`.\n     * @return {jQuery}\n     */\n    $.timepicker.handleRange = function (method, startTime, endTime, options) {\n        options = $.extend({}, {\n            minInterval: 0, // min allowed interval in milliseconds\n            maxInterval: 0, // max allowed interval in milliseconds\n            start: {},      // options for start picker\n            end: {}         // options for end picker\n        }, options);\n\n        // for the mean time this fixes an issue with calling getDate with timepicker()\n        var timeOnly = false;\n        if(method === 'timepicker'){\n            timeOnly = true;\n            method = 'datetimepicker';\n        }\n\n        function checkDates(changed, other) {\n            var startdt = startTime[method]('getDate'),\n                enddt = endTime[method]('getDate'),\n                changeddt = changed[method]('getDate');\n\n            if (startdt !== null) {\n                var minDate = new Date(startdt.getTime()),\n                    maxDate = new Date(startdt.getTime());\n\n                minDate.setMilliseconds(minDate.getMilliseconds() + options.minInterval);\n                maxDate.setMilliseconds(maxDate.getMilliseconds() + options.maxInterval);\n\n                if (options.minInterval > 0 && minDate > enddt) { // minInterval check\n                    endTime[method]('setDate', minDate);\n                }\n                else if (options.maxInterval > 0 && maxDate < enddt) { // max interval check\n                    endTime[method]('setDate', maxDate);\n                }\n                else if (startdt > enddt) {\n                    other[method]('setDate', changeddt);\n                }\n            }\n        }\n\n        function selected(changed, other, option) {\n            if (!changed.val()) {\n                return;\n            }\n            var date = changed[method].call(changed, 'getDate');\n            if (date !== null && options.minInterval > 0) {\n                if (option === 'minDate') {\n                    date.setMilliseconds(date.getMilliseconds() + options.minInterval);\n                }\n                if (option === 'maxDate') {\n                    date.setMilliseconds(date.getMilliseconds() - options.minInterval);\n                }\n            }\n\n            if (date.getTime) {\n                other[method].call(other, 'option', option, date);\n            }\n        }\n\n        $.fn[method].call(startTime, $.extend({\n            timeOnly: timeOnly,\n            onClose: function (dateText, inst) {\n                checkDates($(this), endTime);\n            },\n            onSelect: function (selectedDateTime) {\n                selected($(this), endTime, 'minDate');\n            }\n        }, options, options.start));\n        $.fn[method].call(endTime, $.extend({\n            timeOnly: timeOnly,\n            onClose: function (dateText, inst) {\n                checkDates($(this), startTime);\n            },\n            onSelect: function (selectedDateTime) {\n                selected($(this), startTime, 'maxDate');\n            }\n        }, options, options.end));\n\n        checkDates(startTime, endTime);\n\n        selected(startTime, endTime, 'minDate');\n        selected(endTime, startTime, 'maxDate');\n\n        return $([startTime.get(0), endTime.get(0)]);\n    };\n\n    /**\n     * Log error or data to the console during error or debugging\n     * @param  {Object} err pass any type object to log to the console during error or debugging\n     * @return {void}\n     */\n    $.timepicker.log = function () {\n        // Older IE (9, maybe 10) throw error on accessing `window.console.log.apply`, so check first.\n        if (window.console && window.console.log && window.console.log.apply) {\n            window.console.log.apply(window.console, Array.prototype.slice.call(arguments));\n        }\n    };\n\n    /*\n     * Add util object to allow access to private methods for testability.\n     */\n    $.timepicker._util = {\n        _extendRemove: extendRemove,\n        _isEmptyObject: isEmptyObject,\n        _convert24to12: convert24to12,\n        _detectSupport: detectSupport,\n        _selectLocalTimezone: selectLocalTimezone,\n        _computeEffectiveSetting: computeEffectiveSetting,\n        _splitDateTime: splitDateTime,\n        _parseDateTimeInternal: parseDateTimeInternal\n    };\n\n    /*\n    * Microsecond support\n    */\n    if (!Date.prototype.getMicroseconds) {\n        Date.prototype.microseconds = 0;\n        Date.prototype.getMicroseconds = function () { return this.microseconds; };\n        Date.prototype.setMicroseconds = function (m) {\n            this.setMilliseconds(this.getMilliseconds() + Math.floor(m / 1000));\n            this.microseconds = m % 1000;\n            return this;\n        };\n    }\n\n    /*\n    * Keep up with the version\n    */\n    $.timepicker.version = \"1.6.3\";\n\n}));\n","jquery/compat.js":"// Import every plugin under the sun. Bad for performance,\n// but prevents the store from breaking in situations\n// where a dependency was missed during the migration from\n// a monolith build of jQueryUI to a modular one\n\ndefine([\n    'jquery-ui-modules/core',\n    'jquery-ui-modules/accordion',\n    'jquery-ui-modules/autocomplete',\n    'jquery-ui-modules/button',\n    'jquery-ui-modules/datepicker',\n    'jquery-ui-modules/dialog',\n    'jquery-ui-modules/draggable',\n    'jquery-ui-modules/droppable',\n    'jquery-ui-modules/effect-blind',\n    'jquery-ui-modules/effect-bounce',\n    'jquery-ui-modules/effect-clip',\n    'jquery-ui-modules/effect-drop',\n    'jquery-ui-modules/effect-explode',\n    'jquery-ui-modules/effect-fade',\n    'jquery-ui-modules/effect-fold',\n    'jquery-ui-modules/effect-highlight',\n    'jquery-ui-modules/effect-scale',\n    'jquery-ui-modules/effect-pulsate',\n    'jquery-ui-modules/effect-shake',\n    'jquery-ui-modules/effect-slide',\n    'jquery-ui-modules/effect-transfer',\n    'jquery-ui-modules/effect',\n    'jquery-ui-modules/menu',\n    'jquery-ui-modules/mouse',\n    'jquery-ui-modules/position',\n    'jquery-ui-modules/progressbar',\n    'jquery-ui-modules/resizable',\n    'jquery-ui-modules/selectable',\n    'jquery-ui-modules/slider',\n    'jquery-ui-modules/sortable',\n    'jquery-ui-modules/spinner',\n    'jquery-ui-modules/tabs',\n    'jquery-ui-modules/timepicker',\n    'jquery-ui-modules/tooltip',\n    'jquery-ui-modules/widget'\n], function() {\n    console.warn(\n        'Fallback to JQueryUI Compat activated. ' +\n        'Your store is missing a dependency for a ' +\n        'jQueryUI widget. Identifying and addressing the dependency ' +\n        'will drastically improve the performance of your site.'\n    );\n});\n","jquery/jquery.cookie.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'js-cookie/cookie-wrapper'\n], function () {\n\n});\n","jquery/ui-modules/labels.js":"/*!\n * jQuery UI Labels 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: labels\n//>>group: Core\n//>>description: Find all the labels associated with a given input\n//>>docs: http://api.jqueryui.com/labels/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [ \"jquery\", \"./version\" ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.fn.labels = function() {\n        var ancestor, selector, id, labels, ancestors;\n\n        if ( !this.length ) {\n            return this.pushStack( [] );\n        }\n\n        // Check control.labels first\n        if ( this[ 0 ].labels && this[ 0 ].labels.length ) {\n            return this.pushStack( this[ 0 ].labels );\n        }\n\n        // Support: IE <= 11, FF <= 37, Android <= 2.3 only\n        // Above browsers do not support control.labels. Everything below is to support them\n        // as well as document fragments. control.labels does not work on document fragments\n        labels = this.eq( 0 ).parents( \"label\" );\n\n        // Look for the label based on the id\n        id = this.attr( \"id\" );\n        if ( id ) {\n\n            // We don't search against the document in case the element\n            // is disconnected from the DOM\n            ancestor = this.eq( 0 ).parents().last();\n\n            // Get a full set of top level ancestors\n            ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() );\n\n            // Create a selector for the label based on the id\n            selector = \"label[for='\" + $.escapeSelector( id ) + \"']\";\n\n            labels = labels.add( ancestors.find( selector ).addBack( selector ) );\n\n        }\n\n        // Return whatever we have found for labels\n        return this.pushStack( labels );\n    };\n\n} );\n","jquery/ui-modules/disable-selection.js":"/*!\n * jQuery UI Disable Selection 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: disableSelection\n//>>group: Core\n//>>description: Disable selection of text content within the set of matched elements.\n//>>docs: http://api.jqueryui.com/disableSelection/\n\n// This file is deprecated\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [ \"jquery\", \"./version\" ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.fn.extend( {\n        disableSelection: ( function() {\n            var eventType = \"onselectstart\" in document.createElement( \"div\" ) ?\n                \"selectstart\" :\n                \"mousedown\";\n\n            return function() {\n                return this.on( eventType + \".ui-disableSelection\", function( event ) {\n                    event.preventDefault();\n                } );\n            };\n        } )(),\n\n        enableSelection: function() {\n            return this.off( \".ui-disableSelection\" );\n        }\n    } );\n\n} );\n","jquery/ui-modules/ie.js":"( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"jquery\", \"./version\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery );\n\t}\n} )( function( $ ) {\n\"use strict\";\n\n// This file is deprecated\nreturn $.ui.ie = !!/msie [\\w.]+/.exec( navigator.userAgent.toLowerCase() );\n} );\n","jquery/ui-modules/form.js":"( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"jquery\", \"./version\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery );\n\t}\n} )( function( $ ) {\n\"use strict\";\n\n// Support: IE8 Only\n// IE8 does not support the form attribute and when it is supplied. It overwrites the form prop\n// with a string, so we need to find the proper form.\nreturn $.fn._form = function() {\n\treturn typeof this[ 0 ].form === \"string\" ? this.closest( \"form\" ) : $( this[ 0 ].form );\n};\n\n} );\n","jquery/ui-modules/data.js":"/*!\n * jQuery UI :data 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: :data Selector\n//>>group: Core\n//>>description: Selects elements which have data stored under the specified key.\n//>>docs: http://api.jqueryui.com/data-selector/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [ \"jquery\", \"./version\" ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.extend( $.expr.pseudos, {\n        data: $.expr.createPseudo ?\n            $.expr.createPseudo( function( dataName ) {\n                return function( elem ) {\n                    return !!$.data( elem, dataName );\n                };\n            } ) :\n\n            // Support: jQuery <1.8\n            function( elem, i, match ) {\n                return !!$.data( elem, match[ 3 ] );\n            }\n    } );\n} );\n","jquery/ui-modules/safe-active-element.js":"( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"jquery\", \"./version\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery );\n\t}\n} )( function( $ ) {\n\"use strict\";\n\nreturn $.ui.safeActiveElement = function( document ) {\n\tvar activeElement;\n\n\t// Support: IE 9 only\n\t// IE9 throws an \"Unspecified error\" accessing document.activeElement from an <iframe>\n\ttry {\n\t\tactiveElement = document.activeElement;\n\t} catch ( error ) {\n\t\tactiveElement = document.body;\n\t}\n\n\t// Support: IE 9 - 11 only\n\t// IE may return null instead of an element\n\t// Interestingly, this only seems to occur when NOT in an iframe\n\tif ( !activeElement ) {\n\t\tactiveElement = document.body;\n\t}\n\n\t// Support: IE 11 only\n\t// IE11 returns a seemingly empty object in some cases when accessing\n\t// document.activeElement from an <iframe>\n\tif ( !activeElement.nodeName ) {\n\t\tactiveElement = document.body;\n\t}\n\n\treturn activeElement;\n};\n\n} );\n","jquery/ui-modules/version.js":"( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [ \"jquery\" ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    $.ui = $.ui || {};\n\n    return $.ui.version = \"1.13.2\";\n\n} );\n","jquery/ui-modules/scroll-parent.js":"/*!\n * jQuery UI Scroll Parent 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: scrollParent\n//>>group: Core\n//>>description: Get the closest ancestor element that is scrollable.\n//>>docs: http://api.jqueryui.com/scrollParent/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [ \"jquery\", \"./version\" ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.fn.scrollParent = function( includeHidden ) {\n        var position = this.css( \"position\" ),\n            excludeStaticParent = position === \"absolute\",\n            overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,\n            scrollParent = this.parents().filter( function() {\n                var parent = $( this );\n                if ( excludeStaticParent && parent.css( \"position\" ) === \"static\" ) {\n                    return false;\n                }\n                return overflowRegex.test( parent.css( \"overflow\" ) + parent.css( \"overflow-y\" ) +\n                    parent.css( \"overflow-x\" ) );\n            } ).eq( 0 );\n\n        return position === \"fixed\" || !scrollParent.length ?\n            $( this[ 0 ].ownerDocument || document ) :\n            scrollParent;\n    };\n\n} );\n","jquery/ui-modules/focusable.js":"/*!\n * jQuery UI Focusable 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: :focusable Selector\n//>>group: Core\n//>>description: Selects elements which can be focused.\n//>>docs: http://api.jqueryui.com/focusable-selector/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [ \"jquery\", \"./version\" ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n// Selectors\n    $.ui.focusable = function( element, hasTabindex ) {\n        var map, mapName, img, focusableIfVisible, fieldset,\n            nodeName = element.nodeName.toLowerCase();\n\n        if ( \"area\" === nodeName ) {\n            map = element.parentNode;\n            mapName = map.name;\n            if ( !element.href || !mapName || map.nodeName.toLowerCase() !== \"map\" ) {\n                return false;\n            }\n            img = $( \"img[usemap='#\" + mapName + \"']\" );\n            return img.length > 0 && img.is( \":visible\" );\n        }\n\n        if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) {\n            focusableIfVisible = !element.disabled;\n\n            if ( focusableIfVisible ) {\n\n                // Form controls within a disabled fieldset are disabled.\n                // However, controls within the fieldset's legend do not get disabled.\n                // Since controls generally aren't placed inside legends, we skip\n                // this portion of the check.\n                fieldset = $( element ).closest( \"fieldset\" )[ 0 ];\n                if ( fieldset ) {\n                    focusableIfVisible = !fieldset.disabled;\n                }\n            }\n        } else if ( \"a\" === nodeName ) {\n            focusableIfVisible = element.href || hasTabindex;\n        } else {\n            focusableIfVisible = hasTabindex;\n        }\n\n        return focusableIfVisible && $( element ).is( \":visible\" ) && visible( $( element ) );\n    };\n\n// Support: IE 8 only\n// IE 8 doesn't resolve inherit to visible/hidden for computed values\n    function visible( element ) {\n        var visibility = element.css( \"visibility\" );\n        while ( visibility === \"inherit\" ) {\n            element = element.parent();\n            visibility = element.css( \"visibility\" );\n        }\n        return visibility === \"visible\";\n    }\n\n    $.extend( $.expr.pseudos, {\n        focusable: function( element ) {\n            return $.ui.focusable( element, $.attr( element, \"tabindex\" ) != null );\n        }\n    } );\n\n    return $.ui.focusable;\n\n} );\n","jquery/ui-modules/keycode.js":"/*!\n * jQuery UI Keycode 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Keycode\n//>>group: Core\n//>>description: Provide keycodes as keynames\n//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [ \"jquery\", \"./version\" ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.ui.keyCode = {\n        BACKSPACE: 8,\n        COMMA: 188,\n        DELETE: 46,\n        DOWN: 40,\n        END: 35,\n        ENTER: 13,\n        ESCAPE: 27,\n        HOME: 36,\n        LEFT: 37,\n        PAGE_DOWN: 34,\n        PAGE_UP: 33,\n        PERIOD: 190,\n        RIGHT: 39,\n        SPACE: 32,\n        TAB: 9,\n        UP: 38\n    };\n\n} );\n","jquery/ui-modules/plugin.js":"( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"jquery\", \"./version\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery );\n\t}\n} )( function( $ ) {\n\"use strict\";\n\n// $.ui.plugin is deprecated. Use $.widget() extensions instead.\nreturn $.ui.plugin = {\n\tadd: function( module, option, set ) {\n\t\tvar i,\n\t\t\tproto = $.ui[ module ].prototype;\n\t\tfor ( i in set ) {\n\t\t\tproto.plugins[ i ] = proto.plugins[ i ] || [];\n\t\t\tproto.plugins[ i ].push( [ option, set[ i ] ] );\n\t\t}\n\t},\n\tcall: function( instance, name, args, allowDisconnected ) {\n\t\tvar i,\n\t\t\tset = instance.plugins[ name ];\n\n\t\tif ( !set ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !allowDisconnected && ( !instance.element[ 0 ].parentNode ||\n\t\t\t\tinstance.element[ 0 ].parentNode.nodeType === 11 ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( i = 0; i < set.length; i++ ) {\n\t\t\tif ( instance.options[ set[ i ][ 0 ] ] ) {\n\t\t\t\tset[ i ][ 1 ].apply( instance.element, args );\n\t\t\t}\n\t\t}\n\t}\n};\n\n} );\n","jquery/ui-modules/jquery-patch.js":"/*!\n * jQuery UI Support for jQuery core 1.8.x and newer 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n *\n */\n\n//>>label: jQuery 1.8+ Support\n//>>group: Core\n//>>description: Support version 1.8.x and newer of jQuery core\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [ \"jquery\", \"./version\" ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n// Support: jQuery 1.9.x or older\n// $.expr[ \":\" ] is deprecated.\n    if ( !$.expr.pseudos ) {\n        $.expr.pseudos = $.expr[ \":\" ];\n    }\n\n// Support: jQuery 1.11.x or older\n// $.unique has been renamed to $.uniqueSort\n    if ( !$.uniqueSort ) {\n        $.uniqueSort = $.unique;\n    }\n\n// Support: jQuery 2.2.x or older.\n// This method has been defined in jQuery 3.0.0.\n// Code from https://github.com/jquery/jquery/blob/e539bac79e666bba95bba86d690b4e609dca2286/src/selector/escapeSelector.js\n    if ( !$.escapeSelector ) {\n\n        // CSS string/identifier serialization\n        // https://drafts.csswg.org/cssom/#common-serializing-idioms\n        var rcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\x80-\\uFFFF\\w-]/g;\n\n        var fcssescape = function( ch, asCodePoint ) {\n            if ( asCodePoint ) {\n\n                // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\n                if ( ch === \"\\0\" ) {\n                    return \"\\uFFFD\";\n                }\n\n                // Control characters and (dependent upon position) numbers get escaped as code points\n                return ch.slice( 0, -1 ) + \"\\\\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + \" \";\n            }\n\n            // Other potentially-special ASCII characters get backslash-escaped\n            return \"\\\\\" + ch;\n        };\n\n        $.escapeSelector = function( sel ) {\n            return ( sel + \"\" ).replace( rcssescape, fcssescape );\n        };\n    }\n\n// Support: jQuery 3.4.x or older\n// These methods have been defined in jQuery 3.5.0.\n    if ( !$.fn.even || !$.fn.odd ) {\n        $.fn.extend( {\n            even: function() {\n                return this.filter( function( i ) {\n                    return i % 2 === 0;\n                } );\n            },\n            odd: function() {\n                return this.filter( function( i ) {\n                    return i % 2 === 1;\n                } );\n            }\n        } );\n    }\n\n} );\n","jquery/ui-modules/safe-blur.js":"( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"jquery\", \"./version\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery );\n\t}\n} )( function( $ ) {\n\"use strict\";\n\nreturn $.ui.safeBlur = function( element ) {\n\n\t// Support: IE9 - 10 only\n\t// If the <body> is blurred, IE will switch windows, see #9420\n\tif ( element && element.nodeName.toLowerCase() !== \"body\" ) {\n\t\t$( element ).trigger( \"blur\" );\n\t}\n};\n\n} );\n","jquery/ui-modules/effect.js":"/*!\n * jQuery UI Effects 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Effects Core\n//>>group: Effects\n/* eslint-disable max-len */\n//>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects.\n/* eslint-enable max-len */\n//>>docs: http://api.jqueryui.com/category/effects-core/\n//>>demos: http://jqueryui.com/effect/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [\n            \"jquery\",\n            \"./jquery-var-for-color\",\n            \"./vendor/jquery-color/jquery.color\",\n            \"./version\"\n        ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    var dataSpace = \"ui-effects-\",\n        dataSpaceStyle = \"ui-effects-style\",\n        dataSpaceAnimated = \"ui-effects-animated\";\n\n    $.effects = {\n        effect: {}\n    };\n\n    /******************************************************************************/\n    /****************************** CLASS ANIMATIONS ******************************/\n    /******************************************************************************/\n    ( function() {\n\n        var classAnimationActions = [ \"add\", \"remove\", \"toggle\" ],\n            shorthandStyles = {\n                border: 1,\n                borderBottom: 1,\n                borderColor: 1,\n                borderLeft: 1,\n                borderRight: 1,\n                borderTop: 1,\n                borderWidth: 1,\n                margin: 1,\n                padding: 1\n            };\n\n        $.each(\n            [ \"borderLeftStyle\", \"borderRightStyle\", \"borderBottomStyle\", \"borderTopStyle\" ],\n            function( _, prop ) {\n                $.fx.step[ prop ] = function( fx ) {\n                    if ( fx.end !== \"none\" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {\n                        jQuery.style( fx.elem, prop, fx.end );\n                        fx.setAttr = true;\n                    }\n                };\n            }\n        );\n\n        function camelCase( string ) {\n            return string.replace( /-([\\da-z])/gi, function( all, letter ) {\n                return letter.toUpperCase();\n            } );\n        }\n\n        function getElementStyles( elem ) {\n            var key, len,\n                style = elem.ownerDocument.defaultView ?\n                    elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :\n                    elem.currentStyle,\n                styles = {};\n\n            if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {\n                len = style.length;\n                while ( len-- ) {\n                    key = style[ len ];\n                    if ( typeof style[ key ] === \"string\" ) {\n                        styles[ camelCase( key ) ] = style[ key ];\n                    }\n                }\n\n                // Support: Opera, IE <9\n            } else {\n                for ( key in style ) {\n                    if ( typeof style[ key ] === \"string\" ) {\n                        styles[ key ] = style[ key ];\n                    }\n                }\n            }\n\n            return styles;\n        }\n\n        function styleDifference( oldStyle, newStyle ) {\n            var diff = {},\n                name, value;\n\n            for ( name in newStyle ) {\n                value = newStyle[ name ];\n                if ( oldStyle[ name ] !== value ) {\n                    if ( !shorthandStyles[ name ] ) {\n                        if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {\n                            diff[ name ] = value;\n                        }\n                    }\n                }\n            }\n\n            return diff;\n        }\n\n// Support: jQuery <1.8\n        if ( !$.fn.addBack ) {\n            $.fn.addBack = function( selector ) {\n                return this.add( selector == null ?\n                    this.prevObject : this.prevObject.filter( selector )\n                );\n            };\n        }\n\n        $.effects.animateClass = function( value, duration, easing, callback ) {\n            var o = $.speed( duration, easing, callback );\n\n            return this.queue( function() {\n                var animated = $( this ),\n                    baseClass = animated.attr( \"class\" ) || \"\",\n                    applyClassChange,\n                    allAnimations = o.children ? animated.find( \"*\" ).addBack() : animated;\n\n                // Map the animated objects to store the original styles.\n                allAnimations = allAnimations.map( function() {\n                    var el = $( this );\n                    return {\n                        el: el,\n                        start: getElementStyles( this )\n                    };\n                } );\n\n                // Apply class change\n                applyClassChange = function() {\n                    $.each( classAnimationActions, function( i, action ) {\n                        if ( value[ action ] ) {\n                            animated[ action + \"Class\" ]( value[ action ] );\n                        }\n                    } );\n                };\n                applyClassChange();\n\n                // Map all animated objects again - calculate new styles and diff\n                allAnimations = allAnimations.map( function() {\n                    this.end = getElementStyles( this.el[ 0 ] );\n                    this.diff = styleDifference( this.start, this.end );\n                    return this;\n                } );\n\n                // Apply original class\n                animated.attr( \"class\", baseClass );\n\n                // Map all animated objects again - this time collecting a promise\n                allAnimations = allAnimations.map( function() {\n                    var styleInfo = this,\n                        dfd = $.Deferred(),\n                        opts = $.extend( {}, o, {\n                            queue: false,\n                            complete: function() {\n                                dfd.resolve( styleInfo );\n                            }\n                        } );\n\n                    this.el.animate( this.diff, opts );\n                    return dfd.promise();\n                } );\n\n                // Once all animations have completed:\n                $.when.apply( $, allAnimations.get() ).done( function() {\n\n                    // Set the final class\n                    applyClassChange();\n\n                    // For each animated element,\n                    // clear all css properties that were animated\n                    $.each( arguments, function() {\n                        var el = this.el;\n                        $.each( this.diff, function( key ) {\n                            el.css( key, \"\" );\n                        } );\n                    } );\n\n                    // This is guarnteed to be there if you use jQuery.speed()\n                    // it also handles dequeuing the next anim...\n                    o.complete.call( animated[ 0 ] );\n                } );\n            } );\n        };\n\n        $.fn.extend( {\n            addClass: ( function( orig ) {\n                return function( classNames, speed, easing, callback ) {\n                    return speed ?\n                        $.effects.animateClass.call( this,\n                            { add: classNames }, speed, easing, callback ) :\n                        orig.apply( this, arguments );\n                };\n            } )( $.fn.addClass ),\n\n            removeClass: ( function( orig ) {\n                return function( classNames, speed, easing, callback ) {\n                    return arguments.length > 1 ?\n                        $.effects.animateClass.call( this,\n                            { remove: classNames }, speed, easing, callback ) :\n                        orig.apply( this, arguments );\n                };\n            } )( $.fn.removeClass ),\n\n            toggleClass: ( function( orig ) {\n                return function( classNames, force, speed, easing, callback ) {\n                    if ( typeof force === \"boolean\" || force === undefined ) {\n                        if ( !speed ) {\n\n                            // Without speed parameter\n                            return orig.apply( this, arguments );\n                        } else {\n                            return $.effects.animateClass.call( this,\n                                ( force ? { add: classNames } : { remove: classNames } ),\n                                speed, easing, callback );\n                        }\n                    } else {\n\n                        // Without force parameter\n                        return $.effects.animateClass.call( this,\n                            { toggle: classNames }, force, speed, easing );\n                    }\n                };\n            } )( $.fn.toggleClass ),\n\n            switchClass: function( remove, add, speed, easing, callback ) {\n                return $.effects.animateClass.call( this, {\n                    add: add,\n                    remove: remove\n                }, speed, easing, callback );\n            }\n        } );\n\n    } )();\n\n    /******************************************************************************/\n    /*********************************** EFFECTS **********************************/\n    /******************************************************************************/\n\n    ( function() {\n\n        if ( $.expr && $.expr.pseudos && $.expr.pseudos.animated ) {\n            $.expr.pseudos.animated = ( function( orig ) {\n                return function( elem ) {\n                    return !!$( elem ).data( dataSpaceAnimated ) || orig( elem );\n                };\n            } )( $.expr.pseudos.animated );\n        }\n\n        if ( $.uiBackCompat !== false ) {\n            $.extend( $.effects, {\n\n                // Saves a set of properties in a data storage\n                save: function( element, set ) {\n                    var i = 0, length = set.length;\n                    for ( ; i < length; i++ ) {\n                        if ( set[ i ] !== null ) {\n                            element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );\n                        }\n                    }\n                },\n\n                // Restores a set of previously saved properties from a data storage\n                restore: function( element, set ) {\n                    var val, i = 0, length = set.length;\n                    for ( ; i < length; i++ ) {\n                        if ( set[ i ] !== null ) {\n                            val = element.data( dataSpace + set[ i ] );\n                            element.css( set[ i ], val );\n                        }\n                    }\n                },\n\n                setMode: function( el, mode ) {\n                    if ( mode === \"toggle\" ) {\n                        mode = el.is( \":hidden\" ) ? \"show\" : \"hide\";\n                    }\n                    return mode;\n                },\n\n                // Wraps the element around a wrapper that copies position properties\n                createWrapper: function( element ) {\n\n                    // If the element is already wrapped, return it\n                    if ( element.parent().is( \".ui-effects-wrapper\" ) ) {\n                        return element.parent();\n                    }\n\n                    // Wrap the element\n                    var props = {\n                            width: element.outerWidth( true ),\n                            height: element.outerHeight( true ),\n                            \"float\": element.css( \"float\" )\n                        },\n                        wrapper = $( \"<div></div>\" )\n                            .addClass( \"ui-effects-wrapper\" )\n                            .css( {\n                                fontSize: \"100%\",\n                                background: \"transparent\",\n                                border: \"none\",\n                                margin: 0,\n                                padding: 0\n                            } ),\n\n                        // Store the size in case width/height are defined in % - Fixes #5245\n                        size = {\n                            width: element.width(),\n                            height: element.height()\n                        },\n                        active = document.activeElement;\n\n                    // Support: Firefox\n                    // Firefox incorrectly exposes anonymous content\n                    // https://bugzilla.mozilla.org/show_bug.cgi?id=561664\n                    try {\n                        // eslint-disable-next-line no-unused-expressions\n                        active.id;\n                    } catch ( e ) {\n                        active = document.body;\n                    }\n\n                    element.wrap( wrapper );\n\n                    // Fixes #7595 - Elements lose focus when wrapped.\n                    if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {\n                        $( active ).trigger( \"focus\" );\n                    }\n\n                    // Hotfix for jQuery 1.4 since some change in wrap() seems to actually\n                    // lose the reference to the wrapped element\n                    wrapper = element.parent();\n\n                    // Transfer positioning properties to the wrapper\n                    if ( element.css( \"position\" ) === \"static\" ) {\n                        wrapper.css( { position: \"relative\" } );\n                        element.css( { position: \"relative\" } );\n                    } else {\n                        $.extend( props, {\n                            position: element.css( \"position\" ),\n                            zIndex: element.css( \"z-index\" )\n                        } );\n                        $.each( [ \"top\", \"left\", \"bottom\", \"right\" ], function( i, pos ) {\n                            props[ pos ] = element.css( pos );\n                            if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {\n                                props[ pos ] = \"auto\";\n                            }\n                        } );\n                        element.css( {\n                            position: \"relative\",\n                            top: 0,\n                            left: 0,\n                            right: \"auto\",\n                            bottom: \"auto\"\n                        } );\n                    }\n                    element.css( size );\n\n                    return wrapper.css( props ).show();\n                },\n\n                removeWrapper: function( element ) {\n                    var active = document.activeElement;\n\n                    if ( element.parent().is( \".ui-effects-wrapper\" ) ) {\n                        element.parent().replaceWith( element );\n\n                        // Fixes #7595 - Elements lose focus when wrapped.\n                        if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {\n                            $( active ).trigger( \"focus\" );\n                        }\n                    }\n\n                    return element;\n                }\n            } );\n        }\n\n        $.extend( $.effects, {\n            version: \"1.13.2\",\n\n            define: function( name, mode, effect ) {\n                if ( !effect ) {\n                    effect = mode;\n                    mode = \"effect\";\n                }\n\n                $.effects.effect[ name ] = effect;\n                $.effects.effect[ name ].mode = mode;\n\n                return effect;\n            },\n\n            scaledDimensions: function( element, percent, direction ) {\n                if ( percent === 0 ) {\n                    return {\n                        height: 0,\n                        width: 0,\n                        outerHeight: 0,\n                        outerWidth: 0\n                    };\n                }\n\n                var x = direction !== \"horizontal\" ? ( ( percent || 100 ) / 100 ) : 1,\n                    y = direction !== \"vertical\" ? ( ( percent || 100 ) / 100 ) : 1;\n\n                return {\n                    height: element.height() * y,\n                    width: element.width() * x,\n                    outerHeight: element.outerHeight() * y,\n                    outerWidth: element.outerWidth() * x\n                };\n\n            },\n\n            clipToBox: function( animation ) {\n                return {\n                    width: animation.clip.right - animation.clip.left,\n                    height: animation.clip.bottom - animation.clip.top,\n                    left: animation.clip.left,\n                    top: animation.clip.top\n                };\n            },\n\n            // Injects recently queued functions to be first in line (after \"inprogress\")\n            unshift: function( element, queueLength, count ) {\n                var queue = element.queue();\n\n                if ( queueLength > 1 ) {\n                    queue.splice.apply( queue,\n                        [ 1, 0 ].concat( queue.splice( queueLength, count ) ) );\n                }\n                element.dequeue();\n            },\n\n            saveStyle: function( element ) {\n                element.data( dataSpaceStyle, element[ 0 ].style.cssText );\n            },\n\n            restoreStyle: function( element ) {\n                element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || \"\";\n                element.removeData( dataSpaceStyle );\n            },\n\n            mode: function( element, mode ) {\n                var hidden = element.is( \":hidden\" );\n\n                if ( mode === \"toggle\" ) {\n                    mode = hidden ? \"show\" : \"hide\";\n                }\n                if ( hidden ? mode === \"hide\" : mode === \"show\" ) {\n                    mode = \"none\";\n                }\n                return mode;\n            },\n\n            // Translates a [top,left] array into a baseline value\n            getBaseline: function( origin, original ) {\n                var y, x;\n\n                switch ( origin[ 0 ] ) {\n                    case \"top\":\n                        y = 0;\n                        break;\n                    case \"middle\":\n                        y = 0.5;\n                        break;\n                    case \"bottom\":\n                        y = 1;\n                        break;\n                    default:\n                        y = origin[ 0 ] / original.height;\n                }\n\n                switch ( origin[ 1 ] ) {\n                    case \"left\":\n                        x = 0;\n                        break;\n                    case \"center\":\n                        x = 0.5;\n                        break;\n                    case \"right\":\n                        x = 1;\n                        break;\n                    default:\n                        x = origin[ 1 ] / original.width;\n                }\n\n                return {\n                    x: x,\n                    y: y\n                };\n            },\n\n            // Creates a placeholder element so that the original element can be made absolute\n            createPlaceholder: function( element ) {\n                var placeholder,\n                    cssPosition = element.css( \"position\" ),\n                    position = element.position();\n\n                // Lock in margins first to account for form elements, which\n                // will change margin if you explicitly set height\n                // see: http://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380\n                // Support: Safari\n                element.css( {\n                    marginTop: element.css( \"marginTop\" ),\n                    marginBottom: element.css( \"marginBottom\" ),\n                    marginLeft: element.css( \"marginLeft\" ),\n                    marginRight: element.css( \"marginRight\" )\n                } )\n                    .outerWidth( element.outerWidth() )\n                    .outerHeight( element.outerHeight() );\n\n                if ( /^(static|relative)/.test( cssPosition ) ) {\n                    cssPosition = \"absolute\";\n\n                    placeholder = $( \"<\" + element[ 0 ].nodeName + \">\" ).insertAfter( element ).css( {\n\n                        // Convert inline to inline block to account for inline elements\n                        // that turn to inline block based on content (like img)\n                        display: /^(inline|ruby)/.test( element.css( \"display\" ) ) ?\n                            \"inline-block\" :\n                            \"block\",\n                        visibility: \"hidden\",\n\n                        // Margins need to be set to account for margin collapse\n                        marginTop: element.css( \"marginTop\" ),\n                        marginBottom: element.css( \"marginBottom\" ),\n                        marginLeft: element.css( \"marginLeft\" ),\n                        marginRight: element.css( \"marginRight\" ),\n                        \"float\": element.css( \"float\" )\n                    } )\n                        .outerWidth( element.outerWidth() )\n                        .outerHeight( element.outerHeight() )\n                        .addClass( \"ui-effects-placeholder\" );\n\n                    element.data( dataSpace + \"placeholder\", placeholder );\n                }\n\n                element.css( {\n                    position: cssPosition,\n                    left: position.left,\n                    top: position.top\n                } );\n\n                return placeholder;\n            },\n\n            removePlaceholder: function( element ) {\n                var dataKey = dataSpace + \"placeholder\",\n                    placeholder = element.data( dataKey );\n\n                if ( placeholder ) {\n                    placeholder.remove();\n                    element.removeData( dataKey );\n                }\n            },\n\n            // Removes a placeholder if it exists and restores\n            // properties that were modified during placeholder creation\n            cleanUp: function( element ) {\n                $.effects.restoreStyle( element );\n                $.effects.removePlaceholder( element );\n            },\n\n            setTransition: function( element, list, factor, value ) {\n                value = value || {};\n                $.each( list, function( i, x ) {\n                    var unit = element.cssUnit( x );\n                    if ( unit[ 0 ] > 0 ) {\n                        value[ x ] = unit[ 0 ] * factor + unit[ 1 ];\n                    }\n                } );\n                return value;\n            }\n        } );\n\n// Return an effect options object for the given parameters:\n        function _normalizeArguments( effect, options, speed, callback ) {\n\n            // Allow passing all options as the first parameter\n            if ( $.isPlainObject( effect ) ) {\n                options = effect;\n                effect = effect.effect;\n            }\n\n            // Convert to an object\n            effect = { effect: effect };\n\n            // Catch (effect, null, ...)\n            if ( options == null ) {\n                options = {};\n            }\n\n            // Catch (effect, callback)\n            if ( typeof options === \"function\" ) {\n                callback = options;\n                speed = null;\n                options = {};\n            }\n\n            // Catch (effect, speed, ?)\n            if ( typeof options === \"number\" || $.fx.speeds[ options ] ) {\n                callback = speed;\n                speed = options;\n                options = {};\n            }\n\n            // Catch (effect, options, callback)\n            if ( typeof speed === \"function\" ) {\n                callback = speed;\n                speed = null;\n            }\n\n            // Add options to effect\n            if ( options ) {\n                $.extend( effect, options );\n            }\n\n            speed = speed || options.duration;\n            effect.duration = $.fx.off ? 0 :\n                typeof speed === \"number\" ? speed :\n                    speed in $.fx.speeds ? $.fx.speeds[ speed ] :\n                        $.fx.speeds._default;\n\n            effect.complete = callback || options.complete;\n\n            return effect;\n        }\n\n        function standardAnimationOption( option ) {\n\n            // Valid standard speeds (nothing, number, named speed)\n            if ( !option || typeof option === \"number\" || $.fx.speeds[ option ] ) {\n                return true;\n            }\n\n            // Invalid strings - treat as \"normal\" speed\n            if ( typeof option === \"string\" && !$.effects.effect[ option ] ) {\n                return true;\n            }\n\n            // Complete callback\n            if ( typeof option === \"function\" ) {\n                return true;\n            }\n\n            // Options hash (but not naming an effect)\n            if ( typeof option === \"object\" && !option.effect ) {\n                return true;\n            }\n\n            // Didn't match any standard API\n            return false;\n        }\n\n        $.fn.extend( {\n            effect: function( /* effect, options, speed, callback */ ) {\n                var args = _normalizeArguments.apply( this, arguments ),\n                    effectMethod = $.effects.effect[ args.effect ],\n                    defaultMode = effectMethod.mode,\n                    queue = args.queue,\n                    queueName = queue || \"fx\",\n                    complete = args.complete,\n                    mode = args.mode,\n                    modes = [],\n                    prefilter = function( next ) {\n                        var el = $( this ),\n                            normalizedMode = $.effects.mode( el, mode ) || defaultMode;\n\n                        // Sentinel for duck-punching the :animated pseudo-selector\n                        el.data( dataSpaceAnimated, true );\n\n                        // Save effect mode for later use,\n                        // we can't just call $.effects.mode again later,\n                        // as the .show() below destroys the initial state\n                        modes.push( normalizedMode );\n\n                        // See $.uiBackCompat inside of run() for removal of defaultMode in 1.14\n                        if ( defaultMode && ( normalizedMode === \"show\" ||\n                            ( normalizedMode === defaultMode && normalizedMode === \"hide\" ) ) ) {\n                            el.show();\n                        }\n\n                        if ( !defaultMode || normalizedMode !== \"none\" ) {\n                            $.effects.saveStyle( el );\n                        }\n\n                        if ( typeof next === \"function\" ) {\n                            next();\n                        }\n                    };\n\n                if ( $.fx.off || !effectMethod ) {\n\n                    // Delegate to the original method (e.g., .show()) if possible\n                    if ( mode ) {\n                        return this[ mode ]( args.duration, complete );\n                    } else {\n                        return this.each( function() {\n                            if ( complete ) {\n                                complete.call( this );\n                            }\n                        } );\n                    }\n                }\n\n                function run( next ) {\n                    var elem = $( this );\n\n                    function cleanup() {\n                        elem.removeData( dataSpaceAnimated );\n\n                        $.effects.cleanUp( elem );\n\n                        if ( args.mode === \"hide\" ) {\n                            elem.hide();\n                        }\n\n                        done();\n                    }\n\n                    function done() {\n                        if ( typeof complete === \"function\" ) {\n                            complete.call( elem[ 0 ] );\n                        }\n\n                        if ( typeof next === \"function\" ) {\n                            next();\n                        }\n                    }\n\n                    // Override mode option on a per element basis,\n                    // as toggle can be either show or hide depending on element state\n                    args.mode = modes.shift();\n\n                    if ( $.uiBackCompat !== false && !defaultMode ) {\n                        if ( elem.is( \":hidden\" ) ? mode === \"hide\" : mode === \"show\" ) {\n\n                            // Call the core method to track \"olddisplay\" properly\n                            elem[ mode ]();\n                            done();\n                        } else {\n                            effectMethod.call( elem[ 0 ], args, done );\n                        }\n                    } else {\n                        if ( args.mode === \"none\" ) {\n\n                            // Call the core method to track \"olddisplay\" properly\n                            elem[ mode ]();\n                            done();\n                        } else {\n                            effectMethod.call( elem[ 0 ], args, cleanup );\n                        }\n                    }\n                }\n\n                // Run prefilter on all elements first to ensure that\n                // any showing or hiding happens before placeholder creation,\n                // which ensures that any layout changes are correctly captured.\n                return queue === false ?\n                    this.each( prefilter ).each( run ) :\n                    this.queue( queueName, prefilter ).queue( queueName, run );\n            },\n\n            show: ( function( orig ) {\n                return function( option ) {\n                    if ( standardAnimationOption( option ) ) {\n                        return orig.apply( this, arguments );\n                    } else {\n                        var args = _normalizeArguments.apply( this, arguments );\n                        args.mode = \"show\";\n                        return this.effect.call( this, args );\n                    }\n                };\n            } )( $.fn.show ),\n\n            hide: ( function( orig ) {\n                return function( option ) {\n                    if ( standardAnimationOption( option ) ) {\n                        return orig.apply( this, arguments );\n                    } else {\n                        var args = _normalizeArguments.apply( this, arguments );\n                        args.mode = \"hide\";\n                        return this.effect.call( this, args );\n                    }\n                };\n            } )( $.fn.hide ),\n\n            toggle: ( function( orig ) {\n                return function( option ) {\n                    if ( standardAnimationOption( option ) || typeof option === \"boolean\" ) {\n                        return orig.apply( this, arguments );\n                    } else {\n                        var args = _normalizeArguments.apply( this, arguments );\n                        args.mode = \"toggle\";\n                        return this.effect.call( this, args );\n                    }\n                };\n            } )( $.fn.toggle ),\n\n            cssUnit: function( key ) {\n                var style = this.css( key ),\n                    val = [];\n\n                $.each( [ \"em\", \"px\", \"%\", \"pt\" ], function( i, unit ) {\n                    if ( style.indexOf( unit ) > 0 ) {\n                        val = [ parseFloat( style ), unit ];\n                    }\n                } );\n                return val;\n            },\n\n            cssClip: function( clipObj ) {\n                if ( clipObj ) {\n                    return this.css( \"clip\", \"rect(\" + clipObj.top + \"px \" + clipObj.right + \"px \" +\n                        clipObj.bottom + \"px \" + clipObj.left + \"px)\" );\n                }\n                return parseClip( this.css( \"clip\" ), this );\n            },\n\n            transfer: function( options, done ) {\n                var element = $( this ),\n                    target = $( options.to ),\n                    targetFixed = target.css( \"position\" ) === \"fixed\",\n                    body = $( \"body\" ),\n                    fixTop = targetFixed ? body.scrollTop() : 0,\n                    fixLeft = targetFixed ? body.scrollLeft() : 0,\n                    endPosition = target.offset(),\n                    animation = {\n                        top: endPosition.top - fixTop,\n                        left: endPosition.left - fixLeft,\n                        height: target.innerHeight(),\n                        width: target.innerWidth()\n                    },\n                    startPosition = element.offset(),\n                    transfer = $( \"<div class='ui-effects-transfer'></div>\" );\n\n                transfer\n                    .appendTo( \"body\" )\n                    .addClass( options.className )\n                    .css( {\n                        top: startPosition.top - fixTop,\n                        left: startPosition.left - fixLeft,\n                        height: element.innerHeight(),\n                        width: element.innerWidth(),\n                        position: targetFixed ? \"fixed\" : \"absolute\"\n                    } )\n                    .animate( animation, options.duration, options.easing, function() {\n                        transfer.remove();\n                        if ( typeof done === \"function\" ) {\n                            done();\n                        }\n                    } );\n            }\n        } );\n\n        function parseClip( str, element ) {\n            var outerWidth = element.outerWidth(),\n                outerHeight = element.outerHeight(),\n                clipRegex = /^rect\\((-?\\d*\\.?\\d*px|-?\\d+%|auto),?\\s*(-?\\d*\\.?\\d*px|-?\\d+%|auto),?\\s*(-?\\d*\\.?\\d*px|-?\\d+%|auto),?\\s*(-?\\d*\\.?\\d*px|-?\\d+%|auto)\\)$/,\n                values = clipRegex.exec( str ) || [ \"\", 0, outerWidth, outerHeight, 0 ];\n\n            return {\n                top: parseFloat( values[ 1 ] ) || 0,\n                right: values[ 2 ] === \"auto\" ? outerWidth : parseFloat( values[ 2 ] ),\n                bottom: values[ 3 ] === \"auto\" ? outerHeight : parseFloat( values[ 3 ] ),\n                left: parseFloat( values[ 4 ] ) || 0\n            };\n        }\n\n        $.fx.step.clip = function( fx ) {\n            if ( !fx.clipInit ) {\n                fx.start = $( fx.elem ).cssClip();\n                if ( typeof fx.end === \"string\" ) {\n                    fx.end = parseClip( fx.end, fx.elem );\n                }\n                fx.clipInit = true;\n            }\n\n            $( fx.elem ).cssClip( {\n                top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top,\n                right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right,\n                bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom,\n                left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left\n            } );\n        };\n\n    } )();\n\n    /******************************************************************************/\n    /*********************************** EASING ***********************************/\n    /******************************************************************************/\n\n    ( function() {\n\n// Based on easing equations from Robert Penner (http://www.robertpenner.com/easing)\n\n        var baseEasings = {};\n\n        $.each( [ \"Quad\", \"Cubic\", \"Quart\", \"Quint\", \"Expo\" ], function( i, name ) {\n            baseEasings[ name ] = function( p ) {\n                return Math.pow( p, i + 2 );\n            };\n        } );\n\n        $.extend( baseEasings, {\n            Sine: function( p ) {\n                return 1 - Math.cos( p * Math.PI / 2 );\n            },\n            Circ: function( p ) {\n                return 1 - Math.sqrt( 1 - p * p );\n            },\n            Elastic: function( p ) {\n                return p === 0 || p === 1 ? p :\n                    -Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 );\n            },\n            Back: function( p ) {\n                return p * p * ( 3 * p - 2 );\n            },\n            Bounce: function( p ) {\n                var pow2,\n                    bounce = 4;\n\n                while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}\n                return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );\n            }\n        } );\n\n        $.each( baseEasings, function( name, easeIn ) {\n            $.easing[ \"easeIn\" + name ] = easeIn;\n            $.easing[ \"easeOut\" + name ] = function( p ) {\n                return 1 - easeIn( 1 - p );\n            };\n            $.easing[ \"easeInOut\" + name ] = function( p ) {\n                return p < 0.5 ?\n                    easeIn( p * 2 ) / 2 :\n                    1 - easeIn( p * -2 + 2 ) / 2;\n            };\n        } );\n\n    } )();\n\n    return $.effects;\n\n} );\n","jquery/ui-modules/jquery-var-for-color.js":"( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"jquery\", \"./version\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery );\n\t}\n} )( function( $ ) {\n\t\"use strict\";\n\n// Create a local jQuery because jQuery Color relies on it and the\n// global may not exist with AMD and a custom build (#10199).\n// This module is a noop if used as a regular AMD module.\n// eslint-disable-next-line no-unused-vars\nvar jQuery = $;\n\n} );\n"}
}});