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/bundle2.js
require.config({"config": {
        "jsbuild":{"Smartwave_Filterproducts/js/owl.carousel/owl.carousel.min.js":"/**\n * Owl Carousel v2.3.4\n * Copyright 2013-2018 David Deutsch\n * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE\n */!(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 (a) {\n    'use strict';\n    !function(a,b,c,d){function e(b,c){this.settings=null,this.options=a.extend({},e.Defaults,c),this.$element=a(b),this._handlers={},this._plugins={},this._supress={},this._current=null,this._speed=null,this._coordinates=[],this._breakpoint=null,this._width=null,this._items=[],this._clones=[],this._mergers=[],this._widths=[],this._invalidated={},this._pipe=[],this._drag={time:null,target:null,pointer:null,stage:{start:null,current:null},direction:null},this._states={current:{},tags:{initializing:[\"busy\"],animating:[\"busy\"],dragging:[\"interacting\"]}},a.each([\"onResize\",\"onThrottledResize\"],a.proxy(function(b,c){this._handlers[c]=a.proxy(this[c],this)},this)),a.each(e.Plugins,a.proxy(function(a,b){this._plugins[a.charAt(0).toLowerCase()+a.slice(1)]=new b(this)},this)),a.each(e.Workers,a.proxy(function(b,c){this._pipe.push({filter:c.filter,run:a.proxy(c.run,this)})},this)),this.setup(),this.initialize()}e.Defaults={items:3,loop:!1,center:!1,rewind:!1,checkVisibility:!0,mouseDrag:!0,touchDrag:!0,pullDrag:!0,freeDrag:!1,margin:0,stagePadding:0,merge:!1,mergeFit:!0,autoWidth:!1,startPosition:0,rtl:!1,smartSpeed:250,fluidSpeed:!1,dragEndSpeed:!1,responsive:{},responsiveRefreshRate:200,responsiveBaseElement:b,fallbackEasing:\"swing\",slideTransition:\"\",info:!1,nestedItemSelector:!1,itemElement:\"div\",stageElement:\"div\",refreshClass:\"owl-refresh\",loadedClass:\"owl-loaded\",loadingClass:\"owl-loading\",rtlClass:\"owl-rtl\",responsiveClass:\"owl-responsive\",dragClass:\"owl-drag\",itemClass:\"owl-item\",stageClass:\"owl-stage\",stageOuterClass:\"owl-stage-outer\",grabClass:\"owl-grab\"},e.Width={Default:\"default\",Inner:\"inner\",Outer:\"outer\"},e.Type={Event:\"event\",State:\"state\"},e.Plugins={},e.Workers=[{filter:[\"width\",\"settings\"],run:function(){this._width=this.$element.width()}},{filter:[\"width\",\"items\",\"settings\"],run:function(a){a.current=this._items&&this._items[this.relative(this._current)]}},{filter:[\"items\",\"settings\"],run:function(){this.$stage.children(\".cloned\").remove()}},{filter:[\"width\",\"items\",\"settings\"],run:function(a){var b=this.settings.margin||\"\",c=!this.settings.autoWidth,d=this.settings.rtl,e={width:\"auto\",\"margin-left\":d?b:\"\",\"margin-right\":d?\"\":b};!c&&this.$stage.children().css(e),a.css=e}},{filter:[\"width\",\"items\",\"settings\"],run:function(a){var b=(this.width()/this.settings.items).toFixed(3)-this.settings.margin,c=null,d=this._items.length,e=!this.settings.autoWidth,f=[];for(a.items={merge:!1,width:b};d--;)c=this._mergers[d],c=this.settings.mergeFit&&Math.min(c,this.settings.items)||c,a.items.merge=c>1||a.items.merge,f[d]=e?b*c:this._items[d].width();this._widths=f}},{filter:[\"items\",\"settings\"],run:function(){var b=[],c=this._items,d=this.settings,e=Math.max(2*d.items,4),f=2*Math.ceil(c.length/2),g=d.loop&&c.length?d.rewind?e:Math.max(e,f):0,h=\"\",i=\"\";for(g/=2;g>0;)b.push(this.normalize(b.length/2,!0)),h+=c[b[b.length-1]][0].outerHTML,b.push(this.normalize(c.length-1-(b.length-1)/2,!0)),i=c[b[b.length-1]][0].outerHTML+i,g-=1;this._clones=b,a(h).addClass(\"cloned\").appendTo(this.$stage),a(i).addClass(\"cloned\").prependTo(this.$stage)}},{filter:[\"width\",\"items\",\"settings\"],run:function(){for(var a=this.settings.rtl?1:-1,b=this._clones.length+this._items.length,c=-1,d=0,e=0,f=[];++c<b;)d=f[c-1]||0,e=this._widths[this.relative(c)]+this.settings.margin,f.push(d+e*a);this._coordinates=f}},{filter:[\"width\",\"items\",\"settings\"],run:function(){var a=this.settings.stagePadding,b=this._coordinates,c={width:Math.ceil(Math.abs(b[b.length-1]))+2*a,\"padding-left\":a||\"\",\"padding-right\":a||\"\"};this.$stage.css(c)}},{filter:[\"width\",\"items\",\"settings\"],run:function(a){var b=this._coordinates.length,c=!this.settings.autoWidth,d=this.$stage.children();if(c&&a.items.merge)for(;b--;)a.css.width=this._widths[this.relative(b)],d.eq(b).css(a.css);else c&&(a.css.width=a.items.width,d.css(a.css))}},{filter:[\"items\"],run:function(){this._coordinates.length<1&&this.$stage.removeAttr(\"style\")}},{filter:[\"width\",\"items\",\"settings\"],run:function(a){a.current=a.current?this.$stage.children().index(a.current):0,a.current=Math.max(this.minimum(),Math.min(this.maximum(),a.current)),this.reset(a.current)}},{filter:[\"position\"],run:function(){this.animate(this.coordinates(this._current))}},{filter:[\"width\",\"position\",\"items\",\"settings\"],run:function(){var a,b,c,d,e=this.settings.rtl?1:-1,f=2*this.settings.stagePadding,g=this.coordinates(this.current())+f,h=g+this.width()*e,i=[];for(c=0,d=this._coordinates.length;c<d;c++)a=this._coordinates[c-1]||0,b=Math.abs(this._coordinates[c])+f*e,(this.op(a,\"<=\",g)&&this.op(a,\">\",h)||this.op(b,\"<\",g)&&this.op(b,\">\",h))&&i.push(c);this.$stage.children(\".active\").removeClass(\"active\"),this.$stage.children(\":eq(\"+i.join(\"), :eq(\")+\")\").addClass(\"active\"),this.$stage.children(\".center\").removeClass(\"center\"),this.settings.center&&this.$stage.children().eq(this.current()).addClass(\"center\")}}],e.prototype.initializeStage=function(){this.$stage=this.$element.find(\".\"+this.settings.stageClass),this.$stage.length||(this.$element.addClass(this.options.loadingClass),this.$stage=a(\"<\"+this.settings.stageElement+\">\",{class:this.settings.stageClass}).wrap(a(\"<div/>\",{class:this.settings.stageOuterClass})),this.$element.append(this.$stage.parent()))},e.prototype.initializeItems=function(){var b=this.$element.find(\".owl-item\");if(b.length)return this._items=b.get().map(function(b){return a(b)}),this._mergers=this._items.map(function(){return 1}),void this.refresh();this.replace(this.$element.children().not(this.$stage.parent())),this.isVisible()?this.refresh():this.invalidate(\"width\"),this.$element.removeClass(this.options.loadingClass).addClass(this.options.loadedClass)},e.prototype.initialize=function(){if(this.enter(\"initializing\"),this.trigger(\"initialize\"),this.$element.toggleClass(this.settings.rtlClass,this.settings.rtl),this.settings.autoWidth&&!this.is(\"pre-loading\")){var a,b,c;a=this.$element.find(\"img\"),b=this.settings.nestedItemSelector?\".\"+this.settings.nestedItemSelector:d,c=this.$element.children(b).width(),a.length&&c<=0&&this.preloadAutoWidthImages(a)}this.initializeStage(),this.initializeItems(),this.registerEventHandlers(),this.leave(\"initializing\"),this.trigger(\"initialized\")},e.prototype.isVisible=function(){return!this.settings.checkVisibility||this.$element.is(\":visible\")},e.prototype.setup=function(){var b=this.viewport(),c=this.options.responsive,d=-1,e=null;c?(a.each(c,function(a){a<=b&&a>d&&(d=Number(a))}),e=a.extend({},this.options,c[d]),\"function\"==typeof e.stagePadding&&(e.stagePadding=e.stagePadding()),delete e.responsive,e.responsiveClass&&this.$element.attr(\"class\",this.$element.attr(\"class\").replace(new RegExp(\"(\"+this.options.responsiveClass+\"-)\\\\S+\\\\s\",\"g\"),\"$1\"+d))):e=a.extend({},this.options),this.trigger(\"change\",{property:{name:\"settings\",value:e}}),this._breakpoint=d,this.settings=e,this.invalidate(\"settings\"),this.trigger(\"changed\",{property:{name:\"settings\",value:this.settings}})},e.prototype.optionsLogic=function(){this.settings.autoWidth&&(this.settings.stagePadding=!1,this.settings.merge=!1)},e.prototype.prepare=function(b){var c=this.trigger(\"prepare\",{content:b});return c.data||(c.data=a(\"<\"+this.settings.itemElement+\"/>\").addClass(this.options.itemClass).append(b)),this.trigger(\"prepared\",{content:c.data}),c.data},e.prototype.update=function(){for(var b=0,c=this._pipe.length,d=a.proxy(function(a){return this[a]},this._invalidated),e={};b<c;)(this._invalidated.all||a.grep(this._pipe[b].filter,d).length>0)&&this._pipe[b].run(e),b++;this._invalidated={},!this.is(\"valid\")&&this.enter(\"valid\")},e.prototype.width=function(a){switch(a=a||e.Width.Default){case e.Width.Inner:case e.Width.Outer:return this._width;default:return this._width-2*this.settings.stagePadding+this.settings.margin}},e.prototype.refresh=function(){this.enter(\"refreshing\"),this.trigger(\"refresh\"),this.setup(),this.optionsLogic(),this.$element.addClass(this.options.refreshClass),this.update(),this.$element.removeClass(this.options.refreshClass),this.leave(\"refreshing\"),this.trigger(\"refreshed\")},e.prototype.onThrottledResize=function(){b.clearTimeout(this.resizeTimer),this.resizeTimer=b.setTimeout(this._handlers.onResize,this.settings.responsiveRefreshRate)},e.prototype.onResize=function(){return!!this._items.length&&(this._width!==this.$element.width()&&(!!this.isVisible()&&(this.enter(\"resizing\"),this.trigger(\"resize\").isDefaultPrevented()?(this.leave(\"resizing\"),!1):(this.invalidate(\"width\"),this.refresh(),this.leave(\"resizing\"),void this.trigger(\"resized\")))))},e.prototype.registerEventHandlers=function(){a.support.transition&&this.$stage.on(a.support.transition.end+\".owl.core\",a.proxy(this.onTransitionEnd,this)),!1!==this.settings.responsive&&this.on(b,\"resize\",this._handlers.onThrottledResize),this.settings.mouseDrag&&(this.$element.addClass(this.options.dragClass),this.$stage.on(\"mousedown.owl.core\",a.proxy(this.onDragStart,this)),this.$stage.on(\"dragstart.owl.core selectstart.owl.core\",function(){return!1})),this.settings.touchDrag&&(this.$stage.on(\"touchstart.owl.core\",a.proxy(this.onDragStart,this)),this.$stage.on(\"touchcancel.owl.core\",a.proxy(this.onDragEnd,this)))},e.prototype.onDragStart=function(b){var d=null;3!==b.which&&(a.support.transform?(d=this.$stage.css(\"transform\").replace(/.*\\(|\\)| /g,\"\").split(\",\"),d={x:d[16===d.length?12:4],y:d[16===d.length?13:5]}):(d=this.$stage.position(),d={x:this.settings.rtl?d.left+this.$stage.width()-this.width()+this.settings.margin:d.left,y:d.top}),this.is(\"animating\")&&(a.support.transform?this.animate(d.x):this.$stage.stop(),this.invalidate(\"position\")),this.$element.toggleClass(this.options.grabClass,\"mousedown\"===b.type),this.speed(0),this._drag.time=(new Date).getTime(),this._drag.target=a(b.target),this._drag.stage.start=d,this._drag.stage.current=d,this._drag.pointer=this.pointer(b),a(c).on(\"mouseup.owl.core touchend.owl.core\",a.proxy(this.onDragEnd,this)),a(c).one(\"mousemove.owl.core touchmove.owl.core\",a.proxy(function(b){var d=this.difference(this._drag.pointer,this.pointer(b));a(c).on(\"mousemove.owl.core touchmove.owl.core\",a.proxy(this.onDragMove,this)),Math.abs(d.x)<Math.abs(d.y)&&this.is(\"valid\")||(b.preventDefault(),this.enter(\"dragging\"),this.trigger(\"drag\"))},this)))},e.prototype.onDragMove=function(a){var b=null,c=null,d=null,e=this.difference(this._drag.pointer,this.pointer(a)),f=this.difference(this._drag.stage.start,e);this.is(\"dragging\")&&(a.preventDefault(),this.settings.loop?(b=this.coordinates(this.minimum()),c=this.coordinates(this.maximum()+1)-b,f.x=((f.x-b)%c+c)%c+b):(b=this.settings.rtl?this.coordinates(this.maximum()):this.coordinates(this.minimum()),c=this.settings.rtl?this.coordinates(this.minimum()):this.coordinates(this.maximum()),d=this.settings.pullDrag?-1*e.x/5:0,f.x=Math.max(Math.min(f.x,b+d),c+d)),this._drag.stage.current=f,this.animate(f.x))},e.prototype.onDragEnd=function(b){var d=this.difference(this._drag.pointer,this.pointer(b)),e=this._drag.stage.current,f=d.x>0^this.settings.rtl?\"left\":\"right\";a(c).off(\".owl.core\"),this.$element.removeClass(this.options.grabClass),(0!==d.x&&this.is(\"dragging\")||!this.is(\"valid\"))&&(this.speed(this.settings.dragEndSpeed||this.settings.smartSpeed),this.current(this.closest(e.x,0!==d.x?f:this._drag.direction)),this.invalidate(\"position\"),this.update(),this._drag.direction=f,(Math.abs(d.x)>3||(new Date).getTime()-this._drag.time>300)&&this._drag.target.one(\"click.owl.core\",function(){return!1})),this.is(\"dragging\")&&(this.leave(\"dragging\"),this.trigger(\"dragged\"))},e.prototype.closest=function(b,c){var e=-1,f=30,g=this.width(),h=this.coordinates();return this.settings.freeDrag||a.each(h,a.proxy(function(a,i){return\"left\"===c&&b>i-f&&b<i+f?e=a:\"right\"===c&&b>i-g-f&&b<i-g+f?e=a+1:this.op(b,\"<\",i)&&this.op(b,\">\",h[a+1]!==d?h[a+1]:i-g)&&(e=\"left\"===c?a+1:a),-1===e},this)),this.settings.loop||(this.op(b,\">\",h[this.minimum()])?e=b=this.minimum():this.op(b,\"<\",h[this.maximum()])&&(e=b=this.maximum())),e},e.prototype.animate=function(b){var c=this.speed()>0;this.is(\"animating\")&&this.onTransitionEnd(),c&&(this.enter(\"animating\"),this.trigger(\"translate\")),a.support.transform3d&&a.support.transition?this.$stage.css({transform:\"translate3d(\"+b+\"px,0px,0px)\",transition:this.speed()/1e3+\"s\"+(this.settings.slideTransition?\" \"+this.settings.slideTransition:\"\")}):c?this.$stage.animate({left:b+\"px\"},this.speed(),this.settings.fallbackEasing,a.proxy(this.onTransitionEnd,this)):this.$stage.css({left:b+\"px\"})},e.prototype.is=function(a){return this._states.current[a]&&this._states.current[a]>0},e.prototype.current=function(a){if(a===d)return this._current;if(0===this._items.length)return d;if(a=this.normalize(a),this._current!==a){var b=this.trigger(\"change\",{property:{name:\"position\",value:a}});b.data!==d&&(a=this.normalize(b.data)),this._current=a,this.invalidate(\"position\"),this.trigger(\"changed\",{property:{name:\"position\",value:this._current}})}return this._current},e.prototype.invalidate=function(b){return\"string\"===a.type(b)&&(this._invalidated[b]=!0,this.is(\"valid\")&&this.leave(\"valid\")),a.map(this._invalidated,function(a,b){return b})},e.prototype.reset=function(a){(a=this.normalize(a))!==d&&(this._speed=0,this._current=a,this.suppress([\"translate\",\"translated\"]),this.animate(this.coordinates(a)),this.release([\"translate\",\"translated\"]))},e.prototype.normalize=function(a,b){var c=this._items.length,e=b?0:this._clones.length;return!this.isNumeric(a)||c<1?a=d:(a<0||a>=c+e)&&(a=((a-e/2)%c+c)%c+e/2),a},e.prototype.relative=function(a){return a-=this._clones.length/2,this.normalize(a,!0)},e.prototype.maximum=function(a){var b,c,d,e=this.settings,f=this._coordinates.length;if(e.loop)f=this._clones.length/2+this._items.length-1;else if(e.autoWidth||e.merge){if(b=this._items.length)for(c=this._items[--b].width(),d=this.$element.width();b--&&!((c+=this._items[b].width()+this.settings.margin)>d););f=b+1}else f=e.center?this._items.length-1:this._items.length-e.items;return a&&(f-=this._clones.length/2),Math.max(f,0)},e.prototype.minimum=function(a){return a?0:this._clones.length/2},e.prototype.items=function(a){return a===d?this._items.slice():(a=this.normalize(a,!0),this._items[a])},e.prototype.mergers=function(a){return a===d?this._mergers.slice():(a=this.normalize(a,!0),this._mergers[a])},e.prototype.clones=function(b){var c=this._clones.length/2,e=c+this._items.length,f=function(a){return a%2==0?e+a/2:c-(a+1)/2};return b===d?a.map(this._clones,function(a,b){return f(b)}):a.map(this._clones,function(a,c){return a===b?f(c):null})},e.prototype.speed=function(a){return a!==d&&(this._speed=a),this._speed},e.prototype.coordinates=function(b){var c,e=1,f=b-1;return b===d?a.map(this._coordinates,a.proxy(function(a,b){return this.coordinates(b)},this)):(this.settings.center?(this.settings.rtl&&(e=-1,f=b+1),c=this._coordinates[b],c+=(this.width()-c+(this._coordinates[f]||0))/2*e):c=this._coordinates[f]||0,c=Math.ceil(c))},e.prototype.duration=function(a,b,c){return 0===c?0:Math.min(Math.max(Math.abs(b-a),1),6)*Math.abs(c||this.settings.smartSpeed)},e.prototype.to=function(a,b){var c=this.current(),d=null,e=a-this.relative(c),f=(e>0)-(e<0),g=this._items.length,h=this.minimum(),i=this.maximum();this.settings.loop?(!this.settings.rewind&&Math.abs(e)>g/2&&(e+=-1*f*g),a=c+e,(d=((a-h)%g+g)%g+h)!==a&&d-e<=i&&d-e>0&&(c=d-e,a=d,this.reset(c))):this.settings.rewind?(i+=1,a=(a%i+i)%i):a=Math.max(h,Math.min(i,a)),this.speed(this.duration(c,a,b)),this.current(a),this.isVisible()&&this.update()},e.prototype.next=function(a){a=a||!1,this.to(this.relative(this.current())+1,a)},e.prototype.prev=function(a){a=a||!1,this.to(this.relative(this.current())-1,a)},e.prototype.onTransitionEnd=function(a){if(a!==d&&(a.stopPropagation(),(a.target||a.srcElement||a.originalTarget)!==this.$stage.get(0)))return!1;this.leave(\"animating\"),this.trigger(\"translated\")},e.prototype.viewport=function(){var d;return this.options.responsiveBaseElement!==b?d=a(this.options.responsiveBaseElement).width():b.innerWidth?d=b.innerWidth:c.documentElement&&c.documentElement.clientWidth?d=c.documentElement.clientWidth:console.warn(\"Can not detect viewport width.\"),d},e.prototype.replace=function(b){this.$stage.empty(),this._items=[],b&&(b=b instanceof jQuery?b:a(b)),this.settings.nestedItemSelector&&(b=b.find(\".\"+this.settings.nestedItemSelector)),b.filter(function(){return 1===this.nodeType}).each(a.proxy(function(a,b){b=this.prepare(b),this.$stage.append(b),this._items.push(b),this._mergers.push(1*b.find(\"[data-merge]\").addBack(\"[data-merge]\").attr(\"data-merge\")||1)},this)),this.reset(this.isNumeric(this.settings.startPosition)?this.settings.startPosition:0),this.invalidate(\"items\")},e.prototype.add=function(b,c){var e=this.relative(this._current);c=c===d?this._items.length:this.normalize(c,!0),b=b instanceof jQuery?b:a(b),this.trigger(\"add\",{content:b,position:c}),b=this.prepare(b),0===this._items.length||c===this._items.length?(0===this._items.length&&this.$stage.append(b),0!==this._items.length&&this._items[c-1].after(b),this._items.push(b),this._mergers.push(1*b.find(\"[data-merge]\").addBack(\"[data-merge]\").attr(\"data-merge\")||1)):(this._items[c].before(b),this._items.splice(c,0,b),this._mergers.splice(c,0,1*b.find(\"[data-merge]\").addBack(\"[data-merge]\").attr(\"data-merge\")||1)),this._items[e]&&this.reset(this._items[e].index()),this.invalidate(\"items\"),this.trigger(\"added\",{content:b,position:c})},e.prototype.remove=function(a){(a=this.normalize(a,!0))!==d&&(this.trigger(\"remove\",{content:this._items[a],position:a}),this._items[a].remove(),this._items.splice(a,1),this._mergers.splice(a,1),this.invalidate(\"items\"),this.trigger(\"removed\",{content:null,position:a}))},e.prototype.preloadAutoWidthImages=function(b){b.each(a.proxy(function(b,c){this.enter(\"pre-loading\"),c=a(c),a(new Image).one(\"load\",a.proxy(function(a){c.attr(\"src\",a.target.src),c.css(\"opacity\",1),this.leave(\"pre-loading\"),!this.is(\"pre-loading\")&&!this.is(\"initializing\")&&this.refresh()},this)).attr(\"src\",c.attr(\"src\")||c.attr(\"data-src\")||c.attr(\"data-src-retina\"))},this))},e.prototype.destroy=function(){this.$element.off(\".owl.core\"),this.$stage.off(\".owl.core\"),a(c).off(\".owl.core\"),!1!==this.settings.responsive&&(b.clearTimeout(this.resizeTimer),this.off(b,\"resize\",this._handlers.onThrottledResize));for(var d in this._plugins)this._plugins[d].destroy();this.$stage.children(\".cloned\").remove(),this.$stage.unwrap(),this.$stage.children().contents().unwrap(),this.$stage.children().unwrap(),this.$stage.remove(),this.$element.removeClass(this.options.refreshClass).removeClass(this.options.loadingClass).removeClass(this.options.loadedClass).removeClass(this.options.rtlClass).removeClass(this.options.dragClass).removeClass(this.options.grabClass).attr(\"class\",this.$element.attr(\"class\").replace(new RegExp(this.options.responsiveClass+\"-\\\\S+\\\\s\",\"g\"),\"\")).removeData(\"owl.carousel\")},e.prototype.op=function(a,b,c){var d=this.settings.rtl;switch(b){case\"<\":return d?a>c:a<c;case\">\":return d?a<c:a>c;case\">=\":return d?a<=c:a>=c;case\"<=\":return d?a>=c:a<=c}},e.prototype.on=function(a,b,c,d){a.addEventListener?a.addEventListener(b,c,d):a.attachEvent&&a.attachEvent(\"on\"+b,c)},e.prototype.off=function(a,b,c,d){a.removeEventListener?a.removeEventListener(b,c,d):a.detachEvent&&a.detachEvent(\"on\"+b,c)},e.prototype.trigger=function(b,c,d,f,g){var h={item:{count:this._items.length,index:this.current()}},i=a.camelCase(a.grep([\"on\",b,d],function(a){return a}).join(\"-\").toLowerCase()),j=a.Event([b,\"owl\",d||\"carousel\"].join(\".\").toLowerCase(),a.extend({relatedTarget:this},h,c));return this._supress[b]||(a.each(this._plugins,function(a,b){b.onTrigger&&b.onTrigger(j)}),this.register({type:e.Type.Event,name:b}),this.$element.trigger(j),this.settings&&\"function\"==typeof this.settings[i]&&this.settings[i].call(this,j)),j},e.prototype.enter=function(b){a.each([b].concat(this._states.tags[b]||[]),a.proxy(function(a,b){this._states.current[b]===d&&(this._states.current[b]=0),this._states.current[b]++},this))},e.prototype.leave=function(b){a.each([b].concat(this._states.tags[b]||[]),a.proxy(function(a,b){this._states.current[b]--},this))},e.prototype.register=function(b){if(b.type===e.Type.Event){if(a.event.special[b.name]||(a.event.special[b.name]={}),!a.event.special[b.name].owl){var c=a.event.special[b.name]._default;a.event.special[b.name]._default=function(a){return!c||!c.apply||a.namespace&&-1!==a.namespace.indexOf(\"owl\")?a.namespace&&a.namespace.indexOf(\"owl\")>-1:c.apply(this,arguments)},a.event.special[b.name].owl=!0}}else b.type===e.Type.State&&(this._states.tags[b.name]?this._states.tags[b.name]=this._states.tags[b.name].concat(b.tags):this._states.tags[b.name]=b.tags,this._states.tags[b.name]=a.grep(this._states.tags[b.name],a.proxy(function(c,d){return a.inArray(c,this._states.tags[b.name])===d},this)))},e.prototype.suppress=function(b){a.each(b,a.proxy(function(a,b){this._supress[b]=!0},this))},e.prototype.release=function(b){a.each(b,a.proxy(function(a,b){delete this._supress[b]},this))},e.prototype.pointer=function(a){var c={x:null,y:null};return a=a.originalEvent||a||b.event,a=a.touches&&a.touches.length?a.touches[0]:a.changedTouches&&a.changedTouches.length?a.changedTouches[0]:a,a.pageX?(c.x=a.pageX,c.y=a.pageY):(c.x=a.clientX,c.y=a.clientY),c},e.prototype.isNumeric=function(a){return!isNaN(parseFloat(a))},e.prototype.difference=function(a,b){return{x:a.x-b.x,y:a.y-b.y}},a.fn.owlCarousel=function(b){var c=Array.prototype.slice.call(arguments,1);return this.each(function(){var d=a(this),f=d.data(\"owl.carousel\");f||(f=new e(this,\"object\"==typeof b&&b),d.data(\"owl.carousel\",f),a.each([\"next\",\"prev\",\"to\",\"destroy\",\"refresh\",\"replace\",\"add\",\"remove\"],function(b,c){f.register({type:e.Type.Event,name:c}),f.$element.on(c+\".owl.carousel.core\",a.proxy(function(a){a.namespace&&a.relatedTarget!==this&&(this.suppress([c]),f[c].apply(this,[].slice.call(arguments,1)),this.release([c]))},f))})),\"string\"==typeof b&&\"_\"!==b.charAt(0)&&f[b].apply(f,c)})},a.fn.owlCarousel.Constructor=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this._core=b,this._interval=null,this._visible=null,this._handlers={\"initialized.owl.carousel\":a.proxy(function(a){a.namespace&&this._core.settings.autoRefresh&&this.watch()},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this._core.$element.on(this._handlers)};e.Defaults={autoRefresh:!0,autoRefreshInterval:500},e.prototype.watch=function(){this._interval||(this._visible=this._core.isVisible(),this._interval=b.setInterval(a.proxy(this.refresh,this),this._core.settings.autoRefreshInterval))},e.prototype.refresh=function(){this._core.isVisible()!==this._visible&&(this._visible=!this._visible,this._core.$element.toggleClass(\"owl-hidden\",!this._visible),this._visible&&this._core.invalidate(\"width\")&&this._core.refresh())},e.prototype.destroy=function(){var a,c;b.clearInterval(this._interval);for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(c in Object.getOwnPropertyNames(this))\"function\"!=typeof this[c]&&(this[c]=null)},a.fn.owlCarousel.Constructor.Plugins.AutoRefresh=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this._core=b,this._loaded=[],this._handlers={\"initialized.owl.carousel change.owl.carousel resized.owl.carousel\":a.proxy(function(b){if(b.namespace&&this._core.settings&&this._core.settings.lazyLoad&&(b.property&&\"position\"==b.property.name||\"initialized\"==b.type)){var c=this._core.settings,e=c.center&&Math.ceil(c.items/2)||c.items,f=c.center&&-1*e||0,g=(b.property&&b.property.value!==d?b.property.value:this._core.current())+f,h=this._core.clones().length,i=a.proxy(function(a,b){this.load(b)},this);for(c.lazyLoadEager>0&&(e+=c.lazyLoadEager,c.loop&&(g-=c.lazyLoadEager,e++));f++<e;)this.load(h/2+this._core.relative(g)),h&&a.each(this._core.clones(this._core.relative(g)),i),g++}},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this._core.$element.on(this._handlers)};e.Defaults={lazyLoad:!1,lazyLoadEager:0},e.prototype.load=function(c){var d=this._core.$stage.children().eq(c),e=d&&d.find(\".owl-lazy\");!e||a.inArray(d.get(0),this._loaded)>-1||(e.each(a.proxy(function(c,d){var e,f=a(d),g=b.devicePixelRatio>1&&f.attr(\"data-src-retina\")||f.attr(\"data-src\")||f.attr(\"data-srcset\");this._core.trigger(\"load\",{element:f,url:g},\"lazy\"),f.is(\"img\")?f.one(\"load.owl.lazy\",a.proxy(function(){f.css(\"opacity\",1),this._core.trigger(\"loaded\",{element:f,url:g},\"lazy\")},this)).attr(\"src\",g):f.is(\"source\")?f.one(\"load.owl.lazy\",a.proxy(function(){this._core.trigger(\"loaded\",{element:f,url:g},\"lazy\")},this)).attr(\"srcset\",g):(e=new Image,e.onload=a.proxy(function(){f.css({\"background-image\":'url(\"'+g+'\")',opacity:\"1\"}),this._core.trigger(\"loaded\",{element:f,url:g},\"lazy\")},this),e.src=g)},this)),this._loaded.push(d.get(0)))},e.prototype.destroy=function(){var a,b;for(a in this.handlers)this._core.$element.off(a,this.handlers[a]);for(b in Object.getOwnPropertyNames(this))\"function\"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.Lazy=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(c){this._core=c,this._previousHeight=null,this._handlers={\"initialized.owl.carousel refreshed.owl.carousel\":a.proxy(function(a){a.namespace&&this._core.settings.autoHeight&&this.update()},this),\"changed.owl.carousel\":a.proxy(function(a){a.namespace&&this._core.settings.autoHeight&&\"position\"===a.property.name&&this.update()},this),\"loaded.owl.lazy\":a.proxy(function(a){a.namespace&&this._core.settings.autoHeight&&a.element.closest(\".\"+this._core.settings.itemClass).index()===this._core.current()&&this.update()},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this._core.$element.on(this._handlers),this._intervalId=null;var d=this;a(b).on(\"load\",function(){d._core.settings.autoHeight&&d.update()}),a(b).resize(function(){d._core.settings.autoHeight&&(null!=d._intervalId&&clearTimeout(d._intervalId),d._intervalId=setTimeout(function(){d.update()},250))})};e.Defaults={autoHeight:!1,autoHeightClass:\"owl-height\"},e.prototype.update=function(){var b=this._core._current,c=b+this._core.settings.items,d=this._core.settings.lazyLoad,e=this._core.$stage.children().toArray().slice(b,c),f=[],g=0;a.each(e,function(b,c){f.push(a(c).height())}),g=Math.max.apply(null,f),g<=1&&d&&this._previousHeight&&(g=this._previousHeight),this._previousHeight=g,this._core.$stage.parent().height(g).addClass(this._core.settings.autoHeightClass)},e.prototype.destroy=function(){var a,b;for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(b in Object.getOwnPropertyNames(this))\"function\"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.AutoHeight=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this._core=b,this._videos={},this._playing=null,this._handlers={\"initialized.owl.carousel\":a.proxy(function(a){a.namespace&&this._core.register({type:\"state\",name:\"playing\",tags:[\"interacting\"]})},this),\"resize.owl.carousel\":a.proxy(function(a){a.namespace&&this._core.settings.video&&this.isInFullScreen()&&a.preventDefault()},this),\"refreshed.owl.carousel\":a.proxy(function(a){a.namespace&&this._core.is(\"resizing\")&&this._core.$stage.find(\".cloned .owl-video-frame\").remove()},this),\"changed.owl.carousel\":a.proxy(function(a){a.namespace&&\"position\"===a.property.name&&this._playing&&this.stop()},this),\"prepared.owl.carousel\":a.proxy(function(b){if(b.namespace){var c=a(b.content).find(\".owl-video\");c.length&&(c.css(\"display\",\"none\"),this.fetch(c,a(b.content)))}},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this._core.$element.on(this._handlers),this._core.$element.on(\"click.owl.video\",\".owl-video-play-icon\",a.proxy(function(a){this.play(a)},this))};e.Defaults={video:!1,videoHeight:!1,videoWidth:!1},e.prototype.fetch=function(a,b){var c=function(){return a.attr(\"data-vimeo-id\")?\"vimeo\":a.attr(\"data-vzaar-id\")?\"vzaar\":\"youtube\"}(),d=a.attr(\"data-vimeo-id\")||a.attr(\"data-youtube-id\")||a.attr(\"data-vzaar-id\"),e=a.attr(\"data-width\")||this._core.settings.videoWidth,f=a.attr(\"data-height\")||this._core.settings.videoHeight,g=a.attr(\"href\");if(!g)throw new Error(\"Missing video URL.\");if(d=g.match(/(http:|https:|)\\/\\/(player.|www.|app.)?(vimeo\\.com|youtu(be\\.com|\\.be|be\\.googleapis\\.com|be\\-nocookie\\.com)|vzaar\\.com)\\/(video\\/|videos\\/|embed\\/|channels\\/.+\\/|groups\\/.+\\/|watch\\?v=|v\\/)?([A-Za-z0-9._%-]*)(\\&\\S+)?/),d[3].indexOf(\"youtu\")>-1)c=\"youtube\";else if(d[3].indexOf(\"vimeo\")>-1)c=\"vimeo\";else{if(!(d[3].indexOf(\"vzaar\")>-1))throw new Error(\"Video URL not supported.\");c=\"vzaar\"}d=d[6],this._videos[g]={type:c,id:d,width:e,height:f},b.attr(\"data-video\",g),this.thumbnail(a,this._videos[g])},e.prototype.thumbnail=function(b,c){var d,e,f,g=c.width&&c.height?\"width:\"+c.width+\"px;height:\"+c.height+\"px;\":\"\",h=b.find(\"img\"),i=\"src\",j=\"\",k=this._core.settings,l=function(c){e='<div class=\"owl-video-play-icon\"></div>',d=k.lazyLoad?a(\"<div/>\",{class:\"owl-video-tn \"+j,srcType:c}):a(\"<div/>\",{class:\"owl-video-tn\",style:\"opacity:1;background-image:url(\"+c+\")\"}),b.after(d),b.after(e)};if(b.wrap(a(\"<div/>\",{class:\"owl-video-wrapper\",style:g})),this._core.settings.lazyLoad&&(i=\"data-src\",j=\"owl-lazy\"),h.length)return l(h.attr(i)),h.remove(),!1;\"youtube\"===c.type?(f=\"//img.youtube.com/vi/\"+c.id+\"/hqdefault.jpg\",l(f)):\"vimeo\"===c.type?a.ajax({type:\"GET\",url:\"//vimeo.com/api/v2/video/\"+c.id+\".json\",jsonp:\"callback\",dataType:\"jsonp\",success:function(a){f=a[0].thumbnail_large,l(f)}}):\"vzaar\"===c.type&&a.ajax({type:\"GET\",url:\"//vzaar.com/api/videos/\"+c.id+\".json\",jsonp:\"callback\",dataType:\"jsonp\",success:function(a){f=a.framegrab_url,l(f)}})},e.prototype.stop=function(){this._core.trigger(\"stop\",null,\"video\"),this._playing.find(\".owl-video-frame\").remove(),this._playing.removeClass(\"owl-video-playing\"),this._playing=null,this._core.leave(\"playing\"),this._core.trigger(\"stopped\",null,\"video\")},e.prototype.play=function(b){var c,d=a(b.target),e=d.closest(\".\"+this._core.settings.itemClass),f=this._videos[e.attr(\"data-video\")],g=f.width||\"100%\",h=f.height||this._core.$stage.height();this._playing||(this._core.enter(\"playing\"),this._core.trigger(\"play\",null,\"video\"),e=this._core.items(this._core.relative(e.index())),this._core.reset(e.index()),c=a('<iframe frameborder=\"0\" allowfullscreen mozallowfullscreen webkitAllowFullScreen ></iframe>'),c.attr(\"height\",h),c.attr(\"width\",g),\"youtube\"===f.type?c.attr(\"src\",\"//www.youtube.com/embed/\"+f.id+\"?autoplay=1&rel=0&v=\"+f.id):\"vimeo\"===f.type?c.attr(\"src\",\"//player.vimeo.com/video/\"+f.id+\"?autoplay=1\"):\"vzaar\"===f.type&&c.attr(\"src\",\"//view.vzaar.com/\"+f.id+\"/player?autoplay=true\"),a(c).wrap('<div class=\"owl-video-frame\" />').insertAfter(e.find(\".owl-video\")),this._playing=e.addClass(\"owl-video-playing\"))},e.prototype.isInFullScreen=function(){var b=c.fullscreenElement||c.mozFullScreenElement||c.webkitFullscreenElement;return b&&a(b).parent().hasClass(\"owl-video-frame\")},e.prototype.destroy=function(){var a,b;this._core.$element.off(\"click.owl.video\");for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(b in Object.getOwnPropertyNames(this))\"function\"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.Video=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this.core=b,this.core.options=a.extend({},e.Defaults,this.core.options),this.swapping=!0,this.previous=d,this.next=d,this.handlers={\"change.owl.carousel\":a.proxy(function(a){a.namespace&&\"position\"==a.property.name&&(this.previous=this.core.current(),this.next=a.property.value)},this),\"drag.owl.carousel dragged.owl.carousel translated.owl.carousel\":a.proxy(function(a){a.namespace&&(this.swapping=\"translated\"==a.type)},this),\"translate.owl.carousel\":a.proxy(function(a){a.namespace&&this.swapping&&(this.core.options.animateOut||this.core.options.animateIn)&&this.swap()},this)},this.core.$element.on(this.handlers)};e.Defaults={animateOut:!1,\n    animateIn:!1},e.prototype.swap=function(){if(1===this.core.settings.items&&a.support.animation&&a.support.transition){this.core.speed(0);var b,c=a.proxy(this.clear,this),d=this.core.$stage.children().eq(this.previous),e=this.core.$stage.children().eq(this.next),f=this.core.settings.animateIn,g=this.core.settings.animateOut;this.core.current()!==this.previous&&(g&&(b=this.core.coordinates(this.previous)-this.core.coordinates(this.next),d.one(a.support.animation.end,c).css({left:b+\"px\"}).addClass(\"animated owl-animated-out\").addClass(g)),f&&e.one(a.support.animation.end,c).addClass(\"animated owl-animated-in\").addClass(f))}},e.prototype.clear=function(b){a(b.target).css({left:\"\"}).removeClass(\"animated owl-animated-out owl-animated-in\").removeClass(this.core.settings.animateIn).removeClass(this.core.settings.animateOut),this.core.onTransitionEnd()},e.prototype.destroy=function(){var a,b;for(a in this.handlers)this.core.$element.off(a,this.handlers[a]);for(b in Object.getOwnPropertyNames(this))\"function\"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.Animate=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this._core=b,this._call=null,this._time=0,this._timeout=0,this._paused=!0,this._handlers={\"changed.owl.carousel\":a.proxy(function(a){a.namespace&&\"settings\"===a.property.name?this._core.settings.autoplay?this.play():this.stop():a.namespace&&\"position\"===a.property.name&&this._paused&&(this._time=0)},this),\"initialized.owl.carousel\":a.proxy(function(a){a.namespace&&this._core.settings.autoplay&&this.play()},this),\"play.owl.autoplay\":a.proxy(function(a,b,c){a.namespace&&this.play(b,c)},this),\"stop.owl.autoplay\":a.proxy(function(a){a.namespace&&this.stop()},this),\"mouseover.owl.autoplay\":a.proxy(function(){this._core.settings.autoplayHoverPause&&this._core.is(\"rotating\")&&this.pause()},this),\"mouseleave.owl.autoplay\":a.proxy(function(){this._core.settings.autoplayHoverPause&&this._core.is(\"rotating\")&&this.play()},this),\"touchstart.owl.core\":a.proxy(function(){this._core.settings.autoplayHoverPause&&this._core.is(\"rotating\")&&this.pause()},this),\"touchend.owl.core\":a.proxy(function(){this._core.settings.autoplayHoverPause&&this.play()},this)},this._core.$element.on(this._handlers),this._core.options=a.extend({},e.Defaults,this._core.options)};e.Defaults={autoplay:!1,autoplayTimeout:5e3,autoplayHoverPause:!1,autoplaySpeed:!1},e.prototype._next=function(d){this._call=b.setTimeout(a.proxy(this._next,this,d),this._timeout*(Math.round(this.read()/this._timeout)+1)-this.read()),this._core.is(\"interacting\")||c.hidden||this._core.next(d||this._core.settings.autoplaySpeed)},e.prototype.read=function(){return(new Date).getTime()-this._time},e.prototype.play=function(c,d){var e;this._core.is(\"rotating\")||this._core.enter(\"rotating\"),c=c||this._core.settings.autoplayTimeout,e=Math.min(this._time%(this._timeout||c),c),this._paused?(this._time=this.read(),this._paused=!1):b.clearTimeout(this._call),this._time+=this.read()%c-e,this._timeout=c,this._call=b.setTimeout(a.proxy(this._next,this,d),c-e)},e.prototype.stop=function(){this._core.is(\"rotating\")&&(this._time=0,this._paused=!0,b.clearTimeout(this._call),this._core.leave(\"rotating\"))},e.prototype.pause=function(){this._core.is(\"rotating\")&&!this._paused&&(this._time=this.read(),this._paused=!0,b.clearTimeout(this._call))},e.prototype.destroy=function(){var a,b;this.stop();for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(b in Object.getOwnPropertyNames(this))\"function\"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.autoplay=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){\"use strict\";var e=function(b){this._core=b,this._initialized=!1,this._pages=[],this._controls={},this._templates=[],this.$element=this._core.$element,this._overrides={next:this._core.next,prev:this._core.prev,to:this._core.to},this._handlers={\"prepared.owl.carousel\":a.proxy(function(b){b.namespace&&this._core.settings.dotsData&&this._templates.push('<div class=\"'+this._core.settings.dotClass+'\">'+a(b.content).find(\"[data-dot]\").addBack(\"[data-dot]\").attr(\"data-dot\")+\"</div>\")},this),\"added.owl.carousel\":a.proxy(function(a){a.namespace&&this._core.settings.dotsData&&this._templates.splice(a.position,0,this._templates.pop())},this),\"remove.owl.carousel\":a.proxy(function(a){a.namespace&&this._core.settings.dotsData&&this._templates.splice(a.position,1)},this),\"changed.owl.carousel\":a.proxy(function(a){a.namespace&&\"position\"==a.property.name&&this.draw()},this),\"initialized.owl.carousel\":a.proxy(function(a){a.namespace&&!this._initialized&&(this._core.trigger(\"initialize\",null,\"navigation\"),this.initialize(),this.update(),this.draw(),this._initialized=!0,this._core.trigger(\"initialized\",null,\"navigation\"))},this),\"refreshed.owl.carousel\":a.proxy(function(a){a.namespace&&this._initialized&&(this._core.trigger(\"refresh\",null,\"navigation\"),this.update(),this.draw(),this._core.trigger(\"refreshed\",null,\"navigation\"))},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this.$element.on(this._handlers)};e.Defaults={nav:!1,navText:['<span aria-label=\"Previous\">&#x2039;</span>','<span aria-label=\"Next\">&#x203a;</span>'],navSpeed:!1,navElement:'button type=\"button\" role=\"presentation\"',navContainer:!1,navContainerClass:\"owl-nav\",navClass:[\"owl-prev\",\"owl-next\"],slideBy:1,dotClass:\"owl-dot\",dotsClass:\"owl-dots\",dots:!0,dotsEach:!1,dotsData:!1,dotsSpeed:!1,dotsContainer:!1},e.prototype.initialize=function(){var b,c=this._core.settings;this._controls.$relative=(c.navContainer?a(c.navContainer):a(\"<div>\").addClass(c.navContainerClass).appendTo(this.$element)).addClass(\"disabled\"),this._controls.$previous=a(\"<\"+c.navElement+\">\").addClass(c.navClass[0]).html(c.navText[0]).prependTo(this._controls.$relative).on(\"click\",a.proxy(function(a){this.prev(c.navSpeed)},this)),this._controls.$next=a(\"<\"+c.navElement+\">\").addClass(c.navClass[1]).html(c.navText[1]).appendTo(this._controls.$relative).on(\"click\",a.proxy(function(a){this.next(c.navSpeed)},this)),c.dotsData||(this._templates=[a('<button role=\"button\">').addClass(c.dotClass).append(a(\"<span>\")).prop(\"outerHTML\")]),this._controls.$absolute=(c.dotsContainer?a(c.dotsContainer):a(\"<div>\").addClass(c.dotsClass).appendTo(this.$element)).addClass(\"disabled\"),this._controls.$absolute.on(\"click\",\"button\",a.proxy(function(b){var d=a(b.target).parent().is(this._controls.$absolute)?a(b.target).index():a(b.target).parent().index();b.preventDefault(),this.to(d,c.dotsSpeed)},this));for(b in this._overrides)this._core[b]=a.proxy(this[b],this)},e.prototype.destroy=function(){var a,b,c,d,e;e=this._core.settings;for(a in this._handlers)this.$element.off(a,this._handlers[a]);for(b in this._controls)\"$relative\"===b&&e.navContainer?this._controls[b].html(\"\"):this._controls[b].remove();for(d in this.overides)this._core[d]=this._overrides[d];for(c in Object.getOwnPropertyNames(this))\"function\"!=typeof this[c]&&(this[c]=null)},e.prototype.update=function(){var a,b,c,d=this._core.clones().length/2,e=d+this._core.items().length,f=this._core.maximum(!0),g=this._core.settings,h=g.center||g.autoWidth||g.dotsData?1:g.dotsEach||g.items;if(\"page\"!==g.slideBy&&(g.slideBy=Math.min(g.slideBy,g.items)),g.dots||\"page\"==g.slideBy)for(this._pages=[],a=d,b=0,c=0;a<e;a++){if(b>=h||0===b){if(this._pages.push({start:Math.min(f,a-d),end:a-d+h-1}),Math.min(f,a-d)===f)break;b=0,++c}b+=this._core.mergers(this._core.relative(a))}},e.prototype.draw=function(){var b,c=this._core.settings,d=this._core.items().length<=c.items,e=this._core.relative(this._core.current()),f=c.loop||c.rewind;this._controls.$relative.toggleClass(\"disabled\",!c.nav||d),c.nav&&(this._controls.$previous.toggleClass(\"disabled\",!f&&e<=this._core.minimum(!0)),this._controls.$next.toggleClass(\"disabled\",!f&&e>=this._core.maximum(!0))),this._controls.$absolute.toggleClass(\"disabled\",!c.dots||d),c.dots&&(b=this._pages.length-this._controls.$absolute.children().length,c.dotsData&&0!==b?this._controls.$absolute.html(this._templates.join(\"\")):b>0?this._controls.$absolute.append(new Array(b+1).join(this._templates[0])):b<0&&this._controls.$absolute.children().slice(b).remove(),this._controls.$absolute.find(\".active\").removeClass(\"active\"),this._controls.$absolute.children().eq(a.inArray(this.current(),this._pages)).addClass(\"active\"))},e.prototype.onTrigger=function(b){var c=this._core.settings;b.page={index:a.inArray(this.current(),this._pages),count:this._pages.length,size:c&&(c.center||c.autoWidth||c.dotsData?1:c.dotsEach||c.items)}},e.prototype.current=function(){var b=this._core.relative(this._core.current());return a.grep(this._pages,a.proxy(function(a,c){return a.start<=b&&a.end>=b},this)).pop()},e.prototype.getPosition=function(b){var c,d,e=this._core.settings;return\"page\"==e.slideBy?(c=a.inArray(this.current(),this._pages),d=this._pages.length,b?++c:--c,c=this._pages[(c%d+d)%d].start):(c=this._core.relative(this._core.current()),d=this._core.items().length,b?c+=e.slideBy:c-=e.slideBy),c},e.prototype.next=function(b){a.proxy(this._overrides.to,this._core)(this.getPosition(!0),b)},e.prototype.prev=function(b){a.proxy(this._overrides.to,this._core)(this.getPosition(!1),b)},e.prototype.to=function(b,c,d){var e;!d&&this._pages.length?(e=this._pages.length,a.proxy(this._overrides.to,this._core)(this._pages[(b%e+e)%e].start,c)):a.proxy(this._overrides.to,this._core)(b,c)},a.fn.owlCarousel.Constructor.Plugins.Navigation=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){\"use strict\";var e=function(c){this._core=c,this._hashes={},this.$element=this._core.$element,this._handlers={\"initialized.owl.carousel\":a.proxy(function(c){c.namespace&&\"URLHash\"===this._core.settings.startPosition&&a(b).trigger(\"hashchange.owl.navigation\")},this),\"prepared.owl.carousel\":a.proxy(function(b){if(b.namespace){var c=a(b.content).find(\"[data-hash]\").addBack(\"[data-hash]\").attr(\"data-hash\");if(!c)return;this._hashes[c]=b.content}},this),\"changed.owl.carousel\":a.proxy(function(c){if(c.namespace&&\"position\"===c.property.name){var d=this._core.items(this._core.relative(this._core.current())),e=a.map(this._hashes,function(a,b){return a===d?b:null}).join();if(!e||b.location.hash.slice(1)===e)return;b.location.hash=e}},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this.$element.on(this._handlers),a(b).on(\"hashchange.owl.navigation\",a.proxy(function(a){var c=b.location.hash.substring(1),e=this._core.$stage.children(),f=this._hashes[c]&&e.index(this._hashes[c]);f!==d&&f!==this._core.current()&&this._core.to(this._core.relative(f),!1,!0)},this))};e.Defaults={URLhashListener:!1},e.prototype.destroy=function(){var c,d;a(b).off(\"hashchange.owl.navigation\");for(c in this._handlers)this._core.$element.off(c,this._handlers[c]);for(d in Object.getOwnPropertyNames(this))\"function\"!=typeof this[d]&&(this[d]=null)},a.fn.owlCarousel.Constructor.Plugins.Hash=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){function e(b,c){var e=!1,f=b.charAt(0).toUpperCase()+b.slice(1);return a.each((b+\" \"+h.join(f+\" \")+f).split(\" \"),function(a,b){if(g[b]!==d)return e=!c||b,!1}),e}function f(a){return e(a,!0)}var g=a(\"<support>\").get(0).style,h=\"Webkit Moz O ms\".split(\" \"),i={transition:{end:{WebkitTransition:\"webkitTransitionEnd\",MozTransition:\"transitionend\",OTransition:\"oTransitionEnd\",transition:\"transitionend\"}},animation:{end:{WebkitAnimation:\"webkitAnimationEnd\",MozAnimation:\"animationend\",OAnimation:\"oAnimationEnd\",animation:\"animationend\"}}},j={csstransforms:function(){return!!e(\"transform\")},csstransforms3d:function(){return!!e(\"perspective\")},csstransitions:function(){return!!e(\"transition\")},cssanimations:function(){return!!e(\"animation\")}};j.csstransitions()&&(a.support.transition=new String(f(\"transition\")),a.support.transition.end=i.transition.end[a.support.transition]),j.cssanimations()&&(a.support.animation=new String(f(\"animation\")),a.support.animation.end=i.animation.end[a.support.animation]),j.csstransforms()&&(a.support.transform=new String(f(\"transform\")),a.support.transform3d=j.csstransforms3d())}(window.Zepto||window.jQuery,window,document);\n}));\n","Smartwave_Filterproducts/js/lazyload/jquery.lazyload.js":"/*!\r\n * Lazy Load - JavaScript plugin for lazy loading images\r\n *\r\n * Copyright (c) 2007-2019 Mika Tuupola\r\n *\r\n * Licensed under the MIT license:\r\n *   http://www.opensource.org/licenses/mit-license.php\r\n *\r\n * Project home:\r\n *   https://appelsiini.net/projects/lazyload\r\n *\r\n * Version: 2.0.0-rc.2\r\n *\r\n */\r\n\r\n(function (root, factory) {\r\n    if (typeof exports === \"object\") {\r\n        module.exports = factory(root);\r\n    } else if (typeof define === \"function\" && define.amd) {\r\n        define([], factory);\r\n    } else {\r\n        root.LazyLoad = factory(root);\r\n    }\r\n}) (typeof global !== \"undefined\" ? global : this.window || this.global, function (root) {\r\n\r\n    \"use strict\";\r\n\r\n    if (typeof define === \"function\" && define.amd){\r\n        root = window;\r\n    }\r\n\r\n    const defaults = {\r\n        src: \"data-src\",\r\n        srcset: \"data-srcset\",\r\n        selector: \".lazyload\",\r\n        root: null,\r\n        rootMargin: \"0px\",\r\n        threshold: 0\r\n    };\r\n\r\n    /**\r\n    * Merge two or more objects. Returns a new object.\r\n    * @private\r\n    * @param {Boolean}  deep     If true, do a deep (or recursive) merge [optional]\r\n    * @param {Object}   objects  The objects to merge together\r\n    * @returns {Object}          Merged values of defaults and options\r\n    */\r\n    const extend = function ()  {\r\n\r\n        let extended = {};\r\n        let deep = false;\r\n        let i = 0;\r\n        let length = arguments.length;\r\n\r\n        /* Check if a deep merge */\r\n        if (Object.prototype.toString.call(arguments[0]) === \"[object Boolean]\") {\r\n            deep = arguments[0];\r\n            i++;\r\n        }\r\n\r\n        /* Merge the object into the extended object */\r\n        let merge = function (obj) {\r\n            for (let prop in obj) {\r\n                if (Object.prototype.hasOwnProperty.call(obj, prop)) {\r\n                    /* If deep merge and property is an object, merge properties */\r\n                    if (deep && Object.prototype.toString.call(obj[prop]) === \"[object Object]\") {\r\n                        extended[prop] = extend(true, extended[prop], obj[prop]);\r\n                    } else {\r\n                        extended[prop] = obj[prop];\r\n                    }\r\n                }\r\n            }\r\n        };\r\n\r\n        /* Loop through each object and conduct a merge */\r\n        for (; i < length; i++) {\r\n            let obj = arguments[i];\r\n            merge(obj);\r\n        }\r\n\r\n        return extended;\r\n    };\r\n\r\n    function LazyLoad(images, options) {\r\n        this.settings = extend(defaults, options || {});\r\n        this.images = images || document.querySelectorAll(this.settings.selector);\r\n        this.observer = null;\r\n        this.init();\r\n    }\r\n\r\n    LazyLoad.prototype = {\r\n        init: function() {\r\n\r\n            /* Without observers load everything and bail out early. */\r\n            if (!root.IntersectionObserver) {\r\n                this.loadImages();\r\n                return;\r\n            }\r\n\r\n            let self = this;\r\n            let observerConfig = {\r\n                root: this.settings.root,\r\n                rootMargin: this.settings.rootMargin,\r\n                threshold: [this.settings.threshold]\r\n            };\r\n\r\n            this.observer = new IntersectionObserver(function(entries) {\r\n                Array.prototype.forEach.call(entries, function (entry) {\r\n                    if (entry.isIntersecting) {\r\n                        self.observer.unobserve(entry.target);\r\n                        let src = entry.target.getAttribute(self.settings.src);\r\n                        let srcset = entry.target.getAttribute(self.settings.srcset);\r\n                        if (\"img\" === entry.target.tagName.toLowerCase()) {\r\n                            if (src) {\r\n                                entry.target.src = src;\r\n                            }\r\n                            if (srcset) {\r\n                                entry.target.srcset = srcset;\r\n                            }\r\n                        } else {\r\n                            entry.target.style.backgroundImage = \"url(\" + src + \")\";\r\n                        }\r\n                    }\r\n                });\r\n            }, observerConfig);\r\n\r\n            Array.prototype.forEach.call(this.images, function (image) {\r\n                self.observer.observe(image);\r\n            });\r\n        },\r\n\r\n        loadAndDestroy: function () {\r\n            if (!this.settings) { return; }\r\n            this.loadImages();\r\n            this.destroy();\r\n        },\r\n\r\n        loadImages: function () {\r\n            if (!this.settings) { return; }\r\n\r\n            let self = this;\r\n            Array.prototype.forEach.call(this.images, function (image) {\r\n                let src = image.getAttribute(self.settings.src);\r\n                let srcset = image.getAttribute(self.settings.srcset);\r\n                if (\"img\" === image.tagName.toLowerCase()) {\r\n                    if (src) {\r\n                        image.src = src;\r\n                    }\r\n                    if (srcset) {\r\n                        image.srcset = srcset;\r\n                    }\r\n                } else {\r\n                    image.style.backgroundImage = \"url('\" + src + \"')\";\r\n                }\r\n            });\r\n        },\r\n\r\n        destroy: function () {\r\n            if (!this.settings) { return; }\r\n            this.observer.disconnect();\r\n            this.settings = null;\r\n        }\r\n    };\r\n\r\n    root.lazyload = function(images, options) {\r\n        return new LazyLoad(images, options);\r\n    };\r\n\r\n    if (root.jQuery) {\r\n        const $ = root.jQuery;\r\n        $.fn.lazyload = function (options) {\r\n            options = options || {};\r\n            options.attribute = options.attribute || \"data-src\";\r\n            new LazyLoad($.makeArray(this), options);\r\n            return this;\r\n        };\r\n    }\r\n\r\n    return LazyLoad;\r\n});\r\n","Magento_ReCaptchaWebapiUi/js/webapiReCaptcha.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n// jscs:disable jsDoc\n\n/* global grecaptcha */\ndefine(\n    [\n        'Magento_ReCaptchaFrontendUi/js/reCaptcha',\n        'Magento_ReCaptchaWebapiUi/js/webapiReCaptchaRegistry'\n    ],\n    function (Component, registry) {\n        'use strict';\n\n        return Component.extend({\n            defaults: {\n                autoTrigger: false\n            },\n\n            /**\n             * Provide the token to the registry.\n             *\n             * @param {String} token\n             */\n            reCaptchaCallback: function (token) {\n                //Make the token retrievable in other UI components.\n                registry.tokens[this.getReCaptchaId()] = token;\n\n                if (typeof registry._listeners[this.getReCaptchaId()] !== 'undefined') {\n                    registry._listeners[this.getReCaptchaId()](token);\n                }\n            },\n\n            /**\n             * Register this ReCaptcha.\n             *\n             * @param {Object} parentForm\n             * @param {String} widgetId\n             */\n            initParentForm: function (parentForm, widgetId) {\n                var self = this,\n                    trigger;\n\n                trigger = function () {\n                    self.reCaptchaCallback(grecaptcha.getResponse(widgetId));\n                };\n                registry._isInvisibleType[this.getReCaptchaId()] = false;\n\n                if (this.getIsInvisibleRecaptcha()) {\n                    trigger = function () {\n                        grecaptcha.execute(widgetId);\n                    };\n                    registry._isInvisibleType[this.getReCaptchaId()] = true;\n                }\n\n                if (this.autoTrigger) {\n                    //Validate ReCaptcha when initiated\n                    trigger();\n                    registry.triggers[this.getReCaptchaId()] = new Function();\n                } else {\n                    registry.triggers[this.getReCaptchaId()] = trigger;\n                }\n                this.tokenField = null;\n            }\n        });\n    }\n);\n","Magento_ReCaptchaWebapiUi/js/jquery-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n// jscs:disable requireDotNotation\n\ndefine([\n    'mage/utils/wrapper'\n], function (wrapper) {\n    'use strict';\n\n    return function (jQuery) {\n        jQuery.ajax = wrapper.wrapSuper(jQuery.ajax, function () {\n            //Moving ReCaptcha value from payload to the header for requests to web API\n            var settings,\n                payload;\n\n            if (arguments.length !== 0) {\n                settings = arguments.length === 1 ? arguments[0] : arguments[1];\n            }\n\n            if (settings && settings.hasOwnProperty('data')) {\n                //The request has a body, trying to parse JSON data\n                try {\n                    payload = JSON.parse(settings.data);\n                } catch (e) {\n                    //Not JSON\n                }\n            }\n\n            if (payload && payload.hasOwnProperty('xReCaptchaValue')) {\n                if (!settings.hasOwnProperty('headers')) {\n                    settings.headers = {};\n                }\n                settings.headers['X-ReCaptcha'] = payload.xReCaptchaValue;\n                delete payload['xReCaptchaValue'];\n                settings.data = JSON.stringify(payload);\n            }\n\n            return this._super.apply(this, arguments);\n        });\n\n        return jQuery;\n    };\n});\n","Magento_ReCaptchaWebapiUi/js/webapiReCaptchaRegistry.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        /**\n         * recaptchaId: token map.\n         *\n         * Tokens for already verified recaptcha.\n         */\n        tokens: {},\n\n        /**\n         * recaptchaId: triggerFn map.\n         *\n         * Call a trigger to initiate a recaptcha verification.\n         */\n        triggers: {},\n\n        /**\n         * recaptchaId: callback map\n         */\n        _listeners: {},\n\n        /**\n         * recaptchaId: bool map\n         */\n        _isInvisibleType: {},\n\n        /**\n         * Add a listener to when the ReCaptcha finishes verification\n         * @param {String} id - ReCaptchaId\n         * @param {Function} func - Will be called back with the token\n         */\n        addListener: function (id, func) {\n            if (this.tokens.hasOwnProperty(id)) {\n                func(this.tokens[id]);\n            } else {\n                this._listeners[id] = func;\n            }\n        },\n\n        /**\n         * Remove a listener\n         *\n         * @param id\n         */\n        removeListener: function (id) {\n            this._listeners[id] = undefined;\n        }\n    };\n});\n","Magento_Ui/js/block-loader.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'jquery',\n    'Magento_Ui/js/lib/knockout/template/loader',\n    'mage/template'\n], function (ko, $, templateLoader, template) {\n    'use strict';\n\n    var blockLoaderTemplatePath = 'ui/block-loader',\n        blockContentLoadingClass = '_block-content-loading',\n        blockLoader,\n        blockLoaderClass,\n        blockLoaderElement = $.Deferred(),\n        loaderImageHref = $.Deferred();\n\n    templateLoader.loadTemplate(blockLoaderTemplatePath).done(function (blockLoaderTemplate) {\n        loaderImageHref.done(function (loaderHref) {\n            blockLoader = template(blockLoaderTemplate.trim(), {\n                loaderImageHref: loaderHref\n            });\n            blockLoader = $(blockLoader);\n            blockLoaderClass = '.' + blockLoader.attr('class');\n            blockLoaderElement.resolve();\n        });\n    });\n\n    /**\n     * Helper function to check if blockContentLoading class should be applied.\n     * @param {Object} element\n     * @returns {Boolean}\n     */\n    function isLoadingClassRequired(element) {\n        var position = element.css('position');\n\n        if (position === 'absolute' || position === 'fixed') {\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * Add loader to block.\n     * @param {Object} element\n     */\n    function addBlockLoader(element) {\n        element.find(':focus').trigger('blur');\n        element.find('input:disabled, select:disabled').addClass('_disabled');\n        element.find('input, select').prop('disabled', true);\n\n        if (isLoadingClassRequired(element)) {\n            element.addClass(blockContentLoadingClass);\n        }\n        element.append(blockLoader.clone());\n    }\n\n    /**\n     * Remove loader from block.\n     * @param {Object} element\n     */\n    function removeBlockLoader(element) {\n        if (!element.has(blockLoaderClass).length) {\n            return;\n        }\n        element.find(blockLoaderClass).remove();\n        element.find('input:not(\"._disabled\"), select:not(\"._disabled\")').prop('disabled', false);\n        element.find('input:disabled, select:disabled').removeClass('_disabled');\n        element.removeClass(blockContentLoadingClass);\n    }\n\n    return function (loaderHref) {\n        loaderImageHref.resolve(loaderHref);\n        ko.bindingHandlers.blockLoader = {\n            /**\n             * Process loader for block\n             * @param {String} element\n             * @param {Boolean} displayBlockLoader\n             */\n            update: function (element, displayBlockLoader) {\n                element = $(element);\n\n                if (ko.unwrap(displayBlockLoader())) {\n                    blockLoaderElement.done(addBlockLoader(element));\n                } else {\n                    blockLoaderElement.done(removeBlockLoader(element));\n                }\n            }\n        };\n    };\n});\n","Magento_Ui/js/form/form.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'Magento_Ui/js/lib/spinner',\n    'rjsResolver',\n    './adapter',\n    'uiCollection',\n    'mageUtils',\n    'jquery',\n    'Magento_Ui/js/core/app',\n    'mage/validation'\n], function (_, loader, resolver, adapter, Collection, utils, $, app) {\n    'use strict';\n\n    /**\n     * Format params\n     *\n     * @param {Object} params\n     * @returns {Array}\n     */\n    function prepareParams(params) {\n        var result = '?';\n\n        _.each(params, function (value, key) {\n            result += key + '=' + value + '&';\n        });\n\n        return result.slice(0, -1);\n    }\n\n    /**\n     * Collect form data.\n     *\n     * @param {Array} items\n     * @returns {Object}\n     */\n    function collectData(items) {\n        var result = {},\n            name;\n\n        items = Array.prototype.slice.call(items);\n\n        items.forEach(function (item) {\n            switch (item.type) {\n                case 'checkbox':\n                    result[item.name] = +!!item.checked;\n                    break;\n\n                case 'radio':\n                    if (item.checked) {\n                        result[item.name] = item.value;\n                    }\n                    break;\n\n                case 'select-multiple':\n                    name = item.name.substring(0, item.name.length - 2); //remove [] from the name ending\n                    result[name] = _.pluck(item.selectedOptions, 'value');\n                    break;\n\n                default:\n                    result[item.name] = item.value;\n            }\n        });\n\n        return result;\n    }\n\n    /**\n     * Makes ajax request\n     *\n     * @param {Object} params\n     * @param {Object} data\n     * @param {String} url\n     * @returns {*}\n     */\n    function makeRequest(params, data, url) {\n        var save = $.Deferred();\n\n        data = utils.serialize(data);\n        data['form_key'] = window.FORM_KEY;\n\n        if (!url) {\n            save.resolve();\n        }\n\n        $('body').trigger('processStart');\n\n        $.ajax({\n            url: url + prepareParams(params),\n            data: data,\n            dataType: 'json',\n\n            /**\n             * Success callback.\n             * @param {Object} resp\n             * @returns {Boolean}\n             */\n            success: function (resp) {\n                if (resp.ajaxExpired) {\n                    window.location.href = resp.ajaxRedirect;\n                }\n\n                if (!resp.error) {\n                    save.resolve(resp);\n\n                    return true;\n                }\n\n                $('body').notification('clear');\n                $.each(resp.messages, function (key, message) {\n                    $('body').notification('add', {\n                        error: resp.error,\n                        message: message,\n\n                        /**\n                         * Inserts message on page\n                         * @param {String} msg\n                         */\n                        insertMethod: function (msg) {\n                            $('.page-main-actions').after(msg);\n                        }\n                    });\n                });\n            },\n\n            /**\n             * Complete callback.\n             */\n            complete: function () {\n                $('body').trigger('processStop');\n            }\n        });\n\n        return save.promise();\n    }\n\n    /**\n     * Check if fields is valid.\n     *\n     * @param {Array}items\n     * @returns {Boolean}\n     */\n    function isValidFields(items) {\n        var result = true;\n\n        _.each(items, function (item) {\n            if (!$.validator.validateSingleElement(item)) {\n                result = false;\n            }\n        });\n\n        return result;\n    }\n\n    return Collection.extend({\n        defaults: {\n            additionalFields: [],\n            additionalInvalid: false,\n            selectorPrefix: '.page-content',\n            messagesClass: 'messages',\n            errorClass: '.admin__field._error',\n            eventPrefix: '.${ $.index }',\n            ajaxSave: false,\n            ajaxSaveType: 'default',\n            imports: {\n                reloadUrl: '${ $.provider}:reloadUrl'\n            },\n            listens: {\n                selectorPrefix: 'destroyAdapter initAdapter',\n                '${ $.name }.${ $.reloadItem }': 'params.set reload'\n            },\n            exports: {\n                selectorPrefix: '${ $.provider }:client.selectorPrefix',\n                messagesClass: '${ $.provider }:client.messagesClass'\n            }\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            this._super()\n                .initAdapter();\n\n            resolver(this.hideLoader, this);\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            return this._super()\n                .observe([\n                    'responseData',\n                    'responseStatus'\n                ]);\n        },\n\n        /** @inheritdoc */\n        initConfig: function () {\n            this._super();\n\n            this.selector = '[data-form-part=' + this.namespace + ']';\n\n            return this;\n        },\n\n        /**\n         * Initialize adapter handlers.\n         *\n         * @returns {Object}\n         */\n        initAdapter: function () {\n            adapter.on({\n                'reset': this.reset.bind(this),\n                'save': this.save.bind(this, true, {}),\n                'saveAndContinue': this.save.bind(this, false, {})\n            }, this.selectorPrefix, this.eventPrefix);\n\n            return this;\n        },\n\n        /**\n         * Destroy adapter handlers.\n         *\n         * @returns {Object}\n         */\n        destroyAdapter: function () {\n            adapter.off([\n                'reset',\n                'save',\n                'saveAndContinue'\n            ], this.eventPrefix);\n\n            return this;\n        },\n\n        /**\n         * Hide loader.\n         *\n         * @returns {Object}\n         */\n        hideLoader: function () {\n            loader.get(this.name).hide();\n\n            return this;\n        },\n\n        /**\n         * Validate and save form.\n         *\n         * @param {String} redirect\n         * @param {Object} data\n         */\n        save: function (redirect, data) {\n            this.validate();\n\n            if (!this.additionalInvalid && !this.source.get('params.invalid')) {\n                this.setAdditionalData(data)\n                    .submit(redirect);\n            } else {\n                this.focusInvalid();\n            }\n        },\n\n        /**\n         * Tries to set focus on first invalid form field.\n         *\n         * @returns {Object}\n         */\n        focusInvalid: function () {\n            var invalidField = _.find(this.delegate('checkInvalid'));\n\n            if (!_.isUndefined(invalidField) && _.isFunction(invalidField.focused)) {\n                invalidField.focused(true);\n            }\n\n            return this;\n        },\n\n        /**\n         * Set additional data to source before form submit and after validation.\n         *\n         * @param {Object} data\n         * @returns {Object}\n         */\n        setAdditionalData: function (data) {\n            _.each(data, function (value, name) {\n                this.source.set('data.' + name, value);\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Submits form\n         *\n         * @param {String} redirect\n         */\n        submit: function (redirect) {\n            var additional = collectData(this.additionalFields),\n                source = this.source;\n\n            _.each(additional, function (value, name) {\n                source.set('data.' + name, value);\n            });\n\n            source.save({\n                redirect: redirect,\n                ajaxSave: this.ajaxSave,\n                ajaxSaveType: this.ajaxSaveType,\n                response: {\n                    data: this.responseData,\n                    status: this.responseStatus\n                },\n                attributes: {\n                    id: this.namespace\n                }\n            });\n        },\n\n        /**\n         * Validates each element and returns true, if all elements are valid.\n         */\n        validate: function () {\n            this.additionalFields = document.querySelectorAll(this.selector);\n            this.source.set('params.invalid', false);\n            this.source.trigger('data.validate');\n            this.set('additionalInvalid', !isValidFields(this.additionalFields));\n        },\n\n        /**\n         * Trigger reset form data.\n         */\n        reset: function () {\n            this.source.trigger('data.reset');\n            $('[data-bind*=datepicker]').val('');\n        },\n\n        /**\n         * Trigger overload form data.\n         */\n        overload: function () {\n            this.source.trigger('data.overload');\n        },\n\n        /**\n         * Updates data from server.\n         */\n        reload: function () {\n            makeRequest(this.params, this.data, this.reloadUrl).then(function (data) {\n                app(data, true);\n            });\n        }\n    });\n});\n","Magento_Ui/js/form/adapter.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore',\n    'Magento_Ui/js/form/adapter/buttons'\n], function ($, _, buttons) {\n    'use strict';\n\n    var selectorPrefix = '',\n        eventPrefix;\n\n    /**\n     * Initialize listener.\n     *\n     * @param {Function} callback\n     * @param {String} action\n     */\n    function initListener(callback, action) {\n        var selector    = selectorPrefix ? selectorPrefix + ' ' + buttons[action] : buttons[action],\n            elem        = $(selector)[0];\n\n        if (!elem) {\n            return;\n        }\n\n        if (elem.onclick) {\n            elem.onclick = null;\n        }\n\n        $(elem).on('click' + eventPrefix, callback);\n    }\n\n    /**\n     * Destroy listener.\n     *\n     * @param {String} action\n     */\n    function destroyListener(action) {\n        var selector    = selectorPrefix ? selectorPrefix + ' ' + buttons[action] : buttons[action],\n            elem        = $(selector)[0];\n\n        if (!elem) {\n            return;\n        }\n\n        if (elem.onclick) {\n            elem.onclick = null;\n        }\n\n        $(elem).off('click' + eventPrefix);\n    }\n\n    return {\n\n        /**\n         * Attaches events handlers.\n         *\n         * @param {Object} handlers\n         * @param {String} selectorPref\n         * @param {String} eventPref\n         */\n        on: function (handlers, selectorPref, eventPref) {\n            selectorPrefix = selectorPrefix || selectorPref;\n            eventPrefix = eventPref;\n            _.each(handlers, initListener);\n            selectorPrefix = '';\n        },\n\n        /**\n         * Removes events handlers.\n         *\n         * @param {Object} handlers\n         * @param {String} eventPref\n         */\n        off: function (handlers, eventPref) {\n            eventPrefix = eventPref;\n            _.each(handlers, destroyListener);\n        }\n    };\n});\n","Magento_Ui/js/form/button-adapter.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'uiClass',\n    'jquery',\n    'underscore',\n    'uiRegistry'\n], function (Class, $, _, registry) {\n    'use strict';\n\n    return Class.extend({\n\n        /**\n         * Initialize actions and adapter.\n         *\n         * @param {Object} config\n         * @param {Element} elem\n         * @returns {Object}\n         */\n        initialize: function (config, elem) {\n            return this._super()\n                .initActions()\n                .initAdapter(elem);\n        },\n\n        /**\n         * Creates callback from declared actions.\n         *\n         * @returns {Object}\n         */\n        initActions: function () {\n            var callbacks = [];\n\n            _.each(this.actions, function (action) {\n                callbacks.push({\n                    action: registry.async(action.targetName),\n                    args: _.union([action.actionName], action.params)\n                });\n            });\n\n            /**\n             * Callback function.\n             */\n            this.callback = function () {\n                _.each(callbacks, function (callback) {\n                    callback.action.apply(callback.action, callback.args);\n                });\n            };\n\n            return this;\n        },\n\n        /**\n         * Attach callback handler on button.\n         *\n         * @param {Element} elem\n         */\n        initAdapter: function (elem) {\n            $(elem).on('click', this.callback);\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/form/provider.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'uiElement',\n    './client',\n    'mageUtils'\n], function (_, Element, Client, utils) {\n    'use strict';\n\n    return Element.extend({\n        defaults: {\n            clientConfig: {\n                urls: {\n                    save: '${ $.submit_url }',\n                    beforeSave: '${ $.validate_url }'\n                }\n            },\n            ignoreTmpls: {\n                data: true\n            }\n        },\n\n        /**\n         * Initializes provider component.\n         *\n         * @returns {Provider} Chainable.\n         */\n        initialize: function () {\n            this._super()\n                .initClient();\n\n            return this;\n        },\n\n        /**\n         * Initializes client component.\n         *\n         * @returns {Provider} Chainable.\n         */\n        initClient: function () {\n            this.client = new Client(this.clientConfig);\n\n            return this;\n        },\n\n        /**\n         * Saves currently available data.\n         *\n         * @param {Object} [options] - Addtitional request options.\n         * @returns {Provider} Chainable.\n         */\n        save: function (options) {\n            var data = this.get('data');\n\n            this.client.save(data, options);\n\n            return this;\n        },\n\n        /**\n         * Update data that stored in provider.\n         *\n         * @param {Boolean} isProvider\n         * @param {Object} newData\n         * @param {Object} oldData\n         *\n         * @returns {Provider}\n         */\n        updateConfig: function (isProvider, newData, oldData) {\n            if (isProvider === true) {\n                this.setData(oldData, newData, this);\n            }\n\n            return this;\n        },\n\n        /**\n         *  Set data to provider based on current data.\n         *\n         * @param {Object} oldData\n         * @param {Object} newData\n         * @param {Provider} current\n         * @param {String} parentPath\n         */\n        setData: function (oldData, newData, current, parentPath) {\n            _.each(newData, function (val, key) {\n                if (_.isObject(val) || _.isArray(val)) {\n                    this.setData(oldData[key], val, current[key], utils.fullPath(parentPath, key));\n                } else if (val != oldData[key] && oldData[key] == current[key]) {//eslint-disable-line eqeqeq\n                    this.set(utils.fullPath(parentPath, key), val);\n                }\n            }, this);\n        }\n    });\n});\n","Magento_Ui/js/form/switcher.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'uiRegistry',\n    'uiClass'\n], function (_, registry, Class) {\n    'use strict';\n\n    return Class.extend({\n        defaults: {\n            rules: []\n        },\n\n        /**\n         * Initializes instance of a DataSwitcher.\n         *\n         * @returns {DataSwitcher} Chainable.\n         */\n        initialize: function () {\n            this._super()\n                .initRules();\n\n            return this;\n        },\n\n        /**\n         *\n         * @returns {DataSwitcher} Chainable.\n         */\n        initRules: function () {\n            this.rules.forEach(this.initRule, this);\n\n            return this;\n        },\n\n        /**\n         *\n         * @param {Object} rule - Rule definition.\n         * @returns {DataSwitcher} Chainable.\n         */\n        initRule: function (rule) {\n            var handler = this.onValueChange.bind(this, rule);\n\n            if (!rule.target) {\n                rule.target = this.target;\n            }\n\n            if (!rule.property) {\n                rule.property = this.property;\n            }\n\n            registry.get(rule.target, function (target) {\n                this.applyRule(rule, target.get(rule.property));\n                target.on(rule.property, handler);\n            }.bind(this));\n\n            return this;\n        },\n\n        /**\n         *\n         * @param {Object} rule - Rule definition.\n         * @returns {DataSwitcher} Chainable.\n         */\n        addRule: function (rule) {\n            this.rules.push(rule);\n            this.initRule(rule);\n\n            return this;\n        },\n\n        /**\n         *\n         * @param {Object} rule - Rule object.\n         * @param {*} value - Current value associated with a rule.\n         */\n        applyRule: function (rule, value) {\n            var actions = rule.actions;\n\n            //TODO Refactor this logic in scope of MAGETWO-48585\n            /* eslint-disable eqeqeq */\n            if (rule.value != value) {\n                return;\n            } else if (rule.strict) {\n                return;\n            }\n\n            /* eslint-enable eqeqeq */\n            actions.forEach(this.applyAction, this);\n        },\n\n        /**\n         *\n         * @param {Object} action - Action object.\n         */\n        applyAction: function (action) {\n            registry.get(action.target, function (target) {\n                var callback = target[action.callback];\n\n                callback.apply(target, action.params || []);\n            });\n        },\n\n        /**\n         *\n         * @param {Object} rule - Rules object.\n         * @param {*} value - Current value associated with a rule.\n         */\n        onValueChange: function (rule, value) {\n            this.applyRule(rule, value);\n        }\n    });\n});\n","Magento_Ui/js/form/client.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'underscore',\n    'mageUtils',\n    'uiClass'\n], function ($, _, utils, Class) {\n    'use strict';\n\n    /**\n     * Before save validate request.\n     *\n     * @param {Object} data\n     * @param {String} url\n     * @param {String} selectorPrefix\n     * @param {String} messagesClass\n     * @returns {*}\n     */\n    function beforeSave(data, url, selectorPrefix, messagesClass) {\n        var save = $.Deferred();\n\n        data = utils.serialize(utils.filterFormData(data));\n        data['form_key'] = window.FORM_KEY;\n\n        if (!url || url === 'undefined') {\n            return save.resolve();\n        }\n\n        $('body').trigger('processStart');\n\n        $.ajax({\n            url: url,\n            data: data,\n\n            /**\n             * Success callback.\n             * @param {Object} resp\n             * @returns {Boolean}\n             */\n            success: function (resp) {\n                if (!resp.error) {\n                    save.resolve();\n\n                    return true;\n                }\n\n                $('body').notification('clear');\n                $.each(resp.messages || [resp.message] || [], function (key, message) {\n                    $('body').notification('add', {\n                        error: resp.error,\n                        message: message,\n\n                        /**\n                         * Insert method.\n                         *\n                         * @param {String} msg\n                         */\n                        insertMethod: function (msg) {\n                            var $wrapper = $('<div></div>').addClass(messagesClass).html(msg);\n\n                            $('.page-main-actions', selectorPrefix).after($wrapper);\n                            $('html, body').animate({\n                                scrollTop: $('.page-main-actions', selectorPrefix).offset().top\n                            });\n                        }\n                    });\n                });\n            },\n\n            /**\n             * Complete callback.\n             */\n            complete: function () {\n                $('body').trigger('processStop');\n            }\n        });\n\n        return save.promise();\n    }\n\n    return Class.extend({\n\n        /**\n         * Assembles data and submits it using 'utils.submit' method\n         */\n        save: function (data, options) {\n            var url = this.urls.beforeSave,\n                save = this._save.bind(this, data, options);\n\n            beforeSave(data, url, this.selectorPrefix, this.messagesClass).then(save);\n\n            return this;\n        },\n\n        /**\n         * Save data.\n         *\n         * @param {Object} data\n         * @param {Object} options\n         * @returns {Object}\n         * @private\n         */\n        _save: function (data, options) {\n            var url = this.urls.save;\n\n            $('body').trigger('processStart');\n            options = options || {};\n\n            if (!options.redirect) {\n                url += 'back/edit';\n            }\n\n            if (options.ajaxSave) {\n                utils.ajaxSubmit({\n                    url: url,\n                    data: data\n                }, options);\n\n                $('body').trigger('processStop');\n\n                return this;\n            }\n\n            utils.submit({\n                url: url,\n                data: data\n            }, options.attributes);\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/form/element/url-input.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'uiLayout',\n    'mage/translate',\n    'Magento_Ui/js/form/element/abstract'\n], function (_, layout, $t, Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n        defaults: {\n            linkedElement: {},\n            settingTemplate: 'ui/form/element/urlInput/setting',\n            typeSelectorTemplate: 'ui/form/element/urlInput/typeSelector',\n            options: [],\n            linkedElementInstances: {},\n            //checkbox\n            isDisplayAdditionalSettings: true,\n            settingValue: false,\n            settingLabel: $t('Open in new tab'),\n            tracks: {\n                linkedElement: true\n            },\n            baseLinkSetting: {\n                namePrefix: '${$.name}.',\n                dataScopePrefix: '${$.dataScope}.',\n                provider: '${$.provider}'\n            },\n            urlTypes: {},\n            listens: {\n                settingValue: 'checked',\n                disabled: 'hideLinkedElement',\n                linkType: 'createChildUrlInputComponent'\n            },\n            links: {\n                linkType: '${$.provider}:${$.dataScope}.type',\n                settingValue: '${$.provider}:${$.dataScope}.setting'\n            }\n        },\n\n        /** @inheritdoc */\n        initConfig: function (config) {\n            var processedLinkTypes = {},\n                baseLinkType = this.constructor.defaults.baseLinkSetting;\n\n            _.each(config.urlTypes, function (linkSettingsArray, linkName) {\n                //add link name by link type\n                linkSettingsArray.name = baseLinkType.namePrefix + linkName;\n                linkSettingsArray.dataScope = baseLinkType.dataScopePrefix + linkName;\n                linkSettingsArray.type = linkName;\n                linkSettingsArray.disabled = config.disabled;\n                linkSettingsArray.visible = config.visible;\n                processedLinkTypes[linkName] = {};\n                _.extend(processedLinkTypes[linkName], baseLinkType, linkSettingsArray);\n            });\n            _.extend(this.constructor.defaults.urlTypes, processedLinkTypes);\n\n            this._super();\n        },\n\n        /**\n         * Initializes observable properties of instance\n         *\n         * @returns {Abstract} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .observe('componentTemplate options value linkType settingValue checked isDisplayAdditionalSettings')\n                .setOptions();\n\n            return this;\n        },\n\n        /**\n         * Set options to select based on link types configuration\n         *\n         * @return {Object}\n         */\n        setOptions: function () {\n            var result = [];\n\n            _.each(this.urlTypes, function (option, key) {\n                result.push({\n                    value: key,\n                    label: option.label,\n                    sortOrder: option.sortOrder || 0\n                });\n            });\n\n            //sort options by sortOrder\n            result.sort(function (a, b) {\n                return a.sortOrder > b.sortOrder ? 1 : -1;\n            });\n\n            this.options(result);\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        setPreview: function (visible) {\n            this.linkedElement().visible(visible);\n        },\n\n        /**\n         * Initializes observable properties of instance\n         *\n         * @param {Boolean} disabled\n         */\n        hideLinkedElement: function (disabled) {\n            this.linkedElement().disabled(disabled);\n        },\n\n        /** @inheritdoc */\n        destroy: function () {\n            _.each(this.linkedElementInstances, function (value) {\n                value().destroy();\n            });\n            this._super();\n        },\n\n        /**\n         * Create child component by value\n         *\n         * @param {String} value\n         * @return void\n         */\n        createChildUrlInputComponent: function (value) {\n            var elementConfig;\n\n            if (!_.isEmpty(value) && _.isUndefined(this.linkedElementInstances[value])) {\n                elementConfig = this.urlTypes[value];\n                layout([elementConfig]);\n                this.linkedElementInstances[value] = this.requestModule(elementConfig.name);\n            }\n            this.linkedElement = this.linkedElementInstances[value];\n\n        },\n\n        /**\n         * Returns linked element to display related field in template\n         * @return String\n         */\n        getLinkedElementName: function () {\n            return this.linkedElement;\n        },\n\n        /**\n         * Add ability to choose check box by clicking on label\n         */\n        checkboxClick: function () {\n            if (!this.disabled()) {\n                this.settingValue(!this.settingValue());\n            }\n        }\n    });\n});\n","Magento_Ui/js/form/element/single-checkbox.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'Magento_Ui/js/form/element/abstract',\n    'underscore',\n    'mage/translate'\n], function (AbstractField, _, $t) {\n    'use strict';\n\n    return AbstractField.extend({\n        defaults: {\n            template: 'ui/form/components/single/field',\n            checked: false,\n            initialChecked: false,\n            multiple: false,\n            prefer: 'checkbox', // 'radio' | 'checkbox' | 'toggle'\n            valueMap: {},\n\n            templates: {\n                radio: 'ui/form/components/single/radio',\n                checkbox: 'ui/form/components/single/checkbox',\n                toggle: 'ui/form/components/single/switcher'\n            },\n\n            listens: {\n                'checked': 'onCheckedChanged',\n                'value': 'onExtendedValueChanged'\n            }\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initConfig: function (config) {\n            this._super();\n\n            if (!config.elementTmpl) {\n                if (!this.prefer && !this.multiple) {\n                    this.elementTmpl = this.templates.radio;\n                } else if (this.prefer === 'radio') {\n                    this.elementTmpl = this.templates.radio;\n                } else if (this.prefer === 'checkbox') {\n                    this.elementTmpl = this.templates.checkbox;\n                } else if (this.prefer === 'toggle') {\n                    this.elementTmpl = this.templates.toggle;\n                } else {\n                    this.elementTmpl = this.templates.checkbox;\n                }\n            }\n\n            if (this.prefer === 'toggle' && _.isEmpty(this.toggleLabels)) {\n                this.toggleLabels = {\n                    'on': $t('Yes'),\n                    'off': $t('No')\n                };\n            }\n\n            if (typeof this.default === 'undefined' || this.default === null) {\n                this.default = '';\n            }\n\n            if (typeof this.value === 'undefined' || this.value === null) {\n                this.value = _.isEmpty(this.valueMap) || this.default !== '' ? this.default : this.valueMap.false;\n                this.initialValue = this.value;\n            } else {\n                this.initialValue = this.value;\n            }\n\n            if (this.multiple && !_.isArray(this.value)) {\n                this.value = []; // needed for correct observable assignment\n            }\n\n            this.initialChecked = this.checked;\n\n            return this;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initObservable: function () {\n            return this\n                ._super()\n                .observe('checked');\n        },\n\n        /**\n         * Get true/false key from valueMap by value.\n         *\n         * @param {*} value\n         * @returns {Boolean|undefined}\n         */\n        getReverseValueMap: function getReverseValueMap(value) {\n            var bool = false;\n\n            _.some(this.valueMap, function (iValue, iBool) {\n                if (iValue === value) {\n                    bool = iBool === 'true';\n\n                    return true;\n                }\n            });\n\n            return bool;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        setInitialValue: function () {\n            if (_.isEmpty(this.valueMap)) {\n                this.on('value', this.onUpdate.bind(this));\n            } else {\n                this._super();\n                this.checked(this.getReverseValueMap(this.value()));\n            }\n\n            return this;\n        },\n\n        /**\n         * Handle dataScope changes for checkbox / radio button.\n         *\n         * @param {*} newExportedValue\n         */\n        onExtendedValueChanged: function (newExportedValue) {\n            var isMappedUsed = !_.isEmpty(this.valueMap),\n                oldChecked = this.checked.peek(),\n                oldValue = this.initialValue,\n                newChecked;\n\n            if (this.multiple) {\n                newChecked = newExportedValue.indexOf(oldValue) !== -1;\n            } else if (isMappedUsed) {\n                newChecked = this.getReverseValueMap(newExportedValue);\n            } else if (typeof newExportedValue === 'boolean') {\n                newChecked = newExportedValue;\n            } else {\n                newChecked = newExportedValue === oldValue;\n            }\n\n            if (newChecked !== oldChecked) {\n                this.checked(newChecked);\n            }\n        },\n\n        /**\n         * Handle checked state changes for checkbox / radio button.\n         *\n         * @param {Boolean} newChecked\n         */\n        onCheckedChanged: function (newChecked) {\n            var isMappedUsed = !_.isEmpty(this.valueMap),\n                oldValue = this.initialValue,\n                newValue;\n\n            if (isMappedUsed) {\n                newValue = this.valueMap[newChecked];\n            } else {\n                newValue = oldValue;\n            }\n\n            if (!this.multiple && newChecked) {\n                this.value(newValue);\n            } else if (!this.multiple && !newChecked) {\n                if (typeof newValue === 'boolean') {\n                    this.value(newChecked);\n                } else if (newValue === this.value.peek()) {\n                    this.value('');\n                }\n\n                if (isMappedUsed) {\n                    this.value(newValue);\n                }\n            } else if (this.multiple && newChecked && this.value.indexOf(newValue) === -1) {\n                this.value.push(newValue);\n            } else if (this.multiple && !newChecked && this.value.indexOf(newValue) !== -1) {\n                this.value.splice(this.value.indexOf(newValue), 1);\n            }\n        },\n\n        /**\n         * @inheritdoc\n         */\n        onUpdate: function () {\n            if (this.hasUnique) {\n                this.setUnique();\n            }\n\n            return this._super();\n        },\n\n        /**\n         * @inheritdoc\n         */\n        reset: function () {\n            if (this.multiple && this.initialChecked) {\n                this.value.push(this.initialValue);\n            } else if (this.multiple && !this.initialChecked) {\n                this.value.splice(this.value.indexOf(this.initialValue), 1);\n            } else {\n                this.value(this.initialValue);\n            }\n\n            this.error(false);\n\n            return this;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        clear: function () {\n            if (this.multiple) {\n                this.value([]);\n            } else {\n                this.value('');\n            }\n\n            this.error(false);\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/form/element/color-picker.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'mage/translate',\n    'Magento_Ui/js/form/element/abstract',\n    'Magento_Ui/js/form/element/color-picker-palette'\n], function ($t, Abstract, palette) {\n    'use strict';\n\n    return Abstract.extend({\n\n        defaults: {\n            colorPickerConfig: {\n                chooseText: $t('Apply'),\n                cancelText: $t('Cancel'),\n                maxSelectionSize: 8,\n                clickoutFiresChange: true,\n                allowEmpty: true,\n                localStorageKey: 'magento.spectrum',\n                palette: palette\n            }\n        },\n\n        /**\n         * Invokes initialize method of parent class,\n         * contains initialization logic\n         */\n        initialize: function () {\n            this._super();\n\n            this.colorPickerConfig.value = this.value;\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/form/element/text.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'uiElement',\n    'mageUtils'\n], function (Element, utils) {\n    'use strict';\n\n    return Element.extend({\n        defaults: {\n            visible: true,\n            label: '',\n            error: '',\n            uid: utils.uniqueid(),\n            disabled: false,\n            links: {\n                value: '${ $.provider }:${ $.dataScope }'\n            }\n        },\n\n        /**\n         * Has service\n         *\n         * @returns {Boolean} false.\n         */\n        hasService: function () {\n            return false;\n        },\n\n        /**\n         * Has addons\n         *\n         * @returns {Boolean} false.\n         */\n        hasAddons: function () {\n            return false;\n        },\n\n        /**\n         * Calls 'initObservable' of parent\n         *\n         * @returns {Object} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .observe('disabled visible value');\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/form/element/textarea.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    './abstract'\n], function (Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n        defaults: {\n            cols: 15,\n            rows: 2,\n            elementTmpl: 'ui/form/element/textarea'\n        }\n    });\n});\n","Magento_Ui/js/form/element/abstract.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'mageUtils',\n    'uiLayout',\n    'uiElement',\n    'Magento_Ui/js/lib/validation/validator'\n], function (_, utils, layout, Element, validator) {\n    'use strict';\n\n    return Element.extend({\n        defaults: {\n            visible: true,\n            preview: '',\n            focused: false,\n            required: false,\n            disabled: false,\n            valueChangedByUser: false,\n            elementTmpl: 'ui/form/element/input',\n            tooltipTpl: 'ui/form/element/helper/tooltip',\n            fallbackResetTpl: 'ui/form/element/helper/fallback-reset',\n            'input_type': 'input',\n            placeholder: false,\n            description: '',\n            labelVisible: true,\n            label: '',\n            error: '',\n            warn: '',\n            notice: '',\n            customScope: '',\n            default: '',\n            isDifferedFromDefault: false,\n            showFallbackReset: false,\n            additionalClasses: {},\n            isUseDefault: '',\n            serviceDisabled: false,\n            valueUpdate: false, // ko binding valueUpdate\n\n            switcherConfig: {\n                component: 'Magento_Ui/js/form/switcher',\n                name: '${ $.name }_switcher',\n                target: '${ $.name }',\n                property: 'value'\n            },\n            listens: {\n                visible: 'setPreview',\n                value: 'setDifferedFromDefault',\n                '${ $.provider }:data.reset': 'reset',\n                '${ $.provider }:data.overload': 'overload',\n                '${ $.provider }:${ $.customScope ? $.customScope + \".\" : \"\"}data.validate': 'validate',\n                'isUseDefault': 'toggleUseDefault'\n            },\n            ignoreTmpls: {\n                value: true\n            },\n\n            links: {\n                value: '${ $.provider }:${ $.dataScope }'\n            }\n        },\n\n        /**\n         * Invokes initialize method of parent class,\n         * contains initialization logic\n         */\n        initialize: function () {\n            _.bindAll(this, 'reset');\n\n            this._super()\n                .setInitialValue()\n                ._setClasses()\n                .initSwitcher();\n\n            return this;\n        },\n\n        /**\n         * Checks if component has error.\n         *\n         * @returns {Object}\n         */\n        checkInvalid: function () {\n            return this.error() && this.error().length ? this : null;\n        },\n\n        /**\n         * Initializes observable properties of instance\n         *\n         * @returns {Abstract} Chainable.\n         */\n        initObservable: function () {\n            var rules = this.validation = this.validation || {};\n\n            this._super();\n\n            this.observe('error disabled focused preview visible value warn notice isDifferedFromDefault')\n                .observe('isUseDefault serviceDisabled')\n                .observe({\n                    'required': !!rules['required-entry']\n                });\n\n            return this;\n        },\n\n        /**\n         * Initializes regular properties of instance.\n         *\n         * @returns {Abstract} Chainable.\n         */\n        initConfig: function () {\n            var uid = utils.uniqueid(),\n                name,\n                valueUpdate,\n                scope;\n\n            this._super();\n\n            scope = this.dataScope.split('.');\n            name = scope.length > 1 ? scope.slice(1) : scope;\n\n            valueUpdate = this.showFallbackReset ? 'afterkeydown' : this.valueUpdate;\n\n            _.extend(this, {\n                uid: uid,\n                noticeId: 'notice-' + uid,\n                errorId: 'error-' + uid,\n                tooltipId: 'tooltip-' + uid,\n                inputName: utils.serializeName(name.join('.')),\n                valueUpdate: valueUpdate\n            });\n\n            return this;\n        },\n\n        /**\n         * Initializes switcher element instance.\n         *\n         * @returns {Abstract} Chainable.\n         */\n        initSwitcher: function () {\n            if (this.switcherConfig.enabled) {\n                layout([this.switcherConfig]);\n            }\n\n            return this;\n        },\n\n        /**\n         * Sets initial value of the element and subscribes to it's changes.\n         *\n         * @returns {Abstract} Chainable.\n         */\n        setInitialValue: function () {\n            this.initialValue = this.getInitialValue();\n\n            if (this.value.peek() !== this.initialValue) {\n                this.value(this.initialValue);\n            }\n\n            this.on('value', this.onUpdate.bind(this));\n            this.isUseDefault(this.disabled());\n\n            return this;\n        },\n\n        /**\n         * Extends 'additionalClasses' object.\n         *\n         * @returns {Abstract} Chainable.\n         */\n        _setClasses: function () {\n            var additional = this.additionalClasses;\n\n            if (_.isString(additional)) {\n                this.additionalClasses = {};\n\n                if (additional.trim().length) {\n                    additional = additional.trim().split(' ');\n\n                    additional.forEach(function (name) {\n                        if (name.length) {\n                            this.additionalClasses[name] = true;\n                        }\n                    }, this);\n                }\n            }\n\n            _.extend(this.additionalClasses, {\n                _required: this.required,\n                _error: this.error,\n                _warn: this.warn,\n                _disabled: this.disabled\n            });\n\n            return this;\n        },\n\n        /**\n         * Gets initial value of element\n         *\n         * @returns {*} Elements' value.\n         */\n        getInitialValue: function () {\n            var values = [this.value(), this.default],\n                value;\n\n            values.some(function (v) {\n                if (v !== null && v !== undefined) {\n                    value = v;\n\n                    return true;\n                }\n\n                return false;\n            });\n\n            return this.normalizeData(value);\n        },\n\n        /**\n         * Sets 'value' as 'hidden' property's value, triggers 'toggle' event,\n         * sets instance's hidden identifier in params storage based on\n         * 'value'.\n         *\n         * @returns {Abstract} Chainable.\n         */\n        setVisible: function (isVisible) {\n            this.visible(isVisible);\n\n            return this;\n        },\n\n        /**\n         * Show element.\n         *\n         * @returns {Abstract} Chainable.\n         */\n        show: function () {\n            this.visible(true);\n\n            return this;\n        },\n\n        /**\n         * Hide element.\n         *\n         * @returns {Abstract} Chainable.\n         */\n        hide: function () {\n            this.visible(false);\n\n            return this;\n        },\n\n        /**\n         * Disable element.\n         *\n         * @returns {Abstract} Chainable.\n         */\n        disable: function () {\n            this.disabled(true);\n\n            return this;\n        },\n\n        /**\n         * Enable element.\n         *\n         * @returns {Abstract} Chainable.\n         */\n        enable: function () {\n            this.disabled(false);\n\n            return this;\n        },\n\n        /**\n         *\n         * @param {(String|Object)} rule\n         * @param {(Object|Boolean)} [options]\n         * @returns {Abstract} Chainable.\n         */\n        setValidation: function (rule, options) {\n            var rules = utils.copy(this.validation),\n                changed;\n\n            if (_.isObject(rule)) {\n                _.extend(this.validation, rule);\n            } else {\n                this.validation[rule] = options;\n            }\n\n            changed = !utils.compare(rules, this.validation).equal;\n\n            if (changed) {\n                this.required(!!rules['required-entry']);\n                this.validate();\n            }\n\n            return this;\n        },\n\n        /**\n         * Returns unwrapped preview observable.\n         *\n         * @returns {String} Value of the preview observable.\n         */\n        getPreview: function () {\n            return this.value();\n        },\n\n        /**\n         * Checks if element has addons\n         *\n         * @returns {Boolean}\n         */\n        hasAddons: function () {\n            return this.addbefore || this.addafter;\n        },\n\n        /**\n         * Checks if element has service setting\n         *\n         * @returns {Boolean}\n         */\n        hasService: function () {\n            return this.service && this.service.template;\n        },\n\n        /**\n         * Defines if value has changed.\n         *\n         * @returns {Boolean}\n         */\n        hasChanged: function () {\n            var notEqual = this.value() !== this.initialValue;\n\n            return !this.visible() ? false : notEqual;\n        },\n\n        /**\n         * Checks if 'value' is not empty.\n         *\n         * @returns {Boolean}\n         */\n        hasData: function () {\n            return !utils.isEmpty(this.value());\n        },\n\n        /**\n         * Sets value observable to initialValue property.\n         *\n         * @returns {Abstract} Chainable.\n         */\n        reset: function () {\n            this.value(this.initialValue);\n            this.error(false);\n\n            return this;\n        },\n\n        /**\n         * Sets current state as initial.\n         */\n        overload: function () {\n            this.setInitialValue();\n            this.bubble('update', this.hasChanged());\n        },\n\n        /**\n         * Clears 'value' property.\n         *\n         * @returns {Abstract} Chainable.\n         */\n        clear: function () {\n            this.value('');\n\n            return this;\n        },\n\n        /**\n         * Converts values like 'null' or 'undefined' to an empty string.\n         *\n         * @param {*} value - Value to be processed.\n         * @returns {*}\n         */\n        normalizeData: function (value) {\n            return utils.isEmpty(value) ? '' : value;\n        },\n\n        /**\n         * Validates itself by it's validation rules using validator object.\n         * If validation of a rule did not pass, writes it's message to\n         * 'error' observable property.\n         *\n         * @returns {Object} Validate information.\n         */\n        validate: function () {\n            var value = this.value(),\n                result = validator(this.validation, value, this.validationParams),\n                message = !this.disabled() && this.visible() ? result.message : '',\n                isValid = this.disabled() || !this.visible() || result.passed;\n\n            this.error(message);\n            this.error.valueHasMutated();\n            this.bubble('error', message);\n\n            //TODO: Implement proper result propagation for form\n            if (this.source && !isValid) {\n                this.source.set('params.invalid', true);\n            }\n\n            return {\n                valid: isValid,\n                target: this\n            };\n        },\n\n        /**\n         * Callback that fires when 'value' property is updated.\n         */\n        onUpdate: function () {\n            this.bubble('update', this.hasChanged());\n\n            this.validate();\n        },\n\n        /**\n         * Restore value to default\n         */\n        restoreToDefault: function () {\n            this.value(this.default);\n            this.focused(true);\n        },\n\n        /**\n         * Update whether value differs from default value\n         */\n        setDifferedFromDefault: function () {\n            var value = typeof this.value() != 'undefined' && this.value() !== null ? this.value() : '',\n                defaultValue = typeof this.default != 'undefined' && this.default !== null ? this.default : '';\n\n            this.isDifferedFromDefault(value !== defaultValue);\n        },\n\n        /**\n         * @param {Boolean} state\n         */\n        toggleUseDefault: function (state) {\n            this.disabled(state);\n\n            if (this.source && this.hasService()) {\n                this.source.set('data.use_default.' + this.index, Number(state));\n            }\n        },\n\n        /**\n         *  Callback when value is changed by user\n         */\n        userChanges: function () {\n            this.valueChangedByUser = true;\n        },\n\n        /**\n         * Returns correct id for 'aria-describedby' accessibility attribute\n         *\n         * @returns {Boolean|String}\n         */\n        getDescriptionId: function () {\n            var id = false;\n\n            if (this.error()) {\n                id = this.errorId;\n            } else if (this.notice()) {\n                id = this.noticeId;\n            }\n\n            return id;\n        }\n    });\n});\n","Magento_Ui/js/form/element/media.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'mageUtils',\n    './abstract'\n], function (utils, Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n        defaults: {\n            links: {\n                value: ''\n            }\n        },\n\n        /**\n         * Initializes file component.\n         *\n         * @returns {Media} Chainable.\n         */\n        initialize: function () {\n            this._super()\n                .initFormId();\n\n            return this;\n        },\n\n        /**\n         * Defines form ID with which file input will be associated.\n         *\n         * @returns {Media} Chainable.\n         */\n        initFormId: function () {\n            var namespace;\n\n            if (this.formId) {\n                return this;\n            }\n\n            namespace   = this.name.split('.');\n            this.formId = namespace[0];\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/form/element/post-code.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    './abstract'\n], function (_, Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n        defaults: {\n            imports: {\n                countryOptions: '${ $.parentName }.country_id:indexedOptions',\n                update: '${ $.parentName }.country_id:value'\n            }\n        },\n\n        /**\n         * Initializes observable properties of instance\n         *\n         * @returns {Abstract} Chainable.\n         */\n        initObservable: function () {\n            this._super();\n\n            /**\n             * equalityComparer function\n             *\n             * @returns boolean.\n             */\n            this.value.equalityComparer = function (oldValue, newValue) {\n                return !oldValue && !newValue || oldValue === newValue;\n            };\n\n            return this;\n        },\n\n        /**\n         * Method called every time country selector's value gets changed.\n         * Updates all validations and requirements for certain country.\n         * @param {String} value - Selected country ID.\n         */\n        update: function (value) {\n            var isZipCodeOptional,\n                option;\n\n            if (!value) {\n                return;\n            }\n\n            option = _.isObject(this.countryOptions) && this.countryOptions[value];\n\n            if (!option) {\n                return;\n            }\n\n            isZipCodeOptional = !!option['is_zipcode_optional'];\n\n            if (isZipCodeOptional) {\n                this.error(false);\n            }\n\n            this.validation['required-entry'] = !isZipCodeOptional;\n            this.required(!isZipCodeOptional);\n        }\n    });\n});\n","Magento_Ui/js/form/element/region.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'uiRegistry',\n    './select',\n    'Magento_Checkout/js/model/default-post-code-resolver'\n], function (_, registry, Select, defaultPostCodeResolver) {\n    'use strict';\n\n    return Select.extend({\n        defaults: {\n            skipValidation: false,\n            imports: {\n                countryOptions: '${ $.parentName }.country_id:indexedOptions',\n                update: '${ $.parentName }.country_id:value'\n            }\n        },\n\n        /**\n         * {@inheritdoc}\n         */\n        initialize: function () {\n            var option;\n\n            this._super();\n\n            option = _.find(this.countryOptions, function (row) {\n                return row['is_default'] === true;\n            });\n            this.hideRegion(option);\n\n            return this;\n        },\n\n        /**\n         * Method called every time country selector's value gets changed.\n         * Updates all validations and requirements for certain country.\n         * @param {String} value - Selected country ID.\n         */\n        update: function (value) {\n            var isRegionRequired,\n                option;\n\n            if (!value) {\n                return;\n            }\n\n            option = _.isObject(this.countryOptions) && this.countryOptions[value];\n\n            if (!option) {\n                return;\n            }\n\n            this.hideRegion(option);\n\n            defaultPostCodeResolver.setUseDefaultPostCode(!option['is_zipcode_optional']);\n\n            isRegionRequired = !this.skipValidation && !!option['is_region_required'];\n\n            if (!isRegionRequired) {\n                this.error(false);\n            }\n\n            this.required(isRegionRequired);\n            this.validation['required-entry'] = isRegionRequired;\n\n            registry.get(this.customName, function (input) {\n                input.required(isRegionRequired);\n                input.validation['required-entry'] = isRegionRequired;\n                input.validation['validate-not-number-first'] = !this.options().length;\n            }.bind(this));\n        },\n\n        /**\n         * Hide select and corresponding text input field if region must not be shown for selected country.\n         *\n         * @private\n         * @param {Object}option\n         */\n        hideRegion: function (option) {\n            if (!option || option['is_region_visible'] !== false) {\n                return;\n            }\n\n            this.setVisible(false);\n\n            if (this.customEntry) {\n                this.toggleInput(false);\n            }\n        }\n    });\n});\n","Magento_Ui/js/form/element/image-uploader.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global Base64 */\ndefine([\n    'jquery',\n    'underscore',\n    'mageUtils',\n    'Magento_Ui/js/modal/alert',\n    'Magento_Ui/js/lib/validation/validator',\n    'Magento_Ui/js/form/element/file-uploader',\n    'mage/adminhtml/browser'\n], function ($, _, utils, uiAlert, validator, Element, browser) {\n    'use strict';\n\n    return Element.extend({\n        /**\n         * {@inheritDoc}\n         */\n        initialize: function () {\n            this._super();\n\n            // Listen for file deletions from the media browser\n            $(window).on('fileDeleted.mediabrowser', this.onDeleteFile.bind(this));\n        },\n\n        /**\n         * Assign uid for media gallery\n         *\n         * @return {ImageUploader} Chainable.\n         */\n        initConfig: function () {\n            var mediaGalleryUid = utils.uniqueid();\n\n            this._super();\n\n            _.extend(this, {\n                mediaGalleryUid: mediaGalleryUid\n            });\n\n            return this;\n        },\n\n        /**\n         * Add file event callback triggered from media gallery\n         *\n         * @param {ImageUploader} imageUploader - UI Class\n         * @param {Event} e\n         */\n        addFileFromMediaGallery: function (imageUploader, e) {\n            var $buttonEl = $(e.target),\n                fileSize = $buttonEl.data('size'),\n                fileMimeType = $buttonEl.data('mime-type'),\n                filePathname = $buttonEl.val(),\n                fileBasename = filePathname.split('/').pop();\n\n            this.addFile({\n                type: fileMimeType,\n                name: fileBasename,\n                size: fileSize,\n                url: filePathname\n            });\n        },\n\n        /**\n         * Open the media browser dialog\n         *\n         * @param {ImageUploader} imageUploader - UI Class\n         * @param {Event} e\n         */\n        openMediaBrowserDialog: function (imageUploader, e) {\n            var $buttonEl = $(e.target),\n                openDialogUrl = this.mediaGallery.openDialogUrl +\n                'target_element_id/' + $buttonEl.attr('id') +\n                '/store/' + this.mediaGallery.storeId +\n                '/type/image/?isAjax=true';\n\n            if (this.mediaGallery.initialOpenSubpath) {\n                openDialogUrl += '&current_tree_path=' + Base64.idEncode(this.mediaGallery.initialOpenSubpath);\n            }\n\n            browser.openDialog(\n                openDialogUrl,\n                null,\n                null,\n                this.mediaGallery.openDialogTitle,\n                {\n                    targetElementId: $buttonEl.attr('id')\n                }\n            );\n        },\n\n        /**\n         * @param {jQuery.event} e\n         * @param {Object} data\n         * @returns {Object} Chainables\n         */\n        onDeleteFile: function (e, data) {\n            var fileId = this.getFileId(),\n                deletedFileIds = data.ids;\n\n            if (fileId && $.inArray(fileId, deletedFileIds) > -1) {\n                this.clear();\n            }\n\n            return this;\n        },\n\n        /**\n         * {@inheritDoc}\n         */\n        clear: function () {\n            this.value([]);\n\n            return this;\n        },\n\n        /**\n         * Gets the ID of the file used if set\n         *\n         * @return {String|Null} ID\n         */\n        getFileId: function () {\n            return this.hasData() ? this.value()[0].id : null;\n        },\n\n        /**\n         * Trigger native browser file upload UI via clicking on 'Upload' button\n         *\n         * @param {ImageUploader} imageUploader - UI Class\n         * @param {Event} e\n         */\n        triggerImageUpload: function (imageUploader, e) {\n            $(e.target).closest('.file-uploader').find('input[type=\"file\"]').trigger('click');\n        },\n\n        /**\n         * Get list of file extensions allowed in comma delimited format\n         *\n         * @return {String}\n         */\n        getAllowedFileExtensionsInCommaDelimitedFormat: function () {\n            var allowedExtensions = this.allowedExtensions.toUpperCase().split(' ');\n\n            // if jpg and jpeg in allowed extensions, remove jpeg from list\n            if (allowedExtensions.indexOf('JPG') !== -1 && allowedExtensions.indexOf('JPEG') !== -1) {\n                allowedExtensions.splice(allowedExtensions.indexOf('JPEG'), 1);\n            }\n\n            return allowedExtensions.join(', ');\n        }\n    });\n});\n","Magento_Ui/js/form/element/wysiwyg.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'wysiwygAdapter',\n    'Magento_Ui/js/lib/view/utils/async',\n    'underscore',\n    'ko',\n    './abstract',\n    'mage/adminhtml/events',\n    'Magento_Variable/variables'\n], function (wysiwyg, $, _, ko, Abstract, varienGlobalEvents) {\n    'use strict';\n\n    return Abstract.extend({\n        currentWysiwyg: undefined,\n        defaults: {\n            elementSelector: 'textarea',\n            suffixRegExpPattern: '${ $.wysiwygUniqueSuffix }',\n            $wysiwygEditorButton: '',\n            links: {\n                value: '${ $.provider }:${ $.dataScope }'\n            },\n            template: 'ui/form/field',\n            elementTmpl: 'ui/form/element/wysiwyg',\n            content:        '',\n            showSpinner:    false,\n            loading:        false,\n            listens: {\n                disabled: 'setDisabled'\n            }\n        },\n\n        /**\n         *\n         * @returns {} Chainable.\n         */\n        initialize: function () {\n            this._super()\n                .initNodeListener();\n\n            $.async({\n                component: this,\n                selector: 'button'\n            }, function (element) {\n                this.$wysiwygEditorButton = this.$wysiwygEditorButton ?\n                    this.$wysiwygEditorButton.add($(element)) : $(element);\n            }.bind(this));\n\n            // disable editor completely after initialization is field is disabled\n            varienGlobalEvents.attachEventHandler('wysiwygEditorInitialized', function () {\n                if (!_.isUndefined(window.tinyMceEditors)) {\n                    this.currentWysiwyg = window.tinyMceEditors[this.wysiwygId];\n                }\n\n                if (this.disabled()) {\n                    this.setDisabled(true);\n                }\n            }.bind(this));\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        initConfig: function (config) {\n            var pattern = config.suffixRegExpPattern || this.constructor.defaults.suffixRegExpPattern;\n\n            pattern = pattern.replace(/\\$/g, '\\\\$&');\n            config.content = config.content.replace(new RegExp(pattern, 'g'), this.getUniqueSuffix(config));\n            this._super();\n\n            return this;\n        },\n\n        /**\n         * Build unique id based on name, underscore separated.\n         *\n         * @param {Object} config\n         */\n        getUniqueSuffix: function (config) {\n            return config.name.replace(/(\\.|-)/g, '_');\n        },\n\n        /**\n         * @inheritdoc\n         */\n        destroy: function () {\n            this._super();\n            wysiwyg.removeEvents(this.wysiwygId);\n        },\n\n        /**\n         *\n         * @returns {exports}\n         */\n        initObservable: function () {\n            this._super()\n                .observe(['value', 'content']);\n\n            return this;\n        },\n\n        /**\n         *\n         * @returns {} Chainable.\n         */\n        initNodeListener: function () {\n            $.async({\n                component: this,\n                selector: this.elementSelector\n            }, this.setElementNode.bind(this));\n\n            return this;\n        },\n\n        /**\n         *\n         * @param {HTMLElement} node\n         */\n        setElementNode: function (node) {\n            $(node).bindings({\n                value: this.value\n            });\n        },\n\n        /**\n         * Set disabled property to wysiwyg component\n         *\n         * @param {Boolean} disabled\n         */\n        setDisabled: function (disabled) {\n            if (this.$wysiwygEditorButton && disabled) {\n                this.$wysiwygEditorButton.prop('disabled', 'disabled');\n            } else if (this.$wysiwygEditorButton) {\n                this.$wysiwygEditorButton.prop('disabled', false);\n            }\n\n            /* eslint-disable no-undef */\n            if (!_.isUndefined(this.currentWysiwyg) && this.currentWysiwyg.activeEditor()) {\n                this.currentWysiwyg.setEnabledStatus(!disabled);\n                this.currentWysiwyg.getPluginButtons().prop('disabled', disabled);\n            }\n        },\n\n        /**\n         * Content getter\n         *\n         * @returns {String}\n         */\n        getContentUnsanitizedHtml: function () {\n            return this.content();\n        }\n    });\n});\n","Magento_Ui/js/form/element/select.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'mageUtils',\n    'uiRegistry',\n    './abstract',\n    'uiLayout'\n], function (_, utils, registry, Abstract, layout) {\n    'use strict';\n\n    var inputNode = {\n        parent: '${ $.$data.parentName }',\n        component: 'Magento_Ui/js/form/element/abstract',\n        template: '${ $.$data.template }',\n        provider: '${ $.$data.provider }',\n        name: '${ $.$data.index }_input',\n        dataScope: '${ $.$data.customEntry }',\n        customScope: '${ $.$data.customScope }',\n        sortOrder: {\n            after: '${ $.$data.name }'\n        },\n        displayArea: 'body',\n        label: '${ $.$data.label }'\n    };\n\n    /**\n     * Parses incoming options, considers options with undefined value property\n     *     as caption\n     *\n     * @param  {Array} nodes\n     * @return {Object}\n     */\n    function parseOptions(nodes, captionValue) {\n        var caption,\n            value;\n\n        nodes = _.map(nodes, function (node) {\n            value = node.value;\n\n            if (value === null || value === captionValue) {\n                if (_.isUndefined(caption)) {\n                    caption = node.label;\n                }\n            } else {\n                return node;\n            }\n        });\n\n        return {\n            options: _.compact(nodes),\n            caption: _.isString(caption) ? caption : false\n        };\n    }\n\n    /**\n     * Recursively loops over data to find non-undefined, non-array value\n     *\n     * @param  {Array} data\n     * @return {*} - first non-undefined value in array\n     */\n    function findFirst(data) {\n        var value;\n\n        data.some(function (node) {\n            value = node.value;\n\n            if (Array.isArray(value)) {\n                value = findFirst(value);\n            }\n\n            return !_.isUndefined(value);\n        });\n\n        return value;\n    }\n\n    /**\n     * Recursively set to object item like value and item.value like key.\n     *\n     * @param {Array} data\n     * @param {Object} result\n     * @returns {Object}\n     */\n    function indexOptions(data, result) {\n        var value;\n\n        result = result || {};\n\n        data.forEach(function (item) {\n            value = item.value;\n\n            if (Array.isArray(value)) {\n                indexOptions(value, result);\n            } else {\n                result[value] = item;\n            }\n        });\n\n        return result;\n    }\n\n    return Abstract.extend({\n        defaults: {\n            customName: '${ $.parentName }.${ $.index }_input',\n            elementTmpl: 'ui/form/element/select',\n            caption: '',\n            options: []\n        },\n\n        /**\n         * Extends instance with defaults, extends config with formatted values\n         *     and options, and invokes initialize method of AbstractElement class.\n         *     If instance's 'customEntry' property is set to true, calls 'initInput'\n         */\n        initialize: function () {\n            this._super();\n\n            if (this.customEntry) {\n                registry.get(this.name, this.initInput.bind(this));\n            }\n\n            if (this.filterBy) {\n                this.initFilter();\n            }\n\n            return this;\n        },\n\n        /**\n         * Calls 'initObservable' of parent, initializes 'options' and 'initialOptions'\n         *     properties, calls 'setOptions' passing options to it\n         *\n         * @returns {Object} Chainable.\n         */\n        initObservable: function () {\n            this._super();\n\n            this.initialOptions = this.options;\n\n            this.observe('options caption')\n                .setOptions(this.options());\n\n            return this;\n        },\n\n        /**\n         * Set link for filter.\n         *\n         * @returns {Object} Chainable\n         */\n        initFilter: function () {\n            var filter = this.filterBy;\n\n            this.filter(this.default, filter.field);\n            this.setLinks({\n                filter: filter.target\n            }, 'imports');\n\n            return this;\n        },\n\n        /**\n         * Creates input from template, renders it via renderer.\n         *\n         * @returns {Object} Chainable.\n         */\n        initInput: function () {\n            layout([utils.template(inputNode, this)]);\n\n            return this;\n        },\n\n        /**\n         * Matches specified value with existing options\n         * or, if value is not specified, returns value of the first option.\n         *\n         * @returns {*}\n         */\n        normalizeData: function () {\n            var value = this._super(),\n                option;\n\n            if (value !== '') {\n                option = this.getOption(value);\n\n                return option && option.value;\n            }\n\n            if (!this.caption()) {\n                return findFirst(this.options);\n            }\n        },\n\n        /**\n         * Filters 'initialOptions' property by 'field' and 'value' passed,\n         * calls 'setOptions' passing the result to it\n         *\n         * @param {*} value\n         * @param {String} field\n         */\n        filter: function (value, field) {\n            var source = this.initialOptions,\n                result;\n\n            field = field || this.filterBy.field;\n\n            result = _.filter(source, function (item) {\n                return item[field] === value || item.value === '';\n            });\n\n            this.setOptions(result);\n        },\n\n        /**\n         * Change visibility for input.\n         *\n         * @param {Boolean} isVisible\n         */\n        toggleInput: function (isVisible) {\n            registry.get(this.customName, function (input) {\n                input.setVisible(isVisible);\n            });\n        },\n\n        /**\n         * Sets 'data' to 'options' observable array, if instance has\n         * 'customEntry' property set to true, calls 'setHidden' method\n         *  passing !options.length as a parameter\n         *\n         * @param {Array} data\n         * @returns {Object} Chainable\n         */\n        setOptions: function (data) {\n            var captionValue = this.captionValue || '',\n                result = parseOptions(data, captionValue),\n                isVisible;\n\n            this.indexedOptions = indexOptions(result.options);\n\n            this.options(result.options);\n\n            if (!this.caption()) {\n                this.caption(result.caption);\n            }\n\n            if (this.customEntry) {\n                isVisible = !!result.options.length;\n\n                this.setVisible(isVisible);\n                this.toggleInput(!isVisible);\n            }\n\n            return this;\n        },\n\n        /**\n         * Processes preview for option by it's value, and sets the result\n         * to 'preview' observable\n         *\n         * @returns {Object} Chainable.\n         */\n        getPreview: function () {\n            var value = this.value(),\n                option = this.indexedOptions[value],\n                preview = option ? option.label : '';\n\n            this.preview(preview);\n\n            return preview;\n        },\n\n        /**\n         * Get option from indexedOptions list.\n         *\n         * @param {Number} value\n         * @returns {Object} Chainable\n         */\n        getOption: function (value) {\n            return this.indexedOptions[value];\n        },\n\n        /**\n         * Select first available option\n         *\n         * @returns {Object} Chainable.\n         */\n        clear: function () {\n            var value = this.caption() ? '' : findFirst(this.options);\n\n            this.value(value);\n\n            return this;\n        },\n\n        /**\n         * Initializes observable properties of instance\n         *\n         * @returns {Object} Chainable.\n         */\n        setInitialValue: function () {\n            if (_.isUndefined(this.value()) && !this.default) {\n                this.clear();\n            }\n\n            return this._super();\n        }\n    });\n});\n","Magento_Ui/js/form/element/country.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'uiRegistry',\n    './select'\n], function (_, registry, Select) {\n    'use strict';\n\n    return Select.extend({\n        defaults: {\n            imports: {\n                update: '${ $.parentName }.website_id:value'\n            }\n        },\n\n        /**\n         * Filters 'initialOptions' property by 'field' and 'value' passed,\n         * calls 'setOptions' passing the result to it\n         *\n         * @param {*} value\n         * @param {String} field\n         */\n        filter: function (value, field) {\n            var result, defaultCountry, defaultValue;\n\n            if (!field) { //validate field, if we are on update\n                field = this.filterBy.field;\n            }\n\n            this._super(value, field);\n            result = _.filter(this.initialOptions, function (item) {\n\n                if (item[field]) {\n                    return ~item[field].indexOf(value);\n                }\n\n                return false;\n            });\n\n            this.setOptions(result);\n            this.reset();\n\n            if (!this.value()) {\n                defaultCountry = _.filter(result, function (item) {\n                    return item['is_default'] && _.contains(item['is_default'], value);\n                });\n\n                if (defaultCountry.length) {\n                    defaultValue = defaultCountry.shift();\n                    this.value(defaultValue.value);\n                }\n            }\n        }\n    });\n});\n\n","Magento_Ui/js/form/element/multiselect.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'mageUtils',\n    './select'\n], function (_, utils, Select) {\n    'use strict';\n\n    return Select.extend({\n        defaults: {\n            size: 5,\n            elementTmpl: 'ui/form/element/multiselect',\n            listens: {\n                value: 'setDifferedFromDefault setPrepareToSendData'\n            }\n        },\n\n        /**\n         * @inheritdoc\n         */\n        setInitialValue: function () {\n            this._super();\n\n            this.initialValue = utils.copy(this.initialValue);\n\n            return this;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        normalizeData: function (value) {\n            if (utils.isEmpty(value)) {\n                value = [];\n            }\n\n            return _.isString(value) ? value.split(',') : value;\n        },\n\n        /**\n         * Sets the prepared data to dataSource\n         * by path, where key is component link to dataSource with\n         * suffix \"-prepared-for-send\"\n         *\n         * @param {Array} data - current component value\n         */\n        setPrepareToSendData: function (data) {\n            if (_.isUndefined(data) || !data.length) {\n                data = '';\n            }\n\n            this.source.set(this.dataScope + '-prepared-for-send', data);\n        },\n\n        /**\n         * @inheritdoc\n         */\n        getInitialValue: function () {\n            var values = [\n                    this.normalizeData(this.source.get(this.dataScope)),\n                    this.normalizeData(this.default)\n                ],\n                value;\n\n            values.some(function (v) {\n                return _.isArray(v) && (value = utils.copy(v)) && !_.isEmpty(v);\n            });\n\n            return value;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        hasChanged: function () {\n            var value = this.value(),\n                initial = this.initialValue;\n\n            return !utils.equalArrays(value, initial);\n        },\n\n        /**\n         * @inheritdoc\n         */\n        reset: function () {\n            this.value(utils.copy(this.initialValue));\n            this.error(false);\n\n            return this;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        clear: function () {\n            this.value([]);\n            this.error(false);\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/form/element/website.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'uiRegistry',\n    './select'\n], function (_, registry, Select) {\n    'use strict';\n\n    return Select.extend({\n        defaults: {\n            customerId: null,\n            isGlobalScope: 0\n        },\n\n        /**\n         * Website component constructor.\n         * @returns {exports}\n         */\n        initialize: function () {\n            this._super();\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/form/element/single-checkbox-toggle-notice.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'Magento_Ui/js/form/element/single-checkbox'\n], function (SingleCheckbox) {\n    'use strict';\n\n    return SingleCheckbox.extend({\n        defaults: {\n            notices: [],\n            tracks: {\n                notice: true\n            }\n        },\n\n        /**\n         * Choose notice on initialization\n         *\n         * @returns {*|void|Element}\n         */\n        initialize: function () {\n            this._super()\n                .chooseNotice();\n\n            return this;\n        },\n\n        /**\n         * Choose notice function\n         *\n         * @returns void\n         */\n        chooseNotice: function () {\n            var checkedNoticeNumber = Number(this.checked());\n\n            this.notice = this.notices[checkedNoticeNumber];\n        },\n\n        /**\n         * Choose notice on update\n         *\n         * @returns void\n         */\n        onUpdate: function () {\n            this._super();\n            this.chooseNotice();\n        }\n    });\n});\n","Magento_Ui/js/form/element/date.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'moment',\n    'mageUtils',\n    './abstract',\n    'moment-timezone-with-data'\n], function (moment, utils, Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n        defaults: {\n            options: {},\n\n            storeTimeZone: 'UTC',\n\n            validationParams: {\n                dateFormat: '${ $.outputDateFormat }'\n            },\n\n            /**\n             * Format of date that comes from the\n             * server (ICU Date Format).\n             *\n             * Used only in date picker mode\n             * (this.options.showsTime == false).\n             *\n             * @type {String}\n             */\n            inputDateFormat: 'y-MM-dd',\n\n            /**\n             * Format of date that should be sent to the\n             * server (ICU Date Format).\n             *\n             * Used only in date picker mode\n             * (this.options.showsTime == false).\n             *\n             * @type {String}\n             */\n            outputDateFormat: 'MM/dd/y',\n\n            /**\n             * Date/time format that is used to display date in\n             * the input field.\n             *\n             * @type {String}\n             */\n            pickerDateTimeFormat: '',\n\n            pickerDefaultDateFormat: 'MM/dd/y', // ICU Date Format\n            pickerDefaultTimeFormat: 'h:mm a', // ICU Time Format\n\n            elementTmpl: 'ui/form/element/date',\n\n            /**\n             * Format needed by moment timezone for conversion\n             */\n            timezoneFormat: 'YYYY-MM-DD HH:mm',\n\n            listens: {\n                'value': 'onValueChange',\n                'shiftedValue': 'onShiftedValueChange'\n            },\n\n            /**\n             * Date/time value shifted to corresponding timezone\n             * according to this.storeTimeZone property. This value\n             * will be sent to the server.\n             *\n             * @type {String}\n             */\n            shiftedValue: ''\n        },\n\n        /**\n         * Initializes regular properties of instance.\n         *\n         * @returns {Object} Chainable.\n         */\n        initConfig: function () {\n            this._super();\n\n            if (!this.options.dateFormat) {\n                this.options.dateFormat = this.pickerDefaultDateFormat;\n            }\n\n            if (!this.options.timeFormat) {\n                this.options.timeFormat = this.pickerDefaultTimeFormat;\n            }\n\n            this.prepareDateTimeFormats();\n\n            return this;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initObservable: function () {\n            return this._super().observe(['shiftedValue']);\n        },\n\n        /**\n         * @inheritdoc\n         */\n        getPreview: function () {\n            return this.shiftedValue();\n        },\n\n        /**\n         * Prepares and sets date/time value that will be displayed\n         * in the input field.\n         *\n         * @param {String} value\n         */\n        onValueChange: function (value) {\n            var shiftedValue;\n\n            if (value) {\n                if (this.options.showsTime && !this.options.timeOnly) {\n                    shiftedValue = moment.tz(value, 'UTC').tz(this.storeTimeZone);\n                } else {\n                    shiftedValue = moment(value, this.outputDateFormat, true);\n                }\n\n                if (!shiftedValue.isValid()) {\n                    shiftedValue = moment(value, this.inputDateFormat);\n                }\n                shiftedValue = shiftedValue.format(this.pickerDateTimeFormat);\n            } else {\n                shiftedValue = '';\n            }\n\n            if (shiftedValue !== this.shiftedValue()) {\n                this.shiftedValue(shiftedValue);\n            }\n        },\n\n        /**\n         * Prepares and sets date/time value that will be sent\n         * to the server.\n         *\n         * @param {String} shiftedValue\n         */\n        onShiftedValueChange: function (shiftedValue) {\n            var value,\n                formattedValue,\n                momentValue;\n\n            if (shiftedValue) {\n                momentValue = moment(shiftedValue, this.pickerDateTimeFormat);\n\n                if (this.options.showsTime && !this.options.timeOnly) {\n                    formattedValue = moment(momentValue).format(this.timezoneFormat);\n                    value = moment.tz(formattedValue, this.storeTimeZone).tz('UTC').toISOString();\n                } else {\n                    value = momentValue.format(this.outputDateFormat);\n                }\n            } else {\n                value = '';\n            }\n\n            if (value !== this.value()) {\n                this.value(value);\n            }\n        },\n\n        /**\n         * Prepares and converts all date/time formats to be compatible\n         * with moment.js library.\n         */\n        prepareDateTimeFormats: function () {\n            if (this.options.timeOnly) {\n                this.pickerDateTimeFormat = this.options.timeFormat;\n            } else {\n                this.pickerDateTimeFormat = this.options.dateFormat;\n\n                if (this.options.showsTime) {\n                    this.pickerDateTimeFormat += ' ' + this.options.timeFormat;\n                }\n            }\n\n            this.pickerDateTimeFormat = utils.convertToMomentFormat(this.pickerDateTimeFormat);\n\n            if (this.options.dateFormat) {\n                this.outputDateFormat = this.options.dateFormat;\n            }\n\n            this.inputDateFormat = this.options.timeOnly ?\n                utils.convertToMomentFormat(this.pickerDefaultTimeFormat) :\n                utils.convertToMomentFormat(this.inputDateFormat);\n            this.outputDateFormat = this.options.timeOnly ?\n                utils.convertToMomentFormat(this.options.timeFormat) :\n                utils.convertToMomentFormat(this.outputDateFormat);\n\n            this.validationParams.dateFormat = this.outputDateFormat;\n        }\n    });\n});\n","Magento_Ui/js/form/element/color-picker-palette.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * @api\n */\ndefine([], function () {\n    'use strict';\n\n    return [\n        [\n            'rgb(0,0,0)', 'rgb(52,52,52)', 'rgb(83,83,83)', 'rgb(135,135,135)', 'rgb(193,193,193)',\n            'rgb(234,234,234)', 'rgb(240,240,240)', 'rgb(255,255,255)'\n        ],\n        [\n            'rgb(252,0,9)', 'rgb(253,135,10)', 'rgb(255,255,13)', 'rgb(35,255,9)', 'rgb(33,255,255)',\n            'rgb(0,0,254)', 'rgb(132,0,254)', 'rgb(251,0,255)'\n        ],\n        [\n            'rgb(240,192,194)', 'rgb(251,223,194)', 'rgb(255,241,193)', 'rgb(210,230,201)',\n            'rgb(199,217,220)', 'rgb(197,219,240)', 'rgb(208,200,227)', 'rgb(229,199,212)'\n        ],\n        [\n            'rgb(228,133,135)', 'rgb(246,193,139)', 'rgb(254,225,136)', 'rgb(168,208,152)',\n            'rgb(146,184,190)', 'rgb(143,184,227)', 'rgb(165,148,204)', 'rgb(202,147,175)'\n        ],\n        [\n            'rgb(214,78,83)', 'rgb(243,163,88)', 'rgb(254,211,83)', 'rgb(130,187,106)',\n            'rgb(99,149,159)', 'rgb(93,150,211)', 'rgb(123,100,182)', 'rgb(180,100,142)'\n        ],\n        [\n            'rgb(190,0,5)', 'rgb(222,126,44)', 'rgb(236,183,39)', 'rgb(89,155,61)', 'rgb(55,110,123)',\n            'rgb(49,112,185)', 'rgb(83,55,150)', 'rgb(147,55,101)'\n        ],\n        [\n            'rgb(133,0,3)', 'rgb(163,74,10)', 'rgb(177,127,7)', 'rgb(45,101,23)', 'rgb(18,62,74)',\n            'rgb(14,62,129)', 'rgb(40,15,97)', 'rgb(95,16,55)'\n        ],\n        [\n            'rgb(81,0,1)', 'rgb(100,48,7)', 'rgb(107,78,3)', 'rgb(31,63,16)',\n            'rgb(13,39,46)', 'rgb(10,40,79)', 'rgb(24,12,59)', 'rgb(59,10,36)'\n        ]\n    ];\n});\n","Magento_Ui/js/form/element/checkbox-set.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'mageUtils',\n    './abstract'\n], function (_, utils, Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n        defaults: {\n            template: 'ui/form/element/checkbox-set',\n            multiple: false,\n            multipleScopeValue: null\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initConfig: function () {\n            this._super();\n\n            this.value = this.normalizeData(this.value);\n\n            return this;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initLinks: function () {\n            var scope = this.source.get(this.dataScope);\n\n            this.multipleScopeValue = this.multiple && _.isArray(scope) ? utils.copy(scope) : undefined;\n\n            return this._super();\n        },\n\n        /**\n         * @inheritdoc\n         */\n        reset: function () {\n            this.value(utils.copy(this.initialValue));\n            this.error(false);\n\n            return this;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        clear: function () {\n            var value = this.multiple ? [] : '';\n\n            this.value(value);\n            this.error(false);\n\n            return this;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        normalizeData: function (value) {\n            if (!this.multiple) {\n                return this._super();\n            }\n\n            return _.isArray(value) ? utils.copy(value) : [];\n        },\n\n        /**\n         * @inheritdoc\n         */\n        setInitialValue: function () {\n            this._super();\n\n            this.initialValue = utils.copy(this.initialValue);\n\n            return this;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        getInitialValue: function () {\n            var values = [this.multipleScopeValue, this.default, this.value.peek(), []],\n                value;\n\n            if (!this.multiple) {\n                return this._super();\n            }\n\n            values.some(function (v) {\n                return _.isArray(v) && (value = utils.copy(v));\n            });\n\n            return value;\n        },\n\n        /**\n         * Returns labels which matches current value.\n         *\n         * @returns {String|Array}\n         */\n        getPreview: function () {\n            var option;\n\n            if (!this.multiple) {\n                option = this.getOption(this.value());\n\n                return option ? option.label : '';\n            }\n\n            return this.value.map(function (value) {\n                return this.getOption(value).label;\n            }, this);\n        },\n\n        /**\n         * Returns option object associated with provided value.\n         *\n         * @param {String} value\n         * @returns {Object}\n         */\n        getOption: function (value) {\n            return _.findWhere(this.options, {\n                value: value\n            });\n        },\n\n        /**\n         * @inheritdoc\n         */\n        hasChanged: function () {\n            var value = this.value(),\n                initial = this.initialValue;\n\n            return this.multiple ?\n                !utils.equalArrays(value, initial) :\n                this._super();\n        }\n    });\n});\n","Magento_Ui/js/form/element/boolean.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    './abstract'\n], function (Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n        defaults: {\n            checked: false,\n            links: {\n                checked: 'value'\n            }\n        },\n\n        /**\n         * @returns {*|void|Element}\n         */\n        initObservable: function () {\n            return this._super()\n                    .observe('checked');\n        },\n\n        /**\n         * Converts provided value to boolean.\n         *\n         * @returns {Boolean}\n         */\n        normalizeData: function () {\n            return !!+this._super();\n        },\n\n        /**\n         * Calls 'onUpdate' method of parent, if value is defined and instance's\n         *     'unique' property set to true, calls 'setUnique' method\n         *\n         * @return {Object} - reference to instance\n         */\n        onUpdate: function () {\n            if (this.hasUnique) {\n                this.setUnique();\n            }\n\n            return this._super();\n        }\n    });\n});\n","Magento_Ui/js/form/element/single-checkbox-use-config.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'Magento_Ui/js/form/element/single-checkbox'\n], function (Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            isUseDefault: false,\n            isUseConfig: false,\n            listens: {\n                'isUseConfig': 'toggleElement',\n                'isUseDefault': 'toggleElement'\n            }\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initObservable: function () {\n\n            return this\n                ._super()\n                .observe('isUseConfig');\n        },\n\n        /**\n         * Toggle element\n         */\n        toggleElement: function () {\n            this.disabled(this.isUseDefault() || this.isUseConfig());\n\n            if (this.source) {\n                this.source.set('data.use_default.' + this.index, Number(this.isUseDefault()));\n            }\n        }\n    });\n});\n","Magento_Ui/js/form/adapter/buttons.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine(function () {\n    'use strict';\n\n    return {\n        'reset': '#reset',\n        'save': '#save',\n        'saveAndContinue': '#save_and_continue'\n    };\n});\n","Magento_Ui/js/form/components/insert-form.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    './insert',\n    'mageUtils',\n    'jquery'\n], function (Insert, utils, $) {\n    'use strict';\n\n    /**\n     * Get page actions element.\n     *\n     * @param {String} elem\n     * @param {String} actionsClass\n     * @returns {String}\n     */\n    function getPageActions(elem, actionsClass) {\n        var el = document.createElement('div');\n\n        el.innerHTML = elem;\n\n        return el.getElementsByClassName(actionsClass)[0];\n    }\n\n    /**\n     * Return element without page actions toolbar\n     *\n     * @param {String} elem\n     * @param {String} actionsClass\n     * @returns {String}\n     */\n    function removePageActions(elem, actionsClass) {\n        var el = document.createElement('div'),\n            actions;\n\n        el.innerHTML = elem;\n        actions = el.getElementsByClassName(actionsClass)[0];\n\n        if (actions) {\n            el.removeChild(actions);\n        }\n\n        return el.innerHTML;\n    }\n\n    return Insert.extend({\n        defaults: {\n            externalFormName: '${ $.ns }.${ $.ns }',\n            pageActionsClass: 'page-actions',\n            actionsContainerClass: 'page-main-actions',\n            exports: {\n                prefix: '${ $.externalFormName }:selectorPrefix'\n            },\n            imports: {\n                toolbarSection: '${ $.toolbarContainer }:toolbarSection',\n                prefix: '${ $.toolbarContainer }:rootSelector',\n                messagesClass: '${ $.externalFormName }:messagesClass'\n            },\n            settings: {\n                ajax: {\n                    ajaxSave: true,\n                    exports: {\n                        ajaxSave: '${ $.externalFormName }:ajaxSave'\n                    },\n                    imports: {\n                        responseStatus: '${ $.externalFormName }:responseStatus',\n                        responseData: '${ $.externalFormName }:responseData'\n                    }\n                }\n            },\n            modules: {\n                externalForm: '${ $.externalFormName }'\n            }\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            return this._super()\n                .observe('responseStatus');\n        },\n\n        /** @inheritdoc */\n        initConfig: function (config) {\n            var defaults = this.constructor.defaults;\n\n            utils.extend(defaults, defaults.settings[config.formSubmitType] || {});\n\n            return this._super();\n        },\n\n        /** @inheritdoc*/\n        destroyInserted: function () {\n            if (this.isRendered && this.externalForm()) {\n                this.externalForm().delegate('destroy');\n                this.removeActions();\n                this.responseStatus(undefined);\n                this.responseData = {};\n            }\n\n            return this._super();\n        },\n\n        /** @inheritdoc */\n        onRender: function (data) {\n            var actions = getPageActions(data, this.pageActionsClass);\n\n            if (!data.length) {\n                return this;\n            }\n            data = removePageActions(data, this.pageActionsClass);\n            this.renderActions(actions);\n            this._super(data);\n        },\n\n        /**\n         * Insert actions in toolbar.\n         *\n         * @param {String} actions\n         */\n        renderActions: function (actions) {\n            var $container = $('<div></div>');\n\n            $container\n                .addClass(this.actionsContainerClass)\n                .append(actions);\n\n            this.formHeader = $container;\n\n            $(this.toolbarSection).append(this.formHeader);\n        },\n\n        /**\n         * Remove actions toolbar.\n         */\n        removeActions: function () {\n            $(this.formHeader).siblings('.' + this.messagesClass).remove();\n            $(this.formHeader).remove();\n            this.formHeader = $();\n        },\n\n        /**\n         * Reset external form data.\n         */\n        resetForm: function () {\n            if (this.externalSource()) {\n                this.externalSource().trigger('data.reset');\n                this.responseStatus(undefined);\n            }\n        }\n    });\n});\n","Magento_Ui/js/form/components/group.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'uiCollection'\n], function (_, Collection) {\n    'use strict';\n\n    return Collection.extend({\n        defaults: {\n            visible: true,\n            label: '',\n            showLabel: true,\n            required: false,\n            template: 'ui/group/group',\n            fieldTemplate: 'ui/form/field',\n            breakLine: true,\n            validateWholeGroup: false,\n            additionalClasses: {}\n        },\n\n        /**\n         * Extends this with defaults and config.\n         * Then calls initObservable, iniListenes and extractData methods.\n         */\n        initialize: function () {\n            this._super()\n                ._setClasses();\n\n            return this;\n        },\n\n        /**\n         * Calls initObservable of parent class.\n         * Defines observable properties of instance.\n         *\n         * @return {Object} - reference to instance\n         */\n        initObservable: function () {\n            this._super()\n                .observe('visible')\n                .observe({\n                    required: !!+this.required\n                });\n\n            return this;\n        },\n\n        /**\n         * Extends 'additionalClasses' object.\n         *\n         * @returns {Group} Chainable.\n         */\n        _setClasses: function () {\n            var additional = this.additionalClasses,\n                classes;\n\n            if (_.isString(additional)) {\n                additional = this.additionalClasses.split(' ');\n                classes = this.additionalClasses = {};\n\n                additional.forEach(function (name) {\n                    classes[name] = true;\n                }, this);\n            }\n\n            _.extend(this.additionalClasses, {\n                'admin__control-grouped': !this.breakLine,\n                'admin__control-fields': this.breakLine,\n                required:   this.required,\n                _error:     this.error,\n                _disabled:  this.disabled\n            });\n\n            return this;\n        },\n\n        /**\n         * Defines if group has only one element.\n         * @return {Boolean}\n         */\n        isSingle: function () {\n            return this.elems.getLength() === 1;\n        },\n\n        /**\n         * Defines if group has multiple elements.\n         * @return {Boolean}\n         */\n        isMultiple: function () {\n            return this.elems.getLength() > 1;\n        },\n\n        /**\n         * Returns an array of child components previews.\n         *\n         * @returns {Array}\n         */\n        getPreview: function () {\n            return this.elems.map('getPreview');\n        }\n    });\n});\n","Magento_Ui/js/form/components/button.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'uiElement',\n    'uiRegistry',\n    'uiLayout',\n    'mageUtils',\n    'underscore'\n], function (Element, registry, layout, utils, _) {\n    'use strict';\n\n    return Element.extend({\n        defaults: {\n            buttonClasses: {},\n            additionalClasses: {},\n            displayArea: 'outsideGroup',\n            displayAsLink: false,\n            elementTmpl: 'ui/form/element/button',\n            template: 'ui/form/components/button/simple',\n            visible: true,\n            disabled: false,\n            title: '',\n            buttonTextId: '',\n            ariLabelledby: ''\n        },\n\n        /**\n         * Initializes component.\n         *\n         * @returns {Object} Chainable.\n         */\n        initialize: function () {\n            return this._super()\n                ._setClasses()\n                ._setButtonClasses();\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            return this._super()\n                .observe([\n                    'visible',\n                    'disabled',\n                    'title',\n                    'childError'\n                ]);\n        },\n\n        /**\n         * Performs configured actions\n         */\n        action: function () {\n            this.actions.forEach(this.applyAction, this);\n        },\n\n        /**\n         * Apply action on target component,\n         * but previously create this component from template if it is not existed\n         *\n         * @param {Object} action - action configuration\n         */\n        applyAction: function (action) {\n            var targetName = action.targetName,\n                params = utils.copy(action.params) || [],\n                actionName = action.actionName,\n                target;\n\n            if (!registry.has(targetName)) {\n                this.getFromTemplate(targetName);\n            }\n            target = registry.async(targetName);\n\n            if (target && typeof target === 'function' && actionName) {\n                params.unshift(actionName);\n                target.apply(target, params);\n            }\n        },\n\n        /**\n         * Create target component from template\n         *\n         * @param {Object} targetName - name of component,\n         * that supposed to be a template and need to be initialized\n         */\n        getFromTemplate: function (targetName) {\n            var parentName = targetName.split('.'),\n                index = parentName.pop(),\n                child;\n\n            parentName = parentName.join('.');\n            child = utils.template({\n                parent: parentName,\n                name: index,\n                nodeTemplate: targetName\n            });\n            layout([child]);\n        },\n\n        /**\n         * Extends 'additionalClasses' object.\n         *\n         * @returns {Object} Chainable.\n         */\n        _setClasses: function () {\n            if (typeof this.additionalClasses === 'string') {\n                if (this.additionalClasses === '') {\n                    this.additionalClasses = {};\n\n                    return this;\n                }\n\n                this.additionalClasses = this.additionalClasses\n                    .trim()\n                    .split(' ')\n                    .reduce(function (classes, name) {\n                        classes[name] = true;\n\n                        return classes;\n                    }, {}\n                );\n            }\n\n            return this;\n        },\n\n        /**\n         * Extends 'buttonClasses' object.\n         *\n         * @returns {Object} Chainable.\n         */\n        _setButtonClasses: function () {\n            var additional = this.buttonClasses;\n\n            if (_.isString(additional)) {\n                this.buttonClasses = {};\n\n                if (additional.trim().length) {\n                    additional = additional.trim().split(' ');\n\n                    additional.forEach(function (name) {\n                        if (name.length) {\n                            this.buttonClasses[name] = true;\n                        }\n                    }, this);\n                }\n            }\n\n            _.extend(this.buttonClasses, {\n                'action-basic': !this.displayAsLink,\n                'action-additional': this.displayAsLink\n            });\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/form/components/fieldset.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'Magento_Ui/js/lib/collapsible',\n    'underscore'\n], function (Collapsible, _) {\n    'use strict';\n\n    return Collapsible.extend({\n        defaults: {\n            template: 'ui/form/fieldset',\n            collapsible: false,\n            changed: false,\n            loading: false,\n            error: false,\n            opened: false,\n            level: 0,\n            visible: true,\n            initializeFieldsetDataByDefault: false, /* Data in some fieldsets should be initialized before open */\n            disabled: false,\n            listens: {\n                'opened': 'onVisibilityChange'\n            },\n            additionalClasses: {}\n        },\n\n        /**\n         * Extends instance with defaults. Invokes parent initialize method.\n         * Calls initListeners and pushParams methods.\n         */\n        initialize: function () {\n            _.bindAll(this, 'onChildrenUpdate', 'onChildrenError', 'onContentLoading');\n\n            return this._super()\n                ._setClasses();\n        },\n\n        /**\n         * Initializes components' configuration.\n         *\n         * @returns {Fieldset} Chainable.\n         */\n        initConfig: function () {\n            this._super();\n            this._wasOpened = this.opened || !this.collapsible;\n\n            return this;\n        },\n\n        /**\n         * Calls initObservable of parent class.\n         * Defines observable properties of instance.\n         *\n         * @returns {Object} Reference to instance\n         */\n        initObservable: function () {\n            this._super()\n                .observe('changed loading error visible');\n\n            return this;\n        },\n\n        /**\n         * Calls parent's initElement method.\n         * Assigns callbacks on various events of incoming element.\n         *\n         * @param  {Object} elem\n         * @return {Object} - reference to instance\n         */\n        initElement: function (elem) {\n            elem.initContainer(this);\n\n            elem.on({\n                'update': this.onChildrenUpdate,\n                'loading': this.onContentLoading,\n                'error': this.onChildrenError\n            });\n\n            if (this.disabled) {\n                try {\n                    elem.disabled(true);\n                }\n                catch (e) {\n\n                }\n            }\n\n            return this;\n        },\n\n        /**\n         * Is being invoked on children update.\n         * Sets changed property to one incoming.\n         *\n         * @param  {Boolean} hasChanged\n         */\n        onChildrenUpdate: function (hasChanged) {\n            if (!hasChanged) {\n                hasChanged = _.some(this.delegate('hasChanged'));\n            }\n\n            this.bubble('update', hasChanged);\n            this.changed(hasChanged);\n        },\n\n        /**\n         * Extends 'additionalClasses' object.\n         *\n         * @returns {Group} Chainable.\n         */\n        _setClasses: function () {\n            var additional = this.additionalClasses,\n                classes;\n\n            if (_.isString(additional)) {\n                additional = this.additionalClasses.split(' ');\n                classes = this.additionalClasses = {};\n\n                additional.forEach(function (name) {\n                    classes[name] = true;\n                }, this);\n            }\n\n            _.extend(this.additionalClasses, {\n                'admin__collapsible-block-wrapper': this.collapsible,\n                _show: this.opened,\n                _hide: !this.opened,\n                _disabled: this.disabled\n            });\n\n            return this;\n        },\n\n        /**\n         * Handler of the \"opened\" property changes.\n         *\n         * @param {Boolean} isOpened\n         */\n        onVisibilityChange: function (isOpened) {\n            if (!this._wasOpened) {\n                this._wasOpened = isOpened;\n            }\n        },\n\n        /**\n         * Is being invoked on children validation error.\n         * Sets error property to one incoming.\n         *\n         * @param {String} message - error message.\n         */\n        onChildrenError: function (message) {\n            var hasErrors = false;\n\n            if (!message) {\n                hasErrors = this._isChildrenHasErrors(hasErrors, this);\n            }\n\n            this.error(hasErrors || message);\n\n            if (hasErrors || message) {\n                this.open();\n            }\n        },\n\n        /**\n         * Returns errors of children if exist\n         *\n         * @param {Boolean} hasErrors\n         * @param {*} container\n         * @return {Boolean}\n         * @private\n         */\n        _isChildrenHasErrors: function (hasErrors, container) {\n            var self = this;\n\n            if (hasErrors === false && container.hasOwnProperty('elems')) {\n                hasErrors = container.elems.some('error');\n\n                if (hasErrors === false && container.hasOwnProperty('_elems')) {\n                    container._elems.forEach(function (child) {\n\n                        if (hasErrors === false) {\n                            hasErrors = self._isChildrenHasErrors(hasErrors, child);\n                        }\n                    });\n                }\n            }\n\n            return hasErrors;\n        },\n\n        /**\n         * Callback that sets loading property to true.\n         */\n        onContentLoading: function (isLoading) {\n            this.loading(isLoading);\n        }\n    });\n});\n","Magento_Ui/js/form/components/collection.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'mageUtils',\n    'uiRegistry',\n    'uiComponent',\n    'uiLayout',\n    'Magento_Ui/js/modal/confirm'\n], function (_, utils, registry, Component, layout, confirm) {\n    'use strict';\n\n    var childTemplate = {\n        parent: '${ $.$data.name }',\n        name: '${ $.$data.childIndex }',\n        dataScope: '${ $.name }',\n        nodeTemplate: '${ $.$data.name }.${ $.$data.itemTemplate }'\n    };\n\n    return Component.extend({\n        defaults: {\n            lastIndex: 0,\n            template: 'ui/form/components/collection'\n        },\n\n        /**\n         * Extends instance with default config, calls initialize of parent\n         * class, calls initChildren method.\n         */\n        initialize: function () {\n            this._super()\n                .initChildren();\n\n            return this;\n        },\n\n        /**\n         * Activates the incoming child and triggers the update event.\n         *\n         * @param {Object} elem - Incoming child.\n         */\n        initElement: function (elem) {\n            this._super();\n\n            elem.activate();\n\n            this.bubble('update');\n\n            return this;\n        },\n\n        /**\n         * Loops over corresponding data in data storage,\n         * creates child for each and pushes it's identifier to initialItems array.\n         *\n         * @returns {Collection} Chainable.\n         */\n        initChildren: function () {\n            var children = this.source.get(this.dataScope),\n                initial = this.initialItems = [];\n\n            _.each(children, function (item, index) {\n                initial.push(index);\n                this.addChild(index);\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Creates new item of collection, based on incoming 'index'.\n         * If not passed creates one with 'new_' prefix.\n         *\n         * @param {String|Object} [index] - Index of a child.\n         * @returns {Collection} Chainable.\n         */\n        addChild: function (index) {\n            this.childIndex = !_.isString(index) ?\n                'new_' + this.lastIndex++ :\n                index;\n\n            layout([utils.template(childTemplate, this)]);\n\n            return this;\n        },\n\n        /**\n         * Returns true if current set of items differ from initial one,\n         * or if some child has been changed.\n         *\n         * @returns {Boolean}\n         */\n        hasChanged: function () {\n            var initial = this.initialItems,\n                current = this.elems.pluck('index'),\n                changed = !utils.equalArrays(initial, current);\n\n            return changed || this.elems.some(function (elem) {\n                return _.some(elem.delegate('hasChanged'));\n            });\n        },\n\n        /**\n         * Initiates validation of its' children components.\n         *\n         * @returns {Array} An array of validation results.\n         */\n        validate: function () {\n            var elems;\n\n            this.allValid = true;\n\n            elems = this.elems.sortBy(function (elem) {\n                return !elem.active();\n            });\n\n            elems = elems.map(this._validate, this);\n\n            return _.flatten(elems);\n        },\n\n        /**\n         * Iterator function for components validation.\n         * Activates first invalid child component.\n         *\n         * @param {Object} elem - Element to run validation on.\n         * @returns {Array} An array of validation results.\n         */\n        _validate: function (elem) {\n            var result = elem.delegate('validate'),\n                invalid;\n\n            invalid = _.some(result, function (item) {\n                return !item.valid;\n            });\n\n            if (this.allValid && invalid) {\n                this.allValid = false;\n\n                elem.activate();\n            }\n\n            return result;\n        },\n\n        /**\n         * Creates function that removes element\n         * from collection using '_removeChild' method.\n         * @param  {Object} elem - Element that should be removed.\n         * @deprecated Not used anymore\n         */\n        removeAddress: function (elem) {\n            var self = this;\n\n            confirm({\n                content: this.removeMessage,\n                actions: {\n                    /** @inheritdoc */\n                    confirm: function () {\n                        self._removeAddress(elem);\n                    }\n                }\n            });\n        },\n\n        /**\n         * Removes element from both collection and data storage,\n         * activates first element if removed one was active,\n         * triggers 'update' event.\n         *\n         * @param {Object} elem - Element to remove.\n         */\n        _removeAddress: function (elem) {\n            var isActive = elem.active(),\n                first;\n\n            elem.destroy();\n\n            first = this.elems.first();\n\n            if (first && isActive) {\n                first.activate();\n            }\n\n            this.bubble('update');\n        }\n    });\n});\n","Magento_Ui/js/form/components/tab_group.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'Magento_Ui/js/lib/collapsible'\n], function (_, Collapsible) {\n    'use strict';\n\n    return Collapsible.extend({\n        defaults: {\n            listens: {\n                '${ $.provider }:data.validate': 'onValidate'\n            },\n            collapsible: false,\n            opened: true\n        },\n\n        /**\n         * Invokes initElement method of parent class, calls 'initActivation' method\n         * passing element to it.\n         * @param {Object} elem\n         * @returns {Object} - reference to instance\n         */\n        initElement: function (elem) {\n            this._super()\n                .initActivation(elem);\n\n            return this;\n        },\n\n        /**\n         * Activates element if one is first or if one has 'active' propert\n         * set to true.\n         *\n         * @param  {Object} elem\n         * @returns {Object} - reference to instance\n         */\n        initActivation: function (elem) {\n            var elems   = this.elems(),\n                isFirst = !elems.indexOf(elem);\n\n            if (isFirst || elem.active()) {\n                elem.activate();\n            }\n\n            return this;\n        },\n\n        /**\n         * Delegates 'validate' method on element, then reads 'invalid' property\n         * of params storage, and if defined, activates element, sets\n         * 'allValid' property of instance to false and sets invalid's\n         * 'focused' property to true.\n         *\n         * @param {Object} elem\n         */\n        validate: function (elem) {\n            var result  = elem.delegate('validate'),\n                invalid;\n\n            invalid = _.find(result, function (item) {\n                return typeof item !== 'undefined' && !item.valid;\n            });\n\n            if (invalid) {\n                elem.activate();\n                invalid.target.focused(true);\n            }\n\n            return invalid;\n        },\n\n        /**\n         * Sets 'allValid' property of instance to true, then calls 'validate' method\n         * of instance for each element.\n         */\n        onValidate: function () {\n            this.elems.sortBy(function (elem) {\n                return !elem.active();\n            }).some(this.validate, this);\n        }\n    });\n});\n","Magento_Ui/js/form/components/multiline.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    './group'\n], function (Group) {\n    'use strict';\n\n    return Group.extend({\n        defaults: {\n            links: {\n                value: '${ $.provider }:${ $.dataScope }'\n            }\n        },\n\n        /**\n         * Initialize Multiline component.\n         *\n         * @returns {Object}\n         */\n        initialize: function () {\n            return this._super()\n                ._prepareValue();\n        },\n\n        /**\n         * {@inheritdoc}\n         */\n        initObservable: function () {\n            this._super()\n                .observe('value');\n\n            return this;\n        },\n\n        /**\n         * Prepare value for Multiline options.\n         *\n         * @returns {Object} Chainable.\n         * @private\n         */\n        _prepareValue: function () {\n            var value = this.value();\n\n            if (typeof value === 'string') {\n                this.value(value.split('\\n'));\n            }\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/form/components/tab.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'uiCollection'\n], function (Collection) {\n    'use strict';\n\n    return Collection.extend({\n        defaults: {\n            uniqueProp:     'active',\n            active:         false,\n            wasActivated:   false\n        },\n\n        /**\n         * Extends instance with defaults. Invokes parent initialize method.\n         * Calls initListeners and pushParams methods.\n         */\n        initialize: function () {\n            this._super()\n                .setUnique();\n        },\n\n        /**\n         * Calls initObservable of parent class.\n         * Defines observable properties of instance.\n         * @return {Object} - reference to instance\n         */\n        initObservable: function () {\n            this._super()\n                .observe('active wasActivated');\n\n            return this;\n        },\n\n        /**\n         * Sets active property to true, then invokes pushParams method.\n         */\n        activate: function () {\n            this.active(true);\n            this.wasActivated(true);\n\n            this.setUnique();\n\n            return true;\n        }\n    });\n});\n","Magento_Ui/js/form/components/area.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    './tab'\n], function (_, Tab) {\n    'use strict';\n\n    return Tab.extend({\n        defaults: {\n            uniqueNs:   'params.activeArea',\n            template:   'ui/area',\n            changed:    false,\n            loading:    false\n        },\n\n        /**\n         * Extends instance with defaults. Invokes parent initialize method.\n         * Calls initListeners and pushParams methods.\n         */\n        initialize: function () {\n            _.bindAll(this, 'onChildrenUpdate', 'onContentLoading');\n\n            return this._super();\n        },\n\n        /**\n         * Calls initObservable of parent class.\n         * Defines observable properties of instance.\n         * @return {Object} - reference to instance\n         */\n        initObservable: function () {\n            this._super()\n                .observe('changed loading');\n\n            return this;\n        },\n\n        /**\n         * Calls parent's initElement method.\n         * Assigns callbacks on various events of incoming element.\n         * @param  {Object} elem\n         * @return {Object} - reference to instance\n         */\n        initElement: function (elem) {\n            this._super();\n\n            elem.on({\n                'update':   this.onChildrenUpdate,\n                'loading':  this.onContentLoading\n            });\n\n            return this;\n        },\n\n        /**\n         * Is being invoked on children update.\n         * Sets changed property to one incoming.\n         * Invokes setActive method if settings\n         * contain makeVisible property set to true.\n         *\n         * @param  {Boolean} hasChanged\n         */\n        onChildrenUpdate: function (hasChanged) {\n            if (!hasChanged) {\n                hasChanged = _.some(this.delegate('hasChanged'));\n            }\n\n            this.changed(hasChanged);\n        },\n\n        /**\n         * Callback that sets loading property to true.\n         */\n        onContentLoading: function (isLoading) {\n            this.loading(isLoading);\n        }\n    });\n});\n","Magento_Ui/js/form/components/html.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore',\n    'uiComponent'\n], function ($, _, Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            content:        '',\n            showSpinner:    false,\n            loading:        false,\n            visible:        true,\n            template:       'ui/content/content',\n            additionalClasses: {},\n            ignoreTmpls: {\n                content: true\n            }\n        },\n\n        /**\n         * Extends instance with default config, calls 'initialize' method of\n         *     parent, calls 'initAjaxConfig'\n         */\n        initialize: function () {\n            _.bindAll(this, 'onContainerToggle', 'onDataLoaded');\n\n            this._super()\n                ._setClasses()\n                .initAjaxConfig();\n\n            return this;\n        },\n\n        /**\n         * Calls 'initObservable' method of parent, initializes observable\n         * properties of instance\n         *\n         * @return {Object} - reference to instance\n         */\n        initObservable: function () {\n            this._super()\n                .observe('content loading visible');\n\n            return this;\n        },\n\n        /**\n         * Extends 'additionalClasses' object.\n         *\n         * @returns {Group} Chainable.\n         */\n        _setClasses: function () {\n            var additional = this.additionalClasses,\n                classes;\n\n            if (_.isString(additional)) {\n                additional = this.additionalClasses.split(' ');\n                classes = this.additionalClasses = {};\n\n                additional.forEach(function (name) {\n                    classes[name] = true;\n                }, this);\n            }\n\n            _.extend(this.additionalClasses, {\n                'admin__scope-old': !!additional\n            });\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        initContainer: function (parent) {\n            this._super();\n\n            parent.on('active', this.onContainerToggle);\n\n            return this;\n        },\n\n        /**\n         * Initializes default ajax config on instance\n         *\n         * @return {Object} - reference to instance\n         */\n        initAjaxConfig: function () {\n            this.ajaxConfig = {\n                url: this.url,\n                data: {\n                    FORM_KEY: window.FORM_KEY\n                },\n                success:    this.onDataLoaded\n            };\n\n            return this;\n        },\n\n        /**\n         * Calls 'loadData' if both 'active' variable and 'shouldLoad'\n         * property are truthy\n         *\n         * @param  {Boolean} active\n         */\n        onContainerToggle: function (active) {\n            if (active && this.shouldLoad()) {\n                this.loadData();\n            }\n        },\n\n        /**\n         * Defines if instance has 'content' property defined.\n         *\n         * @return {Boolean} [description]\n         */\n        hasData: function () {\n            return !!this.content();\n        },\n\n        /**\n         * Defines if instance should load external data\n         *\n         * @return {Boolean}\n         */\n        shouldLoad: function () {\n            return this.url && !this.hasData() && !this.loading();\n        },\n\n        /**\n         * Sets loading property to true, makes ajax call\n         *\n         * @return {Object} - reference to instance\n         */\n        loadData: function () {\n            this.loading(true);\n\n            $.ajax(this.ajaxConfig);\n\n            return this;\n        },\n\n        /**\n         * Ajax's request success handler. Calls 'updateContent' passing 'data'\n         * to it, then sets 'loading' property to false.\n         *\n         * @param  {String} data\n         */\n        onDataLoaded: function (data) {\n            this.updateContent(data)\n                .loading(false);\n        },\n\n        /**\n         * Sets incoming data 'content' property's value\n         *\n         * @param  {String} content\n         * @return {Object} - reference to instance\n         */\n        updateContent: function (content) {\n            this.content(content);\n\n            return this;\n        },\n\n        /**\n         * Content getter\n         *\n         * @returns {String}\n         */\n        getContentUnsanitizedHtml: function () {\n            return this.content();\n        }\n    });\n});\n","Magento_Ui/js/form/components/collection/item.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'mageUtils',\n    '../tab'\n], function (_, utils, Tab) {\n    'use strict';\n\n    var previewConfig = {\n        separator: ' ',\n        prefix: ''\n    };\n\n    /**\n     * Parses incoming data and returns result merged with default preview config\n     *\n     * @param  {Object|String} data\n     * @return {Object}\n     */\n    function parsePreview(data) {\n        if (typeof data == 'string') {\n            data = {\n                items: data\n            };\n        }\n\n        data.items = utils.stringToArray(data.items);\n\n        return _.defaults(data, previewConfig);\n    }\n\n    return Tab.extend({\n        defaults: {\n            label: '',\n            uniqueNs: 'activeCollectionItem',\n            previewTpl: 'ui/form/components/collection/preview'\n        },\n\n        /**\n         * Extends instance with default config, calls initializes of parent class\n         */\n        initialize: function () {\n            _.bindAll(this, 'buildPreview', 'hasPreview');\n\n            return this._super();\n        },\n\n        /**\n         * Calls initProperties of parent class, initializes properties\n         * of instance.\n         *\n         * @return {Object} - reference to instance\n         */\n        initConfig: function () {\n            this._super();\n\n            this.displayed = [];\n\n            return this;\n        },\n\n        /**\n         * Calls initObservable of parent class, initializes observable\n         * properties of instance.\n         *\n         * @return {Object} - reference to instance\n         */\n        initObservable: function () {\n            this._super()\n                .observe({\n                    noPreview: true,\n                    indexed: {}\n                });\n\n            return this;\n        },\n\n        /**\n         * Is being called when child element has been initialized,\n         *     calls initElement of parent class, binds to element's update event,\n         *     calls insertToArea and insertToIndexed methods passing element to it\n         *\n         * @param  {Object} elem\n         */\n        initElement: function (elem) {\n            this._super()\n                .insertToIndexed(elem);\n\n            return this;\n        },\n\n        /**\n         * Adds element to observable indexed object of instance\n         *\n         * @param  {Object} elem\n         * @return {Object} - reference to instance\n         */\n        insertToIndexed: function (elem) {\n            var indexed = this.indexed();\n\n            indexed[elem.index] = elem;\n\n            this.indexed(indexed);\n\n            return this;\n        },\n\n        /**\n         * Destroys current instance along with all of its' children.\n         * Overrides base method to clear data when this method is called.\n         */\n        destroy: function () {\n            this._super();\n            this._clearData();\n        },\n\n        /**\n         * Clears all data associated with component.\n         * @private\n         *\n         * @returns {Item} Chainable.\n         */\n        _clearData: function () {\n            this.source.remove(this.dataScope);\n\n            return this;\n        },\n\n        /**\n         * Formats incoming previews array via parsePreview function.\n         *\n         * @param  {Array} previews\n         * @return {Array} - formatted previews\n         */\n        formatPreviews: function (previews) {\n            return previews.map(parsePreview);\n        },\n\n        /**\n         * Creates string view of previews\n         *\n         * @param  {Object} data\n         * @return {Strict} - formatted preview string\n         */\n        buildPreview: function (data) {\n            var preview = this.getPreview(data.items),\n                prefix = data.prefix;\n\n            return prefix + preview.join(data.separator);\n        },\n\n        /**\n         * Defines if instance has preview for incoming data\n         *\n         * @param  {Object}  data\n         * @return {Boolean}\n         */\n        hasPreview: function (data) {\n            return !!this.getPreview(data.items).length;\n        },\n\n        /**\n         * Creates an array of previews for elements specified in incoming\n         * items array, calls updatePreview afterwards.\n         *\n         * @param  {Array} items - An array of element's indexes.\n         * @returns {Array} An array of previews.\n         */\n        getPreview: function (items) {\n            var elems = this.indexed(),\n                displayed = this.displayed,\n                preview;\n\n            items = items.map(function (index) {\n                var elem = elems[index];\n\n                preview = elem && elem.visible() ? elem.getPreview() : '';\n\n                preview = Array.isArray(preview) ?\n                    _.compact(preview).join(', ') :\n                    preview;\n\n                utils.toggle(displayed, index, !!preview);\n\n                return preview;\n            });\n\n            this.noPreview(!displayed.length);\n\n            return _.compact(items);\n        }\n    });\n});\n","Magento_Ui/js/view/messages.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'ko',\n    'jquery',\n    'uiComponent',\n    '../model/messageList',\n    'jquery-ui-modules/effect-blind'\n], function (ko, $, Component, globalMessages) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Ui/messages',\n            selector: '[data-role=checkout-messages]',\n            isHidden: false,\n            hideTimeout: 5000,\n            hideSpeed: 500,\n            listens: {\n                isHidden: 'onHiddenChange'\n            }\n        },\n\n        /** @inheritdoc */\n        initialize: function (config, messageContainer) {\n            this._super()\n                .initObservable();\n\n            this.messageContainer = messageContainer || config.messageContainer || globalMessages;\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            this._super()\n                .observe('isHidden');\n\n            return this;\n        },\n\n        /**\n         * Checks visibility.\n         *\n         * @return {Boolean}\n         */\n        isVisible: function () {\n            return this.isHidden(this.messageContainer.hasMessages());\n        },\n\n        /**\n         * Remove all messages.\n         */\n        removeAll: function () {\n            this.messageContainer.clear();\n        },\n\n        /**\n         * @param {Boolean} isHidden\n         */\n        onHiddenChange: function (isHidden) {\n            // Hide message block if needed\n            if (isHidden) {\n                setTimeout(function () {\n                    $(this.selector).hide('slow');\n\n                    //commented because effect-blind.js(1.13.1) is having show & hide issue\n                    // $(this.selector).hide('blind', {}, this.hideSpeed);\n                }.bind(this), this.hideTimeout);\n            }\n        }\n    });\n});\n","Magento_Ui/js/core/app.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    './renderer/types',\n    './renderer/layout',\n    '../lib/knockout/bootstrap'\n], function (types, layout) {\n    'use strict';\n\n    return function (data, merge) {\n        types.set(data.types);\n        layout(data.components, undefined, true, merge);\n    };\n});\n","Magento_Ui/js/core/renderer/layout.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'jquery',\n    'mageUtils',\n    'uiRegistry',\n    './types',\n    '../../lib/logger/console-logger'\n], function (_, $, utils, registry, types, consoleLogger) {\n    'use strict';\n\n    var templates = registry.create(),\n        layout = {},\n        cachedConfig = {};\n\n    /**\n     * Build name from parent name and node name\n     *\n     * @param {Object} parent\n     * @param {Object} node\n     * @param {String} [name]\n     * @returns {String}\n     */\n    function getNodeName(parent, node, name) {\n        var parentName = parent && parent.name;\n\n        if (typeof name !== 'string') {\n            name = node.name || name;\n        }\n\n        return utils.fullPath(parentName, name);\n    }\n\n    /**\n     * Get node type from node or parent.\n     *\n     * @param {Object} parent\n     * @param {Object} node\n     * @returns {String}\n     */\n    function getNodeType(parent, node) {\n        return node.type || parent && parent.childType;\n    }\n\n    /**\n     * Get data scope based on parent data scope and node data scope.\n     *\n     * @param {Object} parent\n     * @param {Object} node\n     * @returns {String}\n     */\n    function getDataScope(parent, node) {\n        var dataScope = node.dataScope,\n            parentScope = parent && parent.dataScope;\n\n        return !utils.isEmpty(parentScope) ?\n            !utils.isEmpty(dataScope) ?\n                parentScope + '.' + dataScope :\n                parentScope :\n            dataScope || '';\n    }\n\n    /**\n     * Load node dependencies on other instances.\n     *\n     * @param {Object} node\n     * @returns {jQueryPromise}\n     */\n    function loadDeps(node) {\n        var loaded = $.Deferred(),\n            loggerUtils = consoleLogger.utils;\n\n        if (node.deps) {\n            consoleLogger.utils.asyncLog(\n                loaded,\n                {\n                    data: {\n                        component: node.name,\n                        deps: node.deps\n                    },\n                    messages: loggerUtils.createMessages(\n                        'depsStartRequesting',\n                        'depsFinishRequesting',\n                        'depsLoadingFail'\n                    )\n                }\n            );\n        }\n\n        registry.get(node.deps, function (deps) {\n            node.provider = node.extendProvider ? deps && deps.name : node.provider;\n            loaded.resolve(node);\n        });\n\n        return loaded.promise();\n    }\n\n    /**\n     * Load node component file via requirejs.\n     *\n     * @param {Object} node\n     * @returns {jQueryPromise}\n     */\n    function loadSource(node) {\n        var loaded = $.Deferred(),\n            source = node.component;\n\n        consoleLogger.info('componentStartLoading', {\n            component: node.component\n        });\n\n        require([source], function (constr) {\n            consoleLogger.info('componentFinishLoading', {\n                component: node.component\n            });\n            loaded.resolve(node, constr);\n        }, function () {\n            consoleLogger.error('componentLoadingFail', {\n                component: node.component\n            });\n        });\n\n        return loaded.promise();\n    }\n\n    /**\n     * Create a new component instance and set it to the registry.\n     *\n     * @param {Object} node\n     * @param {Function} Constr\n     */\n    function initComponent(node, Constr) {\n        var component = new Constr(_.omit(node, 'children'));\n\n        consoleLogger.info('componentStartInitialization', {\n            component: node.component,\n            componentName: node.name\n        });\n\n        registry.set(node.name, component);\n    }\n\n    /**\n     * Application entry point.\n     *\n     * @param {Object} nodes\n     * @param {Object} parent\n     * @param {Boolean} cached\n     * @param {Boolean} merge\n     * @returns {Boolean|undefined}\n     */\n    function run(nodes, parent, cached, merge) {\n        if (_.isBoolean(merge) && merge) {\n            layout.merge(nodes);\n\n            return false;\n        }\n\n        if (cached) {\n            cachedConfig[_.keys(nodes)[0]] = JSON.parse(JSON.stringify(nodes));\n        }\n\n        _.each(nodes || [], layout.iterator.bind(layout, parent));\n    }\n\n    _.extend(layout, {\n        /**\n         * Determines if node ready to be added or process it.\n         *\n         * @param {Object} parent\n         * @param {Object|String} node\n         */\n        iterator: function (parent, node) {\n            var action = _.isString(node) ?\n                this.addChild :\n                this.process;\n\n            action.apply(this, arguments);\n        },\n\n        /**\n         * Prepare component.\n         *\n         * @param {Object} parent\n         * @param {Object} node\n         * @param {String} name\n         * @returns {Object}\n         */\n        process: function (parent, node, name) {\n            if (!parent && node.parent) {\n                return this.waitParent(node, name);\n            }\n\n            if (node.nodeTemplate) {\n                return this.waitTemplate.apply(this, arguments);\n            }\n\n            node = this.build.apply(this, arguments);\n\n            if (!registry.has(node.name)) {\n                this.addChild(parent, node)\n                    .manipulate(node)\n                    .initComponent(node);\n            }\n\n            if (node) {\n                run(node.children, node);\n            }\n\n            return this;\n        },\n\n        /**\n         * Detailed processing of component config.\n         *\n         * @param {Object} parent\n         * @param {Object} node\n         * @param {String} name\n         * @returns {Boolean|Object}\n         */\n        build: function (parent, node, name) {\n            var defaults    = parent && parent.childDefaults || {},\n                children    = this.filterDisabledChildren(node.children),\n                type        = getNodeType(parent, node),\n                dataScope   = getDataScope(parent, node),\n                component,\n                extendDeps  = true,\n                nodeName;\n\n            node.children = false;\n            node.extendProvider = true;\n\n            if (node.config && node.config.provider || node.provider) {\n                node.extendProvider = false;\n            }\n\n            if (node.config && node.config.deps || node.deps) {\n                extendDeps = false;\n            }\n\n            node = utils.extend({\n            }, types.get(type), defaults, node);\n\n            nodeName = getNodeName(parent, node, name);\n\n            if (registry.has(nodeName)) {\n                component = registry.get(nodeName);\n                component.children = children;\n\n                return component;\n            }\n\n            if (extendDeps && parent && parent.deps && type) {\n                node.deps = parent.deps;\n            }\n\n            _.extend(node, node.config || {}, {\n                index: node.name || name,\n                name: nodeName,\n                dataScope: dataScope,\n                parentName: utils.getPart(nodeName, -2),\n                parentScope: utils.getPart(dataScope, -2)\n            });\n\n            node.children = children;\n            node.componentType = node.type;\n\n            delete node.type;\n            delete node.config;\n\n            if (children) {\n                node.initChildCount = _.size(children);\n            }\n\n            if (node.isTemplate) {\n                node.isTemplate = false;\n\n                templates.set(node.name, node);\n                registry.get(node.parentName, function (parentComp) {\n                    parentComp.childTemplate = node;\n                });\n\n                return false;\n            }\n\n            if (node.componentDisabled === true) {\n                return false;\n            }\n\n            return node;\n        },\n\n        /**\n         * Filter out all disabled components.\n         *\n         * @param {Object} children\n         * @returns {*}\n         */\n        filterDisabledChildren: function (children) {\n            var cIds;\n\n            //cleanup children config.componentDisabled = true\n            if (children && typeof children === 'object') {\n                cIds = Object.keys(children);\n\n                if (cIds) {\n                    _.each(cIds, function (cId) {\n                        if (typeof children[cId] === 'object' &&\n                            children[cId].hasOwnProperty('config') &&\n                            typeof children[cId].config === 'object' &&\n                            children[cId].config.hasOwnProperty('componentDisabled') &&\n                            children[cId].config.componentDisabled === true) {\n                            delete children[cId];\n                        }\n                    });\n                }\n            }\n\n            return children;\n        },\n\n        /**\n         * Init component.\n         *\n         * @param {Object} node\n         * @returns {Object}\n         */\n        initComponent: function (node) {\n            if (!node.component) {\n                return this;\n            }\n\n            loadDeps(node)\n                .then(loadSource)\n                .done(initComponent);\n\n            return this;\n        }\n    });\n\n    _.extend(layout, {\n        /**\n         * Loading component marked as isTemplate.\n         *\n         * @param {Object} parent\n         * @param {Object} node\n         * @returns {Object}\n         */\n        waitTemplate: function (parent, node) {\n            var args = _.toArray(arguments);\n\n            templates.get(node.nodeTemplate, function () {\n                this.applyTemplate.apply(this, args);\n            }.bind(this));\n\n            return this;\n        },\n\n        /**\n         * Waiting for parent component and process provided component.\n         *\n         * @param {Object} node\n         * @param {String} name\n         * @returns {Object}\n         */\n        waitParent: function (node, name) {\n            var process = this.process.bind(this);\n\n            registry.get(node.parent, function (parent) {\n                process(parent, node, name);\n            });\n\n            return this;\n        },\n\n        /**\n         * Processing component marked as isTemplate.\n         *\n         * @param {Object} parent\n         * @param {Object} node\n         * @param {String} name\n         */\n        applyTemplate: function (parent, node, name) {\n            var template = templates.get(node.nodeTemplate);\n\n            node = utils.extend({}, template, node);\n\n            delete node.nodeTemplate;\n\n            this.process(parent, node, name);\n        }\n    });\n\n    _.extend(layout, {\n        /**\n         * Determines inserting strategy.\n         *\n         * @param {Object} node\n         * @returns {Object}\n         */\n        manipulate: function (node) {\n            var name = node.name;\n\n            if (node.appendTo) {\n                this.insert(name, node.appendTo, -1);\n            }\n\n            if (node.prependTo) {\n                this.insert(name, node.prependTo, 0);\n            }\n\n            if (node.insertTo) {\n                this.insertTo(name, node.insertTo);\n            }\n\n            return this;\n        },\n\n        /**\n         * Insert component to provide target and position.\n         *\n         * @param {Object|String} item\n         * @param {Object} target\n         * @param {Number} position\n         * @returns {Object}\n         */\n        insert: function (item, target, position) {\n            registry.get(target, function (container) {\n                container.insertChild(item, position);\n            });\n\n            return this;\n        },\n\n        /**\n         * Insert component into multiple targets.\n         *\n         * @param {Object} item\n         * @param {Array} targets\n         * @returns {Object}\n         */\n        insertTo: function (item, targets) {\n            _.each(targets, function (info, target) {\n                this.insert(item, target, info.position);\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Add provided child to parent.\n         *\n         * @param {Object} parent\n         * @param {Object|String} child\n         * @returns {Object}\n         */\n        addChild: function (parent, child) {\n            var name;\n\n            if (parent && parent.component) {\n                name = child.name || child;\n\n                this.insert(name, parent.name, child.sortOrder);\n            }\n\n            return this;\n        },\n\n        /**\n         * Merge components configuration with cached configuration.\n         *\n         * @param {Array} components\n         */\n        merge: function (components) {\n            var cachedKey = _.keys(components)[0],\n                compared = utils.compare(cachedConfig[cachedKey], components),\n                remove = this.filterComponents(this.getByProperty(compared.changes, 'type', 'remove'), true),\n                update = this.getByProperty(compared.changes, 'type', 'update'),\n                dataSources = this.getDataSources(components),\n                names, index, name, component;\n\n            _.each(dataSources, function (val, key) {\n                name = key.replace(/\\.children|\\.config/g, '');\n                component = registry.get(name);\n\n                component.cacheData();\n                component.updateConfig(\n                    true,\n                    this.getFullConfig(key, components),\n                    this.getFullConfig(key, cachedConfig[cachedKey])\n                );\n            }, this);\n\n            _.each(remove, function (val) {\n                component = registry.get(val.path);\n\n                if (component) {\n                    component.destroy();\n                }\n            });\n\n            update = _.compact(_.filter(update, function (val) {\n                return !_.isEqual(val.oldValue, val.value);\n            }));\n\n            _.each(update, function (val) {\n                names = val.path.split('.');\n                index = Math.max(_.lastIndexOf(names, 'config'), _.lastIndexOf(names, 'children') + 2);\n                name = _.without(names.splice(0, index), 'children', 'config').join('.');\n                component = registry.get(name);\n\n                if (val.name === 'sortOrder' && component) {\n                    registry.get(component.parentName).insertChild(component, val.value);\n                } else if (component) {\n                    component.updateConfig(\n                        val.oldValue,\n                        val.value,\n                        val.path\n                    );\n                }\n            }, this);\n\n            run(components, undefined, true);\n        },\n\n        /**\n         * Recursive dataSource assignment.\n         *\n         * @param {Object} config\n         * @param {String} parentPath\n         * @returns {Object}\n         */\n        getDataSources: function (config, parentPath) {\n            var dataSources = {},\n                key, obj;\n\n            /* eslint-disable no-loop-func, max-depth */\n            for (key in config) {\n                if (config.hasOwnProperty(key)) {\n                    if (\n                        key === 'type' &&\n                        config[key] === 'dataSource' &&\n                        config.hasOwnProperty('config')\n                    ) {\n                        dataSources[parentPath + '.config'] = config.config;\n                    } else if (_.isObject(config[key])) {\n                        obj = this.getDataSources(config[key], utils.fullPath(parentPath, key));\n\n                        _.each(obj, function (value, path) {\n                            dataSources[path] = value;\n                        });\n                    }\n                }\n            }\n\n            /* eslint-enable no-loop-func, max-depth */\n\n            return dataSources;\n        },\n\n        /**\n         * Configuration getter.\n         *\n         * @param {String} path\n         * @param {Object} config\n         * @returns {Boolean|Object}\n         */\n        getFullConfig: function (path, config) {\n            var index;\n\n            path = path.split('.');\n            index = _.lastIndexOf(path, 'config');\n\n            if (!~index) {\n                return false;\n            }\n            path = path.splice(0, index);\n\n            _.each(path, function (val) {\n                config = config[val];\n            });\n\n            return config.config;\n        },\n\n        /**\n         * Filter data by property and value.\n         *\n         * @param {Object} data\n         * @param {String} prop\n         * @param {*} propValue\n         */\n        getByProperty: function (data, prop, propValue) {\n            return _.filter(data, function (value) {\n                return value[prop] === propValue;\n            });\n        },\n\n        /**\n         * Filter components.\n         *\n         * @param {Array} data\n         * @param {Boolean} splitPath\n         * @param {Number} index\n         * @param {String} separator\n         * @param {String} keyName\n         * @returns {Array}\n         */\n        filterComponents: function (data, splitPath, index, separator, keyName) {\n            var result = [],\n                names, length;\n\n            index = -2;\n            separator = '.' || separator;\n            keyName = 'children' || keyName;\n\n            _.each(data, function (val) {\n                names = val.path.split(separator);\n                length  = names.length;\n\n                if (names[length + index] === keyName) {\n                    val.path = splitPath ? _.without(names, keyName).join(separator) : val.path;\n                    result.push(val);\n                }\n            });\n\n            return result;\n        }\n    });\n\n    return run;\n});\n","Magento_Ui/js/core/renderer/types.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'mageUtils'\n], function (_, utils) {\n    'use strict';\n\n    var store = {};\n\n    /**\n     * Flatten a nested data.\n     *\n     * @param {Object} data\n     * @returns {Object}\n     */\n    function flatten(data) {\n        var extender = data.extends || [],\n            result = {};\n\n        extender = utils.stringToArray(extender);\n\n        extender.push(data);\n\n        extender.forEach(function (item) {\n            if (_.isString(item)) {\n                item = store[item] || {};\n            }\n\n            utils.extend(result, item);\n        });\n\n        delete result.extends;\n\n        return result;\n    }\n\n    return {\n        /**\n         * Set types to store object.\n         *\n         * @param {Object} types\n         */\n        set: function (types) {\n            types = types || {};\n\n            utils.extend(store, types);\n\n            _.each(types, function (data, type) {\n                store[type] = flatten(data);\n            });\n        },\n\n        /**\n         * Get type from store object.\n         *\n         * @param {String} type\n         * @returns {*|{}}\n         */\n        get: function (type) {\n            return store[type] || {};\n        }\n    };\n});\n","Magento_Ui/js/modal/prompt.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore',\n    'mage/template',\n    'text!ui/template/modal/modal-prompt-content.html',\n    'jquery-ui-modules/widget',\n    'Magento_Ui/js/modal/modal',\n    'mage/translate'\n], function ($, _, template, promptContentTmpl) {\n    'use strict';\n\n    $.widget('mage.prompt', $.mage.modal, {\n        options: {\n            modalClass: 'prompt',\n            promptContentTmpl: promptContentTmpl,\n            promptField: '[data-role=\"promptField\"]',\n            attributesForm: {},\n            attributesField: {},\n            value: '',\n            validation: false,\n            validationRules: [],\n            keyEventHandlers: {\n\n                /**\n                 * Enter key press handler,\n                 * submit result and close modal window\n                 * @param {Object} event - event\n                 */\n                enterKey: function (event) {\n                    if (this.options.isOpen && this.modal.find(document.activeElement).length ||\n                        this.options.isOpen && this.modal[0] === document.activeElement) {\n                        this.closeModal(true);\n                        event.preventDefault();\n                    }\n                },\n\n                /**\n                 * Tab key press handler,\n                 * set focus to elements\n                 */\n                tabKey: function () {\n                    if (document.activeElement === this.modal[0]) {\n                        this._setFocus('start');\n                    }\n                },\n\n                /**\n                 * Escape key press handler,\n                 * cancel and close modal window\n                 * @param {Object} event - event\n                 */\n                escapeKey: function (event) {\n                    if (this.options.isOpen && this.modal.find(document.activeElement).length ||\n                        this.options.isOpen && this.modal[0] === document.activeElement) {\n                        this.closeModal();\n                        event.preventDefault();\n                    }\n                }\n            },\n            actions: {\n\n                /**\n                 * Callback always - called on all actions.\n                 */\n                always: function () {},\n\n                /**\n                 * Callback confirm.\n                 */\n                confirm: function () {},\n\n                /**\n                 * Callback cancel.\n                 */\n                cancel: function () {}\n            },\n            buttons: [{\n                text: $.mage.__('Cancel'),\n                class: 'action-secondary action-dismiss',\n\n                /**\n                 * Click handler.\n                 */\n                click: function () {\n                    this.closeModal();\n                }\n            }, {\n                text: $.mage.__('OK'),\n                class: 'action-primary action-accept',\n\n                /**\n                 * Click handler.\n                 */\n                click: function () {\n                    this.closeModal(true);\n                }\n            }]\n        },\n\n        /**\n         * Create widget.\n         */\n        _create: function () {\n            this.options.focus = this.options.promptField;\n            this.options.validation = this.options.validation && this.options.validationRules.length;\n            this.options.outerClickHandler = this.options.outerClickHandler || _.bind(this.closeModal, this, false);\n            this._super();\n            this.modal.find(this.options.modalContent).append(this.getFormTemplate());\n            this.modal.find(this.options.modalCloseBtn).off().on('click',  _.bind(this.closeModal, this, false));\n\n            if (this.options.validation) {\n                this.setValidationClasses();\n            }\n\n            this.openModal();\n        },\n\n        /**\n         * Form template getter.\n         *\n         * @returns {Object} Form template.\n         */\n        getFormTemplate: function () {\n            var formTemplate,\n                formAttr = '',\n                inputAttr = '',\n                attributeName;\n\n            for (attributeName in this.options.attributesForm) {\n                if (this.options.attributesForm.hasOwnProperty(attributeName)) {\n                    formAttr = formAttr + ' ' + attributeName + '=\"' +\n                        this.options.attributesForm[attributeName] + '\"';\n                }\n            }\n\n            for (attributeName in this.options.attributesField) {\n                if (this.options.attributesField.hasOwnProperty(attributeName)) {\n                    inputAttr = inputAttr + ' ' + attributeName + '=\"' +\n                        this.options.attributesField[attributeName] + '\"';\n                }\n            }\n\n            formTemplate = $(template(this.options.promptContentTmpl, {\n                data: this.options,\n                formAttr: formAttr,\n                inputAttr: inputAttr\n            }));\n\n            return formTemplate;\n        },\n\n        /**\n         * Remove widget\n         */\n        _remove: function () {\n            this.modal.remove();\n        },\n\n        /**\n         * Validate prompt field\n         */\n        validate: function () {\n            return $.validator.validateSingleElement(this.options.promptField);\n        },\n\n        /**\n         * Add validation classes to prompt field\n         */\n        setValidationClasses: function () {\n            this.modal.find(this.options.promptField).attr('class', $.proxy(function (i, val) {\n                return val + ' ' + this.options.validationRules.join(' ');\n            }, this));\n        },\n\n        /**\n         * Open modal window\n         */\n        openModal: function () {\n            this._super();\n            this.modal.find(this.options.promptField).val(this.options.value);\n        },\n\n        /**\n         * Close modal window\n         */\n        closeModal: function (result) {\n            var value;\n\n            if (result) {\n                if (this.options.validation && !this.validate()) {\n                    return false;\n                }\n\n                value = this.modal.find(this.options.promptField).val();\n                this.options.actions.confirm.call(this, value);\n            } else {\n                this.options.actions.cancel.call(this, result);\n            }\n\n            this.options.actions.always();\n            this.element.on('promptclosed', _.bind(this._remove, this));\n\n            return this._super();\n        }\n    });\n\n    return function (config) {\n        return $('<div class=\"prompt-message\"></div>').html(config.content).prompt(config);\n    };\n});\n","Magento_Ui/js/modal/alert.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore',\n    'jquery-ui-modules/widget',\n    'Magento_Ui/js/modal/confirm',\n    'mage/translate'\n], function ($, _) {\n    'use strict';\n\n    $.widget('mage.alert', $.mage.confirm, {\n        options: {\n            modalClass: 'confirm',\n            title: $.mage.__('Attention'),\n            actions: {\n\n                /**\n                 * Callback always - called on all actions.\n                 */\n                always: function () {}\n            },\n            buttons: [{\n                text: $.mage.__('OK'),\n                class: 'action-primary action-accept',\n\n                /**\n                 * Click handler.\n                 */\n                click: function () {\n                    this.closeModal(true);\n                }\n            }]\n        },\n\n        /**\n         * Close modal window.\n         */\n        closeModal: function () {\n            this.options.actions.always();\n            this.element.on('alertclosed', _.bind(this._remove, this));\n\n            return this._super();\n        }\n    });\n\n    return function (config) {\n        return $('<div></div>').html(config.content).alert(config);\n    };\n});\n","Magento_Ui/js/modal/modal-component.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'Magento_Ui/js/lib/view/utils/async',\n    'uiCollection',\n    'uiRegistry',\n    'underscore',\n    './modal'\n], function ($, Collection, registry, _) {\n    'use strict';\n\n    return Collection.extend({\n        defaults: {\n            template: 'ui/modal/modal-component',\n            title: '',\n            subTitle: '',\n            options: {\n                modalClass: '',\n                title: '',\n                subTitle: '',\n                buttons: [],\n                keyEventHandlers: {}\n            },\n            valid: true,\n            links: {\n                title: 'options.title',\n                subTitle: 'options.subTitle'\n            },\n            listens: {\n                state: 'onState',\n                title: 'setTitle',\n                'options.subTitle': 'setSubTitle'\n            },\n            modalClass: 'modal-component',\n            onCancel: 'closeModal'\n        },\n\n        /**\n         * Initializes component.\n         *\n         * @returns {Object} Chainable.\n         */\n        initialize: function () {\n            this._super();\n            _.bindAll(this,\n                'initModal',\n                'openModal',\n                'closeModal',\n                'toggleModal',\n                'setPrevValues',\n                'validate');\n            this.initializeContent();\n\n            return this;\n        },\n\n        /**\n         * Initializes modal configuration\n         *\n         * @returns {Object} Chainable.\n         */\n        initConfig: function () {\n            return this._super()\n                .initSelector()\n                .initModalEvents();\n        },\n\n        /**\n         * Configure modal selector\n         *\n         * @returns {Object} Chainable.\n         */\n        initSelector: function () {\n            var modalClass = this.name.replace(/\\./g, '_');\n\n            this.contentSelector = '.' + this.modalClass;\n            this.options.modalClass = this.options.modalClass + ' ' + modalClass;\n            this.rootSelector = '.' + modalClass;\n\n            return this;\n        },\n\n        /**\n         * Configure modal keyboard handlers\n         * and outer click\n         *\n         * @returns {Object} Chainable.\n         */\n        initModalEvents: function () {\n            this.options.keyEventHandlers.escapeKey = this.options.outerClickHandler = this[this.onCancel].bind(this);\n\n            return this;\n        },\n\n        /**\n         * Initialize modal's content components\n         */\n        initializeContent: function () {\n            $.async({\n                component: this.name\n            }, this.initModal);\n        },\n\n        /**\n         * Init toolbar section so other components will be able to place something in it\n         */\n        initToolbarSection: function () {\n            this.set('toolbarSection', this.modal.data('mage-modal').modal.find('header').get(0));\n        },\n\n        /**\n         * Initializes observable properties.\n         *\n         * @returns {Object} Chainable.\n         */\n        initObservable: function () {\n            this._super();\n            this.observe(['state', 'focused']);\n\n            return this;\n        },\n\n        /**\n         * Wrap content in a modal of certain type\n         *\n         * @param {HTMLElement} element\n         * @returns {Object} Chainable.\n         */\n        initModal: function (element) {\n            if (!this.modal) {\n                this.overrideModalButtonCallback();\n                this.options.modalCloseBtnHandler = this[this.onCancel].bind(this);\n                this.modal = $(element).modal(this.options);\n                this.initToolbarSection();\n\n                if (this.waitCbk) {\n                    this.waitCbk();\n                    this.waitCbk = null;\n                }\n            }\n\n            return this;\n        },\n\n        /**\n         * Open modal\n         */\n        openModal: function () {\n            if (this.modal) {\n                this.state(true);\n            } else {\n                this.waitCbk = this.openModal;\n            }\n        },\n\n        /**\n         * Close modal\n         */\n        closeModal: function () {\n            if (this.modal) {\n                this.state(false);\n            } else {\n                this.waitCbk = this.closeModal;\n            }\n        },\n\n        /**\n         * Toggle modal\n         */\n        toggleModal: function () {\n            if (this.modal) {\n                this.state(!this.state());\n            } else {\n                this.waitCbk = this.toggleModal;\n            }\n        },\n\n        /**\n         * Sets title for modal\n         *\n         * @param {String} title\n         */\n        setTitle: function (title) {\n            if (this.title !== title) {\n                this.title = title;\n            }\n\n            if (this.modal) {\n                this.modal.modal('setTitle', title);\n            }\n        },\n\n        /**\n         * Sets subTitle for modal\n         *\n         * @param {String} subTitle\n         */\n        setSubTitle: function (subTitle) {\n            if (this.subTitle !== subTitle) {\n                this.subTitle = subTitle;\n            }\n\n            if (this.modal) {\n                this.modal.modal('setSubTitle', subTitle);\n            }\n        },\n\n        /**\n         * Wrap content in a modal of certain type\n         *\n         * @param {Boolean} state\n         */\n        onState: function (state) {\n            if (state) {\n                this.modal.modal('openModal');\n                this.applyData();\n            } else {\n                this.modal.modal('closeModal');\n            }\n        },\n\n        /**\n         * Validate everything validatable in modal\n         */\n        validate: function (elem) {\n            if (typeof elem === 'undefined') {\n                return;\n            }\n\n            if (typeof elem.validate === 'function') {\n                this.valid &= elem.validate().valid;\n            } else if (elem.elems) {\n                elem.elems().forEach(this.validate, this);\n            }\n        },\n\n        /**\n         * Reset data from provider\n         */\n        resetData: function () {\n            this.elems().forEach(this.resetValue, this);\n        },\n\n        /**\n         * Update 'applied' property with data from modal content\n         */\n        applyData: function () {\n            var applied = {};\n\n            this.elems().forEach(this.gatherValues.bind(this, applied), this);\n            this.applied = applied;\n        },\n\n        /**\n         * Gather values from modal content\n         *\n         * @param {Array} applied\n         * @param {HTMLElement} elem\n         */\n        gatherValues: function (applied, elem) {\n            if (typeof elem.value === 'function') {\n                applied[elem.name] = elem.value();\n            } else if (elem.elems) {\n                elem.elems().forEach(this.gatherValues.bind(this, applied), this);\n            }\n        },\n\n        /**\n         * Set to previous values from modal content\n         *\n         * @param {HTMLElement} elem\n         */\n        setPrevValues: function (elem) {\n            if (typeof elem.value === 'function') {\n                this.modal.focus();\n                elem.value(this.applied[elem.name]);\n            } else if (elem.elems) {\n                elem.elems().forEach(this.setPrevValues, this);\n            }\n        },\n\n        /**\n         * Triggers some method in every modal child elem, if this method is defined\n         *\n         * @param {Object} action - action configuration,\n         * must contain actionName and targetName and\n         * can contain params\n         */\n        triggerAction: function (action) {\n            var targetName = action.targetName,\n                params = action.params || [],\n                actionName = action.actionName,\n                target;\n\n            target = registry.async(targetName);\n\n            if (target && typeof target === 'function' && actionName) {\n                params.unshift(actionName);\n                target.apply(target, params);\n            }\n        },\n\n        /**\n         * Override modal buttons callback placeholders with real callbacks\n         */\n        overrideModalButtonCallback: function () {\n            var buttons = this.options.buttons;\n\n            if (buttons && buttons.length) {\n                buttons.forEach(function (button) {\n                    button.click = this.getButtonClickHandler(button.actions);\n                }, this);\n            }\n        },\n\n        /**\n         * Generate button click handler based on button's 'actions' configuration\n         */\n        getButtonClickHandler: function (actionsConfig) {\n            var actions = actionsConfig.map(\n                function (actionConfig) {\n                    if (_.isObject(actionConfig)) {\n                        return this.triggerAction.bind(this, actionConfig);\n                    }\n\n                    return this[actionConfig] ? this[actionConfig].bind(this) : function () {};\n                }, this);\n\n            return function () {\n                actions.forEach(\n                    function (action) {\n                        action();\n                    }\n                );\n            };\n        },\n\n        /**\n         * Cancels changes in modal:\n         * returning elems values to the previous state,\n         * and close modal\n         */\n        actionCancel: function () {\n            this.elems().forEach(this.setPrevValues, this);\n            this.closeModal();\n        },\n\n        /**\n         * Accept changes in modal by not preventing them.\n         * Can be extended by exporting 'gatherValues' result somewhere\n         */\n        actionDone: function () {\n            this.valid = true;\n            this.elems().forEach(this.validate, this);\n\n            if (this.valid) {\n                this.closeModal();\n            }\n        }\n    });\n});\n","Magento_Ui/js/modal/modalToggle.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'Magento_Ui/js/modal/modal'\n], function ($) {\n    'use strict';\n\n    return function (config, el) {\n        var widget,\n            content;\n\n        if (config.contentSelector) {\n            content = $(config.contentSelector);\n        } else if (config.content) {\n            content = $('<div></div>').html(config.content);\n        } else {\n            content = $('<div></div>');\n        }\n\n        widget = content.modal(config);\n\n        $(el).on(config.toggleEvent, function () {\n            var state = widget.data('mage-modal').options.isOpen;\n\n            if (state) {\n                widget.modal('closeModal');\n            } else {\n                widget.modal('openModal');\n            }\n\n            return false;\n        });\n\n        return widget;\n    };\n});\n","Magento_Ui/js/modal/confirm.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore',\n    'mage/translate',\n    'jquery-ui-modules/widget',\n    'Magento_Ui/js/modal/modal'\n], function ($, _, $t) {\n    'use strict';\n\n    $.widget('mage.confirm', $.mage.modal, {\n        options: {\n            modalClass: 'confirm',\n            title: '',\n            focus: '.action-accept',\n            actions: {\n\n                /**\n                 * Callback always - called on all actions.\n                 */\n                always: function () {},\n\n                /**\n                 * Callback confirm.\n                 */\n                confirm: function () {},\n\n                /**\n                 * Callback cancel.\n                 */\n                cancel: function () {}\n            },\n            buttons: [{\n                text: $t('Cancel'),\n                class: 'action-secondary action-dismiss',\n\n                /**\n                 * Click handler.\n                 */\n                click: function (event) {\n                    this.closeModal(event);\n                }\n            }, {\n                text: $t('OK'),\n                class: 'action-primary action-accept',\n\n                /**\n                 * Click handler.\n                 */\n                click: function (event) {\n                    this.closeModal(event, true);\n                }\n            }]\n        },\n\n        /**\n         * Create widget.\n         */\n        _create: function () {\n            this._super();\n            this.modal.find(this.options.modalCloseBtn).off().on('click', _.bind(this.closeModal, this));\n            this.openModal();\n        },\n\n        /**\n         * Remove modal window.\n         */\n        _remove: function () {\n            this.modal.remove();\n        },\n\n        /**\n         * Open modal window.\n         */\n        openModal: function () {\n            return this._super();\n        },\n\n        /**\n         * Close modal window.\n         */\n        closeModal: function (event, result) {\n            result = result || false;\n\n            if (result) {\n                this.options.actions.confirm(event);\n            } else {\n                this.options.actions.cancel(event);\n            }\n            this.options.actions.always(event);\n            this.element.on('confirmclosed', _.bind(this._remove, this));\n\n            return this._super();\n        }\n    });\n\n    return function (config) {\n        return $('<div></div>').html(config.content).confirm(config);\n    };\n});\n","Magento_Ui/js/modal/modal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore',\n    'mage/template',\n    'text!ui/template/modal/modal-popup.html',\n    'text!ui/template/modal/modal-slide.html',\n    'text!ui/template/modal/modal-custom.html',\n    'Magento_Ui/js/lib/key-codes',\n    'jquery-ui-modules/widget',\n    'jquery-ui-modules/core',\n    'mage/translate',\n    'jquery/z-index'\n], function ($, _, template, popupTpl, slideTpl, customTpl, keyCodes) {\n    'use strict';\n\n    /**\n     * Detect browser transition end event.\n     * @return {String|undefined} - transition event.\n     */\n    var transitionEvent = (function () {\n        var transition,\n            elementStyle = document.createElement('div').style,\n            transitions = {\n                'transition': 'transitionend',\n                'OTransition': 'oTransitionEnd',\n                'MozTransition': 'transitionend',\n                'WebkitTransition': 'webkitTransitionEnd'\n            };\n\n        for (transition in transitions) {\n            if (elementStyle[transition] !== undefined && transitions.hasOwnProperty(transition)) {\n                return transitions[transition];\n            }\n        }\n    })();\n\n    /**\n     * Modal Window Widget\n     */\n    $.widget('mage.modal', {\n        options: {\n            id: null,\n            type: 'popup',\n            title: '',\n            subTitle: '',\n            modalClass: '',\n            focus: '[data-role=\"closeBtn\"]',\n            autoOpen: false,\n            clickableOverlay: true,\n            popupTpl: popupTpl,\n            slideTpl: slideTpl,\n            customTpl: customTpl,\n            modalVisibleClass: '_show',\n            parentModalClass: '_has-modal',\n            innerScrollClass: '_inner-scroll',\n            responsive: false,\n            innerScroll: false,\n            modalTitle: '[data-role=\"title\"]',\n            modalSubTitle: '[data-role=\"subTitle\"]',\n            modalBlock: '[data-role=\"modal\"]',\n            modalCloseBtn: '[data-role=\"closeBtn\"]',\n            modalContent: '[data-role=\"content\"]',\n            modalAction: '[data-role=\"action\"]',\n            focusableScope: '[data-role=\"focusable-scope\"]',\n            focusableStart: '[data-role=\"focusable-start\"]',\n            focusableEnd: '[data-role=\"focusable-end\"]',\n            appendTo: 'body',\n            wrapperClass: 'modals-wrapper',\n            overlayClass: 'modals-overlay',\n            responsiveClass: 'modal-slide',\n            trigger: '',\n            modalLeftMargin: 45,\n            closeText: $.mage.__('Close'),\n            buttons: [{\n                text: $.mage.__('Ok'),\n                class: '',\n                attr: {},\n\n                /**\n                 * Default action on button click\n                 */\n                click: function (event) {\n                    this.closeModal(event);\n                }\n            }],\n            keyEventHandlers: {\n\n                /**\n                 * Tab key press handler,\n                 * set focus to elements\n                 */\n                tabKey: function () {\n                    if (document.activeElement === this.modal[0]) {\n                        this._setFocus('start');\n                    }\n                },\n\n                /**\n                 * Escape key press handler,\n                 * close modal window\n                 * @param {Object} event - event\n                 */\n                escapeKey: function (event) {\n                    if (this.options.isOpen && this.modal.find(document.activeElement).length ||\n                        this.options.isOpen && this.modal[0] === document.activeElement) {\n                        this.closeModal(event);\n                    }\n                }\n            }\n        },\n\n        /**\n         * Creates modal widget.\n         */\n        _create: function () {\n            _.bindAll(\n                this,\n                'keyEventSwitcher',\n                '_tabSwitcher',\n                'closeModal'\n            );\n\n            this.options.id = this.uuid;\n            this.options.transitionEvent = transitionEvent;\n            this._createWrapper();\n            this._renderModal();\n            this._createButtons();\n\n            if (this.options.trigger) {\n                $(document).on('click', this.options.trigger, _.bind(this.toggleModal, this));\n            }\n            this._on(this.modal.find(this.options.modalCloseBtn), {\n                'click': this.options.modalCloseBtnHandler ? this.options.modalCloseBtnHandler : this.closeModal\n            });\n            this._on(this.element, {\n                'openModal': this.openModal,\n                'closeModal': this.closeModal\n            });\n            this.options.autoOpen ? this.openModal() : false;\n        },\n\n        /**\n         * Returns element from modal node.\n         * @return {Object} - element.\n         */\n        _getElem: function (elem) {\n            return this.modal.find(elem);\n        },\n\n        /**\n         * Gets visible modal count.\n         * * @return {Number} - visible modal count.\n         */\n        _getVisibleCount: function () {\n            var modals = this.modalWrapper.find(this.options.modalBlock);\n\n            return modals.filter('.' + this.options.modalVisibleClass).length;\n        },\n\n        /**\n         * Gets count of visible modal by slide type.\n         * * @return {Number} - visible modal count.\n         */\n        _getVisibleSlideCount: function () {\n            var elems = this.modalWrapper.find('[data-type=\"slide\"]');\n\n            return elems.filter('.' + this.options.modalVisibleClass).length;\n        },\n\n        /**\n         * Listener key events.\n         * Call handler function if it exists\n         */\n        keyEventSwitcher: function (event) {\n            var key = keyCodes[event.keyCode];\n\n            if (this.options.keyEventHandlers.hasOwnProperty(key)) {\n                this.options.keyEventHandlers[key].apply(this, arguments);\n            }\n        },\n\n        /**\n         * Set title for modal.\n         *\n         * @param {String} title\n         */\n        setTitle: function (title) {\n            var $title = this.modal.find(this.options.modalTitle),\n                $subTitle = this.modal.find(this.options.modalSubTitle);\n\n            $title.text(title);\n            $title.append($subTitle);\n        },\n\n        /**\n         * Set sub title for modal.\n         *\n         * @param {String} subTitle\n         */\n        setSubTitle: function (subTitle) {\n            this.options.subTitle = subTitle;\n            this.modal.find(this.options.modalSubTitle).html(subTitle);\n        },\n\n        /**\n         * Toggle modal.\n         * * @return {Element} - current element.\n         */\n        toggleModal: function () {\n            if (this.options.isOpen === true) {\n                this.closeModal();\n            } else {\n                this.openModal();\n            }\n        },\n\n        /**\n         * Open modal.\n         * * @return {Element} - current element.\n         */\n        openModal: function () {\n            this.options.isOpen = true;\n            this.focussedElement = document.activeElement;\n            this._createOverlay();\n            this._setActive();\n            this._setKeyListener();\n            this.modal.one(this.options.transitionEvent, _.bind(this._setFocus, this, 'end', 'opened'));\n            this.modal.one(this.options.transitionEvent, _.bind(this._trigger, this, 'opened'));\n            this.modal.addClass(this.options.modalVisibleClass);\n\n            if (!this.options.transitionEvent) {\n                this._trigger('opened');\n            }\n\n            return this.element;\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         *  @param {String} type - can be \"opened\" or false\n         *      If type is \"opened\" - looks to \"this.options.focus\"\n         *      property and sets focus\n         */\n        _setFocus: function (position, type) {\n            var focusableElements,\n                infelicity;\n\n            if (type === 'opened' && this.options.focus) {\n                this.modal.find($(this.options.focus)).trigger('focus');\n            } else if (type === 'opened' && !this.options.focus) {\n                this.modal.find(this.options.focusableScope).trigger('focus');\n            } else if (position === 'end') {\n                this.modal.find(this.options.modalCloseBtn).trigger('focus');\n            } else if (position === 'start') {\n                infelicity = 2; //Constant for find last focusable element\n                focusableElements = this.modal.find(':focusable');\n                focusableElements.eq(focusableElements.length - infelicity).trigger('focus');\n            }\n        },\n\n        /**\n         * Set events listener when modal is opened.\n         */\n        _setKeyListener: function () {\n            this.modal.find(this.options.focusableStart).on('focusin', this._tabSwitcher);\n            this.modal.find(this.options.focusableEnd).on('focusin', this._tabSwitcher);\n            this.modal.on('keydown', this.keyEventSwitcher);\n        },\n\n        /**\n         * Remove events listener when modal is closed.\n         */\n        _removeKeyListener: function () {\n            this.modal.find(this.options.focusableStart).off('focusin', this._tabSwitcher);\n            this.modal.find(this.options.focusableEnd).off('focusin', this._tabSwitcher);\n            this.modal.off('keydown', this.keyEventSwitcher);\n        },\n\n        /**\n         * Switcher for focus event.\n         * @param {Object} e - event\n         */\n        _tabSwitcher: function (e) {\n            var target = $(e.target);\n\n            if (target.is(this.options.focusableStart)) {\n                this._setFocus('start');\n            } else if (target.is(this.options.focusableEnd)) {\n                this._setFocus('end');\n            }\n        },\n\n        /**\n         * Close modal.\n         * * @return {Element} - current element.\n         */\n        closeModal: function () {\n            var that = this;\n\n            this._removeKeyListener();\n            this.options.isOpen = false;\n            this.modal.one(this.options.transitionEvent, function () {\n                that._close();\n            });\n            this.modal.removeClass(this.options.modalVisibleClass);\n\n            if (!this.options.transitionEvent) {\n                that._close();\n            }\n\n            return this.element;\n        },\n\n        /**\n         * Helper for closeModal function.\n         */\n        _close: function () {\n            var trigger = _.bind(this._trigger, this, 'closed', this.modal);\n\n            $(this.focussedElement).trigger('focus');\n            this._destroyOverlay();\n            this._unsetActive();\n            _.defer(trigger, this);\n        },\n\n        /**\n         * Set z-index and margin for modal and overlay.\n         */\n        _setActive: function () {\n            var zIndex = this.modal.zIndex(),\n                baseIndex = zIndex + this._getVisibleCount();\n\n            if (this.modal.data('active')) {\n                return;\n            }\n\n            this.modal.data('active', true);\n\n            this.overlay.zIndex(++baseIndex);\n            this.prevOverlayIndex = this.overlay.zIndex();\n            this.modal.zIndex(this.overlay.zIndex() + 1);\n\n            if (this._getVisibleSlideCount()) {\n                this.modal.css('marginLeft', this.options.modalLeftMargin * this._getVisibleSlideCount());\n            }\n        },\n\n        /**\n         * Unset styles for modal and set z-index for previous modal.\n         */\n        _unsetActive: function () {\n            this.modal.removeAttr('style');\n            this.modal.data('active', false);\n\n            if (this.overlay) {\n                this.overlay.zIndex(this.prevOverlayIndex - 1);\n            }\n        },\n\n        /**\n         * Creates wrapper to hold all modals.\n         */\n        _createWrapper: function () {\n            this.modalWrapper = $(this.options.appendTo).find('.' + this.options.wrapperClass);\n\n            if (!this.modalWrapper.length) {\n                this.modalWrapper = $('<div></div>')\n                    .addClass(this.options.wrapperClass)\n                    .appendTo(this.options.appendTo);\n            }\n        },\n\n        /**\n         * Compile template and append to wrapper.\n         */\n        _renderModal: function () {\n            $(template(\n                this.options[this.options.type + 'Tpl'],\n                {\n                    data: this.options\n                })).appendTo(this.modalWrapper);\n            this.modal = this.modalWrapper.find(this.options.modalBlock).last();\n            this.element.appendTo(this._getElem(this.options.modalContent));\n\n            if (this.element.is(':hidden')) {\n                this.element.show();\n            }\n        },\n\n        /**\n         * Creates buttons pane.\n         */\n        _createButtons: function () {\n            this.buttons = this._getElem(this.options.modalAction);\n            _.each(this.options.buttons, function (btn, key) {\n                var button = this.buttons[key];\n\n                if (btn.attr) {\n                    $(button).attr(btn.attr);\n                }\n\n                if (btn.class) {\n                    $(button).addClass(btn.class);\n                }\n\n                if (!btn.click) {\n                    btn.click = this.closeModal;\n                }\n                $(button).on('click', _.bind(btn.click, this));\n            }, this);\n        },\n\n        /**\n         * Creates overlay, append it to wrapper, set previous click event on overlay.\n         */\n        _createOverlay: function () {\n            var events,\n                outerClickHandler = this.options.outerClickHandler || this.closeModal;\n\n            this.overlay = $('.' + this.options.overlayClass);\n\n            if (!this.overlay.length) {\n                $(this.options.appendTo).addClass(this.options.parentModalClass);\n                this.overlay = $('<div></div>')\n                    .addClass(this.options.overlayClass)\n                    .appendTo(this.modalWrapper);\n            }\n            events = $._data(this.overlay.get(0), 'events');\n            events ? this.prevOverlayHandler = events.click[0].handler : false;\n            this.options.clickableOverlay ? this.overlay.off().on('click', outerClickHandler) : false;\n        },\n\n        /**\n         * Destroy overlay.\n         */\n        _destroyOverlay: function () {\n            if (this._getVisibleCount()) {\n                this.overlay.off().on('click', this.prevOverlayHandler);\n            } else {\n                $(this.options.appendTo).removeClass(this.options.parentModalClass);\n                this.overlay.remove();\n                this.overlay = null;\n            }\n        }\n    });\n\n    return $.mage.modal;\n});\n","Magento_Ui/js/model/messages.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'ko',\n    'uiClass'\n], function (ko, Class) {\n    'use strict';\n\n    return Class.extend({\n        /** @inheritdoc */\n        initialize: function () {\n            this._super()\n                .initObservable();\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            this.errorMessages = ko.observableArray([]);\n            this.successMessages = ko.observableArray([]);\n\n            return this;\n        },\n\n        /**\n         * Add  message to list.\n         * @param {Object} messageObj\n         * @param {Object} type\n         * @returns {Boolean}\n         */\n        add: function (messageObj, type) {\n            var expr = /([%])\\w+/g,\n                message;\n\n            if (!messageObj.hasOwnProperty('parameters')) {\n                this.clear();\n                type.push(messageObj.message);\n\n                return true;\n            }\n            message = messageObj.message.replace(expr, function (varName) {\n                varName = varName.substr(1);\n\n                if (!isNaN(varName)) {\n                    varName--;\n                }\n\n                if (messageObj.parameters.hasOwnProperty(varName)) {\n                    return messageObj.parameters[varName];\n                }\n\n                return messageObj.parameters.shift();\n            });\n            this.clear();\n            type.push(message);\n\n            return true;\n        },\n\n        /**\n         * Add success message.\n         *\n         * @param {Object} message\n         * @return {*|Boolean}\n         */\n        addSuccessMessage: function (message) {\n            return this.add(message, this.successMessages);\n        },\n\n        /**\n         * Add error message.\n         *\n         * @param {Object} message\n         * @return {*|Boolean}\n         */\n        addErrorMessage: function (message) {\n            return this.add(message, this.errorMessages);\n        },\n\n        /**\n         * Get error messages.\n         *\n         * @return {Array}\n         */\n        getErrorMessages: function () {\n            return this.errorMessages;\n        },\n\n        /**\n         * Get success messages.\n         *\n         * @return {Array}\n         */\n        getSuccessMessages: function () {\n            return this.successMessages;\n        },\n\n        /**\n         * Checks if an instance has stored messages.\n         *\n         * @return {Boolean}\n         */\n        hasMessages: function () {\n            return this.errorMessages().length > 0 || this.successMessages().length > 0;\n        },\n\n        /**\n         * Removes stored messages.\n         */\n        clear: function () {\n            this.errorMessages.removeAll();\n            this.successMessages.removeAll();\n        }\n    });\n});\n","Magento_Ui/js/model/messageList.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    './messages'\n], function (Messages) {\n    'use strict';\n\n    return new Messages();\n});\n","Magento_Ui/js/lib/key-codes.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([], function () {\n    'use strict';\n\n    return {\n        13: 'enterKey',\n        27: 'escapeKey',\n        40: 'pageDownKey',\n        38: 'pageUpKey',\n        32: 'spaceKey',\n        9:  'tabKey',\n        37: 'pageLeftKey',\n        39: 'pageRightKey',\n        17: 'ctrlKey',\n        18: 'altKey',\n        16: 'shiftKey',\n        191: 'forwardSlashKey',\n        66: 'bKey',\n        73: 'iKey',\n        85: 'uKey'\n    };\n});\n","Magento_Ui/js/lib/spinner.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    var selector = '[data-role=\"spinner\"]',\n        spinner = $(selector);\n\n    return {\n        /**\n         * Show spinner.\n         */\n        show: function () {\n            spinner.show();\n        },\n\n        /**\n         * Hide spinner.\n         */\n        hide: function () {\n            spinner.hide();\n        },\n\n        /**\n         * Get spinner by selector.\n         *\n         * @param {String} id\n         * @return {jQuery}\n         */\n        get: function (id) {\n            return $(selector + '[data-component=\"' + id + '\"]');\n        }\n    };\n});\n","Magento_Ui/js/lib/collapsible.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'uiComponent'\n], function (Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            opened: false,\n            collapsible: true\n        },\n\n        /**\n         * Initializes observable properties.\n         *\n         * @returns {Collapsible} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .observe('opened');\n\n            return this;\n        },\n\n        /**\n         * Toggles value of the 'opened' property.\n         *\n         * @returns {Collapsible} Chainable.\n         */\n        toggleOpened: function () {\n            this.opened() ?\n                this.close() :\n                this.open();\n\n            return this;\n        },\n\n        /**\n         * Sets 'opened' flag to false.\n         *\n         * @returns {Collapsible} Chainable.\n         */\n        close: function () {\n            if (this.collapsible) {\n                this.opened(false);\n            }\n\n            return this;\n        },\n\n        /**\n         * Sets 'opened' flag to true.\n         *\n         * @returns {Collapsible} Chainable.\n         */\n        open: function () {\n            if (this.collapsible) {\n                this.opened(true);\n            }\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/lib/validation/utils.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine(function () {\n    'use strict';\n\n    var utils = {\n        /**\n         * Check if string is empty with trim.\n         *\n         * @param {String} value\n         * @return {Boolean}\n         */\n        isEmpty: function (value) {\n            return value === '' || value == null || value.length === 0 || /^\\s+$/.test(value);\n        },\n\n        /**\n         * Check if string is empty no trim.\n         *\n         * @param {String} value\n         * @return {Boolean}\n         */\n        isEmptyNoTrim: function (value) {\n            return value === '' || value == null || value.length === 0;\n        },\n\n        /**\n         * Checks if {value} is between numbers {from} and {to}.\n         *\n         * @param {String} value\n         * @param {String} from\n         * @param {String} to\n         * @return {Boolean}\n         */\n        isBetween: function (value, from, to) {\n            return (from === null || from === '' || value >= utils.parseNumber(from)) &&\n                   (to === null || to === '' || value <= utils.parseNumber(to));\n        },\n\n        /**\n         * Parse price string.\n         *\n         * @param {String} value\n         * @return {Number}\n         */\n        parseNumber: function (value) {\n            var isDot, isComa;\n\n            if (typeof value !== 'string') {\n                return parseFloat(value);\n            }\n            isDot = value.indexOf('.');\n            isComa = value.indexOf(',');\n\n            if (isDot !== -1 && isComa !== -1) {\n                if (isComa > isDot) {\n                    value = value.replace('.', '').replace(',', '.');\n                } else {\n                    value = value.replace(',', '');\n                }\n            } else if (isComa !== -1) {\n                value = value.replace(',', '.');\n            }\n\n            return parseFloat(value);\n        },\n\n        /**\n         * Removes HTML tags and space characters, numbers and punctuation.\n         *\n         * @param {String} value -  Value being stripped.\n         * @return {String}\n         */\n        stripHtml: function (value) {\n            return value.replace(/<.[^<>]*?>/g, ' ').replace(/&nbsp;|&#160;/gi, ' ')\n                .replace(/[0-9.(),;:!?%#$'\"_+=\\/-]*/g, '');\n        }\n    };\n\n    return utils;\n});\n","Magento_Ui/js/lib/validation/rules.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore',\n    './utils',\n    'moment',\n    'tinycolor',\n    'jquery/validate',\n    'mage/translate'\n], function ($, _, utils, moment, tinycolor) {\n    'use strict';\n\n    /**\n     * validate credit card number using mod10\n     * @param {String} s\n     * @return {Boolean}\n     */\n    function validateCreditCard(s) {\n        // remove non-numerics\n        var v = '0123456789',\n            w = '',\n            i, j, k, m, c, a, x;\n\n        for (i = 0; i < s.length; i++) {\n            x = s.charAt(i);\n\n            if (v.indexOf(x, 0) !== -1) {\n                w += x;\n            }\n        }\n        // validate number\n        j = w.length / 2;\n        k = Math.floor(j);\n        m = Math.ceil(j) - k;\n        c = 0;\n\n        for (i = 0; i < k; i++) {\n            a = w.charAt(i * 2 + m) * 2;\n            c += a > 9 ? Math.floor(a / 10 + a % 10) : a;\n        }\n\n        for (i = 0; i < k + m; i++) {\n            c += w.charAt(i * 2 + 1 - m) * 1;\n        }\n\n        return c % 10 === 0;\n    }\n\n    /**\n     * Collection of validation rules including rules from additional-methods.js\n     * @type {Object}\n     */\n    return _.mapObject({\n        'min_text_length': [\n            function (value, params) {\n                return _.isUndefined(value) || value.length === 0 || value.length >= +params;\n            },\n            $.mage.__('Please enter more or equal than {0} symbols.')\n        ],\n        'max_text_length': [\n            function (value, params) {\n                return !_.isUndefined(value) && value.length <= +params;\n            },\n            $.mage.__('Please enter less or equal than {0} symbols.')\n        ],\n        'max-words': [\n            function (value, params) {\n                return utils.isEmpty(value) || utils.stripHtml(value).match(/\\b\\w+\\b/g).length < params;\n            },\n            $.mage.__('Please enter {0} words or less.')\n        ],\n        'min-words': [\n            function (value, params) {\n                return utils.isEmpty(value) || utils.stripHtml(value).match(/\\b\\w+\\b/g).length >= params;\n            },\n            $.mage.__('Please enter at least {0} words.')\n        ],\n        'range-words': [\n            function (value, params) {\n                var match = utils.stripHtml(value).match(/\\b\\w+\\b/g) || [];\n\n                return utils.isEmpty(value) || match.length >= params[0] &&\n                    match.length <= params[1];\n            },\n            $.mage.__('Please enter between {0} and {1} words.')\n        ],\n        'letters-with-basic-punc': [\n            function (value) {\n                return utils.isEmpty(value) || /^[a-z\\-.,()\\u0027\\u0022\\s]+$/i.test(value);\n            },\n            $.mage.__('Letters or punctuation only please')\n        ],\n        'alphanumeric': [\n            function (value) {\n                return utils.isEmpty(value) || /^\\w+$/i.test(value);\n            },\n            $.mage.__('Letters, numbers, spaces or underscores only please')\n        ],\n        'letters-only': [\n            function (value) {\n                return utils.isEmpty(value) || /^[a-z]+$/i.test(value);\n            },\n            $.mage.__('Letters only please')\n        ],\n        'no-whitespace': [\n            function (value) {\n                return utils.isEmpty(value) || /^\\S+$/i.test(value);\n            },\n            $.mage.__('No white space please')\n        ],\n        'no-marginal-whitespace': [\n            function (value) {\n                return !/^\\s+|\\s+$/i.test(value);\n            },\n            $.mage.__('No marginal white space please')\n        ],\n        'zip-range': [\n            function (value) {\n                return utils.isEmpty(value) || /^90[2-5]-\\d{2}-\\d{4}$/.test(value);\n            },\n            $.mage.__('Your ZIP-code must be in the range 902xx-xxxx to 905-xx-xxxx')\n        ],\n        'integer': [\n            function (value) {\n                return utils.isEmpty(value) || /^-?\\d+$/.test(value);\n            },\n            $.mage.__('A positive or negative non-decimal number please')\n        ],\n        'vinUS': [\n            function (value) {\n                if (utils.isEmpty(value)) {\n                    return true;\n                }\n\n                if (value.length !== 17) {\n                    return false;\n                }\n                var i, n, d, f, cd, cdv,//eslint-disable-line vars-on-top\n                    LL = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'],//eslint-disable-line max-len\n                    VL = [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 7, 9, 2, 3, 4, 5, 6, 7, 8, 9],\n                    FL = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2],\n                    rs = 0;\n\n                for (i = 0; i < 17; i++) {\n                    f = FL[i];\n                    d = value.slice(i, i + 1);\n\n                    if (i === 8) {\n                        cdv = d;\n                    }\n\n                    if (!isNaN(d)) {\n                        d *= f;\n                    } else {\n                        for (n = 0; n < LL.length; n++) {//eslint-disable-line max-depth\n                            if (d.toUpperCase() === LL[n]) {//eslint-disable-line max-depth\n                                d = VL[n];\n                                d *= f;\n\n                                if (isNaN(cdv) && n === 8) {//eslint-disable-line max-depth\n                                    cdv = LL[n];\n                                }\n                                break;\n                            }\n                        }\n                    }\n                    rs += d;\n                }\n                cd = rs % 11;\n\n                if (cd === 10) {\n                    cd = 'X';\n                }\n\n                if (cd === cdv) {\n                    return true;\n                }\n\n                return false;\n            },\n            $.mage.__('The specified vehicle identification number (VIN) is invalid.')\n        ],\n        'dateITA': [\n            function (value) {\n                var check = false,\n                    re = /^\\d{1,2}\\/\\d{1,2}\\/\\d{4}$/,\n                    adata, gg, mm, aaaa, xdata;\n\n                if (re.test(value)) {\n                    adata = value.split('/');\n                    gg = parseInt(adata[0], 10);\n                    mm = parseInt(adata[1], 10);\n                    aaaa = parseInt(adata[2], 10);\n                    xdata = new Date(aaaa, mm - 1, gg);\n\n                    if (xdata.getFullYear() === aaaa &&\n                        xdata.getMonth() === mm - 1 &&\n                        xdata.getDate() === gg\n                    ) {\n                        check = true;\n                    } else {\n                        check = false;\n                    }\n                } else {\n                    check = false;\n                }\n\n                return check;\n            },\n            $.mage.__('Please enter a correct date')\n        ],\n        'dateNL': [\n            function (value) {\n                return /^\\d\\d?[\\.\\/-]\\d\\d?[\\.\\/-]\\d\\d\\d?\\d?$/.test(value);\n            },\n            $.mage.__('Vul hier een geldige datum in.')\n        ],\n        'time': [\n            function (value) {\n                return utils.isEmpty(value) || /^([01]\\d|2[0-3])(:[0-5]\\d){0,2}$/.test(value);\n            },\n            $.mage.__('Please enter a valid time, between 00:00 and 23:59')\n        ],\n        'time12h': [\n            function (value) {\n                return utils.isEmpty(value) || /^((0?[1-9]|1[012])(:[0-5]\\d){0,2}(\\s[AP]M))$/i.test(value);\n            },\n            $.mage.__('Please enter a valid time, between 00:00 am and 12:00 pm')\n        ],\n        'phoneUS': [\n            function (value) {\n                value = value.replace(/\\s+/g, '');\n\n                return utils.isEmpty(value) || value.length > 9 &&\n                    value.match(/^(1-?)?(\\([2-9]\\d{2}\\)|[2-9]\\d{2})-?[2-9]\\d{2}-?\\d{4}$/);\n            },\n            $.mage.__('Please specify a valid phone number')\n        ],\n        'phoneUK': [\n            function (value) {\n                return utils.isEmpty(value) || value.length > 9 &&\n                    value.match(/^(\\(?(0|\\+44)[1-9]{1}\\d{1,4}?\\)?\\s?\\d{3,4}\\s?\\d{3,4})$/);\n            },\n            $.mage.__('Please specify a valid phone number')\n        ],\n        'mobileUK': [\n            function (value) {\n                return utils.isEmpty(value) || value.length > 9 && value.match(/^((0|\\+44)7\\d{3}\\s?\\d{6})$/);\n            },\n            $.mage.__('Please specify a valid mobile number')\n        ],\n        'stripped-min-length': [\n            function (value, param) {\n                return _.isUndefined(value) || value.length === 0 || utils.stripHtml(value).length >= param;\n            },\n            $.mage.__('Please enter at least {0} characters')\n        ],\n        'email2': [\n            function (value) {\n                return utils.isEmpty(value) || /^((([a-z]|\\d|[!#\\$%&\\u0027\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&\\u0027\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\u0022)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\u0022)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)*(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?$/i.test(value);//eslint-disable-line max-len\n            },\n            $.validator.messages.email\n        ],\n        'url2': [\n            function (value) {\n                return utils.isEmpty(value) || /^(https?|ftp):\\/\\/(((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&\\u0027\\(\\)\\*\\+,;=]|:)*@)?(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]))|((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)*(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?)(:\\d*)?)(\\/((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&\\u0027\\(\\)\\*\\+,;=]|:|@)+(\\/(([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&\\u0027\\(\\)\\*\\+,;=]|:|@)*)*)?)?(\\?((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&\\u0027\\(\\)\\*\\+,;=]|:|@)|[\\uE000-\\uF8FF]|\\/|\\?)*)?(\\#((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&\\u0027\\(\\)\\*\\+,;=]|:|@)|\\/|\\?)*)?$/i.test(value);//eslint-disable-line max-len\n            },\n            $.validator.messages.url\n        ],\n        'credit-card-types': [\n            function (value, param) {\n                var validTypes;\n\n                if (utils.isEmpty(value)) {\n                    return true;\n                }\n\n                if (/[^0-9-]+/.test(value)) {\n                    return false;\n                }\n                value = value.replace(/\\D/g, '');\n                validTypes = 0x0000;\n\n                if (param.mastercard) {\n                    validTypes |= 0x0001;\n                }\n\n                if (param.visa) {\n                    validTypes |= 0x0002;\n                }\n\n                if (param.amex) {\n                    validTypes |= 0x0004;\n                }\n\n                if (param.dinersclub) {\n                    validTypes |= 0x0008;\n                }\n\n                if (param.enroute) {\n                    validTypes |= 0x0010;\n                }\n\n                if (param.discover) {\n                    validTypes |= 0x0020;\n                }\n\n                if (param.jcb) {\n                    validTypes |= 0x0040;\n                }\n\n                if (param.unknown) {\n                    validTypes |= 0x0080;\n                }\n\n                if (param.all) {\n                    validTypes = 0x0001 | 0x0002 | 0x0004 | 0x0008 | 0x0010 | 0x0020 | 0x0040 | 0x0080;\n                }\n\n                if (validTypes & 0x0001 && /^(51|52|53|54|55)/.test(value)) { //mastercard\n                    return value.length === 16;\n                }\n\n                if (validTypes & 0x0002 && /^(4)/.test(value)) { //visa\n                    return value.length === 16;\n                }\n\n                if (validTypes & 0x0004 && /^(34|37)/.test(value)) { //amex\n                    return value.length === 15;\n                }\n\n                if (validTypes & 0x0008 && /^(300|301|302|303|304|305|36|38)/.test(value)) { //dinersclub\n                    return value.length === 14;\n                }\n\n                if (validTypes & 0x0010 && /^(2014|2149)/.test(value)) { //enroute\n                    return value.length === 15;\n                }\n\n                if (validTypes & 0x0020 && /^(6011)/.test(value)) { //discover\n                    return value.length === 16;\n                }\n\n                if (validTypes & 0x0040 && /^(3)/.test(value)) { //jcb\n                    return value.length === 16;\n                }\n\n                if (validTypes & 0x0040 && /^(2131|1800)/.test(value)) { //jcb\n                    return value.length === 15;\n                }\n\n                if (validTypes & 0x0080) { //unknown\n                    return true;\n                }\n\n                return false;\n            },\n            $.mage.__('Please enter a valid credit card number.')\n        ],\n        'ipv4': [\n            function (value) {\n                return utils.isEmpty(value) || /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/i.test(value);//eslint-disable-line max-len\n            },\n            $.mage.__('Please enter a valid IP v4 address.')\n        ],\n        'ipv6': [\n            function (value) {\n                return utils.isEmpty(value) || /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i.test(value);//eslint-disable-line max-len\n            },\n            $.mage.__('Please enter a valid IP v6 address.')\n        ],\n        'pattern': [\n            function (value, param) {\n                return utils.isEmpty(value) || new RegExp(param).test(value);\n            },\n            $.mage.__('Invalid format.')\n        ],\n        'validate-no-html-tags': [\n            function (value) {\n                return !/<(\\/)?\\w+/.test(value);\n            },\n            $.mage.__('HTML tags are not allowed.')\n        ],\n        'validate-select': [\n            function (value) {\n                return value !== 'none' && value != null && value.length !== 0;\n            },\n            $.mage.__('Please select an option.')\n        ],\n        'validate-no-empty': [\n            function (value) {\n                return !utils.isEmpty(value);\n            },\n            $.mage.__('Empty Value.')\n        ],\n        'validate-alphanum-with-spaces': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[a-zA-Z0-9 ]+$/.test(value);\n            },\n            $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9) or spaces only in this field.')\n        ],\n        'validate-data': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[A-Za-z]+[A-Za-z0-9_]+$/.test(value);\n            },\n            $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9) or underscore (_) in this field, and the first character should be a letter.')//eslint-disable-line max-len\n        ],\n        'validate-street': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) ||\n                    /^[ \\w]{3,}([A-Za-z]\\.)?([ \\w]*\\#\\d+)?(\\r\\n| )[ \\w]{3,}/.test(value);\n            },\n            $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9), spaces and \"#\" in this field.')\n        ],\n        'validate-phoneStrict': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^(\\()?\\d{3}(\\))?(-|\\s)?\\d{3}(-|\\s)\\d{4}$/.test(value);\n            },\n            $.mage.__('Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.')\n        ],\n        'validate-phoneLax': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) ||\n                    /^((\\d[\\-. ]?)?((\\(\\d{3}\\))|\\d{3}))?[\\-. ]?\\d{3}[\\-. ]?\\d{4}$/.test(value);\n            },\n            $.mage.__('Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.')\n        ],\n        'validate-fax': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^(\\()?\\d{3}(\\))?(-|\\s)?\\d{3}(-|\\s)\\d{4}$/.test(value);\n            },\n            $.mage.__('Please enter a valid fax number (Ex: 123-456-7890).')\n        ],\n        'validate-email': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^([a-z0-9,!\\#\\$%&'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z0-9,!\\#\\$%&'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*@([a-z0-9-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z0-9-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*\\.(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]){2,})$/i.test(value);//eslint-disable-line max-len\n            },\n            $.mage.__('Please enter a valid email address (Ex: johndoe@domain.com).')\n        ],\n        'validate-emailSender': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[\\S ]+$/.test(value);\n            },\n            $.mage.__('Please enter a valid email address (Ex: johndoe@domain.com).')\n        ],\n        'validate-password': [\n            function (value) {\n                var pass;\n\n                if (value == null) {\n                    return false;\n                }\n\n                pass = value.trim();\n\n                if (!pass.length) {\n                    return true;\n                }\n\n                return !(pass.length > 0 && pass.length < 6);\n            },\n            $.mage.__('Please enter 6 or more characters. Leading and trailing spaces will be ignored.')\n        ],\n        'validate-admin-password': [\n            function (value) {\n                var pass;\n\n                if (value == null) {\n                    return false;\n                }\n\n                pass = value.trim();\n\n                if (pass.length === 0) {\n                    return true;\n                }\n\n                if (!/[a-z]/i.test(value) || !/[0-9]/.test(value)) {\n                    return false;\n                }\n\n                if (pass.length < 7) {\n                    return false;\n                }\n\n                return true;\n            },\n            $.mage.__('Please enter 7 or more characters, using both numeric and alphabetic.')\n        ],\n        'validate-customer-password': [\n            function (v, elm) {\n                var validator = this,\n                    counter = 0,\n                    passwordMinLength = $(elm).data('password-min-length'),\n                    passwordMinCharacterSets = $(elm).data('password-min-character-sets'),\n                    pass = v.trim(),\n                    result = pass.length >= passwordMinLength;\n\n                if (result === false) {\n                    validator.passwordErrorMessage = $.mage.__('Minimum length of this field must be equal or greater than %1 symbols. Leading and trailing spaces will be ignored.').replace('%1', passwordMinLength);//eslint-disable-line max-len\n\n                    return result;\n                }\n\n                if (pass.match(/\\d+/)) {\n                    counter++;\n                }\n\n                if (pass.match(/[a-z]+/)) {\n                    counter++;\n                }\n\n                if (pass.match(/[A-Z]+/)) {\n                    counter++;\n                }\n\n                if (pass.match(/[^a-zA-Z0-9]+/)) {\n                    counter++;\n                }\n\n                if (counter < passwordMinCharacterSets) {\n                    result = false;\n                    validator.passwordErrorMessage = $.mage.__('Minimum of different classes of characters in password is %1. Classes of characters: Lower Case, Upper Case, Digits, Special Characters.').replace('%1', passwordMinCharacterSets);//eslint-disable-line max-len\n                }\n\n                return result;\n            }, function () {\n                return this.passwordErrorMessage;\n            }\n        ],\n        'validate-url': [\n            function (value) {\n                if (utils.isEmptyNoTrim(value)) {\n                    return true;\n                }\n                value = (value || '').replace(/^\\s+/, '').replace(/\\s+$/, '');\n\n                return (/^(http|https|ftp):\\/\\/(([A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))(\\.[A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))*)(:(\\d+))?(\\/[A-Z0-9~](([A-Z0-9_~-]|\\.)*[A-Z0-9~]|))*\\/?(.*)?$/i).test(value);//eslint-disable-line max-len\n\n            },\n            $.mage.__('Please enter a valid URL. Protocol is required (http://, https:// or ftp://).')\n        ],\n        'validate-clean-url': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^(http|https|ftp):\\/\\/(([A-Z0-9][A-Z0-9_-]*)(\\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\\d+))?\\/?/i.test(value) || /^(www)((\\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\\d+))?\\/?/i.test(value);//eslint-disable-line max-len\n\n            },\n            $.mage.__('Please enter a valid URL. For example http://www.example.com or www.example.com.')\n        ],\n        'validate-xml-identifier': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[A-Z][A-Z0-9_\\/-]*$/i.test(value);\n\n            },\n            $.mage.__('Please enter a valid XML-identifier (Ex: something_1, block5, id-4).')\n        ],\n        'validate-ssn': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^\\d{3}-?\\d{2}-?\\d{4}$/.test(value);\n\n            },\n            $.mage.__('Please enter a valid social security number (Ex: 123-45-6789).')\n        ],\n        'validate-zip-us': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /(^\\d{5}$)|(^\\d{5}-\\d{4}$)/.test(value);\n\n            },\n            $.mage.__('Please enter a valid zip code (Ex: 90602 or 90602-1234).')\n        ],\n        'validate-date-au': [\n            function (value) {\n                var regex = /^(\\d{2})\\/(\\d{2})\\/(\\d{4})$/,\n                    d;\n\n                if (utils.isEmptyNoTrim(value)) {\n                    return true;\n                }\n\n                if (utils.isEmpty(value) || !regex.test(value)) {\n                    return false;\n                }\n                d = new Date(value.replace(regex, '$2/$1/$3'));\n\n                return parseInt(RegExp.$2, 10) === 1 + d.getMonth() &&\n                    parseInt(RegExp.$1, 10) === d.getDate() &&\n                    parseInt(RegExp.$3, 10) === d.getFullYear();\n\n            },\n            $.mage.__('Please use this date format: dd/mm/yyyy. For example 17/03/2006 for the 17th of March, 2006.')\n        ],\n        'validate-currency-dollar': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^\\$?\\-?([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}\\d*(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)$/.test(value);//eslint-disable-line max-len\n\n            },\n            $.mage.__('Please enter a valid $ amount. For example $100.00.')\n        ],\n        'validate-not-negative-number': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || !isNaN(utils.parseNumber(value))\n                    && value >= 0 && (/^\\s*-?\\d+([,.]\\d+)*\\s*%?\\s*$/).test(value);\n\n            },\n            $.mage.__('Please enter a number 0 or greater, without comma in this field.')\n        ],\n        // validate-not-negative-number should be replaced in all places with this one and then removed\n        'validate-zero-or-greater': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || !isNaN(utils.parseNumber(value))\n                    && value >= 0 && (/^\\s*-?\\d+([,.]\\d+)*\\s*%?\\s*$/).test(value);\n            },\n            $.mage.__('Please enter a number 0 or greater, without comma in this field.')\n        ],\n        'validate-greater-than-zero': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || !isNaN(utils.parseNumber(value))\n                    && value > 0 && (/^\\s*-?\\d+([,.]\\d+)*\\s*%?\\s*$/).test(value);\n            },\n            $.mage.__('Please enter a number greater than 0, without comma in this field.')\n        ],\n        'validate-css-length': [\n            function (value) {\n                if (value !== '') {\n                    return (/^[0-9]*\\.*[0-9]+(px|pc|pt|ex|em|mm|cm|in|%)?$/).test(value);\n                }\n\n                return true;\n            },\n            $.mage.__('Please input a valid CSS-length (Ex: 100px, 77pt, 20em, .5ex or 50%).')\n        ],\n        'validate-number': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) ||\n                    !isNaN(utils.parseNumber(value)) &&\n                    /^\\s*-?\\d*(?:[.,|'|\\s]\\d+)*(?:[.,|'|\\s]\\d{2})?-?\\s*$/.test(value);\n            },\n            $.mage.__('Please enter a valid number in this field.')\n        ],\n        'validate-integer': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || !isNaN(utils.parseNumber(value)) && /^\\s*-?\\d*\\s*$/.test(value);\n            },\n            $.mage.__('Please enter a valid integer in this field.')\n        ],\n        'validate-number-range': [\n            function (value, param) {\n                var numValue, dataAttrRange, result, range, m;\n\n                if (utils.isEmptyNoTrim(value)) {\n                    return true;\n                }\n\n                numValue = utils.parseNumber(value);\n\n                if (isNaN(numValue)) {\n                    return false;\n                }\n\n                dataAttrRange = /^(-?[\\d.,]+)?-(-?[\\d.,]+)?$/;\n                result = true;\n                range = param;\n\n                if (range) {\n                    m = dataAttrRange.exec(range);\n\n                    if (m) {\n                        result = result && utils.isBetween(numValue, m[1], m[2]);\n                    }\n                }\n\n                return result;\n            },\n            $.mage.__('The value is not within the specified range.')\n        ],\n        'validate-positive-percent-decimal': [\n            function (value) {\n                var numValue;\n\n                if (utils.isEmptyNoTrim(value) || !/^\\s*-?\\d*(\\.\\d*)?\\s*$/.test(value)) {\n                    return false;\n                }\n\n                numValue = utils.parseNumber(value);\n\n                if (isNaN(numValue)) {\n                    return false;\n                }\n\n                return utils.isBetween(numValue, 0.01, 100);\n            },\n            $.mage.__('Please enter a valid percentage discount value greater than 0.')\n        ],\n        'validate-digits': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || !/[^\\d]/.test(value);\n            },\n            $.mage.__('Please enter a valid number in this field.')\n        ],\n        'validate-digits-range': [\n            function (value, param) {\n                var numValue, dataAttrRange, result, range, m;\n\n                if (utils.isEmptyNoTrim(value)) {\n                    return true;\n                }\n\n                numValue = utils.parseNumber(value);\n\n                if (isNaN(numValue)) {\n                    return false;\n                }\n\n                dataAttrRange = /^(-?\\d+)?-(-?\\d+)?$/;\n                result = true;\n                range = param;\n\n                if (range) {\n                    m = dataAttrRange.exec(range);\n\n                    if (m) {\n                        result = result && utils.isBetween(numValue, m[1], m[2]);\n                    }\n                }\n\n                return result;\n            },\n            $.mage.__('The value is not within the specified range.')\n        ],\n        'validate-range': [\n            function (value) {\n                var minValue, maxValue, ranges;\n\n                if (utils.isEmptyNoTrim(value)) {\n                    return true;\n                } else if ($.validator.methods['validate-digits'] && $.validator.methods['validate-digits'](value)) {\n                    minValue = maxValue = utils.parseNumber(value);\n                } else {\n                    ranges = /^(-?\\d+)?-(-?\\d+)?$/.exec(value);\n\n                    if (ranges) {\n                        minValue = utils.parseNumber(ranges[1]);\n                        maxValue = utils.parseNumber(ranges[2]);\n\n                        if (minValue > maxValue) {//eslint-disable-line max-depth\n                            return false;\n                        }\n                    } else {\n                        return false;\n                    }\n                }\n            },\n            $.mage.__('The value is not within the specified range.')\n        ],\n        'validate-alpha': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[a-zA-Z]+$/.test(value);\n            },\n            $.mage.__('Please use letters only (a-z or A-Z) in this field.')\n        ],\n        'validate-code': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[a-z]+[a-z0-9_]+$/.test(value);\n            },\n            $.mage.__('Please use only lowercase letters (a-z), numbers (0-9) or underscore (_) in this field, and the first character should be a letter.')//eslint-disable-line max-len\n        ],\n        'validate-alphanum': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[a-zA-Z0-9]+$/.test(value);\n            },\n            $.mage.__('Please use only letters (a-z or A-Z) or numbers (0-9) in this field. No spaces or other characters are allowed.')//eslint-disable-line max-len\n        ],\n        'validate-not-number-first': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[^0-9-\\.].*$/.test(value.trim());\n            },\n            $.mage.__('First character must be letter.')\n        ],\n        'validate-date': [\n            function (value, params, additionalParams) {\n                var test = moment(value, additionalParams.dateFormat);\n\n                return utils.isEmptyNoTrim(value) || test.isValid();\n            },\n            $.mage.__('Please enter a valid date.')\n        ],\n        'validate-date-range': [\n            function (value, params) {\n                var fromDate = $('input[name*=\"' + params + '\"]').val();\n\n                return moment.utc(value).unix() >= moment.utc(fromDate).unix() || isNaN(moment.utc(value).unix());\n            },\n            $.mage.__('Make sure the To Date is later than or the same as the From Date.')\n        ],\n        'validate-identifier': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[a-z0-9][a-z0-9_\\/-]+(\\.[a-z0-9_-]+)?$/.test(value);\n            },\n            $.mage.__('Please enter a valid URL Key (Ex: \"example-page\", \"example-page.html\" or \"anotherlevel/example-page\").')//eslint-disable-line max-len\n        ],\n        'validate-trailing-hyphen': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^(?!-)(?!.*-$).+$/.test(value);\n            },\n            $.mage.__('Trailing hyphens are not allowed.')\n        ],\n        'validate-zip-international': [\n\n            /*function(v) {\n            // @TODO: Cleanup\n            return Validation.get('IsEmpty').test(v) || /(^[A-z0-9]{2,10}([\\s]{0,1}|[\\-]{0,1})[A-z0-9]{2,10}$)/.test(v);\n            }*/\n            function () {\n                return true;\n            },\n            $.mage.__('Please enter a valid zip code.')\n        ],\n        'validate-state': [\n            function (value) {\n                return value !== 0;\n            },\n            $.mage.__('Please select State/Province.')\n        ],\n        'less-than-equals-to': [\n            function (value, params) {\n                value = utils.parseNumber(value);\n\n                if (isNaN(parseFloat(params))) {\n                    params = $(params).val();\n                }\n\n                params = utils.parseNumber(params);\n\n                if (!isNaN(params) && !isNaN(value)) {\n                    this.lteToVal = params;\n\n                    return value <= params;\n                }\n\n                return true;\n            },\n            function () {\n                return $.mage.__('Please enter a value less than or equal to %s.').replace('%s', this.lteToVal);\n            }\n        ],\n        'greater-than-equals-to': [\n            function (value, params) {\n                value = utils.parseNumber(value);\n\n                if (isNaN(parseFloat(params))) {\n                    params = $(params).val();\n                }\n\n                params = utils.parseNumber(params);\n\n                if (!isNaN(params) && !isNaN(value)) {\n                    this.gteToVal = params;\n\n                    return value >= params;\n                }\n\n                return true;\n            },\n            function () {\n                return $.mage.__('Please enter a value greater than or equal to %s.').replace('%s', this.gteToVal);\n            }\n        ],\n        'validate-emails': [\n            function (value) {\n                var validRegexp, emails, i;\n\n                if (utils.isEmpty(value)) {\n                    return true;\n                }\n                validRegexp = /^[a-z0-9\\._-]{1,30}@([a-z0-9_-]{1,30}\\.){1,5}[a-z]{2,4}$/i;\n                emails = value.split(/[\\s\\n\\,]+/g);\n\n                for (i = 0; i < emails.length; i++) {\n                    if (!validRegexp.test(emails[i].strip())) {\n                        return false;\n                    }\n                }\n\n                return true;\n            },\n            $.mage.__('Please enter valid email addresses, separated by commas. For example, johndoe@domain.com, johnsmith@domain.com.')//eslint-disable-line max-len\n        ],\n        'validate-cc-number': [\n\n            /**\n             * Validate credit card number based on mod 10.\n             *\n             * @param {String} value - credit card number\n             * @return {Boolean}\n             */\n            function (value) {\n                if (value) {\n                    return validateCreditCard(value);\n                }\n\n                return true;\n            },\n            $.mage.__('Please enter a valid credit card number.')\n        ],\n        'validate-cc-ukss': [\n\n            /**\n             * Validate Switch/Solo/Maestro issue number and start date is filled.\n             *\n             * @param {String} value - input field value\n             * @return {*}\n             */\n            function (value) {\n                return value;\n            },\n            $.mage.__('Please enter issue number or start date for switch/solo card type.')\n        ],\n        'required-entry': [\n            function (value) {\n                return !utils.isEmpty(value);\n            },\n            $.mage.__('This is a required field.')\n        ],\n        'checked': [\n            function (value) {\n                return value;\n            },\n            $.mage.__('This is a required field.')\n        ],\n        'not-negative-amount': [\n            function (value) {\n                if (value.length) {\n                    return (/^\\s*\\d+([,.]\\d+)*\\s*%?\\s*$/).test(value);\n                }\n\n                return true;\n            },\n            $.mage.__('Please enter positive number in this field.')\n        ],\n        'validate-per-page-value-list': [\n            function (value) {\n                var isValid = true,\n                    values = value.split(','),\n                    i;\n\n                if (utils.isEmpty(value)) {\n                    return isValid;\n                }\n\n                for (i = 0; i < values.length; i++) {\n                    if (!/^[0-9]+$/.test(values[i])) {\n                        isValid = false;\n                    }\n                }\n\n                return isValid;\n            },\n            $.mage.__('Please enter a valid value, ex: 10,20,30')\n        ],\n        'validate-new-password': [\n            function (value) {\n                if ($.validator.methods['validate-password'] && !$.validator.methods['validate-password'](value)) {\n                    return false;\n                }\n\n                if (utils.isEmpty(value) && value !== '') {\n                    return false;\n                }\n\n                return true;\n            },\n            $.mage.__('Please enter 6 or more characters. Leading and trailing spaces will be ignored.')\n        ],\n        'validate-item-quantity': [\n            function (value, params) {\n                var validator = this,\n                    result = false,\n                    // obtain values for validation\n                    qty = utils.parseNumber(value),\n                    isMinAllowedValid = typeof params.minAllowed === 'undefined' ||\n                        qty >= utils.parseNumber(params.minAllowed),\n                    isMaxAllowedValid = typeof params.maxAllowed === 'undefined' ||\n                        qty <= utils.parseNumber(params.maxAllowed),\n                    isQtyIncrementsValid = typeof params.qtyIncrements === 'undefined' ||\n                        qty % utils.parseNumber(params.qtyIncrements) === 0;\n\n                result = qty > 0;\n\n                if (result === false) {\n                    validator.itemQtyErrorMessage = $.mage.__('Please enter a quantity greater than 0.');//eslint-disable-line max-len\n\n                    return result;\n                }\n\n                result = isMinAllowedValid;\n\n                if (result === false) {\n                    validator.itemQtyErrorMessage = $.mage.__('The fewest you may purchase is %1.').replace('%1', params.minAllowed);//eslint-disable-line max-len\n\n                    return result;\n                }\n\n                result = isMaxAllowedValid;\n\n                if (result === false) {\n                    validator.itemQtyErrorMessage = $.mage.__('The maximum you may purchase is %1.').replace('%1', params.maxAllowed);//eslint-disable-line max-len\n\n                    return result;\n                }\n\n                result = isQtyIncrementsValid;\n\n                if (result === false) {\n                    validator.itemQtyErrorMessage = $.mage.__('You can buy this product only in quantities of %1 at a time.').replace('%1', params.qtyIncrements);//eslint-disable-line max-len\n\n                    return result;\n                }\n\n                return result;\n            }, function () {\n                return this.itemQtyErrorMessage;\n            }\n        ],\n        'equalTo': [\n            function (value, param) {\n                return value === $(param).val();\n            },\n            $.validator.messages.equalTo\n        ],\n        'validate-file-type': [\n            function (name, types) {\n                var extension = name.split('.').pop().toLowerCase();\n\n                if (types && typeof types === 'string') {\n                    types = types.split(' ');\n                }\n\n                return !types || !types.length || ~types.indexOf(extension);\n            },\n            $.mage.__('We don\\'t recognize or support this file extension type.')\n        ],\n        'validate-max-size': [\n            function (size, maxSize) {\n                return maxSize === false || size < maxSize;\n            },\n            $.mage.__('File you are trying to upload exceeds maximum file size limit.')\n        ],\n        'validate-if-tag-script-exist': [\n            function (value) {\n                return !value || (/<script\\b[^>]*>([\\s\\S]*?)<\\/script>$/ig).test(value);\n            },\n            $.mage.__('Please use tag SCRIPT with SRC attribute or with proper content to include JavaScript to the document.')//eslint-disable-line max-len\n        ],\n        'date_range_min': [\n            function (value, minValue, params) {\n                return moment.utc(value, params.dateFormat).unix() >= minValue;\n            },\n            $.mage.__('The date is not within the specified range.')\n        ],\n        'date_range_max': [\n            function (value, maxValue, params) {\n                return moment.utc(value, params.dateFormat).unix() <= maxValue;\n            },\n            $.mage.__('The date is not within the specified range.')\n        ],\n        'validate-color': [\n            function (value) {\n                if (value === '') {\n                    return true;\n                }\n\n                return tinycolor(value).isValid();\n            },\n            $.mage.__('Wrong color format. Please specify color in HEX, RGBa, HSVa, HSLa or use color name.')\n        ],\n        'blacklist-url': [\n            function (value, param) {\n                return new RegExp(param).test(value);\n            },\n            $.mage.__('This link is not allowed.')\n        ],\n        'validate-dob': [\n            function (value, param, params) {\n                if (value === '') {\n                    return true;\n                }\n\n                return moment.utc(value, params.dateFormat).isSameOrBefore(moment.utc());\n            },\n            $.mage.__('The Date of Birth should not be greater than today.')\n        ],\n        'validate-no-utf8mb4-characters': [\n            function (value) {\n                var validator = this,\n                    message = $.mage.__('Please remove invalid characters: {0}.'),\n                    matches = value.match(/(?:[\\uD800-\\uDBFF][\\uDC00-\\uDFFF])/g),\n                    result = matches === null;\n\n                if (!result) {\n                    validator.charErrorMessage = message.replace('{0}', matches.join());\n                }\n\n                return result;\n            }, function () {\n                return this.charErrorMessage;\n            }\n        ]\n    }, function (data) {\n        return {\n            handler: data[0],\n            message: data[1]\n        };\n    });\n});\n","Magento_Ui/js/lib/validation/validator.js":"/*\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    './rules'\n], function (_, rulesList) {\n    'use strict';\n\n    /**\n     * Validates provided value be the specified rule.\n     *\n     * @param {String} id - Rule identifier.\n     * @param {*} value - Value to be checked.\n     * @param {*} [params]\n     * @param {*} additionalParams - additional validation params set by method caller\n     * @returns {Object}\n     */\n    function validate(id, value, params, additionalParams) {\n        var rule,\n            message,\n            valid,\n            result = {\n                rule: id,\n                passed: true,\n                message: ''\n            };\n\n        if (_.isObject(params)) {\n            message = params.message || '';\n        }\n\n        if (!rulesList[id]) {\n            return result;\n        }\n\n        rule    = rulesList[id];\n        message = message || rule.message;\n        valid   = rule.handler(value, params, additionalParams);\n\n        if (!valid) {\n            params = Array.isArray(params) ?\n                params :\n                [params];\n\n            if (typeof message === 'function') {\n                message = message.call(rule);\n            }\n\n            message = params.reduce(function (msg, param, idx) {\n                return msg.replace(new RegExp('\\\\{' + idx + '\\\\}', 'g'), param);\n            }, message);\n\n            result.passed = false;\n            result.message = message;\n        }\n\n        return result;\n    }\n\n    /**\n     * Validates provided value by a specified set of rules.\n     *\n     * @param {(String|Object)} rules - One or many validation rules.\n     * @param {*} value - Value to be checked.\n     * @param {*} additionalParams - additional validation params set by method caller\n     * @returns {Object}\n     */\n    function validator(rules, value, additionalParams) {\n        var result;\n\n        if (typeof rules === 'object') {\n            result = {\n                passed: true\n            };\n\n            _.every(rules, function (ruleParams, id) {\n                if (ruleParams.validate || ruleParams !== false || additionalParams) {\n                    result = validate(id, value, ruleParams, additionalParams);\n\n                    return result.passed;\n                }\n\n                return true;\n            });\n\n            return result;\n        }\n\n        return validate.apply(null, arguments);\n    }\n\n    /**\n     * Adds new validation rule.\n     *\n     * @param {String} id - Rule identifier.\n     * @param {Function} handler - Validation function.\n     * @param {String} message - Error message.\n     */\n    validator.addRule = function (id, handler, message) {\n        rulesList[id] = {\n            handler: handler,\n            message: message\n        };\n    };\n\n    /**\n     * Returns rule object found by provided identifier.\n     *\n     * @param {String} id - Rule identifier.\n     * @returns {Object}\n     */\n    validator.getRule = function (id) {\n        return rulesList[id];\n    };\n\n    return validator;\n});\n","Magento_Ui/js/lib/logger/levels-pool.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore'\n], function (_) {\n    'use strict';\n\n    var LEVELS,\n        CODE_MAP;\n\n    LEVELS = {\n        NONE: 0,\n        ERROR: 1,\n        WARN: 2,\n        INFO: 3,\n        DEBUG: 4,\n        ALL: 5\n    };\n\n    CODE_MAP = _.invert(LEVELS);\n\n    return {\n        /**\n         * Returns the list of available log levels.\n         *\n         * @returns {Object}\n         */\n        getLevels: function () {\n            return LEVELS;\n        },\n\n        /**\n         * Returns name of the log level that matches to the provided code.\n         *\n         * @returns {String}\n         */\n        getNameByCode: function (code) {\n            return CODE_MAP[code];\n        }\n    };\n});\n","Magento_Ui/js/lib/logger/logger-utils.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    /**\n     * Utils methods for logger\n     * @param {Logger} logger\n     */\n    function LogUtils(logger) {\n        this.logger = logger;\n\n    }\n\n    /**\n     * Method for logging asynchronous operations\n     * @param {Promise} promise\n     * @param {Object} config\n     */\n    LogUtils.prototype.asyncLog = function (promise, config) {\n        var levels,\n            messages,\n            wait;\n\n        config = config || {};\n        levels = config.levels || this.createLevels();\n        messages = config.messages || this.createMessages();\n        wait = config.wait || 5000;\n\n        this.logger[levels.requested](messages.requested, config.data);\n        setTimeout(function () {\n            promise.state() === 'pending' ?\n                this.logger[levels.failed](messages.failed, config.data) :\n                this.logger[levels.loaded](messages.loaded, config.data);\n        }.bind(this), wait);\n    };\n\n    /**\n     * Method that creates object of messages\n     * @param {String} requested - log message that showing that request for class is started\n     * @param {String} loaded - log message that show when requested class is loaded\n     * @param {String} failed - log message that show when requested class is failed\n     * @returns {Object}\n     */\n    LogUtils.prototype.createMessages = function (requested, loaded, failed) {\n        return {\n            requested: requested || '',\n            loaded: loaded || '',\n            failed: failed || ''\n        };\n    };\n\n    /**\n     * Method that creates object of log levels\n     * @param {String} requested - log message that showing that request for class is started\n     * @param {String} loaded - log message that show when requested class is loaded\n     * @param {String} failed - log message that show when requested class is failed\n     * @returns {Object}\n     */\n    LogUtils.prototype.createLevels = function (requested, loaded, failed) {\n        return {\n            requested: requested || 'info',\n            loaded: loaded || 'info',\n            failed: failed || 'warn'\n        };\n    };\n\n    return LogUtils;\n});\n","Magento_Ui/js/lib/logger/entry-factory.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    './entry'\n], function (LogEntry) {\n    'use strict';\n\n    return {\n        /**\n         * @param {String} message\n         * @param {Number} level\n         * @param {Object} [messageData]\n         * @returns {LogEntry}\n         */\n        createEntry: function (message, level, messageData) {\n            return new LogEntry(message, level, messageData);\n        }\n    };\n});\n","Magento_Ui/js/lib/logger/console-output-handler.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    './levels-pool'\n], function (logLevels) {\n    'use strict';\n\n    var levels = logLevels.getLevels();\n\n    /**\n     * @param {LogFormatter} formatter\n     */\n    function ConsoleOutputHandler(formatter) {\n        /**\n         * @protected\n         * @type {LogFormatter}\n         */\n        this.formatter_ = formatter;\n    }\n\n    /**\n     * Display data of the provided entry to the console.\n     *\n     * @param {LogEntry} entry - Entry to be displayed.\n     */\n    ConsoleOutputHandler.prototype.show = function (entry) {\n        var displayString = this.formatter_.process(entry);\n\n        switch (entry.level) {\n            case levels.ERROR:\n                console.error(displayString);\n                break;\n\n            case levels.WARN:\n                console.warn(displayString);\n                break;\n\n            case levels.INFO:\n                console.info(displayString);\n                break;\n\n            case levels.DEBUG:\n                console.log(displayString);\n                break;\n        }\n    };\n\n    /**\n     * Displays the array of entries.\n     *\n     * @param {Array<LogEntry>} entries\n     */\n    ConsoleOutputHandler.prototype.dump = function (entries) {\n        entries.forEach(this.show, this);\n    };\n\n    return ConsoleOutputHandler;\n});\n","Magento_Ui/js/lib/logger/entry.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    './levels-pool'\n], function (logLevels) {\n    'use strict';\n\n    /**\n     * @param {String} message\n     * @param {Number} level\n     * @param {Object} [data]\n     */\n    function LogEntry(message, level, data) {\n        /**\n         * @readonly\n         * @type {Number}\n         */\n        this.timestamp = Date.now();\n\n        /**\n         * @readonly\n         * @type {Number}\n         */\n        this.level = level;\n\n        /**\n         * @readonly\n         * @type {String}\n         */\n        this.levelName = logLevels.getNameByCode(level);\n\n        /**\n         * @readonly\n         * @type {Object}\n         */\n        this.data = data;\n\n        /**\n         * @readonly\n         * @type {String}\n         */\n        this.message = message;\n    }\n\n    return LogEntry;\n});\n","Magento_Ui/js/lib/logger/message-pool.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 MESSAGES = {\n        templateStartLoading:\n            'The \"${ $.template }\" template requested by  the \"${$.component}\" component started loading.',\n        templateLoadedFromServer:\n            'The \"${ $.template }\" template requested by the \"${$.component}\" component  was loaded from server.\"',\n        templateLoadedFromCache:\n            'The \"${ $.template }\" template  requested by the \"${$.component}\" component was loaded from cache.\"',\n        templateLoadingFail: 'Failed to load the \"${ $.template }\" template requested by \"${$.component}\".',\n        componentStartInitialization:\n            'Component \"${$.component}\" start initialization with instance name \"${$.componentName}\".',\n        componentStartLoading: ' Started loading the \"${$.component}\" component.',\n        componentFinishLoading: 'The \"${$.component}\" component was loaded.',\n        componentLoadingFail: 'Failed to load the \"${$.component}\" component.',\n        depsLoadingFail: 'Could not get the declared \"${$.deps}\" dependency for the \"${$.component}\" instance.',\n        depsStartRequesting: 'Requesting the \"${$.deps}\" dependency for the \"${$.component}\" instance.',\n        depsFinishRequesting: 'The \"${$.deps}\" dependency for the \"${$.component}\" instance was received.',\n        requestingComponent: 'Requesting the \"${$.component}\" component.',\n        requestingComponentIsLoaded: 'The requested \"${$.component}\" component was received.',\n        requestingComponentIsFailed: 'Could not get the requested \"${$.component}\" component.'\n    };\n\n    return {\n        /**\n         * Returns message that matches the provided code.\n         *\n         * @param {String} code - Message's identifier\n         * @returns {String}\n         */\n        getMessage: function (code) {\n            return MESSAGES[code];\n        },\n\n        /**\n         * Adds a new message to the poll.\n         *\n         * @param {String} code - Message's identifier.\n         * @param {String} message - Text of the message\n         */\n        addMessage: function (code, message) {\n            MESSAGES[code] = message;\n        },\n\n        /**\n         * Tells whether message with provide code exists in the poll.\n         *\n         * @param {String} code - Message's identifier.\n         * @returns {Boolean}\n         */\n        hasMessage: function (code) {\n            return MESSAGES.hasOwnProperty(code);\n        }\n    };\n});\n","Magento_Ui/js/lib/logger/console-logger.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    './logger',\n    './entry-factory',\n    './console-output-handler',\n    './formatter',\n    './message-pool',\n    './levels-pool',\n    'Magento_Ui/js/lib/core/storage/local',\n    'underscore',\n    './logger-utils'\n], function (Logger, entryFactory, ConsoleHandler, Formatter, messagePoll, levelsPoll, storage, _, LoggerUtils) {\n    'use strict';\n\n    var STORAGE_NAMESPACE = 'CONSOLE_LOGGER';\n\n    /**\n     * Singleton Logger's sub-class instance of which is configured to display its\n     * messages to the console. It also provides the support of predefined messages\n     * and persists its display level.\n     */\n    function ConsoleLogger() {\n        var formatter = new Formatter(),\n            consoleHandler = new ConsoleHandler(formatter),\n            savedLevel = storage.get(STORAGE_NAMESPACE),\n            utils = new LoggerUtils(this);\n\n        Logger.call(this, consoleHandler, entryFactory);\n\n        if (savedLevel) {\n            this.displayLevel_ = savedLevel;\n        }\n\n        this.utils = utils;\n        this.messages = messagePoll;\n        this.levels = levelsPoll.getLevels();\n    }\n\n    _.extend(ConsoleLogger, Logger);\n\n    ConsoleLogger.prototype = Object.create(Logger.prototype);\n    ConsoleLogger.prototype.constructor = ConsoleLogger;\n\n    /**\n     * Overrides parent method to save the provided display level.\n     *\n     * @override\n     */\n    ConsoleLogger.prototype.setDisplayLevel = function (level) {\n        Logger.prototype.setDisplayLevel.call(this, level);\n\n        storage.set(STORAGE_NAMESPACE, level);\n    };\n\n    /**\n     * Adds the support of predefined messages.\n     *\n     * @protected\n     * @override\n     */\n    ConsoleLogger.prototype.createEntry_ = function (message, level, data) {\n        var code;\n\n        if (messagePoll.hasMessage(message)) {\n            data = data || {};\n            code = message;\n            message = messagePoll.getMessage(code);\n\n            data.messageCode = code;\n        }\n\n        return Logger.prototype.createEntry_.call(this, message, level, data);\n    };\n\n    return new ConsoleLogger();\n});\n","Magento_Ui/js/lib/logger/formatter.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'moment',\n    'mage/utils/template'\n], function (moment, mageTemplate) {\n    'use strict';\n\n    /**\n     * @param {String} dateFormat\n     * @param {String} template\n     */\n    function LogFormatter(dateFormat, template) {\n        /**\n         * @protected\n         * @type {String}\n         */\n        this.dateFormat_ = 'YYYY-MM-DD hh:mm:ss';\n\n        /**\n         * @protected\n         * @type {String}\n         */\n        this.template_ = '[${ $.date }] [${ $.entry.levelName }] ${ $.message }';\n\n        if (dateFormat) {\n            this.dateFormat_ = dateFormat;\n        }\n\n        if (template) {\n            this.template_ = template;\n        }\n    }\n\n    /**\n     * @param {LogEntry} entry\n     * @returns {String}\n     */\n    LogFormatter.prototype.process = function (entry) {\n        var message = mageTemplate.template(entry.message, entry.data),\n            date = moment(entry.timestamp).format(this.dateFormat_);\n\n        return mageTemplate.template(this.template_, {\n            date: date,\n            entry: entry,\n            message: message\n        });\n    };\n\n    return LogFormatter;\n});\n","Magento_Ui/js/lib/logger/logger.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    './levels-pool'\n], function (logLevels) {\n    'use strict';\n\n    var levels = logLevels.getLevels();\n\n    /**\n     * @param {LogOutputHandler} outputHandler\n     * @param {LogEntryFactory} entryFactory\n     */\n    function Logger(outputHandler, entryFactory) {\n        /**\n         * An array of log entries.\n         *\n         * @protected\n         * @type {Array<LogEntry>}\n         */\n        this.entries_ = [];\n\n        /**\n         * Current display level.\n         *\n         * @protected\n         * @type {Number}\n         */\n        this.displayLevel_ = levels.ERROR;\n\n        /**\n         * An array of display criteria.\n         *\n         * @protected\n         * @type {Array<LogCriteria>}\n         */\n        this.displayCriteria_ = [];\n\n        /**\n         * @protected\n         * @type {LogEntryFactory}\n         */\n        this.entryFactory_ = entryFactory;\n\n        /**\n         * @protected\n         * @type {Array<LogOutputHandler>}\n         */\n        this.outputHandlers_ = [outputHandler];\n\n        this.addDisplayCriteria(this.matchesLevel_);\n    }\n\n    /**\n     * Swaps current display level with the provided one.\n     *\n     * @param {Number} level - Level's code.\n     */\n    Logger.prototype.setDisplayLevel = function (level) {\n        var levelName = logLevels.getNameByCode(level);\n\n        if (!levelName) {\n            throw new TypeError('The provided level is not defined in the levels list.');\n        }\n\n        this.displayLevel_ = level;\n    };\n\n    /**\n     * Sets up the criteria by which log entries will be filtered out from the output.\n     *\n     * @param {LogCriteria} criteria\n     */\n    Logger.prototype.addDisplayCriteria = function (criteria) {\n        this.displayCriteria_.push(criteria);\n    };\n\n    /**\n     * Removes previously defined criteria.\n     *\n     * @param {LogCriteria} criteria\n     */\n    Logger.prototype.removeDisplayCriteria = function (criteria) {\n        var index = this.displayCriteria_.indexOf(criteria);\n\n        if (~index) {\n            this.displayCriteria_.splice(index, 1);\n        }\n    };\n\n    /**\n     * @param {String} message\n     * @param {Object} [messageData]\n     * @returns {LogEntry}\n     */\n    Logger.prototype.error = function (message, messageData) {\n        return this.log_(message, levels.ERROR, messageData);\n    };\n\n    /**\n     * @param {String} message\n     * @param {Object} [messageData]\n     * @returns {LogEntry}\n     */\n    Logger.prototype.warn = function (message, messageData) {\n        return this.log_(message, levels.WARN, messageData);\n    };\n\n    /**\n     * @param {String} message\n     * @param {Object} [messageData]\n     * @returns {LogEntry}\n     */\n    Logger.prototype.info = function (message, messageData) {\n        return this.log_(message, levels.INFO, messageData);\n    };\n\n    /**\n     * @param {String} message\n     * @param {Object} [messageData]\n     * @returns {LogEntry}\n     */\n    Logger.prototype.debug = function (message, messageData) {\n        return this.log_(message, levels.DEBUG, messageData);\n    };\n\n    /**\n     * @protected\n     * @param {String} message\n     * @param {Number} level\n     * @param {Object} [messageData]\n     * @returns {LogEntry}\n     */\n    Logger.prototype.log_ = function (message, level, messageData) {\n        var entry = this.createEntry_(message, level, messageData);\n\n        this.entries_.push(entry);\n\n        if (this.matchesCriteria_(entry)) {\n            this.processOutput_(entry);\n        }\n\n        return entry;\n    };\n\n    /**\n     * @protected\n     * @param {String} message\n     * @param {Number} level\n     * @param {Object} [messageData]\n     * @returns {LogEntry}\n     */\n    Logger.prototype.createEntry_ = function (message, level, messageData) {\n        return this.entryFactory_.createEntry(message, level, messageData);\n    };\n\n    /**\n     * Returns an array of log entries that have been added to the logger.\n     *\n     * @param {LogCriteria} [criteria] - Optional filter criteria.\n     * @returns {Array<LogEntry>}\n     */\n    Logger.prototype.getEntries = function (criteria) {\n        if (criteria) {\n            return this.entries_.filter(criteria);\n        }\n\n        return this.entries_;\n    };\n\n    /**\n     * @param {LogCriteria} [criteria]\n     */\n    Logger.prototype.dump = function (criteria) {\n        var entries;\n\n        if (!criteria) {\n            criteria = this.matchesCriteria_;\n        }\n\n        entries = this.entries_.filter(criteria, this);\n\n        this.outputHandlers_.forEach(function (handler) {\n            handler.dump(entries);\n        });\n    };\n\n    /**\n     * @protected\n     * @param {LogEntry} entry\n     */\n    Logger.prototype.processOutput_ = function (entry) {\n        this.outputHandlers_.forEach(function (handler) {\n            handler.show(entry);\n        });\n    };\n\n    /**\n     * @protected\n     * @param {LogEntry} entry\n     * @returns {Boolean}\n     */\n    Logger.prototype.matchesCriteria_ = function (entry) {\n        return this.displayCriteria_.every(function (criteria) {\n            return criteria.call(this, entry);\n        }, this);\n    };\n\n    /**\n     * Checks that the level of provided entry passes the \"displayLevel_\" threshold.\n     *\n     * @protected\n     * @param {LogEntry} entry - Entry to be checked.\n     * @returns {Boolean}\n     */\n    Logger.prototype.matchesLevel_ = function (entry) {\n        return entry.level <= this.displayLevel_;\n    };\n\n    return Logger;\n});\n","Magento_Ui/js/lib/registry/registry.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore'\n], function ($, _) {\n    'use strict';\n\n    var privateData = new WeakMap();\n\n    /**\n     * Extracts private item storage associated\n     * with a provided registry instance.\n     *\n     * @param {Object} container\n     * @returns {Object}\n     */\n    function getItems(container) {\n        return privateData.get(container).items;\n    }\n\n    /**\n     * Extracts private requests array associated\n     * with a provided registry instance.\n     *\n     * @param {Object} container\n     * @returns {Array}\n     */\n    function getRequests(container) {\n        return privateData.get(container).requests;\n    }\n\n    /**\n     * Wrapper function used for convenient access to the elements.\n     * See 'async' method for examples of usage and comparison\n     * with a regular 'get' method.\n     *\n     * @param {(String|Object|Function)} name - Key of the requested element.\n     * @param {Registry} registry - Instance of a registry\n     *      where to search for the element.\n     * @param {(Function|String)} [method] - Optional callback function\n     *      or a name of the elements' method which\n     *      will be invoked when element is available in registry.\n     * @returns {*}\n     */\n    function async(name, registry, method) {\n        var args = _.toArray(arguments).slice(3);\n\n        if (_.isString(method)) {\n            registry.get(name, function (component) {\n                component[method].apply(component, args);\n            });\n        } else if (_.isFunction(method)) {\n            registry.get(name, method);\n        } else if (!args.length) {\n            return registry.get(name);\n        }\n    }\n\n    /**\n     * Checks that every property of the query object\n     * is present and equal to the corresponding\n     * property in target object.\n     * Note that non-strict comparison is used.\n     *\n     * @param {Object} query - Query object.\n     * @param {Object} target - Target object.\n     * @returns {Boolean}\n     */\n    function compare(query, target) {\n        var matches = true,\n            index,\n            keys,\n            key;\n\n        if (!_.isObject(query) || !_.isObject(target)) {\n            return false;\n        }\n\n        keys = Object.getOwnPropertyNames(query);\n        index = keys.length;\n\n        while (matches && index--) {\n            key = keys[index];\n\n            /* eslint-disable eqeqeq */\n            if (target[key] != query[key]) {\n                matches = false;\n            }\n\n            /* eslint-enable eqeqeq */\n        }\n\n        return matches;\n    }\n\n    /**\n     * Explodes incoming string into object if\n     * string is defined as a set of key = value pairs.\n     *\n     * @param {(String|*)} query - String to be processed.\n     * @returns {Object|*} Either created object or an unmodified incoming\n     *      value if conversion was not possible.\n     * @example Sample conversions.\n     *      'key = value, key2 = value2'\n     *      => {key: 'value', key2: 'value2'}\n     */\n    function explode(query) {\n        var result = {},\n            index,\n            data;\n\n        if (typeof query !== 'string' || !~query.indexOf('=')) {\n            return query;\n        }\n\n        query = query.split(',');\n        index = query.length;\n\n        while (index--) {\n            data = query[index].split('=');\n\n            result[data[0].trim()] = data[1].trim();\n        }\n\n        return result;\n    }\n\n    /**\n     * Extracts items from the provided data object\n     * which matches specified search criteria.\n     *\n     * @param {Object} data - Data object where to perform a lookup.\n     * @param {(String|Object|Function)} query - Search criteria.\n     * @param {Boolean} findAll - Flag that defines whether to\n     *      search for all applicable items or to stop on a first found entry.\n     * @returns {Array|Object|*}\n     */\n    function find(data, query, findAll) {\n        var iterator,\n            item;\n\n        query = explode(query);\n\n        if (typeof query === 'string') {\n            item = data[query];\n\n            if (findAll) {\n                return item ? [item] : [];\n            }\n\n            return item;\n        }\n\n        iterator = !_.isFunction(query) ?\n            compare.bind(null, query) :\n            query;\n\n        return findAll ?\n            _.filter(data, iterator) :\n            _.find(data, iterator);\n    }\n\n    /**\n     * @constructor\n     */\n    function Registry() {\n        var data = {\n            items: {},\n            requests: []\n        };\n\n        this._updateRequests = _.debounce(this._updateRequests.bind(this), 10);\n        privateData.set(this, data);\n    }\n\n    Registry.prototype = {\n        constructor: Registry,\n\n        /**\n         * Retrieves item from registry which matches specified search criteria.\n         *\n         * @param {(Object|String|Function|Array)} query - Search condition (see examples).\n         * @param {Function} [callback] - Callback that will be invoked when\n         *      all of the requested items are available.\n         * @returns {*}\n         *\n         * @example Requesting item by it's name.\n         *      var obj = {index: 'test', sample: true};\n         *\n         *      registry.set('first', obj);\n         *      registry.get('first') === obj;\n         *      => true\n         *\n         * @example Requesting item with a specific properties.\n         *      registry.get('sample = 1, index = test') === obj;\n         *      => true\n         *      registry.get('sample = 0, index = foo') === obj;\n         *      => false\n         *\n         * @example Declaring search criteria as an object.\n         *      registry.get({sample: true}) === obj;\n         *      => true;\n         *\n         * @example Providing custom search handler.\n         *      registry.get(function (item) { return item.sample === true; }) === obj;\n         *      => true\n         *\n         * @example Sample asynchronous request declaration.\n         *      registry.get('index = test', function (item) {});\n         *\n         * @example Requesting multiple elements.\n         *      registry.set('second', {index: 'test2'});\n         *      registry.get(['first', 'second'], function (first, second) {});\n         */\n        get: function (query, callback) {\n            if (typeof callback !== 'function') {\n                return find(getItems(this), query);\n            }\n\n            this._addRequest(query, callback);\n        },\n\n        /**\n         * Sets provided item to the registry.\n         *\n         * @param {String} id - Item's identifier.\n         * @param {*} item - Item's data.\n         * returns {Registry} Chainable.\n         */\n        set: function (id, item) {\n            getItems(this)[id] = item;\n\n            this._updateRequests();\n\n            return this;\n        },\n\n        /**\n         * Removes specified item from registry.\n         * Note that search query is not applicable.\n         *\n         * @param {String} id - Item's identifier.\n         * @returns {Registry} Chainable.\n         */\n        remove: function (id) {\n            delete getItems(this)[id];\n\n            return this;\n        },\n\n        /**\n         * Retrieves a collection of elements that match\n         * provided search criteria.\n         *\n         * @param {(Object|String|Function)} query - Search query.\n         *      See 'get' method for the syntax examples.\n         * @returns {Array} Found elements.\n         */\n        filter: function (query) {\n            return find(getItems(this), query, true);\n        },\n\n        /**\n         * Checks that at least one element in collection\n         * matches provided search criteria.\n         *\n         * @param {(Object|String|Function)} query - Search query.\n         *      See 'get' method for the syntax examples.\n         * @returns {Boolean}\n         */\n        has: function (query) {\n            return !!this.get(query);\n        },\n\n        /**\n         * Checks that registry contains a provided item.\n         *\n         * @param {*} item - Item to be checked.\n         * @returns {Boolean}\n         */\n        contains: function (item) {\n            return _.contains(getItems(this), item);\n        },\n\n        /**\n         * Extracts identifier of an item if it's present in registry.\n         *\n         * @param {*} item - Item whose identifier will be extracted.\n         * @returns {String|Undefined}\n         */\n        indexOf: function (item) {\n            return _.findKey(getItems(this), function (elem) {\n                return item === elem;\n            });\n        },\n\n        /**\n         * Same as a 'get' method except that it returns\n         * a promise object instead of invoking provided callback.\n         *\n         * @param {(String|Function|Object|Array)} query - Search query.\n         *      See 'get' method for the syntax examples.\n         * @returns {jQueryPromise}\n         */\n        promise: function (query) {\n            var defer    = $.Deferred(),\n                callback = defer.resolve.bind(defer);\n\n            this.get(query, callback);\n\n            return defer.promise();\n        },\n\n        /**\n         * Creates a wrapper function over the provided search query\n         * in order to provide somehow more convenient access to the\n         * registry's items.\n         *\n         * @param {(String|Object|Function)} query - Search criteria.\n         *      See 'get' method for the syntax examples.\n         * @returns {Function}\n         *\n         * @example Comparison with a 'get' method on retrieving items.\n         *      var module = registry.async('name');\n         *\n         *      module();\n         *      => registry.get('name');\n         *\n         * @example Asynchronous request.\n         *      module(function (component) {});\n         *      => registry.get('name', function (component) {});\n         *\n         * @example Requesting item and invoking it's method with specified parameters.\n         *      module('trigger', true);\n         *      => registry.get('name', function (component) {\n         *          component.trigger(true);\n         *      });\n         */\n        async: function (query) {\n            return async.bind(null, query, this);\n        },\n\n        /**\n         * Creates new instance of a Registry.\n         *\n         * @returns {Registry} New instance.\n         */\n        create: function () {\n            return new Registry;\n        },\n\n        /**\n         * Adds new request to the queue or resolves it immediately\n         * if all of the required items are available.\n         *\n         * @private\n         * @param {(Object|String|Function|Array)} queries - Search criteria.\n         *      See 'get' method for the syntax examples.\n         * @param {Function} callback - Callback that will be invoked when\n         *      all of the requested items are available.\n         * @returns {Registry}\n         */\n        _addRequest: function (queries, callback) {\n            var request;\n\n            if (!Array.isArray(queries)) {\n                queries = queries ? [queries] : [];\n            }\n\n            request = {\n                queries: queries.map(explode),\n                callback: callback\n            };\n\n            this._canResolve(request) ?\n                this._resolveRequest(request) :\n                getRequests(this).push(request);\n\n            return this;\n        },\n\n        /**\n         * Updates requests list resolving applicable items.\n         *\n         * @private\n         * @returns {Registry} Chainable.\n         */\n        _updateRequests: function () {\n            getRequests(this)\n                .filter(this._canResolve, this)\n                .forEach(this._resolveRequest, this);\n\n            return this;\n        },\n\n        /**\n         * Resolves provided request invoking it's callback\n         * with items specified in query parameters.\n         *\n         * @private\n         * @param {Object} request - Request object.\n         * @returns {Registry} Chainable.\n         */\n        _resolveRequest: function (request) {\n            var requests = getRequests(this),\n                items    = request.queries.map(this.get, this),\n                index    = requests.indexOf(request);\n\n            request.callback.apply(null, items);\n\n            if (~index) {\n                requests.splice(index, 1);\n            }\n\n            return this;\n        },\n\n        /**\n         * Checks if provided request can be resolved.\n         *\n         * @private\n         * @param {Object} request - Request object.\n         * @returns {Boolean}\n         */\n        _canResolve: function (request) {\n            var queries = request.queries;\n\n            return queries.every(this.has, this);\n        }\n    };\n\n    return new Registry;\n});\n","Magento_Ui/js/lib/view/utils/dom-observer.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'underscore',\n    'domReady!'\n], function ($, _) {\n    'use strict';\n\n    var counter = 1,\n        watchers,\n        globalObserver,\n        disabledNodes = [];\n\n    watchers = {\n        selectors: {},\n        nodes: {}\n    };\n\n    /**\n     * Checks if node represents an element node (nodeType === 1).\n     *\n     * @param {HTMLElement} node\n     * @returns {Boolean}\n     */\n    function isElementNode(node) {\n        return node.nodeType === 1;\n    }\n\n    /**\n     * Extracts all child descendant\n     * elements of a specified node.\n     *\n     * @param {HTMLElement} node\n     * @returns {Array}\n     */\n    function extractChildren(node) {\n        var children = node.querySelectorAll('*');\n\n        return _.toArray(children);\n    }\n\n    /**\n     * Extracts node identifier. If ID is not specified,\n     * then it will be created for the provided node.\n     *\n     * @param {HTMLElement} node\n     * @returns {Number}\n     */\n    function getNodeId(node) {\n        var id = node._observeId;\n\n        if (!id) {\n            id = node._observeId = counter++;\n        }\n\n        return id;\n    }\n\n    /**\n     * Invokes callback passing node to it.\n     *\n     * @param {HTMLElement} node\n     * @param {Object} data\n     */\n    function trigger(node, data) {\n        var id = getNodeId(node),\n            ids = data.invoked;\n\n        if (_.contains(ids, id)) {\n            return;\n        }\n\n        data.callback(node);\n        data.invoked.push(id);\n    }\n\n    /**\n     * Adds node to the observer list.\n     *\n     * @param {HTMLElement} node\n     * @returns {Object}\n     */\n    function createNodeData(node) {\n        var nodes   = watchers.nodes,\n            id      = getNodeId(node);\n\n        nodes[id] = nodes[id] || {};\n\n        return nodes[id];\n    }\n\n    /**\n     * Returns data associated with a specified node.\n     *\n     * @param {HTMLElement} node\n     * @returns {Object|Undefined}\n     */\n    function getNodeData(node) {\n        var nodeId = node._observeId;\n\n        return watchers.nodes[nodeId];\n    }\n\n    /**\n     * Removes data associated with a specified node.\n     *\n     * @param {HTMLElement} node\n     */\n    function removeNodeData(node) {\n        var nodeId = node._observeId;\n\n        delete watchers.nodes[nodeId];\n    }\n\n    /**\n     * Adds removal listener for a specified node.\n     *\n     * @param {HTMLElement} node\n     * @param {Object} data\n     */\n    function addRemovalListener(node, data) {\n        var nodeData = createNodeData(node);\n\n        (nodeData.remove = nodeData.remove || []).push(data);\n    }\n\n    /**\n     * Adds listener for the nodes which matches specified selector.\n     *\n     * @param {String} selector - CSS selector.\n     * @param {Object} data\n     */\n    function addSelectorListener(selector, data) {\n        var storage = watchers.selectors;\n\n        (storage[selector] = storage[selector] || []).push(data);\n    }\n\n    /**\n     * Calls handlers associated with an added node.\n     * Adds listeners for the node removal.\n     *\n     * @param {HTMLElement} node - Added node.\n     */\n    function processAdded(node) {\n        _.each(watchers.selectors, function (listeners, selector) {\n            listeners.forEach(function (data) {\n                if (!data.ctx.contains(node) || !$(node, data.ctx).is(selector)) {\n                    return;\n                }\n\n                if (data.type === 'add') {\n                    trigger(node, data);\n                } else if (data.type === 'remove') {\n                    addRemovalListener(node, data);\n                }\n            });\n        });\n    }\n\n    /**\n     * Calls handlers associated with a removed node.\n     *\n     * @param {HTMLElement} node - Removed node.\n     */\n    function processRemoved(node) {\n        var nodeData    = getNodeData(node),\n            listeners   = nodeData && nodeData.remove;\n\n        if (!listeners) {\n            return;\n        }\n\n        listeners.forEach(function (data) {\n            trigger(node, data);\n        });\n\n        removeNodeData(node);\n    }\n\n    /**\n     * Removes all non-element nodes from provided array\n     * and appends to it descendant elements.\n     *\n     * @param {Array} nodes\n     * @returns {Array}\n     */\n    function formNodesList(nodes) {\n        var result = [],\n            children;\n\n        nodes = _.toArray(nodes).filter(isElementNode);\n\n        nodes.forEach(function (node) {\n            result.push(node);\n\n            children = extractChildren(node);\n            result   = result.concat(children);\n        });\n\n        return result;\n    }\n\n    /**\n     * Collects all removed and added nodes from\n     * mutation records into separate arrays\n     * while removing duplicates between both types of changes.\n     *\n     * @param {Array} mutations - An array of mutation records.\n     * @returns {Object} Object with 'removed' and 'added' nodes arrays.\n     */\n    function formChangesLists(mutations) {\n        var removed = [],\n            added = [];\n\n        mutations.forEach(function (record) {\n            removed = removed.concat(_.toArray(record.removedNodes));\n            added   = added.concat(_.toArray(record.addedNodes));\n        });\n\n        removed = removed.filter(function (node) {\n            var addIndex = added.indexOf(node),\n                wasAdded = !!~addIndex;\n\n            if (wasAdded) {\n                added.splice(addIndex, 1);\n            }\n\n            return !wasAdded;\n        });\n\n        return {\n            removed: formNodesList(removed),\n            added: formNodesList(added)\n        };\n    }\n\n    /**\n     * Verify if the DOM node is a child of a defined disabled node, if so we shouldn't observe provided mutation.\n     *\n     * @param {Object} mutation - a single mutation\n     * @returns {Boolean}\n     */\n    function shouldObserveMutation(mutation) {\n        var isDisabled;\n\n        if (disabledNodes.length > 0) {\n            // Iterate through the disabled nodes and determine if this mutation is occurring inside one of them\n            isDisabled = _.find(disabledNodes, function (node) {\n                return node === mutation.target || $.contains(node, mutation.target);\n            });\n\n            // If we find a matching node we should not observe the mutation\n            return !isDisabled;\n        }\n\n        return true;\n    }\n\n    /**\n     * Should we observe these mutations? Check the first and last mutation to determine if this is a disabled mutation,\n     * we check both the first and last in case one has been removed from the DOM during the process of the mutation.\n     *\n     * @param {Array} mutations - An array of mutation records.\n     * @returns {Boolean}\n     */\n    function shouldObserveMutations(mutations) {\n        var firstMutation,\n            lastMutation;\n\n        if (mutations.length > 0) {\n            firstMutation = mutations[0];\n            lastMutation = mutations[mutations.length - 1];\n\n            return shouldObserveMutation(firstMutation) && shouldObserveMutation(lastMutation);\n        }\n\n        return true;\n    }\n\n    globalObserver = new MutationObserver(function (mutations) {\n        var changes;\n\n        if (shouldObserveMutations(mutations)) {\n            changes = formChangesLists(mutations);\n\n            changes.removed.forEach(processRemoved);\n            changes.added.forEach(processAdded);\n        }\n    });\n\n    globalObserver.observe(document.body, {\n        subtree: true,\n        childList: true\n    });\n\n    return {\n        /**\n         * Disable a node from being observed by the mutations, you may want to disable specific aspects of the\n         * application which are heavy on DOM changes. The observer running on some actions could cause significant\n         * delays and degrade the performance of that specific part of the application exponentially.\n         *\n         * @param {HTMLElement} node - a HTML node within the document\n         */\n        disableNode: function (node) {\n            disabledNodes.push(node);\n        },\n\n        /**\n         * Adds listener for the appearance of nodes that matches provided\n         * selector and which are inside of the provided context. Callback will be\n         * also invoked on elements which a currently present.\n         *\n         * @param {String} selector - CSS selector.\n         * @param {Function} callback - Function that will invoked when node appears.\n         * @param {HTMLElement} [ctx=document.body] - Context inside of which to search for the node.\n         */\n        get: function (selector, callback, ctx) {\n            var data,\n                nodes;\n\n            data = {\n                ctx: ctx || document.body,\n                type: 'add',\n                callback: callback,\n                invoked: []\n            };\n\n            nodes = $(selector, data.ctx).toArray();\n\n            nodes.forEach(function (node) {\n                trigger(node, data);\n            });\n\n            addSelectorListener(selector, data);\n        },\n\n        /**\n         * Adds listener for the nodes removal.\n         *\n         * @param {(jQueryObject|HTMLElement|Array|String)} selector\n         * @param {Function} callback - Function that will invoked when node is removed.\n         * @param {HTMLElement} [ctx=document.body] - Context inside of which to search for the node.\n         */\n        remove: function (selector, callback, ctx) {\n            var nodes = [],\n                data;\n\n            data = {\n                ctx: ctx || document.body,\n                type: 'remove',\n                callback: callback,\n                invoked: []\n            };\n\n            if (typeof selector === 'object') {\n                nodes = !_.isUndefined(selector.length) ?\n                    _.toArray(selector) :\n                    [selector];\n            } else if (_.isString(selector)) {\n                nodes = $(selector, ctx).toArray();\n\n                addSelectorListener(selector, data);\n            }\n\n            nodes.forEach(function (node) {\n                addRemovalListener(node, data);\n            });\n        },\n\n        /**\n         * Removes listeners.\n         *\n         * @param {String} selector\n         * @param {Function} [fn]\n         */\n        off: function (selector, fn) {\n            var selectors = watchers.selectors,\n                listeners = selectors[selector];\n\n            if (selector && !fn) {\n                delete selectors[selector];\n            } else if (listeners && fn) {\n                selectors[selector] = listeners.filter(function (data) {\n                    return data.callback !== fn;\n                });\n            }\n        }\n    };\n});\n","Magento_Ui/js/lib/view/utils/bindings.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], function (ko, $, _) {\n    'use strict';\n\n    /**\n     * Checks if provided  value is a dom element.\n     *\n     * @param {*} node - Value to be checked.\n     * @returns {Boolean}\n     */\n    function isDomElement(node) {\n        return typeof node === 'object' && node.tagName && node.nodeType;\n    }\n\n    /**\n     * Removes from the provided array all non-root nodes located inside\n     * of the comment element as long as the closing comment tags.\n     *\n     * @param {(Array|ArrayLike)} nodes - An array of nodes to be processed.\n     * @returns {Array}\n     */\n    function normalize(nodes) {\n        var result;\n\n        nodes   = _.toArray(nodes);\n        result  = nodes.slice();\n\n        nodes.forEach(function (node) {\n            if (node.nodeType === 8) {\n                result = !ko.virtualElements.hasBindingValue(node) ?\n                    _.without(result, node) :\n                    _.difference(result, ko.virtualElements.childNodes(node));\n            }\n        });\n\n        return result;\n    }\n\n    /**\n     * Extends binding context of each item in the collection.\n     *\n     * @param {...Object} extenders - Multiple extender objects to be applied to the context.\n     * @returns {jQueryCollection} Chainable.\n     */\n    $.fn.extendCtx = function () {\n        var nodes       = normalize(this),\n            extenders   = _.toArray(arguments);\n\n        nodes.forEach(function (node) {\n            var ctx  = ko.contextFor(node),\n                data = [ctx].concat(extenders);\n\n            _.extend.apply(_, data);\n        });\n\n        return this;\n    };\n\n    /**\n     * Evaluates bindings specified in each DOM element of collection.\n     *\n     * @param {(HTMLElement|Object)} [ctx] - Context to use for bindings evaluation.\n     *      If not specified then current context of a collections' item will be used.\n     * @returns {jQueryCollection} Chainable.\n     */\n    $.fn.applyBindings = function (ctx) {\n        var nodes = normalize(this),\n            nodeCtx;\n\n        if (isDomElement(ctx)) {\n            ctx = ko.contextFor(ctx);\n        }\n\n        nodes.forEach(function (node) {\n            nodeCtx = ctx || ko.contextFor(node);\n\n            ko.applyBindings(nodeCtx, node);\n        });\n\n        return this;\n    };\n\n    /**\n     * Adds specified bindings to each DOM element in\n     * collection and evaluates them with provided context.\n     *\n     * @param {(Object|Function)} data - Either bindings object or a function\n     *      which returns bindings data for each element in collection.\n     * @param {(HTMLElement|Object)} [ctx] - Context to use for bindings evaluation.\n     *      If not specified then current context of a collections' item will be used.\n     * @returns {jQueryCollection} Chainable.\n     */\n    $.fn.bindings = function (data, ctx) {\n        var nodes    = normalize(this),\n            bindings = data,\n            nodeCtx;\n\n        if (isDomElement(ctx)) {\n            ctx = ko.contextFor(ctx);\n        }\n\n        nodes.forEach(function (node) {\n            nodeCtx = ctx || ko.contextFor(node);\n\n            if (_.isFunction(data)) {\n                bindings = data(nodeCtx, node);\n            }\n\n            ko.applyBindingsToNode(node, bindings, nodeCtx);\n        });\n\n        return this;\n    };\n});\n","Magento_Ui/js/lib/view/utils/raf.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 processMap = new WeakMap(),\n        origRaf,\n        raf;\n\n    origRaf = window.requestAnimationFrame ||\n        window.webkitRequestAnimationFrame ||\n        window.mozRequestAnimationFrame ||\n        window.onRequestAnimationFrame ||\n        window.msRequestAnimationFrame ||\n        function (callback) {\n            if (typeof callback != 'function') {\n                throw new Error('raf argument \"callback\" must be of type function');\n            }\n            window.setTimeout(callback, 1000 / 60);\n        };\n\n    /**\n     * Creates new process object or extracts the\n     * the existing one.\n     *\n     * @param {*} id - Process identifier.\n     * @param {Number} fps - Required FPS count.\n     * @returns {Object}\n     */\n    function getProcess(id, fps) {\n        var process = processMap.get(id);\n\n        if (!process) {\n            process = {};\n            processMap.set(id, process);\n        }\n\n        if (process.fps !== fps) {\n            process.fps        = fps;\n            process.interval   = 1000 / fps;\n            process.update     = Date.now();\n        }\n\n        return process;\n    }\n\n    /**\n     * Proxy method which delegates call to the 'requestAnimationFrame'\n     * function and optionally can keep track of the FPS with which\n     * provided function is called.\n     *\n     * @param {Function} callback - Callback function to be passed to 'requestAnimationFrame'.\n     * @param {Number} [fps] - If specified, will update FPS counter for the provided function.\n     * @returns {Number|Boolean} ID of request or a flag which indicates\n     *      whether callback fits specified FPS.\n     */\n    raf = function (callback, fps) {\n        var rafId = origRaf(callback);\n\n        return fps ? raf.tick(callback, fps) : rafId;\n    };\n\n    /**\n     * Updates FPS counter for the specified process\n     * and returns a flag which indicates whether\n     * counter value is equal or greater than the required FPS.\n     *\n     * @param {*} id - Process identifier.\n     * @param {Number} fps - Required FPS count.\n     * @returns {Boolean}\n     */\n    raf.tick = function (id, fps) {\n        var process  = getProcess(id, fps),\n            now      = Date.now(),\n            delta    = now - process.update,\n            interval = process.interval;\n\n        if (fps >= 60 || delta >= interval) {\n            process.update = now - delta % interval;\n\n            return true;\n        }\n\n        return false;\n    };\n\n    return raf;\n});\n","Magento_Ui/js/lib/view/utils/async.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'ko',\n    'jquery',\n    'underscore',\n    'uiRegistry',\n    './dom-observer',\n    'Magento_Ui/js/lib/knockout/extender/bound-nodes',\n    './bindings'\n], function (ko, $, _, registry, domObserver, boundedNodes) {\n    'use strict';\n\n    /**\n     * Checks if provided value is a dom element.\n     *\n     * @param {*} node - Value to be checked.\n     * @returns {Boolean}\n     */\n    function isDomElement(node) {\n        return typeof node === 'object' && node.tagName && node.nodeType;\n    }\n\n    /**\n     * Parses provided string and extracts\n     * component, context and selector data from it.\n     *\n     * @param {String} str - String to be processed.\n     * @returns {Object} Data retrieved from string.\n     *\n     * @example Sample format.\n     *      '{{component}}:{{ctx}} -> {{selector}}'\n     *\n     *      component - Name of component.\n     *      ctx - Selector of the root node upon which component is binded.\n     *      selector - Selector of DOM elements located\n     *          inside of a previously specified context.\n     */\n    function parseSelector(str) {\n        var data    = str.trim().split('->'),\n            result  = {},\n            componentData;\n\n        if (data.length === 1) {\n            if (!~data[0].indexOf(':')) {\n                result.selector = data[0];\n            } else {\n                componentData = data[0];\n            }\n        } else {\n            componentData   = data[0];\n            result.selector = data[1];\n        }\n\n        if (componentData) {\n            componentData = componentData.split(':');\n\n            result.component = componentData[0];\n            result.ctx = componentData[1];\n        }\n\n        _.each(result, function (value, key) {\n            result[key] = value.trim();\n        });\n\n        return result;\n    }\n\n    /**\n     * Internal method used to normalize argumnets passed\n     * to 'async' module methods.\n     *\n     * @param {(String|Object)} selector\n     * @param {(HTMLElement|Object|String)} [ctx]\n     * @returns {Object}\n     */\n    function parseData(selector, ctx) {\n        var data = {};\n\n        if (arguments.length === 2) {\n            data.selector = selector;\n\n            if (isDomElement(ctx)) {\n                data.ctx = ctx;\n            } else {\n                data.component = ctx;\n                data.ctx = '*';\n            }\n        } else {\n            data = _.isString(selector) ?\n                parseSelector(selector) :\n                selector;\n        }\n\n        return data;\n    }\n\n    /**\n     * Creates promise that will be resolved\n     * when requested component is registred.\n     *\n     * @param {String} name - Name of component.\n     * @returns {jQueryPromise}\n     */\n    function waitComponent(name) {\n        var deffer = $.Deferred();\n\n        if (_.isString(name)) {\n            registry.get(name, function (component) {\n                deffer.resolve(component);\n            });\n        } else {\n            deffer.resolve(name);\n        }\n\n        return deffer.promise();\n    }\n\n    /**\n     * Creates listener for the nodes binded to provided component.\n     *\n     * @param {Object} data - Listener data.\n     * @param {Object} component - Associated with nodes component.\n     */\n    function setRootListener(data, component) {\n        boundedNodes.get(component, function (root) {\n            if (!$(root).is(data.ctx || '*')) {\n                return;\n            }\n\n            data.selector ?\n                domObserver.get(data.selector, data.fn, root) :\n                data.fn(root);\n        });\n    }\n\n    /*eslint-disable no-unused-vars*/\n    /**\n     * Sets listener for the appearance of elements which\n     * matches specified selector data.\n     *\n     * @param {(String|Object)} selector - Valid css selector or a string\n     *      in format acceptable by 'parseSelector' method or an object with\n     *      'component', 'selector' and 'ctx' properties.\n     * @param {(HTMLElement|Object|String)} [ctx] - Optional context parameter\n     *      which might be a DOM element, component instance or components' name.\n     * @param {Function} fn - Callback that will be invoked\n     *      when required DOM element appears.\n     *\n     * @example\n     *      Creating listener of the 'span' nodes appearance,\n     *      located inside of 'div' nodes, which are binded to 'cms_page_listing' component:\n     *\n     *      $.async('cms_page_listing:div -> span', function (node) {});\n     *\n     * @example Another syntaxes of the previous example.\n     *      $.async({\n     *          component: 'cms_page_listing',\n     *          ctx: 'div',\n     *          selector: 'span'\n     *       }, function (node) {});\n     *\n     * @example Listens for appearance of any child node inside of specified component.\n     *      $.async('> *', 'cms_page_lsiting', function (node) {});\n     *\n     * @example Listens for appearance of 'span' nodes inside of specific context.\n     *      $.async('span', document.getElementById('test'), function (node) {});\n     */\n    $.async = function (selector, ctx, fn) {\n        var args = _.toArray(arguments),\n            data = parseData.apply(null, _.initial(args));\n\n        data.fn = _.last(args);\n\n        if (data.component) {\n            waitComponent(data.component)\n                .then(setRootListener.bind(null, data));\n        } else {\n            domObserver.get(data.selector, data.fn, data.ctx);\n        }\n    };\n\n    /*eslint-enable no-unused-vars*/\n\n    _.extend($.async, {\n\n        /*eslint-disable no-unused-vars*/\n        /**\n         * Returns collection of elements found by provided selector data.\n         *\n         * @param {(String|Object)} selector - See 'async' definition.\n         * @param {(HTMLElement|Object|String)} [ctx] - See 'async' definition.\n         * @returns {Array} An array of DOM elements.\n         */\n        get: function (selector, ctx) {\n            var data        = parseData.apply(null, arguments),\n                component   = data.component,\n                nodes;\n\n            if (!component) {\n                return $(data.selector, data.ctx).toArray();\n            } else if (_.isString(component)) {\n                component = registry.get(component);\n            }\n\n            if (!component) {\n                return [];\n            }\n\n            nodes = boundedNodes.get(component);\n            nodes = $(nodes).filter(data.ctx).toArray();\n\n            return data.selector ?\n                $(data.selector, nodes).toArray() :\n                nodes;\n        },\n\n        /*eslint-enable no-unused-vars*/\n\n        /**\n         * Sets removal listener of the specified nodes.\n         *\n         * @param {(HTMLElement|Array|ArrayLike)} nodes - Nodes whose removal to track.\n         * @param {Function} fn - Callback that will be invoked when node is removed.\n         */\n        remove: function (nodes, fn) {\n            domObserver.remove(nodes, fn);\n        },\n\n        parseSelector: parseSelector\n    });\n\n    return $;\n});\n","Magento_Ui/js/lib/knockout/bootstrap.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/** Loads all available knockout bindings, sets custom template engine, initializes knockout on page */\n\ndefine([\n    'ko',\n    './template/engine',\n    'knockoutjs/knockout-es5',\n    './bindings/bootstrap',\n    './extender/observable_array',\n    './extender/bound-nodes',\n    'domReady!'\n], function (ko, templateEngine) {\n    'use strict';\n\n    ko.uid = 0;\n\n    ko.setTemplateEngine(templateEngine);\n    ko.applyBindings();\n});\n","Magento_Ui/js/lib/knockout/template/loader.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    var licenseRegExp   = /<!--[\\s\\S]*?-->/,\n        defaultPlugin   = 'text',\n        defaultExt      = 'html';\n\n    /**\n     * Checks of provided string contains a file extension.\n     *\n     * @param {String} str - String to be checked.\n     * @returns {Boolean}\n     */\n    function hasFileExtension(str) {\n        return !!~str.indexOf('.') && !!str.split('.').pop();\n    }\n\n    /**\n     * Checks if provided string contains a requirejs's plugin reference.\n     *\n     * @param {String} str - String to be checked.\n     * @returns {Boolean}\n     */\n    function hasPlugin(str) {\n        return !!~str.indexOf('!');\n    }\n\n    /**\n     * Checks if provided string is a full path to the file.\n     *\n     * @param {String} str - String to be checked.\n     * @returns {Boolean}\n     */\n    function isFullPath(str) {\n        return !!~str.indexOf('://');\n    }\n\n    /**\n     * Removes license comment from the provided string.\n     *\n     * @param {String} content - String to be processed.\n     * @returns {String}\n     */\n    function removeLicense(content) {\n        return content.replace(licenseRegExp, function (match) {\n            return ~match.indexOf('/**') ? '' : match;\n        });\n    }\n\n    return {\n\n        /**\n         * Attempts to extract template by provided path from\n         * a DOM element and falls back to a file loading if\n         * none of the DOM nodes was found.\n         *\n         * @param {String} path - Path to the template or a DOM selector.\n         * @returns {jQueryPromise}\n         */\n        loadTemplate: function (path) {\n            var content = this.loadFromNode(path),\n                defer;\n\n            if (content) {\n                defer = $.Deferred();\n\n                defer.resolve(content);\n\n                return defer.promise();\n            }\n\n            return this.loadFromFile(path);\n        },\n\n        /**\n         * Loads template from external file by provided\n         * path, which will be preliminary formatted.\n         *\n         * @param {String} path - Path to the template.\n         * @returns {jQueryPromise}\n         */\n        loadFromFile: function (path) {\n            var loading = $.Deferred();\n\n            path = this.formatPath(path);\n\n            require([path], function (template) {\n                template = removeLicense(template);\n                loading.resolve(template);\n            }, function (err) {\n                loading.reject(err);\n            });\n\n            return loading.promise();\n        },\n\n        /**\n         * Attempts to extract content of a node found by provided selector.\n         *\n         * @param {String} selector - Node's selector (not necessary valid).\n         * @returns {String|Boolean} If specified node doesn't exists\n         *      'false' will be returned, otherwise returns node's content.\n         */\n        loadFromNode: function (selector) {\n            var node;\n\n            try {\n                node =\n                    document.getElementById(selector) ||\n                    document.querySelector(selector);\n\n                return node ? node.innerHTML : false;\n            } catch (e) {\n                return false;\n            }\n        },\n\n        /**\n         * Adds requirejs's plugin and file extension to\n         * to the provided string if it's necessary.\n         *\n         * @param {String} path - Path to be processed.\n         * @returns {String} Formatted path.\n         */\n        formatPath: function (path) {\n            var result = path;\n\n            if (!hasPlugin(path)) {\n                result = defaultPlugin + '!' + result;\n            }\n\n            if (isFullPath(path)) {\n                return result;\n            }\n\n            if (!hasFileExtension(path)) {\n                result += '.' + defaultExt;\n            }\n\n            return result.replace(/^([^\\/]+)/g, '$1/template');\n        }\n    };\n});\n","Magento_Ui/js/lib/knockout/template/engine.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'ko',\n    'underscore',\n    './observable_source',\n    './renderer',\n    '../../logger/console-logger'\n], function ($, ko, _, Source, renderer, consoleLogger) {\n    'use strict';\n\n    var RemoteTemplateEngine,\n        NativeTemplateEngine = ko.nativeTemplateEngine,\n        sources = {};\n\n    /**\n     * Remote template engine class. Is used to be able to load remote templates via knockout template binding.\n     */\n    RemoteTemplateEngine = function () {\n        // Instance reference for closure.\n        var engine = this,\n        // Decorate the builtin Knockout \"template\" binding to track synchronous template renders.\n        origUpdate = ko.bindingHandlers.template.update;\n\n        /**\n         * Counter to track the number of currently running render tasks (both synchronous and asynchronous).\n         * @type {Number}\n         * @private\n         */\n        this._rendersOutstanding = 0;\n\n        /**\n         * Use a jQuery object as an event bus (but any event emitter with on/off/emit methods could work)\n         * @type {jQuery}\n         * @private\n         */\n        this._events = $(this);\n\n        /**\n         * Rendered templates\n         * @type {Object}\n         * @private\n         */\n        this._templatesRendered = {};\n\n        /*eslint-disable no-unused-vars*/\n        /**\n         * Decorate update method\n         *\n         * @param {HTMLElement} element\n         * @param {Function} valueAccessor\n         * @param {Object} allBindings\n         * @param {Object} viewModel\n         * @param {ko.bindingContext} bindingContext\n         * @returns {*}\n         */\n        ko.bindingHandlers.template.update = function (element, valueAccessor, allBindings, viewModel, bindingContext) {\n            /*eslint-enable no-unused-vars*/\n            var options = ko.utils.peekObservable(valueAccessor()),\n                templateName,\n                isSync,\n                updated;\n\n            if (typeof options === 'object') {\n                if (options.templateEngine && options.templateEngine !== engine) {\n                    return origUpdate.apply(this, arguments);\n                }\n\n                if (!options.name) {\n                    consoleLogger.error('Could not find template name', options);\n                }\n                templateName = options.name;\n            } else if (typeof options === 'string') {\n                templateName = options;\n            } else {\n                consoleLogger.error('Could not build a template binding', options);\n            }\n            engine._trackRender(templateName);\n            isSync = engine._hasTemplateLoaded(templateName);\n            updated = origUpdate.apply(this, arguments);\n\n            if (isSync) {\n                engine._releaseRender(templateName, 'sync');\n            }\n\n            return updated;\n        };\n    };\n\n    /**\n     * Creates unique template identifier based on template name and it's extenders (optional)\n     * @param  {String} templateName\n     * @return {String} - unique template identifier\n     */\n    function createTemplateIdentifier(templateName) {\n        return templateName;\n    }\n\n    RemoteTemplateEngine.prototype = new NativeTemplateEngine;\n    RemoteTemplateEngine.prototype.constructor = RemoteTemplateEngine;\n\n    /**\n     * When an asynchronous render task begins, increment the internal counter for tracking when renders are complete.\n     * @private\n     */\n    RemoteTemplateEngine.prototype._trackRender = function (templateName) {\n        var rendersForTemplate = this._templatesRendered[templateName] !== undefined ?\n            this._templatesRendered[templateName] : 0;\n\n        this._rendersOutstanding++;\n        this._templatesRendered[templateName] = rendersForTemplate + 1;\n        this._resolveRenderWaits();\n    };\n\n    /**\n     * When an asynchronous render task ends, decrement the internal counter for tracking when renders are complete.\n     * @private\n     */\n    RemoteTemplateEngine.prototype._releaseRender = function (templateName) {\n        var rendersForTemplate = this._templatesRendered[templateName];\n\n        this._rendersOutstanding--;\n        this._templatesRendered[templateName] = rendersForTemplate - 1;\n        this._resolveRenderWaits();\n    };\n\n    /**\n     * Check to see if renders are complete and trigger events for listeners.\n     * @private\n     */\n    RemoteTemplateEngine.prototype._resolveRenderWaits = function () {\n        if (this._rendersOutstanding === 0) {\n            this._events.triggerHandler('finishrender');\n        }\n    };\n\n    /**\n     * Get a promise for the end of the current run of renders, both sync and async.\n     * @return {jQueryPromise} - promise that resolves when render completes\n     */\n    RemoteTemplateEngine.prototype.waitForFinishRender = function () {\n        var defer = $.Deferred();\n\n        this._events.one('finishrender', defer.resolve);\n\n        return defer.promise();\n    };\n\n    /**\n     * Returns true if this template has already been asynchronously loaded and will be synchronously rendered.\n     * @param {String} templateName\n     * @returns {Boolean}\n     * @private\n     */\n    RemoteTemplateEngine.prototype._hasTemplateLoaded = function (templateName) {\n        // Sources object will have cached template once makeTemplateSource has run\n        return sources.hasOwnProperty(templateName);\n    };\n\n    /**\n     * Overrided method of native knockout template engine.\n     * Caches template after it's unique name and renders in once.\n     * If template name is not typeof string, delegates work to knockout.templateSources.anonymousTemplate.\n     * @param  {*} template\n     * @param  {HTMLElement} templateDocument - document\n     * @param  {Object} options - options, passed to template binding\n     * @param  {ko.bindingContext} bindingContext\n     * @returns {TemplateSource} Object with methods 'nodes' and 'data'.\n     */\n    RemoteTemplateEngine.prototype.makeTemplateSource = function (template, templateDocument, options, bindingContext) {\n        var engine = this,\n            source,\n            templateId;\n\n        if (typeof template === 'string') {\n            templateId = createTemplateIdentifier(template);\n            source = sources[templateId];\n\n            if (!source) {\n                source = new Source(template);\n                source.requestedBy = bindingContext.$data.name;\n                sources[templateId] = source;\n\n                consoleLogger.info('templateStartLoading', {\n                    template: templateId,\n                    component: bindingContext.$data.name\n                });\n\n                renderer.render(template).then(function (rendered) {\n                    consoleLogger.info('templateLoadedFromServer', {\n                        template: templateId,\n                        component: bindingContext.$data.name\n                    });\n                    source.nodes(rendered);\n                    engine._releaseRender(templateId, 'async');\n                }).fail(function () {\n                    consoleLogger.error('templateLoadingFail', {\n                        template: templateId,\n                        component: bindingContext.$data.name\n                    });\n                });\n            }\n\n            if (source.requestedBy !== bindingContext.$data.name) {\n                consoleLogger.info('templateLoadedFromCache', {\n                    template: templateId,\n                    component: bindingContext.$data.name\n                });\n            }\n\n            return source;\n        } else if (template.nodeType === 1 || template.nodeType === 8) {\n            source = new ko.templateSources.anonymousTemplate(template);\n\n            return source;\n        }\n\n        throw new Error('Unknown template type: ' + template);\n    };\n\n    /**\n     * Overrided method of native knockout template engine.\n     * Should return array of html elements.\n     * @param  {TemplateSource} templateSource - object with methods 'nodes' and 'data'.\n     * @return {Array} - array of html elements\n     */\n    RemoteTemplateEngine.prototype.renderTemplateSource = function (templateSource) {\n        var nodes = templateSource.nodes();\n\n        return ko.utils.cloneNodes(nodes);\n    };\n\n    /**\n     * Overrided method of native knockout template engine.\n     * Created in order to invoke makeTemplateSource method with custom set of params.\n     * @param  {*} template - template identifier\n     * @param  {ko.bindingContext} bindingContext\n     * @param  {Object} options - options, passed to template binding\n     * @param  {HTMLElement} templateDocument - document\n     * @return {Array} - array of html elements\n     */\n    RemoteTemplateEngine.prototype.renderTemplate = function (template, bindingContext, options, templateDocument) {\n        var templateSource = this.makeTemplateSource(template, templateDocument, options, bindingContext);\n\n        return this.renderTemplateSource(templateSource);\n    };\n\n    return new RemoteTemplateEngine;\n});\n","Magento_Ui/js/lib/knockout/template/renderer.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'underscore',\n    './loader'\n], function ($, _, loader) {\n    'use strict';\n\n    var colonReg       = /\\\\:/g,\n        renderedTemplatePromises = {},\n        attributes     = {},\n        elements       = {},\n        globals        = [],\n        renderer,\n        preset;\n\n    renderer = {\n\n        /**\n         * Loads template by provided path and\n         * than converts it's content to html.\n         *\n         * @param {String} tmplPath - Path to the template.\n         * @returns {jQueryPromise}\n         * @alias getRendered\n         */\n        render: function (tmplPath) {\n            var cachedPromise = renderedTemplatePromises[tmplPath];\n\n            if (!cachedPromise) {\n                cachedPromise = renderedTemplatePromises[tmplPath] = loader\n                    .loadTemplate(tmplPath)\n                    .then(renderer.parseTemplate);\n            }\n\n            return cachedPromise;\n        },\n\n        /**\n         * @ignore\n         */\n        getRendered: function (tmplPath) {\n            return renderer.render(tmplPath);\n        },\n\n        /**\n         * Parses provided string as html content\n         * and returns an array of DOM elements.\n         *\n         * @param {String} html - String to be processed.\n         * @returns {Array}\n         */\n        parseTemplate: function (html) {\n            var fragment = document.createDocumentFragment();\n\n            $(fragment).append(html);\n\n            return renderer.normalize(fragment);\n        },\n\n        /**\n         * Processes custom attributes and nodes of provided DOM element.\n         *\n         * @param {HTMLElement} content - Element to be processed.\n         * @returns {Array} An array of content's child nodes.\n         */\n        normalize: function (content) {\n            globals.forEach(function (handler) {\n                handler(content);\n            });\n\n            return _.toArray(content.childNodes);\n        },\n\n        /**\n         * Adds new global content handler.\n         *\n         * @param {Function} handler - Function which will be invoked for\n         *      an every content passed to 'normalize' method.\n         * @returns {Renderer} Chainable.\n         */\n        addGlobal: function (handler) {\n            if (!_.contains(globals, handler)) {\n                globals.push(handler);\n            }\n\n            return this;\n        },\n\n        /**\n         * Removes specified global content handler.\n         *\n         * @param {Function} handler - Handler to be removed.\n         * @returns {Renderer} Chainable.\n         */\n        removeGlobal: function (handler) {\n            var index = globals.indexOf(handler);\n\n            if (~index) {\n                globals.splice(index, 1);\n            }\n\n            return this;\n        },\n\n        /**\n         * Adds new custom attribute handler.\n         *\n         * @param {String} id - Attribute identifier.\n         * @param {(Object|Function)} [config={}]\n         * @returns {Renderer} Chainable.\n         */\n        addAttribute: function (id, config) {\n            var data = {\n                name: id,\n                binding: id,\n                handler: renderer.handlers.attribute\n            };\n\n            if (_.isFunction(config)) {\n                data.handler = config;\n            } else if (_.isObject(config)) {\n                _.extend(data, config);\n            }\n\n            data.id = id;\n            attributes[id] = data;\n\n            return this;\n        },\n\n        /**\n         * Removes specified attribute handler.\n         *\n         * @param {String} id - Attribute identifier.\n         * @returns {Renderer} Chainable.\n         */\n        removeAttribute: function (id) {\n            delete attributes[id];\n\n            return this;\n        },\n\n        /**\n         * Adds new custom node handler.\n         *\n         * @param {String} id - Node identifier.\n         * @param {(Object|Function)} [config={}]\n         * @returns {Renderer} Chainable.\n         */\n        addNode: function (id, config) {\n            var data = {\n                name: id,\n                binding: id,\n                handler: renderer.handlers.node\n            };\n\n            if (_.isFunction(config)) {\n                data.handler = config;\n            } else if (_.isObject(config)) {\n                _.extend(data, config);\n            }\n\n            data.id = id;\n            elements[id] = data;\n\n            return this;\n        },\n\n        /**\n         * Removes specified custom node handler.\n         *\n         * @param {String} id - Node identifier.\n         * @returns {Renderer} Chainable.\n         */\n        removeNode: function (id) {\n            delete elements[id];\n\n            return this;\n        },\n\n        /**\n         * Checks if provided DOM element is a custom node.\n         *\n         * @param {HTMLElement} node - Node to be checked.\n         * @returns {Boolean}\n         */\n        isCustomNode: function (node) {\n            return _.some(elements, function (elem) {\n                return elem.name.toUpperCase() === node.tagName;\n            });\n        },\n\n        /**\n         * Processes custom attributes of a content's child nodes.\n         *\n         * @param {HTMLElement} content - DOM element to be processed.\n         */\n        processAttributes: function (content) {\n            var repeat;\n\n            repeat = _.some(attributes, function (attr) {\n                var attrName = attr.name,\n                    nodes    = content.querySelectorAll('[' + attrName + ']'),\n                    handler  = attr.handler;\n\n                return _.toArray(nodes).some(function (node) {\n                    var data = node.getAttribute(attrName);\n\n                    return handler(node, data, attr) === true;\n                });\n            });\n\n            if (repeat) {\n                renderer.processAttributes(content);\n            }\n        },\n\n        /**\n         * Processes custom nodes of a provided content.\n         *\n         * @param {HTMLElement} content - DOM element to be processed.\n         */\n        processNodes: function (content) {\n            var repeat;\n\n            repeat = _.some(elements, function (element) {\n                var nodes   = content.querySelectorAll(element.name),\n                    handler = element.handler;\n\n                return _.toArray(nodes).some(function (node) {\n                    var data = node.getAttribute('args');\n\n                    return handler(node, data, element) === true;\n                });\n            });\n\n            if (repeat) {\n                renderer.processNodes(content);\n            }\n        },\n\n        /**\n         * Wraps provided string in curly braces if it's necessary.\n         *\n         * @param {String} args - String to be wrapped.\n         * @returns {String} Wrapped string.\n         */\n        wrapArgs: function (args) {\n            if (~args.indexOf('\\\\:')) {\n                args = args.replace(colonReg, ':');\n            } else if (~args.indexOf(':') && !~args.indexOf('}')) {\n                args = '{' + args + '}';\n            }\n\n            return args;\n        },\n\n        /**\n         * Wraps child nodes of provided DOM element\n         * with knockout's comment tag.\n         *\n         * @param {HTMLElement} node - Node whose children should be wrapped.\n         * @param {String} binding - Name of the binding for the opener comment tag.\n         * @param {String} data - Data associated with a binding.\n         *\n         * @example\n         *      <div id=\"example\"><span/></div>\n         *      wrapChildren(document.getElementById('example'), 'foreach', 'data');\n         *      =>\n         *      <div id=\"example\">\n         *      <!-- ko foreach: data -->\n         *          <span></span>\n         *      <!-- /ko -->\n         *      </div>\n         */\n        wrapChildren: function (node, binding, data) {\n            var tag = this.createComment(binding, data),\n                $node = $(node);\n\n            $node.prepend(tag.open);\n            $node.append(tag.close);\n        },\n\n        /**\n         * Wraps specified node with knockout's comment tag.\n         *\n         * @param {HTMLElement} node - Node to be wrapped.\n         * @param {String} binding - Name of the binding for the opener comment tag.\n         * @param {String} data - Data associated with a binding.\n         *\n         * @example\n         *      <div id=\"example\"></div>\n         *      wrapNode(document.getElementById('example'), 'foreach', 'data');\n         *      =>\n         *      <!-- ko foreach: data -->\n         *          <div id=\"example\"></div>\n         *      <!-- /ko -->\n         */\n        wrapNode: function (node, binding, data) {\n            var tag = this.createComment(binding, data),\n                $node = $(node);\n\n            $node.before(tag.open);\n            $node.after(tag.close);\n        },\n\n        /**\n         * Creates knockouts' comment tag for the provided binding.\n         *\n         * @param {String} binding - Name of the binding.\n         * @param {String} data - Data associated with a binding.\n         * @returns {Object} Object with an open and close comment elements.\n         */\n        createComment: function (binding, data) {\n            return {\n                open: document.createComment(' ko ' + binding + ': ' + data + ' '),\n                close: document.createComment(' /ko ')\n            };\n        }\n    };\n\n    renderer.handlers = {\n\n        /**\n         * Basic node handler. Replaces custom nodes\n         * with a corresponding knockout's comment tag.\n         *\n         * @param {HTMLElement} node - Node to be processed.\n         * @param {String} data\n         * @param {Object} element\n         * @returns {Boolean} True\n         *\n         * @example Sample syntaxes conversions.\n         *      <with args=\"model\">\n         *          <span/>\n         *      </with>\n         *      =>\n         *      <!-- ko with: model-->\n         *          <span/>\n         *      <!-- /ko -->\n         */\n        node: function (node, data, element) {\n            data = renderer.wrapArgs(data);\n\n            renderer.wrapNode(node, element.binding, data);\n            $(node).replaceWith(node.childNodes);\n\n            return true;\n        },\n\n        /**\n         * Base attribute handler. Replaces custom attributes with\n         * a corresponding knockouts' data binding.\n         *\n         * @param {HTMLElement} node - Node to be processed.\n         * @param {String} data - Data associated with a binding.\n         * @param {Object} attr - Attribute definition.\n         *\n         * @example Sample syntaxes conversions.\n         *      <div text=\"label\"></div>\n         *      =>\n         *      <div data-bind=\"text: label\"></div>\n         */\n        attribute: function (node, data, attr) {\n            data = renderer.wrapArgs(data);\n\n            renderer.bindings.add(node, attr.binding, data);\n            node.removeAttribute(attr.name);\n        },\n\n        /**\n         * Wraps provided node with a knockouts' comment tag.\n         *\n         * @param {HTMLElement} node - Node that will be wrapped.\n         * @param {String} data - Data associated with a binding.\n         * @param {Object} attr - Attribute definition.\n         *\n         * @example\n         *      <div outereach=\"data\" class=\"test\"></div>\n         *      =>\n         *      <!-- ko foreach: data -->\n         *          <div class=\"test\"></div>\n         *      <!-- /ko -->\n         */\n        wrapAttribute: function (node, data, attr) {\n            data = renderer.wrapArgs(data);\n\n            renderer.wrapNode(node, attr.binding, data);\n            node.removeAttribute(attr.name);\n        }\n    };\n\n    renderer.bindings = {\n\n        /**\n         * Appends binding string to the current\n         * 'data-bind' attribute of provided node.\n         *\n         * @param {HTMLElement} node - DOM element whose 'data-bind' attribute will be extended.\n         * @param {String} name - Name of a binding.\n         * @param {String} data - Data associated with the binding.\n         */\n        add: function (node, name, data) {\n            var bindings = this.get(node);\n\n            if (bindings) {\n                bindings += ', ';\n            }\n\n            bindings += name;\n\n            if (data) {\n                bindings += ': ' + data;\n            }\n\n            this.set(node, bindings);\n        },\n\n        /**\n         * Extracts value of a 'data-bind' attribute from provided node.\n         *\n         * @param {HTMLElement} node - Node whose attribute to be extracted.\n         * @returns {String}\n         */\n        get: function (node) {\n            return node.getAttribute('data-bind') || '';\n        },\n\n        /**\n         * Sets 'data-bind' attribute of the specified node\n         * to the provided value.\n         *\n         * @param {HTMLElement} node - Node whose attribute will be altered.\n         * @param {String} bindings - New value of 'data-bind' attribute.\n         */\n        set: function (node, bindings) {\n            node.setAttribute('data-bind', bindings);\n        }\n    };\n\n    renderer\n        .addGlobal(renderer.processAttributes)\n        .addGlobal(renderer.processNodes);\n\n    /**\n     * Collection of default binding conversions.\n     */\n    preset = {\n        nodes: _.object([\n            'if',\n            'text',\n            'with',\n            'scope',\n            'ifnot',\n            'foreach',\n            'component'\n        ], Array.prototype),\n        attributes: _.object([\n            'css',\n            'attr',\n            'html',\n            'with',\n            'text',\n            'click',\n            'event',\n            'submit',\n            'enable',\n            'disable',\n            'options',\n            'visible',\n            'template',\n            'hasFocus',\n            'textInput',\n            'component',\n            'uniqueName',\n            'optionsText',\n            'optionsValue',\n            'checkedValue',\n            'selectedOptions'\n        ], Array.prototype)\n    };\n\n    _.extend(preset.attributes, {\n        if: renderer.handlers.wrapAttribute,\n        ifnot: renderer.handlers.wrapAttribute,\n        innerif: {\n            binding: 'if'\n        },\n        innerifnot: {\n            binding: 'ifnot'\n        },\n        outereach: {\n            binding: 'foreach',\n            handler: renderer.handlers.wrapAttribute\n        },\n        foreach: {\n            name: 'each'\n        },\n        value: {\n            name: 'ko-value'\n        },\n        style: {\n            name: 'ko-style'\n        },\n        checked: {\n            name: 'ko-checked'\n        },\n        disabled: {\n            name: 'ko-disabled',\n            binding: 'disable'\n        },\n        focused: {\n            name: 'ko-focused',\n            binding: 'hasFocus'\n        },\n\n        /**\n         * Custom 'render' attribute handler function. Wraps child elements\n         * of a node with knockout's 'ko template:' comment tag.\n         *\n         * @param {HTMLElement} node - Element to be processed.\n         * @param {String} data - Data specified in 'render' attribute of a node.\n         */\n        render: function (node, data) {\n            data = data || 'getTemplate()';\n            data = renderer.wrapArgs(data);\n\n            renderer.wrapChildren(node, 'template', data);\n            node.removeAttribute('render');\n        }\n    });\n\n    _.extend(preset.nodes, {\n        foreach: {\n            name: 'each'\n        },\n\n        /**\n         * Custom 'render' node handler function.\n         * Replaces node with knockout's 'ko template:' comment tag.\n         *\n         * @param {HTMLElement} node - Element to be processed.\n         * @param {String} data - Data specified in 'args' attribute of a node.\n         */\n        render: function (node, data) {\n            data = data || 'getTemplate()';\n            data = renderer.wrapArgs(data);\n\n            renderer.wrapNode(node, 'template', data);\n            $(node).replaceWith(node.childNodes);\n        }\n    });\n\n    _.each(preset.attributes, function (data, id) {\n        renderer.addAttribute(id, data);\n    });\n\n    _.each(preset.nodes, function (data, id) {\n        renderer.addNode(id, data);\n    });\n\n    return renderer;\n});\n","Magento_Ui/js/lib/knockout/template/observable_source.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * Is being used by knockout template engine to store template to.\n */\ndefine([\n    'ko',\n    'uiClass'\n], function (ko, Class) {\n    'use strict';\n\n    return Class.extend({\n\n        /**\n         * Initializes templateName, _data, nodes properties.\n         *\n         * @param  {template} template - identifier of template\n         */\n        initialize: function (template) {\n            this.templateName = template;\n            this._data = {};\n            this.nodes = ko.observable([]);\n        },\n\n        /**\n         * Data setter. If only one arguments passed, returns corresponding value.\n         * Else, writes into it.\n         * @param  {String} key - key to write to or to read from\n         * @param  {*} value\n         * @return {*} - if 1 arg provided, Returns _data[key] property\n         */\n        data: function (key, value) {\n            if (arguments.length === 1) {\n                return this._data[key];\n            }\n\n            this._data[key] = value;\n        }\n    });\n});\n","Magento_Ui/js/lib/knockout/bindings/mage-init.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'underscore',\n    'mage/apply/main'\n], function (ko, _, mage) {\n    'use strict';\n\n    ko.bindingHandlers.mageInit = {\n        /**\n         * Initializes components assigned to HTML elements.\n         *\n         * @param {HTMLElement} el\n         * @param {Function} valueAccessor\n         */\n        init: function (el, valueAccessor) {\n            var data = valueAccessor();\n\n            _.each(data, function (config, component) {\n                mage.applyFor(el, config, component);\n            });\n        }\n    };\n});\n","Magento_Ui/js/lib/knockout/bindings/i18n.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'ko',\n    'module',\n    '../template/renderer',\n    'mage/translate'\n], function ($, ko, module, renderer) {\n    'use strict';\n\n    var locations = {\n            'legend': 'Caption for the fieldset element',\n            'label': 'Label for an input element.',\n            'button': 'Push button',\n            'a': 'Link label',\n            'b': 'Bold text',\n            'strong': 'Strong emphasized text',\n            'i': 'Italic text',\n            'em': 'Emphasized text',\n            'u': 'Underlined text',\n            'sup': 'Superscript text',\n            'sub': 'Subscript text',\n            'span': 'Span element',\n            'small': 'Smaller text',\n            'big': 'Bigger text',\n            'address': 'Contact information',\n            'blockquote': 'Long quotation',\n            'q': 'Short quotation',\n            'cite': 'Citation',\n            'caption': 'Table caption',\n            'abbr': 'Abbreviated phrase',\n            'acronym': 'An acronym',\n            'var': 'Variable part of a text',\n            'dfn': 'Term',\n            'strike': 'Strikethrough text',\n            'del': 'Deleted text',\n            'ins': 'Inserted text',\n            'h1': 'Heading level 1',\n            'h2': 'Heading level 2',\n            'h3': 'Heading level 3',\n            'h4': 'Heading level 4',\n            'h5': 'Heading level 5',\n            'h6': 'Heading level 6',\n            'center': 'Centered text',\n            'select': 'List options',\n            'img': 'Image',\n            'input': 'Form element'\n        },\n\n        /**\n         * Generates [data-translate] attribute's value\n         * @param {Object} translationData\n         * @param {String} location\n         */\n        composeTranslateAttr = function (translationData, location) {\n            var obj = [{\n                'shown': translationData.shown,\n                'translated': translationData.translated,\n                'original': translationData.original,\n                'location': locations[location] || 'Text'\n            }];\n\n            return JSON.stringify(obj);\n        },\n\n        /**\n         * Sets text for the element\n         * @param {Object} el\n         * @param {String} text\n         */\n        setText = function (el, text) {\n            $(el).text(text);\n        },\n\n        /**\n         * Sets [data-translate] attribute for the element\n         * @param {Object} el - The element which is binded\n         * @param {String} original - The original value of the element\n         */\n        setTranslateProp = function (el, original) {\n            var location = $(el).prop('tagName').toLowerCase(),\n                translated = $.mage.__(original),\n                translationData = {\n                    shown: translated,\n                    translated: translated,\n                    original: original\n                },\n                translateAttr = composeTranslateAttr(translationData, location);\n\n            $(el).attr('data-translate', translateAttr);\n\n            setText(el, translationData.shown);\n        },\n\n        /**\n         * Checks if node represents ko virtual node (nodeType === 8, nodeName === '#comment').\n         *\n         * @param {HTMLElement} node\n         * @returns {Boolean}\n         */\n        isVirtualElement = function (node) {\n            return node.nodeType === 8;\n        },\n\n        /**\n        * Checks if it's real DOM element\n        * in case of virtual element, returns span wrapper\n        * @param {Object} el\n        * @param {bool} isUpdate\n        * @return {Object} el\n        */\n        getRealElement = function (el, isUpdate) {\n            if (isVirtualElement(el)) {\n                if (isUpdate) {\n                    return $(el).next('span');\n                }\n\n                return $('<span></span>').insertAfter(el);\n            }\n\n            return el;\n        },\n\n        /**\n         * execute i18n binding\n         * @param {Object} element\n         * @param {Function} valueAccessor\n         * @param {bool} isUpdate\n         */\n        execute = function (element, valueAccessor, isUpdate) {\n            var original = ko.unwrap(valueAccessor() || ''),\n                el = getRealElement(element, isUpdate),\n                inlineTranslation = (module.config() || {}).inlineTranslation;\n\n            if (inlineTranslation) {\n                setTranslateProp(el, original);\n            } else {\n                setText(el, $.mage.__(original));\n            }\n        };\n\n    /**\n     * i18n binding\n     * @property {Function}  init\n     * @property {Function}  update\n     */\n    ko.bindingHandlers.i18n = {\n\n        /**\n         * init i18n binding\n         * @param {Object} element\n         * @param {Function} valueAccessor\n         */\n        init: function (element, valueAccessor) {\n            execute(element, valueAccessor);\n        },\n\n        /**\n         * update i18n binding\n         * @param {Object} element\n         * @param {Function} valueAccessor\n         */\n        update: function (element, valueAccessor) {\n            execute(element, valueAccessor, true);\n        }\n    };\n\n    ko.virtualElements.allowedBindings.i18n = true;\n\n    renderer\n        .addNode('translate', {\n            binding: 'i18n'\n        })\n        .addAttribute('translate', {\n            binding: 'i18n'\n        });\n});\n","Magento_Ui/js/lib/knockout/bindings/color-picker.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    'jquery',\n    '../template/renderer',\n    'spectrum',\n    'tinycolor'\n], function (ko, $, renderer, spectrum, tinycolor) {\n    'use strict';\n\n    /**\n     * Change color picker status to be enabled or disabled\n     *\n     * @param {HTMLElement} element - Element to apply colorpicker enable/disable status to.\n     * @param {Object} viewModel - Object, which represents view model binded to el.\n     */\n    function changeColorPickerStateBasedOnViewModel(element, viewModel) {\n        $(element).spectrum(viewModel.disabled() ? 'disable' : 'enable');\n    }\n\n    ko.bindingHandlers.colorPicker = {\n        /**\n         * Binding init callback.\n         *\n         * @param {*} element\n         * @param {Function} valueAccessor\n         * @param {Function} allBindings\n         * @param {Object} viewModel\n         */\n        init: function (element, valueAccessor, allBindings, viewModel) {\n            var config = valueAccessor(),\n\n                /** change value */\n                changeValue = function (value) {\n                    if (value == null) {\n                        value = '';\n                    }\n                    config.value(value.toString());\n                };\n\n            config.change = changeValue;\n\n            config.hide = changeValue;\n\n            /** show value */\n            config.show = function () {\n                if (!viewModel.focused()) {\n                    viewModel.focused(true);\n                }\n\n                return true;\n            };\n\n            $(element).spectrum(config);\n\n            changeColorPickerStateBasedOnViewModel(element, viewModel);\n        },\n\n        /**\n         * Reads params passed to binding, parses component declarations.\n         * Fetches for those found and attaches them to the new context.\n         *\n         * @param {HTMLElement} element - Element to apply bindings to.\n         * @param {Function} valueAccessor - Function that returns value, passed to binding.\n         * @param {Object} allBindings - Object, which represents all bindings applied to element.\n         * @param {Object} viewModel - Object, which represents view model binded to element.\n         */\n        update: function (element, valueAccessor, allBindings, viewModel) {\n            var config = valueAccessor();\n\n            /** Initialise value as empty if it is undefined when color picker input is reset **/\n            if (config.value() === undefined) {\n                config.value('');\n            }\n\n            if (tinycolor(config.value()).isValid() || config.value() === '') {\n                $(element).spectrum('set', config.value());\n\n                if (config.value() !== '') {\n                    config.value($(element).spectrum('get').toString());\n                }\n            }\n\n            changeColorPickerStateBasedOnViewModel(element, viewModel);\n        }\n    };\n\n    renderer.addAttribute('colorPicker');\n});\n","Magento_Ui/js/lib/knockout/bindings/bootstrap.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 renderer = require('../template/renderer');\n\n    renderer.addAttribute('repeat', renderer.handlers.wrapAttribute);\n\n    renderer.addAttribute('outerfasteach', {\n        binding: 'fastForEach',\n        handler: renderer.handlers.wrapAttribute\n    });\n\n    renderer\n        .addNode('repeat')\n        .addNode('fastForEach');\n\n    return {\n        resizable:      require('./resizable'),\n        i18n:           require('./i18n'),\n        scope:          require('./scope'),\n        range:          require('./range'),\n        mageInit:       require('./mage-init'),\n        keyboard:       require('./keyboard'),\n        optgroup:       require('./optgroup'),\n        afterRender:     require('./after-render'),\n        autoselect:     require('./autoselect'),\n        datepicker:     require('./datepicker'),\n        outerClick:     require('./outer_click'),\n        fadeVisible:    require('./fadeVisible'),\n        collapsible:    require('./collapsible'),\n        staticChecked:  require('./staticChecked'),\n        simpleChecked:  require('./simple-checked'),\n        bindHtml:       require('./bind-html'),\n        tooltip:        require('./tooltip'),\n        repeat:         require('knockoutjs/knockout-repeat'),\n        fastForEach:    require('knockoutjs/knockout-fast-foreach'),\n        colorPicker:    require('./color-picker')\n    };\n});\n","Magento_Ui/js/lib/knockout/bindings/fadeVisible.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'ko'\n], function ($, ko) {\n    'use strict';\n\n    ko.bindingHandlers.fadeVisible = {\n        /**\n         * Initially set the element to be instantly visible/hidden depending on the value.\n         *\n         * @param {HTMLElement} element\n         * @param {Function} valueAccessor\n         */\n        init: function (element, valueAccessor) {\n            var value = valueAccessor();\n\n            // Use \"unwrapObservable\" so we can handle values that may or may not be observable\n            $(element).toggle(ko.unwrap(value));\n        },\n\n        /**\n         * Whenever the value subsequently changes, slowly fade the element in or out.\n         *\n         * @param {HTMLElement} element\n         * @param {Function} valueAccessor\n         */\n        update: function (element, valueAccessor) {\n            var value = valueAccessor();\n\n            ko.unwrap(value) ? $(element).fadeIn() : $(element).fadeOut();\n        }\n    };\n});\n","Magento_Ui/js/lib/knockout/bindings/optgroup.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'mageUtils'\n    ], function (ko, utils) {\n    'use strict';\n\n    var captionPlaceholder = {},\n        optgroupTmpl = '<optgroup label=\"${ $.label }\"></optgroup>',\n        nbspRe = /&nbsp;/g,\n        optionsText,\n        optionsValue,\n        optionTitle;\n\n    ko.bindingHandlers.optgroup = {\n        /**\n         * @param {*} element\n         */\n        init: function (element) {\n            if (ko.utils.tagNameLower(element) !== 'select') {\n                throw new Error('options binding applies only to SELECT elements');\n            }\n\n            // Remove all existing <option>s.\n            while (element.length > 0) {\n                element.remove(0);\n            }\n        },\n\n        /**\n         * @param {*} element\n         * @param {*} valueAccessor\n         * @param {*} allBindings\n         */\n        update: function (element, valueAccessor, allBindings) {\n            var selectWasPreviouslyEmpty = element.length === 0,\n                previousScrollTop = !selectWasPreviouslyEmpty && element.multiple ? element.scrollTop : null,\n                includeDestroyed = allBindings.get('optionsIncludeDestroyed'),\n                arrayToDomNodeChildrenOptions = {},\n                captionValue,\n                unwrappedArray = ko.utils.unwrapObservable(valueAccessor()),\n                filteredArray,\n                previousSelectedValues,\n                itemUpdate = false,\n                callback = setSelectionCallback,//eslint-disable-line no-use-before-define\n                nestedOptionsLevel = -1;\n\n            optionsText = ko.utils.unwrapObservable(allBindings.get('optionsText')) || 'text';\n            optionsValue = ko.utils.unwrapObservable(allBindings.get('optionsValue')) || 'value';\n            optionTitle = optionsText + 'title';\n\n            if (element.multiple) {\n                previousSelectedValues = ko.utils.arrayMap(\n                    selectedOptions(),//eslint-disable-line no-use-before-define\n                    ko.selectExtensions.readValue\n                );\n            } else {\n                previousSelectedValues = element.selectedIndex >= 0 ?\n                    [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\n                // Filter out any entries marked as destroyed\n                filteredArray = ko.utils.arrayFilter(unwrappedArray, function (item) {\n                    if (item && !item.label) {\n                        return false;\n                    }\n\n                    return includeDestroyed ||\n                        item === undefined ||\n                        item === null ||\n                        !ko.utils.unwrapObservable(item._destroy);\n                });\n                filteredArray.map(recursivePathBuilder, null);//eslint-disable-line no-use-before-define\n            }\n\n            /**\n             * @param {*} option\n             */\n            arrayToDomNodeChildrenOptions.beforeRemove = function (option) {\n                element.removeChild(option);\n            };\n\n            if (allBindings.has('optionsAfterRender')) {\n\n                /**\n                 * @param {*} arrayEntry\n                 * @param {*} newOptions\n                 */\n                callback = function (arrayEntry, newOptions) {\n                    setSelectionCallback(arrayEntry, newOptions);//eslint-disable-line no-use-before-define\n                    ko.dependencyDetection.ignore(\n                        allBindings.get('optionsAfterRender'),\n                        null,\n                        [newOptions[0],\n                        arrayEntry !== captionPlaceholder ? arrayEntry : undefined]\n                    );\n                };\n            }\n\n            filteredArray = formatOptions(filteredArray);//eslint-disable-line no-use-before-define\n            ko.utils.setDomNodeChildrenFromArrayMapping(\n                element,\n                filteredArray,\n                optionNodeFromArray,//eslint-disable-line no-use-before-define\n                arrayToDomNodeChildrenOptions,\n                callback\n            );\n\n            ko.dependencyDetection.ignore(function () {\n                var selectionChanged;\n\n                if (allBindings.get('valueAllowUnset') && allBindings.has('value')) {\n                    // The model value is authoritative, so make sure its value is the one selected\n                    ko.selectExtensions.writeValue(\n                        element,\n                        ko.utils.unwrapObservable(allBindings.get('value')),\n                        true /* allowUnset */\n                    );\n                } else {\n                    // Determine if the selection has changed as a result of updating the options list\n                    if (element.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 &&\n                            selectedOptions().length < //eslint-disable-line no-use-before-define\n                            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,\n                        // just look for a change in selection\n                        selectionChanged = previousSelectedValues.length && element.selectedIndex >= 0 ?\n                            ko.selectExtensions.readValue(element.options[element.selectedIndex]) !==\n                            previousSelectedValues[0] : 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.utils.triggerEvent(element, 'change');\n                    }\n                }\n            });\n\n            /*eslint-enable max-len, no-use-before-define*/\n\n            if (previousScrollTop && Math.abs(previousScrollTop - element.scrollTop) > 20) {\n                element.scrollTop = previousScrollTop;\n            }\n\n            /**\n             * @returns {*}\n             */\n            function selectedOptions() {\n                return ko.utils.arrayFilter(element.options, function (node) {\n                    return node.selected;\n                });\n            }\n\n            /**\n             * @param {*} object\n             * @param {*} predicate\n             * @param {*} defaultValue\n             * @returns {*}\n             */\n            function applyToObject(object, predicate, defaultValue) {\n                var predicateType = typeof predicate;\n\n                if (predicateType === 'function') {   // run it against the data value\n                    return predicate(object);\n                } else if (predicateType === 'string') { // treat it as a property name on the data value\n                    return object[predicate];\n                }\n\n                return defaultValue;\n            }\n\n            /**\n             * @param {*} obj\n             */\n            function recursivePathBuilder(obj) {\n\n                obj[optionTitle] = (this && this[optionTitle] ? this[optionTitle] + '/' : '') + obj[optionsText].trim();\n\n                if (Array.isArray(obj[optionsValue])) {\n                    obj[optionsValue].map(recursivePathBuilder, obj);\n                }\n            }\n\n            /**\n             * @param {Array} arrayEntry\n             * @param {*} oldOptions\n             * @returns {*[]}\n             */\n            function optionNodeFromArray(arrayEntry, oldOptions) {\n                var option;\n\n                if (oldOptions.length) {\n                    previousSelectedValues = oldOptions[0].selected ?\n                        [ko.selectExtensions.readValue(oldOptions[0])] : [];\n                    itemUpdate = true;\n                }\n\n                if (arrayEntry === captionPlaceholder) { // empty value, label === caption\n                    option = element.ownerDocument.createElement('option');\n                    ko.utils.setTextContent(option, allBindings.get('optionsCaption'));\n                    ko.selectExtensions.writeValue(option, undefined);\n                } else if (typeof arrayEntry[optionsValue] === 'undefined') { // empty value === optgroup\n                    if (arrayEntry.__disableTmpl) {\n                        option = '<optgroup label=\"' + arrayEntry[optionsText] + '\"></optgroup>';\n                    } else {\n                        option = utils.template(optgroupTmpl, {\n                            label: arrayEntry[optionsText],\n                            title: arrayEntry[optionsText + 'title']\n                        });\n                    }\n                    option = ko.utils.parseHtmlFragment(option)[0];\n\n                } else {\n                    option = element.ownerDocument.createElement('option');\n                    option.setAttribute('data-title', arrayEntry[optionsText + 'title']);\n                    ko.selectExtensions.writeValue(option, arrayEntry[optionsValue]);\n                    ko.utils.setTextContent(option, arrayEntry[optionsText]);\n                }\n\n                return [option];\n            }\n\n            /**\n             * @param {*} newOptions\n             */\n            function setSelectionCallback(newOptions) {\n                var isSelected;\n\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                if (previousSelectedValues.length && newOptions.value) {\n                    isSelected = ko.utils.arrayIndexOf(\n                        previousSelectedValues,\n                        ko.selectExtensions.readValue(newOptions.value)\n                    ) >= 0;\n\n                    ko.utils.setOptionNodeSelectionState(newOptions.value, 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            /**\n             * @param {*} string\n             * @param {Number} times\n             * @returns {Array}\n             */\n            function strPad(string, times) {\n                return new Array(times + 1).join(string);\n            }\n\n            /**\n             * @param {*} options\n             * @returns {Array}\n             */\n            function formatOptions(options) {\n                var res = [];\n\n                nestedOptionsLevel++;\n\n                if (!nestedOptionsLevel) { // zero level\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 (//eslint-disable-line max-depth\n                            captionValue !== null &&\n                            captionValue !== undefined &&\n                            captionValue !== false\n                        ) {\n                            res.push(captionPlaceholder);\n                        }\n                    }\n                }\n\n                ko.utils.arrayForEach(options, function (option) {\n                    var value = applyToObject(option, optionsValue, option),\n                        label = applyToObject(option, optionsText, value) || '',\n                        disabled = applyToObject(option, 'disabled', false) || false,\n                        obj = {},\n                        space = '\\u2007\\u2007\\u2007';\n\n                    obj[optionTitle] = applyToObject(option, optionsText + 'title', value);\n\n                    if (disabled) {\n                        obj.disabled = disabled;\n                    }\n\n                    if (option.hasOwnProperty('__disableTmpl')) {\n                        obj.__disableTmpl = option.__disableTmpl;\n                    }\n\n                    label = label.replace(nbspRe, '').trim();\n\n                    if (Array.isArray(value)) {\n                        obj[optionsText] = strPad('&nbsp;', nestedOptionsLevel * 4) + label;\n                        res.push(obj);\n                        res = res.concat(formatOptions(value));\n                    } else {\n                        obj[optionsText] = strPad(space, nestedOptionsLevel * 2) + label;\n                        obj[optionsValue] = value;\n                        res.push(obj);\n                    }\n                });\n                nestedOptionsLevel--;\n\n                return res;\n            }\n        }\n    };\n});\n","Magento_Ui/js/lib/knockout/bindings/collapsible.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    '../template/renderer'\n], function (ko, $, _, renderer) {\n    'use strict';\n\n    var collapsible,\n        defaults;\n\n    defaults = {\n        closeOnOuter: true,\n        onTarget: false,\n        openClass: '_active',\n        as: '$collapsible'\n    };\n\n    collapsible = {\n\n        /**\n         * Sets 'opened' property to true.\n         */\n        open: function () {\n            this.opened(true);\n        },\n\n        /**\n         * Sets 'opened' property to false.\n         */\n        close: function () {\n            this.opened(false);\n        },\n\n        /**\n         * Toggles value of the 'opened' property.\n         */\n        toggle: function () {\n            this.opened(!this.opened());\n        }\n    };\n\n    /**\n     * Document click handler which in case if event target is not\n     * a descendant of provided container element, closes collapsible model.\n     *\n     * @param {HTMLElement} container\n     * @param {Object} model\n     * @param {EventObject} e\n     */\n    function onOuterClick(container, model, e) {\n        var target = e.target;\n\n        if (target !== container && !container.contains(target)) {\n            model.close();\n        }\n    }\n\n    /**\n     * Creates 'css' binding which toggles\n     * class specified in 'name' parameter.\n     *\n     * @param {Object} model\n     * @param {String} name\n     * @returns {Object}\n     */\n    function getClassBinding(model, name) {\n        var binding = {};\n\n        binding[name] = model.opened;\n\n        return {\n            css: binding\n        };\n    }\n\n    /**\n     * Prepares configuration for the binding based\n     * on a default properties and provided options.\n     *\n     * @param {Object} [options={}]\n     * @returns {Object} Complete instance configuration.\n     */\n    function buildConfig(options) {\n        if (typeof options !== 'object') {\n            options = {};\n        }\n\n        return _.extend({}, defaults, options);\n    }\n\n    ko.bindingHandlers.collapsible = {\n\n        /**\n         * Initializes 'collapsible' binding.\n         */\n        init: function (element, valueAccessor, allBindings, viewModel, bindingCtx) {\n            var $collapsible = Object.create(collapsible),\n                config = buildConfig(valueAccessor()),\n                outerClick,\n                bindings;\n\n            _.bindAll($collapsible, 'open', 'close', 'toggle');\n\n            $collapsible.opened = ko.observable(!!config.opened);\n\n            bindingCtx[config.as] = $collapsible;\n\n            if (config.closeOnOuter) {\n                outerClick = onOuterClick.bind(null, element, $collapsible);\n\n                $(document).on('click', outerClick);\n\n                ko.utils.domNodeDisposal.addDisposeCallback(element, function () {\n                    $(document).off('click', outerClick);\n                });\n            }\n\n            if (config.openClass) {\n                bindings = getClassBinding($collapsible, config.openClass);\n\n                ko.applyBindingsToNode(element, bindings, bindingCtx);\n            }\n\n            if (config.onTarget) {\n                $(element).on('click', $collapsible.toggle);\n            }\n\n            if (viewModel && _.isFunction(viewModel.on)) {\n                viewModel.on({\n                    close:          $collapsible.close,\n                    open:           $collapsible.open,\n                    toggleOpened:   $collapsible.toggle\n                });\n            }\n        }\n    };\n\n    ko.bindingHandlers.closeCollapsible = {\n\n        /**\n         * Creates listener for the click event on provided DOM element,\n         * which closes associated with it collapsible model.\n         */\n        init: function (element, valueAccessor, allBindings, viewModel, bindingCtx) {\n            var name = valueAccessor() || defaults.as,\n                $collapsible = bindingCtx[name];\n\n            if ($collapsible) {\n                $(element).on('click', $collapsible.close);\n            }\n        }\n    };\n\n    ko.bindingHandlers.openCollapsible = {\n\n        /**\n         * Creates listener for the click event on provided DOM element,\n         * which opens associated with it collapsible model.\n         */\n        init: function (element, valueAccessor, allBindings, viewModel, bindingCtx) {\n            var name = valueAccessor() || defaults.as,\n                $collapsible = bindingCtx[name];\n\n            if ($collapsible) {\n                $(element).on('click', $collapsible.open);\n            }\n        }\n    };\n\n    ko.bindingHandlers.toggleCollapsible = {\n\n        /**\n         * Creates listener for the click event on provided DOM element,\n         * which toggles associated with it collapsible model.\n         */\n        init: function (element, valueAccessor, allBindings, viewModel, bindingCtx) {\n            var name = valueAccessor() || defaults.as,\n                $collapsible = bindingCtx[name];\n\n            if ($collapsible) {\n                $(element).on('click', $collapsible.toggle);\n            }\n        }\n    };\n\n    renderer\n        .addAttribute('collapsible')\n        .addAttribute('openCollapsible')\n        .addAttribute('closeCollapsible')\n        .addAttribute('toggleCollapsible');\n});\n","Magento_Ui/js/lib/knockout/bindings/scope.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/** Creates scope binding and registers in to ko.bindingHandlers object */\ndefine([\n    'ko',\n    'uiRegistry',\n    'mage/translate',\n    '../template/renderer',\n    'jquery',\n    '../../logger/console-logger'\n], function (ko, registry, $t, renderer, $, consoleLogger) {\n    'use strict';\n\n    /**\n     * Creates child context with passed component param as $data. Extends context with $t helper.\n     * Applies bindings to descendant nodes.\n     * @param {HTMLElement} el - element to apply bindings to.\n     * @param {ko.bindingContext} bindingContext - instance of ko.bindingContext, passed to binding initially.\n     * @param {Promise} promise - instance of jQuery promise\n     * @param {Object} component - component instance to attach to new context\n     */\n    function applyComponents(el, bindingContext, promise, component) {\n        promise.resolve();\n        component = bindingContext.createChildContext(component);\n\n        ko.utils.extend(component, {\n            $t: $t\n        });\n\n        ko.utils.arrayForEach(ko.virtualElements.childNodes(el), ko.cleanNode);\n\n        ko.applyBindingsToDescendants(component, el);\n    }\n\n    ko.bindingHandlers.scope = {\n\n        /**\n         * Scope binding's init method.\n         * @returns {Object} - Knockout declaration for it to let binding control descendants.\n         */\n        init: function () {\n            return {\n                controlsDescendantBindings: true\n            };\n        },\n\n        /**\n         * Reads params passed to binding, parses component declarations.\n         * Fetches for those found and attaches them to the new context.\n         * @param {HTMLElement} el - Element to apply bindings to.\n         * @param {Function} valueAccessor - Function that returns value, passed to binding.\n         * @param {Object} allBindings - Object, which represents all bindings applied to element.\n         * @param {Object} viewModel - Object, which represents view model binded to el.\n         * @param {ko.bindingContext} bindingContext - Instance of ko.bindingContext, passed to binding initially.\n         */\n        update: function (el, valueAccessor, allBindings, viewModel, bindingContext) {\n            var component = valueAccessor(),\n                promise = $.Deferred(),\n                apply = applyComponents.bind(this, el, bindingContext, promise),\n                loggerUtils = consoleLogger.utils;\n\n            if (typeof component === 'string') {\n                loggerUtils.asyncLog(\n                    promise,\n                    {\n                        data: {\n                            component: component\n                        },\n                        messages: loggerUtils.createMessages(\n                            'requestingComponent',\n                            'requestingComponentIsLoaded',\n                            'requestingComponentIsFailed'\n                        )\n                    }\n                );\n\n                registry.get(component, apply);\n            } else if (typeof component === 'function') {\n                component(apply);\n            }\n        }\n    };\n\n    ko.virtualElements.allowedBindings.scope = true;\n\n    renderer\n        .addNode('scope')\n        .addAttribute('scope', {\n            name: 'ko-scope'\n        });\n});\n","Magento_Ui/js/lib/knockout/bindings/range.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'jquery',\n    'underscore',\n    '../template/renderer'\n], function (ko, $, _, renderer) {\n    'use strict';\n\n    var isTouchDevice = !_.isUndefined(document.ontouchstart),\n        sliderFn = 'slider',\n        sliderModule = 'jquery-ui-modules/slider';\n\n    if (isTouchDevice) {\n        sliderFn = 'touchSlider';\n        sliderModule = 'mage/touch-slider';\n    }\n\n    ko.bindingHandlers.range = {\n\n        /**\n         * Initializes binding and a slider update.\n         *\n         * @param {HTMLElement} element\n         * @param {Function} valueAccessor\n         */\n        init: function (element, valueAccessor) {\n            var config  = valueAccessor(),\n                value   = config.value;\n\n            _.extend(config, {\n                value: value(),\n\n                /**\n                 * Callback which is being called when sliders' value changes.\n                 *\n                 * @param {Event} event\n                 * @param {Object} ui\n                 */\n                slide: function (event, ui) {\n                    value(ui.value);\n                }\n            });\n\n            require([sliderModule], function () {\n                $(element)[sliderFn](config);\n            });\n        },\n\n        /**\n         * Updates sliders' plugin configuration.\n         *\n         * @param {HTMLElement} element\n         * @param {Function} valueAccessor\n         */\n        update: function (element, valueAccessor) {\n            var config = valueAccessor();\n\n            config.value = ko.unwrap(config.value);\n\n            require([sliderModule], function () {\n                $(element)[sliderFn]('option', config);\n            });\n        }\n    };\n\n    renderer.addAttribute('range');\n});\n","Magento_Ui/js/lib/knockout/bindings/simple-checked.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    '../template/renderer'\n], function (ko, renderer) {\n    'use strict';\n\n    ko.bindingHandlers.simpleChecked = {\n        'after': ['attr'],\n\n        /**\n         * Implements same functionality as a standard 'simpleChecked' binding,\n         * but with a difference that it wont' change values array if\n         * value of DOM element changes.\n         */\n        init: function (element, valueAccessor) {\n            var isCheckbox = element.type === 'checkbox',\n                isRadio = element.type === 'radio',\n                updateView,\n                updateModel;\n\n            if (!isCheckbox && !isRadio) {\n                return;\n            }\n\n            /**\n             * Updates checked observable\n             */\n            updateModel = function () {\n                var  modelValue = ko.dependencyDetection.ignore(valueAccessor),\n                    isChecked = element.checked;\n\n                if (ko.computedContext.isInitial()) {\n                    return;\n                }\n\n                if (modelValue.peek() === isChecked) {\n                    return;\n                }\n\n                if (isRadio && !isChecked) {\n                    return;\n                }\n\n                modelValue(isChecked);\n            };\n\n            /**\n             * Updates checkbox state\n             */\n            updateView = function () {\n                var modelValue = ko.utils.unwrapObservable(valueAccessor());\n\n                element.checked = !!modelValue;\n            };\n\n            ko.utils.registerEventHandler(element, 'change', updateModel);\n\n            ko.computed(updateModel, null, {\n                disposeWhenNodeIsRemoved: element\n            });\n            ko.computed(updateView, null, {\n                disposeWhenNodeIsRemoved: element\n            });\n        }\n    };\n\n    ko.expressionRewriting._twoWayBindings.simpleChecked = true;\n\n    renderer.addAttribute('simpleChecked');\n    renderer.addAttribute('simple-checked', {\n        binding: 'simpleChecked'\n    });\n});\n","Magento_Ui/js/lib/knockout/bindings/staticChecked.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    '../template/renderer'\n], function (ko, renderer) {\n    'use strict';\n\n    ko.bindingHandlers.staticChecked = {\n        'after': ['value', 'attr'],\n\n        /**\n         * Implements same functionality as a standard 'checked' binding,\n         * but with a difference that it wont' change values array if\n         * value of DOM element changes.\n         */\n        init: function (element, valueAccessor, allBindings) {\n            var isCheckbox = element.type === 'checkbox',\n                isRadio = element.type === 'radio',\n                isValueArray,\n                oldElemValue,\n                useCheckedValue,\n                checkedValue,\n                updateModel,\n                updateView;\n\n            if (!isCheckbox && !isRadio) {\n                return;\n            }\n\n            checkedValue = ko.pureComputed(function () {\n                if (allBindings.has('checkedValue')) {\n                    return ko.utils.unwrapObservable(allBindings.get('checkedValue'));\n                } else if (allBindings.has('value')) {\n                    return ko.utils.unwrapObservable(allBindings.get('value'));\n                }\n\n                return element.value;\n            });\n\n            isValueArray = isCheckbox && ko.utils.unwrapObservable(valueAccessor()) instanceof Array;\n            oldElemValue = isValueArray ? checkedValue() : undefined;\n            useCheckedValue = isRadio || isValueArray;\n\n            /**\n             * Updates values array if it's necessary.\n             */\n            updateModel = function () {\n                var isChecked = element.checked,\n                    elemValue = useCheckedValue ? checkedValue() : isChecked,\n                    modelValue;\n\n                if (ko.computedContext.isInitial()) {\n                    return;\n                }\n\n                if (isRadio && !isChecked) {\n                    return;\n                }\n\n                modelValue = ko.dependencyDetection.ignore(valueAccessor);\n\n                if (isValueArray) {\n                    if (oldElemValue !== elemValue) {\n                        oldElemValue = elemValue;\n                    } else {\n                        ko.utils.addOrRemoveItem(modelValue, elemValue, isChecked);\n                    }\n                } else {\n                    ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'checked', elemValue, true);\n                }\n            };\n\n            /**\n             * Updates checkbox state.\n             */\n            updateView = function () {\n                var modelValue = ko.utils.unwrapObservable(valueAccessor());\n\n                if (isValueArray) {\n                    element.checked = ko.utils.arrayIndexOf(modelValue, checkedValue()) >= 0;\n                } else if (isCheckbox) {\n                    element.checked = modelValue;\n                } else {\n                    element.checked = checkedValue() === modelValue;\n                }\n            };\n\n            ko.computed(updateModel, null, {\n                disposeWhenNodeIsRemoved: element\n            });\n\n            ko.utils.registerEventHandler(element, 'click', updateModel);\n\n            ko.computed(updateView, null, {\n                disposeWhenNodeIsRemoved: element\n            });\n        }\n    };\n\n    ko.expressionRewriting._twoWayBindings.staticChecked = true;\n\n    renderer.addAttribute('staticChecked');\n});\n","Magento_Ui/js/lib/knockout/bindings/autoselect.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    'jquery',\n    '../template/renderer'\n], function (ko, $, renderer) {\n    'use strict';\n\n    /**\n     * 'Focus' event handler.\n     *\n     * @param {EventObject} e\n     */\n    function onFocus(e) {\n        e.target.select();\n    }\n\n    ko.bindingHandlers.autoselect = {\n\n        /**\n         * Adds event handler which automatically\n         * selects inputs' element text when field gets focused.\n         */\n        init: function (element, valueAccessor) {\n            var enabled = ko.unwrap(valueAccessor());\n\n            if (enabled !== false) {\n                $(element).on('focus', onFocus);\n            }\n        }\n    };\n\n    renderer.addAttribute('autoselect');\n});\n","Magento_Ui/js/lib/knockout/bindings/outer_click.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/** Creates outerClick binding and registers in to ko.bindingHandlers object */\ndefine([\n    'ko',\n    'jquery',\n    'underscore',\n    '../template/renderer'\n], function (ko, $, _, renderer) {\n    'use strict';\n\n    var defaults = {\n        onlyIfVisible: true\n    };\n\n    /**\n     * Checks if element sis visible.\n     *\n     * @param {Element} el\n     * @returns {Boolean}\n     */\n    function isVisible(el) {\n        var style = window.getComputedStyle(el),\n            visibility = {\n                display: 'none',\n                visibility: 'hidden',\n                opacity: '0'\n            },\n            visible = true;\n\n        _.each(visibility, function (val, key) {\n            if (style[key] === val) {\n                visible = false;\n            }\n        });\n\n        return visible;\n    }\n\n    /**\n     * Document click handler which in case if event target is not\n     * a descendant of provided container element,\n     * invokes specified in configuration callback.\n     *\n     * @param {HTMLElement} container\n     * @param {Object} config\n     * @param {EventObject} e\n     */\n    function onOuterClick(container, config, e) {\n        var target = e.target,\n            callback = config.callback;\n\n        if (container === target || container.contains(target)) {\n            return;\n        }\n\n        if (config.onlyIfVisible) {\n            if (!_.isNull(container.offsetParent) && isVisible(container)) {\n                callback();\n            }\n        } else {\n            callback();\n        }\n    }\n\n    /**\n     * Prepares configuration for the binding based\n     * on a default properties and provided options.\n     *\n     * @param {(Object|Function)} [options={}]\n     * @returns {Object}\n     */\n    function buildConfig(options) {\n        var config = {};\n\n        if (_.isFunction(options)) {\n            options = {\n                callback: options\n            };\n        } else if (!_.isObject(options)) {\n            options = {};\n        }\n\n        return _.extend(config, defaults, options);\n    }\n\n    ko.bindingHandlers.outerClick = {\n\n        /**\n         * Initializes outer click binding.\n         */\n        init: function (element, valueAccessor) {\n            var config = buildConfig(valueAccessor()),\n                outerClick = onOuterClick.bind(null, element, config),\n                isTouchDevice = typeof document.ontouchstart !== 'undefined';\n\n            if (isTouchDevice) {\n                $(document).on('touchstart', outerClick);\n\n                ko.utils.domNodeDisposal.addDisposeCallback(element, function () {\n                    $(document).off('touchstart', outerClick);\n                });\n            } else {\n                $(document).on('click', outerClick);\n\n                ko.utils.domNodeDisposal.addDisposeCallback(element, function () {\n                    $(document).off('click', outerClick);\n                });\n            }\n        }\n    };\n\n    renderer.addAttribute('outerClick');\n});\n","Magento_Ui/js/lib/knockout/bindings/keyboard.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    '../template/renderer'\n], function (ko, renderer) {\n    'use strict';\n\n    ko.bindingHandlers.keyboard = {\n\n        /**\n         * Attaches keypress handlers to element\n         * @param {HTMLElement} el - Element, that binding is applied to\n         * @param {Function} valueAccessor - Function that returns value, passed to binding\n         * @param  {Object} allBindings - all bindings object\n         * @param  {Object} viewModel - reference to viewmodel\n         */\n        init: function (el, valueAccessor, allBindings, viewModel) {\n            var map = valueAccessor();\n\n            ko.utils.registerEventHandler(el, 'keyup', function (e) {\n                var callback = map[e.keyCode];\n\n                if (callback) {\n                    return callback.call(viewModel, e);\n                }\n            });\n        }\n    };\n\n    renderer.addAttribute('keyboard');\n});\n","Magento_Ui/js/lib/knockout/bindings/after-render.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    '../template/renderer'\n], function (ko, renderer) {\n    'use strict';\n\n    ko.bindingHandlers.afterRender = {\n\n        /**\n         * Binding init callback.\n         */\n        init: function (element, valueAccessor, allBindings, viewModel) {\n            var callback = valueAccessor();\n\n            if (typeof callback === 'function') {\n                callback.call(viewModel, element, viewModel);\n            }\n        }\n    };\n\n    renderer.addAttribute('afterRender');\n});\n","Magento_Ui/js/lib/knockout/bindings/tooltip.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'ko',\n    'underscore',\n    'mage/template',\n    'text!ui/template/tooltip/tooltip.html',\n    '../template/renderer'\n], function ($, ko, _, template, tooltipTmpl, renderer) {\n    'use strict';\n\n    var tooltip,\n        defaults,\n        positions,\n        transformProp,\n        checkedPositions = {},\n        iterator = 0,\n        previousTooltip,\n        tooltipData,\n        positionData = {},\n        tooltipsCollection = {},\n        isTouchDevice = (function () {\n            return 'ontouchstart' in document.documentElement;\n        })(),\n        CLICK_EVENT = (function () {\n            return isTouchDevice ? 'touchstart' : 'click';\n        })();\n\n    defaults = {\n        tooltipWrapper: '[data-tooltip=tooltip-wrapper]',\n        tooltipContentBlock: 'data-tooltip-content',\n        closeButtonClass: 'action-close',\n        tailClass: 'data-tooltip-tail',\n        action: 'hover',\n        delay: 300,\n        track: false,\n        step: 20,\n        position: 'top',\n        closeButton: false,\n        showed: false,\n        strict: true,\n        center: false,\n        closeOnScroll: true\n    };\n\n    tooltipData = {\n        tooltipClasses: '',\n        trigger: false,\n        timeout: 0,\n        element: false,\n        event: false,\n        targetElement: {},\n        showed: false,\n        currentID: 0\n    };\n\n    /**\n     * Polyfill for css transform\n     */\n    transformProp = (function () {\n        var style = document.createElement('div').style,\n            base = 'Transform',\n            vendors = ['webkit', 'moz', 'ms', 'o'],\n            vi = vendors.length,\n            property;\n\n        if (typeof style.transform !== 'undefined') {\n            return 'transform';\n        }\n\n        while (vi--) {\n            property = vendors[vi] + base;\n\n            if (typeof style[property] !== 'undefined') {\n                return property;\n            }\n        }\n    })();\n\n    positions = {\n\n        /*eslint max-depth: [0, 0]*/\n\n        map: {\n            horizontal: {\n                s: 'w',\n                p: 'left'\n            },\n            vertical: {\n                s: 'h',\n                p: 'top'\n            }\n        },\n\n        /**\n         * Wrapper function to get tooltip data (position, className, etc)\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        top: function (s) {\n            return positions._topLeftChecker(s, positions.map, 'vertical', '_bottom', 'top', 'right');\n        },\n\n        /**\n         * Wrapper function to get tooltip data (position, className, etc)\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        left: function (s) {\n            return positions._topLeftChecker(s, positions.map, 'horizontal', '_right', 'left', 'top');\n        },\n\n        /**\n         * Wrapper function to get tooltip data (position, className, etc)\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        bottom: function (s) {\n            return positions._bottomRightChecker(s, positions.map, 'vertical', '_top', 'bottom', 'left');\n        },\n\n        /**\n         * Wrapper function to get tooltip data (position, className, etc)\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        right: function (s) {\n            return positions._bottomRightChecker(s, positions.map, 'horizontal', '_left', 'right', 'bottom');\n        },\n\n        /**\n         * Check can tooltip setted on current position or not. If can't setted - delegate call.\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @param {Object} map - mapping for get direction positions\n         * @param {String} direction - vertical or horizontal\n         * @param {String} className - class whats should be setted to tooltip\n         * @param {String} side - parent method name\n         * @param {String} delegate - method name if tooltip can't be setted in current position\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        _topLeftChecker: function (s, map, direction, className, side, delegate) {\n            var result = {\n                    position: {}\n                },\n                config = tooltip.getTooltip(tooltipData.currentID),\n                startPosition = !config.strict ? s.eventPosition : s.elementPosition,\n                changedDirection;\n\n            checkedPositions[side] = true;\n\n            if (\n                startPosition[map[direction].p] - s.tooltipSize[map[direction].s] - config.step >\n                s.scrollPosition[map[direction].p]\n            ) {\n                result.position[map[direction].p] = startPosition[map[direction].p] - s.tooltipSize[map[direction].s] -\n                    config.step;\n                result.className = className;\n                result.side = side;\n                changedDirection = direction === 'vertical' ? 'horizontal' : 'vertical';\n                result = positions._normalize(s, result, config, delegate, map, changedDirection);\n            } else if (!checkedPositions[delegate]) {\n                result = positions[delegate].apply(null, arguments);\n            } else {\n                result = positions.positionCenter(s, result);\n            }\n\n            return result;\n        },\n\n        /**\n         * Check can tooltip setted on current position or not. If can't setted - delegate call.\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @param {Object} map - mapping for get direction positions\n         * @param {String} direction - vertical or horizontal\n         * @param {String} className - class whats should be setted to tooltip\n         * @param {String} side - parent method name\n         * @param {String} delegate - method name if tooltip can't be setted in current position\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        _bottomRightChecker: function (s, map, direction, className, side, delegate) {\n            var result = {\n                    position: {}\n                },\n                config = tooltip.getTooltip(tooltipData.currentID),\n                startPosition = !config.strict ? s.eventPosition : {\n                    top: s.elementPosition.top + s.elementSize.h,\n                    left: s.elementPosition.left + s.elementSize.w\n                },\n                changedDirection;\n\n            checkedPositions[side] = true;\n\n            if (\n                startPosition[map[direction].p] + s.tooltipSize[map[direction].s] + config.step <\n                s.scrollPosition[map[direction].p] + s.windowSize[map[direction].s]\n            ) {\n                result.position[map[direction].p] = startPosition[map[direction].p] + config.step;\n                result.className = className;\n                result.side = side;\n                changedDirection = direction === 'vertical' ? 'horizontal' : 'vertical';\n                result = positions._normalize(s, result, config, delegate, map, changedDirection);\n            } else if (!checkedPositions[delegate]) {\n                result = positions[delegate].apply(null, arguments);\n            } else {\n                result = positions.positionCenter(s, result);\n            }\n\n            return result;\n        },\n\n        /**\n         * Centered tooltip if tooltip does not fit in window\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @param {Object} data - current data (position, className, etc)\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        positionCenter: function (s, data) {\n            data = positions._positionCenter(s, data, 'horizontal', positions.map);\n            data = positions._positionCenter(s, data, 'vertical', positions.map);\n\n            return data;\n        },\n\n        /**\n         * Centered tooltip side\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @param {Object} data - current data (position, className, etc)\n         * @param {String} direction - vertical or horizontal\n         * @param {Object} map - mapping for get direction positions\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        _positionCenter: function (s, data, direction, map) {\n            if (s.tooltipSize[map[direction].s] < s.windowSize[map[direction].s]) {\n                data.position[map[direction].p] = (s.windowSize[map[direction].s] -\n                    s.tooltipSize[map[direction].s]) / 2 + s.scrollPosition[map[direction].p];\n            } else {\n                data.position[map[direction].p] = s.scrollPosition[map[direction].p];\n                data.tooltipSize = {};\n                data.tooltipSize[map[direction].s] = s.windowSize[map[direction].s];\n            }\n\n            return data;\n        },\n\n        /**\n         * Normalize horizontal or vertical position.\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @param {Object} data - current data (position, className, etc)\n         * @param {Object} config - tooltip config\n         * @param {String} delegate - method name if tooltip can't be setted in current position\n         * @param {Object} map - mapping for get direction positions\n         * @param {String} direction - vertical or horizontal\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        _normalize: function (s, data, config, delegate, map, direction) {\n            var startPosition = !config.center ? s.eventPosition : {\n                    left: s.elementPosition.left + s.elementSize.w / 2,\n                    top: s.elementPosition.top + s.elementSize.h / 2\n                },\n                depResult;\n\n            if (startPosition[map[direction].p] - s.tooltipSize[map[direction].s] / 2 >\n                s.scrollPosition[map[direction].p] && startPosition[map[direction].p] +\n                s.tooltipSize[map[direction].s] / 2 <\n                s.scrollPosition[map[direction].p] + s.windowSize[map[direction].s]\n            ) {\n                data.position[map[direction].p] = startPosition[map[direction].p] - s.tooltipSize[map[direction].s] / 2;\n            } else {\n\n                /*eslint-disable no-lonely-if*/\n                if (!checkedPositions[delegate]) {\n                    depResult = positions[delegate].apply(null, arguments);\n\n                    if (depResult.hasOwnProperty('className')) {\n                        data = depResult;\n                    } else {\n                        data = positions._normalizeTail(s, data, config, delegate, map, direction, startPosition);\n                    }\n                } else {\n                    data = positions._normalizeTail(s, data, config, delegate, map, direction, startPosition);\n                }\n            }\n\n            return data;\n        },\n\n        /**\n         * Calc tail position.\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @param {Object} data - current data (position, className, etc)\n         * @param {Object} config - tooltip config\n         * @param {String} delegate - method name if tooltip can't be setted in current position\n         * @param {Object} map - mapping for get direction positions\n         * @param {String} direction - vertical or horizontal\n         * @param {Object} startPosition - start position\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        _normalizeTail: function (s, data, config, delegate, map, direction, startPosition) {\n            data.tail = {};\n\n            if (s.tooltipSize[map[direction].s] < s.windowSize[map[direction].s]) {\n\n                if (\n                    startPosition[map[direction].p] >\n                    s.windowSize[map[direction].s] / 2 + s.scrollPosition[map[direction].p]\n                ) {\n                    data.position[map[direction].p] = s.windowSize[map[direction].s] +\n                        s.scrollPosition[map[direction].p] - s.tooltipSize[map[direction].s];\n                    data.tail[map[direction].p] = startPosition[map[direction].p] -\n                        s.tooltipSize[map[direction].s] / 2 - data.position[map[direction].p];\n                } else {\n                    data.position[map[direction].p] = s.scrollPosition[map[direction].p];\n                    data.tail[map[direction].p] = startPosition[map[direction].p] -\n                        s.tooltipSize[map[direction].s] / 2 - data.position[map[direction].p];\n                }\n            } else {\n                data.position[map[direction].p] = s.scrollPosition[map[direction].p];\n                data.tail[map[direction].p] = s.eventPosition[map[direction].p] - s.windowSize[map[direction].s] / 2;\n                data.tooltipSize = {};\n                data.tooltipSize[map[direction].s] = s.windowSize[map[direction].s];\n            }\n\n            return data;\n        }\n    };\n\n    tooltip = {\n\n        /**\n         * Set new tooltip to tooltipCollection, save config, and add unic id\n         *\n         * @param {Object} config - tooltip config\n         * @returns {String} tooltip id\n         */\n        setTooltip: function (config) {\n            var property = 'id-' + iterator;\n\n            tooltipsCollection[property] = config;\n            iterator++;\n\n            return property;\n        },\n\n        /**\n         * Get tooltip config by id\n         *\n         * @param {String} id - tooltip id\n         * @returns {Object} tooltip config\n         */\n        getTooltip: function (id) {\n            return tooltipsCollection[id];\n        },\n\n        /**\n         * Set content to current tooltip\n         *\n         * @param {Object} tooltipElement - tooltip element\n         * @param {Object} viewModel - tooltip view model\n         * @param {String} id - tooltip id\n         * @param {Object} bindingCtx - tooltip context\n         * @param {Object} event - action event\n         */\n        setContent: function (tooltipElement, viewModel, id, bindingCtx, event) {\n            var html = $(tooltipElement).html(),\n                config = tooltip.getTooltip(id),\n                body = $('body');\n\n            tooltipData.currentID = id;\n            tooltipData.trigger = $(event.currentTarget);\n            tooltip.setTargetData(event);\n            body.on('mousemove.setTargetData', tooltip.setTargetData);\n            tooltip.clearTimeout(id);\n\n            tooltipData.timeout = _.delay(function () {\n                body.off('mousemove.setTargetData', tooltip.setTargetData);\n\n                if (tooltipData.trigger[0] === tooltipData.targetElement) {\n                    tooltip.destroy(id);\n                    event.stopPropagation();\n                    tooltipElement = tooltip.createTooltip(id);\n                    tooltipElement.find('.' + defaults.tooltipContentBlock).append(html);\n                    tooltipElement.applyBindings(bindingCtx);\n                    tooltip.setHandlers(id);\n                    tooltip.setPosition(tooltipElement, id);\n                    previousTooltip = id;\n                }\n\n            }, config.delay);\n        },\n\n        /**\n         * Set position to current tooltip\n         *\n         * @param {Object} tooltipElement - tooltip element\n         * @param {String} id - tooltip id\n         */\n        setPosition: function (tooltipElement, id) {\n            var config = tooltip.getTooltip(id);\n\n            tooltip.sizeData = {\n                windowSize: {\n                    h: $(window).outerHeight(),\n                    w: $(window).outerWidth()\n                },\n                scrollPosition: {\n                    top: $(window).scrollTop(),\n                    left: $(window).scrollLeft()\n                },\n                tooltipSize: {\n                    h: tooltipElement.outerHeight(),\n                    w: tooltipElement.outerWidth()\n                },\n                elementSize: {\n                    h: tooltipData.trigger.outerHeight(),\n                    w: tooltipData.trigger.outerWidth()\n                },\n                elementPosition: tooltipData.trigger.offset(),\n                eventPosition: this.getEventPosition(tooltipData.event)\n            };\n\n            _.extend(positionData, positions[config.position](tooltip.sizeData));\n            tooltipElement.css(positionData.position);\n            tooltipElement.addClass(positionData.className);\n            tooltip._setTooltipSize(positionData, tooltipElement);\n            tooltip._setTailPosition(positionData, tooltipElement);\n            checkedPositions = {};\n        },\n\n        /**\n         * Check position data and change tooltip size if needs\n         *\n         * @param {Object} data - position data\n         * @param {Object} tooltipElement - tooltip element\n         */\n        _setTooltipSize: function (data, tooltipElement) {\n            if (data.tooltipSize) {\n                data.tooltipSize.w ?\n                    tooltipElement.css('width', data.tooltipSize.w) :\n                    tooltipElement.css('height', data.tooltipSize.h);\n            }\n        },\n\n        /**\n         * Check position data and set position to tail\n         *\n         * @param {Object} data - position data\n         * @param {Object} tooltipElement - tooltip element\n         */\n        _setTailPosition: function (data, tooltipElement) {\n            var tail,\n                tailMargin;\n\n            if (data.tail) {\n                tail = tooltipElement.find('.' + defaults.tailClass);\n\n                if (data.tail.left) {\n                    tailMargin = parseInt(tail.css('margin-left'), 10);\n                    tail.css('margin-left', tailMargin + data.tail.left);\n                } else {\n                    tailMargin = parseInt(tail.css('margin-top'), 10);\n                    tail.css('margin-top', tailMargin + data.tail.top);\n                }\n            }\n        },\n\n        /**\n         * Resolves position for tooltip\n         *\n         * @param {Object} event\n         * @returns {Object}\n         */\n        getEventPosition: function (event) {\n            var position = {\n                left: event.originalEvent && event.originalEvent.pageX || 0,\n                top: event.originalEvent && event.originalEvent.pageY || 0\n            };\n\n            if (position.left === 0 && position.top === 0) {\n                _.extend(position, event.target.getBoundingClientRect());\n            }\n\n            return position;\n        },\n\n        /**\n         * Close tooltip if action happened outside handler and tooltip element\n         *\n         * @param {String} id - tooltip id\n         * @param {Object} event - action event\n         */\n        outerClick: function (id, event) {\n            var tooltipElement = $(event.target).parents(defaults.tooltipWrapper)[0],\n                isTrigger = event.target === tooltipData.trigger[0] || $.contains(tooltipData.trigger[0], event.target);\n\n            if (tooltipData.showed && tooltipElement !== tooltipData.element[0] && !isTrigger) {\n                tooltip.destroy(id);\n            }\n        },\n\n        /**\n         * Parse keydown event and if event trigger is escape key - close tooltip\n         *\n         * @param {Object} event - action event\n         */\n        keydownHandler: function (event) {\n            if (tooltipData.showed && event.keyCode === 27) {\n                tooltip.destroy(tooltipData.currentID);\n            }\n        },\n\n        /**\n         * Change tooltip position when track is enabled\n         *\n         * @param {Object} event - current event\n         */\n        track: function (event) {\n            var inequality = {},\n                map = positions.map,\n                translate = {\n                    left: 'translateX',\n                    top: 'translateY'\n                },\n                eventPosition = {\n                    left: event.pageX,\n                    top: event.pageY\n                },\n                tooltipSize = {\n                    w: tooltipData.element.outerWidth(),\n                    h: tooltipData.element.outerHeight()\n                },\n                direction = positionData.side === 'bottom' || positionData.side === 'top' ? 'horizontal' : 'vertical';\n\n            inequality[map[direction].p] = eventPosition[map[direction].p] - (positionData.position[map[direction].p] +\n                tooltipSize[map[direction].s] / 2);\n\n            if (positionData.position[map[direction].p] + inequality[map[direction].p] +\n                tooltip.sizeData.tooltipSize[map[direction].s] >\n                tooltip.sizeData.windowSize[map[direction].s] + tooltip.sizeData.scrollPosition[map[direction].p] ||\n                inequality[map[direction].p] + positionData.position[map[direction].p] <\n                tooltip.sizeData.scrollPosition[map[direction].p]) {\n\n                return false;\n            }\n\n            tooltipData.element[0].style[transformProp] = translate[map[direction].p] +\n                '(' + inequality[map[direction].p] + 'px)';\n        },\n\n        /**\n         * Set handlers to tooltip\n         *\n         * @param {String} id - tooltip id\n         */\n        setHandlers: function (id) {\n            var config = tooltip.getTooltip(id);\n\n            if (config.track) {\n                tooltipData.trigger.on('mousemove.track', tooltip.track);\n            }\n\n            if (config.action === 'click') {\n                $(window).on(CLICK_EVENT + '.outerClick', tooltip.outerClick.bind(null, id));\n            }\n\n            if (config.closeButton) {\n                $('.' + config.closeButtonClass).on('click.closeButton', tooltip.destroy.bind(null, id));\n            }\n\n            if (config.closeOnScroll) {\n                document.addEventListener('scroll', tooltip.destroy, true);\n                $(window).on('scroll.tooltip', tooltip.outerClick.bind(null, id));\n            }\n\n            $(window).on('keydown.tooltip', tooltip.keydownHandler);\n            $(window).on('resize.outerClick', tooltip.outerClick.bind(null, id));\n        },\n\n        /**\n         * Toggle tooltip\n         *\n         * @param {Object} tooltipElement - tooltip element\n         * @param {Object} viewModel - tooltip view model\n         * @param {String} id - tooltip id\n         */\n        toggleTooltip: function (tooltipElement, viewModel, id) {\n            if (previousTooltip === id && tooltipData.showed) {\n                tooltip.destroy(id);\n\n                return false;\n            }\n\n            tooltip.setContent.apply(null, arguments);\n\n            return false;\n        },\n\n        /**\n         * Create tooltip and append to DOM\n         *\n         * @param {String} id - tooltip id\n         * @returns {Object} tooltip element\n         */\n        createTooltip: function (id) {\n            var body = $('body'),\n                config = tooltip.getTooltip(id);\n\n            $(template(tooltipTmpl, {\n                data: config\n            })).appendTo(body);\n\n            tooltipData.showed = true;\n            tooltipData.element = $(config.tooltipWrapper);\n\n            return tooltipData.element;\n        },\n\n        /**\n         * Check action and clean timeout\n         *\n         * @param {String} id - tooltip id\n         */\n        clearTimeout: function (id) {\n            var config = tooltip.getTooltip(id);\n\n            if (config.action === 'hover') {\n                clearTimeout(tooltipData.timeout);\n            }\n        },\n\n        /**\n         * Check previous tooltip\n         */\n        checkPreviousTooltip: function () {\n            if (!tooltipData.timeout) {\n                tooltip.destroy();\n            }\n        },\n\n        /**\n         * Destroy tooltip instance\n         */\n        destroy: function () {\n            if (tooltipData.element) {\n                tooltipData.element.remove();\n                tooltipData.showed = false;\n            }\n\n            positionData = {};\n            tooltipData.timeout = false;\n            tooltip.removeHandlers();\n        },\n\n        /**\n         * Remove tooltip handlers\n         */\n        removeHandlers: function () {\n            $('.' + defaults.closeButtonClass).off('click.closeButton');\n            tooltipData.trigger.off('mousemove.track');\n            document.removeEventListener('scroll', tooltip.destroy, true);\n            $(window).off('scroll.tooltip');\n            $(window).off(CLICK_EVENT + '.outerClick');\n            $(window).off('keydown.tooltip');\n            $(window).off('resize.outerClick');\n        },\n\n        /**\n         * Set target element\n         *\n         * @param {Object} event - current event\n         */\n        setTargetData: function (event) {\n            tooltipData.event = event;\n\n            //TODO: bug chrome v.49; Link to issue https://bugs.chromium.org/p/chromium/issues/detail?id=161464\n            if (event.timeStamp - (tooltipData.timestamp || 0) < 1) {\n                return;\n            }\n\n            if (event.type === 'mousemove') {\n                tooltipData.targetElement = event.target;\n            } else {\n                tooltipData.targetElement = event.currentTarget;\n                tooltipData.timestamp = event.timeStamp;\n            }\n        },\n\n        /**\n         * Merged user config with defaults configuration\n         *\n         * @param {Object} config - user config\n         * @returns {Object} merged config\n         */\n        processingConfig: function (config) {\n            return _.extend({}, defaults, config);\n        }\n    };\n\n    ko.bindingHandlers.tooltip = {\n\n        /**\n         * Initialize tooltip\n         *\n         * @param {Object} elem - tooltip DOM element\n         * @param {Function} valueAccessor - ko observable property, tooltip data\n         * @param {Object} allBindings - all bindings on current element\n         * @param {Object} viewModel - current element viewModel\n         * @param {Object} bindingCtx - current element binding context\n         */\n        init: function (elem, valueAccessor, allBindings, viewModel, bindingCtx) {\n            var config = tooltip.processingConfig(valueAccessor()),\n                $parentScope = config.parentScope ? $(config.parentScope) : $(elem).parent(),\n                tooltipId;\n\n            $(elem).addClass('hidden');\n\n            if (isTouchDevice) {\n                config.action = 'click';\n            }\n            tooltipId = tooltip.setTooltip(config);\n\n            if (config.action === 'hover') {\n                $parentScope.on(\n                    'mouseenter',\n                    config.trigger,\n                    tooltip.setContent.bind(null, elem, viewModel, tooltipId, bindingCtx)\n                );\n                $parentScope.on(\n                    'mouseleave',\n                    config.trigger,\n                    tooltip.checkPreviousTooltip.bind(null, tooltipId)\n                );\n            } else if (config.action === 'click') {\n                $parentScope.on(\n                    'click',\n                    config.trigger,\n                    tooltip.toggleTooltip.bind(null, elem, viewModel, tooltipId, bindingCtx)\n                );\n            }\n\n            return {\n                controlsDescendantBindings: true\n            };\n        }\n    };\n\n    renderer.addAttribute('tooltip');\n});\n","Magento_Ui/js/lib/knockout/bindings/datepicker.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/** Creates datepicker binding and registers in to ko.bindingHandlers object */\ndefine([\n    'ko',\n    'underscore',\n    'jquery',\n    'mage/translate'\n], function (ko, _, $, $t) {\n    'use strict';\n\n    var defaults = {\n        dateFormat: 'mm\\/dd\\/yyyy',\n        showsTime: false,\n        timeFormat: null,\n        buttonImage: null,\n        buttonImageOnly: null,\n        buttonText: $t('Select Date')\n    };\n\n    ko.bindingHandlers.datepicker = {\n        /**\n         * Initializes calendar widget on element and stores it's value to observable property.\n         * Datepicker binding takes either observable property or object\n         *  { storage: {ko.observable}, options: {Object} }.\n         * For more info about options take a look at \"mage/calendar\" and jquery.ui.datepicker widget.\n         * @param {HTMLElement} el - Element, that binding is applied to\n         * @param {Function} valueAccessor - Function that returns value, passed to binding\n         * @param {object} allBindings\n         * @param {object} viewModel\n         * @param {object} bindingContext\n         */\n        init: function (el, valueAccessor, allBindings, viewModel, bindingContext) {\n            var config = valueAccessor(),\n                observable,\n                options = {};\n\n            _.extend(options, defaults);\n\n            if (typeof config === 'object') {\n                observable = config.storage;\n                _.extend(options, config.options);\n            } else {\n                observable = config;\n            }\n\n            require(['mage/calendar'], function () {\n                $(el).calendar(options);\n\n                ko.utils.registerEventHandler(el, 'change', function () {\n                    observable(this.value);\n                });\n            });\n\n            if (bindingContext.$data) {\n                bindingContext.$data.value.subscribe(function (newVal) {\n                    if (!newVal) {\n                        $(el).val('');\n                    }\n                }, this);\n            }\n\n\n        },\n\n        /**\n         * Update calendar widget on element and stores it's value to observable property.\n         * Datepicker binding takes either observable property or object\n         *  { storage: {ko.observable}, options: {Object} }.\n         * @param {HTMLElement} element - Element, that binding is applied to\n         * @param {Function} valueAccessor - Function that returns value, passed to binding\n         */\n        update: function (element, valueAccessor) {\n            var config = valueAccessor(),\n                $element = $(element),\n                observable,\n                options = {},\n                newVal;\n\n            _.extend(options, defaults);\n\n            if (typeof config === 'object') {\n                observable = config.storage;\n                _.extend(options, config.options);\n            } else {\n                observable = config;\n            }\n\n            require(['moment', 'mage/utils/misc', 'mage/calendar'], function (moment, utils) {\n                if (_.isEmpty(observable())) {\n                    newVal = null;\n                } else {\n                    newVal = moment(\n                        observable(),\n                        utils.convertToMomentFormat(\n                            options.dateFormat + (options.showsTime ? ' ' + options.timeFormat : '')\n                        )\n                    ).toDate();\n                }\n\n                if (!options.timeOnly) {\n                    $element.datepicker('setDate', newVal);\n                    $element.trigger('blur');\n                }\n            });\n        }\n    };\n});\n","Magento_Ui/js/lib/knockout/bindings/resizable.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    'jquery',\n    'Magento_Ui/js/lib/view/utils/async',\n    'uiRegistry',\n    'underscore',\n    '../template/renderer'\n], function (ko, $, async, registry, _, renderer) {\n    'use strict';\n\n    var sizeOptions = [\n            'minHeight',\n            'maxHeight',\n            'minWidth',\n            'maxWidth'\n        ],\n\n        handles = {\n            height: '.ui-resizable-s, .ui-resizable-n',\n            width: '.ui-resizable-w, .ui-resizable-e'\n        };\n\n    /**\n     * Recalcs visibility of handles, width and height of resizable based on content\n     * @param {HTMLElement} element\n     */\n    function adjustSize(element) {\n        var maxHeight,\n            maxWidth;\n\n        element = $(element);\n        maxHeight = element.resizable('option').maxHeight;\n        maxWidth = element.resizable('option').maxWidth;\n\n        if (maxHeight && element.height() > maxHeight) {\n            element.height(maxHeight + 1);\n            $(handles.height).hide();\n        } else {\n            $(handles.height).show();\n        }\n\n        if (maxWidth && element.width() > maxWidth) {\n            element.width(maxWidth + 1);\n            $(handles.width).hide();\n        } else {\n            $(handles.width).show();\n        }\n    }\n\n    /**\n     * Recalcs allowed min, max width and height based on configured selectors\n     * @param {Object} sizeConstraints\n     * @param {String} componentName\n     * @param {HTMLElement} element\n     * @param {Boolean} hasWidthUpdate\n     */\n    function recalcAllowedSize(sizeConstraints, componentName, element, hasWidthUpdate) {\n        var size;\n\n        element = $(element);\n\n        if (!element.data('resizable')) {\n            return;\n        }\n\n        if (!hasWidthUpdate) {\n            element.css('width', 'auto');\n        }\n\n        _.each(sizeConstraints, function (selector, key) {\n            async.async({\n                component: componentName,\n                selector: selector\n            }, function (elem) {\n                size = key.indexOf('Height') !== -1 ? $(elem).outerHeight(true) : $(elem).outerWidth(true);\n\n                if (element.data('resizable')) {\n                    element.resizable('option', key, size + 1);\n                }\n            });\n        }, this);\n\n        adjustSize(element);\n    }\n\n    /**\n     * Preprocess config to separate options,\n     * which must be processed further before applying\n     *\n     * @param {Object} config\n     * @param {Object} viewModel\n     * @param {*} element\n     * @return {Object} config\n     */\n    function processConfig(config, viewModel, element) {\n        var sizeConstraint,\n            sizeConstraints = {},\n            recalc,\n            hasWidthUpdate;\n\n        if (_.isEmpty(config)) {\n            return {};\n        }\n        _.each(sizeOptions, function (key) {\n            sizeConstraint = config[key];\n\n            if (sizeConstraint && !_.isNumber(sizeConstraint)) {\n                sizeConstraints[key] = sizeConstraint;\n                delete config[key];\n            }\n        });\n        hasWidthUpdate =  _.some(sizeConstraints, function (value, key) {\n            return key.indexOf('Width') !== -1;\n        });\n\n        recalc = recalcAllowedSize.bind(null, sizeConstraints, viewModel.name, element, hasWidthUpdate);\n        config.start = recalc;\n        $(window).on('resize.resizable', recalc);\n        registry.get(viewModel.provider).on('reloaded', recalc);\n\n        return config;\n    }\n\n    ko.bindingHandlers.resizable = {\n\n        /**\n         * Binding init callback.\n         *\n         * @param {*} element\n         * @param {Function} valueAccessor\n         * @param {Function} allBindings\n         * @param {Object} viewModel\n         */\n        init: function (element, valueAccessor, allBindings, viewModel) {\n            var config = processConfig(valueAccessor(), viewModel, element);\n\n            require(['jquery-ui-modules/resizable'], function () {\n                if ($.fn.resizable) {\n                    $(element).resizable(config);\n                }\n            });\n        }\n    };\n\n    renderer.addAttribute('resizable');\n});\n","Magento_Ui/js/lib/knockout/bindings/bind-html.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'underscore',\n    'mage/apply/main',\n    '../template/renderer'\n], function (ko, _, mage, renderer) {\n    'use strict';\n\n    /**\n     * Set html to node element.\n     *\n     * @param {HTMLElement} el - Element to apply bindings to.\n     * @param {Function} html - Observable html content.\n     */\n    function setHtml(el, html) {\n        ko.utils.emptyDomNode(el);\n        html = ko.utils.unwrapObservable(html);\n\n        if (!_.isNull(html) && !_.isUndefined(html)) {\n            if (!_.isString(html)) {\n                html = html.toString();\n            }\n\n            el.innerHTML = html;\n        }\n    }\n\n    /**\n     * Apply bindings and call magento attributes parser.\n     *\n     * @param {HTMLElement} el - Element to apply bindings to.\n     * @param {ko.bindingContext} ctx - Instance of ko.bindingContext, passed to binding initially.\n     */\n    function applyComponents(el, ctx) {\n        ko.utils.arrayForEach(el.childNodes, ko.cleanNode);\n        ko.applyBindingsToDescendants(ctx, el);\n        mage.apply();\n    }\n\n    ko.bindingHandlers.bindHtml = {\n        /**\n         * Scope binding's init method.\n         *\n         * @returns {Object} - Knockout declaration for it to let binding control descendants.\n         */\n        init: function () {\n            return {\n                controlsDescendantBindings: true\n            };\n        },\n\n        /**\n         * Reads params passed to binding.\n         * Set html to node element, apply bindings and call magento attributes parser.\n         *\n         * @param {HTMLElement} el - Element to apply bindings to.\n         * @param {Function} valueAccessor - Function that returns value, passed to binding.\n         * @param {Object} allBindings - Object, which represents all bindings applied to element.\n         * @param {Object} viewModel - Object, which represents view model binded to el.\n         * @param {ko.bindingContext} bindingContext - Instance of ko.bindingContext, passed to binding initially.\n         */\n        update: function (el, valueAccessor, allBindings, viewModel, bindingContext) {\n            setHtml(el, valueAccessor());\n            applyComponents(el, bindingContext);\n        }\n    };\n\n    renderer.addAttribute('bindHtml');\n});\n","Magento_Ui/js/lib/knockout/extender/observable_array.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'underscore'\n], function (ko, _) {\n    'use strict';\n\n    /**\n     * Iterator function.\n     *\n     * @param {String} callback\n     * @param {Array} args\n     * @param {Object} elem\n     * @returns {*}\n     */\n    function iterator(callback, args, elem) {\n        callback = elem[callback];\n\n        if (_.isFunction(callback)) {\n            return callback.apply(elem, args);\n        }\n\n        return callback;\n    }\n\n    /**\n     * Wrapper function.\n     *\n     * @param {String} method\n     * @returns {Function}\n     */\n    function wrapper(method) {\n        return function (iteratee) {\n            var callback = iteratee,\n                elems = this(),\n                args = _.toArray(arguments);\n\n            if (_.isString(iteratee)) {\n                callback = iterator.bind(null, iteratee, args.slice(1));\n\n                args.unshift(callback);\n            }\n\n            args.unshift(elems);\n\n            return _[method].apply(_, args);\n        };\n    }\n\n    _.extend(ko.observableArray.fn, {\n        each: wrapper('each'),\n\n        map: wrapper('map'),\n\n        filter: wrapper('filter'),\n\n        some: wrapper('some'),\n\n        every: wrapper('every'),\n\n        groupBy: wrapper('groupBy'),\n\n        sortBy: wrapper('sortBy'),\n\n        /**\n         * Wrapper for underscore findWhere function.\n         *\n         * @param {Object} properties\n         * @return {Object}\n         */\n        findWhere: function (properties) {\n            return _.findWhere(this(), properties);\n        },\n\n        /**\n         * Wrapper for underscore contains function.\n         *\n         * @param {*} value\n         * @return {Boolean}\n         */\n        contains: function (value) {\n            return _.contains(this(), value);\n        },\n\n        /**\n         * Inverse contains call.\n         *\n         * @return {Boolean}\n         */\n        hasNo: function () {\n            return !this.contains.apply(this, arguments);\n        },\n\n        /**\n         * Getter for length property.\n         *\n         * @return {Number}\n         */\n        getLength: function () {\n            return this().length;\n        },\n\n        /**\n         * Create object with keys that gets from each object property.\n         *\n         * @return {Object}\n         */\n        indexBy: function (key) {\n            return _.indexBy(this(), key);\n        },\n\n        /**\n         * Returns a copy of the array with all instances of the values removed.\n         *\n         * @return {Array}\n         */\n        without: function () {\n            var args = Array.prototype.slice.call(arguments);\n\n            args.unshift(this());\n\n            return _.without.apply(_, args);\n        },\n\n        /**\n         * Returns the first element of an array.\n         *\n         * @return {*}\n         */\n        first: function () {\n            return _.first(this());\n        },\n\n        /**\n         * Returns the last element of an array\n         *\n         * @return {*}\n         */\n        last: function () {\n            return _.last(this());\n        },\n\n        /**\n         * Iterate and pick provided properties.\n         *\n         * @return {Array}\n         */\n        pluck: function () {\n            var args = Array.prototype.slice.call(arguments);\n\n            args.unshift(this());\n\n            return _.pluck.apply(_, args);\n        }\n    });\n});\n","Magento_Ui/js/lib/knockout/extender/bound-nodes.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'underscore',\n    'mage/utils/wrapper',\n    'uiEvents'\n], function (ko, _, wrapper, Events) {\n    'use strict';\n\n    var nodesMap = new WeakMap();\n\n    /**\n     * Returns a array of nodes associated with a specified model.\n     *\n     * @param {Object} model\n     * @returns {Undefined|Array}\n     */\n    function getBounded(model) {\n        return nodesMap.get(model);\n    }\n\n    /**\n     * Removes specified node to models' associations list, if it's\n     * a root node (node is not a descendant of any previously added nodes).\n     * Triggers 'addNode' event.\n     *\n     * @param {Object} model\n     * @param {HTMLElement} node\n     */\n    function addBounded(model, node) {\n        var nodes = getBounded(model),\n            isRoot;\n\n        if (!nodes) {\n            nodesMap.set(model, [node]);\n\n            Events.trigger.call(model, 'addNode', node);\n\n            return;\n        }\n\n        isRoot = nodes.every(function (bounded) {\n            return !bounded.contains(node);\n        });\n\n        if (isRoot) {\n            nodes.push(node);\n\n            Events.trigger.call(model, 'addNode', node);\n        }\n    }\n\n    /**\n     * Removes specified node from models' associations list.\n     * Triggers 'removeNode' event.\n     *\n     * @param {Object} model\n     * @param {HTMLElement} node\n     */\n    function removeBounded(model, node) {\n        var nodes = getBounded(model),\n            index;\n\n        if (!nodes) {\n            return;\n        }\n\n        index = nodes.indexOf(node);\n\n        if (~index) {\n            nodes.splice(index, 0);\n\n            Events.trigger.call(model, 'removeNode', node);\n        }\n\n        if (!nodes.length) {\n            nodesMap.delete(model);\n        }\n    }\n\n    /**\n     * Returns node's first sibling of 'element' type within the common component scope\n     *\n     * @param {HTMLElement} node\n     * @param {*} data\n     * @returns {HTMLElement}\n     */\n    function getElement(node, data) {\n        var elem;\n\n        while (node.nextElementSibling) {\n            node = node.nextElementSibling;\n\n            if (node.nodeType === 1 && ko.dataFor(node) === data) {\n                elem = node;\n                break;\n            }\n        }\n\n        return elem;\n    }\n\n    wrapper.extend(ko, {\n\n        /**\n         * Extends knockouts' 'applyBindings'\n         * to track nodes associated with model.\n         *\n         * @param {Function} orig - Original 'applyBindings' method.\n         * @param {Object} ctx\n         * @param {HTMLElement} node - Original 'applyBindings' method.\n         */\n        applyBindings: function (orig, ctx, node) {\n            var result = orig(),\n                data = ctx && (ctx.$data || ctx);\n\n            if (node && node.nodeType === 8) {\n                node = getElement(node, data);\n            }\n\n            if (!node || node.nodeType !== 1) {\n                return result;\n            }\n\n            if (data && data.registerNodes) {\n                addBounded(data, node);\n            }\n\n            return result;\n        },\n\n        /**\n         * Extends knockouts' cleanNode\n         * to track nodes associated with model.\n         *\n         * @param {Function} orig - Original 'cleanNode' method.\n         * @param {HTMLElement} node - Original 'cleanNode' method.\n         */\n        cleanNode: function (orig, node) {\n            var result = orig(),\n                data;\n\n            if (node.nodeType !== 1) {\n                return result;\n            }\n\n            data = ko.dataFor(node);\n\n            if (data && data.registerNodes) {\n                removeBounded(data, node);\n            }\n\n            return result;\n        }\n    });\n\n    return {\n\n        /**\n         * Returns root nodes associated with a model. If callback is provided,\n         * will iterate through all of the present nodes triggering callback\n         * for each of it. Also it will subscribe to the 'addNode' event.\n         *\n         * @param {Object} model\n         * @param {Function} [callback]\n         * @returns {Array|Undefined}\n         */\n        get: function (model, callback) {\n            var nodes = getBounded(model) || [];\n\n            if (!_.isFunction(callback)) {\n                return nodes;\n            }\n\n            nodes.forEach(function (node) {\n                callback(node);\n            });\n\n            this.add.apply(this, arguments);\n        },\n\n        /**\n         * Subscribes to adding of nodes associated with a model.\n         *\n         * @param {Object} model\n         */\n        add: function (model) {\n            var args = _.toArray(arguments).slice(1);\n\n            args.unshift('addNode');\n\n            Events.on.apply(model, args);\n        },\n\n        /**\n         * Subscribes to removal of nodes associated with a model.\n         *\n         * @param {Object} model\n         */\n        remove: function (model) {\n            var args = _.toArray(arguments).slice(1);\n\n            args.unshift('removeNode');\n\n            Events.on.apply(model, args);\n        },\n\n        /**\n         * Removes subscriptions from the model.\n         *\n         * @param {Object} model\n         */\n        off: function (model) {\n            var args = _.toArray(arguments).slice(1);\n\n            Events.off.apply(model, args);\n        }\n    };\n});\n","Magento_Ui/js/lib/core/events.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'underscore'\n], function (ko, _) {\n    'use strict';\n\n    var eventsMap = new WeakMap();\n\n    /**\n     * Returns events map or a specific event\n     * data associated with a provided object.\n     *\n     * @param {Object} obj - Key in the events weakmap.\n     * @param {String} [name] - Name of the event.\n     * @returns {Map|Array|Boolean}\n     */\n    function getEvents(obj, name) {\n        var events = eventsMap.get(obj);\n\n        if (!events) {\n            return false;\n        }\n\n        return name ? events.get(name) : events;\n    }\n\n    /**\n     * Adds new event handler.\n     *\n     * @param {Object} obj - Key in the events weakmap.\n     * @param {String} ns - Callback namespace.\n     * @param {Function} callback - Event callback.\n     * @param {String} name - Name of the event.\n     */\n    function addHandler(obj, ns, callback, name) {\n        var events      = getEvents(obj),\n            observable,\n            data;\n\n        observable = !ko.isObservable(obj[name]) ?\n            ko.getObservable(obj, name) :\n            obj[name];\n\n        if (observable) {\n            observable.subscribe(callback);\n\n            return;\n        }\n\n        if (!events) {\n            events = new Map();\n\n            eventsMap.set(obj, events);\n        }\n\n        data = {\n            callback: callback,\n            ns: ns\n        };\n\n        events.has(name) ?\n            events.get(name).push(data) :\n            events.set(name, [data]);\n    }\n\n    /**\n     * Invokes provided callbacks with a specified arguments.\n     *\n     * @param {Array} handlers\n     * @param {Array} args\n     * @returns {Boolean}\n     */\n    function trigger(handlers, args) {\n        var bubble = true,\n            callback;\n\n        handlers.forEach(function (handler) {\n            callback = handler.callback;\n\n            if (callback.apply(null, args) === false) {\n                bubble = false;\n            }\n        });\n\n        return bubble;\n    }\n\n    return {\n\n        /**\n         * Calls callback when name event is triggered.\n         * @param  {String}   events\n         * @param  {Function} callback\n         * @param  {Function} ns\n         * @return {Object} reference to this\n         */\n        on: function (events, callback, ns) {\n            var iterator;\n\n            if (arguments.length < 2) {\n                ns = callback;\n            }\n\n            iterator = addHandler.bind(null, this, ns);\n\n            _.isObject(events) ?\n                _.each(events, iterator) :\n                iterator(callback, events);\n\n            return this;\n        },\n\n        /**\n         * Removed callback from listening to target event\n         * @param  {String} ns\n         * @return {Object} reference to this\n         */\n        off: function (ns) {\n            var storage = getEvents(this);\n\n            if (!storage) {\n                return this;\n            }\n\n            storage.forEach(function (handlers, name) {\n                handlers = handlers.filter(function (handler) {\n                    return !ns ? false : handler.ns !== ns;\n                });\n\n                handlers.length ?\n                    storage.set(name, handlers) :\n                    storage.delete(name);\n            });\n\n            return this;\n        },\n\n        /**\n         * Triggers event and executes all attached callbacks.\n         *\n         * @param {String} name - Name of the event to be triggered.\n         * @returns {Boolean}\n         */\n        trigger: function (name) {\n            var handlers,\n                args;\n\n            handlers = getEvents(this, name),\n            args = _.toArray(arguments).slice(1);\n\n            if (!handlers || !name) {\n                return true;\n            }\n\n            return trigger(handlers, args);\n        }\n    };\n});\n","Magento_Ui/js/lib/core/collection.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'mageUtils',\n    'uiRegistry',\n    'uiElement'\n], function (_, utils, registry, Element) {\n    'use strict';\n\n    /**\n     * Removes non plain object items from the specified array.\n     *\n     * @param {Array} container - Array whose value should be filtered.\n     * @returns {Array}\n     */\n    function compact(container) {\n        return _.values(container).filter(utils.isObject);\n    }\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 _findIndex(item, container) {\n        var index = _.findKey(container, function (value) {\n            return value === item;\n        });\n\n        if (typeof index === 'undefined') {\n            index = _.findKey(container, function (value) {\n                return value && value.name === item;\n            });\n        }\n\n        return typeof index === 'undefined' ? -1 : index;\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    function _insertAt(item, container, position) {\n        var currentIndex = _findIndex(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 = _findIndex(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    return Element.extend({\n        defaults: {\n            template: 'ui/collection',\n            _elems: [],\n            ignoreTmpls: {\n                childDefaults: true\n            }\n        },\n\n        /**\n         * Initializes observable properties.\n         *\n         * @returns {Model} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .observe({\n                    elems: []\n                });\n\n            return this;\n        },\n\n        /**\n         * Called when another element was added to current component.\n         *\n         * @param {Object} elem - Instance of an element that was added.\n         * @returns {Collection} Chainable.\n         */\n        initElement: function (elem) {\n            elem.initContainer(this);\n\n            return this;\n        },\n\n        /**\n         * Returns instance of a child found by provided index.\n         *\n         * @param {String} index - Index of a child.\n         * @returns {Object}\n         */\n        getChild: function (index) {\n            return _.findWhere(this.elems(), {\n                index: index\n            });\n        },\n\n        /**\n         * Requests specified components to insert\n         * them into 'elems' array starting from provided position.\n         *\n         * @param {(String|Array)} elems - Name of the component to insert.\n         * @param {Number} [position=-1] - Position at which to insert elements.\n         * @returns {Collection} Chainable.\n         */\n        insertChild: function (elems, position) {\n            var container   = this._elems,\n                insert      = this._insert.bind(this),\n                update;\n\n            if (!Array.isArray(elems)) {\n                elems = [elems];\n            }\n\n            elems.map(function (item) {\n                return item.elem ?\n                    _insertAt(item.elem, container, item.position) :\n                    _insertAt(item, container, position);\n            }).forEach(function (item) {\n                if (item === true) {\n                    update = true;\n                } else if (_.isString(item)) {\n                    registry.get(item, insert);\n                } else if (utils.isObject(item)) {\n                    insert(item);\n                }\n            });\n\n            if (update) {\n                this._updateCollection();\n            }\n\n            return this;\n        },\n\n        /**\n         * Removes specified child from collection.\n         *\n         * @param {(Object|String)} elem - Child or index of a child to be removed.\n         * @param {Boolean} skipUpdate - skip collection update when element to be destroyed.\n         *\n         * @returns {Collection} Chainable.\n         */\n        removeChild: function (elem, skipUpdate) {\n            if (_.isString(elem)) {\n                elem = this.getChild(elem);\n            }\n\n            if (elem) {\n                utils.remove(this._elems, elem);\n\n                if (!skipUpdate) {\n                    this._updateCollection();\n                }\n            }\n\n            return this;\n        },\n\n        /**\n         * Destroys collection children with its' elements.\n         */\n        destroyChildren: function () {\n            this.elems.each(function (elem) {\n                elem.destroy(true);\n            });\n\n            this._updateCollection();\n        },\n\n        /**\n         * Clear data. Call method \"clear\"\n         * in child components\n         *\n         * @returns {Object} Chainable.\n         */\n        clear: function () {\n            var elems = this.elems();\n\n            _.each(elems, function (elem) {\n                if (_.isFunction(elem.clear)) {\n                    elem.clear();\n                }\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Checks if specified child exists in collection.\n         *\n         * @param {String} index - Index of a child.\n         * @returns {Boolean}\n         */\n        hasChild: function (index) {\n            return !!this.getChild(index);\n        },\n\n        /**\n         * Creates 'async' wrapper for the specified child\n         * using uiRegistry 'async' method and caches it\n         * in a '_requested' components  object.\n         *\n         * @param {String} index - Index of a child.\n         * @returns {Function} Async module wrapper.\n         */\n        requestChild: function (index) {\n            var name = this.formChildName(index);\n\n            return this.requestModule(name);\n        },\n\n        /**\n         * Creates complete child name based on a provided index.\n         *\n         * @param {String} index - Index of a child.\n         * @returns {String}\n         */\n        formChildName: function (index) {\n            return this.name + '.' + index;\n        },\n\n        /**\n         * Retrieves requested region.\n         * Creates region if it was not created yet\n         *\n         * @returns {ObservableArray}\n         */\n        getRegion: function (name) {\n            var regions = this.regions = this.regions || {};\n\n            if (!regions[name]) {\n                regions[name] = [];\n\n                this.observe.call(regions, name);\n            }\n\n            return regions[name];\n        },\n\n        /**\n         * Checks if the specified region has any elements\n         * associated with it.\n         *\n         * @param {String} name\n         * @returns {Boolean}\n         */\n        regionHasElements: function (name) {\n            var region = this.getRegion(name);\n\n            return region().length > 0;\n        },\n\n        /**\n         * Replaces specified regions' data with a provided one.\n         * Creates region if it was not created yet.\n         *\n         * @param {Array} items - New regions' data.\n         * @param {String} name - Name of the region.\n         * @returns {Collection} Chainable.\n         */\n        updateRegion: function (items, name) {\n            this.getRegion(name)(items);\n\n            return this;\n        },\n\n        /**\n         * Destroys collection along with its' elements.\n         */\n        destroy: function () {\n            this._super();\n\n            this.elems.each('destroy');\n        },\n\n        /**\n         * Inserts provided component into 'elems' array at a specified position.\n         * @private\n         *\n         * @param {Object} elem - Element to insert.\n         */\n        _insert: function (elem) {\n            var index = _.findKey(this._elems, function (value) {\n                return value === elem.name;\n            });\n\n            if (typeof index !== 'undefined') {\n                this._elems[index] = elem;\n            }\n\n            this._updateCollection()\n                .initElement(elem);\n        },\n\n        /**\n         * Synchronizes multiple elements arrays with a core '_elems' container.\n         * Performs elemets grouping by theirs 'displayArea' property.\n         * @private\n         *\n         * @returns {Collection} Chainable.\n         */\n        _updateCollection: function () {\n            var _elems = compact(this._elems),\n                grouped;\n\n            grouped = _elems.filter(function (elem) {\n                return elem.displayArea && _.isString(elem.displayArea);\n            });\n            grouped = _.groupBy(grouped, 'displayArea');\n\n            _.each(grouped, this.updateRegion, this);\n\n            _.each(this.regions, function (items) {\n                var hasObsoleteComponents = items().length && !_.intersection(_elems, items()).length;\n\n                if (hasObsoleteComponents) {\n                    items.removeAll();\n                }\n            });\n\n            this.elems(_elems);\n\n            return this;\n        },\n\n        /**\n         * Tries to call specified method of a current component,\n         * otherwise delegates attempt to its' children.\n         *\n         * @param {String} target - Name of the method.\n         * @param {...*} parameters - Arguments that will be passed to method.\n         * @returns {*} Result of the method calls.\n         */\n        delegate: function (target) {\n            var args = _.toArray(arguments);\n\n            target = this[target];\n\n            if (_.isFunction(target)) {\n                return target.apply(this, args.slice(1));\n            }\n\n            return this._delegate(args);\n        },\n\n        /**\n         * Calls 'delegate' method of all of it's children components.\n         * @private\n         *\n         * @param {Array} args - An array of arguments to pass to the next delegation call.\n         * @returns {Array} An array of delegation results.\n         */\n        _delegate: function (args) {\n            var result;\n\n            result = this.elems.map(function (elem) {\n                var target;\n\n                if (!_.isFunction(elem.delegate)) {\n                    target = elem[args[0]];\n\n                    if (_.isFunction(target)) {\n                        return target.apply(elem, args.slice(1));\n                    }\n                } else {\n                    return elem.delegate.apply(elem, args);\n                }\n            });\n\n            return _.flatten(result);\n        }\n    });\n});\n","Magento_Ui/js/lib/core/class.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'mageUtils',\n    'mage/utils/wrapper'\n], function (_, utils, wrapper) {\n    'use strict';\n\n    var Class;\n\n    /**\n     * Returns property of an object if\n     * it's his own property.\n     *\n     * @param {Object} obj - Object whose property should be retrieved.\n     * @param {String} prop - Name of the property.\n     * @returns {*} Value of the property or false.\n     */\n    function getOwn(obj, prop) {\n        return _.isObject(obj) && obj.hasOwnProperty(prop) && obj[prop];\n    }\n\n    /**\n     * Creates constructor function which allows\n     * initialization without usage of a 'new' operator.\n     *\n     * @param {Object} protoProps - Prototypal properties of a new constructor.\n     * @param {Function} constructor\n     * @returns {Function} Created constructor.\n     */\n    function createConstructor(protoProps, constructor) {\n        var UiClass = constructor;\n\n        if (!UiClass) {\n\n            /**\n             * Default constructor function.\n             */\n            UiClass = function () {\n                var obj = this;\n\n                if (!_.isObject(obj) || Object.getPrototypeOf(obj) !== UiClass.prototype) {\n                    obj = Object.create(UiClass.prototype);\n                }\n\n                obj.initialize.apply(obj, arguments);\n\n                return obj;\n            };\n        }\n\n        UiClass.prototype = protoProps;\n        UiClass.prototype.constructor = UiClass;\n\n        return UiClass;\n    }\n\n    Class = createConstructor({\n\n        /**\n         * Entry point to the initialization of constructor's instance.\n         *\n         * @param {Object} [options={}]\n         * @returns {Class} Chainable.\n         */\n        initialize: function (options) {\n            this.initConfig(options);\n\n            return this;\n        },\n\n        /**\n         * Recursively extends data specified in constructors' 'defaults'\n         * property with provided options object. Evaluates resulting\n         * object using string templates (see: mage/utils/template.js).\n         *\n         * @param {Object} [options={}]\n         * @returns {Class} Chainable.\n         */\n        initConfig: function (options) {\n            var defaults    = this.constructor.defaults,\n                config      = utils.extend({}, defaults, options || {}),\n                ignored     = config.ignoreTmpls || {},\n                cached      = utils.omit(config, ignored);\n\n            config = utils.template(config, this, false, true);\n\n            _.each(cached, function (value, key) {\n                utils.nested(config, key, value);\n            });\n\n            return _.extend(this, config);\n        }\n    });\n\n    _.extend(Class, {\n        defaults: {\n            ignoreTmpls: {\n                templates: true\n            }\n        },\n\n        /**\n         * Creates new constructor based on a current prototype properties,\n         * extending them with properties specified in 'exender' object.\n         *\n         * @param {Object} [extender={}]\n         * @returns {Function} New constructor.\n         */\n        extend: function (extender) {\n            var parent      = this,\n                parentProto = parent.prototype,\n                childProto  = Object.create(parentProto),\n                child       = createConstructor(childProto, getOwn(extender, 'constructor')),\n                defaults;\n\n            extender = extender || {};\n            defaults = extender.defaults;\n\n            delete extender.defaults;\n\n            _.each(extender, function (method, name) {\n                childProto[name] = wrapper.wrapSuper(parentProto[name], method);\n            });\n\n            child.defaults = utils.extend({}, parent.defaults || {});\n\n            if (defaults) {\n                utils.extend(child.defaults, defaults);\n                extender.defaults = defaults;\n            }\n\n            return _.extend(child, {\n                __super__:  parentProto,\n                extend:     parent.extend\n            });\n        }\n    });\n\n    return Class;\n});\n","Magento_Ui/js/lib/core/element/element.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'ko',\n    'underscore',\n    'mageUtils',\n    'uiRegistry',\n    'uiEvents',\n    'uiClass',\n    './links',\n    '../storage/local'\n], function (ko, _, utils, registry, Events, Class, links) {\n    'use strict';\n\n    var Element;\n\n    /**\n     * Creates observable property using knockouts'\n     * 'observableArray' or 'observable' methods,\n     * depending on a type of 'value' parameter.\n     *\n     * @param {Object} obj - Object to whom property belongs.\n     * @param {String} key - Key of the property.\n     * @param {*} value - Initial value.\n     */\n    function observable(obj, key, value) {\n        var method = Array.isArray(value) ? 'observableArray' : 'observable';\n\n        if (_.isFunction(obj[key]) && !ko.isObservable(obj[key])) {\n            return;\n        }\n\n        if (ko.isObservable(value)) {\n            value = value();\n        }\n\n        ko.isObservable(obj[key]) ?\n            obj[key](value) :\n            obj[key] = ko[method](value);\n    }\n\n    /**\n     * Creates observable property using 'track' method.\n     *\n     * @param {Object} obj - Object to whom property belongs.\n     * @param {String} key - Key of the property.\n     * @param {*} value - Initial value.\n     */\n    function accessor(obj, key, value) {\n        if (_.isFunction(obj[key]) || ko.isObservable(obj[key])) {\n            return;\n        }\n\n        obj[key] = value;\n\n        if (!ko.es5.isTracked(obj, key)) {\n            ko.track(obj, [key]);\n        }\n    }\n\n    Element = _.extend({\n        defaults: {\n            _requested: {},\n            containers: [],\n            exports: {},\n            imports: {},\n            links: {},\n            listens: {},\n            name: '',\n            ns: '${ $.name.split(\".\")[0] }',\n            provider: '',\n            registerNodes: true,\n            source: null,\n            statefull: {},\n            template: '',\n            tracks: {},\n            storageConfig: {\n                provider: 'localStorage',\n                namespace: '${ $.name }',\n                path: '${ $.storageConfig.provider }:${ $.storageConfig.namespace }'\n            },\n            maps: {\n                imports: {},\n                exports: {}\n            },\n            modules: {\n                storage: '${ $.storageConfig.provider }'\n            }\n        },\n\n        /**\n         * Initializes model instance.\n         *\n         * @returns {Element} Chainable.\n         */\n        initialize: function () {\n            this._super()\n                .initObservable()\n                .initModules()\n                .initStatefull()\n                .initLinks()\n                .initUnique();\n\n            return this;\n        },\n\n        /**\n         * Initializes observable properties.\n         *\n         * @returns {Element} Chainable.\n         */\n        initObservable: function () {\n            _.each(this.tracks, function (enabled, key) {\n                if (enabled) {\n                    this.track(key);\n                }\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Parses 'modules' object and creates\n         * async wrappers for specified components.\n         *\n         * @returns {Element} Chainable.\n         */\n        initModules: function () {\n            _.each(this.modules, function (name, property) {\n                if (name) {\n                    this[property] = this.requestModule(name);\n                }\n            }, this);\n\n            if (!_.isFunction(this.source)) {\n                this.source = registry.get(this.provider);\n            }\n\n            return this;\n        },\n\n        /**\n         * Called when current element was injected to another component.\n         *\n         * @param {Object} parent - Instance of a 'parent' component.\n         * @returns {Collection} Chainable.\n         */\n        initContainer: function (parent) {\n            this.containers.push(parent);\n\n            return this;\n        },\n\n        /**\n         * Initializes statefull properties\n         * based on the keys of 'statefull' object.\n         *\n         * @returns {Element} Chainable.\n         */\n        initStatefull: function () {\n            _.each(this.statefull, function (path, key) {\n                if (path) {\n                    this.setStatefull(key, path);\n                }\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Initializes links between properties.\n         *\n         * @returns {Element} Chainbale.\n         */\n        initLinks: function () {\n            return this.setListeners(this.listens)\n                       .setLinks(this.links, 'imports')\n                       .setLinks(this.links, 'exports')\n                       .setLinks(this.exports, 'exports')\n                       .setLinks(this.imports, 'imports');\n        },\n\n        /**\n         * Initializes listeners of the unique property.\n         *\n         * @returns {Element} Chainable.\n         */\n        initUnique: function () {\n            var update = this.onUniqueUpdate.bind(this),\n                uniqueNs = this.uniqueNs;\n\n            this.hasUnique = this.uniqueProp && uniqueNs;\n\n            if (this.hasUnique) {\n                this.source.on(uniqueNs, update, this.name);\n            }\n\n            return this;\n        },\n\n        /**\n         * Makes specified property to be stored automatically.\n         *\n         * @param {String} key - Name of the property\n         *      that will be stored.\n         * @param {String} [path=key] - Path to the property in storage.\n         * @returns {Element} Chainable.\n         */\n        setStatefull: function (key, path) {\n            var link = {};\n\n            path        = !_.isString(path) || !path ? key : path;\n            link[key]   = this.storageConfig.path + '.' + path;\n\n            this.setLinks(link, 'imports')\n                .setLinks(link, 'exports');\n\n            return this;\n        },\n\n        /**\n         * Updates property specified in uniqueNs\n         * if elements' unique property is set to 'true'.\n         *\n         * @returns {Element} Chainable.\n         */\n        setUnique: function () {\n            var property = this.uniqueProp;\n\n            if (this[property]()) {\n                this.source.set(this.uniqueNs, this.name);\n            }\n\n            return this;\n        },\n\n        /**\n         * Creates 'async' wrapper for the specified component\n         * using uiRegistry 'async' method and caches it\n         * in a '_requested' components  object.\n         *\n         * @param {String} name - Name of requested component.\n         * @returns {Function} Async module wrapper.\n         */\n        requestModule: function (name) {\n            var requested = this._requested;\n\n            if (!requested[name]) {\n                requested[name] = registry.async(name);\n            }\n\n            return requested[name];\n        },\n\n        /**\n         * Returns path to elements' template.\n         *\n         * @returns {String}\n         */\n        getTemplate: function () {\n            return this.template;\n        },\n\n        /**\n         * Checks if template was specified for an element.\n         *\n         * @returns {Boolean}\n         */\n        hasTemplate: function () {\n            return !!this.template;\n        },\n\n        /**\n         * Returns value of the nested property.\n         *\n         * @param {String} path - Path to the property.\n         * @returns {*} Value of the property.\n         */\n        get: function (path) {\n            return utils.nested(this, path);\n        },\n\n        /**\n         * Sets provided value as a value of the specified nested property.\n         * Triggers changes notifications, if value has mutated.\n         *\n         * @param {String} path - Path to property.\n         * @param {*} value - New value of the property.\n         * @returns {Element} Chainable.\n         */\n        set: function (path, value) {\n            var data = this.get(path),\n                diffs;\n\n            diffs = !_.isFunction(data) && !this.isTracked(path) ?\n                utils.compare(data, value, path) :\n                false;\n\n            utils.nested(this, path, value);\n\n            if (diffs) {\n                this._notifyChanges(diffs);\n            }\n\n            return this;\n        },\n\n        /**\n         * Removes nested property from the object.\n         *\n         * @param {String} path - Path to the property.\n         * @returns {Element} Chainable.\n         */\n        remove: function (path) {\n            var data = utils.nested(this, path),\n                diffs;\n\n            if (_.isUndefined(data) || _.isFunction(data)) {\n                return this;\n            }\n\n            diffs = utils.compare(data, undefined, path);\n\n            utils.nestedRemove(this, path);\n\n            this._notifyChanges(diffs);\n\n            return this;\n        },\n\n        /**\n         * Creates observable properties for the current object.\n         *\n         * If 'useTrack' flag is set to 'true' then each property will be\n         * created with a ES5 get/set accessor descriptors, instead of\n         * making them an observable functions.\n         * See 'knockout-es5' library for more information.\n         *\n         * @param {Boolean} [useAccessors=false] - Whether to create an\n         *      observable function or to use property accesessors.\n         * @param {(Object|String|Array)} properties - List of observable properties.\n         * @returns {Element} Chainable.\n         *\n         * @example Sample declaration and equivalent knockout methods.\n         *      this.key = 'value';\n         *      this.array = ['value'];\n         *\n         *      this.observe(['key', 'array']);\n         *      =>\n         *          this.key = ko.observable('value');\n         *          this.array = ko.observableArray(['value']);\n         *\n         * @example Another syntaxes of the previous example.\n         *      this.observe({\n         *          key: 'value',\n         *          array: ['value']\n         *      });\n         */\n        observe: function (useAccessors, properties) {\n            var model = this,\n                trackMethod;\n\n            if (typeof useAccessors !== 'boolean') {\n                properties   = useAccessors;\n                useAccessors = false;\n            }\n\n            trackMethod = useAccessors ? accessor : observable;\n\n            if (_.isString(properties)) {\n                properties = properties.split(' ');\n            }\n\n            if (Array.isArray(properties)) {\n                properties.forEach(function (key) {\n                    trackMethod(model, key, model[key]);\n                });\n            } else if (typeof properties === 'object') {\n                _.each(properties, function (value, key) {\n                    trackMethod(model, key, value);\n                });\n            }\n\n            return this;\n        },\n\n        /**\n         * Delegates call to 'observe' method but\n         * with a predefined 'useAccessors' flag.\n         *\n         * @param {(String|Array|Object)} properties - List of observable properties.\n         * @returns {Element} Chainable.\n         */\n        track: function (properties) {\n            this.observe(true, properties);\n\n            return this;\n        },\n\n        /**\n         * Checks if specified property is tracked.\n         *\n         * @param {String} property - Property to be checked.\n         * @returns {Boolean}\n         */\n        isTracked: function (property) {\n            return ko.es5.isTracked(this, property);\n        },\n\n        /**\n         * Invokes subscribers for the provided changes.\n         *\n         * @param {Object} diffs - Object with changes descriptions.\n         * @returns {Element} Chainable.\n         */\n        _notifyChanges: function (diffs) {\n            diffs.changes.forEach(function (change) {\n                this.trigger(change.path, change.value, change);\n            }, this);\n\n            _.each(diffs.containers, function (changes, name) {\n                var value = utils.nested(this, name);\n\n                this.trigger(name, value, changes);\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Extracts all stored data and sets it to element.\n         *\n         * @returns {Element} Chainable.\n         */\n        restore: function () {\n            var ns = this.storageConfig.namespace,\n                storage = this.storage();\n\n            if (storage) {\n                utils.extend(this, storage.get(ns));\n            }\n\n            return this;\n        },\n\n        /**\n         * Stores value of the specified property in components' storage module.\n         *\n         * @param {String} property\n         * @param {*} [data=this[property]]\n         * @returns {Element} Chainable.\n         */\n        store: function (property, data) {\n            var ns = this.storageConfig.namespace,\n                path = utils.fullPath(ns, property);\n\n            if (arguments.length < 2) {\n                data = this.get(property);\n            }\n\n            this.storage('set', path, data);\n\n            return this;\n        },\n\n        /**\n         * Extracts specified property from storage.\n         *\n         * @param {String} [property] - Name of the property\n         *      to be extracted. If not specified then all of the\n         *      stored will be returned.\n         * @returns {*}\n         */\n        getStored: function (property) {\n            var ns = this.storageConfig.namespace,\n                path = utils.fullPath(ns, property),\n                storage = this.storage(),\n                data;\n\n            if (storage) {\n                data = storage.get(path);\n            }\n\n            return data;\n        },\n\n        /**\n         * Removes stored property.\n         *\n         * @param {String} property - Property to be removed from storage.\n         * @returns {Element} Chainable.\n         */\n        removeStored: function (property) {\n            var ns = this.storageConfig.namespace,\n                path = utils.fullPath(ns, property);\n\n            this.storage('remove', path);\n\n            return this;\n        },\n\n        /**\n         * Destroys current instance along with all of its' children.\n         * @param {Boolean} skipUpdate - skip collection update when element to be destroyed.\n         */\n        destroy: function (skipUpdate) {\n            this._dropHandlers()\n                ._clearRefs(skipUpdate);\n        },\n\n        /**\n         * Removes events listeners.\n         * @private\n         *\n         * @returns {Element} Chainable.\n         */\n        _dropHandlers: function () {\n            this.off();\n\n            if (_.isFunction(this.source)) {\n                this.source().off(this.name);\n            } else if (this.source) {\n                this.source.off(this.name);\n            }\n\n            return this;\n        },\n\n        /**\n         * Removes all references to current instance and\n         * calls 'destroy' method on all of its' children.\n         * @private\n         * @param {Boolean} skipUpdate - skip collection update when element to be destroyed.\n         *\n         * @returns {Element} Chainable.\n         */\n        _clearRefs: function (skipUpdate) {\n            registry.remove(this.name);\n\n            this.containers.forEach(function (parent) {\n                parent.removeChild(this, skipUpdate);\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Overrides 'EventsBus.trigger' method to implement events bubbling.\n         *\n         * @param {...*} arguments - Any number of arguments that should be passed to the events' handler.\n         * @returns {Boolean} False if event bubbling was canceled.\n         */\n        bubble: function () {\n            var args = _.toArray(arguments),\n                bubble = this.trigger.apply(this, args),\n                result;\n\n            if (!bubble) {\n                return false;\n            }\n\n            this.containers.forEach(function (parent) {\n                result = parent.bubble.apply(parent, args);\n\n                if (result === false) {\n                    bubble = false;\n                }\n            });\n\n            return !!bubble;\n        },\n\n        /**\n         * Callback which fires when property under uniqueNs has changed.\n         */\n        onUniqueUpdate: function (name) {\n            var active = name === this.name,\n                property = this.uniqueProp;\n\n            this[property](active);\n        },\n\n        /**\n         * Clean data form data source.\n         *\n         * @returns {Element}\n         */\n        cleanData: function () {\n            if (this.source && this.source.componentType === 'dataSource') {\n                if (this.elems) {\n                    _.each(this.elems(), function (val) {\n                        val.cleanData();\n                    });\n                } else {\n                    this.source.remove(this.dataScope);\n                }\n            }\n\n            return this;\n        },\n\n        /**\n         * Fallback data.\n         */\n        cacheData: function () {\n            this.cachedComponent = utils.copy(this);\n        },\n\n        /**\n         * Update configuration in component.\n         *\n         * @param {*} oldValue\n         * @param {*} newValue\n         * @param {String} path - path to value.\n         * @returns {Element}\n         */\n        updateConfig: function (oldValue, newValue, path) {\n            var names = path.split('.'),\n                index = _.lastIndexOf(names, 'config') + 1;\n\n            names = names.splice(index, names.length - index).join('.');\n            this.set(names, newValue);\n\n            return this;\n        }\n    }, Events, links);\n\n    return Class.extend(Element);\n});\n","Magento_Ui/js/lib/core/element/links.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'underscore',\n    'mageUtils',\n    'uiRegistry'\n], function (ko, _, utils, registry) {\n    'use strict';\n\n    /**\n     * Parse provided data.\n     *\n     * @param {String} placeholder\n     * @param {String} data\n     * @param {String} direction\n     * @returns {Boolean|Object}\n     */\n    function parseData(placeholder, data, direction) {\n        if (typeof data !== 'string') {\n            return false;\n        }\n\n        data = data.split(':');\n\n        if (!data[0]) {\n            return false;\n        }\n\n        if (!data[1]) {\n            data[1] = data[0];\n            data[0] = placeholder;\n        }\n\n        return {\n            target: data[0],\n            property: data[1],\n            direction: direction\n        };\n    }\n\n    /**\n     * Check if value not empty.\n     *\n     * @param {*} value\n     * @returns {Boolean}\n     */\n    function notEmpty(value) {\n        return typeof value !== 'undefined' && value != null;\n    }\n\n    /**\n     * Update value for linked component.\n     *\n     * @param {Object} data\n     * @param {Object} owner\n     * @param {Object} target\n     * @param {*} value\n     */\n    function updateValue(data, owner, target, value) {\n        var component = target.component,\n            property = target.property,\n            linked = data.linked;\n\n        if (data.mute) {\n            return;\n        }\n\n        if (linked) {\n            linked.mute = true;\n        }\n\n        if (owner.component !== target.component) {\n            value = data.inversionValue ? !utils.copy(value) : utils.copy(value);\n        }\n\n        component.set(property, value, owner);\n\n        if (property === 'disabled' && value) {\n            component.set('validate', value, owner);\n        }\n\n        if (linked) {\n            linked.mute = false;\n        }\n    }\n\n    /**\n     * Get value form owner component property.\n     *\n     * @param {Object} owner\n     * @returns {*}\n     */\n    function getValue(owner) {\n        var component = owner.component,\n            property = owner.property;\n\n        return component.get(property);\n    }\n\n    /**\n     * Format provided params to object.\n     *\n     * @param {String} ownerComponent\n     * @param {String} targetComponent\n     * @param {String} ownerProp\n     * @param {String} targetProp\n     * @param {String} direction\n     * @returns {Object}\n     */\n    function form(ownerComponent, targetComponent, ownerProp, targetProp, direction) {\n        var result,\n            tmp;\n\n        result = {\n            owner: {\n                component: ownerComponent,\n                property: ownerProp\n            },\n            target: {\n                component: targetComponent,\n                property: targetProp\n            }\n        };\n\n        if (direction === 'exports') {\n            tmp = result.owner;\n            result.owner = result.target;\n            result.target = tmp;\n        }\n\n        return result;\n    }\n\n    /**\n     * Set data to linked property.\n     *\n     * @param {Object} map\n     * @param {Object} data\n     */\n    function setLinked(map, data) {\n        var match;\n\n        if (!map) {\n            return;\n        }\n\n        match = _.findWhere(map, {\n            linked: false,\n            target: data.target,\n            property: data.property\n        });\n\n        if (match) {\n            match.linked = data;\n            data.linked = match;\n        }\n    }\n\n    /**\n     * Set data by direction.\n     *\n     * @param {Object} maps\n     * @param {String} property\n     * @param {Object} data\n     */\n    function setData(maps, property, data) {\n        var direction   = data.direction,\n            map         = maps[direction];\n\n        data.linked = false;\n\n        (map[property] = map[property] || []).push(data);\n\n        direction = direction === 'imports' ? 'exports' : 'imports';\n\n        setLinked(maps[direction][property], data);\n    }\n\n    /**\n     * Set links for components.\n     *\n     * @param {String} target\n     * @param {String} owner\n     * @param {Object} data\n     * @param {String} property\n     * @param {Boolean} immediate\n     */\n    function setLink(target, owner, data, property, immediate) {\n        var direction = data.direction,\n            formated = form(target, owner, data.property, property, direction),\n            callback,\n            value;\n\n        owner = formated.owner;\n        target = formated.target;\n\n        callback = updateValue.bind(null, data, owner, target);\n\n        owner.component.on(owner.property, callback, target.component.name);\n\n        if (immediate) {\n            value = getValue(owner);\n\n            if (notEmpty(value)) {\n                updateValue(data, owner, target, value);\n            }\n        }\n    }\n\n    /**\n     * Transfer data between components.\n     *\n     * @param {Object} owner\n     * @param {Object} data\n     */\n    function transfer(owner, data) {\n        var args = _.toArray(arguments);\n\n        if (data.target.substr(0, 1) === '!') {\n            data.target = data.target.substr(1);\n            data.inversionValue = true;\n        }\n\n        if (owner.name === data.target) {\n            args.unshift(owner);\n\n            setLink.apply(null, args);\n        } else {\n            registry.get(data.target, function (target) {\n                args.unshift(target);\n\n                setLink.apply(null, args);\n            });\n        }\n    }\n\n    return {\n        /**\n         * Assign listeners.\n         *\n         * @param {Object} listeners\n         * @returns {Object} Chainable\n         */\n        setListeners: function (listeners) {\n            var owner = this,\n                data;\n\n            _.each(listeners, function (callbacks, sources) {\n                sources = sources.split(' ');\n                callbacks = callbacks.split(' ');\n\n                sources.forEach(function (target) {\n                    callbacks.forEach(function (callback) {//eslint-disable-line max-nested-callbacks\n                        data = parseData(owner.name, target, 'imports');\n\n                        if (data) {\n                            setData(owner.maps, callback, data);\n                            transfer(owner, data, callback);\n                        }\n                    });\n                });\n            });\n\n            return this;\n        },\n\n        /**\n         * Set links in provided direction.\n         *\n         * @param {Object} links\n         * @param {String} direction\n         * @returns {Object} Chainable\n         */\n        setLinks: function (links, direction) {\n            var owner = this,\n                property,\n                data;\n\n            for (property in links) {\n                if (links.hasOwnProperty(property)) {\n                    data = parseData(owner.name, links[property], direction);\n\n                    if (data) {//eslint-disable-line max-depth\n                        setData(owner.maps, property, data);\n                        transfer(owner, data, property, true);\n                    }\n                }\n            }\n\n            return this;\n        }\n    };\n});\n","Magento_Ui/js/lib/core/storage/local.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'uiRegistry',\n    'mageUtils',\n    'uiEvents'\n], function (_, registry, utils, EventsBus) {\n    'use strict';\n\n    var root = 'appData',\n        localStorage,\n        hasSupport,\n        storage;\n\n    /**\n     * Flag which indicates whether localStorage is supported.\n     */\n    hasSupport = (function () {\n        var key = '_storageSupported';\n\n        try {\n            localStorage = window.localStorage;\n            localStorage.setItem(key, 'true');\n\n            if (localStorage.getItem(key) === 'true') {\n                localStorage.removeItem(key);\n\n                return true;\n            }\n\n            return false;\n        } catch (e) {\n            return false;\n        }\n    })();\n\n    if (!hasSupport) {\n        localStorage = {\n            _data: {},\n\n            /**\n             * Sets value of the specified item.\n             *\n             * @param {String} key - Key of the property.\n             * @param {*} value - Properties' value.\n             */\n            setItem: function (key, value) {\n                this._data[key] = value + '';\n            },\n\n            /**\n             * Retrieves specified item.\n             *\n             * @param {String} key - Key of the property to be retrieved.\n             */\n            getItem: function (key) {\n                return this._data[key];\n            },\n\n            /**\n             * Removes specified item.\n             *\n             * @param {String} key - Key of the property to be removed.\n             */\n            removeItem: function (key) {\n                delete this._data[key];\n            },\n\n            /**\n             * Removes all items.\n             */\n            clear: function () {\n                this._data = {};\n            }\n        };\n    }\n\n    /**\n     * Extracts and parses data stored in localStorage by the\n     * key specified in 'root' variable.\n     *\n     * @returns {Object}\n     */\n    function getRoot() {\n        var data = localStorage.getItem(root),\n            result = {};\n\n        if (!_.isNull(data) && typeof data != 'undefined') {\n            result = JSON.parse(data);\n        }\n\n        return result;\n    }\n\n    /**\n     * Writes provided data to the localStorage.\n     *\n     * @param {*} data - Data to be stored.\n     */\n    function setRoot(data) {\n        localStorage.setItem(root, JSON.stringify(data));\n    }\n\n    /**\n     * Provides methods to work with a localStorage\n     * as a single nested structure.\n     */\n    storage = _.extend({\n\n        /**\n         * Retrieves value of the specified property.\n         *\n         * @param {String} path - Path to the property.\n         *\n         * @example Retrieving data.\n         *      localStorage =>\n         *          'appData' => '\n         *              \"one\": {\"two\": \"three\"}\n         *          '\n         *      storage.get('one.two')\n         *      => \"three\"\n         *\n         *      storage.get('one')\n         *      => {\"two\": \"three\"}\n         */\n        get: function (path) {\n            var data = getRoot();\n\n            return utils.nested(data, path);\n        },\n\n        /**\n         * Sets specified data to the localStorage.\n         *\n         * @param {String} path - Path of the property.\n         * @param {*} value - Value of the property.\n         *\n         * @example Setting data.\n         *      storage.set('one.two', 'four');\n         *      => localStorage =>\n         *          'appData' => '\n         *              \"one\": {\"two\": \"four\"}\n         *          '\n         */\n        set: function (path, value) {\n            var data = getRoot();\n\n            utils.nested(data, path, value);\n\n            setRoot(data);\n        },\n\n        /**\n         * Removes specified data from the localStorage.\n         *\n         * @param {String} path - Path to the property that should be removed.\n         *\n         * @example Removing data.\n         *      storage.remove('one.two', 'four');\n         *      => localStorage =>\n         *          'appData' => '\n         *              \"one\": {}\n         *          '\n         */\n        remove: function (path) {\n            var data = getRoot();\n\n            utils.nestedRemove(data, path);\n\n            setRoot(data);\n        }\n    }, EventsBus);\n\n    registry.set('localStorage', storage);\n\n    return storage;\n});\n","Magento_SendFriend/requirejs-config.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\nvar config = {\n    map: {\n        '*': {\n            'Magento_SendFriend/back-event': 'Magento_SendFriend/js/back-event'\n        }\n    }\n};\n","Magento_SendFriend/js/back-event.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 (config, element) {\n        $(element).on('click', function () {\n            history.back();\n\n            return false;\n        });\n    };\n});\n","Magento_InventorySwatchesFrontendUi/js/swatch-renderer.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'configurableVariationQty',\n    'jquery-ui-modules/widget'\n], function ($, configurableVariationQty) {\n    'use strict';\n\n    return function (SwatchRenderer) {\n        $.widget('mage.SwatchRenderer', SwatchRenderer, {\n\n            /** @inheritdoc */\n            _OnClick: function ($this, widget) {\n                var salesChannel = this.options.jsonConfig.channel,\n                    salesChannelCode = this.options.jsonConfig.salesChannelCode,\n                    productVariationsSku = this.options.jsonConfig.sku;\n\n                this._super($this, widget);\n                configurableVariationQty(productVariationsSku[widget.getProductId()], salesChannel, salesChannelCode);\n            }\n        });\n\n        return $.mage.SwatchRenderer;\n    };\n});\n","Magento_OfflineShipping/js/view/shipping-rates-validation/flatrate.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent',\n    'Magento_Checkout/js/model/shipping-rates-validator',\n    'Magento_Checkout/js/model/shipping-rates-validation-rules',\n    '../../model/shipping-rates-validator/flatrate',\n    '../../model/shipping-rates-validation-rules/flatrate'\n], function (\n    Component,\n    defaultShippingRatesValidator,\n    defaultShippingRatesValidationRules,\n    flatrateShippingRatesValidator,\n    flatrateShippingRatesValidationRules\n) {\n    'use strict';\n\n    defaultShippingRatesValidator.registerValidator('flatrate', flatrateShippingRatesValidator);\n    defaultShippingRatesValidationRules.registerRules('flatrate', flatrateShippingRatesValidationRules);\n\n    return Component;\n});\n","Magento_OfflineShipping/js/view/shipping-rates-validation/freeshipping.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent',\n    'Magento_Checkout/js/model/shipping-rates-validator',\n    'Magento_Checkout/js/model/shipping-rates-validation-rules',\n    '../../model/shipping-rates-validator/freeshipping',\n    '../../model/shipping-rates-validation-rules/freeshipping'\n], function (\n    Component,\n    defaultShippingRatesValidator,\n    defaultShippingRatesValidationRules,\n    freeshippingShippingRatesValidator,\n    freeshippingShippingRatesValidationRules\n) {\n    'use strict';\n\n    defaultShippingRatesValidator.registerValidator('freeshipping', freeshippingShippingRatesValidator);\n    defaultShippingRatesValidationRules.registerRules('freeshipping', freeshippingShippingRatesValidationRules);\n\n    return Component;\n});\n","Magento_OfflineShipping/js/view/shipping-rates-validation/tablerate.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent',\n    'Magento_Checkout/js/model/shipping-rates-validator',\n    'Magento_Checkout/js/model/shipping-rates-validation-rules',\n    '../../model/shipping-rates-validator/tablerate',\n    '../../model/shipping-rates-validation-rules/tablerate'\n], function (\n    Component,\n    defaultShippingRatesValidator,\n    defaultShippingRatesValidationRules,\n    tablerateShippingRatesValidator,\n    tablerateShippingRatesValidationRules\n) {\n    'use strict';\n\n    defaultShippingRatesValidator.registerValidator('tablerate', tablerateShippingRatesValidator);\n    defaultShippingRatesValidationRules.registerRules('tablerate', tablerateShippingRatesValidationRules);\n\n    return Component;\n});\n","Magento_OfflineShipping/js/model/shipping-rates-validation-rules/flatrate.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        /**\n         * @return {Object}\n         */\n        getRules: function () {\n            return {\n                'country_id': {\n                    'required': true\n                }\n            };\n        }\n    };\n});\n","Magento_OfflineShipping/js/model/shipping-rates-validation-rules/freeshipping.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        /**\n         * @return {Object}\n         */\n        getRules: function () {\n            return {\n                'country_id': {\n                    'required': true\n                }\n            };\n        }\n    };\n});\n","Magento_OfflineShipping/js/model/shipping-rates-validation-rules/tablerate.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        /**\n         * @return {Object}\n         */\n        getRules: function () {\n            return {\n                'postcode': {\n                    'required': true\n                },\n                'country_id': {\n                    'required': true\n                },\n                'region_id': {\n                    'required': true\n                },\n                'region_id_input': {\n                    'required': true\n                }\n            };\n        }\n    };\n});\n","Magento_OfflineShipping/js/model/shipping-rates-validator/flatrate.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mageUtils',\n    '../shipping-rates-validation-rules/flatrate',\n    'mage/translate'\n], function ($, utils, validationRules, $t) {\n    'use strict';\n\n    return {\n        validationErrors: [],\n\n        /**\n         * @param {Object} address\n         * @return {Boolean}\n         */\n        validate: function (address) {\n            var self = this;\n\n            this.validationErrors = [];\n            $.each(validationRules.getRules(), function (field, rule) {\n                var message;\n\n                if (rule.required && utils.isEmpty(address[field])) {\n                    message = $t('Field ') + field + $t(' is required.');\n                    self.validationErrors.push(message);\n                }\n            });\n\n            return !this.validationErrors.length;\n        }\n    };\n});\n","Magento_OfflineShipping/js/model/shipping-rates-validator/freeshipping.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mageUtils',\n    '../shipping-rates-validation-rules/freeshipping',\n    'mage/translate'\n], function ($, utils, validationRules, $t) {\n    'use strict';\n\n    return {\n        validationErrors: [],\n\n        /**\n         * @param {Object} address\n         * @return {Boolean}\n         */\n        validate: function (address) {\n            var self = this;\n\n            this.validationErrors = [];\n            $.each(validationRules.getRules(), function (field, rule) {\n                var message;\n\n                if (rule.required && utils.isEmpty(address[field])) {\n                    message = $t('Field ') + field + $t(' is required.');\n                    self.validationErrors.push(message);\n                }\n            });\n\n            return !this.validationErrors.length;\n        }\n    };\n});\n","Magento_OfflineShipping/js/model/shipping-rates-validator/tablerate.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mageUtils',\n    '../shipping-rates-validation-rules/tablerate',\n    'mage/translate'\n], function ($, utils, validationRules, $t) {\n    'use strict';\n\n    return {\n        validationErrors: [],\n\n        /**\n         * @param {Object} address\n         * @return {Boolean}\n         */\n        validate: function (address) {\n            var self = this;\n\n            this.validationErrors = [];\n            $.each(validationRules.getRules(), function (field, rule) {\n                var message, regionFields;\n\n                if (rule.required && utils.isEmpty(address[field])) {\n                    message = $t('Field ') + field + $t(' is required.');\n                    regionFields = ['region', 'region_id', 'region_id_input'];\n\n                    if (\n                        $.inArray(field, regionFields) === -1 ||\n                        utils.isEmpty(address.region) && utils.isEmpty(address['region_id'])\n                    ) {\n                        self.validationErrors.push(message);\n                    }\n                }\n            });\n\n            return !this.validationErrors.length;\n        }\n    };\n});\n","Magento_ConfigurableProduct/js/catalog-add-to-cart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\nrequire([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    /**\n     * Add selected configurable attributes to redirect url\n     *\n     * @see Magento_Catalog/js/catalog-add-to-cart\n     */\n    $('body').on('catalogCategoryAddToCartRedirect', function (event, data) {\n        $(data.form).find('select[name*=\"super\"]').each(function (index, item) {\n            data.redirectParameters.push(item.config.id + '=' + $(item).val());\n        });\n    });\n});\n","Magento_ConfigurableProduct/js/configurable-customer-data.js":"require([\n    'jquery',\n    'Magento_ConfigurableProduct/js/options-updater'\n], function ($, Updater) {\n    'use strict';\n\n    var selectors = {\n            formSelector: '#product_addtocart_form'\n        },\n        configurableWidgetName = 'mageConfigurable',\n        widgetInitEvent = 'configurable.initialized',\n\n    /**\n    * Sets all configurable attribute's selected values\n    */\n    updateConfigurableOptions = function () {\n        var configurableWidget = $(selectors.formSelector).data(configurableWidgetName);\n\n        if (!configurableWidget) {\n            return;\n        }\n        configurableWidget.options.values = this.productOptions || {};\n        configurableWidget._configureForValues();\n    },\n    updater = new Updater(widgetInitEvent, updateConfigurableOptions);\n\n    updater.listen();\n});\n","Magento_ConfigurableProduct/js/configurable.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore',\n    'mage/template',\n    'mage/translate',\n    'priceUtils',\n    'priceBox',\n    'jquery-ui-modules/widget',\n    'jquery/jquery.parsequery',\n    'fotoramaVideoEvents'\n], function ($, _, mageTemplate, $t, priceUtils) {\n    'use strict';\n\n    $.widget('mage.configurable', {\n        options: {\n            superSelector: '.super-attribute-select',\n            selectSimpleProduct: '[name=\"selected_configurable_option\"]',\n            priceHolderSelector: '.price-box',\n            spConfig: {},\n            state: {},\n            priceFormat: {},\n            optionTemplate: '<%- data.label %>' +\n            '<% if (typeof data.finalPrice.value !== \"undefined\") { %>' +\n            ' <%- data.finalPrice.formatted %>' +\n            '<% } %>',\n            mediaGallerySelector: '[data-gallery-role=gallery-placeholder]',\n            mediaGalleryInitial: null,\n            slyOldPriceSelector: '.sly-old-price',\n            normalPriceLabelSelector: '.product-info-main .normal-price .price-label',\n\n            /**\n             * Defines the mechanism of how images of a gallery should be\n             * updated when user switches between configurations of a product.\n             *\n             * As for now value of this option can be either 'replace' or 'prepend'.\n             *\n             * @type {String}\n             */\n            gallerySwitchStrategy: 'replace',\n            tierPriceTemplateSelector: '#tier-prices-template',\n            tierPriceBlockSelector: '[data-role=\"tier-price-block\"]',\n            tierPriceTemplate: '',\n            selectorProduct: '.product-info-main',\n            selectorProductPrice: '[data-role=priceBox]',\n            qtyInfo: '#qty'\n        },\n\n        /**\n         * Creates widget\n         * @private\n         */\n        _create: function () {\n            // Initial setting of various option values\n            this._initializeOptions();\n\n            // Override defaults with URL query parameters and/or inputs values\n            this._overrideDefaults();\n\n            // Change events to check select reloads\n            this._setupChangeEvents();\n\n            // Fill state\n            this._fillState();\n\n            // Setup child and prev/next settings\n            this._setChildSettings();\n\n            // Setup/configure values to inputs\n            this._configureForValues();\n\n            $(this.element).trigger('configurable.initialized');\n            $(this.options.qtyInfo).on('input', this._reloadPrice.bind(this));\n        },\n\n        /**\n         * Initialize tax configuration, initial settings, and options values.\n         * @private\n         */\n        _initializeOptions: function () {\n            var options = this.options,\n                gallery = $(options.mediaGallerySelector),\n                priceBoxOptions = $(this.options.priceHolderSelector).priceBox('option').priceConfig || null;\n\n            if (priceBoxOptions && priceBoxOptions.optionTemplate) {\n                options.optionTemplate = priceBoxOptions.optionTemplate;\n            }\n\n            if (priceBoxOptions && priceBoxOptions.priceFormat) {\n                options.priceFormat = priceBoxOptions.priceFormat;\n            }\n            options.optionTemplate = mageTemplate(options.optionTemplate);\n            options.tierPriceTemplate = $(this.options.tierPriceTemplateSelector).html();\n\n            options.settings = options.spConfig.containerId ?\n                $(options.spConfig.containerId).find(options.superSelector) :\n                $(options.superSelector);\n\n            options.values = options.spConfig.defaultValues || {};\n            options.parentImage = $('[data-role=base-image-container] img').attr('src');\n\n            this.inputSimpleProduct = this.element.find(options.selectSimpleProduct);\n\n            gallery.data('gallery') ?\n                this._onGalleryLoaded(gallery) :\n                gallery.on('gallery:loaded', this._onGalleryLoaded.bind(this, gallery));\n\n        },\n\n        /**\n         * Override default options values settings with either URL query parameters or\n         * initialized inputs values.\n         * @private\n         */\n        _overrideDefaults: function () {\n            var hashIndex = window.location.href.indexOf('#');\n\n            if (hashIndex !== -1) {\n                this._parseQueryParams(window.location.href.substr(hashIndex + 1));\n            }\n\n            if (this.options.spConfig.inputsInitialized) {\n                this._setValuesByAttribute();\n            }\n\n            this._setInitialOptionsLabels();\n        },\n\n        /**\n         * Parse query parameters from a query string and set options values based on the\n         * key value pairs of the parameters.\n         * @param {*} queryString - URL query string containing query parameters.\n         * @private\n         */\n        _parseQueryParams: function (queryString) {\n            var queryParams = $.parseQuery({\n                query: queryString\n            });\n\n            $.each(queryParams, $.proxy(function (key, value) {\n                if (this.options.spConfig.attributes[key] !== undefined &&\n                    _.find(this.options.spConfig.attributes[key].options, function (element) {\n                        return element.id === value;\n                    })) {\n                    this.options.values[key] = value;\n                }\n            }, this));\n        },\n\n        /**\n         * Override default options values with values based on each element's attribute\n         * identifier.\n         * @private\n         */\n        _setValuesByAttribute: function () {\n            this.options.values = {};\n            $.each(this.options.settings, $.proxy(function (index, element) {\n                var attributeId;\n\n                if (element.value) {\n                    attributeId = element.id.replace(/[a-z]*/, '');\n\n                    if (this.options.spConfig.attributes[attributeId] !== undefined &&\n                        _.find(this.options.spConfig.attributes[attributeId].options, function (optionElement) {\n                            return optionElement.id === element.value;\n                        })) {\n                        this.options.values[attributeId] = element.value;\n                    }\n                }\n            }, this));\n        },\n\n        /**\n         * Set additional field with initial label to be used when switching between options with different prices.\n         * @private\n         */\n        _setInitialOptionsLabels: function () {\n            $.each(this.options.spConfig.attributes, $.proxy(function (index, element) {\n                $.each(element.options, $.proxy(function (optIndex, optElement) {\n                    this.options.spConfig.attributes[index].options[optIndex].initialLabel = optElement.label;\n                }, this));\n            }, this));\n        },\n\n        /**\n         * Set up .on('change') events for each option element to configure the option.\n         * @private\n         */\n        _setupChangeEvents: function () {\n            $.each(this.options.settings, $.proxy(function (index, element) {\n                $(element).on('change', this, this._configure);\n            }, this));\n        },\n\n        /**\n         * Iterate through the option settings and set each option's element configuration,\n         * attribute identifier. Set the state based on the attribute identifier.\n         * @private\n         */\n        _fillState: function () {\n            $.each(this.options.settings, $.proxy(function (index, element) {\n                var attributeId = element.id.replace(/[a-z]*/, '');\n\n                if (attributeId && this.options.spConfig.attributes[attributeId]) {\n                    element.config = this.options.spConfig.attributes[attributeId];\n                    element.attributeId = attributeId;\n                    this.options.state[attributeId] = false;\n                }\n            }, this));\n        },\n\n        /**\n         * Set each option's child settings, and next/prev option setting. Fill (initialize)\n         * an option's list of selections as needed or disable an option's setting.\n         * @private\n         */\n        _setChildSettings: function () {\n            var childSettings = [],\n                settings = this.options.settings,\n                index = settings.length,\n                option;\n\n            while (index--) {\n                option = settings[index];\n\n                if (index) {\n                    option.disabled = true;\n                } else {\n                    this._fillSelect(option);\n                }\n\n                _.extend(option, {\n                    childSettings: childSettings.slice(),\n                    prevSetting: settings[index - 1],\n                    nextSetting: settings[index + 1]\n                });\n\n                childSettings.push(option);\n            }\n        },\n\n        /**\n         * Setup for all configurable option settings. Set the value of the option and configure\n         * the option, which sets its state, and initializes the option's choices, etc.\n         * @private\n         */\n        _configureForValues: function () {\n            if (this.options.values) {\n                this.options.settings.each($.proxy(function (index, element) {\n                    var attributeId = element.attributeId;\n\n                    element.value = this.options.values[attributeId] || '';\n                    this._configureElement(element);\n                }, this));\n            }\n        },\n\n        /**\n         * Event handler for configuring an option.\n         * @private\n         * @param {Object} event - Event triggered to configure an option.\n         */\n        _configure: function (event) {\n            event.data._configureElement(this);\n        },\n\n        /**\n         * Configure an option, initializing it's state and enabling related options, which\n         * populates the related option's selection and resets child option selections.\n         * @private\n         * @param {*} element - The element associated with a configurable option.\n         */\n        _configureElement: function (element) {\n            this.simpleProduct = this._getSimpleProductId(element);\n\n            if (element.value) {\n                this.options.state[element.config.id] = element.value;\n\n                if (element.nextSetting) {\n                    element.nextSetting.disabled = false;\n                    this._fillSelect(element.nextSetting);\n                    this._resetChildren(element.nextSetting);\n                } else {\n                    if (!!document.documentMode) { //eslint-disable-line\n                        this.inputSimpleProduct.val(element.options[element.selectedIndex].config.allowedProducts[0]);\n                    } else {\n                        this.inputSimpleProduct.val(element.selectedOptions[0].config.allowedProducts[0]);\n                    }\n                }\n            } else {\n                this._resetChildren(element);\n            }\n\n            this._reloadPrice();\n            this._displayRegularPriceBlock(this.simpleProduct);\n            this._displayTierPriceBlock(this.simpleProduct);\n            this._displayNormalPriceLabel();\n            this._changeProductImage();\n        },\n\n        /**\n         * Change displayed product image according to chosen options of configurable product\n         *\n         * @private\n         */\n        _changeProductImage: function () {\n            var images,\n                initialImages = this.options.mediaGalleryInitial,\n                gallery = $(this.options.mediaGallerySelector).data('gallery');\n\n            if (_.isUndefined(gallery)) {\n                $(this.options.mediaGallerySelector).on('gallery:loaded', function () {\n                    this._changeProductImage();\n                }.bind(this));\n\n                return;\n            }\n\n            images = this.options.spConfig.images[this.simpleProduct];\n\n            if (images) {\n                images = this._sortImages(images);\n\n                if (this.options.gallerySwitchStrategy === 'prepend') {\n                    images = images.concat(initialImages);\n                }\n\n                images = $.extend(true, [], images);\n                images = this._setImageIndex(images);\n\n                gallery.updateData(images);\n                this._addFotoramaVideoEvents(false);\n            } else {\n                gallery.updateData(initialImages);\n                this._addFotoramaVideoEvents(true);\n            }\n        },\n\n        /**\n         * Add video events\n         *\n         * @param {Boolean} isInitial\n         * @private\n         */\n        _addFotoramaVideoEvents: function (isInitial) {\n            if (_.isUndefined($.mage.AddFotoramaVideoEvents)) {\n                return;\n            }\n\n            if (isInitial) {\n                $(this.options.mediaGallerySelector).AddFotoramaVideoEvents();\n\n                return;\n            }\n\n            $(this.options.mediaGallerySelector).AddFotoramaVideoEvents({\n                selectedOption: this.simpleProduct,\n                dataMergeStrategy: this.options.gallerySwitchStrategy\n            });\n        },\n\n        /**\n         * Sorting images array\n         *\n         * @private\n         */\n        _sortImages: function (images) {\n            return _.sortBy(images, function (image) {\n                return image.position;\n            });\n        },\n\n        /**\n         * Set correct indexes for image set.\n         *\n         * @param {Array} images\n         * @private\n         */\n        _setImageIndex: function (images) {\n            var length = images.length,\n                i;\n\n            for (i = 0; length > i; i++) {\n                images[i].i = i + 1;\n            }\n\n            return images;\n        },\n\n        /**\n         * For a given option element, reset all of its selectable options. Clear any selected\n         * index, disable the option choice, and reset the option's state if necessary.\n         * @private\n         * @param {*} element - The element associated with a configurable option.\n         */\n        _resetChildren: function (element) {\n            if (element.childSettings) {\n                _.each(element.childSettings, function (set) {\n                    set.selectedIndex = 0;\n                    set.disabled = true;\n                });\n\n                if (element.config) {\n                    this.options.state[element.config.id] = false;\n                }\n            }\n        },\n\n        /**\n         * Populates an option's selectable choices.\n         * @private\n         * @param {*} element - Element associated with a configurable option.\n         */\n        _fillSelect: function (element) {\n            var attributeId = element.id.replace(/[a-z]*/, ''),\n                options = this._getAttributeOptions(attributeId),\n                prevConfig,\n                index = 1,\n                allowedProducts,\n                allowedProductsByOption,\n                allowedProductsAll,\n                i,\n                j,\n                finalPrice = parseFloat(this.options.spConfig.prices.finalPrice.amount),\n                optionFinalPrice,\n                optionPriceDiff,\n                optionPrices = this.options.spConfig.optionPrices,\n                allowedOptions = [],\n                indexKey,\n                allowedProductMinPrice,\n                allowedProductsAllMinPrice,\n                canDisplayOutOfStockProducts = false,\n                filteredSalableProducts;\n\n            this._clearSelect(element);\n            element.options[0] = new Option('', '');\n            element.options[0].innerHTML = this.options.spConfig.chooseText;\n            prevConfig = false;\n\n            if (element.prevSetting) {\n                prevConfig = element.prevSetting.options[element.prevSetting.selectedIndex];\n            }\n\n            if (options) {\n                for (indexKey in this.options.spConfig.index) {\n                    /* eslint-disable max-depth */\n                    if (this.options.spConfig.index.hasOwnProperty(indexKey)) {\n                        allowedOptions = allowedOptions.concat(_.values(this.options.spConfig.index[indexKey]));\n                    }\n                }\n\n                if (prevConfig) {\n                    allowedProductsByOption = {};\n                    allowedProductsAll = [];\n\n                    for (i = 0; i < options.length; i++) {\n                        /* eslint-disable max-depth */\n                        for (j = 0; j < options[i].products.length; j++) {\n                            // prevConfig.config can be undefined\n                            if (prevConfig.config &&\n                                prevConfig.config.allowedProducts &&\n                                prevConfig.config.allowedProducts.indexOf(options[i].products[j]) > -1) {\n                                if (!allowedProductsByOption[i]) {\n                                    allowedProductsByOption[i] = [];\n                                }\n                                allowedProductsByOption[i].push(options[i].products[j]);\n                                allowedProductsAll.push(options[i].products[j]);\n                            }\n                        }\n                    }\n\n                    if (typeof allowedProductsAll[0] !== 'undefined' &&\n                        typeof optionPrices[allowedProductsAll[0]] !== 'undefined') {\n                        allowedProductsAllMinPrice = this._getAllowedProductWithMinPrice(allowedProductsAll);\n                        finalPrice = parseFloat(optionPrices[allowedProductsAllMinPrice].finalPrice.amount);\n                    }\n                }\n\n                for (i = 0; i < options.length; i++) {\n                    if (prevConfig && typeof allowedProductsByOption[i] === 'undefined') {\n                        continue; //jscs:ignore disallowKeywords\n                    }\n\n                    allowedProducts = prevConfig ? allowedProductsByOption[i] : options[i].products.slice(0);\n                    optionPriceDiff = 0;\n\n                    if (typeof allowedProducts[0] !== 'undefined' &&\n                        typeof optionPrices[allowedProducts[0]] !== 'undefined') {\n                        allowedProductMinPrice = this._getAllowedProductWithMinPrice(allowedProducts);\n                        optionFinalPrice = parseFloat(optionPrices[allowedProductMinPrice].finalPrice.amount);\n                        optionPriceDiff = optionFinalPrice - finalPrice;\n                        options[i].label = options[i].initialLabel;\n\n                        if (optionPriceDiff !== 0) {\n                            options[i].label += ' ' + priceUtils.formatPriceLocale(\n                                optionPriceDiff,\n                                this.options.priceFormat,\n                                true\n                            );\n                        }\n                    }\n\n                    if (allowedProducts.length > 0 || _.include(allowedOptions, options[i].id)) {\n                        options[i].allowedProducts = allowedProducts;\n                        element.options[index] = new Option(this._getOptionLabel(options[i]), options[i].id);\n\n                        if (this.options.spConfig.canDisplayShowOutOfStockStatus) {\n                            filteredSalableProducts = $(this.options.spConfig.salable[attributeId][options[i].id]).\n                            filter(options[i].allowedProducts);\n                            canDisplayOutOfStockProducts = filteredSalableProducts.length === 0;\n                        }\n\n                        if (typeof options[i].price !== 'undefined') {\n                            element.options[index].setAttribute('price', options[i].price);\n                        }\n\n                        if (allowedProducts.length === 0 || canDisplayOutOfStockProducts) {\n                            element.options[index].disabled = true;\n                        }\n\n                        element.options[index].config = options[i];\n                        index++;\n                    }\n\n                    /* eslint-enable max-depth */\n                }\n            }\n        },\n\n        /**\n         * Generate the label associated with a configurable option. This includes the option's\n         * label or value and the option's price.\n         * @private\n         * @param {*} option - A single choice among a group of choices for a configurable option.\n         * @return {String} The option label with option value and price (e.g. Black +1.99)\n         */\n        _getOptionLabel: function (option) {\n            return option.label;\n        },\n\n        /**\n         * Removes an option's selections.\n         * @private\n         * @param {*} element - The element associated with a configurable option.\n         */\n        _clearSelect: function (element) {\n            var i;\n\n            for (i = element.options.length - 1; i >= 0; i--) {\n                element.remove(i);\n            }\n        },\n\n        /**\n         * Retrieve the attribute options associated with a specific attribute Id.\n         * @private\n         * @param {Number} attributeId - The id of the attribute whose configurable options are sought.\n         * @return {Object} Object containing the attribute options.\n         */\n        _getAttributeOptions: function (attributeId) {\n            if (this.options.spConfig.attributes[attributeId]) {\n                return this.options.spConfig.attributes[attributeId].options;\n            }\n        },\n\n        /**\n         * Reload the price of the configurable product incorporating the prices of all of the\n         * configurable product's option selections.\n         */\n        _reloadPrice: function () {\n            $(this.options.priceHolderSelector).trigger('updatePrice', this._getPrices());\n        },\n\n        /**\n         * Get product various prices\n         * @returns {{}}\n         * @private\n         */\n        _getPrices: function () {\n            var prices = {},\n                elements = _.toArray(this.options.settings),\n                allowedProduct;\n\n            _.each(elements, function (element) {\n                var selected = element.options[element.selectedIndex],\n                    config = selected && selected.config,\n                    priceValue = this._calculatePrice({});\n\n                if (config && config.allowedProducts.length === 1) {\n                    priceValue = this._calculatePrice(config);\n                } else if (element.value) {\n                    allowedProduct = this._getAllowedProductWithMinPrice(config.allowedProducts);\n                    priceValue = this._calculatePrice({\n                        'allowedProducts': [\n                            allowedProduct\n                        ]\n                    });\n                }\n\n                if (!_.isEmpty(priceValue)) {\n                    prices.prices = priceValue;\n                }\n            }, this);\n\n            return prices;\n        },\n\n        /**\n         * Get product with minimum price from selected options.\n         *\n         * @param {Array} allowedProducts\n         * @returns {String}\n         * @private\n         */\n        _getAllowedProductWithMinPrice: function (allowedProducts) {\n            var optionPrices = this.options.spConfig.optionPrices,\n                product = {},\n                optionMinPrice, optionFinalPrice;\n\n            _.each(allowedProducts, function (allowedProduct) {\n                optionFinalPrice = parseFloat(optionPrices[allowedProduct].finalPrice.amount);\n\n                if (_.isEmpty(product) || optionFinalPrice < optionMinPrice) {\n                    optionMinPrice = optionFinalPrice;\n                    product = allowedProduct;\n                }\n            }, this);\n\n            return product;\n        },\n\n        /**\n         * Returns prices for configured products\n         *\n         * @param {*} config - Products configuration\n         * @returns {*}\n         * @private\n         */\n        _calculatePrice: function (config) {\n            var displayPrices = $(this.options.priceHolderSelector).priceBox('option').prices,\n                newPrices = this.options.spConfig.optionPrices[_.first(config.allowedProducts)] || {};\n\n            _.each(displayPrices, function (price, code) {\n                displayPrices[code].amount = newPrices[code] ? newPrices[code].amount - displayPrices[code].amount : 0;\n            });\n\n            return displayPrices;\n        },\n\n        /**\n         * Returns Simple product Id\n         *  depending on current selected option.\n         *\n         * @private\n         * @param {HTMLElement} element\n         * @returns {String|undefined}\n         */\n        _getSimpleProductId: function (element) {\n            // TODO: Rewrite algorithm. It should return ID of\n            //        simple product based on selected options.\n            var allOptions = element.config.options,\n                value = element.value,\n                config;\n\n            config = _.filter(allOptions, function (option) {\n                return option.id === value;\n            });\n            config = _.first(config);\n\n            return _.isEmpty(config) ?\n                undefined :\n                _.first(config.allowedProducts);\n\n        },\n\n        /**\n         * Show or hide regular price block\n         *\n         * @param {*} optionId\n         * @private\n         */\n        _displayRegularPriceBlock: function (optionId) {\n            var shouldBeShown = true,\n                $priceBox = this.element.parents(this.options.selectorProduct)\n                    .find(this.options.selectorProductPrice);\n\n            _.each(this.options.settings, function (element) {\n                if (element.value === '') {\n                    shouldBeShown = false;\n                }\n            });\n\n            if (shouldBeShown &&\n                this.options.spConfig.optionPrices[optionId].oldPrice.amount !==\n                this.options.spConfig.optionPrices[optionId].finalPrice.amount\n            ) {\n                $(this.options.slyOldPriceSelector).show();\n            } else {\n                $(this.options.slyOldPriceSelector).hide();\n            }\n\n            $(document).trigger('updateMsrpPriceBlock',\n                [\n                    optionId,\n                    this.options.spConfig.optionPrices,\n                    $priceBox\n                ]\n            );\n        },\n\n        /**\n         * Show or hide normal price label\n         *\n         * @private\n         */\n        _displayNormalPriceLabel: function () {\n            var shouldBeShown = false;\n\n            _.each(this.options.settings, function (element) {\n                if (element.value === '') {\n                    shouldBeShown = true;\n                }\n            });\n\n            if (shouldBeShown) {\n                $(this.options.normalPriceLabelSelector).show();\n            } else {\n                $(this.options.normalPriceLabelSelector).hide();\n            }\n        },\n\n        /**\n         * Callback which fired after gallery gets initialized.\n         *\n         * @param {HTMLElement} element - DOM element associated with gallery.\n         */\n        _onGalleryLoaded: function (element) {\n            var galleryObject = element.data('gallery');\n\n            this.options.mediaGalleryInitial = galleryObject.returnCurrentImages();\n        },\n\n        /**\n         * Show or hide tier price block\n         *\n         * @param {*} optionId\n         * @private\n         */\n        _displayTierPriceBlock: function (optionId) {\n            var tierPrices = typeof optionId != 'undefined' && this.options.spConfig.optionPrices[optionId].tierPrices;\n\n            if (_.isArray(tierPrices) && tierPrices.length > 0) {\n\n                if (this.options.tierPriceTemplate) {\n                    $(this.options.tierPriceBlockSelector).html(\n                        mageTemplate(this.options.tierPriceTemplate, {\n                            'tierPrices': tierPrices,\n                            '$t': $t,\n                            'currencyFormat': this.options.spConfig.currencyFormat,\n                            'priceUtils': priceUtils\n                        })\n                    ).show();\n                }\n            } else {\n                $(this.options.tierPriceBlockSelector).hide();\n            }\n        }\n    });\n\n    return $.mage.configurable;\n});\n","Magento_ConfigurableProduct/js/options-updater.js":"define([\n    'jquery',\n    'underscore',\n    'Magento_Customer/js/customer-data',\n    'domReady!'\n], function ($, _, customerData) {\n    'use strict';\n\n    var selectors = {\n        formSelector: '#product_addtocart_form',\n        productIdSelector: '#product_addtocart_form [name=\"product\"]',\n        itemIdSelector: '#product_addtocart_form [name=\"item\"]'\n    },\n    cartData = customerData.get('cart'),\n    productId = $(selectors.productIdSelector).val(),\n    itemId = $(selectors.itemIdSelector).val(),\n\n    /**\n    * set productOptions according to cart data from customer-data\n    *\n    * @param {Object} data - cart data from customer-data\n    * @returns {Boolean} - whether the new options differ from previous\n    */\n    setProductOptions = function (data) {\n        var changedProductOptions;\n\n        if (!(data && data.items && data.items.length && productId)) {\n            return false;\n        }\n        changedProductOptions = _.find(data.items, function (item) {\n            if (item['item_id'] === itemId) {\n                return item['product_id'] === productId;\n            }\n        });\n        changedProductOptions = changedProductOptions && changedProductOptions.options &&\n            changedProductOptions.options.reduce(function (obj, val) {\n                obj[val['option_id']] = val['option_value'];\n\n                return obj;\n            }, {});\n\n        if (JSON.stringify(this.productOptions || {}) === JSON.stringify(changedProductOptions || {})) {\n            return false;\n        }\n\n        this.productOptions = changedProductOptions;\n\n        return true;\n    },\n\n    /**\n    * Listens to update of cart data or options initialization and update selected option according to customer data\n    *\n    */\n    listen = function () {\n        cartData.subscribe(function (updateCartData) {\n            if (this.setProductOptions(updateCartData)) {\n                this.updateOptions();\n            }\n        }.bind(this));\n        $(selectors.formSelector).on(this.eventName, function () {\n            this.setProductOptions(cartData());\n            this.updateOptions();\n        }.bind(this));\n    },\n\n    /**\n    * Updater constructor function\n    *\n    */\n    Updater = function (eventName, updateOptionsCallback) {\n        if (this instanceof Updater) {\n            this.eventName = eventName;\n            this.updateOptions = updateOptionsCallback;\n            this.productOptions = {};\n        }\n    };\n\n    Updater.prototype.setProductOptions = setProductOptions;\n    Updater.prototype.listen = listen;\n\n    return Updater;\n});\n","Magento_ConfigurableProduct/js/catalog-add-to-cart-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'jquery',\n    'Magento_ConfigurableProduct/js/product/view/product-info-resolver'\n], function (_, $, productInfoResolver) {\n    'use strict';\n\n    return function (widget) {\n\n        $.widget('mage.catalogAddToCart', widget, {\n            /**\n             * @param {jQuery} form\n             */\n            ajaxSubmit: function (form) {\n                var isConfigurable = !!_.find(form.serializeArray(), function (item) {\n                    return item.name.indexOf('super_attribute') !== -1;\n                });\n\n                if (isConfigurable) {\n                    this.options.productInfoResolver = productInfoResolver;\n                }\n\n                return this._super(form);\n            }\n        });\n\n        return $.mage.catalogAddToCart;\n    };\n});\n","Magento_ConfigurableProduct/js/product/view/product-info-resolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'Magento_Catalog/js/product/view/product-info'\n], function (_, productInfo) {\n    'use strict';\n\n    /**\n     * Returns info about configurable products in form.\n     *\n     * @param {jQuery} $form\n     * @return {Array}\n     */\n    return function ($form) {\n        var optionValues = [],\n            product = _.findWhere($form.serializeArray(), {\n                name: 'product'\n            }),\n            productId;\n\n        if (!_.isUndefined(product)) {\n            productId = product.value;\n            _.each($form.serializeArray(), function (item) {\n                if (item.name.indexOf('super_attribute') !== -1) {\n                    optionValues.push(item.value);\n                }\n            });\n            optionValues.sort();\n            productInfo().push(\n                {\n                    'id': productId,\n                    'optionValues': optionValues\n                }\n            );\n        }\n\n        return _.uniq(productInfo(), function (item) {\n            var optionValuesStr = item.optionValues ? item.optionValues.join() : '';\n\n            return item.id + optionValuesStr;\n        });\n    };\n});\n\n","Magento_Ups/js/view/shipping-rates-validation.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent',\n    'Magento_Checkout/js/model/shipping-rates-validator',\n    'Magento_Checkout/js/model/shipping-rates-validation-rules',\n    'Magento_Ups/js/model/shipping-rates-validator',\n    'Magento_Ups/js/model/shipping-rates-validation-rules'\n], function (\n    Component,\n    defaultShippingRatesValidator,\n    defaultShippingRatesValidationRules,\n    upsShippingRatesValidator,\n    upsShippingRatesValidationRules\n) {\n    'use strict';\n\n    defaultShippingRatesValidator.registerValidator('ups', upsShippingRatesValidator);\n    defaultShippingRatesValidationRules.registerRules('ups', upsShippingRatesValidationRules);\n\n    return Component;\n});\n","Magento_Ups/js/model/shipping-rates-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mageUtils',\n    'Magento_Ups/js/model/shipping-rates-validation-rules',\n    'mage/translate'\n], function ($, utils, validationRules, $t) {\n    'use strict';\n\n    return {\n        validationErrors: [],\n\n        /**\n         * @param {Object} address\n         * @return {Boolean}\n         */\n        validate: function (address) {\n            var self = this;\n\n            this.validationErrors = [];\n            $.each(validationRules.getRules(), function (field, rule) {\n                var message;\n\n                if (rule.required && utils.isEmpty(address[field])) {\n                    message = $t('Field ') + field + $t(' is required.');\n                    self.validationErrors.push(message);\n                }\n            });\n\n            return !this.validationErrors.length;\n        }\n    };\n});\n","Magento_Ups/js/model/shipping-rates-validation-rules.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        /**\n         * @return {Object}\n         */\n        getRules: function () {\n            return {\n                'postcode': {\n                    'required': true\n                },\n                'country_id': {\n                    'required': true\n                }\n            };\n        }\n    };\n});\n","Magento_GoogleGtag/js/google-adwords.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/* jscs:disable */\n/* eslint-disable */\ndefine([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    /**\n     * @param {Object} config\n     */\n    return function (config) {\n        if (!window.gtag) {\n            // Inject Global Site Tag\n            var gtagScript = document.createElement('script');\n            gtagScript.type = 'text/javascript';\n            gtagScript.async = true;\n            gtagScript.src = config.gtagSiteSrc;\n            document.head.appendChild(gtagScript);\n\n            window.dataLayer = window.dataLayer || [];\n\n            function gtag(){dataLayer.push(arguments);}\n            gtag('js', new Date());\n            gtag('set', 'developer_id.dYjhlMD', true);\n            if (config.conversionLabel) {\n                gtag(\n                    'event',\n                    'conversion',\n                    {'send_to': config.conversionId + '/'\n                            + config.conversionLabel}\n                );\n            }\n        } else {\n            gtag('config', config.conversionId);\n        }\n    }\n});\n","Magento_GoogleGtag/js/google-analytics.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/* jscs:disable */\n/* eslint-disable */\ndefine([\n    'jquery',\n    'mage/cookies'\n], function ($) {\n    'use strict';\n\n    /**\n     * @param {Object} config\n     */\n    return function (config) {\n        var allowServices = false,\n            allowedCookies,\n            allowedWebsites,\n            measurementId;\n\n        if (config.isCookieRestrictionModeEnabled) {\n            allowedCookies = $.mage.cookies.get(config.cookieName);\n\n            if (allowedCookies !== null) {\n                allowedWebsites = JSON.parse(allowedCookies);\n\n                if (allowedWebsites[config.currentWebsite] === 1) {\n                    allowServices = true;\n                }\n            }\n        } else {\n            allowServices = true;\n        }\n\n        if (allowServices) {\n            /* Global site tag (gtag.js) - Google Analytics */\n            measurementId = config.pageTrackingData.measurementId;\n            if (window.gtag) {\n                gtag('config', measurementId, { 'anonymize_ip': true });\n                // Purchase Event\n                if (config.ordersTrackingData.hasOwnProperty('currency')) {\n                    var purchaseObject = config.ordersTrackingData.orders[0];\n                    purchaseObject['items'] = config.ordersTrackingData.products;\n                    gtag('event', 'purchase', purchaseObject);\n                }\n            } else {\n                (function(d,s,u){\n                    var gtagScript = d.createElement(s);\n                    gtagScript.type = 'text/javascript';\n                    gtagScript.async = true;\n                    gtagScript.src = u;\n                    d.head.insertBefore(gtagScript, d.head.children[0]);\n                })(document, 'script', 'https://www.googletagmanager.com/gtag/js?id=' + measurementId);\n                window.dataLayer = window.dataLayer || [];\n                function gtag(){dataLayer.push(arguments);}\n                gtag('js', new Date());\n                gtag('set', 'developer_id.dYjhlMD', true);\n                gtag('config', measurementId, { 'anonymize_ip': true });\n                // Purchase Event\n                if (config.ordersTrackingData.hasOwnProperty('currency')) {\n                    var purchaseObject = config.ordersTrackingData.orders[0];\n                    purchaseObject['items'] = config.ordersTrackingData.products;\n                    gtag('event', 'purchase', purchaseObject);\n                }\n            }\n        }\n    }\n});\n","Magento_Reports/js/recently-viewed.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'jquery-ui-modules/widget'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.recentlyViewedProducts', {\n        options: {\n            localStorageKey: 'recently-viewed-products',\n            productBlock: '#widget_viewed_item',\n            viewedContainer: 'ol'\n        },\n\n        /**\n         * Bind events to the appropriate handlers.\n         * @private\n         */\n        _create: function () {\n            var productHtml = $(this.options.productBlock).html(),\n                productSku = $(this.options.productBlock).data('sku'),\n                products = JSON.parse(window.localStorage.getItem(this.options.localStorageKey)),\n                productsLength, maximum, showed, index;\n\n            if (products) {\n                productsLength = products.sku.length;\n                maximum = $(this.element).data('count');\n                showed = 0;\n\n                for (index = 0; index <= productsLength; index++) {\n                    if (products.sku[index] == productSku || showed >= maximum) { //eslint-disable-line\n                        products.sku.splice(index, 1);\n                        products.html.splice(index, 1);\n                    } else {\n                        $(this.element).find(this.options.viewedContainer).append(products.html[index]);\n                        $(this.element).show();\n                        showed++;\n                    }\n                }\n                $(this.element).find(this.options.productBlock).show();\n            } else {\n                products = {};\n                products.sku = [];\n                products.html = [];\n            }\n            products.sku.unshift(productSku);\n            products.html.unshift(productHtml);\n            window.localStorage.setItem(this.options.localStorageKey, JSON.stringify(products));\n        }\n    });\n\n    return $.mage.recentlyViewedProducts;\n});\n","Magento_CheckoutAgreements/js/view/agreement-validation.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent',\n    'Magento_Checkout/js/model/payment/additional-validators',\n    'Magento_CheckoutAgreements/js/model/agreement-validator'\n], function (Component, additionalValidators, agreementValidator) {\n    'use strict';\n\n    additionalValidators.registerValidator(agreementValidator);\n\n    return Component.extend({});\n});\n","Magento_CheckoutAgreements/js/view/checkout-agreements.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'jquery',\n    'uiComponent',\n    'Magento_CheckoutAgreements/js/model/agreements-modal'\n], function (ko, $, Component, agreementsModal) {\n    'use strict';\n\n    var checkoutConfig = window.checkoutConfig,\n        agreementManualMode = 1,\n        agreementsConfig = checkoutConfig ? checkoutConfig.checkoutAgreements : {};\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_CheckoutAgreements/checkout/checkout-agreements'\n        },\n        isVisible: agreementsConfig.isEnabled,\n        agreements: agreementsConfig.agreements,\n        modalTitle: ko.observable(null),\n        modalContent: ko.observable(null),\n        contentHeight: ko.observable(null),\n        modalWindow: null,\n\n        /**\n         * Checks if agreement required\n         *\n         * @param {Object} element\n         */\n        isAgreementRequired: function (element) {\n            return element.mode == agreementManualMode; //eslint-disable-line eqeqeq\n        },\n\n        /**\n         * Show agreement content in modal\n         *\n         * @param {Object} element\n         */\n        showContent: function (element) {\n            this.modalTitle(element.checkboxText);\n            this.modalContent(element.content);\n            this.contentHeight(element.contentHeight ? element.contentHeight : 'auto');\n            agreementsModal.showModal();\n        },\n\n        /**\n         * build a unique id for the term checkbox\n         *\n         * @param {Object} context - the ko context\n         * @param {Number} agreementId\n         */\n        getCheckboxId: function (context, agreementId) {\n            var paymentMethodName = '',\n                paymentMethodRenderer = context.$parents[1];\n\n            // corresponding payment method fetched from parent context\n            if (paymentMethodRenderer) {\n                // item looks like this: {title: \"Check / Money order\", method: \"checkmo\"}\n                paymentMethodName = paymentMethodRenderer.item ?\n                  paymentMethodRenderer.item.method : '';\n            }\n\n            return 'agreement_' + paymentMethodName + '_' + agreementId;\n        },\n\n        /**\n         * Init modal window for rendered element\n         *\n         * @param {Object} element\n         */\n        initModal: function (element) {\n            agreementsModal.createModal(element);\n        }\n    });\n});\n","Magento_CheckoutAgreements/js/model/place-order-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/utils/wrapper',\n    'Magento_CheckoutAgreements/js/model/agreements-assigner'\n], function ($, wrapper, agreementsAssigner) {\n    'use strict';\n\n    return function (placeOrderAction) {\n\n        /** Override default place order action and add agreement_ids to request */\n        return wrapper.wrap(placeOrderAction, function (originalAction, paymentData, messageContainer) {\n            agreementsAssigner(paymentData);\n\n            return originalAction(paymentData, messageContainer);\n        });\n    };\n});\n","Magento_CheckoutAgreements/js/model/set-payment-information-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/utils/wrapper',\n    'Magento_CheckoutAgreements/js/model/agreements-assigner'\n], function ($, wrapper, agreementsAssigner) {\n    'use strict';\n\n    return function (placeOrderAction) {\n\n        /** Override place-order-mixin for set-payment-information action as they differs only by method signature */\n        return wrapper.wrap(placeOrderAction, function (originalAction, messageContainer, paymentData) {\n            agreementsAssigner(paymentData);\n\n            return originalAction(messageContainer, paymentData);\n        });\n    };\n});\n","Magento_CheckoutAgreements/js/model/agreements-assigner.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    var agreementsConfig = window.checkoutConfig.checkoutAgreements;\n\n    /** Override default place order action and add agreement_ids to request */\n    return function (paymentData) {\n        var agreementForm,\n            agreementData,\n            agreementIds;\n\n        if (!agreementsConfig.isEnabled) {\n            return;\n        }\n\n        agreementForm = $('.payment-method._active div[data-role=checkout-agreements] input');\n        agreementData = agreementForm.serializeArray();\n        agreementIds = [];\n\n        agreementData.forEach(function (item) {\n            agreementIds.push(item.value);\n        });\n\n        if (paymentData['extension_attributes'] === undefined) {\n            paymentData['extension_attributes'] = {};\n        }\n\n        paymentData['extension_attributes']['agreement_ids'] = agreementIds;\n    };\n});\n","Magento_CheckoutAgreements/js/model/agreements-modal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Ui/js/modal/modal',\n    'mage/translate'\n], function ($, modal, $t) {\n    'use strict';\n\n    return {\n        modalWindow: null,\n\n        /**\n         * Create popUp window for provided element.\n         *\n         * @param {HTMLElement} element\n         */\n        createModal: function (element) {\n            var options;\n\n            this.modalWindow = element;\n            options = {\n                'type': 'popup',\n                'modalClass': 'agreements-modal',\n                'responsive': true,\n                'innerScroll': true,\n                'trigger': '.show-modal',\n                'buttons': [\n                    {\n                        text: $t('Close'),\n                        class: 'action secondary action-hide-popup',\n\n                        /** @inheritdoc */\n                        click: function () {\n                            this.closeModal();\n                        }\n                    }\n                ]\n            };\n            modal(options, $(this.modalWindow));\n        },\n\n        /** Show login popup window */\n        showModal: function () {\n            $(this.modalWindow).modal('openModal');\n        }\n    };\n});\n","Magento_CheckoutAgreements/js/model/agreement-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/validation'\n], function ($) {\n    'use strict';\n\n    var checkoutConfig = window.checkoutConfig,\n        agreementsConfig = checkoutConfig ? checkoutConfig.checkoutAgreements : {},\n        agreementsInputPath = '.payment-method._active div.checkout-agreements input';\n\n    return {\n        /**\n         * Validate checkout agreements\n         *\n         * @returns {Boolean}\n         */\n        validate: function (hideError) {\n            var isValid = true;\n\n            if (!agreementsConfig.isEnabled || $(agreementsInputPath).length === 0) {\n                return true;\n            }\n\n            $(agreementsInputPath).each(function (index, element) {\n                if (!$.validator.validateSingleElement(element, {\n                    errorElement: 'div',\n                    hideError: hideError || false\n                })) {\n                    isValid = false;\n                }\n            });\n\n            return isValid;\n        }\n    };\n});\n","Magento_CardinalCommerce/js/cardinal-factory.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 (environment) {\n        var deferred = $.Deferred(),\n            dependency = 'cardinaljs';\n\n        if (environment === 'sandbox') {\n            dependency = 'cardinaljsSandbox';\n        }\n\n        require(\n            [dependency],\n            function (Cardinal) {\n                deferred.resolve(Cardinal);\n            },\n            deferred.reject\n        );\n\n        return deferred.promise();\n    };\n});\n","Magento_CardinalCommerce/js/cardinal-client.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'uiClass',\n    'Magento_CardinalCommerce/js/cardinal-factory',\n    'Magento_Checkout/js/model/quote',\n    'mage/translate'\n], function ($, Class, cardinalFactory, quote, $t) {\n    'use strict';\n\n    return {\n        /**\n         * Starts Cardinal Consumer Authentication\n         *\n         * @param {Object} cardData\n         * @return {jQuery.Deferred}\n         */\n        startAuthentication: function (cardData) {\n            var deferred = $.Deferred();\n\n            if (this.cardinalClient) {\n                this._startAuthentication(deferred, cardData);\n            } else {\n                cardinalFactory(this.getEnvironment())\n                    .done(function (client) {\n                        this.cardinalClient = client;\n                        this._startAuthentication(deferred, cardData);\n                    }.bind(this));\n            }\n\n            return deferred.promise();\n        },\n\n        /**\n         * Cardinal Consumer Authentication\n         *\n         * @param {jQuery.Deferred} deferred\n         * @param {Object} cardData\n         */\n        _startAuthentication: function (deferred, cardData) {\n            //this.cardinalClient.configure({ logging: { level: 'verbose' } });\n            this.cardinalClient.on('payments.validated', function (data, jwt) {\n                if (data.ErrorNumber !== 0) {\n                    deferred.reject(data.ErrorDescription);\n                } else if ($.inArray(data.ActionCode, ['FAILURE', 'ERROR']) !== -1) {\n                    deferred.reject($t('Authentication Failed. Please try again with another form of payment.'));\n                } else {\n                    deferred.resolve(jwt);\n                }\n                this.cardinalClient.off('payments.validated');\n            }.bind(this));\n\n            this.cardinalClient.on('payments.setupComplete', function () {\n                this.cardinalClient.start('cca', this.getRequestOrderObject(cardData));\n                this.cardinalClient.off('payments.setupComplete');\n            }.bind(this));\n\n            this.cardinalClient.setup('init', {\n                jwt: this.getRequestJWT()\n            });\n        },\n\n        /**\n         * Returns request order object.\n         *\n         * The request order object is structured object that is used to pass data\n         * to Cardinal that describes an order you'd like to process.\n         *\n         * If you pass a request object in both the JWT and the browser,\n         * Cardinal will merge the objects together where the browser overwrites\n         * the JWT object as it is considered the most recently captured data.\n         *\n         * @param {Object} cardData\n         * @returns {Object}\n         */\n        getRequestOrderObject: function (cardData) {\n            var totalAmount = quote.totals()['base_grand_total'],\n                currencyCode = quote.totals()['base_currency_code'],\n                billingAddress = quote.billingAddress(),\n                requestObject;\n\n            requestObject = {\n                OrderDetails: {\n                    Amount: totalAmount * 100,\n                    CurrencyCode: currencyCode\n                },\n                Consumer: {\n                    Account: {\n                        AccountNumber: cardData.accountNumber,\n                        ExpirationMonth: cardData.expMonth,\n                        ExpirationYear: cardData.expYear,\n                        CardCode: cardData.cardCode\n                    },\n                    BillingAddress: {\n                        FirstName: billingAddress.firstname,\n                        LastName: billingAddress.lastname,\n                        Address1: billingAddress.street[0],\n                        Address2: billingAddress.street[1],\n                        City: billingAddress.city,\n                        State: billingAddress.region,\n                        PostalCode: billingAddress.postcode,\n                        CountryCode: billingAddress.countryId,\n                        Phone1: billingAddress.telephone\n                    }\n                }\n            };\n\n            return requestObject;\n        },\n\n        /**\n         * Returns request JWT\n         * @returns {String}\n         */\n        getRequestJWT: function () {\n            return window.checkoutConfig.cardinal.requestJWT;\n        },\n\n        /**\n         * Returns type of environment\n         * @returns {String}\n         */\n        getEnvironment: function () {\n            return window.checkoutConfig.cardinal.environment;\n        }\n    };\n});\n","Magento_ReCaptchaCheckoutSalesRule/js/checkout-sales-rule.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/* global grecaptcha */\ndefine(\n    [\n        'Magento_ReCaptchaWebapiUi/js/webapiReCaptcha',\n        'Magento_ReCaptchaWebapiUi/js/webapiReCaptchaRegistry',\n        'jquery',\n        'Magento_SalesRule/js/action/set-coupon-code',\n        'Magento_SalesRule/js/action/cancel-coupon',\n        'Magento_Checkout/js/model/quote',\n        'ko'\n    ], function (Component, recaptchaRegistry, $, setCouponCodeAction, cancelCouponAction, quote, ko) {\n        'use strict';\n\n        var totals = quote.getTotals(),\n            couponCode = ko.observable(null),\n            isApplied;\n\n        if (totals()) {\n            couponCode(totals()['coupon_code']);\n        }\n        //Captcha can only be required for adding a coupon so we need to know if one was added already.\n        isApplied = ko.observable(couponCode() != null);\n\n        return Component.extend({\n\n            /**\n             * Initialize parent form.\n             *\n             * @param {Object} parentForm\n             * @param {String} widgetId\n             */\n            initParentForm: function (parentForm, widgetId) {\n                var self = this,\n                    xRecaptchaValue,\n                    captchaId = this.getReCaptchaId();\n\n                this._super();\n\n                if (couponCode() != null) {\n                    if (isApplied) {\n                        self.validateReCaptcha(true);\n                        $('#' + captchaId).hide();\n                    }\n                }\n\n                if (recaptchaRegistry.triggers.hasOwnProperty('recaptcha-checkout-coupon-apply')) {\n                    recaptchaRegistry.addListener('recaptcha-checkout-coupon-apply', function (token) {\n                        //Add reCaptcha value to coupon request\n                        xRecaptchaValue = token;\n                    });\n                }\n\n                setCouponCodeAction.registerDataModifier(function (headers) {\n                    headers['X-ReCaptcha'] = xRecaptchaValue;\n                });\n\n                if (self.getIsInvisibleRecaptcha()) {\n                    grecaptcha.execute(widgetId);\n                    self.validateReCaptcha(true);\n                }\n                //Refresh reCaptcha after failed request.\n                setCouponCodeAction.registerFailCallback(function () {\n                    if (self.getIsInvisibleRecaptcha()) {\n                        grecaptcha.execute(widgetId);\n                        self.validateReCaptcha(true);\n                    } else {\n                        self.validateReCaptcha(false);\n                        grecaptcha.reset(widgetId);\n                        $('#' + captchaId).show();\n                    }\n                });\n                //Hide captcha when a coupon has been applied.\n                setCouponCodeAction.registerSuccessCallback(function () {\n                    self.validateReCaptcha(true);\n                    $('#' + captchaId).hide();\n                });\n                //Show captcha again if it was canceled.\n                cancelCouponAction.registerSuccessCallback(function () {\n                    self.validateReCaptcha(false);\n                    grecaptcha.reset(widgetId);\n                    $('#' + captchaId).show();\n                });\n            }\n        });\n    });\n","Magento_Swatches/js/catalog-add-to-cart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\nrequire([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    /**\n     * Add selected swatch attributes to redirect url\n     *\n     * @see Magento_Catalog/js/catalog-add-to-cart\n     */\n    $('body').on('catalogCategoryAddToCartRedirect', function (event, data) {\n        $(data.form).find('[name*=\"super\"]').each(function (index, item) {\n            var $item = $(item),\n                attr;\n\n            if ($item.attr('data-attr-name')) {\n                attr = $item.attr('data-attr-name');\n            } else {\n                attr = $item.parent().attr('attribute-code');\n            }\n            data.redirectParameters.push(attr + '=' + $item.val());\n\n        });\n    });\n});\n","Magento_Swatches/js/configurable-customer-data.js":"require([\n    'jquery',\n    'Magento_ConfigurableProduct/js/options-updater'\n], function ($, Updater) {\n    'use strict';\n\n    var selectors = {\n            formSelector: '#product_addtocart_form',\n            swatchSelector: '.swatch-opt'\n        },\n        swatchWidgetName = 'mage-SwatchRenderer',\n        widgetInitEvent = 'swatch.initialized',\n\n    /**\n    * Sets all configurable swatch attribute's selected values\n    */\n    updateSwatchOptions = function () {\n        var swatchWidget = $(selectors.swatchSelector).data(swatchWidgetName);\n\n        if (!swatchWidget || !swatchWidget._EmulateSelectedByAttributeId) {\n            return;\n        }\n        swatchWidget._EmulateSelectedByAttributeId(this.productOptions);\n    },\n    updater = new Updater(widgetInitEvent, updateSwatchOptions);\n\n    updater.listen();\n});\n","Magento_Swatches/js/swatch-renderer.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'underscore',\n    'mage/template',\n    'mage/smart-keyboard-handler',\n    'mage/translate',\n    'priceUtils',\n    'jquery-ui-modules/widget',\n    'jquery/jquery.parsequery',\n    'mage/validation/validation'\n], function ($, _, mageTemplate, keyboardHandler, $t, priceUtils) {\n    'use strict';\n\n    /**\n     * Extend form validation to support swatch accessibility\n     */\n    $.widget('mage.validation', $.mage.validation, {\n        /**\n         * Handle form with swatches validation. Focus on first invalid swatch block.\n         *\n         * @param {jQuery.Event} event\n         * @param {Object} validation\n         */\n        listenFormValidateHandler: function (event, validation) {\n            var swatchWrapper, firstActive, swatches, swatch, successList, errorList, firstSwatch;\n\n            this._superApply(arguments);\n\n            swatchWrapper = '.swatch-attribute-options';\n            swatches = $(event.target).find(swatchWrapper);\n\n            if (!swatches.length) {\n                return;\n            }\n\n            swatch = '.swatch-attribute';\n            firstActive = $(validation.errorList[0].element || []);\n            successList = validation.successList;\n            errorList = validation.errorList;\n            firstSwatch = $(firstActive).parent(swatch).find(swatchWrapper);\n\n            keyboardHandler.focus(swatches);\n\n            $.each(successList, function (index, item) {\n                $(item).parent(swatch).find(swatchWrapper).attr('aria-invalid', false);\n            });\n\n            $.each(errorList, function (index, item) {\n                $(item.element).parent(swatch).find(swatchWrapper).attr('aria-invalid', true);\n            });\n\n            if (firstSwatch.length) {\n                $(firstSwatch).trigger('focus');\n            }\n        }\n    });\n\n    /**\n     * Render tooltips by attributes (only to up).\n     * Required element attributes:\n     *  - data-option-type (integer, 0-3)\n     *  - data-option-label (string)\n     *  - data-option-tooltip-thumb\n     *  - data-option-tooltip-value\n     *  - data-thumb-width\n     *  - data-thumb-height\n     */\n    $.widget('mage.SwatchRendererTooltip', {\n        options: {\n            delay: 200,                             //how much ms before tooltip to show\n            tooltipClass: 'swatch-option-tooltip'  //configurable, but remember about css\n        },\n\n        /**\n         * @private\n         */\n        _init: function () {\n            var $widget = this,\n                $this = this.element,\n                $element = $('.' + $widget.options.tooltipClass),\n                timer,\n                type = parseInt($this.data('option-type'), 10),\n                label = $this.data('option-label'),\n                thumb = $this.data('option-tooltip-thumb'),\n                value = $this.data('option-tooltip-value'),\n                width = $this.data('thumb-width'),\n                height = $this.data('thumb-height'),\n                $image,\n                $title,\n                $corner;\n\n            if (!$element.length) {\n                $element = $('<div class=\"' +\n                    $widget.options.tooltipClass +\n                    '\"><div class=\"image\"></div><div class=\"title\"></div><div class=\"corner\"></div></div>'\n                );\n                $('body').append($element);\n            }\n\n            $image = $element.find('.image');\n            $title = $element.find('.title');\n            $corner = $element.find('.corner');\n\n            $this.on('mouseenter', function () {\n                if (!$this.hasClass('disabled')) {\n                    timer = setTimeout(\n                        function () {\n                            var leftOpt = null,\n                                leftCorner = 0,\n                                left,\n                                $window;\n\n                            if (type === 2) {\n                                // Image\n                                $image.css({\n                                    'background': 'url(\"' + thumb + '\") no-repeat center', //Background case\n                                    'background-size': 'initial',\n                                    'width': width + 'px',\n                                    'height': height + 'px'\n                                });\n                                $image.show();\n                            } else if (type === 1) {\n                                // Color\n                                $image.css({\n                                    background: value\n                                });\n                                $image.show();\n                            } else if (type === 0 || type === 3) {\n                                // Default\n                                $image.hide();\n                            }\n\n                            $title.text(label);\n\n                            leftOpt = $this.offset().left;\n                            left = leftOpt + $this.width() / 2 - $element.width() / 2;\n                            $window = $(window);\n\n                            // the numbers (5 and 5) is magick constants for offset from left or right page\n                            if (left < 0) {\n                                left = 5;\n                            } else if (left + $element.width() > $window.width()) {\n                                left = $window.width() - $element.width() - 5;\n                            }\n\n                            // the numbers (6,  3 and 18) is magick constants for offset tooltip\n                            leftCorner = 0;\n\n                            if ($element.width() < $this.width()) {\n                                leftCorner = $element.width() / 2 - 3;\n                            } else {\n                                leftCorner = (leftOpt > left ? leftOpt - left : left - leftOpt) + $this.width() / 2 - 6;\n                            }\n\n                            $corner.css({\n                                left: leftCorner\n                            });\n                            $element.css({\n                                left: left,\n                                top: $this.offset().top - $element.height() - $corner.height() - 18\n                            }).show();\n                        },\n                        $widget.options.delay\n                    );\n                }\n            });\n\n            $this.on('mouseleave', function () {\n                $element.hide();\n                clearTimeout(timer);\n            });\n\n            $(document).on('tap', function () {\n                $element.hide();\n                clearTimeout(timer);\n            });\n\n            $this.on('tap', function (event) {\n                event.stopPropagation();\n            });\n        }\n    });\n\n    /**\n     * Render swatch controls with options and use tooltips.\n     * Required two json:\n     *  - jsonConfig (magento's option config)\n     *  - jsonSwatchConfig (swatch's option config)\n     *\n     *  Tuning:\n     *  - numberToShow (show \"more\" button if options are more)\n     *  - onlySwatches (hide selectboxes)\n     *  - moreButtonText (text for \"more\" button)\n     *  - selectorProduct (selector for product container)\n     *  - selectorProductPrice (selector for change price)\n     */\n    $.widget('mage.SwatchRenderer', {\n        options: {\n            classes: {\n                attributeClass: 'swatch-attribute',\n                attributeLabelClass: 'swatch-attribute-label',\n                attributeSelectedOptionLabelClass: 'swatch-attribute-selected-option',\n                attributeOptionsWrapper: 'swatch-attribute-options',\n                attributeInput: 'swatch-input',\n                optionClass: 'swatch-option',\n                selectClass: 'swatch-select',\n                moreButton: 'swatch-more',\n                loader: 'swatch-option-loading'\n            },\n            // option's json config\n            jsonConfig: {},\n\n            // swatch's json config\n            jsonSwatchConfig: {},\n\n            // selector of parental block of prices and swatches (need to know where to seek for price block)\n            selectorProduct: '.product-info-main',\n\n            // selector of price wrapper (need to know where set price)\n            selectorProductPrice: '[data-role=priceBox]',\n\n            //selector of product images gallery wrapper\n            mediaGallerySelector: '[data-gallery-role=gallery-placeholder]',\n\n            // selector of category product tile wrapper\n            selectorProductTile: '.product-item',\n\n            // number of controls to show (false or zero = show all)\n            numberToShow: false,\n\n            // show only swatch controls\n            onlySwatches: false,\n\n            // enable label for control\n            enableControlLabel: true,\n\n            // control label id\n            controlLabelId: '',\n\n            // text for more button\n            moreButtonText: $t('More'),\n\n            // Callback url for media\n            mediaCallback: '',\n\n            // Local media cache\n            mediaCache: {},\n\n            // Cache for BaseProduct images. Needed when option unset\n            mediaGalleryInitial: [{}],\n\n            // Use ajax to get image data\n            useAjax: false,\n\n            /**\n             * Defines the mechanism of how images of a gallery should be\n             * updated when user switches between configurations of a product.\n             *\n             * As for now value of this option can be either 'replace' or 'prepend'.\n             *\n             * @type {String}\n             */\n            gallerySwitchStrategy: 'replace',\n\n            // whether swatches are rendered in product list or on product page\n            inProductList: false,\n\n            // sly-old-price block selector\n            slyOldPriceSelector: '.sly-old-price',\n\n            // tier prise selectors start\n            tierPriceTemplateSelector: '#tier-prices-template',\n            tierPriceBlockSelector: '[data-role=\"tier-price-block\"]',\n            tierPriceTemplate: '',\n            // tier prise selectors end\n\n            // A price label selector\n            normalPriceLabelSelector: '.product-info-main .normal-price .price-label',\n            qtyInfo: '#qty'\n        },\n\n        /**\n         * Get chosen product\n         *\n         * @returns int|null\n         */\n        getProduct: function () {\n            var products = this._CalcProducts();\n\n            return _.isArray(products) ? products[0] : null;\n        },\n\n        /**\n         * Get chosen product id\n         *\n         * @returns int|null\n         */\n        getProductId: function () {\n            var products = this._CalcProducts();\n\n            return _.isArray(products) && products.length === 1 ? products[0] : null;\n        },\n\n        /**\n         * @private\n         */\n        _init: function () {\n            // Don't render the same set of swatches twice\n            if ($(this.element).attr('data-rendered')) {\n                return;\n            }\n\n            $(this.element).attr('data-rendered', true);\n\n            if (_.isEmpty(this.options.jsonConfig.images)) {\n                this.options.useAjax = true;\n                // creates debounced variant of _LoadProductMedia()\n                // to use it in events handlers instead of _LoadProductMedia()\n                this._debouncedLoadProductMedia = _.debounce(this._LoadProductMedia.bind(this), 500);\n            }\n\n            this.options.tierPriceTemplate = $(this.options.tierPriceTemplateSelector).html();\n\n            if (this.options.jsonConfig !== '' && this.options.jsonSwatchConfig !== '') {\n                // store unsorted attributes\n                this.options.jsonConfig.mappedAttributes = _.clone(this.options.jsonConfig.attributes);\n                this._sortAttributes();\n                this._RenderControls();\n                this._setPreSelectedGallery();\n                $(this.element).trigger('swatch.initialized');\n            } else {\n                console.log('SwatchRenderer: No input data received');\n            }\n        },\n\n        /**\n         * @private\n         */\n        _sortAttributes: function () {\n            this.options.jsonConfig.attributes = _.sortBy(this.options.jsonConfig.attributes, function (attribute) {\n                return parseInt(attribute.position, 10);\n            });\n        },\n\n        /**\n         * @private\n         */\n        _create: function () {\n            var options = this.options,\n                gallery = $('[data-gallery-role=gallery-placeholder]', '.column.main'),\n                productData = this._determineProductData(),\n                $main = productData.isInProductView ?\n                    this.element.parents('.column.main') :\n                    this.element.parents('.product-item-info');\n\n            if (productData.isInProductView) {\n                gallery.data('gallery') ?\n                    this._onGalleryLoaded(gallery) :\n                    gallery.on('gallery:loaded', this._onGalleryLoaded.bind(this, gallery));\n            } else {\n                options.mediaGalleryInitial = [{\n                    'img': $main.find('.product-image-photo').attr('src')\n                }];\n            }\n\n            this.productForm = this.element.parents(this.options.selectorProductTile).find('form:first');\n            this.inProductList = this.productForm.length > 0;\n            $(this.options.qtyInfo).on('input', this._onQtyChanged.bind(this));\n        },\n\n        /**\n         * Determine product id and related data\n         *\n         * @returns {{productId: *, isInProductView: bool}}\n         * @private\n         */\n        _determineProductData: function () {\n            // Check if product is in a list of products.\n            var productId,\n                isInProductView = false;\n\n            productId = this.element.parents('.product-item-details')\n                    .find('.price-box.price-final_price').attr('data-product-id');\n\n            if (!productId) {\n                // Check individual product.\n                productId = $('[name=product]').val();\n                isInProductView = productId > 0;\n            }\n\n            return {\n                productId: productId,\n                isInProductView: isInProductView\n            };\n        },\n\n        /**\n         * Render controls\n         *\n         * @private\n         */\n        _RenderControls: function () {\n            var $widget = this,\n                container = this.element,\n                classes = this.options.classes,\n                chooseText = this.options.jsonConfig.chooseText,\n                showTooltip = this.options.showTooltip;\n\n            $widget.optionsMap = {};\n\n            $.each(this.options.jsonConfig.attributes, function () {\n                var item = this,\n                    controlLabelId = 'option-label-' + item.code + '-' + item.id,\n                    options = $widget._RenderSwatchOptions(item, controlLabelId),\n                    select = $widget._RenderSwatchSelect(item, chooseText),\n                    input = $widget._RenderFormInput(item),\n                    listLabel = '',\n                    label = '';\n\n                // Show only swatch controls\n                if ($widget.options.onlySwatches && !$widget.options.jsonSwatchConfig.hasOwnProperty(item.id)) {\n                    return;\n                }\n\n                if ($widget.options.enableControlLabel) {\n                    label +=\n                        '<span id=\"' + controlLabelId + '\" class=\"' + classes.attributeLabelClass + '\">' +\n                        $('<i></i>').text(item.label).html() +\n                        '</span>' +\n                        '<span class=\"' + classes.attributeSelectedOptionLabelClass + '\"></span>';\n                }\n\n                if ($widget.inProductList) {\n                    $widget.productForm.append(input);\n                    input = '';\n                    listLabel = 'aria-label=\"' + $('<i></i>').text(item.label).html() + '\"';\n                } else {\n                    listLabel = 'aria-labelledby=\"' + controlLabelId + '\"';\n                }\n\n                // Create new control\n                container.append(\n                    '<div class=\"' + classes.attributeClass + ' ' + item.code + '\" ' +\n                         'data-attribute-code=\"' + item.code + '\" ' +\n                         'data-attribute-id=\"' + item.id + '\">' +\n                        label +\n                        '<div aria-activedescendant=\"\" ' +\n                             'tabindex=\"0\" ' +\n                             'aria-invalid=\"false\" ' +\n                             'aria-required=\"true\" ' +\n                             'role=\"listbox\" ' + listLabel +\n                             'class=\"' + classes.attributeOptionsWrapper + ' clearfix\">' +\n                            options + select +\n                        '</div>' + input +\n                    '</div>'\n                );\n\n                $widget.optionsMap[item.id] = {};\n\n                // Aggregate options array to hash (key => value)\n                $.each(item.options, function () {\n                    if (this.products.length > 0) {\n                        $widget.optionsMap[item.id][this.id] = {\n                            price: parseInt(\n                                $widget.options.jsonConfig.optionPrices[this.products[0]].finalPrice.amount,\n                                10\n                            ),\n                            products: this.products\n                        };\n                    }\n                });\n            });\n\n            if (showTooltip === 1) {\n                // Connect Tooltip\n                container\n                    .find('[data-option-type=\"1\"], [data-option-type=\"2\"],' +\n                        ' [data-option-type=\"0\"], [data-option-type=\"3\"]')\n                    .SwatchRendererTooltip();\n            }\n\n            // Hide all elements below more button\n            $('.' + classes.moreButton).nextAll().hide();\n\n            // Handle events like click or change\n            $widget._EventListener();\n\n            // Rewind options\n            $widget._Rewind(container);\n\n            //Emulate click on all swatches from Request\n            $widget._EmulateSelected($.parseQuery());\n            $widget._EmulateSelected($widget._getSelectedAttributes());\n        },\n\n        disableSwatchForOutOfStockProducts: function () {\n            let $widget = this, container = this.element;\n\n            $.each(this.options.jsonConfig.attributes, function () {\n                let item = this;\n\n                if ($widget.options.jsonConfig.canDisplayShowOutOfStockStatus) {\n                    let salableProducts = $widget.options.jsonConfig.salable[item.id],\n                        swatchOptions = $(container).find(`[data-attribute-id='${item.id}']`).find('.swatch-option');\n\n                    swatchOptions.each(function (key, value) {\n                        let optionId = $(value).data('option-id');\n\n                        if (!salableProducts.hasOwnProperty(optionId)) {\n                            $(value).attr('disabled', true).addClass('disabled');\n                        }\n                    });\n                }\n            });\n        },\n\n        /**\n         * Render swatch options by part of config\n         *\n         * @param {Object} config\n         * @param {String} controlId\n         * @returns {String}\n         * @private\n         */\n        _RenderSwatchOptions: function (config, controlId) {\n            var optionConfig = this.options.jsonSwatchConfig[config.id],\n                optionClass = this.options.classes.optionClass,\n                sizeConfig = this.options.jsonSwatchImageSizeConfig,\n                moreLimit = parseInt(this.options.numberToShow, 10),\n                moreClass = this.options.classes.moreButton,\n                moreText = this.options.moreButtonText,\n                countAttributes = 0,\n                html = '';\n\n            if (!this.options.jsonSwatchConfig.hasOwnProperty(config.id)) {\n                return '';\n            }\n\n            $.each(config.options, function (index) {\n                var id,\n                    type,\n                    value,\n                    thumb,\n                    label,\n                    width,\n                    height,\n                    attr,\n                    swatchImageWidth,\n                    swatchImageHeight;\n\n                if (!optionConfig.hasOwnProperty(this.id)) {\n                    return '';\n                }\n\n                // Add more button\n                if (moreLimit === countAttributes++) {\n                    html += '<a href=\"#\" class=\"' + moreClass + '\"><span>' + moreText + '</span></a>';\n                }\n\n                id = this.id;\n                type = parseInt(optionConfig[id].type, 10);\n                value = optionConfig[id].hasOwnProperty('value') ?\n                    $('<i></i>').text(optionConfig[id].value).html() : '';\n                thumb = optionConfig[id].hasOwnProperty('thumb') ? optionConfig[id].thumb : '';\n                width = _.has(sizeConfig, 'swatchThumb') ? sizeConfig.swatchThumb.width : 110;\n                height = _.has(sizeConfig, 'swatchThumb') ? sizeConfig.swatchThumb.height : 90;\n                label = this.label ? $('<i></i>').text(this.label).html() : '';\n                attr =\n                    ' id=\"' + controlId + '-item-' + id + '\"' +\n                    ' index=\"' + index + '\"' +\n                    ' aria-checked=\"false\"' +\n                    ' aria-describedby=\"' + controlId + '\"' +\n                    ' tabindex=\"0\"' +\n                    ' data-option-type=\"' + type + '\"' +\n                    ' data-option-id=\"' + id + '\"' +\n                    ' data-option-label=\"' + label + '\"' +\n                    ' aria-label=\"' + label + '\"' +\n                    ' role=\"option\"' +\n                    ' data-thumb-width=\"' + width + '\"' +\n                    ' data-thumb-height=\"' + height + '\"';\n\n                attr += thumb !== '' ? ' data-option-tooltip-thumb=\"' + thumb + '\"' : '';\n                attr += value !== '' ? ' data-option-tooltip-value=\"' + value + '\"' : '';\n\n                swatchImageWidth = _.has(sizeConfig, 'swatchImage') ? sizeConfig.swatchImage.width : 30;\n                swatchImageHeight = _.has(sizeConfig, 'swatchImage') ? sizeConfig.swatchImage.height : 20;\n\n                if (!this.hasOwnProperty('products') || this.products.length <= 0) {\n                    attr += ' data-option-empty=\"true\"';\n                }\n\n                if (type === 0) {\n                    // Text\n                    html += '<div class=\"' + optionClass + ' text\" ' + attr + '>' + (value ? value : label) +\n                        '</div>';\n                } else if (type === 1) {\n                    // Color\n                    html += '<div class=\"' + optionClass + ' color\" ' + attr +\n                        ' style=\"background: ' + value +\n                        ' no-repeat center; background-size: initial;\">' + '' +\n                        '</div>';\n                } else if (type === 2) {\n                    // Image\n                    html += '<div class=\"' + optionClass + ' image\" ' + attr +\n                        ' style=\"background: url(' + value + ') no-repeat center; background-size: initial;width:' +\n                        swatchImageWidth + 'px; height:' + swatchImageHeight + 'px\">' + '' +\n                        '</div>';\n                } else if (type === 3) {\n                    // Clear\n                    html += '<div class=\"' + optionClass + '\" ' + attr + '></div>';\n                } else {\n                    // Default\n                    html += '<div class=\"' + optionClass + '\" ' + attr + '>' + label + '</div>';\n                }\n            });\n\n            return html;\n        },\n\n        /**\n         * Render select by part of config\n         *\n         * @param {Object} config\n         * @param {String} chooseText\n         * @returns {String}\n         * @private\n         */\n        _RenderSwatchSelect: function (config, chooseText) {\n            var html;\n\n            if (this.options.jsonSwatchConfig.hasOwnProperty(config.id)) {\n                return '';\n            }\n\n            html =\n                '<select class=\"' + this.options.classes.selectClass + ' ' + config.code + '\">' +\n                '<option value=\"0\" data-option-id=\"0\">' + chooseText + '</option>';\n\n            $.each(config.options, function () {\n                var label = this.label,\n                    attr = ' value=\"' + this.id + '\" data-option-id=\"' + this.id + '\"';\n\n                if (!this.hasOwnProperty('products') || this.products.length <= 0) {\n                    attr += ' data-option-empty=\"true\"';\n                }\n\n                html += '<option ' + attr + '>' + label + '</option>';\n            });\n\n            html += '</select>';\n\n            return html;\n        },\n\n        /**\n         * Input for submit form.\n         * This control shouldn't have \"type=hidden\", \"display: none\" for validation work :(\n         *\n         * @param {Object} config\n         * @private\n         */\n        _RenderFormInput: function (config) {\n            return '<input class=\"' + this.options.classes.attributeInput + ' super-attribute-select\" ' +\n                'name=\"super_attribute[' + config.id + ']\" ' +\n                'type=\"text\" ' +\n                'value=\"\" ' +\n                'data-selector=\"super_attribute[' + config.id + ']\" ' +\n                'data-validate=\"{required: true}\" ' +\n                'aria-required=\"true\" ' +\n                'aria-invalid=\"false\">';\n        },\n\n        /**\n         * Event listener\n         *\n         * @private\n         */\n        _EventListener: function () {\n            var $widget = this,\n                options = this.options.classes,\n                target;\n\n            $widget.element.on('click', '.' + options.optionClass, function () {\n                return $widget._OnClick($(this), $widget);\n            });\n\n            $widget.element.on('change', '.' + options.selectClass, function () {\n                return $widget._OnChange($(this), $widget);\n            });\n\n            $widget.element.on('click', '.' + options.moreButton, function (e) {\n                e.preventDefault();\n\n                return $widget._OnMoreClick($(this));\n            });\n\n            $widget.element.on('keydown', function (e) {\n                if (e.which === 13) {\n                    target = $(e.target);\n\n                    if (target.is('.' + options.optionClass)) {\n                        return $widget._OnClick(target, $widget);\n                    } else if (target.is('.' + options.selectClass)) {\n                        return $widget._OnChange(target, $widget);\n                    } else if (target.is('.' + options.moreButton)) {\n                        e.preventDefault();\n\n                        return $widget._OnMoreClick(target);\n                    }\n                }\n            });\n        },\n\n        /**\n         * Load media gallery using ajax or json config.\n         *\n         * @private\n         */\n        _loadMedia: function () {\n            var $main = this.inProductList ?\n                    this.element.parents('.product-item-info') :\n                    this.element.parents('.column.main'),\n                images;\n\n            if (this.options.useAjax) {\n                this._debouncedLoadProductMedia();\n            }  else {\n                images = this.options.jsonConfig.images[this.getProduct()];\n\n                if (!images) {\n                    images = this.options.mediaGalleryInitial;\n                }\n                this.updateBaseImage(this._sortImages(images), $main, !this.inProductList);\n            }\n        },\n\n        /**\n         * Sorting images array\n         *\n         * @private\n         */\n        _sortImages: function (images) {\n            return _.sortBy(images, function (image) {\n                return parseInt(image.position, 10);\n            });\n        },\n\n        /**\n         * Event for swatch options\n         *\n         * @param {Object} $this\n         * @param {Object} $widget\n         * @private\n         */\n        _OnClick: function ($this, $widget) {\n            var $parent = $this.parents('.' + $widget.options.classes.attributeClass),\n                $wrapper = $this.parents('.' + $widget.options.classes.attributeOptionsWrapper),\n                $label = $parent.find('.' + $widget.options.classes.attributeSelectedOptionLabelClass),\n                attributeId = $parent.data('attribute-id'),\n                $input = $parent.find('.' + $widget.options.classes.attributeInput),\n                checkAdditionalData = JSON.parse(this.options.jsonSwatchConfig[attributeId]['additional_data']),\n                $priceBox = $widget.element.parents($widget.options.selectorProduct)\n                    .find(this.options.selectorProductPrice);\n\n            if ($widget.inProductList) {\n                $input = $widget.productForm.find(\n                    '.' + $widget.options.classes.attributeInput + '[name=\"super_attribute[' + attributeId + ']\"]'\n                );\n            }\n\n            if ($this.hasClass('disabled')) {\n                return;\n            }\n\n            if ($this.hasClass('selected')) {\n                $parent.removeAttr('data-option-selected').find('.selected').removeClass('selected');\n                $input.val('');\n                $label.text('');\n                $this.attr('aria-checked', false);\n            } else {\n                $parent.attr('data-option-selected', $this.data('option-id')).find('.selected').removeClass('selected');\n                $label.text($this.data('option-label'));\n                $input.val($this.data('option-id'));\n                $input.attr('data-attr-name', this._getAttributeCodeById(attributeId));\n                $this.addClass('selected');\n                $widget._toggleCheckedAttributes($this, $wrapper);\n            }\n\n            $widget._Rebuild();\n\n            if ($priceBox.is(':data(mage-priceBox)')) {\n                $widget._UpdatePrice();\n            }\n\n            $(document).trigger('updateMsrpPriceBlock',\n                [\n                    this._getSelectedOptionPriceIndex(),\n                    $widget.options.jsonConfig.optionPrices,\n                    $priceBox\n                ]);\n\n            if (parseInt(checkAdditionalData['update_product_preview_image'], 10) === 1) {\n                $widget._loadMedia();\n            }\n\n            $input.trigger('change');\n        },\n\n        /**\n         * Get selected option price index\n         *\n         * @return {String|undefined}\n         * @private\n         */\n        _getSelectedOptionPriceIndex: function () {\n            var allowedProduct = this._getAllowedProductWithMinPrice(this._CalcProducts());\n\n            if (_.isEmpty(allowedProduct)) {\n                return undefined;\n            }\n\n            return allowedProduct;\n        },\n\n        /**\n         * Get human readable attribute code (eg. size, color) by it ID from configuration\n         *\n         * @param {Number} attributeId\n         * @returns {*}\n         * @private\n         */\n        _getAttributeCodeById: function (attributeId) {\n            var attribute = this.options.jsonConfig.mappedAttributes[attributeId];\n\n            return attribute ? attribute.code : attributeId;\n        },\n\n        /**\n         * Toggle accessibility attributes\n         *\n         * @param {Object} $this\n         * @param {Object} $wrapper\n         * @private\n         */\n        _toggleCheckedAttributes: function ($this, $wrapper) {\n            $wrapper.attr('aria-activedescendant', $this.attr('id'))\n                    .find('.' + this.options.classes.optionClass).attr('aria-checked', false);\n            $this.attr('aria-checked', true);\n        },\n\n        /**\n         * Event for select\n         *\n         * @param {Object} $this\n         * @param {Object} $widget\n         * @private\n         */\n        _OnChange: function ($this, $widget) {\n            var $parent = $this.parents('.' + $widget.options.classes.attributeClass),\n                attributeId = $parent.data('attribute-id'),\n                $input = $parent.find('.' + $widget.options.classes.attributeInput);\n\n            if ($widget.productForm.length > 0) {\n                $input = $widget.productForm.find(\n                    '.' + $widget.options.classes.attributeInput + '[name=\"super_attribute[' + attributeId + ']\"]'\n                );\n            }\n\n            if ($this.val() > 0) {\n                $parent.attr('data-option-selected', $this.val());\n                $input.val($this.val());\n            } else {\n                $parent.removeAttr('data-option-selected');\n                $input.val('');\n            }\n\n            $widget._Rebuild();\n            $widget._UpdatePrice();\n            $widget._loadMedia();\n            $input.trigger('change');\n        },\n\n        /**\n         * Event for more switcher\n         *\n         * @param {Object} $this\n         * @private\n         */\n        _OnMoreClick: function ($this) {\n            $this.nextAll().show();\n            $this.trigger('blur').remove();\n        },\n\n        /**\n         * Rewind options for controls\n         *\n         * @private\n         */\n        _Rewind: function (controls) {\n            controls.find('div[data-option-id], option[data-option-id]')\n                .removeClass('disabled')\n                .prop('disabled', false);\n            controls.find('div[data-option-empty], option[data-option-empty]')\n                .attr('disabled', true)\n                .addClass('disabled')\n                .attr('tabindex', '-1');\n            this.disableSwatchForOutOfStockProducts();\n        },\n\n        /**\n         * Rebuild container\n         *\n         * @private\n         */\n        _Rebuild: function () {\n            var $widget = this,\n                controls = $widget.element.find('.' + $widget.options.classes.attributeClass + '[data-attribute-id]'),\n                selected = controls.filter('[data-option-selected]');\n\n            // Enable all options\n            $widget._Rewind(controls);\n\n            // done if nothing selected\n            if (selected.length <= 0) {\n                return;\n            }\n\n            // Disable not available options\n            controls.each(function () {\n                var $this = $(this),\n                    id = $this.data('attribute-id'),\n                    products = $widget._CalcProducts(id);\n\n                if (selected.length === 1 && selected.first().data('attribute-id') === id) {\n                    return;\n                }\n\n                $this.find('[data-option-id]').each(function () {\n                    var $element = $(this),\n                        option = $element.data('option-id');\n\n                    if (!$widget.optionsMap.hasOwnProperty(id) || !$widget.optionsMap[id].hasOwnProperty(option) ||\n                        $element.hasClass('selected') ||\n                        $element.is(':selected')) {\n                        return;\n                    }\n\n                    if (_.intersection(products, $widget.optionsMap[id][option].products).length <= 0) {\n                        $element.attr('disabled', true).addClass('disabled');\n                    }\n                });\n            });\n        },\n\n        /**\n         * Get selected product list\n         *\n         * @returns {Array}\n         * @private\n         */\n        _CalcProducts: function ($skipAttributeId) {\n            var $widget = this,\n                selectedOptions = '.' + $widget.options.classes.attributeClass + '[data-option-selected]',\n                products = [];\n\n            // Generate intersection of products\n            $widget.element.find(selectedOptions).each(function () {\n                var id = $(this).data('attribute-id'),\n                    option = $(this).attr('data-option-selected');\n\n                if ($skipAttributeId !== undefined && $skipAttributeId === id) {\n                    return;\n                }\n\n                if (!$widget.optionsMap.hasOwnProperty(id) || !$widget.optionsMap[id].hasOwnProperty(option)) {\n                    return;\n                }\n\n                if (products.length === 0) {\n                    products = $widget.optionsMap[id][option].products;\n                } else {\n                    products = _.intersection(products, $widget.optionsMap[id][option].products);\n                }\n            });\n\n            return products;\n        },\n\n        /**\n         * Update total price\n         *\n         * @private\n         */\n        _UpdatePrice: function () {\n            var $widget = this,\n                $product = $widget.element.parents($widget.options.selectorProduct),\n                $productPrice = $product.find(this.options.selectorProductPrice),\n                result = $widget._getNewPrices(),\n                tierPriceHtml,\n                isShow;\n\n            $productPrice.trigger(\n                'updatePrice',\n                {\n                    'prices': $widget._getPrices(result, $productPrice.priceBox('option').prices)\n                }\n            );\n\n            isShow = typeof result != 'undefined' && result.oldPrice.amount !== result.finalPrice.amount;\n\n            $productPrice.find('span:first').toggleClass('special-price', isShow);\n\n            $product.find(this.options.slyOldPriceSelector)[isShow ? 'show' : 'hide']();\n\n            if (typeof result != 'undefined' && result.tierPrices && result.tierPrices.length) {\n                if (this.options.tierPriceTemplate) {\n                    tierPriceHtml = mageTemplate(\n                        this.options.tierPriceTemplate,\n                        {\n                            'tierPrices': result.tierPrices,\n                            '$t': $t,\n                            'currencyFormat': this.options.jsonConfig.currencyFormat,\n                            'priceUtils': priceUtils\n                        }\n                    );\n                    $(this.options.tierPriceBlockSelector).html(tierPriceHtml).show();\n                }\n            } else {\n                $(this.options.tierPriceBlockSelector).hide();\n            }\n\n            $(this.options.normalPriceLabelSelector).hide();\n\n            _.each($('.' + this.options.classes.attributeOptionsWrapper), function (attribute) {\n                if ($(attribute).find('.' + this.options.classes.optionClass + '.selected').length === 0) {\n                    if ($(attribute).find('.' + this.options.classes.selectClass).length > 0) {\n                        _.each($(attribute).find('.' + this.options.classes.selectClass), function (dropdown) {\n                            if ($(dropdown).val() === '0') {\n                                $(this.options.normalPriceLabelSelector).show();\n                            }\n                        }.bind(this));\n                    } else {\n                        $(this.options.normalPriceLabelSelector).show();\n                    }\n                }\n            }.bind(this));\n        },\n\n        /**\n         * Get new prices for selected options\n         *\n         * @returns {*}\n         * @private\n         */\n        _getNewPrices: function () {\n            var $widget = this,\n                newPrices = $widget.options.jsonConfig.prices,\n                allowedProduct = this._getAllowedProductWithMinPrice(this._CalcProducts());\n\n            if (!_.isEmpty(allowedProduct)) {\n                newPrices = this.options.jsonConfig.optionPrices[allowedProduct];\n            }\n\n            return newPrices;\n        },\n\n        /**\n         * Get prices\n         *\n         * @param {Object} newPrices\n         * @param {Object} displayPrices\n         * @returns {*}\n         * @private\n         */\n        _getPrices: function (newPrices, displayPrices) {\n            var $widget = this;\n\n            if (_.isEmpty(newPrices)) {\n                newPrices = $widget._getNewPrices();\n            }\n            _.each(displayPrices, function (price, code) {\n\n                if (newPrices[code]) {\n                    displayPrices[code].amount = newPrices[code].amount - displayPrices[code].amount;\n                }\n            });\n\n            return displayPrices;\n        },\n\n        /**\n         * Get product with minimum price from selected options.\n         *\n         * @param {Array} allowedProducts\n         * @returns {String}\n         * @private\n         */\n        _getAllowedProductWithMinPrice: function (allowedProducts) {\n            var optionPrices = this.options.jsonConfig.optionPrices,\n                product = {},\n                optionFinalPrice, optionMinPrice;\n\n            _.each(allowedProducts, function (allowedProduct) {\n                optionFinalPrice = parseFloat(optionPrices[allowedProduct].finalPrice.amount);\n\n                if (_.isEmpty(product) || optionFinalPrice < optionMinPrice) {\n                    optionMinPrice = optionFinalPrice;\n                    product = allowedProduct;\n                }\n            }, this);\n\n            return product;\n        },\n\n        /**\n         * Gets all product media and change current to the needed one\n         *\n         * @private\n         */\n        _LoadProductMedia: function () {\n            var $widget = this,\n                $this = $widget.element,\n                productData = this._determineProductData(),\n                mediaCallData,\n                mediaCacheKey,\n\n                /**\n                 * Processes product media data\n                 *\n                 * @param {Object} data\n                 * @returns void\n                 */\n                mediaSuccessCallback = function (data) {\n                    if (!(mediaCacheKey in $widget.options.mediaCache)) {\n                        $widget.options.mediaCache[mediaCacheKey] = data;\n                    }\n                    $widget._ProductMediaCallback($this, data, productData.isInProductView);\n                    setTimeout(function () {\n                        $widget._DisableProductMediaLoader($this);\n                    }, 300);\n                };\n\n            if (!$widget.options.mediaCallback) {\n                return;\n            }\n\n            mediaCallData = {\n                'product_id': this.getProduct()\n            };\n\n            mediaCacheKey = JSON.stringify(mediaCallData);\n\n            if (mediaCacheKey in $widget.options.mediaCache) {\n                $widget._XhrKiller();\n                $widget._EnableProductMediaLoader($this);\n                mediaSuccessCallback($widget.options.mediaCache[mediaCacheKey]);\n            } else {\n                mediaCallData.isAjax = true;\n                $widget._XhrKiller();\n                $widget._EnableProductMediaLoader($this);\n                $widget.xhr = $.ajax({\n                    url: $widget.options.mediaCallback,\n                    cache: true,\n                    type: 'GET',\n                    dataType: 'json',\n                    data: mediaCallData,\n                    success: mediaSuccessCallback\n                }).done(function () {\n                    $widget._XhrKiller();\n                });\n            }\n        },\n\n        /**\n         * Enable loader\n         *\n         * @param {Object} $this\n         * @private\n         */\n        _EnableProductMediaLoader: function ($this) {\n            var $widget = this;\n\n            if ($('body.catalog-product-view').length > 0) {\n                $this.parents('.column.main').find('.photo.image')\n                    .addClass($widget.options.classes.loader);\n            } else {\n                //Category View\n                $this.parents('.product-item-info').find('.product-image-photo')\n                    .addClass($widget.options.classes.loader);\n            }\n        },\n\n        /**\n         * Disable loader\n         *\n         * @param {Object} $this\n         * @private\n         */\n        _DisableProductMediaLoader: function ($this) {\n            var $widget = this;\n\n            if ($('body.catalog-product-view').length > 0) {\n                $this.parents('.column.main').find('.photo.image')\n                    .removeClass($widget.options.classes.loader);\n            } else {\n                //Category View\n                $this.parents('.product-item-info').find('.product-image-photo')\n                    .removeClass($widget.options.classes.loader);\n            }\n        },\n\n        /**\n         * Callback for product media\n         *\n         * @param {Object} $this\n         * @param {String} response\n         * @param {Boolean} isInProductView\n         * @private\n         */\n        _ProductMediaCallback: function ($this, response, isInProductView) {\n            var $main = isInProductView ? $this.parents('.column.main') : $this.parents('.product-item-info'),\n                $widget = this,\n                images = [],\n\n                /**\n                 * Check whether object supported or not\n                 *\n                 * @param {Object} e\n                 * @returns {*|Boolean}\n                 */\n                support = function (e) {\n                    return e.hasOwnProperty('large') && e.hasOwnProperty('medium') && e.hasOwnProperty('small');\n                };\n\n            if (_.size($widget) < 1 || !support(response)) {\n                this.updateBaseImage(this.options.mediaGalleryInitial, $main, isInProductView);\n\n                return;\n            }\n\n            images.push({\n                full: response.large,\n                img: response.medium,\n                thumb: response.small,\n                isMain: true\n            });\n\n            if (response.hasOwnProperty('gallery')) {\n                $.each(response.gallery, function () {\n                    if (!support(this) || response.large === this.large) {\n                        return;\n                    }\n                    images.push({\n                        full: this.large,\n                        img: this.medium,\n                        thumb: this.small\n                    });\n                });\n            }\n\n            this.updateBaseImage(images, $main, isInProductView);\n        },\n\n        /**\n         * Check if images to update are initial and set their type\n         * @param {Array} images\n         */\n        _setImageType: function (images) {\n\n            images.map(function (img) {\n                if (!img.type) {\n                    img.type = 'image';\n                }\n            });\n\n            return images;\n        },\n\n        /**\n         * Update [gallery-placeholder] or [product-image-photo]\n         * @param {Array} images\n         * @param {jQuery} context\n         * @param {Boolean} isInProductView\n         */\n        updateBaseImage: function (images, context, isInProductView) {\n            var justAnImage = images[0],\n                initialImages = this.options.mediaGalleryInitial,\n                imagesToUpdate,\n                gallery = context.find(this.options.mediaGallerySelector).data('gallery'),\n                isInitial;\n\n            if (isInProductView) {\n                if (_.isUndefined(gallery)) {\n                    context.find(this.options.mediaGallerySelector).on('gallery:loaded', function () {\n                        this.updateBaseImage(images, context, isInProductView);\n                    }.bind(this));\n\n                    return;\n                }\n\n                imagesToUpdate = images.length ? this._setImageType($.extend(true, [], images)) : [];\n                isInitial = _.isEqual(imagesToUpdate, initialImages);\n\n                if (this.options.gallerySwitchStrategy === 'prepend' && !isInitial) {\n                    imagesToUpdate = imagesToUpdate.concat(initialImages);\n                }\n\n                imagesToUpdate = this._setImageIndex(imagesToUpdate);\n\n                gallery.updateData(imagesToUpdate);\n                this._addFotoramaVideoEvents(isInitial);\n            } else if (justAnImage && justAnImage.img) {\n                context.find('.product-image-photo').attr('src', justAnImage.img);\n            }\n        },\n\n        /**\n         * Add video events\n         *\n         * @param {Boolean} isInitial\n         * @private\n         */\n        _addFotoramaVideoEvents: function (isInitial) {\n            if (_.isUndefined($.mage.AddFotoramaVideoEvents)) {\n                return;\n            }\n\n            if (isInitial) {\n                $(this.options.mediaGallerySelector).AddFotoramaVideoEvents();\n\n                return;\n            }\n\n            $(this.options.mediaGallerySelector).AddFotoramaVideoEvents({\n                selectedOption: this.getProduct(),\n                dataMergeStrategy: this.options.gallerySwitchStrategy\n            });\n        },\n\n        /**\n         * Set correct indexes for image set.\n         *\n         * @param {Array} images\n         * @private\n         */\n        _setImageIndex: function (images) {\n            var length = images.length,\n                i;\n\n            for (i = 0; length > i; i++) {\n                images[i].i = i + 1;\n            }\n\n            return images;\n        },\n\n        /**\n         * Kill doubled AJAX requests\n         *\n         * @private\n         */\n        _XhrKiller: function () {\n            var $widget = this;\n\n            if ($widget.xhr !== undefined && $widget.xhr !== null) {\n                $widget.xhr.abort();\n                $widget.xhr = null;\n            }\n        },\n\n        /**\n         * Emulate mouse click on all swatches that should be selected\n         * @param {Object} [selectedAttributes]\n         * @private\n         */\n        _EmulateSelected: function (selectedAttributes) {\n            $.each(selectedAttributes, $.proxy(function (attributeCode, optionId) {\n                var elem = this.element.find('.' + this.options.classes.attributeClass +\n                    '[data-attribute-code=\"' + attributeCode + '\"] [data-option-id=\"' + optionId + '\"]'),\n                    parentInput = elem.parent();\n\n                if (elem.hasClass('selected')) {\n                    return;\n                }\n\n                if (parentInput.hasClass(this.options.classes.selectClass)) {\n                    parentInput.val(optionId);\n                    parentInput.trigger('change');\n                } else {\n                    elem.trigger('click');\n                }\n            }, this));\n        },\n\n        /**\n         * Emulate mouse click or selection change on all swatches that should be selected\n         * @param {Object} [selectedAttributes]\n         * @private\n         */\n        _EmulateSelectedByAttributeId: function (selectedAttributes) {\n            $.each(selectedAttributes, $.proxy(function (attributeId, optionId) {\n                var elem = this.element.find('.' + this.options.classes.attributeClass +\n                    '[data-attribute-id=\"' + attributeId + '\"] [data-option-id=\"' + optionId + '\"]'),\n                    parentInput = elem.parent();\n\n                if (elem.hasClass('selected')) {\n                    return;\n                }\n\n                if (parentInput.hasClass(this.options.classes.selectClass)) {\n                    parentInput.val(optionId);\n                    parentInput.trigger('change');\n                } else {\n                    elem.trigger('click');\n                }\n            }, this));\n        },\n\n        /**\n         * Get default options values settings with either URL query parameters\n         * @private\n         */\n        _getSelectedAttributes: function () {\n            var hashIndex = window.location.href.indexOf('#'),\n                selectedAttributes = {},\n                params;\n\n            if (hashIndex !== -1) {\n                params = $.parseQuery(window.location.href.substr(hashIndex + 1));\n\n                selectedAttributes = _.invert(_.mapObject(_.invert(params), function (attributeId) {\n                    var attribute = this.options.jsonConfig.mappedAttributes[attributeId];\n\n                    return attribute ? attribute.code : attributeId;\n                }.bind(this)));\n            }\n\n            return selectedAttributes;\n        },\n\n        /**\n         * Callback which fired after gallery gets initialized.\n         *\n         * @param {HTMLElement} element - DOM element associated with a gallery.\n         */\n        _onGalleryLoaded: function (element) {\n            var galleryObject = element.data('gallery');\n\n            this.options.mediaGalleryInitial = galleryObject.returnCurrentImages();\n        },\n\n        /**\n         * Sets mediaCache for cases when jsonConfig contains preSelectedGallery on layered navigation result pages\n         *\n         * @private\n         */\n        _setPreSelectedGallery: function () {\n            var mediaCallData;\n\n            if (this.options.jsonConfig.preSelectedGallery) {\n                mediaCallData = {\n                    'product_id': this.getProduct()\n                };\n\n                this.options.mediaCache[JSON.stringify(mediaCallData)] = this.options.jsonConfig.preSelectedGallery;\n            }\n        },\n\n        /**\n         * Callback for quantity change event.\n         */\n        _onQtyChanged: function () {\n            var $price = this.element.parents(this.options.selectorProduct)\n                .find(this.options.selectorProductPrice);\n\n            $price.trigger(\n                'updatePrice',\n                {\n                    'prices': this._getPrices(this._getNewPrices(), $price.priceBox('option').prices)\n                }\n            );\n        }\n    });\n\n    return $.mage.SwatchRenderer;\n});\n","Magento_Security/js/escaper.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * A loose JavaScript version of Magento\\Framework\\Escaper\n *\n * Due to differences in how XML/HTML is processed in PHP vs JS there are a couple of minor differences in behavior\n * from the PHP counterpart.\n *\n * The first difference is that the default invocation of escapeHtml without allowedTags will double-escape existing\n * entities as the intention of such an invocation is that the input isn't supposed to contain any HTML.\n *\n * The second difference is that escapeHtml will not escape quotes. Since the input is actually being processed by the\n * DOM there is no chance of quotes being mixed with HTML syntax. And, since escapeHtml is not\n * intended to be used with raw injection into a HTML attribute, this is acceptable.\n *\n * @api\n */\ndefine([], function () {\n    'use strict';\n\n    return {\n        neverAllowedElements: ['script', 'img', 'embed', 'iframe', 'video', 'source', 'object', 'audio'],\n        generallyAllowedAttributes: ['id', 'class', 'href', 'title', 'style'],\n        forbiddenAttributesByElement: {\n            a: ['style']\n        },\n\n        /**\n         * Escape a string for safe injection into HTML\n         *\n         * @param {String} data\n         * @param {Array|null} allowedTags\n         * @returns {String}\n         */\n        escapeHtml: function (data, allowedTags) {\n            var domParser = new DOMParser(),\n                fragment = domParser.parseFromString('<div></div>', 'text/html');\n\n            fragment = fragment.body.childNodes[0];\n            allowedTags = typeof allowedTags === 'object' && allowedTags.length ? allowedTags : null;\n\n            if (allowedTags) {\n                fragment.innerHTML = data || '';\n                allowedTags = this._filterProhibitedTags(allowedTags);\n\n                this._removeComments(fragment);\n                this._removeNotAllowedElements(fragment, allowedTags);\n                this._removeNotAllowedAttributes(fragment);\n\n                return fragment.innerHTML;\n            }\n\n            fragment.textContent = data || '';\n\n            return fragment.innerHTML;\n        },\n\n        /**\n         * Remove the always forbidden tags from a list of provided tags\n         *\n         * @param {Array} tags\n         * @returns {Array}\n         * @private\n         */\n        _filterProhibitedTags: function (tags) {\n            return tags.filter(function (n) {\n                return this.neverAllowedElements.indexOf(n) === -1;\n            }.bind(this));\n        },\n\n        /**\n         * Remove comment nodes from the given node\n         *\n         * @param {Node} node\n         * @private\n         */\n        _removeComments: function (node) {\n            var treeWalker = node.ownerDocument.createTreeWalker(\n                    node,\n                    NodeFilter.SHOW_COMMENT,\n                    function () {\n                        return NodeFilter.FILTER_ACCEPT;\n                    },\n                    false\n                ),\n                nodesToRemove = [];\n\n            while (treeWalker.nextNode()) {\n                nodesToRemove.push(treeWalker.currentNode);\n            }\n\n            nodesToRemove.forEach(function (nodeToRemove) {\n                nodeToRemove.parentNode.removeChild(nodeToRemove);\n            });\n        },\n\n        /**\n         * Strip the given node of all disallowed tags while permitting any nested text nodes\n         *\n         * @param {Node} node\n         * @param {Array|null} allowedTags\n         * @private\n         */\n        _removeNotAllowedElements: function (node, allowedTags) {\n            var treeWalker = node.ownerDocument.createTreeWalker(\n                    node,\n                    NodeFilter.SHOW_ELEMENT,\n                    function (currentNode) {\n                        return allowedTags.indexOf(currentNode.nodeName.toLowerCase()) === -1 ?\n                            NodeFilter.FILTER_ACCEPT\n                            // SKIP instead of REJECT because REJECT also rejects child nodes\n                            : NodeFilter.FILTER_SKIP;\n                    },\n                false\n                ),\n                nodesToRemove = [];\n\n            while (treeWalker.nextNode()) {\n                if (allowedTags.indexOf(treeWalker.currentNode.nodeName.toLowerCase()) === -1) {\n                    nodesToRemove.push(treeWalker.currentNode);\n                }\n            }\n\n            nodesToRemove.forEach(function (nodeToRemove) {\n                nodeToRemove.parentNode.replaceChild(\n                    node.ownerDocument.createTextNode(nodeToRemove.textContent),\n                    nodeToRemove\n                );\n            });\n        },\n\n        /**\n         * Remove any invalid attributes from the given node\n         *\n         * @param {Node} node\n         * @private\n         */\n        _removeNotAllowedAttributes: function (node) {\n            var treeWalker = node.ownerDocument.createTreeWalker(\n                    node,\n                    NodeFilter.SHOW_ELEMENT,\n                    function () {\n                        return NodeFilter.FILTER_ACCEPT;\n                    },\n                false\n                ),\n                i,\n                attribute,\n                nodeName,\n                attributesToRemove = [];\n\n            while (treeWalker.nextNode()) {\n                for (i = 0; i < treeWalker.currentNode.attributes.length; i++) {\n                    attribute = treeWalker.currentNode.attributes[i];\n                    nodeName = treeWalker.currentNode.nodeName.toLowerCase();\n\n                    if (this.generallyAllowedAttributes.indexOf(attribute.name) === -1  || // eslint-disable-line max-depth,max-len\n                        this._checkHrefValue(attribute) ||\n                        this.forbiddenAttributesByElement[nodeName] &&\n                        this.forbiddenAttributesByElement[nodeName].indexOf(attribute.name) !== -1\n                    ) {\n                        attributesToRemove.push(attribute);\n                    }\n                }\n            }\n\n            attributesToRemove.forEach(function (attributeToRemove) {\n                attributeToRemove.ownerElement.removeAttribute(attributeToRemove.name);\n            });\n        },\n\n        /**\n         * Check that attribute contains script content\n         *\n         * @param {Object} attribute\n         * @private\n         */\n        _checkHrefValue: function (attribute) {\n            return attribute.nodeName === 'href' && attribute.nodeValue.startsWith('javascript');\n        }\n    };\n});\n","Magento_GroupedProduct/js/product-ids-resolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'Magento_Catalog/js/product/view/product-ids',\n    'Magento_Catalog/js/product/view/product-info'\n], function ($, productIds, productInfo) {\n    'use strict';\n\n    /**\n     * Returns id's of products in form.\n     *\n     * @param {Object} config\n     * @param {HTMLElement} element\n     * @return {Array}\n     */\n    return function (config, element) {\n        $(element).find('div[data-product-id]').each(function () {\n            productIds.push($(this).data('productId').toString());\n            productInfo.push(\n                {\n                    'id': $(this).data('productId').toString()\n                }\n            );\n        });\n\n        return productIds();\n    };\n});\n","Magento_ReCaptchaPaypal/js/reCaptchaPaypal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(\n    [\n        'Magento_ReCaptchaFrontendUi/js/reCaptcha',\n        'jquery'\n    ],\n    function (Component, $) {\n        'use strict';\n\n        return Component.extend({\n\n            /**\n             * Recaptcha callback\n             * @param {String} token\n             */\n            reCaptchaCallback: function (token) {\n                this.tokenField.value = token;\n                this.$parentForm.trigger('captcha:endExecute');\n            },\n\n            /**\n             * Initialize parent form.\n             *\n             * @param {Object} parentForm\n             * @param {String} widgetId\n             */\n            initParentForm: function (parentForm, widgetId) {\n                var me = this;\n\n                parentForm.on('captcha:startExecute', function (event) {\n                    if (!me.tokenField.value && me.getIsInvisibleRecaptcha()) {\n                        // eslint-disable-next-line no-undef\n                        grecaptcha.execute(widgetId);\n                        event.preventDefault(event);\n                        event.stopImmediatePropagation();\n                    } else {\n                        me.$parentForm.trigger('captcha:endExecute');\n                    }\n                });\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            }\n        });\n    }\n);\n","Magento_ReCaptchaPaypal/js/payflowpro-method-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'Magento_Checkout/js/model/payment/additional-validators'\n], function ($, additionalValidators) {\n    'use strict';\n\n    return function (originalComponent) {\n        return originalComponent.extend({\n            /**\n             * Initializes reCaptcha\n             */\n            placeOrder: function () {\n                var original = this._super.bind(this),\n                    // jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n                    isEnabledForPaypal = window.checkoutConfig.recaptcha_paypal,\n                    // jscs:enable requireCamelCaseOrUpperCaseIdentifiers\n                    paymentFormSelector = $('#co-payment-form'),\n                    startEvent = 'captcha:startExecute',\n                    endEvent = 'captcha:endExecute';\n\n                if (!this.validateHandler() || !additionalValidators.validate() || !isEnabledForPaypal) {\n                    return original();\n                }\n\n                paymentFormSelector.off(endEvent).on(endEvent, function () {\n                    original();\n                    paymentFormSelector.off(endEvent);\n                });\n\n                paymentFormSelector.trigger(startEvent);\n            }\n        });\n    };\n});\n","PayPal_Braintree/js/form-builder.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(\n    [\n        'jquery',\n        'underscore',\n        'mage/template'\n    ],\n    function ($, _, mageTemplate) {\n        'use strict';\n\n        return {\n\n            /**\n             * @param {Object} formData\n             * @returns {*|jQuery}\n             */\n            build: function (formData) {\n                var formTmpl = mageTemplate('<form action=\"<%= data.action %>\"' +\n                    ' method=\"POST\" hidden enctype=\"application/x-www-form-urlencoded\">' +\n                        '<% _.each(data.fields, function(val, key){ %>' +\n                            '<input value=\\'<%= val %>\\' name=\"<%= key %>\" type=\"hidden\">' +\n                        '<% }); %>' +\n                    '</form>');\n\n                return $(formTmpl({\n                    data: {\n                        action: formData.action,\n                        fields: formData.fields\n                    }\n                })).appendTo($('[data-container=\"body\"]'));\n            }\n        };\n    }\n);\n","PayPal_Braintree/js/validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\ndefine([\n    'underscore'\n], function (_) {\n    'use strict';\n\n    return {\n        config: {},\n\n        /**\n         * Set configuration\n         * @param {Object} config\n         */\n        setConfig: function (config) {\n            this.config = config;\n        },\n\n        /**\n         * Get List of available card types\n         * @returns {*|exports.defaults.availableCardTypes|{}}\n         */\n        getAvailableCardTypes: function () {\n            return this.config.availableCardTypes;\n        },\n\n        /**\n         * Get list of card types\n         * @returns {Object}\n         */\n        getCcTypesMapper: function () {\n            return this.config.ccTypesMapper;\n        },\n\n        /**\n         * Find mage card type by Braintree type\n         * @param {String} type\n         * @param {Object} availableTypes\n         * @returns {*}\n         */\n        getMageCardType: function (type, availableTypes) {\n            var storedCardType = null,\n                mapper = this.getCcTypesMapper();\n\n            if (type && typeof mapper[type] !== 'undefined') {\n                storedCardType = mapper[type];\n\n                if (_.indexOf(availableTypes, storedCardType) !== -1) {\n                    return storedCardType;\n                }\n            }\n\n            return null;\n        },\n\n        /**\n         * Filter list of available card types\n         * @param {Object} availableTypes\n         * @param {Object} countrySpecificCardTypes\n         * @returns {Object}\n         */\n        collectTypes: function (availableTypes, countrySpecificCardTypes) {\n            var key,\n                filteredTypes = [];\n\n            for (key in availableTypes) {\n                if (_.indexOf(countrySpecificCardTypes, availableTypes[key]) !== -1) {\n                    filteredTypes.push(availableTypes[key]);\n                }\n            }\n\n            return filteredTypes;\n        },\n\n        /**\n         * Get list of card types for country\n         * @param {String} countryId\n         * @returns {*}\n         */\n        getCountrySpecificCardTypes: function (countryId) {\n            if (typeof this.config.countrySpecificCardTypes[countryId] !== 'undefined') {\n                return this.config.countrySpecificCardTypes[countryId];\n            }\n\n            return false;\n        }\n    };\n});\n","PayPal_Braintree/js/view/product-page.js":"define(\n    ['uiComponent'],\n    function (Component) {\n        'use strict';\n\n        return Component.extend({\n\n        });\n    }\n);","PayPal_Braintree/js/view/payment/ach.js":"define(\n    [\n        'uiComponent',\n        'Magento_Checkout/js/model/payment/renderer-list'\n    ],\n    function (\n        Component,\n        rendererList\n    ) {\n        'use strict';\n\n        rendererList.push(\n            {\n                type: 'braintree_ach_direct_debit',\n                component: 'PayPal_Braintree/js/view/payment/method-renderer/ach'\n            }\n        );\n\n        return Component.extend({});\n    }\n);\n","PayPal_Braintree/js/view/payment/3d-secure.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\n\ndefine([\n    'jquery',\n    'PayPal_Braintree/js/view/payment/adapter',\n    'Magento_Checkout/js/model/quote',\n    'mage/translate',\n    'braintreeThreeDSecure',\n    'Magento_Checkout/js/model/full-screen-loader'\n], function ($, braintree, quote, $t, threeDSecure, fullScreenLoader) {\n    'use strict';\n\n    return {\n        config: null,\n\n        /**\n         * Set 3d secure config\n         * @param {Object} config\n         */\n        setConfig: function (config) {\n            this.config = config;\n            this.config.thresholdAmount = parseFloat(config.thresholdAmount);\n        },\n\n        /**\n         * Get code\n         * @returns {String}\n         */\n        getCode: function () {\n            return 'three_d_secure';\n        },\n\n        /**\n         * convert Non-ASCII characters into unicode\n         * @param str\n         * @returns {string}\n         */\n        escapeNonAsciiCharacters: function (str) {\n            return str.split(\"\").map(function (c) { return /[^\\x00-\\x7F]$/.test(c) ? c : c.split(\"\").map(function (a) { return \"\\\\u00\" + a.charCodeAt().toString(16)}).join(\"\")}).join(\"\");\n        },\n\n        /**\n         * Validate Braintree payment nonce\n         * @param {Object} context\n         * @returns {Object}\n         */\n        validate: function (context) {\n            let clientInstance = braintree.getApiClient(),\n                state = $.Deferred(),\n                totalAmount = parseFloat(quote.totals()['base_grand_total']).toFixed(2),\n                billingAddress = quote.billingAddress();\n\n            if (billingAddress.regionCode == null) {\n                billingAddress.regionCode = undefined;\n            }\n\n            if (billingAddress.regionCode !== undefined && billingAddress.regionCode.length > 2) {\n                billingAddress.regionCode = undefined;\n            }\n\n            // No 3d secure if using CVV verification on vaulted cards\n            if (quote.paymentMethod().method.indexOf('braintree_cc_vault_') !== -1) {\n                if (this.config.useCvvVault === true) {\n                    state.resolve();\n                    return state.promise();\n                }\n            }\n\n            if (!this.isAmountAvailable(totalAmount) || !this.isCountryAvailable(billingAddress.countryId)) {\n                state.resolve();\n                return state.promise();\n            }\n\n            let firstName = this.escapeNonAsciiCharacters(billingAddress.firstname);\n            let lastName = this.escapeNonAsciiCharacters(billingAddress.lastname);\n\n            let challengeRequested = this.getChallengeRequested();\n\n            fullScreenLoader.startLoader();\n\n            let setup3d = function(clientInstance) {\n                threeDSecure.create({\n                    version: 2,\n                    client: clientInstance\n                }, function (threeDSecureErr, threeDSecureInstance) {\n                    if (threeDSecureErr) {\n                        fullScreenLoader.stopLoader();\n                        return state.reject($t('Please try again with another form of payment.'));\n                    }\n\n                    let threeDSContainer = document.createElement('div'),\n                        tdMask = document.createElement('div'),\n                        tdFrame = document.createElement('div'),\n                        tdBody = document.createElement('div');\n\n                    threeDSContainer.id = 'braintree-three-d-modal';\n                    tdMask.className =\"bt-mask\";\n                    tdFrame.className =\"bt-modal-frame\";\n                    tdBody.className =\"bt-modal-body\";\n\n                    tdFrame.appendChild(tdBody);\n                    threeDSContainer.appendChild(tdMask);\n                    threeDSContainer.appendChild(tdFrame);\n\n                    threeDSecureInstance.verifyCard({\n                        amount: totalAmount,\n                        nonce: context.paymentMethodNonce,\n                        bin: context.creditCardBin,\n                        challengeRequested: challengeRequested,\n                        billingAddress: {\n                            givenName: firstName,\n                            surname: lastName,\n                            phoneNumber: billingAddress.telephone,\n                            streetAddress: billingAddress.street[0],\n                            extendedAddress: billingAddress.street[1],\n                            locality: billingAddress.city,\n                            region: billingAddress.regionCode,\n                            postalCode: billingAddress.postcode,\n                            countryCodeAlpha2: billingAddress.countryId\n                        },\n                        onLookupComplete: function (data, next) {\n                            next();\n                        },\n                        addFrame: function (err, iframe) {\n                            fullScreenLoader.stopLoader();\n\n                            if (err) {\n                                console.log(\"Unable to verify card over 3D Secure\", err);\n                                return state.reject($t('Please try again with another form of payment.'));\n                            }\n\n                            tdBody.appendChild(iframe);\n                            document.body.appendChild(threeDSContainer);\n                        },\n                        removeFrame: function () {\n                            fullScreenLoader.startLoader();\n                            document.body.removeChild(threeDSContainer);\n                        }\n                    }, function (err, response) {\n                        fullScreenLoader.stopLoader();\n\n                        if (err) {\n                            console.error(\"3DSecure validation failed\", err);\n                            if (err.code === 'THREEDS_LOOKUP_VALIDATION_ERROR') {\n                                let errorMessage = err.details.originalError.details.originalError.error.message;\n                                if (errorMessage === 'Billing line1 format is invalid.' && billingAddress.street[0].length > 50) {\n                                    return state.reject(\n                                      $t('Billing line1 must be string and less than 50 characters. Please update the address and try again.')\n                                    );\n\n                                } else if (errorMessage === 'Billing line2 format is invalid.' && billingAddress.street[1].length > 50) {\n                                    return state.reject(\n                                      $t('Billing line2 must be string and less than 50 characters. Please update the address and try again.')\n                                    );\n                                }\n                                return state.reject($t(errorMessage));\n                            } else {\n                                return state.reject($t('Please try again with another form of payment.'));\n                            }\n                        }\n\n                        let liability = {\n                            shifted: response.liabilityShifted,\n                            shiftPossible: response.liabilityShiftPossible\n                        };\n\n                        if (liability.shifted || !liability.shifted && !liability.shiftPossible) {\n                            context.paymentMethodNonce = response.nonce;\n                            state.resolve();\n                        } else {\n                            state.reject($t('Please try again with another form of payment.'));\n                        }\n                    });\n                });\n            };\n\n            if (!clientInstance) {\n                require(['PayPal_Braintree/js/view/payment/method-renderer/cc-form'], function(c) {\n                    let config = c.extend({\n                        defaults: {\n                            clientConfig: {\n                                onReady: function() {}\n                            }\n                        }\n                    });\n                    braintree.setConfig(config.defaults.clientConfig);\n                    braintree.setup(setup3d);\n                });\n            } else {\n                setup3d(clientInstance);\n            }\n\n            return state.promise();\n        },\n\n        /**\n         * Check minimal amount for 3d secure activation\n         * @param {Number} amount\n         * @returns {Boolean}\n         */\n        isAmountAvailable: function (amount) {\n            amount = parseFloat(amount.toString());\n\n            return amount >= this.config.thresholdAmount;\n        },\n\n        /**\n         * Check if current country is available for 3d secure\n         * @param {String} countryId\n         * @returns {Boolean}\n         */\n        isCountryAvailable: function (countryId) {\n            let key,\n                specificCountries = this.config.specificCountries;\n\n            // all countries are available\n            if (!specificCountries.length) {\n                return true;\n            }\n\n            for (key in specificCountries) {\n                if (countryId === specificCountries[key]) {\n                    return true;\n                }\n            }\n\n            return false;\n        },\n\n        /**\n         * @returns {Boolean}\n         */\n        getChallengeRequested: function () {\n            return this.config.challengeRequested;\n        }\n    };\n});\n","PayPal_Braintree/js/view/payment/lpm.js":"define(\n    [\n        'uiComponent',\n        'Magento_Checkout/js/model/payment/renderer-list'\n    ],\n    function (\n        Component,\n        rendererList\n    ) {\n        'use strict';\n\n        rendererList.push(\n            {\n                type: 'braintree_local_payment',\n                component: 'PayPal_Braintree/js/view/payment/method-renderer/lpm'\n            }\n        );\n\n        return Component.extend({});\n    }\n);\n","PayPal_Braintree/js/view/payment/adapter.js":"/**\n * Copyright 2013-2017 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\ndefine([\n    'jquery',\n    'braintree',\n    'braintreeDataCollector',\n    'braintreeHostedFields',\n    'Magento_Checkout/js/model/full-screen-loader',\n    'Magento_Ui/js/model/messageList',\n    'mage/translate'\n], function ($, client, dataCollector, hostedFields, fullScreenLoader, globalMessageList, $t) {\n    'use strict';\n\n    return {\n        apiClient: null,\n        config: {},\n        checkout: null,\n        deviceData: null,\n        clientInstance: null,\n        hostedFieldsInstance: null,\n        paypalInstance: null,\n        code: 'braintree',\n\n        /**\n         * {Object}\n         */\n        events: {\n            onClick: null,\n            onCancel: null,\n            onError: null\n        },\n\n        /**\n         * Get Braintree api client\n         * @returns {Object}\n         */\n        getApiClient: function () {\n            return this.clientInstance;\n        },\n\n        /**\n         * Set configuration\n         * @param {Object} config\n         */\n        setConfig: function (config) {\n            this.config = config;\n        },\n\n        /**\n         * Get payment name\n         * @returns {String}\n         */\n        getCode: function () {\n            if (window.checkoutConfig.payment[this.code]) {\n                return this.code;\n            } else {\n                return 'braintree_paypal';\n            }\n        },\n\n        /**\n         * Get client token\n         * @returns {String|*}\n         */\n        getClientToken: function () {\n            return window.checkoutConfig.payment[this.getCode()].clientToken;\n        },\n\n        /**\n         * @returns {String}\n         */\n        getEnvironment: function () {\n            return window.checkoutConfig.payment[this.getCode()].environment;\n        },\n\n        getCurrentCode: function (paypalType = null) {\n            var code = 'braintree_paypal';\n            if (paypalType !== 'paypal') {\n                code = code + '_' + paypalType;\n            }\n            return code;\n        },\n\n        /**\n         * @returns {String}\n         */\n        getColor: function (paypalType = null) {\n            return window.checkoutConfig.payment[this.getCurrentCode(paypalType)].style.color;\n        },\n\n        /**\n         * @returns {String}\n         */\n        getShape: function (paypalType = null) {\n            return window.checkoutConfig.payment[this.getCurrentCode(paypalType)].style.shape;\n        },\n\n        /**\n         * @returns {String}\n         */\n        getSize: function (paypalType = null) {\n            return window.checkoutConfig.payment[this.getCurrentCode(paypalType)].style.size;\n        },\n\n        /**\n         * @returns {String}\n         */\n        getLabel: function (paypalType = null) {\n            return window.checkoutConfig.payment[this.getCurrentCode(paypalType)].style.label;\n        },\n\n        /**\n         * @returns {String}\n         */\n        getBranding: function () {\n            return null;\n        },\n\n        /**\n         * @returns {String}\n         */\n        getFundingIcons: function () {\n            return null;\n        },\n\n        /**\n         * @returns {String}\n         */\n        getDisabledFunding: function () {\n            return window.checkoutConfig.payment[this.getCode()].disabledFunding;\n        },\n\n        /**\n         * Show error message\n         *\n         * @param {String} errorMessage\n         */\n        showError: function (errorMessage) {\n            globalMessageList.addErrorMessage({\n                message: errorMessage\n            });\n            fullScreenLoader.stopLoader(true);\n        },\n\n        /**\n         * Disable submit button\n         */\n        disableButton: function () {\n            // stop any previous shown loaders\n            fullScreenLoader.stopLoader(true);\n            fullScreenLoader.startLoader();\n            $('[data-button=\"place\"]').attr('disabled', 'disabled');\n        },\n\n        /**\n         * Enable submit button\n         */\n        enableButton: function () {\n            $('[data-button=\"place\"]').removeAttr('disabled');\n            fullScreenLoader.stopLoader();\n        },\n\n        /**\n         * Has PayPal been init'd already\n         */\n        getPayPalInstance: function() {\n            if (typeof this.config.paypalInstance !== 'undefined' && this.config.paypalInstance) {\n                return this.config.paypalInstance;\n            }\n\n            return null;\n        },\n\n        setPayPalInstance: function(val) {\n            this.config.paypalInstance = val;\n        },\n\n        /**\n         * Setup Braintree SDK\n         */\n        setup: function (callback) {\n            if (!this.getClientToken()) {\n                this.showError($t('Sorry, but something went wrong.'));\n                return;\n            }\n\n            if (this.clientInstance) {\n                if (typeof this.config.onReady === 'function') {\n                    this.config.onReady(this);\n                }\n\n                if (typeof callback === \"function\") {\n                    callback(this.clientInstance);\n                }\n                return;\n            }\n\n            client.create({\n                authorization: this.getClientToken()\n            }, function (clientErr, clientInstance) {\n                if (clientErr) {\n                    console.error('Braintree Setup Error', clientErr);\n                    return this.showError(\"Sorry, but something went wrong. Please contact the store owner.\");\n                }\n\n                var options = {\n                    client: clientInstance\n                };\n\n                if (typeof this.config.dataCollector === 'object' && typeof this.config.dataCollector.paypal === 'boolean') {\n                    options.paypal = true;\n                }\n\n                dataCollector.create(options, function (err, dataCollectorInstance) {\n                    if (err) {\n                        return console.log(err);\n                    }\n\n                    this.deviceData = dataCollectorInstance.deviceData;\n                    this.config.onDeviceDataReceived(this.deviceData);\n                }.bind(this));\n\n                this.clientInstance = clientInstance;\n\n                if (typeof this.config.onReady === 'function') {\n                    this.config.onReady(this);\n                }\n\n                if (typeof callback === \"function\") {\n                    callback(this.clientInstance);\n                }\n            }.bind(this));\n        },\n\n        /**\n         * Setup hosted fields instance\n         */\n        setupHostedFields: function () {\n            var self = this;\n\n            if (this.hostedFieldsInstance) {\n                this.hostedFieldsInstance.teardown(function () {\n                    this.hostedFieldsInstance = null;\n                    this.setupHostedFields();\n                }.bind(this));\n                return;\n            }\n\n            hostedFields.create({\n                client: this.clientInstance,\n                fields: this.config.hostedFields,\n                styles: {\n                    \"input\": {\n                        \"font-size\": \"14pt\",\n                        \"color\": \"#3A3A3A\"\n                    },\n                    \":focus\": {\n                        \"color\": \"black\"\n                    },\n                    \".valid\": {\n                        \"color\": \"green\"\n                    },\n                    \".invalid\": {\n                        \"color\": \"red\"\n                    }\n                }\n            }, function (createErr, hostedFieldsInstance) {\n                if (createErr) {\n                    self.showError($t(\"Braintree hosted fields could not be initialized. Please contact the store owner.\"));\n                    console.error('Braintree hosted fields error', createErr);\n                    return;\n                }\n\n                this.config.onInstanceReady(hostedFieldsInstance);\n                this.hostedFieldsInstance = hostedFieldsInstance;\n            }.bind(this));\n        },\n\n        tokenizeHostedFields: function () {\n            this.hostedFieldsInstance.tokenize({}, function (tokenizeErr, payload) {\n                if (tokenizeErr) {\n                    switch (tokenizeErr.code) {\n                        case 'HOSTED_FIELDS_FIELDS_EMPTY':\n                            // occurs when none of the fields are filled in\n                            console.error('All fields are empty! Please fill out the form.');\n                            break;\n                        case 'HOSTED_FIELDS_FIELDS_INVALID':\n                            // occurs when certain fields do not pass client side validation\n                            console.error('Some fields are invalid:', tokenizeErr.details.invalidFieldKeys);\n                            break;\n                        case 'HOSTED_FIELDS_TOKENIZATION_FAIL_ON_DUPLICATE':\n                            // occurs when:\n                            //   * the client token used for client authorization was generated\n                            //     with a customer ID and the fail on duplicate payment method\n                            //     option is set to true\n                            //   * the card being tokenized has previously been vaulted (with any customer)\n                            // See: https://developers.braintreepayments.com/reference/request/client-token/generate/#options.fail_on_duplicate_payment_method\n                            console.error('This payment method already exists in your vault.');\n                            break;\n                        case 'HOSTED_FIELDS_TOKENIZATION_CVV_VERIFICATION_FAILED':\n                            // occurs when:\n                            //   * the client token used for client authorization was generated\n                            //     with a customer ID and the verify card option is set to true\n                            //     and you have credit card verification turned on in the Braintree\n                            //     control panel\n                            //   * the cvv does not pass verfication (https://developers.braintreepayments.com/reference/general/testing/#avs-and-cvv/cid-responses)\n                            // See: https://developers.braintreepayments.com/reference/request/client-token/generate/#options.verify_card\n                            console.error('CVV did not pass verification');\n                            break;\n                        case 'HOSTED_FIELDS_FAILED_TOKENIZATION':\n                            // occurs for any other tokenization error on the server\n                            console.error('Tokenization failed server side. Is the card valid?');\n                            break;\n                        case 'HOSTED_FIELDS_TOKENIZATION_NETWORK_ERROR':\n                            // occurs when the Braintree gateway cannot be contacted\n                            console.error('Network error occurred when tokenizing.');\n                            break;\n                        default:\n                            console.error('Something bad happened!', tokenizeErr);\n                    }\n                } else {\n                    this.config.onPaymentMethodReceived(payload);\n                }\n            }.bind(this));\n        }\n    };\n});\n\n","PayPal_Braintree/js/view/payment/validator-handler.js":"/**\n * Copyright 2013-2017 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\n\ndefine([\n    'jquery',\n    'Magento_Ui/js/model/messageList',\n    'PayPal_Braintree/js/view/payment/3d-secure',\n    'Magento_Checkout/js/model/full-screen-loader'\n], function ($, globalMessageList, verify3DSecure, fullScreenLoader) {\n    'use strict';\n\n    return {\n        validators: [],\n\n        /**\n         * Get payment config\n         * @returns {Object}\n         */\n        getConfig: function () {\n            return window.checkoutConfig.payment;\n        },\n\n        /**\n         * Init list of validators\n         */\n        initialize: function () {\n            var config = this.getConfig();\n\n            if (config[verify3DSecure.getCode()].enabled) {\n                verify3DSecure.setConfig(config[verify3DSecure.getCode()]);\n                this.add(verify3DSecure);\n            }\n        },\n\n        /**\n         * Add new validator\n         * @param {Object} validator\n         */\n        add: function (validator) {\n            this.validators.push(validator);\n        },\n\n        /**\n         * Run pull of validators\n         * @param {Object} context\n         * @param {Function} callback\n         */\n        validate: function (context, callback, errorCallback) {\n            var self = this,\n                deferred;\n\n            // no available validators\n            if (!self.validators.length) {\n                callback();\n\n                return;\n            }\n\n            // get list of deferred validators\n            deferred = $.map(self.validators, function (current) {\n                return current.validate(context);\n            });\n\n            $.when.apply($, deferred)\n                .done(function () {\n                    callback();\n                }).fail(function (error) {\n                    errorCallback();\n                    self.showError(error);\n                });\n        },\n\n        /**\n         * Show error message\n         * @param {String} errorMessage\n         */\n        showError: function (errorMessage) {\n            globalMessageList.addErrorMessage({\n                message: errorMessage\n            });\n            fullScreenLoader.stopLoader(true);\n        }\n    };\n});\n","PayPal_Braintree/js/view/payment/braintree.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\ndefine([\n    'uiComponent',\n    'Magento_Checkout/js/model/payment/renderer-list'\n], function (Component, rendererList) {\n    'use strict';\n\n    let config = window.checkoutConfig.payment,\n        braintreeType = 'braintree',\n        payPalType = 'braintree_paypal',\n        braintreeAchDirectDebit = 'braintree_ach_direct_debit',\n        braintreeVenmo = 'braintree_venmo',\n        braintreeLocalPayment = 'braintree_local_payment';\n\n    if (config[braintreeType] && config[braintreeType].isActive && config[braintreeType].clientToken) {\n        rendererList.push({\n            type: braintreeType,\n            component: 'PayPal_Braintree/js/view/payment/method-renderer/hosted-fields'\n        });\n    }\n\n    if (config[payPalType] && config[payPalType].isActive) {\n        rendererList.push({\n            type: payPalType,\n            component: 'PayPal_Braintree/js/view/payment/method-renderer/paypal'\n        });\n    }\n\n    if (config[braintreeVenmo] && config[braintreeVenmo].isAllowed && config[braintreeVenmo].clientToken) {\n        rendererList.push({\n            type: braintreeVenmo,\n            component: 'PayPal_Braintree/js/view/payment/method-renderer/venmo'\n        });\n    }\n\n    if (config[braintreeAchDirectDebit] && config[braintreeAchDirectDebit].isActive && config[braintreeAchDirectDebit].clientToken) {\n        rendererList.push({\n            type: braintreeAchDirectDebit,\n            component: 'PayPal_Braintree/js/view/payment/method-renderer/ach'\n        });\n    }\n\n    if (config[braintreeLocalPayment] && config[braintreeLocalPayment].clientToken) {\n        rendererList.push({\n            type: braintreeLocalPayment,\n            component: 'PayPal_Braintree/js/view/payment/method-renderer/lpm'\n        });\n    }\n\n    /** Add view logic here if needed */\n    return Component.extend({});\n});\n","PayPal_Braintree/js/view/payment/venmo.js":"define(\n    [\n        'uiComponent',\n        'Magento_Checkout/js/model/payment/renderer-list'\n    ],\n    function (\n        Component,\n        rendererList\n    ) {\n        'use strict';\n\n        rendererList.push(\n            {\n                type: 'braintree_venmo',\n                component: 'PayPal_Braintree/js/view/payment/method-renderer/venmo'\n            }\n        );\n\n        return Component.extend({});\n    }\n);\n","PayPal_Braintree/js/view/payment/method-renderer/ach.js":"define(\n    [\n        'Magento_Checkout/js/view/payment/default',\n        'ko',\n        'jquery',\n        'braintree',\n        'braintreeDataCollector',\n        'braintreeAch',\n        'PayPal_Braintree/js/form-builder',\n        'Magento_Ui/js/model/messageList',\n        'Magento_Checkout/js/action/select-billing-address',\n        'Magento_Checkout/js/model/full-screen-loader',\n        'Magento_Checkout/js/model/quote',\n        'mage/translate'\n    ],\n    function (\n        Component,\n        ko,\n        $,\n        braintree,\n        dataCollector,\n        ach,\n        formBuilder,\n        messageList,\n        selectBillingAddress,\n        fullScreenLoader,\n        quote,\n        $t\n    ) {\n        'use strict';\n\n        return Component.extend({\n            defaults: {\n                deviceData: null,\n                paymentMethodNonce: null,\n                template: 'PayPal_Braintree/payment/ach',\n                achInstance: null,\n                routingNumber: ko.observable(\"\"),\n                accountNumber: ko.observable(\"\"),\n                accountType: ko.observable(\"checking\"),\n                ownershipType: ko.observable(\"personal\"),\n                firstName: ko.observable(\"\"),\n                lastName: ko.observable(\"\"),\n                businessName: ko.observable(\"\"),\n                hasAuthorization: ko.observable(false),\n                business: ko.observable(false), // for ownership type\n                personal: ko.observable(true) // for ownership type\n            },\n\n            clickAchBtn: function () {\n                if (!this.validateForm('#' + this.getCode() + '-form')) {\n                    return;\n                }\n\n                fullScreenLoader.startLoader();\n\n                var self = this;\n\n                var billingAddress = quote.billingAddress();\n\n                let regionCode;\n\n                let bankDetails = {\n                    routingNumber: self.routingNumber(),\n                    accountNumber: self.accountNumber(),\n                    accountType: self.accountType(),\n                    ownershipType: self.ownershipType(),\n                    billingAddress: {\n                        streetAddress: billingAddress.street[0],\n                        extendedAddress: billingAddress.street[1],\n                        locality: billingAddress.city,\n                        region: billingAddress.regionCode,\n                        postalCode: billingAddress.postcode,\n                    }\n                };\n\n                if (bankDetails.ownershipType === 'personal') {\n                    bankDetails.firstName = self.firstName();\n                    bankDetails.lastName = self.lastName();\n                } else {\n                    bankDetails.businessName = self.businessName();\n                }\n\n                var mandateText = document.getElementById('braintree-ach-mandate').textContent;\n\n                // if no region code is available, lets find one!\n                if (typeof billingAddress.regionCode === 'undefined') {\n                    $.get('/rest/V1/directory/countries/' + billingAddress.countryId).done(function (data) {\n                        if (typeof data.available_regions !== 'undefined') {\n                            for (var i = 0; i < data.available_regions.length; ++i) {\n                                if (data.available_regions[i].id === billingAddress.regionId) {\n                                    regionCode = data.available_regions[i].code;\n                                    bankDetails.billingAddress.region = regionCode;\n                                    self.tokenizeAch(bankDetails, mandateText);\n                                }\n                            }\n                        } else {\n                            fullScreenLoader.stopLoader();\n                            self.tokenizeAch(bankDetails, mandateText);\n                        }\n                    }).fail(function() {\n                        fullScreenLoader.stopLoader();\n                    });\n                } else {\n                    self.tokenizeAch(bankDetails, mandateText);\n                }\n            },\n\n            tokenizeAch: function (bankDetails, mandateText) {\n                var self = this;\n                this.achInstance.tokenize({\n                    bankDetails: bankDetails,\n                    mandateText: mandateText\n                }, function (tokenizeErr, tokenizedPayload) {\n                    if (tokenizeErr) {\n                        self.setErrorMsg($t('There was an error with the provided bank details. Please check and try again.'));\n                        self.hasAuthorization(false);\n                    } else {\n                        fullScreenLoader.stopLoader();\n                        self.handleAchSuccess(tokenizedPayload);\n                    }\n                });\n            },\n\n            getClientToken: function () {\n                return window.checkoutConfig.payment[this.getCode()].clientToken;\n            },\n\n            getCode: function () {\n                return 'braintree_ach_direct_debit';\n            },\n\n            getStoreName: function () {\n                return window.checkoutConfig.payment[this.getCode()].storeName;\n            },\n\n            getData: function () {\n                let data = {\n                    'method': this.getCode(),\n                    'additional_data': {\n                        'payment_method_nonce': this.paymentMethodNonce,\n                    }\n                };\n\n                data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n                return data;\n            },\n\n            getTitle: function() {\n                return 'ACH Direct Debit';\n            },\n\n            handleAchSuccess: function (payload) {\n                this.setPaymentMethodNonce(payload.nonce);\n                this.placeOrder();\n            },\n\n            initialize: function () {\n                this._super();\n\n                var self = this;\n\n                braintree.create({\n                    authorization: self.getClientToken()\n                }, function (clientError, clientInstance) {\n                    if (clientError) {\n                        this.setErrorMsg($t('Unable to initialize Braintree Client.'));\n                        return;\n                    }\n\n                    ach.create({\n                        client: clientInstance\n                    }, function (achErr, achInstance) {\n                        if (achErr) {\n                            self.setErrorMsg($t('Error initializing ACH: %1').replace('%1', achErr));\n                            return;\n                        }\n\n                        self.setAchInstance(achInstance);\n                    });\n                });\n\n                return this;\n            },\n\n            isAllowed: function () {\n                return window.checkoutConfig.payment[this.getCode()].isAllowed;\n            },\n\n            changeOwnershipType: function (data, event) {\n                var self = this;\n                if (event.currentTarget.value === 'business') {\n                    self.business(true);\n                    self.personal(false);\n                } else {\n                    self.business(false);\n                    self.personal(true);\n                }\n            },\n\n            isBusiness: function () {\n                return this.business;\n            },\n\n            isPersonal: function () {\n                return this.personal;\n            },\n\n            setErrorMsg: function (message) {\n                messageList.addErrorMessage({\n                    message: message\n                });\n            },\n\n            setPaymentMethodNonce: function (nonce) {\n                this.paymentMethodNonce = nonce;\n            },\n\n            setAchInstance: function (instance) {\n                this.achInstance = instance;\n            },\n\n            validateForm: function (form) {\n                return $(form).validation() && $(form).validation('isValid');\n            }\n        });\n    }\n);\n","PayPal_Braintree/js/view/payment/method-renderer/paypal-vault.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\ndefine([\n    'jquery',\n    'underscore',\n    'Magento_Vault/js/view/payment/method-renderer/vault',\n    'Magento_Ui/js/model/messageList',\n    'Magento_Checkout/js/model/full-screen-loader'\n], function ($, _, VaultComponent, globalMessageList, fullScreenLoader) {\n    'use strict';\n\n    return VaultComponent.extend({\n        defaults: {\n            template: 'PayPal_Braintree/payment/paypal/vault',\n            additionalData: {}\n        },\n\n        /**\n         * Get PayPal payer email\n         * @returns {String}\n         */\n        getPayerEmail: function () {\n            return this.details.payerEmail;\n        },\n\n        /**\n         * Get type of payment\n         * @returns {String}\n         */\n        getPaymentIcon: function () {\n            return window.checkoutConfig.payment['braintree_paypal'].paymentIcon;\n        },\n\n        /**\n         * Place order\n         */\n        beforePlaceOrder: function () {\n            this.getPaymentMethodNonce();\n        },\n\n        /**\n         * Send request to get payment method nonce\n         */\n        getPaymentMethodNonce: function () {\n            var self = this;\n\n            fullScreenLoader.startLoader();\n            $.getJSON(self.nonceUrl, {\n                'public_hash': self.publicHash\n            })\n                .done(function (response) {\n                    fullScreenLoader.stopLoader();\n                    self.additionalData['payment_method_nonce'] = response.paymentMethodNonce;\n                    self.placeOrder();\n                })\n                .fail(function (response) {\n                    var error = JSON.parse(response.responseText);\n\n                    fullScreenLoader.stopLoader();\n                    globalMessageList.addErrorMessage({\n                        message: error.message\n                    });\n                });\n        },\n\n        /**\n         * Get payment method data\n         * @returns {Object}\n         */\n        getData: function () {\n            var data = {\n                'method': this.code,\n                'additional_data': {\n                    'public_hash': this.publicHash\n                }\n            };\n\n            data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n            return data;\n        }\n    });\n});\n","PayPal_Braintree/js/view/payment/method-renderer/cc-form.js":"/**\n * Copyright 2013-2017 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\ndefine(\n    [\n        'underscore',\n        'jquery',\n        'Magento_Payment/js/view/payment/cc-form',\n        'Magento_Checkout/js/model/quote',\n        'PayPal_Braintree/js/view/payment/adapter',\n        'mage/translate',\n        'PayPal_Braintree/js/validator',\n        'PayPal_Braintree/js/view/payment/validator-handler',\n        'Magento_Checkout/js/model/full-screen-loader'\n    ],\n    function (\n        _,\n        $,\n        Component,\n        quote,\n        braintree,\n        $t,\n        validator,\n        validatorManager,\n        fullScreenLoader\n    ) {\n        'use strict';\n\n        return Component.extend({\n            defaults: {\n                active: false,\n                braintreeClient: null,\n                braintreeDeviceData: null,\n                paymentMethodNonce: null,\n                lastBillingAddress: null,\n                validatorManager: validatorManager,\n                code: 'braintree',\n                isProcessing: false,\n                creditCardBin: null,\n\n                /**\n                 * Additional payment data\n                 *\n                 * {Object}\n                 */\n                additionalData: {},\n\n                /**\n                 * Braintree client configuration\n                 *\n                 * {Object}\n                 */\n                clientConfig: {\n                    onReady: function (context) {\n                        context.setupHostedFields();\n                    },\n\n                    /**\n                     * Triggers on payment nonce receive\n                     * @param {Object} response\n                     */\n                    onPaymentMethodReceived: function (response) {\n                        this.handleNonce(response);\n                        this.isProcessing = false;\n                    },\n\n                    /**\n                     * Allow a new nonce to be generated\n                     */\n                    onPaymentMethodError: function() {\n                        this.isProcessing = false;\n                    },\n\n                    /**\n                     * Device data initialization\n                     * @param {String} deviceData\n                     */\n                    onDeviceDataReceived: function (deviceData) {\n                        this.additionalData['device_data'] = deviceData;\n                    },\n\n                    /**\n                     * After Braintree instance initialization\n                     */\n                    onInstanceReady: function () {},\n\n                    /**\n                     * Triggers on any Braintree error\n                     * @param {Object} response\n                     */\n                    onError: function (response) {\n                        this.isProcessing = false;\n                        braintree.showError($t('Payment ' + this.getTitle() + ' can\\'t be initialized'));\n                        throw response.message;\n                    },\n\n                    /**\n                     * Triggers when customer click \"Cancel\"\n                     */\n                    onCancelled: function () {\n                        this.paymentMethodNonce = null;\n                        this.isProcessing = false;\n                    }\n                },\n                imports: {\n                    onActiveChange: 'active'\n                }\n            },\n\n            /**\n             * Set list of observable attributes\n             *\n             * @returns {exports.initObservable}\n             */\n            initObservable: function () {\n                validator.setConfig(window.checkoutConfig.payment[this.getCode()]);\n                this._super()\n                    .observe(['active']);\n                this.validatorManager.initialize();\n                this.initClientConfig();\n\n                return this;\n            },\n\n            /**\n             * Get payment name\n             *\n             * @returns {String}\n             */\n            getCode: function () {\n                return this.code;\n            },\n\n            /**\n             * Check if payment is active\n             *\n             * @returns {Boolean}\n             */\n            isActive: function () {\n                let active = this.getCode() === this.isChecked();\n                this.active(active);\n\n                return active;\n            },\n\n            /**\n             * Triggers when payment method change\n             * @param {Boolean} isActive\n             */\n            onActiveChange: function (isActive) {\n                if (!isActive) {\n                    return;\n                }\n\n                this.initBraintree();\n            },\n\n            /**\n             * Init config\n             */\n            initClientConfig: function () {\n                _.each(this.clientConfig, function (fn, name) {\n                    if (typeof fn === 'function') {\n                        this.clientConfig[name] = fn.bind(this);\n                    }\n                }, this);\n            },\n\n            /**\n             * Init Braintree configuration\n             */\n            initBraintree: function () {\n                let intervalId = setInterval(function () {\n                    // stop loader when frame will be loaded\n                    if ($('#braintree-hosted-field-number').length) {\n                        clearInterval(intervalId);\n                        fullScreenLoader.stopLoader(true);\n                    }\n                }, 500);\n\n                if (braintree.checkout) {\n                    braintree.checkout.teardown(function () {\n                        braintree.checkout = null;\n                    });\n                }\n\n                fullScreenLoader.startLoader();\n                braintree.setConfig(this.clientConfig);\n                braintree.setup();\n            },\n\n            /**\n             * Get full selector name\n             *\n             * @param {String} field\n             * @returns {String}\n             */\n            getSelector: function (field) {\n                return '#' + this.getCode() + '_' + field;\n            },\n\n            /**\n             * Get list of available CC types\n             *\n             * @returns {Object}\n             */\n            getCcAvailableTypes: function () {\n                let availableTypes = validator.getAvailableCardTypes(),\n                    billingAddress = quote.billingAddress(),\n                    billingCountryId;\n\n                this.lastBillingAddress = quote.shippingAddress();\n\n                if (!billingAddress) {\n                    billingAddress = this.lastBillingAddress;\n                }\n\n                billingCountryId = billingAddress.countryId;\n\n                if (billingCountryId && validator.getCountrySpecificCardTypes(billingCountryId)) {\n                    return validator.collectTypes(\n                        availableTypes,\n                        validator.getCountrySpecificCardTypes(billingCountryId)\n                    );\n                }\n\n                return availableTypes;\n            },\n\n            /**\n             * @returns {String}\n             */\n            getEnvironment: function () {\n                return window.checkoutConfig.payment[this.getCode()].environment;\n            },\n\n            /**\n             * Get data\n             *\n             * @returns {Object}\n             */\n            getData: function () {\n                let data = {\n                    'method': this.getCode(),\n                    'additional_data': {\n                        'payment_method_nonce': this.paymentMethodNonce,\n                        'g-recaptcha-response' : $(\"#token-grecaptcha-braintree\").val()\n                    }\n                };\n\n                data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n                return data;\n            },\n\n            /**\n             * Set payment nonce\n             * @param {String} paymentMethodNonce\n             */\n            setPaymentMethodNonce: function (paymentMethodNonce) {\n                this.paymentMethodNonce = paymentMethodNonce;\n            },\n\n            /**\n             * Set credit card bin\n             * @param creditCardBin\n             */\n            setCreditCardBin: function (creditCardBin) {\n                this.creditCardBin = creditCardBin;\n            },\n\n            /**\n             * Prepare payload to place order\n             * @param {Object} payload\n             */\n            handleNonce: function (payload) {\n                let self = this;\n\n                this.setPaymentMethodNonce(payload.nonce);\n                this.setCreditCardBin(payload.details.bin);\n\n                // place order on success validation\n                self.validatorManager.validate(self, function () {\n                    return self.placeOrder('parent');\n                }, function() {\n                    self.isProcessing = false;\n                    self.paymentMethodNonce = null;\n                    self.creditCardBin = null;\n                });\n            },\n\n            /**\n             * Action to place order\n             * @param {String} key\n             */\n            placeOrder: function (key) {\n                if (key) {\n                    return this._super();\n                }\n\n                if (this.isProcessing) {\n                    return false;\n                } else {\n                    this.isProcessing = true;\n                }\n\n                braintree.tokenizeHostedFields();\n                return false;\n            },\n\n            /**\n             * Get payment icons\n             * @param {String} type\n             * @returns {Boolean}\n             */\n            getIcons: function (type) {\n                return window.checkoutConfig.payment.braintree.icons.hasOwnProperty(type) ?\n                    window.checkoutConfig.payment.braintree.icons[type]\n                    : false;\n            },\n        });\n    }\n);\n","PayPal_Braintree/js/view/payment/method-renderer/lpm.js":"define(\n    [\n        'Magento_Checkout/js/view/payment/default',\n        'ko',\n        'jquery',\n        'braintree',\n        'braintreeLpm',\n        'PayPal_Braintree/js/form-builder',\n        'Magento_Ui/js/model/messageList',\n        'Magento_Checkout/js/action/select-billing-address',\n        'Magento_Checkout/js/model/full-screen-loader',\n        'Magento_Checkout/js/model/quote',\n        'Magento_Checkout/js/model/payment/additional-validators',\n        'mage/url',\n        'mage/translate'\n    ],\n    function (\n        Component,\n        ko,\n        $,\n        braintree,\n        lpm,\n        formBuilder,\n        messageList,\n        selectBillingAddress,\n        fullScreenLoader,\n        quote,\n        additionalValidators,\n        url,\n        $t\n    ) {\n        'use strict';\n\n        return Component.extend({\n            defaults: {\n                code: 'braintree_local_payment',\n                paymentMethodsAvailable: ko.observable(false),\n                paymentMethodNonce: null,\n                template: 'PayPal_Braintree/payment/lpm'\n            },\n\n            clickPaymentBtn: function (method) {\n                var self = this;\n\n                if (additionalValidators.validate()) {\n                    fullScreenLoader.startLoader();\n\n                    braintree.create({\n                        authorization: self.getClientToken()\n                    }, function (clientError, clientInstance) {\n                        if (clientError) {\n                            self.setErrorMsg($t('Unable to initialize Braintree Client.'));\n                            fullScreenLoader.stopLoader();\n                            return;\n                        }\n\n                        lpm.create({\n                            client: clientInstance,\n                            merchantAccountId: self.getMerchantAccountId()\n                        }, function (lpmError, lpmInstance) {\n                            if (lpmError) {\n                                self.setErrorMsg(lpmError);\n                                fullScreenLoader.stopLoader();\n                                return;\n                            }\n\n                            lpmInstance.startPayment({\n                                amount: self.getAmount(),\n                                currencyCode: self.getCurrencyCode(),\n                                email: self.getCustomerDetails().email,\n                                phone: self.getCustomerDetails().phone,\n                                givenName: self.getCustomerDetails().firstName,\n                                surname: self.getCustomerDetails().lastName,\n                                shippingAddressRequired: !quote.isVirtual(),\n                                address: self.getAddress(),\n                                paymentType: method,\n                                onPaymentStart: function (data, start) {\n                                    start();\n                                },\n                                // This is a required option, however it will apparently never be used in the current payment flow.\n                                // Therefore, both values are set to allow the payment flow to continute, rather than erroring out.\n                                fallback: {\n                                    url: 'N/A',\n                                    buttonText: 'N/A'\n                                }\n                            }, function (startPaymentError, payload) {\n                                fullScreenLoader.stopLoader();\n                                if (startPaymentError) {\n                                    switch (startPaymentError.code) {\n                                        case 'LOCAL_PAYMENT_POPUP_CLOSED':\n                                            self.setErrorMsg($t('Local Payment popup was closed unexpectedly.'));\n                                            break;\n                                        case 'LOCAL_PAYMENT_WINDOW_OPEN_FAILED':\n                                            self.setErrorMsg($t('Local Payment popup failed to open.'));\n                                            break;\n                                        case 'LOCAL_PAYMENT_WINDOW_CLOSED':\n                                            self.setErrorMsg($t('Local Payment popup was closed. Payment cancelled.'));\n                                            break;\n                                        default:\n                                            self.setErrorMsg('Error! ' + startPaymentError);\n                                            break;\n                                    }\n                                } else {\n                                    // Send the nonce to your server to create a transaction\n                                    self.setPaymentMethodNonce(payload.nonce);\n                                    self.placeOrder();\n                                }\n                            });\n                        });\n                    });\n                }\n            },\n\n            getAddress: function () {\n                var shippingAddress = quote.shippingAddress();\n\n                if (quote.isVirtual()) {\n                    return {\n                        countryCode: shippingAddress.countryId\n                    }\n                }\n\n                return {\n                    streetAddress: shippingAddress.street[0],\n                    extendedAddress: shippingAddress.street[1],\n                    locality: shippingAddress.city,\n                    postalCode: shippingAddress.postcode,\n                    region: shippingAddress.region,\n                    countryCode: shippingAddress.countryId\n                }\n            },\n\n            getAmount: function () {\n                return quote.totals()['base_grand_total'].toString();\n            },\n\n            getBillingAddress: function () {\n                return quote.billingAddress();\n            },\n\n            getClientToken: function () {\n                return window.checkoutConfig.payment[this.getCode()].clientToken;\n            },\n\n            getCode: function () {\n                return this.code;\n            },\n\n            getCurrencyCode: function () {\n                return quote.totals()['base_currency_code'];\n            },\n\n            getCustomerDetails: function () {\n                var billingAddress = quote.billingAddress();\n                return {\n                    firstName: billingAddress.firstname,\n                    lastName: billingAddress.lastname,\n                    phone: billingAddress.telephone,\n                    email: typeof quote.guestEmail === 'string' ? quote.guestEmail : window.checkoutConfig.customerData.email\n                }\n            },\n\n            getData: function () {\n                let data = {\n                    'method': this.getCode(),\n                    'additional_data': {\n                        'payment_method_nonce': this.paymentMethodNonce,\n                    }\n                };\n\n                data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n                return data;\n            },\n\n            getMerchantAccountId: function () {\n                return window.checkoutConfig.payment[this.getCode()].merchantAccountId;\n            },\n\n            getPaymentMethod: function (method) {\n                var methods = this.getPaymentMethods();\n\n                for (var i = 0; i < methods.length; i++) {\n                    if (methods[i].method === method) {\n                        return methods[i]\n                    }\n                }\n            },\n\n            getPaymentMethods: function () {\n                return window.checkoutConfig.payment[this.getCode()].allowedMethods;\n            },\n\n            getPaymentMarkSrc: function () {\n                return window.checkoutConfig.payment[this.getCode()].paymentIcons;\n            },\n\n            getTitle: function () {\n                return window.checkoutConfig.payment[this.getCode()].title;\n            },\n\n            initialize: function () {\n                this._super();\n                return this;\n            },\n\n            isActive: function () {\n                var address = quote.billingAddress() || quote.shippingAddress();\n                var methods = this.getPaymentMethods();\n\n                for (var i = 0; i < methods.length; i++) {\n                    if (methods[i].countries.includes(address.countryId)) {\n                        return true;\n                    }\n                }\n\n                return false;\n            },\n\n            isValidCountryAndCurrency: function (method) {\n                var address = quote.billingAddress();\n\n                if (!address) {\n                    this.paymentMethodsAvailable(false);\n                    return false;\n                }\n\n                var countryId = address.countryId;\n                var quoteCurrency = quote.totals()['base_currency_code'];\n                var paymentMethodDetails = this.getPaymentMethod(method);\n\n                if ((countryId !== 'GB' && paymentMethodDetails.countries.includes(countryId) && (quoteCurrency === 'EUR' || quoteCurrency === 'PLN')) || (countryId === 'GB' && paymentMethodDetails.countries.includes(countryId) && quoteCurrency === 'GBP')) {\n                    this.paymentMethodsAvailable(true);\n                    return true;\n                }\n\n                return false;\n            },\n\n            setErrorMsg: function (message) {\n                messageList.addErrorMessage({\n                    message: message\n                });\n            },\n\n            setPaymentMethodNonce: function (nonce) {\n                this.paymentMethodNonce = nonce;\n            },\n\n            validateForm: function (form) {\n                return $(form).validation() && $(form).validation('isValid');\n            }\n        });\n    }\n);\n","PayPal_Braintree/js/view/payment/method-renderer/paypal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\ndefine([\n    'jquery',\n    'underscore',\n    'Magento_Checkout/js/view/payment/default',\n    'braintree',\n    'braintreeCheckoutPayPalAdapter',\n    'braintreePayPalCheckout',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/model/full-screen-loader',\n    'Magento_Checkout/js/model/payment/additional-validators',\n    'Magento_Checkout/js/model/step-navigator',\n    'Magento_Vault/js/view/payment/vault-enabler',\n    'Magento_Checkout/js/action/create-billing-address',\n    'Magento_Checkout/js/action/select-billing-address',\n    'Magento_CheckoutAgreements/js/view/checkout-agreements',\n    'mage/translate'\n], function (\n    $,\n    _,\n    Component,\n    braintree,\n    Braintree,\n    paypalCheckout,\n    quote,\n    fullScreenLoader,\n    additionalValidators,\n    stepNavigator,\n    VaultEnabler,\n    createBillingAddress,\n    selectBillingAddress,\n    checkoutAgreements,\n    $t\n) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'PayPal_Braintree/payment/paypal',\n            code: 'braintree_paypal',\n            active: false,\n            paypalInstance: null,\n            paymentMethodNonce: null,\n            grandTotalAmount: null,\n            isReviewRequired: false,\n            customerEmail: null,\n\n            /**\n             * Additional payment data\n             *\n             * {Object}\n             */\n            additionalData: {},\n\n            /**\n             * {Array}\n             */\n            lineItemsArray: [\n                'name',\n                'kind',\n                'quantity',\n                'unitAmount',\n                'unitTaxAmount',\n                'productCode',\n                'description'\n            ],\n\n            /**\n             * PayPal client configuration\n             * {Object}\n             */\n            clientConfig: {\n                offerCredit: false,\n                offerCreditOnly: false,\n                dataCollector: {\n                    paypal: true\n                },\n\n                buttonPayPalId: 'braintree_paypal_placeholder',\n                buttonCreditId: 'braintree_paypal_credit_placeholder',\n                buttonPaylaterId: 'braintree_paypal_paylater_placeholder',\n\n                onDeviceDataReceived: function (deviceData) {\n                    this.additionalData['device_data'] = deviceData;\n                },\n\n                /**\n                 * Triggers when widget is loaded\n                 * @param {Object} context\n                 */\n                onReady: function (context) {\n                    this.setupPayPal();\n                },\n\n                /**\n                 * Triggers on payment nonce receive\n                 * @param {Object} response\n                 */\n                onPaymentMethodReceived: function (response) {\n                    this.beforePlaceOrder(response);\n                }\n            },\n            imports: {\n                onActiveChange: 'active'\n            }\n        },\n\n        /**\n         * Set list of observable attributes\n         * @returns {exports.initObservable}\n         */\n        initObservable: function () {\n            var self = this;\n\n            this._super()\n                .observe(['active', 'isReviewRequired', 'customerEmail']);\n\n            window.addEventListener('hashchange', function (e) {\n                var methodCode = quote.paymentMethod();\n\n                if (methodCode === 'braintree_paypal' || methodCode === 'braintree_paypal_vault') {\n                    if (e.newURL.indexOf('payment') > 0 && self.grandTotalAmount !== null) {\n                        self.reInitPayPal();\n                    }\n                }\n            });\n\n            quote.paymentMethod.subscribe(function (value) {\n                var methodCode = value;\n\n                if (methodCode === 'braintree_paypal' || methodCode === 'braintree_paypal_vault') {\n                    self.reInitPayPal();\n                }\n            });\n\n            this.vaultEnabler = new VaultEnabler();\n            this.vaultEnabler.setPaymentCode(this.getVaultCode());\n            this.vaultEnabler.isActivePaymentTokenEnabler.subscribe(function () {\n                self.onVaultPaymentTokenEnablerChange();\n            });\n\n            this.grandTotalAmount = quote.totals()['base_grand_total'];\n\n            quote.totals.subscribe(function () {\n                if (self.grandTotalAmount !== quote.totals()['base_grand_total']) {\n                    self.grandTotalAmount = quote.totals()['base_grand_total'];\n                    var methodCode = quote.paymentMethod();\n\n                    if (methodCode && (methodCode.method === 'braintree_paypal' || methodCode.method === 'braintree_paypal_vault')) {\n                        self.reInitPayPal();\n                    }\n                }\n            });\n\n            // for each component initialization need update property\n            this.isReviewRequired(false);\n            this.initClientConfig();\n\n            return this;\n        },\n\n        /**\n         * Get payment name\n         *\n         * @returns {String}\n         */\n        getCode: function () {\n            return this.code;\n        },\n\n        /**\n         * Get payment title\n         *\n         * @returns {String}\n         */\n        getTitle: function () {\n            return window.checkoutConfig.payment[this.getCode()].title;\n        },\n\n        /**\n         * Check if payment is active\n         *\n         * @returns {Boolean}\n         */\n        isActive: function () {\n            var active = this.getCode() === this.isChecked();\n\n            this.active(active);\n\n            return active;\n        },\n\n        /**\n         * Triggers when payment method change\n         * @param {Boolean} isActive\n         */\n        onActiveChange: function (isActive) {\n            if (!isActive) {\n                return;\n            }\n\n            // need always re-init Braintree with PayPal configuration\n            this.reInitPayPal();\n        },\n\n        /**\n         * Init config\n         */\n        initClientConfig: function () {\n            this.clientConfig = _.extend(this.clientConfig, this.getPayPalConfig());\n\n            _.each(this.clientConfig, function (fn, name) {\n                if (typeof fn === 'function') {\n                    this.clientConfig[name] = fn.bind(this);\n                }\n            }, this);\n        },\n\n        /**\n         * Set payment nonce\n         * @param {String} paymentMethodNonce\n         */\n        setPaymentMethodNonce: function (paymentMethodNonce) {\n            this.paymentMethodNonce = paymentMethodNonce;\n        },\n\n        /**\n         * Update quote billing address\n         * @param {Object}customer\n         * @param {Object}address\n         */\n        setBillingAddress: function (customer, address) {\n            var billingAddress = {\n                street: [address.line1],\n                city: address.city,\n                postcode: address.postalCode,\n                countryId: address.countryCode,\n                email: customer.email,\n                firstname: customer.firstName,\n                lastname: customer.lastName,\n                telephone: typeof customer.phone !== 'undefined' ? customer.phone : '00000000000'\n            };\n\n            billingAddress['region_code'] = typeof address.state === 'string' ? address.state : '';\n            billingAddress = createBillingAddress(billingAddress);\n            quote.billingAddress(billingAddress);\n        },\n\n        /**\n         * Prepare data to place order\n         * @param {Object} data\n         */\n        beforePlaceOrder: function (data) {\n            this.setPaymentMethodNonce(data.nonce);\n            this.customerEmail(data.details.email);\n            if (quote.isVirtual()) {\n                this.isReviewRequired(true);\n            } else {\n                if (this.isRequiredBillingAddress() === '1' || quote.billingAddress() === null) {\n                    if (typeof data.details.billingAddress !== 'undefined') {\n                        this.setBillingAddress(data.details, data.details.billingAddress);\n                    } else {\n                        this.setBillingAddress(data.details, data.details.shippingAddress);\n                    }\n                } else {\n                    if (quote.shippingAddress() === quote.billingAddress()) {\n                        selectBillingAddress(quote.shippingAddress());\n                    } else {\n                        selectBillingAddress(quote.billingAddress());\n                    }\n                }\n            }\n            this.placeOrder();\n        },\n\n        /**\n         * Re-init PayPal Auth Flow\n         */\n        reInitPayPal: function () {\n            this.disableButton();\n            this.clientConfig.paypal.amount = parseFloat(this.grandTotalAmount).toFixed(2);\n\n            if (!quote.isVirtual()) {\n                this.clientConfig.paypal.enableShippingAddress = true;\n                this.clientConfig.paypal.shippingAddressEditable = false;\n                this.clientConfig.paypal.shippingAddressOverride = this.getShippingAddress();\n            }\n            // Send Line Items\n            this.clientConfig.paypal.lineItems = this.getLineItems();\n\n            Braintree.setConfig(this.clientConfig);\n\n            if (Braintree.getPayPalInstance()) {\n                Braintree.getPayPalInstance().teardown(function () {\n                    Braintree.setup();\n                }.bind(this));\n                Braintree.setPayPalInstance(null);\n            } else {\n                Braintree.setup();\n                this.enableButton();\n            }\n        },\n\n        /**\n         * Setup PayPal instance\n         */\n        setupPayPal: function () {\n            var self = this;\n\n            if (Braintree.config.paypalInstance) {\n                fullScreenLoader.stopLoader(true);\n                return;\n            }\n\n            paypalCheckout.create({\n                client: Braintree.clientInstance\n            }, function (createErr, paypalCheckoutInstance) {\n                if (createErr) {\n                    Braintree.showError($t(\"PayPal Checkout could not be initialized. Please contact the store owner.\"));\n                    console.error('paypalCheckout error', createErr);\n                    return;\n                }\n                let quoteObj = quote.totals();\n\n                var configSDK = {\n                    components: 'buttons,messages,funding-eligibility',\n                    \"enable-funding\": \"paylater\",\n                    currency: quoteObj['base_currency_code']\n                };\n                var merchantCountry = window.checkoutConfig.payment['braintree_paypal'].merchantCountry;\n                if (Braintree.getEnvironment() == 'sandbox' && merchantCountry != null) {\n                    configSDK[\"buyer-country\"] = merchantCountry;\n                }\n                paypalCheckoutInstance.loadPayPalSDK(configSDK, function () {\n                    this.loadPayPalButton(paypalCheckoutInstance, 'paypal');\n                    if (this.isCreditEnabled()) {\n                        this.loadPayPalButton(paypalCheckoutInstance, 'credit');\n                    }\n                    if (this.isPaylaterEnabled()) {\n                        this.loadPayPalButton(paypalCheckoutInstance, 'paylater');\n                    }\n\n                }.bind(this));\n            }.bind(this));\n        },\n\n        loadPayPalButton: function (paypalCheckoutInstance, funding) {\n            var paypalPayment = Braintree.config.paypal,\n                onPaymentMethodReceived = Braintree.config.onPaymentMethodReceived;\n            var style = {\n                color: Braintree.getColor(funding),\n                shape: Braintree.getShape(funding),\n                size: Braintree.getSize(funding),\n                label: Braintree.getLabel(funding)\n            };\n\n            if (Braintree.getBranding()) {\n                style.branding = Braintree.getBranding();\n            }\n            if (Braintree.getFundingIcons()) {\n                style.fundingicons = Braintree.getFundingIcons();\n            }\n\n            if (funding === 'credit') {\n                Braintree.config.buttonId = this.clientConfig.buttonCreditId;\n            } else if (funding === 'paylater') {\n                Braintree.config.buttonId = this.clientConfig.buttonPaylaterId;\n            } else {\n                Braintree.config.buttonId = this.clientConfig.buttonPayPalId;\n            }\n            // Render\n            Braintree.config.paypalInstance = paypalCheckoutInstance;\n            var events = Braintree.events;\n            $('#' + Braintree.config.buttonId).html('');\n\n            var button = paypal.Buttons({\n                fundingSource: funding,\n                env: Braintree.getEnvironment(),\n                style: style,\n                commit: true,\n                locale: Braintree.config.paypal.locale,\n\n                onInit: function (data, actions) {\n                    var agreements = checkoutAgreements().agreements,\n                        shouldDisableActions = false;\n\n                    actions.disable();\n\n                    _.each(agreements, function (item, index) {\n                        if (checkoutAgreements().isAgreementRequired(item)) {\n                            var paymentMethodCode = quote.paymentMethod().method,\n                                inputId = '#agreement_' + paymentMethodCode + '_' + item.agreementId,\n                                inputEl = document.querySelector(inputId);\n\n\n                            if (!inputEl.checked) {\n                                shouldDisableActions = true;\n                            }\n\n                            inputEl.addEventListener('change', function (event) {\n                                if (additionalValidators.validate()) {\n                                    actions.enable();\n                                } else {\n                                    actions.disable();\n                                }\n                            });\n                        }\n                    });\n\n                    if (!shouldDisableActions) {\n                        actions.enable();\n                    }\n                },\n\n                createOrder: function () {\n                    return paypalCheckoutInstance.createPayment(paypalPayment).catch(function (err) {\n                        throw err.details.originalError.details.originalError.paymentResource;\n                    });\n                },\n\n                onCancel: function (data) {\n                    console.log('checkout.js payment cancelled', JSON.stringify(data, 0, 2));\n\n                    if (typeof events.onCancel === 'function') {\n                        events.onCancel();\n                    }\n                },\n\n                onError: function (err) {\n                    if (err.errorName === 'VALIDATION_ERROR' && err.errorMessage.indexOf('Value is invalid') !== -1) {\n                        Braintree.showError($t('Address failed validation. Please check and confirm your City, State, and Postal Code'));\n                    } else {\n                        Braintree.showError($t(\"PayPal Checkout could not be initialized. Please contact the store owner.\"));\n                    }\n                    Braintree.config.paypalInstance = null;\n                    console.error('Paypal checkout.js error', err);\n\n                    if (typeof events.onError === 'function') {\n                        events.onError(err);\n                    }\n                }.bind(this),\n\n                onClick: function (data) {\n                    if (!quote.isVirtual()) {\n                        this.clientConfig.paypal.enableShippingAddress = true;\n                        this.clientConfig.paypal.shippingAddressEditable = false;\n                        this.clientConfig.paypal.shippingAddressOverride = this.getShippingAddress();\n                    }\n\n                    // To check term & conditions input checked - validate additional validators.\n                    if (!additionalValidators.validate()) {\n                        return false;\n                    }\n\n                    if (typeof events.onClick === 'function') {\n                        events.onClick(data);\n                    }\n                }.bind(this),\n\n                onApprove: function (data, actions) {\n                    return paypalCheckoutInstance.tokenizePayment(data)\n                        .then(function (payload) {\n                            onPaymentMethodReceived(payload);\n                        });\n                }\n\n            });\n            if (button.isEligible() && $('#' + Braintree.config.buttonId).length) {\n                button.render('#' + Braintree.config.buttonId).then(function () {\n                    Braintree.enableButton();\n                    if (typeof Braintree.config.onPaymentMethodError === 'function') {\n                        Braintree.config.onPaymentMethodError();\n                    }\n                }.bind(this)).then(function (data) {\n                    if (typeof events.onRender === 'function') {\n                        events.onRender(data);\n                    }\n                });\n            }\n        },\n\n        /**\n         * Get locale\n         * @returns {String}\n         */\n        getLocale: function () {\n            return window.checkoutConfig.payment[this.getCode()].locale;\n        },\n\n        /**\n         * Is Billing Address required from PayPal side\n         * @returns {exports.isRequiredBillingAddress|(function())|boolean}\n         */\n        isRequiredBillingAddress: function () {\n            return window.checkoutConfig.payment[this.getCode()].isRequiredBillingAddress;\n        },\n\n        /**\n         * Get configuration for PayPal\n         * @returns {Object}\n         */\n        getPayPalConfig: function () {\n            var totals = quote.totals(),\n                config = {},\n                isActiveVaultEnabler = this.isActiveVault();\n\n            config.paypal = {\n                flow: 'checkout',\n                amount: parseFloat(this.grandTotalAmount).toFixed(2),\n                currency: totals['base_currency_code'],\n                locale: this.getLocale(),\n\n                /**\n                 * Triggers on any Braintree error\n                 */\n                onError: function () {\n                    this.paymentMethodNonce = null;\n                },\n\n                /**\n                 * Triggers if browser doesn't support PayPal Checkout\n                 */\n                onUnsupported: function () {\n                    this.paymentMethodNonce = null;\n                }\n            };\n\n            if (isActiveVaultEnabler) {\n                config.paypal.requestBillingAgreement = true;\n            }\n\n            if (!quote.isVirtual()) {\n                config.paypal.enableShippingAddress = true;\n                config.paypal.shippingAddressEditable = false;\n                config.paypal.shippingAddressOverride = this.getShippingAddress();\n            }\n\n            if (this.getMerchantName()) {\n                config.paypal.displayName = this.getMerchantName();\n            }\n\n            return config;\n        },\n\n        /**\n         * Get shipping address\n         * @returns {Object}\n         */\n        getShippingAddress: function () {\n            var address = quote.shippingAddress();\n\n            return {\n                recipientName: address.firstname + ' ' + address.lastname,\n                line1: address.street[0],\n                line2: typeof address.street[2] === 'undefined' ? address.street[1] : address.street[1] + ' ' + address.street[2],\n                city: address.city,\n                countryCode: address.countryId,\n                postalCode: address.postcode,\n                state: address.regionCode\n            };\n        },\n\n        /**\n         * Get merchant name\n         * @returns {String}\n         */\n        getMerchantName: function () {\n            return window.checkoutConfig.payment[this.getCode()].merchantName;\n        },\n\n        /**\n         * Get data\n         * @returns {Object}\n         */\n        getData: function () {\n            var data = {\n                'method': this.getCode(),\n                'additional_data': {\n                    'payment_method_nonce': this.paymentMethodNonce\n                }\n            };\n\n            data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n            this.vaultEnabler.visitAdditionalData(data);\n\n            return data;\n        },\n\n        /**\n         * Returns payment acceptance mark image path\n         * @returns {String}\n         */\n        getPaymentAcceptanceMarkSrc: function () {\n            return window.checkoutConfig.payment[this.getCode()].paymentAcceptanceMarkSrc;\n        },\n\n        /**\n         * @returns {String}\n         */\n        getVaultCode: function () {\n            return window.checkoutConfig.payment[this.getCode()].vaultCode;\n        },\n\n        /**\n         * Check if need to skip order review\n         * @returns {Boolean}\n         */\n        isSkipOrderReview: function () {\n            return window.checkoutConfig.payment[this.getCode()].skipOrderReview;\n        },\n\n        /**\n         * Checks if vault is active\n         * @returns {Boolean}\n         */\n        isActiveVault: function () {\n            return this.vaultEnabler.isVaultEnabled() && this.vaultEnabler.isActivePaymentTokenEnabler();\n        },\n\n        /**\n         * Re-init PayPal Auth flow to use Vault\n         */\n        onVaultPaymentTokenEnablerChange: function () {\n            this.clientConfig.paypal.singleUse = !this.isActiveVault();\n            this.reInitPayPal();\n        },\n\n        /**\n         * Disable submit button\n         */\n        disableButton: function () {\n            // stop any previous shown loaders\n            fullScreenLoader.stopLoader(true);\n            fullScreenLoader.startLoader();\n            $('[data-button=\"place\"]').attr('disabled', 'disabled');\n        },\n\n        /**\n         * Enable submit button\n         */\n        enableButton: function () {\n            $('[data-button=\"place\"]').removeAttr('disabled');\n            fullScreenLoader.stopLoader(true);\n        },\n\n        /**\n         * Triggers when customer click \"Continue to PayPal\" button\n         */\n        payWithPayPal: function () {\n            if (additionalValidators.validate()) {\n                Braintree.checkout.paypal.initAuthFlow();\n            }\n        },\n\n        /**\n         * Get button id\n         * @returns {String}\n         */\n        getPayPalButtonId: function () {\n            return this.clientConfig.buttonPayPalId;\n        },\n\n        /**\n         * Get button id\n         * @returns {String}\n         */\n        getCreditButtonId: function () {\n            return this.clientConfig.buttonCreditId;\n        },\n\n        /**\n         * Get button id\n         * @returns {String}\n         */\n        getPaylaterButtonId: function () {\n            return this.clientConfig.buttonPaylaterId;\n        },\n\n        isPaylaterEnabled: function () {\n            return window.checkoutConfig.payment['braintree_paypal_paylater']['isActive'];\n        },\n\n        isPaylaterMessageEnabled: function () {\n            return window.checkoutConfig.payment['braintree_paypal_paylater']['isMessageActive'];\n        },\n\n        getGrandTotalAmount: function () {\n            return parseFloat(this.grandTotalAmount).toFixed(2);\n        },\n\n        isCreditEnabled: function () {\n            return window.checkoutConfig.payment['braintree_paypal_credit']['isActive'];\n        },\n\n        /**\n         * Get Message Layout\n         * @returns {*}\n         */\n        getMessagingLayout: function () {\n            return window.checkoutConfig.payment['braintree_paypal_paylater']['message']['layout'];\n        },\n\n        /**\n         * Get Message Logo\n         * @returns {*}\n         */\n        getMessagingLogo: function () {\n            return window.checkoutConfig.payment['braintree_paypal_paylater']['message']['logo'];\n        },\n\n        /**\n         * Get Message Logo position\n         * @returns {*}\n         */\n        getMessagingLogoPosition: function () {\n            return window.checkoutConfig.payment['braintree_paypal_paylater']['message']['logo_position'];\n        },\n\n        /**\n         * Get Message Text Color\n         * @returns {*}\n         */\n        getMessagingTextColor: function () {\n            return window.checkoutConfig.payment['braintree_paypal_paylater']['message']['text_color'];\n        },\n\n        /**\n         * Get line items\n         * @returns {Array}\n         */\n        getLineItems: function () {\n            let self = this;\n            let lineItems = [], storeCredit = 0, giftCardAccount = 0;\n            let giftWrappingItems = 0, giftWrappingOrder = 0;\n            $.each(quote.totals()['total_segments'], function(segmentsKey, segmentsItem) {\n                if (segmentsItem['code'] === 'customerbalance') {\n                    storeCredit = parseFloat(Math.abs(segmentsItem['value']).toString()).toFixed(2);\n                }\n                if (segmentsItem['code'] === 'giftcardaccount') {\n                    giftCardAccount = parseFloat(Math.abs(segmentsItem['value']).toString()).toFixed(2);\n                }\n                if (segmentsItem['code'] === 'giftwrapping') {\n                    let extensionAttributes = segmentsItem['extension_attributes'];\n                    giftWrappingOrder = extensionAttributes['gw_base_price'];\n                    giftWrappingItems = extensionAttributes['gw_items_base_price'];\n                }\n            });\n            if (this.canSendLineItems()) {\n                $.each(quote.getItems(), function(quoteItemKey, quoteItem) {\n                    if (quoteItem.parent_item_id !== null || 0.0 === quoteItem.price) {\n                        return true;\n                    }\n\n                    let itemName = self.replaceUnsupportedCharacters(quoteItem.name);\n                    let itemSku = self.replaceUnsupportedCharacters(quoteItem.sku);\n\n                    let description = '';\n                    let itemQty = parseFloat(quoteItem.qty);\n                    let itemUnitAmount = parseFloat(quoteItem.price);\n                    if (itemQty > Math.floor(itemQty) && itemQty < Math.ceil(itemQty)) {\n                        description = 'Item quantity is ' + itemQty.toFixed(2) + ' and per unit amount is ' + itemUnitAmount.toFixed(2);\n                        itemUnitAmount = parseFloat(itemQty * itemUnitAmount);\n                        itemQty = parseFloat('1');\n                    }\n\n                    let lineItemValues = [\n                        itemName,\n                        'debit',\n                        itemQty.toFixed(2),\n                        itemUnitAmount.toFixed(2),\n                        parseFloat(quoteItem.base_tax_amount).toFixed(2),\n                        itemSku,\n                        description\n                    ];\n\n                    let mappedLineItems = $.map(self.lineItemsArray, function(itemElement, itemIndex) {\n                        return [[\n                            self.lineItemsArray[itemIndex],\n                            lineItemValues[itemIndex]\n                        ]]\n                    });\n\n                    lineItems[quoteItemKey] = Object.fromEntries(mappedLineItems);\n                });\n\n                /**\n                 * Adds credit (refund or discount) kind as LineItems for the\n                 * PayPal transaction if discount amount is greater than 0(Zero)\n                 * as discountAmount lineItem field is not being used by PayPal.\n                 *\n                 * https://developer.paypal.com/braintree/docs/reference/response/transaction-line-item/php#discount_amount\n                 */\n                let baseDiscountAmount = parseFloat(Math.abs(quote.totals()['base_discount_amount']).toString()).toFixed(2);\n                if (baseDiscountAmount > 0) {\n                    let discountLineItem = {\n                        'name': 'Discount',\n                        'kind': 'credit',\n                        'quantity': 1.00,\n                        'unitAmount': baseDiscountAmount\n                    };\n\n                    lineItems = $.merge(lineItems, [discountLineItem]);\n                }\n\n                /**\n                 * Adds shipping as LineItems for the PayPal transaction\n                 * if shipping amount is greater than 0(Zero) to manage\n                 * the totals with client-side implementation as there is\n                 * no any field exist in the client-side implementation\n                 * to send the shipping amount to the Braintree.\n                 */\n                if (quote.totals()['base_shipping_amount'] > 0) {\n                    let shippingLineItem = {\n                        'name': 'Shipping',\n                        'kind': 'debit',\n                        'quantity': 1.00,\n                        'unitAmount': quote.totals()['base_shipping_amount']\n                    };\n\n                    lineItems = $.merge(lineItems, [shippingLineItem]);\n                }\n\n                /**\n                 * Adds credit (Store Credit) kind as LineItems for the\n                 * PayPal transaction if store credit is greater than 0(Zero)\n                 * to manage the totals with client-side implementation\n                 */\n                if (storeCredit > 0) {\n                    let storeCreditItem = {\n                        'name': 'Store Credit',\n                        'kind': 'credit',\n                        'quantity': 1.00,\n                        'unitAmount': storeCredit\n                    };\n\n                    lineItems = $.merge(lineItems, [storeCreditItem]);\n                }\n\n                /**\n                 * Adds Gift Wrapping for items as LineItems for the PayPal\n                 * transaction if it is greater than 0(Zero) to manage\n                 * the totals with client-side implementation\n                 */\n                if (giftWrappingItems > 0) {\n                    let gwItems = {\n                        'name': 'Gift Wrapping for Items',\n                        'kind': 'debit',\n                        'quantity': 1.00,\n                        'unitAmount': giftWrappingItems\n                    };\n\n                    lineItems = $.merge(lineItems, [gwItems]);\n                }\n\n                /**\n                 * Adds Gift Wrapping for order as LineItems for the PayPal\n                 * transaction if it is greater than 0(Zero) to manage\n                 * the totals with client-side implementation\n                 */\n                if (giftWrappingOrder > 0) {\n                    let gwOrderItem = {\n                        'name': 'Gift Wrapping for Order',\n                        'kind': 'debit',\n                        'quantity': 1.00,\n                        'unitAmount': giftWrappingOrder\n                    };\n\n                    lineItems = $.merge(lineItems, [gwOrderItem]);\n                }\n\n                /**\n                 * Adds Gift Cards as credit LineItems for the PayPal\n                 * transaction if it is greater than 0(Zero) to manage\n                 * the totals with client-side implementation\n                 */\n                if (giftCardAccount > 0) {\n                    let giftCardItem = {\n                        'name': 'Gift Cards',\n                        'kind': 'credit',\n                        'quantity': 1.00,\n                        'unitAmount': giftCardAccount\n                    };\n\n                    lineItems = $.merge(lineItems, [giftCardItem]);\n                }\n\n                if (lineItems.length >= 250) {\n                    lineItems = [];\n                }\n            }\n            return lineItems;\n        },\n\n        /**\n         * Regex to replace all unsupported characters.\n         *\n         * @param str\n         */\n        replaceUnsupportedCharacters: function (str) {\n            str.replace('/[^a-zA-Z0-9\\s\\-.\\']/', '');\n            return str.substr(0, 127);\n        },\n\n        /**\n         * Can send line items\n         *\n         * @returns {Boolean}\n         */\n        canSendLineItems: function () {\n            return window.checkoutConfig.payment[this.getCode()].canSendLineItems;\n        }\n    });\n});\n","PayPal_Braintree/js/view/payment/method-renderer/hosted-fields.js":"/**\n * Copyright 2013-2017 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\n\ndefine([\n    'jquery',\n    'PayPal_Braintree/js/view/payment/method-renderer/cc-form',\n    'PayPal_Braintree/js/validator',\n    'Magento_Vault/js/view/payment/vault-enabler',\n    'Magento_Checkout/js/model/payment/additional-validators',\n    'mage/translate'\n], function ($, Component, validator, VaultEnabler, additionalValidators, $t) {\n    'use strict';\n\n    return Component.extend({\n\n        defaults: {\n            template: 'PayPal_Braintree/payment/form',\n            clientConfig: {\n\n                /**\n                 * {String}\n                 */\n                id: 'co-transparent-form-braintree'\n            },\n            isValidCardNumber: false,\n            isValidExpirationDate: false,\n            isValidCvvNumber: false,\n\n            onInstanceReady: function (instance) {\n                instance.on('validityChange', this.onValidityChange.bind(this));\n                instance.on('cardTypeChange', this.onCardTypeChange.bind(this));\n            }\n        },\n\n        /**\n         * @returns {exports.initialize}\n         */\n        initialize: function () {\n            this._super();\n            this.vaultEnabler = new VaultEnabler();\n            this.vaultEnabler.setPaymentCode(this.getVaultCode());\n\n            return this;\n        },\n\n        /**\n         * Init config\n         */\n        initClientConfig: function () {\n            this._super();\n\n            this.clientConfig.hostedFields = this.getHostedFields();\n            this.clientConfig.onInstanceReady = this.onInstanceReady.bind(this);\n        },\n\n        /**\n         * @returns {Object}\n         */\n        getData: function () {\n            var data = this._super();\n\n            this.vaultEnabler.visitAdditionalData(data);\n\n            return data;\n        },\n\n        /**\n         * @returns {Bool}\n         */\n        isVaultEnabled: function () {\n            return this.vaultEnabler.isVaultEnabled();\n        },\n\n        /**\n         * Get Braintree Hosted Fields\n         * @returns {Object}\n         */\n        getHostedFields: function () {\n            var self = this,\n                fields = {\n                    number: {\n                        selector: self.getSelector('cc_number'),\n                        placeholder: $t('4111 1111 1111 1111')\n                    },\n                    expirationDate: {\n                        selector: self.getSelector('expirationDate'),\n                        placeholder: $t('MM/YYYY')\n                    }\n                };\n\n            if (self.hasVerification()) {\n                fields.cvv = {\n                    selector: self.getSelector('cc_cid'),\n                    placeholder: $t('123')\n                };\n            }\n\n            return fields;\n        },\n\n        /**\n         * Triggers on Hosted Field changes\n         * @param {Object} event\n         * @returns {Boolean}\n         */\n        onValidityChange: function (event) {\n            // Handle a change in validation or card type\n            if (event.emittedBy === 'number') {\n                this.selectedCardType(null);\n\n                if (event.cards.length === 1) {\n                    this.isValidCardNumber = event.fields.number.isValid;\n                    this.selectedCardType(\n                        validator.getMageCardType(event.cards[0].type, this.getCcAvailableTypes())\n                    );\n                    this.validateCardType();\n                } else {\n                    this.isValidCardNumber = event.fields.number.isValid;\n                    this.validateCardType();\n                }\n            }\n\n            // Other field validations\n            if (event.emittedBy === 'expirationDate') {\n                this.isValidExpirationDate = event.fields.expirationDate.isValid;\n            }\n            if (event.emittedBy === 'cvv') {\n                this.isValidCvvNumber = event.fields.cvv.isValid;\n            }\n        },\n\n        /**\n         * Triggers on Hosted Field card type changes\n         * @param {Object} event\n         * @returns {Boolean}\n         */\n        onCardTypeChange: function (event) {\n            if (event.cards.length === 1) {\n                this.selectedCardType(\n                    validator.getMageCardType(event.cards[0].type, this.getCcAvailableTypes())\n                );\n            } else {\n                this.selectedCardType(null);\n            }\n        },\n\n        /**\n         * Toggle invalid class on selector\n         * @param selector\n         * @param state\n         * @returns {boolean}\n         */\n        validateField: function (selector, state) {\n            var $selector = $(this.getSelector(selector)),\n                invalidClass = 'braintree-hosted-fields-invalid';\n\n            if (state === true) {\n                $selector.removeClass(invalidClass);\n                return true;\n            }\n\n            $selector.addClass(invalidClass);\n            return false;\n        },\n\n        /**\n         * Validate current credit card type\n         * @returns {Boolean}\n         */\n        validateCardType: function () {\n            return this.validateField(\n                'cc_number',\n                (this.isValidCardNumber)\n            );\n        },\n\n        /**\n         * Validate current expiry date\n         * @returns {boolean}\n         */\n        validateExpirationDate: function () {\n            return this.validateField(\n                'expirationDate',\n                (this.isValidExpirationDate === true)\n            );\n        },\n\n        /**\n         * Validate current CVV field\n         * @returns {boolean}\n         */\n        validateCvvNumber: function () {\n            var self = this;\n\n            if (self.hasVerification() === false) {\n                return true;\n            }\n\n            return this.validateField(\n                'cc_cid',\n                (this.isValidCvvNumber === true)\n            );\n        },\n\n        /**\n         * Validate all fields\n         * @returns {boolean}\n         */\n        validateFormFields: function () {\n            return (this.validateCardType() && this.validateExpirationDate() && this.validateCvvNumber()) === true;\n        },\n\n        /**\n         * Trigger order placing\n         */\n        placeOrderClick: function () {\n            if (this.validateFormFields() && additionalValidators.validate()) {\n                this.placeOrder();\n            }\n        },\n        /**\n         * @returns {String}\n         */\n        getVaultCode: function () {\n            return window.checkoutConfig.payment[this.getCode()].ccVaultCode;\n        }\n    });\n});\n","PayPal_Braintree/js/view/payment/method-renderer/venmo.js":"define(\n    [\n        'Magento_Checkout/js/view/payment/default',\n        'braintree',\n        'braintreeDataCollector',\n        'braintreeVenmo',\n        'PayPal_Braintree/js/form-builder',\n        'Magento_Ui/js/model/messageList',\n        'Magento_Checkout/js/model/full-screen-loader',\n        'Magento_Checkout/js/model/payment/additional-validators',\n        'mage/translate'\n    ],\n    function (\n        Component,\n        braintree,\n        dataCollector,\n        venmo,\n        formBuilder,\n        messageList,\n        fullScreenLoader,\n        additionalValidators,\n        $t\n    ) {\n        'use strict';\n\n        return Component.extend({\n            defaults: {\n                deviceData: null,\n                paymentMethodNonce: null,\n                template: 'PayPal_Braintree/payment/venmo',\n                venmoInstance: null\n            },\n\n            clickVenmoBtn: function () {\n                let self = this;\n\n                if (!additionalValidators.validate()) {\n                    return false;\n                }\n\n                if (!this.venmoInstance) {\n                    this.setErrorMsg($t('Venmo not initialized, please try reloading.'));\n                    return;\n                }\n\n                this.venmoInstance.tokenize(function (tokenizeErr, payload) {\n                    if (tokenizeErr) {\n                        if (tokenizeErr.code === 'VENMO_CANCELED') {\n                            self.setErrorMsg($t('Venmo app is not available or the payment flow was cancelled.'));\n                        } else if (tokenizeErr.code === 'VENMO_APP_CANCELED') {\n                            self.setErrorMsg($t('Venmo payment flow cancelled.'));\n                        } else {\n                            self.setErrorMsg(tokenizeErr.message);\n                        }\n                    } else {\n                        self.handleVenmoSuccess(payload);\n                    }\n                });\n            },\n\n            collectDeviceData: function (clientInstance, callback) {\n                let self = this;\n                dataCollector.create({\n                    client: clientInstance,\n                    paypal: true\n                }, function (dataCollectorErr, dataCollectorInstance) {\n                    if (dataCollectorErr) {\n                        return;\n                    }\n                    self.deviceData = dataCollectorInstance.deviceData;\n                    callback();\n                });\n            },\n\n            getClientToken: function () {\n                return window.checkoutConfig.payment[this.getCode()].clientToken;\n            },\n\n            getCode: function() {\n                return 'braintree_venmo';\n            },\n\n            getData: function () {\n                let data = {\n                    'method': this.getCode(),\n                    'additional_data': {\n                        'payment_method_nonce': this.paymentMethodNonce,\n                        'device_data': this.deviceData\n                    }\n                };\n\n                data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n                return data;\n            },\n\n            getPaymentMarkSrc: function () {\n                return window.checkoutConfig.payment[this.getCode()].paymentMarkSrc;\n            },\n\n            getTitle: function() {\n                return 'Venmo';\n            },\n\n            handleVenmoSuccess: function (payload) {\n                this.setPaymentMethodNonce(payload.nonce);\n                this.placeOrder();\n            },\n\n            initialize: function () {\n                this._super();\n\n                let self = this;\n\n                braintree.create({\n                    authorization: self.getClientToken()\n                }, function (clientError, clientInstance) {\n                    if (clientError) {\n                        this.setErrorMsg($t('Unable to initialize Braintree Client.'));\n                        return;\n                    }\n\n                    // Collect device data\n                    self.collectDeviceData(clientInstance, function () {\n                        // callback from collectDeviceData\n                        venmo.create({\n                            client: clientInstance,\n                            allowDesktop: true,\n                            allowDesktopWebLogin: true,\n                            mobileWebFallBack: true,\n                            paymentMethodUsage: 'single_use',\n                            allowNewBrowserTab: false\n                        }, function (venmoErr, venmoInstance) {\n                            if (venmoErr) {\n                                self.setErrorMsg($t('Error initializing Venmo: %1').replace('%1', venmoErr));\n                                return;\n                            }\n\n                            if (!venmoInstance.isBrowserSupported()) {\n                                console.log('Browser does not support Venmo');\n                                return;\n                            }\n\n                            self.setVenmoInstance(venmoInstance);\n                        });\n                    });\n                });\n\n                return this;\n            },\n\n            isAllowed: function () {\n                return window.checkoutConfig.payment[this.getCode()].isAllowed;\n            },\n\n            setErrorMsg: function (message) {\n                messageList.addErrorMessage({\n                    message: message\n                });\n            },\n\n            setPaymentMethodNonce: function (nonce) {\n                this.paymentMethodNonce = nonce;\n            },\n\n            setVenmoInstance: function (instance) {\n                this.venmoInstance = instance;\n            }\n        });\n    }\n);\n","PayPal_Braintree/js/view/payment/method-renderer/vault.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\ndefine([\n    'ko',\n    'jquery',\n    'Magento_Vault/js/view/payment/method-renderer/vault',\n    'PayPal_Braintree/js/view/payment/adapter',\n    'Magento_Ui/js/model/messageList',\n    'PayPal_Braintree/js/view/payment/validator-handler',\n    'Magento_Checkout/js/model/payment/additional-validators',\n    'Magento_Checkout/js/model/full-screen-loader',\n    'braintree',\n    'braintreeHostedFields',\n    'mage/url'\n], function (\n    ko,\n    $,\n    VaultComponent,\n    Braintree,\n    globalMessageList,\n    validatorManager,\n    additionalValidators,\n    fullScreenLoader,\n    client,\n    hostedFields,\n    url\n) {\n    'use strict';\n\n    return VaultComponent.extend({\n        defaults: {\n            active: false,\n            hostedFieldsInstance: null,\n            imports: {\n                onActiveChange: 'active'\n            },\n            modules: {\n                hostedFields: '${ $.parentName }.braintree'\n            },\n            template: 'PayPal_Braintree/payment/cc/vault',\n            updatePaymentUrl: url.build('braintree/payment/updatepaymentmethod'),\n            vaultedCVV: ko.observable(\"\"),\n            validatorManager: validatorManager,\n            isValidCvv: false,\n            onInstanceReady: function (instance) {\n                instance.on('validityChange', this.onValidityChange.bind(this));\n            }\n        },\n\n        /**\n         * Event fired by Braintree SDK whenever input value length matches the validation length.\n         * In the case of a CVV, this is 3, or 4 for AMEX.\n         * @param event\n         */\n        onValidityChange: function (event) {\n            if (event.emittedBy === 'cvv') {\n                this.isValidCvv = event.fields.cvv.isValid;\n            }\n        },\n\n        /**\n         * @returns {exports}\n         */\n        initObservable: function () {\n            this._super().observe(['active']);\n            this.validatorManager.initialize();\n            return this;\n        },\n\n        /**\n         * Is payment option active?\n         * @returns {boolean}\n         */\n        isActive: function () {\n            let active = this.getId() === this.isChecked();\n            this.active(active);\n            return active;\n        },\n\n        /**\n         * Fired whenever a payment option is changed.\n         * @param isActive\n         */\n        onActiveChange: function (isActive) {\n            let self = this;\n\n            if (!isActive) {\n                return;\n            }\n\n            if (self.showCvvVerify()) {\n                if (self.hostedFieldsInstance) {\n                    self.hostedFieldsInstance.teardown(function (teardownError) {\n                        if (teardownError) {\n                            globalMessageList.addErrorMessage({\n                                message: teardownError.message\n                            });\n                        }\n                        self.hostedFieldsInstance = null;\n                        self.initHostedCvvField();\n                    });\n                    return;\n                }\n                self.initHostedCvvField();\n            }\n        },\n\n        /**\n         * Initialize the CVV input field with the Braintree Hosted Fields SDK.\n         */\n        initHostedCvvField: function () {\n            let self = this;\n            client.create({\n                authorization: Braintree.getClientToken()\n            }, function (clientError, clientInstance) {\n                if (clientError) {\n                    globalMessageList.addErrorMessage({\n                        message: clientError.message\n                    });\n                }\n                hostedFields.create({\n                    client: clientInstance,\n                    fields: {\n                        cvv: {\n                            selector: '#' + self.getId() + '_cid',\n                            placeholder: '123'\n                        }\n                    }\n                }, function (hostedError, hostedFieldsInstance) {\n                    if (hostedError) {\n                        globalMessageList.addErrorMessage({\n                            message: hostedError.message\n                        });\n                        return;\n                    }\n\n                    self.hostedFieldsInstance = hostedFieldsInstance;\n                    self.onInstanceReady(self.hostedFieldsInstance);\n                });\n            });\n        },\n\n        /**\n         * Return the payment method code.\n         * @returns {string}\n         */\n        getCode: function () {\n            return 'braintree_cc_vault';\n        },\n\n        /**\n         * Get last 4 digits of card\n         * @returns {String}\n         */\n        getMaskedCard: function () {\n            return this.details.maskedCC;\n        },\n\n        /**\n         * Get expiration date\n         * @returns {String}\n         */\n        getExpirationDate: function () {\n            return this.details.expirationDate;\n        },\n\n        /**\n         * Get card type\n         * @returns {String}\n         */\n        getCardType: function () {\n            return this.details.type;\n        },\n\n        /**\n         * Get show CVV Field\n         * @returns {Boolean}\n         */\n        showCvvVerify: function () {\n            return window.checkoutConfig.payment[this.code].cvvVerify;\n        },\n\n        /**\n         * Show or hide the error message.\n         * @param selector\n         * @param state\n         * @returns {boolean}\n         */\n        validateCvv: function (selector, state) {\n            let $selector = $(selector),\n                invalidClass = 'braintree-hosted-fields-invalid';\n\n            if (state === true) {\n                $selector.removeClass(invalidClass);\n                return true;\n            }\n\n            $selector.addClass(invalidClass);\n            return false;\n        },\n\n        /**\n         * Place order\n         */\n        placeOrder: function () {\n            let self = this;\n\n            if (self.showCvvVerify()) {\n                if (!self.validateCvv('#' + self.getId() + '_cid', self.isValidCvv) || !additionalValidators.validate()) {\n                    return;\n                }\n            } else {\n                if (!additionalValidators.validate()) {\n                    return;\n                }\n            }\n\n            fullScreenLoader.startLoader();\n\n            if (self.showCvvVerify() && typeof self.hostedFieldsInstance !== 'undefined') {\n                self.hostedFieldsInstance.tokenize({}, function (error, payload) {\n                    if (error) {\n                        fullScreenLoader.stopLoader();\n                        globalMessageList.addErrorMessage({\n                            message: error.message\n                        });\n                        return;\n                    }\n                    $.getJSON(self.updatePaymentUrl, {\n                        'nonce': payload.nonce,\n                        'public_hash': self.publicHash\n                    }).done(function (response) {\n                        if (response.success === false) {\n                            fullScreenLoader.stopLoader();\n                            globalMessageList.addErrorMessage({\n                                message: 'CVV verification failed.'\n                            });\n                            return;\n                        }\n                        self.getPaymentMethodNonce();\n                    })\n                });\n            } else {\n                self.getPaymentMethodNonce();\n            }\n        },\n\n        /**\n         * Send request to get payment method nonce\n         */\n        getPaymentMethodNonce: function () {\n            let self = this;\n\n            fullScreenLoader.startLoader();\n            $.getJSON(self.nonceUrl, {\n                'public_hash': self.publicHash,\n                'cvv': self.vaultedCVV()\n            }).done(function (response) {\n                fullScreenLoader.stopLoader();\n                self.hostedFields(function (formComponent) {\n                    formComponent.setPaymentMethodNonce(response.paymentMethodNonce);\n                    formComponent.setCreditCardBin(response.details.bin);\n                    formComponent.additionalData['public_hash'] = self.publicHash;\n                    formComponent.code = self.code;\n                    if (self.vaultedCVV()) {\n                        formComponent.additionalData['cvv'] = self.vaultedCVV();\n                    }\n\n                    self.validatorManager.validate(formComponent, function () {\n                        fullScreenLoader.stopLoader();\n                        return formComponent.placeOrder('parent');\n                    }, function() {\n                        // No teardown actions required.\n                        fullScreenLoader.stopLoader();\n                        formComponent.setPaymentMethodNonce(null);\n                        formComponent.setCreditCardBin(null);\n                    });\n\n                });\n            }).fail(function (response) {\n                let error = JSON.parse(response.responseText);\n\n                fullScreenLoader.stopLoader();\n                globalMessageList.addErrorMessage({\n                    message: error.message\n                });\n            });\n        }\n    });\n});\n","PayPal_Braintree/js/view/payment/method-renderer/multishipping/paypal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\ndefine([\n    'jquery',\n    'underscore',\n    'braintreeCheckoutPayPalAdapter',\n    'Magento_Checkout/js/model/quote',\n    'PayPal_Braintree/js/view/payment/method-renderer/paypal',\n    'Magento_Checkout/js/action/set-payment-information',\n    'Magento_Checkout/js/model/payment/additional-validators',\n    'Magento_Checkout/js/model/full-screen-loader',\n    'mage/translate'\n], function (\n    $,\n    _,\n    Braintree,\n    quote,\n    Component,\n    setPaymentInformationAction,\n    additionalValidators,\n    fullScreenLoader,\n    $t\n) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'PayPal_Braintree/payment/multishipping/paypal',\n            submitButtonSelector: '[id=\"parent-payment-continue\"]',\n            reviewButtonHtml: ''\n        },\n\n        /**\n         * @override\n         */\n        initObservable: function () {\n            this.reviewButtonHtml = $(this.submitButtonSelector).html();\n            return this._super();\n        },\n\n        initClientConfig: function () {\n            this.clientConfig = _.extend(this.clientConfig, this.getPayPalConfig());\n            this.clientConfig.paypal.enableShippingAddress = false;\n\n            _.each(this.clientConfig, function (fn, name) {\n                if (typeof fn === 'function') {\n                    this.clientConfig[name] = fn.bind(this);\n                }\n            }, this);\n            this.clientConfig.buttonPayPalId = 'parent-payment-continue';\n\n        },\n\n        /**\n         * @override\n         */\n        onActiveChange: function (isActive) {\n            this.updateSubmitButtonHtml(isActive);\n            this._super(isActive);\n        },\n\n        /**\n         * @override\n         */\n        beforePlaceOrder: function (data) {\n            this._super(data);\n        },\n\n        /**\n         * Re-init PayPal Auth Flow\n         */\n        reInitPayPal: function () {\n            this.disableButton();\n            this.clientConfig.paypal.amount = parseFloat(this.grandTotalAmount).toFixed(2);\n\n            if (!quote.isVirtual()) {\n                this.clientConfig.paypal.enableShippingAddress = false;\n                this.clientConfig.paypal.shippingAddressEditable = false;\n            }\n\n            Braintree.setConfig(this.clientConfig);\n\n            if (Braintree.getPayPalInstance()) {\n                Braintree.getPayPalInstance().teardown(function () {\n                    Braintree.setup();\n                }.bind(this));\n                Braintree.setPayPalInstance(null);\n            } else {\n                Braintree.setup();\n                this.enableButton();\n            }\n        },\n\n        loadPayPalButton: function (paypalCheckoutInstance, funding) {\n            let paypalPayment = Braintree.config.paypal,\n                onPaymentMethodReceived = Braintree.config.onPaymentMethodReceived;\n            let style = {\n                color: Braintree.getColor(funding),\n                shape: Braintree.getShape(funding),\n                size: Braintree.getSize(funding),\n                label: Braintree.getLabel(funding)\n            };\n\n            if (Braintree.getBranding()) {\n                style.branding = Braintree.getBranding();\n            }\n            if (Braintree.getFundingIcons()) {\n                style.fundingicons = Braintree.getFundingIcons();\n            }\n\n            if (funding === 'credit') {\n                Braintree.config.buttonId = this.clientConfig.buttonCreditId;\n            } else if (funding === 'paylater') {\n                Braintree.config.buttonId = this.clientConfig.buttonPaylaterId;\n            } else {\n                Braintree.config.buttonId = this.clientConfig.buttonPayPalId;\n            }\n\n            // Render\n            Braintree.config.paypalInstance = paypalCheckoutInstance;\n            var events = Braintree.events;\n            $('#' + Braintree.config.buttonId).html('');\n\n            var button = paypal.Buttons({\n                fundingSource: funding,\n                env: Braintree.getEnvironment(),\n                style: style,\n                commit: true,\n                locale: Braintree.config.paypal.locale,\n\n                createOrder: function () {\n                    return paypalCheckoutInstance.createPayment(paypalPayment);\n                },\n\n                onCancel: function (data) {\n                    console.log('checkout.js payment cancelled', JSON.stringify(data, 0, 2));\n\n                    if (typeof events.onCancel === 'function') {\n                        events.onCancel();\n                    }\n                },\n\n                onError: function (err) {\n                    Braintree.showError($t(\"PayPal Checkout could not be initialized. Please contact the store owner.\"));\n                    Braintree.config.paypalInstance = null;\n                    console.error('Paypal checkout.js error', err);\n\n                    if (typeof events.onError === 'function') {\n                        events.onError(err);\n                    }\n                }.bind(this),\n\n                onClick: function (data) {\n                    // To check term & conditions input checked - validate additional validators.\n                    if (!additionalValidators.validate()) {\n                        return false;\n                    }\n\n                    if (typeof events.onClick === 'function') {\n                        events.onClick(data);\n                    }\n                }.bind(this),\n\n                onApprove: function (data, actions) {\n                    return paypalCheckoutInstance.tokenizePayment(data)\n                        .then(function (payload) {\n                            onPaymentMethodReceived(payload);\n                        });\n                }\n\n            });\n            if (button.isEligible() && $('#' + Braintree.config.buttonId).length) {\n\n                button.render('#' + Braintree.config.buttonId).then(function () {\n                    Braintree.enableButton();\n                    if (typeof Braintree.config.onPaymentMethodError === 'function') {\n                        Braintree.config.onPaymentMethodError();\n                    }\n                }.bind(this)).then(function (data) {\n                    if (typeof events.onRender === 'function') {\n                        events.onRender(data);\n                    }\n                });\n            }\n        },\n\n        /**\n         * Get configuration for PayPal\n         * @returns {Object}\n         */\n        getPayPalConfig: function () {\n            var totals = quote.totals(),\n                config = {},\n                isActiveVaultEnabler = this.isActiveVault();\n\n            config.paypal = {\n                flow: 'checkout',\n                amount: parseFloat(this.grandTotalAmount).toFixed(2),\n                currency: totals['base_currency_code'],\n                locale: this.getLocale(),\n                requestBillingAgreement: true,\n                /**\n                 * Triggers on any Braintree error\n                 */\n                onError: function () {\n                    this.paymentMethodNonce = null;\n                },\n\n                /**\n                 * Triggers if browser doesn't support PayPal Checkout\n                 */\n                onUnsupported: function () {\n                    this.paymentMethodNonce = null;\n                }\n            };\n\n            if (!quote.isVirtual()) {\n                config.paypal.enableShippingAddress = false;\n                config.paypal.shippingAddressEditable = false;\n            }\n\n            if (this.getMerchantName()) {\n                config.paypal.displayName = this.getMerchantName();\n            }\n\n            return config;\n        },\n\n        getShippingAddress: function () {\n\n            return {};\n        },\n\n        /**\n         * @override\n         */\n        getData: function () {\n            var data = this._super();\n\n            data['additional_data']['is_active_payment_token_enabler'] = true;\n\n            return data;\n        },\n\n        /**\n         * @override\n         */\n        isActiveVault: function () {\n            return true;\n        },\n\n        /**\n         * Skipping order review step on checkout with multiple addresses is not allowed.\n         *\n         * @returns {Boolean}\n         */\n        isSkipOrderReview: function () {\n            return false;\n        },\n\n        /**\n         * Checks if payment method nonce is already received.\n         *\n         * @returns {Boolean}\n         */\n        isPaymentMethodNonceReceived: function () {\n            return this.paymentMethodNonce !== null;\n        },\n\n        /**\n         * Update submit button on multi-addresses checkout billing form.\n         *\n         * @param {Boolean} isActive\n         */\n        updateSubmitButtonHtml: function (isActive) {\n            $(this.submitButtonSelector).removeClass(\"primary\");\n            if (this.isPaymentMethodNonceReceived() || !isActive) {\n                $(this.submitButtonSelector).addClass(\"primary\");\n                $(this.submitButtonSelector).html(this.reviewButtonHtml);\n            }\n        },\n\n        /**\n         * @override\n         */\n        placeOrder: function () {\n            if (!this.isPaymentMethodNonceReceived()) {\n                this.payWithPayPal();\n            } else {\n                fullScreenLoader.startLoader();\n\n                $.when(\n                    setPaymentInformationAction(\n                        this.messageContainer,\n                        this.getData()\n                    )\n                ).done(this.done.bind(this))\n                    .fail(this.fail.bind(this));\n            }\n        },\n\n        /**\n         * {Function}\n         */\n        fail: function () {\n            fullScreenLoader.stopLoader();\n\n            return this;\n        },\n\n        /**\n         * {Function}\n         */\n        done: function () {\n            fullScreenLoader.stopLoader();\n            $('#multishipping-billing-form').submit();\n\n            return this;\n        }\n    });\n});\n","PayPal_Braintree/js/view/payment/method-renderer/multishipping/hosted-fields.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\n\ndefine([\n    'jquery',\n    'PayPal_Braintree/js/view/payment/method-renderer/hosted-fields',\n    'PayPal_Braintree/js/validator',\n    'Magento_Ui/js/model/messageList',\n    'mage/translate',\n    'Magento_Checkout/js/model/full-screen-loader',\n    'Magento_Checkout/js/action/set-payment-information',\n    'Magento_Checkout/js/model/payment/additional-validators',\n    'PayPal_Braintree/js/view/payment/adapter'\n], function (\n    $,\n    Component,\n    validator,\n    messageList,\n    $t,\n    fullScreenLoader,\n    setPaymentInformationAction,\n    additionalValidators,\n    braintree\n) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'PayPal_Braintree/payment/multishipping/form'\n        },\n\n        /**\n         * Get list of available CC types\n         *\n         * @returns {Object}\n         */\n        getCcAvailableTypes: function () {\n            let availableTypes = validator.getAvailableCardTypes(),\n                billingCountryId;\n\n            billingCountryId = $('#multishipping_billing_country_id').val();\n\n            if (billingCountryId && validator.getCountrySpecificCardTypes(billingCountryId)) {\n                return validator.collectTypes(\n                    availableTypes, validator.getCountrySpecificCardTypes(billingCountryId)\n                );\n            }\n\n            return availableTypes;\n        },\n\n        /**\n         * @override\n         */\n        handleNonce: function (payload) {\n            let self = this;\n            this.setPaymentMethodNonce(payload.nonce);\n            this.setCreditCardBin(payload.details.bin);\n\n            // place order on success validation\n            self.validatorManager.validate(self, function () {\n                return self.setPaymentInformation();\n            }, function() {\n                self.isProcessing = false;\n                self.paymentMethodNonce = null;\n                self.creditCardBin = null;\n            });\n        },\n\n        /**\n         * @override\n         */\n        placeOrder: function () {\n            if (this.isProcessing) {\n                return false;\n            } else {\n                this.isProcessing = true;\n            }\n\n            braintree.tokenizeHostedFields();\n            return false;\n        },\n\n        /**\n         * @override\n         */\n        setPaymentInformation: function () {\n            if (additionalValidators.validate()) {\n                fullScreenLoader.startLoader();\n                $.when(\n                    setPaymentInformationAction(\n                        this.messageContainer,\n                        this.getData()\n                    )\n                ).done(this.done.bind(this))\n                    .fail(this.fail.bind(this));\n            }\n        },\n\n        /**\n         * {Function}\n         */\n        fail: function () {\n            fullScreenLoader.stopLoader();\n\n            return this;\n        },\n\n        /**\n         * {Function}\n         */\n        done: function () {\n            fullScreenLoader.stopLoader();\n            $('#multishipping-billing-form').submit();\n\n            return this;\n        }\n    });\n});\n","PayPal_Braintree/js/paypal/button.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(\n    [\n        'rjsResolver',\n        'uiRegistry',\n        'uiComponent',\n        'underscore',\n        'jquery',\n        'Magento_Customer/js/customer-data',\n        'mage/translate',\n        'braintree',\n        'braintreeDataCollector',\n        'braintreePayPalCheckout',\n        'PayPal_Braintree/js/form-builder',\n        'domReady!'\n    ],\n    function (\n        resolver,\n        registry,\n        Component,\n        _,\n        $,\n        customerData,\n        $t,\n        braintree,\n        dataCollector,\n        paypalCheckout,\n        formBuilder\n    ) {\n        'use strict';\n        let buttonIds = [];\n\n        return {\n            events: {\n                onClick: null,\n                onCancel: null,\n                onError: null\n            },\n\n            /**\n             * @param token\n             * @param currency\n             * @param env\n             * @param local\n             * @param lineItems\n             */\n            init: function (token, currency, env, local, lineItems) {\n                if ($('.action-braintree-paypal-message').length) {\n                    $('.product-add-form form').on('keyup change paste', 'input, select, textarea', function () {\n                        var currentPrice, currencySymbol;\n                        currentPrice = $(\".product-info-main span\").find(\"[data-price-type='finalPrice']\").text();\n                        currencySymbol = $('.action-braintree-paypal-message[data-pp-type=\"product\"]').data('currency-symbol');\n                        $('.action-braintree-paypal-message[data-pp-type=\"product\"]').attr('data-pp-amount', currentPrice.replace(currencySymbol,''));\n                    });\n                }\n\n                buttonIds = [];\n                $('.action-braintree-paypal-logo').each(function () {\n                    if (!$(this).hasClass(\"button-loaded\")) {\n                        $(this).addClass('button-loaded');\n                        buttonIds.push($(this).attr('id'));\n                    }\n                });\n\n                if (buttonIds.length > 0) {\n                    this.loadSDK(token, currency, env, local, lineItems);\n                }\n            },\n\n            /**\n             * Load Braintree PayPal SDK\n             * @param token\n             * @param currency\n             * @param env\n             * @param local\n             * @param lineItems\n             */\n            loadSDK: function (token, currency, env, local, lineItems) {\n                braintree.create({\n                    authorization: token\n                }, function (clientErr, clientInstance) {\n                    if (clientErr) {\n                        console.error('paypalCheckout error', clientErr);\n                        return this.showError(\"PayPal Checkout could not be initialized. Please contact the store owner.\");\n                    }\n                    dataCollector.create({\n                        client: clientInstance,\n                        paypal: true\n                    }, function (err, dataCollectorInstance) {\n                        if (err) {\n                            return console.log(err);\n                        }\n                    });\n                    paypalCheckout.create({\n                        client: clientInstance\n                    }, function (err, paypalCheckoutInstance) {\n                        if (typeof paypal !== 'undefined' ) {\n                            this.renderPayPalButtons(buttonIds, paypalCheckoutInstance, lineItems);\n                            this.renderPayPalMessages();\n                        } else {\n                            var configSDK = {\n                                components: 'buttons,messages,funding-eligibility',\n                                \"enable-funding\": \"paylater\",\n                                currency: currency\n                            };\n                            if (env === 'sandbox' && local !== '') {\n                                configSDK[\"buyer-country\"] = local;\n                            }\n                            paypalCheckoutInstance.loadPayPalSDK(configSDK, function () {\n                                this.renderPayPalButtons(buttonIds, paypalCheckoutInstance, lineItems);\n                                this.renderPayPalMessages();\n                            }.bind(this));\n                        }\n                    }.bind(this));\n                }.bind(this));\n            },\n\n            /**\n             * Render PayPal buttons\n             *\n             * @param ids\n             * @param paypalCheckoutInstance\n             * @param lineItems\n             */\n            renderPayPalButtons: function (ids, paypalCheckoutInstance, lineItems) {\n                _.each(ids, function (id) {\n                    this.payPalButton(id, paypalCheckoutInstance, lineItems);\n                }.bind(this));\n            },\n\n            /**\n             * Render PayPal messages\n             */\n            renderPayPalMessages: function () {\n                $('.action-braintree-paypal-message').each(function () {\n                    paypal.Messages({\n                        amount: $(this).data('pp-amount'),\n                        pageType: $(this).data('pp-type'),\n                        style: {\n                            layout: $(this).data('messaging-layout'),\n                            text: {\n                              color:   $(this).data('messaging-text-color')\n                            },\n                            logo: {\n                                type: $(this).data('messaging-logo'),\n                                position: $(this).data('messaging-logo-position')\n                            }\n                        }\n                    }).render('#' + $(this).attr('id'));\n\n\n                });\n            },\n\n            /**\n             * @param id\n             * @param paypalCheckoutInstance\n             * @param lineItems\n             */\n            payPalButton: function (id, paypalCheckoutInstance, lineItems) {\n                let data = $('#' + id);\n                let style = {\n                    color: data.data('color'),\n                    shape: data.data('shape'),\n                    size: data.data('size'),\n                    label: data.data('label')\n                };\n\n                if (data.data('fundingicons')) {\n                    style.fundingicons = data.data('fundingicons');\n                }\n\n                // Render\n                var paypalActions;\n                var button = paypal.Buttons({\n                    fundingSource: data.data('funding'),\n                    style: style,\n                    createOrder: function () {\n                        return paypalCheckoutInstance.createPayment({\n                            amount: data.data('amount'),\n                            locale: data.data('locale'),\n                            currency: data.data('currency'),\n                            flow: 'checkout',\n                            enableShippingAddress: true,\n                            displayName: data.data('displayname'),\n                            lineItems: $.parseJSON(lineItems)\n                        });\n                    },\n                    validate: function (actions) {\n                        var cart = customerData.get('cart'),\n                            customer = customerData.get('customer'),\n                            declinePayment = false,\n                            isGuestCheckoutAllowed;\n                        isGuestCheckoutAllowed = cart().isGuestCheckoutAllowed;\n                        declinePayment = !customer().firstname && !isGuestCheckoutAllowed;\n                        if (declinePayment) {\n                            actions.disable();\n                        }\n                        paypalActions = actions;\n                    },\n\n                    onCancel: function (data) {\n                        jQuery(\"#maincontent\").trigger('processStop');\n                    },\n\n                    onError: function (err) {\n                        console.error('paypalCheckout button render error', err);\n                        jQuery(\"#maincontent\").trigger('processStop');\n                    },\n\n                    onClick: function (data) {\n                        var cart = customerData.get('cart'),\n                            customer = customerData.get('customer'),\n                            declinePayment = false,\n                            isGuestCheckoutAllowed;\n\n                        isGuestCheckoutAllowed = cart().isGuestCheckoutAllowed;\n                        declinePayment = !customer().firstname && !isGuestCheckoutAllowed && (typeof isGuestCheckoutAllowed !== 'undefined');\n                        if (declinePayment) {\n                            alert($t('To check out, please sign in with your email address.'));\n                        }\n                    },\n\n                    onApprove: function (data1) {\n                        return paypalCheckoutInstance.tokenizePayment(data1, function (err, payload) {\n                            jQuery(\"#maincontent\").trigger('processStart');\n\n                            // Map the shipping address correctly\n                            var address = payload.details.shippingAddress;\n                            var recipientFirstName, recipientLastName;\n                            if (typeof address.recipientName !== 'undefined') {\n                                var recipientName = address.recipientName.split(\" \");\n                                recipientFirstName = recipientName[0].replace(/'/g, \"&apos;\");\n                                recipientLastName = recipientName[1].replace(/'/g, \"&apos;\");\n                            } else {\n                                recipientFirstName = payload.details.firstName.replace(/'/g, \"&apos;\");\n                                recipientLastName = payload.details.lastName.replace(/'/g, \"&apos;\");\n                            }\n                            payload.details.shippingAddress = {\n                                streetAddress: typeof address.line2 !== 'undefined' ? address.line1.replace(/'/g, \"&apos;\") + \" \" + address.line2.replace(/'/g, \"&apos;\") : address.line1.replace(/'/g, \"&apos;\"),\n                                locality: address.city.replace(/'/g, \"&apos;\"),\n                                postalCode: address.postalCode,\n                                countryCodeAlpha2: address.countryCode,\n                                email: payload.details.email.replace(/'/g, \"&apos;\"),\n                                recipientFirstName: recipientFirstName,\n                                recipientLastName: recipientLastName,\n                                telephone: typeof payload.details.phone !== 'undefined' ? payload.details.phone : '',\n                                region: typeof address.state !== 'undefined' ? address.state.replace(/'/g, \"&apos;\") : ''\n                            };\n\n                            payload.details.email = payload.details.email.replace(/'/g, \"&apos;\");\n                            payload.details.firstName = payload.details.firstName.replace(/'/g, \"&apos;\");\n                            payload.details.lastName = payload.details.lastName.replace(/'/g, \"&apos;\");\n                            if (typeof payload.details.businessName !== 'undefined') {\n                                payload.details.businessName = payload.details.businessName.replace(/'/g, \"&apos;\");\n                            }\n\n                            // Map the billing address correctly\n                            let isRequiredBillingAddress = data.data('requiredbillingaddress');\n                            if ((isRequiredBillingAddress === 1) && (typeof payload.details.billingAddress !== 'undefined')) {\n                                var billingAddress = payload.details.billingAddress;\n                                payload.details.billingAddress = {\n                                    streetAddress: typeof billingAddress.line2 !== 'undefined' ? billingAddress.line1.replace(/'/g, \"&apos;\") + \" \" + billingAddress.line2.replace(/'/g, \"&apos;\") : billingAddress.line1.replace(/'/g, \"&apos;\"),\n                                    locality: billingAddress.city.replace(/'/g, \"&apos;\"),\n                                    postalCode: billingAddress.postalCode,\n                                    countryCodeAlpha2: billingAddress.countryCode,\n                                    telephone: typeof payload.details.phone !== 'undefined' ? payload.details.phone : '',\n                                    region: typeof billingAddress.state !== 'undefined' ? billingAddress.state.replace(/'/g, \"&apos;\") : ''\n                                };\n                            }\n\n                            if (data.data('location') == 'productpage') {\n                                var form = $(\"#product_addtocart_form\");\n                                if (!(form.validation() && form.validation('isValid'))) {\n                                    return false;\n                                }\n                                payload.additionalData = form.serialize();\n                            }\n\n                            var actionSuccess = data.data('actionsuccess');\n                            formBuilder.build(\n                                {\n                                    action: actionSuccess,\n                                    fields: {\n                                        result: JSON.stringify(payload)\n                                    }\n                                }\n                            ).submit();\n                        });\n                    }\n                });\n                if (!button.isEligible()) {\n                    console.log('PayPal button is not elligible')\n                    data.parent().remove();\n                    return;\n                }\n                if ($('#' + data.attr('id')).length) {\n                    button.render('#' + data.attr('id'));\n                }\n            },\n        }\n    }\n);\n","PayPal_Braintree/js/paypal/form-builder.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(\n    [\n        'jquery',\n        'underscore',\n        'mage/template'\n    ],\n    function ($, _, mageTemplate) {\n        'use strict';\n\n        return {\n\n            /**\n             * @param {Object} formData\n             * @returns {*|jQuery}\n             */\n            build: function (formData) {\n                var formTmpl = mageTemplate('<form action=\"<%= data.action %>\"' +\n                    ' method=\"POST\" hidden enctype=\"application/x-www-form-urlencoded\">' +\n                        '<% _.each(data.fields, function(val, key){ %>' +\n                            '<input value=\\'<%= val %>\\' name=\"<%= key %>\" type=\"hidden\">' +\n                        '<% }); %>' +\n                    '</form>');\n\n                return $(formTmpl({\n                    data: {\n                        action: formData.action,\n                        fields: formData.fields\n                    }\n                })).appendTo($('[data-container=\"body\"]'));\n            }\n        };\n    }\n);\n","PayPal_Braintree/js/paypal/product-page.js":"define(\n    ['PayPal_Braintree/js/paypal/button', 'jquery'],\n    function (button, $) {\n        'use strict';\n\n        return button.extend({\n\n            defaults: {\n                label: 'buynow',\n                branding: true,\n            },\n\n            /**\n             * The validation on the add-to-cart form is done after the PayPal window has opened.\n             * This is because the validate method exposed by the PP Button requires an event to disable/enable the button.\n             * We can't fire an event due to the way the mage.validation widget works and we can't do something gross like\n             * an interval because the validation() method shows the error messages and focuses the user's input on the\n             * first erroring input field.\n             * @param payload\n             * @returns {*}\n             */\n            beforeSubmit: function (payload) {\n                var form = $(\"#product_addtocart_form\");\n\n                if (!(form.validation() && form.validation('isValid'))) {\n                    return false;\n                }\n\n                payload.additionalData = form.serialize();\n\n                return payload;\n            }\n        });\n    }\n);","PayPal_Braintree/js/paypal/credit/calculator.js":"define([\n    'underscore',\n    'uiComponent',\n    'jquery'\n], function (_, Component, $) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: \"PayPal_Braintree/credit/calculator\",\n            displaySummary: true, // \"From X per month\"\n            displayInterestDetails: false, // Display the more in-depth summary of interest rates\n            instalmentsFrom: 0,\n            currentInstalment: {\n                term: 0,\n                monthlyPayment: 0,\n                apr: 0,\n                cost: 0,\n                costIncInterest: 0\n            },\n            endpoint: null,\n            instalments: [],\n            visible: false,\n            merchantName: ''\n        },\n\n        initObservable: function () {\n            this._super();\n            if (this.instalments.length > 0) {\n                this.currentInstalment = this.instalments[0];\n                this.instalmentsFrom = this.instalments[this.instalments.length-1].monthlyPayment;\n                this.visible = true;\n            } else {\n                this.loadInstalments();\n            }\n\n            this.observe(['instalments', 'currentInstalment', 'instalmentsFrom', 'visible']);\n            return this;\n        },\n\n        isCurrentInstalment: function (term) {\n            return (this.currentInstalment().term === term);\n        },\n\n        setCurrentInstalment: function (instalment) {\n            this.currentInstalment(instalment);\n        },\n\n        loadInstalments: function () {\n            if (!this.endpoint) {\n                return false;\n            }\n\n            var self = this;\n            require(['Magento_Checkout/js/model/quote', 'jquery'], function (quote, $) {\n                if (typeof quote.totals().base_grand_total === 'undefined') {\n                    return false;\n                }\n\n                $.getJSON(self.endpoint, {amount: quote.totals().base_grand_total}, function (response) {\n                    self.instalments(response);\n                    self.setCurrentInstalment(response[0]);\n                    self.visible(true);\n                });\n            });\n        }\n    });\n});\n","PayPal_Braintree/js/googlepay/button.js":"/**\n * Braintree Google Pay button\n **/\ndefine(\n    [\n        'uiComponent',\n        \"knockout\",\n        \"jquery\",\n        'Magento_Checkout/js/model/payment/additional-validators',\n        'Magento_CheckoutAgreements/js/view/checkout-agreements',\n        'braintree',\n        'braintreeDataCollector',\n        'braintreeGooglePay',\n        'mage/translate',\n        'googlePayLibrary'\n    ],\n    function (\n        Component,\n        ko,\n        jQuery,\n        additionalValidators,\n        checkoutAgreements,\n        braintree,\n        dataCollector,\n        googlePay,\n        $t\n    ) {\n        'use strict';\n\n        return {\n            init: function (element, context) {\n\n                // No element or context\n                if (!element || !context ) {\n                    return;\n                }\n\n                // Context must implement these methods\n                if (typeof context.getClientToken !== 'function') {\n                    console.error(\"Braintree GooglePay Context passed does not provide a getClientToken method\", context);\n                    return;\n                }\n                if (typeof context.getPaymentRequest !== 'function') {\n                    console.error(\"Braintree GooglePay Context passed does not provide a getPaymentRequest method\", context);\n                    return;\n                }\n                if (typeof context.startPlaceOrder !== 'function') {\n                    console.error(\"Braintree GooglePay Context passed does not provide a startPlaceOrder method\", context);\n                    return;\n                }\n\n                // init google pay object\n                var paymentsClient = new google.payments.api.PaymentsClient({\n                    environment: context.getEnvironment()\n                });\n\n                // Create a button within the KO element, as google pay can only be instantiated through\n                // a valid on click event (ko onclick bind interferes with this).\n                var deviceData;\n                var button = document.createElement('button');\n                button.className = \"braintree-googlepay-button long \" + (context.getBtnColor() == 1 ? 'black' : 'white');\n                button.title = $t(\"Buy with Google Pay\");\n\n                // init braintree api\n                braintree.create({\n                    authorization: context.getClientToken()\n                }, function (clientErr, clientInstance) {\n                    if (clientErr) {\n                        console.error('Error creating client:', clientErr);\n                        return;\n                    }\n                    dataCollector.create({\n                        client: clientInstance\n                    }, function (dataCollectorErr, dataCollectorInstance) {\n                        if (dataCollectorErr) {\n                            return;\n                        }\n                        googlePay.create({\n                            client: clientInstance,\n                            googlePayVersion: 2\n                        }, function (googlePayErr, googlePaymentInstance) {\n                            // No instance\n                            if (googlePayErr) {\n                                console.error('Braintree GooglePay Error creating googlePayInstance:', googlePayErr);\n                                return;\n                            }\n\n                            paymentsClient.isReadyToPay({\n                                apiVersion: 2,\n                                apiVersionMinor: 0,\n                                allowedPaymentMethods: googlePaymentInstance.createPaymentDataRequest().allowedPaymentMethods\n                            }).then(function(response) {\n                                if (response.result) {\n                                    button.addEventListener('click', function (event) {\n\n                                        var agreements = checkoutAgreements().agreements,\n                                            shouldDisableActions = false;\n\n\n                                        _.each(agreements, function (item, index) {\n                                            if (checkoutAgreements().isAgreementRequired(item)) {\n                                                var inputId = '#agreement_braintree_googlepay_' + item.agreementId,\n                                                    inputEl = document.querySelector(inputId);\n\n                                                if (inputEl !== null && !inputEl.checked) {\n                                                    shouldDisableActions = true;\n                                                }\n\n                                            }\n                                        });\n\n                                        if (!additionalValidators.validate()) {\n                                            event.preventDefault();\n                                            return false;\n                                        }\n\n                                        if (!shouldDisableActions) {\n                                            event.preventDefault();\n                                            jQuery(\"body\").loader('show');\n                                            var responseData;\n\n                                            var paymentDataRequest = googlePaymentInstance.createPaymentDataRequest(context.getPaymentRequest());\n                                            paymentsClient.loadPaymentData(paymentDataRequest).then(function (paymentData) {\n                                                // Persist the paymentData (shipping address etc)\n                                                responseData = paymentData;\n                                                // Return the braintree nonce promise\n                                                return googlePaymentInstance.parseResponse(paymentData);\n                                            }).then(function (result) {\n                                                context.startPlaceOrder(result.nonce, responseData, dataCollectorInstance.deviceData);\n                                            }).catch(function (err) {\n                                                // Handle errors\n                                                // err = {statusCode: \"CANCELED\"}\n                                                console.error(err);\n                                                jQuery(\"body\").loader('hide');\n                                            });\n                                        }\n                                    });\n\n                                    element.appendChild(button);\n                                }\n                            }).catch(function (err) {\n                                console.error(err);\n                                jQuery(\"body\").loader('hide');\n                            });\n                        });\n                    });\n                });\n            }\n        };\n    }\n);\n","PayPal_Braintree/js/googlepay/api.js":"/**\n * Braintree Google Pay button api\n **/\ndefine([\n    'uiComponent',\n    'mage/translate',\n    'mage/storage',\n    'jquery',\n    'PayPal_Braintree/js/form-builder'\n], function (Component, $t, storage, jQuery, formBuilder) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            clientToken: null,\n            merchantId: null,\n            currencyCode: null,\n            actionSuccess: null,\n            amount: null,\n            cardTypes: [],\n            btnColor: 0\n        },\n\n        /**\n         * Set & get environment\n         * \"PRODUCTION\" or \"TEST\"\n         */\n        setEnvironment: function (value) {\n            this.environment = value;\n        },\n        getEnvironment: function () {\n            return this.environment;\n        },\n\n        /**\n         * Set & get api token\n         */\n        setClientToken: function (value) {\n            this.clientToken = value;\n        },\n        getClientToken: function () {\n            return this.clientToken;\n        },\n\n        /**\n         * Set and get display name\n         */\n        setMerchantId: function (value) {\n            this.merchantId = value;\n        },\n        getMerchantId: function () {\n            return this.merchantId;\n        },\n\n        /**\n         * Set and get currency code\n         */\n        setAmount: function (value) {\n            this.amount = parseFloat(value).toFixed(2);\n        },\n        getAmount: function () {\n            return this.amount;\n        },\n\n        /**\n         * Set and get currency code\n         */\n        setCurrencyCode: function (value) {\n            this.currencyCode = value;\n        },\n        getCurrencyCode: function () {\n            return this.currencyCode;\n        },\n\n        /**\n         * Set and get success redirection url\n         */\n        setActionSuccess: function (value) {\n            this.actionSuccess = value;\n        },\n        getActionSuccess: function () {\n            return this.actionSuccess;\n        },\n\n        /**\n         * Set and get success redirection url\n         */\n        setCardTypes: function (value) {\n            this.cardTypes = value;\n        },\n        getCardTypes: function () {\n            return this.cardTypes;\n        },\n\n        /**\n         * BTN Color\n         */\n        setBtnColor: function (value) {\n            this.btnColor = value;\n        },\n        getBtnColor: function () {\n            return this.btnColor;\n        },\n\n        /**\n         * Payment request info\n         */\n        getPaymentRequest: function () {\n            var result = {\n                transactionInfo: {\n                    totalPriceStatus: 'ESTIMATED',\n                    totalPrice: this.getAmount(),\n                    currencyCode: this.getCurrencyCode()\n                },\n                allowedPaymentMethods: [\n                    {\n                        \"type\": \"CARD\",\n                        \"parameters\": {\n                            \"allowedCardNetworks\": this.getCardTypes(),\n                            \"billingAddressRequired\": true,\n                            \"billingAddressParameters\": {\n                                format: 'FULL',\n                                phoneNumberRequired: true\n                            },\n                        },\n\n                    }\n                ],\n                shippingAddressRequired: true,\n                emailRequired: true,\n            };\n\n            if (this.getEnvironment() !== \"TEST\") {\n                result.merchantInfo = { merchantId: this.getMerchantId() };\n            }\n\n            return result;\n        },\n\n        /**\n         * Place the order\n         */\n        startPlaceOrder: function (nonce, paymentData, deviceData) {\n            var payload = {\n                details: {\n                    shippingAddress: {\n                        streetAddress: paymentData.shippingAddress.address1 + \"\\n\"\n                            + paymentData.shippingAddress.address2,\n                        locality: paymentData.shippingAddress.locality,\n                        postalCode: paymentData.shippingAddress.postalCode,\n                        countryCodeAlpha2: paymentData.shippingAddress.countryCode,\n                        email: paymentData.email,\n                        name: paymentData.shippingAddress.name,\n                        telephone: typeof paymentData.shippingAddress.phoneNumber !== 'undefined' ? paymentData.shippingAddress.phoneNumber : '',\n                        region: typeof paymentData.shippingAddress.administrativeArea !== 'undefined' ? paymentData.shippingAddress.administrativeArea : ''\n                    },\n                    billingAddress: {\n                        streetAddress: paymentData.paymentMethodData.info.billingAddress.address1 + \"\\n\"\n                            + paymentData.paymentMethodData.info.billingAddress.address2,\n                        locality: paymentData.paymentMethodData.info.billingAddress.locality,\n                        postalCode: paymentData.paymentMethodData.info.billingAddress.postalCode,\n                        countryCodeAlpha2: paymentData.paymentMethodData.info.billingAddress.countryCode,\n                        email: paymentData.email,\n                        name: paymentData.paymentMethodData.info.billingAddress.name,\n                        telephone: typeof paymentData.paymentMethodData.info.billingAddress.phoneNumber !== 'undefined' ? paymentData.paymentMethodData.info.billingAddress.phoneNumber : '',\n                        region: typeof paymentData.paymentMethodData.info.billingAddress.administrativeArea !== 'undefined' ? paymentData.paymentMethodData.info.billingAddress.administrativeArea : ''\n                    }\n                },\n                nonce: nonce,\n                deviceData: deviceData,\n            };\n\n            formBuilder.build({\n                action: this.getActionSuccess(),\n                fields: {\n                    result: JSON.stringify(payload)\n                }\n            }).submit();\n        }\n    });\n});\n","PayPal_Braintree/js/googlepay/implementations/shortcut.js":"/**\n * Braintree Google Pay mini cart payment method integration.\n **/\ndefine(\n    [\n        'uiComponent',\n        'PayPal_Braintree/js/googlepay/button',\n        'PayPal_Braintree/js/googlepay/api',\n        'mage/translate',\n        'domReady!'\n    ],\n    function (\n        Component,\n        button,\n        buttonApi,\n        $t\n    ) {\n        'use strict';\n\n        return Component.extend({\n\n            defaults: {\n                id: null,\n                clientToken: null,\n                merchantId: null,\n                currencyCode: null,\n                actionSuccess: null,\n                amount: null,\n                environment: \"TEST\",\n                cardType: [],\n                btnColor: 0\n            },\n\n            /**\n             * @returns {Object}\n             */\n            initialize: function () {\n                this._super();\n\n                var api = new buttonApi();\n                api.setEnvironment(this.environment);\n                api.setCurrencyCode(this.currencyCode);\n                api.setClientToken(this.clientToken);\n                api.setMerchantId(this.merchantId);\n                api.setActionSuccess(this.actionSuccess);\n                api.setAmount(this.amount);\n                api.setCardTypes(this.cardTypes)\n                api.setBtnColor(this.btnColor);\n\n                // Attach the button\n                button.init(\n                    document.getElementById(this.id),\n                    api\n                );\n\n                return this;\n            }\n        });\n    }\n);\n","PayPal_Braintree/js/googlepay/implementations/core-checkout/method-googlepay.js":"define([\n    'uiComponent',\n    'Magento_Checkout/js/model/payment/renderer-list'\n], function (Component, rendererList) {\n    'use strict';\n\n    let config = window.checkoutConfig.payment;\n\n    if (config['braintree_googlepay'].clientToken) {\n        rendererList.push({\n            type: 'braintree_googlepay',\n            component: 'PayPal_Braintree/js/googlepay/implementations/core-checkout/method-renderer/googlepay'\n        });\n    }\n\n    return Component.extend({});\n});\n","PayPal_Braintree/js/googlepay/implementations/core-checkout/method-renderer/googlepay.js":"/**\n * Braintree Google Pay payment method integration.\n **/\ndefine([\n    'Magento_Checkout/js/view/payment/default',\n    'Magento_Checkout/js/model/quote',\n    'PayPal_Braintree/js/googlepay/button'\n], function (\n    Component,\n    quote,\n    button\n) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'PayPal_Braintree/googlepay/core-checkout',\n            paymentMethodNonce: null,\n            deviceData: null,\n            grandTotalAmount: 0\n        },\n\n        /**\n         * Inject the google pay button into the target element\n         */\n        getGooglePayBtn: function (id) {\n            button.init(\n                document.getElementById(id),\n                this\n            );\n        },\n\n        /**\n         * Subscribe to grand totals\n         */\n        initObservable: function () {\n            this._super();\n            this.grandTotalAmount = parseFloat(quote.totals()['base_grand_total']).toFixed(2);\n            this.currencyCode = quote.totals()['base_currency_code'];\n\n            quote.totals.subscribe(function () {\n                if (this.grandTotalAmount !== quote.totals()['base_grand_total']) {\n                    this.grandTotalAmount = parseFloat(quote.totals()['base_grand_total']).toFixed(2);\n                }\n            }.bind(this));\n\n            return this;\n        },\n\n        /**\n         * Google pay place order method\n         */\n        startPlaceOrder: function (nonce, paymentData, device_data) {\n            this.setPaymentMethodNonce(nonce);\n            this.setDeviceData(device_data);\n            this.placeOrder();\n        },\n\n        /**\n         * Save nonce\n         */\n        setPaymentMethodNonce: function (nonce) {\n            this.paymentMethodNonce = nonce;\n        },\n\n        /**\n         * Save device_data\n         */\n        setDeviceData: function (device_data) {\n            this.deviceData = device_data;\n        },\n\n        /**\n         * Retrieve the client token\n         * @returns null|string\n         */\n        getClientToken: function () {\n            return window.checkoutConfig.payment[this.getCode()].clientToken;\n        },\n\n        /**\n         * Payment request info\n         */\n        getPaymentRequest: function () {\n           var result = {\n               transactionInfo: {\n                   totalPriceStatus: 'FINAL',\n                   totalPrice: this.grandTotalAmount,\n                   currencyCode: this.currencyCode\n               },\n               allowedPaymentMethods: [\n                   {\n                       \"type\": \"CARD\",\n                       \"parameters\": {\n                           \"allowedCardNetworks\": this.getCardTypes(),\n                           \"billingAddressRequired\": false,\n                       },\n\n                   }\n               ],\n               shippingAddressRequired: false,\n               emailRequired: false,\n            };\n\n            if (this.getEnvironment() !== \"TEST\") {\n                result.merchantInfo = { merchantId: this.getMerchantId() };\n            }\n\n           return result;\n        },\n\n        /**\n         * Merchant display name\n         */\n        getMerchantId: function () {\n            return window.checkoutConfig.payment[this.getCode()].merchantId;\n        },\n\n        /**\n         * Environment\n         */\n        getEnvironment: function () {\n            return window.checkoutConfig.payment[this.getCode()].environment;\n        },\n\n        /**\n         * Card Types\n         */\n        getCardTypes: function () {\n            return window.checkoutConfig.payment[this.getCode()].cardTypes;\n        },\n\n        /**\n         * BTN Color\n         */\n        getBtnColor: function () {\n            return window.checkoutConfig.payment[this.getCode()].btnColor;\n        },\n\n        /**\n         * Get data\n         * @returns {Object}\n         */\n        getData: function () {\n            return {\n                'method': this.getCode(),\n                'additional_data': {\n                    'payment_method_nonce': this.paymentMethodNonce,\n                    'device_data': this.deviceData\n                }\n            };\n        },\n\n        /**\n         * Return image url for the google pay mark\n         */\n        getPaymentMarkSrc: function () {\n            return window.checkoutConfig.payment[this.getCode()].paymentMarkSrc;\n        }\n    });\n});\n","PayPal_Braintree/js/applepay/button.js":"/**\n * Braintree Apple Pay button\n **/\ndefine(\n    [\n        'uiComponent',\n        \"knockout\",\n        \"jquery\",\n        'braintree',\n        'braintreeDataCollector',\n        'braintreeApplePay',\n        'mage/translate',\n        'Magento_Checkout/js/model/payment/additional-validators',\n        ],\n    function (\n        Component,\n        ko,\n        jQuery,\n        braintree,\n        dataCollector,\n        applePay,\n        $t,\n        additionalValidators\n    ) {\n        'use strict';\n\n        var that;\n\n        return {\n            init: function (element, context) {\n                // No element or context\n                if (!element || !context) {\n                    return;\n                }\n\n                // Context must implement these methods\n                if (typeof context.getClientToken !== 'function') {\n                    console.error(\"Braintree ApplePay Context passed does not provide a getClientToken method\", context);\n                    return;\n                }\n                if (typeof context.getPaymentRequest !== 'function') {\n                    console.error(\"Braintree ApplePay Context passed does not provide a getPaymentRequest method\", context);\n                    return;\n                }\n                if (typeof context.startPlaceOrder !== 'function') {\n                    console.error(\"Braintree ApplePay Context passed does not provide a startPlaceOrder method\", context);\n                    return;\n                }\n\n                if (this.deviceSupported() === false) {\n                    return;\n                }\n\n                // init braintree api\n                braintree.create({\n                    authorization: context.getClientToken()\n                }, function (clientErr, clientInstance) {\n                    if (clientErr) {\n                        console.error('Error creating client:', clientErr);\n                        return;\n                    }\n\n                        dataCollector.create({\n                            client: clientInstance\n                        }, function (dataCollectorErr, dataCollectorInstance) {\n                            if (dataCollectorErr) {\n                                return;\n                            }\n\n                            applePay.create({\n                                client: clientInstance\n                            }, function (applePayErr, applePayInstance) {\n                                // No instance\n                                if (applePayErr) {\n                                    console.error('Braintree ApplePay Error creating applePayInstance:', applePayErr);\n                                    return;\n                                }\n\n                                // Create a button within the KO element, as apple pay can only be instantiated through\n                                // a valid on click event (ko onclick bind interferes with this).\n                                var el = document.createElement('div');\n                                el.className = \"braintree-apple-pay-button\";\n                                el.title = $t(\"Pay with Apple Pay\");\n                                el.alt = $t(\"Pay with Apple Pay\");\n                                el.addEventListener('click', function (e) {\n                                    e.preventDefault();\n\n                                    if (!additionalValidators.validate()) {\n                                        return false;\n                                    }\n                                    // Payment request object\n                                    var paymentRequest = applePayInstance.createPaymentRequest(context.getPaymentRequest());\n                                    if (!paymentRequest) {\n                                        alert($t(\"We're unable to take payments through Apple Pay at the moment. Please try an alternative payment method.\"));\n                                        console.error('Braintree ApplePay Unable to create paymentRequest', paymentRequest);\n                                        return;\n                                    }\n\n                                    // Show the loader\n                                    jQuery(\"body\").loader('show');\n\n                                    // Init apple pay session\n                                    try {\n                                        var session = new ApplePaySession(1, paymentRequest);\n                                    } catch (err) {\n                                        jQuery(\"body\").loader('hide');\n                                        console.error('Braintree ApplePay Unable to create ApplePaySession', err);\n                                        alert($t(\"We're unable to take payments through Apple Pay at the moment. Please try an alternative payment method.\"));\n                                        return false;\n                                    }\n\n                                    // Handle invalid merchant\n                                    session.onvalidatemerchant = function (event) {\n                                        applePayInstance.performValidation({\n                                            validationURL: event.validationURL,\n                                            displayName: context.getDisplayName()\n                                        }, function (validationErr, merchantSession) {\n                                            if (validationErr) {\n                                                session.abort();\n                                                console.error('Braintree ApplePay Error validating merchant:', validationErr);\n                                                alert($t(\"We're unable to take payments through Apple Pay at the moment. Please try an alternative payment method.\"));\n                                                return;\n                                            }\n\n                                            session.completeMerchantValidation(merchantSession);\n                                        });\n                                    };\n\n                                    // Attach payment auth event\n                                    session.onpaymentauthorized = function (event) {\n                                        applePayInstance.tokenize({\n                                            token: event.payment.token\n                                        }, function (tokenizeErr, payload) {\n                                            if (tokenizeErr) {\n                                                console.error('Error tokenizing Apple Pay:', tokenizeErr);\n                                                session.completePayment(ApplePaySession.STATUS_FAILURE);\n                                                return;\n                                            }\n\n                                            // Pass the nonce back to the payment method\n                                            context.startPlaceOrder(payload.nonce, event, session, dataCollectorInstance.deviceData);\n                                        });\n                                    };\n\n                                    // Attach onShippingContactSelect method\n                                    if (typeof context.onShippingContactSelect === 'function') {\n                                        session.onshippingcontactselected = function (event) {\n                                            return context.onShippingContactSelect(event, session);\n                                        };\n                                    }\n\n                                    // Attach onShippingMethodSelect method\n                                    if (typeof context.onShippingMethodSelect === 'function') {\n                                        session.onshippingmethodselected = function (event) {\n                                            return context.onShippingMethodSelect(event, session);\n                                        };\n                                    }\n\n                                    // Hook\n                                    if (typeof context.onButtonClick === 'function') {\n                                        context.onButtonClick(session, this, e);\n                                    } else {\n                                        jQuery(\"body\").loader('hide');\n                                        session.begin();\n                                    }\n                                });\n                                element.appendChild(el);\n                            });\n                        });\n\n                });\n            },\n\n            /**\n             * Check the site is using HTTPS & apple pay is supported on this device.\n             * @return boolean\n             */\n            deviceSupported: function () {\n                if (location.protocol != 'https:') {\n                    console.warn(\"Braintree Apple Pay requires your checkout be served over HTTPS\");\n                    return false;\n                }\n\n                if ((window.ApplePaySession && ApplePaySession.canMakePayments()) !== true) {\n                    console.warn(\"Braintree Apple Pay is not supported on this device/browser\");\n                    return false;\n                }\n\n                return true;\n            }\n        };\n    }\n);\n","PayPal_Braintree/js/applepay/api.js":"/**\n * Braintree Apple Pay button API\n *\n **/\ndefine(\n    [\n        'jquery',\n        'underscore',\n        'uiComponent',\n        'mage/translate',\n        'mage/storage',\n        'Magento_Customer/js/customer-data'\n    ],\n    function (\n        $,\n        _,\n        Component,\n        $t,\n        storage,\n        customerData\n    ) {\n        'use strict';\n\n        return Component.extend({\n            defaults: {\n                clientToken: null,\n                quoteId: 0,\n                displayName: null,\n                actionSuccess: null,\n                grandTotalAmount: 0,\n                isLoggedIn: false,\n                storeCode: \"default\",\n                shippingAddress: {},\n                countryDirectory: null,\n                shippingMethods: {}\n            },\n\n            initialize: function () {\n                this._super();\n                if (!this.countryDirectory) {\n                    storage.get(\"rest/V1/directory/countries\").done(function (result) {\n                        this.countryDirectory = {};\n                        let i, data, x, region;\n                        for (i = 0; i < result.length; ++i) {\n                            data = result[i];\n                            this.countryDirectory[data.two_letter_abbreviation] = {};\n                            if (typeof data.available_regions !== 'undefined') {\n                                for (x = 0; x < data.available_regions.length; ++x) {\n                                    region = data.available_regions[x];\n                                    this.countryDirectory[data.two_letter_abbreviation][region.name.toLowerCase().replace(/[^A-Z0-9]/ig, '')] = region.id;\n                                }\n                            }\n                        }\n                    }.bind(this));\n                }\n            },\n\n            /**\n             * Get region ID\n             */\n            getRegionId: function (countryCode, regionName) {\n                if (typeof regionName !== 'string') {\n                    return null;\n                }\n\n                regionName = regionName.toLowerCase().replace(/[^A-Z0-9]/ig, '');\n\n                if (typeof this.countryDirectory[countryCode] !== 'undefined' && typeof this.countryDirectory[countryCode][regionName] !== 'undefined') {\n                    return this.countryDirectory[countryCode][regionName];\n                }\n\n                return 0;\n            },\n\n            /**\n             * Set & get api token\n             */\n            setClientToken: function (value) {\n                this.clientToken = value;\n            },\n            getClientToken: function () {\n                return this.clientToken;\n            },\n\n            /**\n             * Set and get quote id\n             */\n            setQuoteId: function (value) {\n                this.quoteId = value;\n            },\n            getQuoteId: function () {\n                return this.quoteId;\n            },\n\n            /**\n             * Set and get display name\n             */\n            setDisplayName: function (value) {\n                this.displayName = value;\n            },\n            getDisplayName: function () {\n                return this.displayName;\n            },\n\n            /**\n             * Set and get success redirection url\n             */\n            setActionSuccess: function (value) {\n                this.actionSuccess = value;\n            },\n            getActionSuccess: function () {\n                return this.actionSuccess;\n            },\n\n            /**\n             * Set and get grand total\n             */\n            setGrandTotalAmount: function (value) {\n                this.grandTotalAmount = parseFloat(value).toFixed(2);\n            },\n            getGrandTotalAmount: function () {\n                return parseFloat(this.grandTotalAmount);\n            },\n\n            /**\n             * Set and get is logged in\n             */\n            setIsLoggedIn: function (value) {\n                this.isLoggedIn = value;\n            },\n            getIsLoggedIn: function () {\n                return this.isLoggedIn;\n            },\n\n            /**\n             * Set and get store code\n             */\n            setStoreCode: function (value) {\n                this.storeCode = value;\n            },\n            getStoreCode: function () {\n                return this.storeCode;\n            },\n\n            /**\n             * API Urls for logged in / guest\n             */\n            getApiUrl: function (uri) {\n                if (this.getIsLoggedIn() === true) {\n                    return \"rest/\" + this.getStoreCode() + \"/V1/carts/mine/\" + uri;\n                } else {\n                    return \"rest/\" + this.getStoreCode() + \"/V1/guest-carts/\" + this.getQuoteId() + \"/\" + uri;\n                }\n            },\n\n            /**\n             * Payment request info\n             */\n            getPaymentRequest: function () {\n                return {\n                    total: {\n                        label: this.getDisplayName(),\n                        amount: this.getGrandTotalAmount()\n                    },\n                    requiredShippingContactFields: ['postalAddress', 'name', 'email', 'phone'],\n                    requiredBillingContactFields: ['postalAddress', 'name']\n                };\n            },\n\n            /**\n             * Retrieve shipping methods based on address\n             */\n            onShippingContactSelect: function (event, session) {\n                // Get the address.\n                let address = event.shippingContact;\n\n                // Create a payload.\n                let payload = {\n                    address: {\n                        city: address.locality,\n                        region: address.administrativeArea,\n                        country_id: address.countryCode.toUpperCase(),\n                        postcode: address.postalCode,\n                        save_in_address_book: 0\n                    }\n                };\n\n                this.shippingAddress = payload.address;\n\n                // POST to endpoint for shipping methods.\n                storage.post(\n                    this.getApiUrl(\"estimate-shipping-methods\"),\n                    JSON.stringify(payload)\n                ).done(function (result) {\n                    // Stop if no shipping methods.\n                    let virtualFlag = false;\n                    if (result.length === 0) {\n                        let productItems = customerData.get('cart')().items;\n                        _.each(productItems,\n                            function (item) {\n                                if (item.is_virtual || item.product_type == 'bundle') {\n                                    virtualFlag = true;\n                                } else {\n                                    virtualFlag = false;\n                                }\n                            }\n                        );\n                        if (!virtualFlag) {\n                            session.abort();\n                            alert($t(\"There are no shipping methods available for you right now. Please try again or use an alternative payment method.\"));\n                            return false;\n                        }\n                    }\n\n                    let shippingMethods = [];\n                    this.shippingMethods = {};\n\n                    // Format shipping methods array.\n                    for (let i = 0; i < result.length; i++) {\n                        if (typeof result[i].method_code !== 'string') {\n                            continue;\n                        }\n\n                        let method = {\n                            identifier: result[i].method_code,\n                            label: result[i].method_title,\n                            detail: result[i].carrier_title ? result[i].carrier_title : \"\",\n                            amount: parseFloat(result[i].amount).toFixed(2)\n                        };\n\n                        // Add method object to array.\n                        shippingMethods.push(method);\n\n                        this.shippingMethods[result[i].method_code] = result[i];\n\n                        if (!this.shippingMethod) {\n                            this.shippingMethod = result[i].method_code;\n                        }\n                    }\n\n                    // Create payload to get totals\n                    let totalsPayload = {\n                        \"addressInformation\": {\n                            \"address\": {\n                                \"countryId\": this.shippingAddress.country_id,\n                                \"region\": this.shippingAddress.region,\n                                \"regionId\": this.getRegionId(this.shippingAddress.country_id, this.shippingAddress.region),\n                                \"postcode\": this.shippingAddress.postcode\n                            },\n                            \"shipping_method_code\": virtualFlag ? null : this.shippingMethods[shippingMethods[0].identifier].method_code,\n                            \"shipping_carrier_code\": virtualFlag ? null : this.shippingMethods[shippingMethods[0].identifier].carrier_code\n                        }\n                    };\n\n                    // POST to endpoint to get totals, using 1st shipping method\n                    storage.post(\n                        this.getApiUrl(\"totals-information\"),\n                        JSON.stringify(totalsPayload)\n                    ).done(function (result) {\n                        // Set total\n                        this.setGrandTotalAmount(result.base_grand_total);\n\n                        // Pass shipping methods back\n                        session.completeShippingContactSelection(\n                            ApplePaySession.STATUS_SUCCESS,\n                            shippingMethods,\n                            {\n                                label: this.getDisplayName(),\n                                amount: this.getGrandTotalAmount()\n                            },\n                            [{\n                                type: 'final',\n                                label: $t('Shipping'),\n                                amount: virtualFlag ? 0 : shippingMethods[0].amount\n                            }]\n                        );\n                    }.bind(this)).fail(function (result) {\n                        session.abort();\n                        alert($t(\"We're unable to fetch the cart totals for you. Please try an alternative payment method.\"));\n                        console.error(\"Braintree ApplePay: Unable to get totals\", result);\n                        return false;\n                    });\n\n                }.bind(this)).fail(function (result) {\n                    session.abort();\n                    alert($t(\"We're unable to find any shipping methods for you. Please try an alternative payment method.\"));\n                    console.error(\"Braintree ApplePay: Unable to find shipping methods for estimate-shipping-methods\", result);\n                    return false;\n                });\n            },\n\n            /**\n             * Record which shipping method has been selected & Updated totals\n             */\n            onShippingMethodSelect: function (event, session) {\n                let shippingMethod = event.shippingMethod;\n                this.shippingMethod = shippingMethod.identifier;\n\n                let payload = {\n                    \"addressInformation\": {\n                        \"address\": {\n                            \"countryId\": this.shippingAddress.country_id,\n                            \"region\": this.shippingAddress.region,\n                            \"regionId\": this.getRegionId(this.shippingAddress.country_id, this.shippingAddress.region),\n                            \"postcode\": this.shippingAddress.postcode\n                        },\n                        \"shipping_method_code\": this.shippingMethods[this.shippingMethod].method_code,\n                        \"shipping_carrier_code\": this.shippingMethods[this.shippingMethod].carrier_code\n                    }\n                };\n\n                storage.post(\n                    this.getApiUrl(\"totals-information\"),\n                    JSON.stringify(payload)\n                ).done(function (r) {\n                    this.setGrandTotalAmount(r.base_grand_total);\n\n                    session.completeShippingMethodSelection(\n                        ApplePaySession.STATUS_SUCCESS,\n                        {\n                            label: this.getDisplayName(),\n                            amount: this.getGrandTotalAmount()\n                        },\n                        [{\n                            type: 'final',\n                            label: $t('Shipping'),\n                            amount: shippingMethod.amount\n                        }]\n                    );\n                }.bind(this));\n            },\n\n            /**\n             * Place the order\n             */\n            startPlaceOrder: function (nonce, event, session, device_data) {\n                let shippingContact = event.payment.shippingContact,\n                    billingContact = event.payment.billingContact,\n                    payload = {\n                        \"addressInformation\": {\n                            \"shipping_address\": {\n                                \"email\": shippingContact.emailAddress,\n                                \"telephone\": shippingContact.phoneNumber,\n                                \"firstname\": shippingContact.givenName,\n                                \"lastname\": shippingContact.familyName,\n                                \"street\": shippingContact.addressLines,\n                                \"city\": shippingContact.locality,\n                                \"region\": shippingContact.administrativeArea,\n                                \"region_id\": this.getRegionId(shippingContact.countryCode.toUpperCase(), shippingContact.administrativeArea),\n                                \"region_code\": null,\n                                \"country_id\": shippingContact.countryCode.toUpperCase(),\n                                \"postcode\": shippingContact.postalCode,\n                                \"same_as_billing\": 0,\n                                \"customer_address_id\": 0,\n                                \"save_in_address_book\": 0\n                            },\n                            \"billing_address\": {\n                                \"email\": shippingContact.emailAddress,\n                                \"telephone\": shippingContact.phoneNumber,\n                                \"firstname\": billingContact.givenName,\n                                \"lastname\": billingContact.familyName,\n                                \"street\": billingContact.addressLines,\n                                \"city\": billingContact.locality,\n                                \"region\": billingContact.administrativeArea,\n                                \"region_id\": this.getRegionId(billingContact.countryCode.toUpperCase(), billingContact.administrativeArea),\n                                \"region_code\": null,\n                                \"country_id\": billingContact.countryCode.toUpperCase(),\n                                \"postcode\": billingContact.postalCode,\n                                \"same_as_billing\": 0,\n                                \"customer_address_id\": 0,\n                                \"save_in_address_book\": 0\n                            },\n                            \"shipping_method_code\": this.shippingMethod ? this.shippingMethods[this.shippingMethod].method_code : '' ,\n                            \"shipping_carrier_code\": this.shippingMethod ? this.shippingMethods[this.shippingMethod].carrier_code : ''\n                        }\n                    };\n\n                // Set addresses\n                storage.post(\n                    this.getApiUrl(\"shipping-information\"),\n                    JSON.stringify(payload)\n                ).done(function () {\n                    // Submit payment information\n                    let paymentInformation = {\n                            \"email\": shippingContact.emailAddress,\n                            \"paymentMethod\": {\n                                \"method\": \"braintree_applepay\",\n                                \"additional_data\": {\n                                    \"payment_method_nonce\": nonce,\n                                    \"device_data\": device_data\n                                }\n                            }\n                        };\n                    if (window.checkout && window.checkout.agreementIds) {\n                        paymentInformation.paymentMethod.extension_attributes = {\n                            \"agreement_ids\": window.checkout.agreementIds\n                        };\n                    }\n                    storage.post(\n                        this.getApiUrl(\"payment-information\"),\n                        JSON.stringify(paymentInformation)\n                    ).done(function (r) {\n                        document.location = this.getActionSuccess();\n                        session.completePayment(ApplePaySession.STATUS_SUCCESS);\n                    }.bind(this)).fail(function (r) {\n                        session.completePayment(ApplePaySession.STATUS_FAILURE);\n                        session.abort();\n                        alert($t(\"We're unable to take your payment through Apple Pay. Please try an again or use an alternative payment method.\"));\n                        console.error(\"Braintree ApplePay Unable to take payment\", r);\n                        return false;\n                    });\n\n                }.bind(this)).fail(function (r) {\n                    console.error(\"Braintree ApplePay Unable to set shipping information\", r);\n                    session.completePayment(ApplePaySession.STATUS_INVALID_BILLING_POSTAL_ADDRESS);\n                });\n            }\n        });\n    });\n","PayPal_Braintree/js/applepay/implementations/shortcut.js":"/**\n * Braintree Apple Pay mini cart payment method integration.\n **/\ndefine(\n    [\n        'uiComponent',\n        'PayPal_Braintree/js/applepay/button',\n        'PayPal_Braintree/js/applepay/api',\n        'mage/translate',\n        'domReady!'\n    ],\n    function (\n        Component,\n        button,\n        buttonApi,\n        $t\n    ) {\n        'use strict';\n\n        return Component.extend({\n\n            defaults: {\n                id: null,\n                clientToken: null,\n                quoteId: 0,\n                displayName: null,\n                actionSuccess: null,\n                grandTotalAmount: 0,\n                isLoggedIn: false,\n                storeCode: \"default\"\n            },\n\n            /**\n             * @returns {Object}\n             */\n            initialize: function () {\n                this._super();\n                if (!this.displayName) {\n                    this.displayName = $t('Store');\n                }\n\n                var api = new buttonApi();\n                api.setGrandTotalAmount(parseFloat(this.grandTotalAmount).toFixed(2));\n                api.setClientToken(this.clientToken);\n                api.setDisplayName(this.displayName);\n                api.setQuoteId(this.quoteId);\n                api.setActionSuccess(this.actionSuccess);\n                api.setIsLoggedIn(this.isLoggedIn);\n                api.setStoreCode(this.storeCode);\n\n                // Attach the button\n                button.init(\n                    document.getElementById(this.id),\n                    api\n                );\n\n                return this;\n            }\n        });\n    }\n);\n","PayPal_Braintree/js/applepay/implementations/core-checkout/method-applepay.js":"define([\n    'uiComponent',\n    'Magento_Checkout/js/model/payment/renderer-list'\n], function (Component, rendererList) {\n    'use strict';\n\n    let config = window.checkoutConfig.payment;\n\n    if (config['braintree_applepay'].clientToken) {\n        rendererList.push({\n            type: 'braintree_applepay',\n            component: 'PayPal_Braintree/js/applepay/implementations/core-checkout/method-renderer/applepay'\n        });\n    }\n\n    return Component.extend({});\n});\n","PayPal_Braintree/js/applepay/implementations/core-checkout/method-renderer/applepay.js":"/**\n * Braintree Apple Pay payment method integration.\n **/\ndefine([\n    'Magento_Checkout/js/view/payment/default',\n    'Magento_Checkout/js/model/quote',\n    'PayPal_Braintree/js/applepay/button'\n], function (\n    Component,\n    quote,\n    button\n) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'PayPal_Braintree/applepay/core-checkout',\n            paymentMethodNonce: null,\n            deviceData: null,\n            grandTotalAmount: 0,\n            deviceSupported: button.deviceSupported()\n        },\n\n        /**\n         * Inject the apple pay button into the target element\n         */\n        getApplePayBtn: function (id) {\n            button.init(\n                document.getElementById(id),\n                this\n            );\n        },\n\n        /**\n         * Subscribe to grand totals\n         */\n        initObservable: function () {\n            this._super();\n            this.grandTotalAmount = parseFloat(quote.totals()['base_grand_total']).toFixed(2);\n\n            quote.totals.subscribe(function () {\n                if (this.grandTotalAmount !== quote.totals()['base_grand_total']) {\n                    this.grandTotalAmount = parseFloat(quote.totals()['base_grand_total']).toFixed(2);\n                }\n            }.bind(this));\n\n            return this;\n        },\n\n        /**\n         * Apple pay place order method\n         */\n        startPlaceOrder: function (nonce, event, session, device_data) {\n            this.setPaymentMethodNonce(nonce);\n            this.setDeviceData(device_data);\n            this.placeOrder();\n\n            session.completePayment(ApplePaySession.STATUS_SUCCESS);\n        },\n\n        /**\n         * Save nonce\n         */\n        setPaymentMethodNonce: function (nonce) {\n            this.paymentMethodNonce = nonce;\n        },\n\n        /**\n         * Save nonce\n         */\n        setDeviceData: function (device_data) {\n            this.deviceData = device_data;\n        },\n\n        /**\n         * Retrieve the client token\n         * @returns null|string\n         */\n        getClientToken: function () {\n            return window.checkoutConfig.payment[this.getCode()].clientToken;\n        },\n\n        /**\n         * Payment request data\n         */\n        getPaymentRequest: function () {\n            return {\n                total: {\n                    label: this.getDisplayName(),\n                    amount: this.grandTotalAmount\n                }\n            };\n        },\n\n        /**\n         * Merchant display name\n         */\n        getDisplayName: function () {\n            return window.checkoutConfig.payment[this.getCode()].merchantName;\n        },\n\n        /**\n         * Get data\n         * @returns {Object}\n         */\n        getData: function () {\n            var data = {\n                'method': this.getCode(),\n                'additional_data': {\n                    'payment_method_nonce': this.paymentMethodNonce,\n                    'device_data': this.deviceData\n                }\n            };\n            return data;\n        },\n\n        /**\n         * Return image url for the apple pay mark\n         */\n        getPaymentMarkSrc: function () {\n            return window.checkoutConfig.payment[this.getCode()].paymentMarkSrc;\n        }\n    });\n});\n","PayPal_Braintree/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-braintree')) {\n                //ReCaptcha is present for checkout\n                recaptchaDeferred = $.Deferred();\n                recaptchaRegistry.addListener('recaptcha-checkout-braintree', 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-braintree']();\n                //remove listener so that place order action is only triggered by the 'Place Order' button\n                recaptchaRegistry.removeListener('recaptcha-checkout-braintree');\n                return recaptchaDeferred;\n            }\n\n            //No ReCaptcha, just sending the request\n            return originalAction(serviceUrl, payload, messageContainer);\n        });\n    };\n});\n","PayPal_Braintree/js/model/step-navigator-mixin.js":"define([\n    'mage/utils/wrapper',\n    'jquery'\n], function (wrapper, $) {\n    'use strict';\n\n    let mixin = {\n        handleHash: function (originalFn) {\n            var hashString = window.location.hash.replace('#', '');\n            if (hashString.indexOf('venmo') > -1) {\n                return false;\n            }\n\n            return originalFn();\n        }\n    };\n\n    return function (target) {\n        return wrapper.extend(target, mixin);\n    };\n});\n","PayPal_Braintree/js/reCaptcha/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","fotorama/fotorama.js":"/*!\n * Fotorama 4.6.4 | http://fotorama.io/license/\n */\nfotoramaVersion = '4.6.4';\n(function (window, document, location, $, undefined) {\n    \"use strict\";\n    var _fotoramaClass = 'fotorama',\n        _fullscreenClass = 'fotorama__fullscreen',\n\n        wrapClass = _fotoramaClass + '__wrap',\n        wrapCss2Class = wrapClass + '--css2',\n        wrapCss3Class = wrapClass + '--css3',\n        wrapVideoClass = wrapClass + '--video',\n        wrapFadeClass = wrapClass + '--fade',\n        wrapSlideClass = wrapClass + '--slide',\n        wrapNoControlsClass = wrapClass + '--no-controls',\n        wrapNoShadowsClass = wrapClass + '--no-shadows',\n        wrapPanYClass = wrapClass + '--pan-y',\n        wrapRtlClass = wrapClass + '--rtl',\n        wrapOnlyActiveClass = wrapClass + '--only-active',\n        wrapNoCaptionsClass = wrapClass + '--no-captions',\n        wrapToggleArrowsClass = wrapClass + '--toggle-arrows',\n\n        stageClass = _fotoramaClass + '__stage',\n        stageFrameClass = stageClass + '__frame',\n        stageFrameVideoClass = stageFrameClass + '--video',\n        stageShaftClass = stageClass + '__shaft',\n\n        grabClass = _fotoramaClass + '__grab',\n        pointerClass = _fotoramaClass + '__pointer',\n\n        arrClass = _fotoramaClass + '__arr',\n        arrDisabledClass = arrClass + '--disabled',\n        arrPrevClass = arrClass + '--prev',\n        arrNextClass = arrClass + '--next',\n\n        navClass = _fotoramaClass + '__nav',\n        navWrapClass = navClass + '-wrap',\n        navShaftClass = navClass + '__shaft',\n        navShaftVerticalClass = navWrapClass + '--vertical',\n        navShaftListClass = navWrapClass + '--list',\n        navShafthorizontalClass = navWrapClass + '--horizontal',\n        navDotsClass = navClass + '--dots',\n        navThumbsClass = navClass + '--thumbs',\n        navFrameClass = navClass + '__frame',\n\n        fadeClass = _fotoramaClass + '__fade',\n        fadeFrontClass = fadeClass + '-front',\n        fadeRearClass = fadeClass + '-rear',\n\n        shadowClass = _fotoramaClass + '__shadow',\n        shadowsClass = shadowClass + 's',\n        shadowsLeftClass = shadowsClass + '--left',\n        shadowsRightClass = shadowsClass + '--right',\n        shadowsTopClass = shadowsClass + '--top',\n        shadowsBottomClass = shadowsClass + '--bottom',\n\n        activeClass = _fotoramaClass + '__active',\n        selectClass = _fotoramaClass + '__select',\n\n        hiddenClass = _fotoramaClass + '--hidden',\n\n        fullscreenClass = _fotoramaClass + '--fullscreen',\n        fullscreenIconClass = _fotoramaClass + '__fullscreen-icon',\n\n        errorClass = _fotoramaClass + '__error',\n        loadingClass = _fotoramaClass + '__loading',\n        loadedClass = _fotoramaClass + '__loaded',\n        loadedFullClass = loadedClass + '--full',\n        loadedImgClass = loadedClass + '--img',\n\n        grabbingClass = _fotoramaClass + '__grabbing',\n\n        imgClass = _fotoramaClass + '__img',\n        imgFullClass = imgClass + '--full',\n\n        thumbClass = _fotoramaClass + '__thumb',\n        thumbArrLeft = thumbClass + '__arr--left',\n        thumbArrRight = thumbClass + '__arr--right',\n        thumbBorderClass = thumbClass + '-border',\n\n        htmlClass = _fotoramaClass + '__html',\n\n        videoContainerClass = _fotoramaClass + '-video-container',\n        videoClass = _fotoramaClass + '__video',\n        videoPlayClass = videoClass + '-play',\n        videoCloseClass = videoClass + '-close',\n\n\n        horizontalImageClass = _fotoramaClass + '_horizontal_ratio',\n        verticalImageClass = _fotoramaClass + '_vertical_ratio',\n        fotoramaSpinnerClass = _fotoramaClass + '__spinner',\n        spinnerShowClass = fotoramaSpinnerClass + '--show';\n    var JQUERY_VERSION = $ && $.fn.jquery.split('.');\n\n    if (!JQUERY_VERSION\n        || JQUERY_VERSION[0] < 1\n        || (JQUERY_VERSION[0] == 1 && JQUERY_VERSION[1] < 8)) {\n        throw 'Fotorama requires jQuery 1.8 or later and will not run without it.';\n    }\n\n    var _ = {};\n    /* Modernizr 2.8.3 (Custom Build) | MIT & BSD\n     * Build: http://modernizr.com/download/#-csstransforms3d-csstransitions-touch-prefixed\n     */\n\n    var Modernizr = (function (window, document, undefined) {\n        var version = '2.8.3',\n            Modernizr = {},\n\n\n            docElement = document.documentElement,\n\n            mod = 'modernizr',\n            modElem = document.createElement(mod),\n            mStyle = modElem.style,\n            inputElem,\n\n\n            toString = {}.toString,\n\n            prefixes = ' -webkit- -moz- -o- -ms- '.split(' '),\n\n\n            omPrefixes = 'Webkit Moz O ms',\n\n            cssomPrefixes = omPrefixes.split(' '),\n\n            domPrefixes = omPrefixes.toLowerCase().split(' '),\n\n\n            tests = {},\n            inputs = {},\n            attrs = {},\n\n            classes = [],\n\n            slice = classes.slice,\n\n            featureName,\n\n\n            injectElementWithStyles = function (rule, callback, nodes, testnames) {\n\n                var style, ret, node, docOverflow,\n                    div = document.createElement('div'),\n                    body = document.body,\n                    fakeBody = body || document.createElement('body');\n\n                if (parseInt(nodes, 10)) {\n                    while (nodes--) {\n                        node = document.createElement('div');\n                        node.id = testnames ? testnames[nodes] : mod + (nodes + 1);\n                        div.appendChild(node);\n                    }\n                }\n\n                style = ['&#173;', '<style id=\"s', mod, '\">', rule, '</style>'].join('');\n                div.id = mod;\n                (body ? div : fakeBody).innerHTML += style;\n                fakeBody.appendChild(div);\n                if (!body) {\n                    fakeBody.style.background = '';\n                    fakeBody.style.overflow = 'hidden';\n                    docOverflow = docElement.style.overflow;\n                    docElement.style.overflow = 'hidden';\n                    docElement.appendChild(fakeBody);\n                }\n\n                ret = callback(div, rule);\n                if (!body) {\n                    fakeBody.parentNode.removeChild(fakeBody);\n                    docElement.style.overflow = docOverflow;\n                } else {\n                    div.parentNode.removeChild(div);\n                }\n\n                return !!ret;\n\n            },\n            _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;\n\n        if (!is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined')) {\n            hasOwnProp = function (object, property) {\n                return _hasOwnProperty.call(object, property);\n            };\n        }\n        else {\n            hasOwnProp = function (object, property) {\n                return ((property in object) && is(object.constructor.prototype[property], 'undefined'));\n            };\n        }\n\n\n        if (!Function.prototype.bind) {\n            Function.prototype.bind = function bind(that) {\n\n                var target = this;\n\n                if (typeof target != \"function\") {\n                    throw new TypeError();\n                }\n\n                var args = slice.call(arguments, 1),\n                    bound = function () {\n\n                        if (this instanceof bound) {\n\n                            var F = function () {\n                            };\n                            F.prototype = target.prototype;\n                            var self = new F();\n\n                            var result = target.apply(\n                                self,\n                                args.concat(slice.call(arguments))\n                            );\n                            if (Object(result) === result) {\n                                return result;\n                            }\n                            return self;\n\n                        } else {\n\n                            return target.apply(\n                                that,\n                                args.concat(slice.call(arguments))\n                            );\n\n                        }\n\n                    };\n\n                return bound;\n            };\n        }\n\n        function setCss(str) {\n            mStyle.cssText = str;\n        }\n\n        function setCssAll(str1, str2) {\n            return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));\n        }\n\n        function is(obj, type) {\n            return typeof obj === type;\n        }\n\n        function contains(str, substr) {\n            return !!~('' + str).indexOf(substr);\n        }\n\n        function testProps(props, prefixed) {\n            for (var i in props) {\n                var prop = props[i];\n                if (!contains(prop, \"-\") && mStyle[prop] !== undefined) {\n                    return prefixed == 'pfx' ? prop : true;\n                }\n            }\n            return false;\n        }\n\n        function testDOMProps(props, obj, elem) {\n            for (var i in props) {\n                var item = obj[props[i]];\n                if (item !== undefined) {\n\n                    if (elem === false) return props[i];\n\n                    if (is(item, 'function')) {\n                        return item.bind(elem || obj);\n                    }\n\n                    return item;\n                }\n            }\n            return false;\n        }\n\n        function testPropsAll(prop, prefixed, elem) {\n\n            var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),\n                props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');\n\n            if (is(prefixed, \"string\") || is(prefixed, \"undefined\")) {\n                return testProps(props, prefixed);\n\n            } else {\n                props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');\n                return testDOMProps(props, prefixed, elem);\n            }\n        }\n\n        tests['touch'] = function () {\n            var bool;\n\n            if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {\n                bool = true;\n            } else {\n                injectElementWithStyles(['@media (', prefixes.join('touch-enabled),('), mod, ')', '{#modernizr{top:9px;position:absolute}}'].join(''), function (node) {\n                    bool = node.offsetTop === 9;\n                });\n            }\n\n            return bool;\n        };\n        tests['csstransforms3d'] = function () {\n\n            var ret = !!testPropsAll('perspective');\n\n            if (ret && 'webkitPerspective' in docElement.style) {\n\n                injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function (node, rule) {\n                    ret = node.offsetLeft === 9 && node.offsetHeight === 3;\n                });\n            }\n            return ret;\n        };\n\n\n        tests['csstransitions'] = function () {\n            return testPropsAll('transition');\n        };\n\n\n        for (var feature in tests) {\n            if (hasOwnProp(tests, feature)) {\n                featureName = feature.toLowerCase();\n                Modernizr[featureName] = tests[feature]();\n\n                classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);\n            }\n        }\n\n\n        Modernizr.addTest = function (feature, test) {\n            if (typeof feature == 'object') {\n                for (var key in feature) {\n                    if (hasOwnProp(feature, key)) {\n                        Modernizr.addTest(key, feature[key]);\n                    }\n                }\n            } else {\n\n                feature = feature.toLowerCase();\n\n                if (Modernizr[feature] !== undefined) {\n                    return Modernizr;\n                }\n\n                test = typeof test == 'function' ? test() : test;\n\n                if (typeof enableClasses !== \"undefined\" && enableClasses) {\n                    docElement.className += ' ' + (test ? '' : 'no-') + feature;\n                }\n                Modernizr[feature] = test;\n\n            }\n\n            return Modernizr;\n        };\n\n\n        setCss('');\n        modElem = inputElem = null;\n\n\n        Modernizr._version = version;\n\n        Modernizr._prefixes = prefixes;\n        Modernizr._domPrefixes = domPrefixes;\n        Modernizr._cssomPrefixes = cssomPrefixes;\n\n\n        Modernizr.testProp = function (prop) {\n            return testProps([prop]);\n        };\n\n        Modernizr.testAllProps = testPropsAll;\n        Modernizr.testStyles = injectElementWithStyles;\n        Modernizr.prefixed = function (prop, obj, elem) {\n            if (!obj) {\n                return testPropsAll(prop, 'pfx');\n            } else {\n                return testPropsAll(prop, obj, elem);\n            }\n        };\n        return Modernizr;\n    })(window, document);\n\n    var fullScreenApi = {\n            ok: false,\n            is: function () {\n                return false;\n            },\n            request: function () {\n            },\n            cancel: function () {\n            },\n            event: '',\n            prefix: ''\n        },\n        browserPrefixes = 'webkit moz o ms khtml'.split(' ');\n\n// check for native support\n    if (typeof document.cancelFullScreen != 'undefined') {\n        fullScreenApi.ok = true;\n    } else {\n        // check for fullscreen support by vendor prefix\n        for (var i = 0, il = browserPrefixes.length; i < il; i++) {\n            fullScreenApi.prefix = browserPrefixes[i];\n            if (typeof document[fullScreenApi.prefix + 'CancelFullScreen'] != 'undefined') {\n                fullScreenApi.ok = true;\n                break;\n            }\n        }\n    }\n\n// update methods to do something useful\n    if (fullScreenApi.ok) {\n        fullScreenApi.event = fullScreenApi.prefix + 'fullscreenchange';\n        fullScreenApi.is = function () {\n            switch (this.prefix) {\n                case '':\n                    return document.fullScreen;\n                case 'webkit':\n                    return document.webkitIsFullScreen;\n                default:\n                    return document[this.prefix + 'FullScreen'];\n            }\n        };\n        fullScreenApi.request = function (el) {\n            return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen']();\n        };\n        fullScreenApi.cancel = function (el) {\n            if (!this.is()) {\n                return false;\n            }\n            return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen']();\n        };\n    }\n    /* Bez v1.0.10-g5ae0136\n     * http://github.com/rdallasgray/bez\n     *\n     * A plugin to convert CSS3 cubic-bezier co-ordinates to jQuery-compatible easing functions\n     *\n     * With thanks to Nikolay Nemshilov for clarification on the cubic-bezier maths\n     * See http://st-on-it.blogspot.com/2011/05/calculating-cubic-bezier-function.html\n     *\n     * Copyright 2011 Robert Dallas Gray. All rights reserved.\n     * Provided under the FreeBSD license: https://github.com/rdallasgray/bez/blob/master/LICENSE.txt\n     */\n    function bez(coOrdArray) {\n        var encodedFuncName = \"bez_\" + $.makeArray(arguments).join(\"_\").replace(\".\", \"p\");\n        if (typeof $['easing'][encodedFuncName] !== \"function\") {\n            var polyBez = function (p1, p2) {\n                var A = [null, null],\n                    B = [null, null],\n                    C = [null, null],\n                    bezCoOrd = function (t, ax) {\n                        C[ax] = 3 * p1[ax];\n                        B[ax] = 3 * (p2[ax] - p1[ax]) - C[ax];\n                        A[ax] = 1 - C[ax] - B[ax];\n                        return t * (C[ax] + t * (B[ax] + t * A[ax]));\n                    },\n                    xDeriv = function (t) {\n                        return C[0] + t * (2 * B[0] + 3 * A[0] * t);\n                    },\n                    xForT = function (t) {\n                        var x = t, i = 0, z;\n                        while (++i < 14) {\n                            z = bezCoOrd(x, 0) - t;\n                            if (Math.abs(z) < 1e-3) break;\n                            x -= z / xDeriv(x);\n                        }\n                        return x;\n                    };\n                return function (t) {\n                    return bezCoOrd(xForT(t), 1);\n                }\n            };\n            $['easing'][encodedFuncName] = function (x, t, b, c, d) {\n                return c * polyBez([coOrdArray[0], coOrdArray[1]], [coOrdArray[2], coOrdArray[3]])(t / d) + b;\n            }\n        }\n        return encodedFuncName;\n    }\n\n    var $WINDOW = $(window),\n        $DOCUMENT = $(document),\n        $HTML,\n        $BODY,\n\n        QUIRKS_FORCE = location.hash.replace('#', '') === 'quirks',\n        TRANSFORMS3D = Modernizr.csstransforms3d,\n        CSS3 = TRANSFORMS3D && !QUIRKS_FORCE,\n        COMPAT = TRANSFORMS3D || document.compatMode === 'CSS1Compat',\n        FULLSCREEN = fullScreenApi.ok,\n\n        MOBILE = navigator.userAgent.match(/Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i),\n        SLOW = !CSS3 || MOBILE,\n\n        MS_POINTER = navigator.msPointerEnabled,\n\n        WHEEL = \"onwheel\" in document.createElement(\"div\") ? \"wheel\" : document.onmousewheel !== undefined ? \"mousewheel\" : \"DOMMouseScroll\",\n\n        TOUCH_TIMEOUT = 250,\n        TRANSITION_DURATION = 300,\n\n        SCROLL_LOCK_TIMEOUT = 1400,\n\n        AUTOPLAY_INTERVAL = 5000,\n        MARGIN = 2,\n        THUMB_SIZE = 64,\n\n        WIDTH = 500,\n        HEIGHT = 333,\n\n        STAGE_FRAME_KEY = '$stageFrame',\n        NAV_DOT_FRAME_KEY = '$navDotFrame',\n        NAV_THUMB_FRAME_KEY = '$navThumbFrame',\n\n        AUTO = 'auto',\n\n        BEZIER = bez([.1, 0, .25, 1]),\n\n        MAX_WIDTH = 1200,\n\n        /**\n         * Number of thumbnails in slide. Calculated only on setOptions and resize.\n         * @type {number}\n         */\n        thumbsPerSlide = 1,\n\n        OPTIONS = {\n\n            /**\n             * Set width for gallery.\n             * Default value - width of first image\n             * Number - set value in px\n             * String - set value in quotes\n             *\n             */\n            width: null,\n\n            /**\n             * Set min-width for gallery\n             *\n             */\n            minwidth: null,\n\n            /**\n             * Set max-width for gallery\n             *\n             */\n            maxwidth: '100%',\n\n            /**\n             * Set height for gallery\n             * Default value - height of first image\n             * Number - set value in px\n             * String - set value in quotes\n             *\n             */\n            height: null,\n\n            /**\n             * Set min-height for gallery\n             *\n             */\n            minheight: null,\n\n            /**\n             * Set max-height for gallery\n             *\n             */\n            maxheight: null,\n\n            /**\n             * Set proportion ratio for gallery depends of image\n             *\n             */\n            ratio: null, // '16/9' || 500/333 || 1.5\n\n            margin: MARGIN,\n\n            nav: 'dots', // 'thumbs' || false\n            navposition: 'bottom', // 'top'\n            navwidth: null,\n            thumbwidth: THUMB_SIZE,\n            thumbheight: THUMB_SIZE,\n            thumbmargin: MARGIN,\n            thumbborderwidth: MARGIN,\n\n            allowfullscreen: false, // true || 'native'\n\n            transition: 'slide', // 'crossfade' || 'dissolve'\n            clicktransition: null,\n            transitionduration: TRANSITION_DURATION,\n\n            captions: true,\n\n            startindex: 0,\n\n            loop: false,\n\n            autoplay: false,\n            stopautoplayontouch: true,\n\n            keyboard: false,\n\n            arrows: true,\n            click: true,\n            swipe: false,\n            trackpad: false,\n\n            shuffle: false,\n\n            direction: 'ltr', // 'rtl'\n\n            shadows: true,\n\n            showcaption: true,\n\n            /**\n             * Set type of thumbnail navigation\n             */\n            navdir: 'horizontal',\n\n            /**\n             * Set configuration to show or hide arrows in thumb navigation\n             */\n            navarrows: true,\n\n            /**\n             * Set type of navigation. Can be thumbs or slides\n             */\n            navtype: 'thumbs'\n\n        },\n\n        KEYBOARD_OPTIONS = {\n            left: true,\n            right: true,\n            down: true,\n            up: true,\n            space: false,\n            home: false,\n            end: false\n        };\n\n    function noop() {\n    }\n\n    function minMaxLimit(value, min, max) {\n        return Math.max(isNaN(min) ? -Infinity : min, Math.min(isNaN(max) ? Infinity : max, value));\n    }\n\n    function readTransform(css, dir) {\n        return css.match(/ma/) && css.match(/-?\\d+(?!d)/g)[css.match(/3d/) ?\n                (dir === 'vertical' ? 13 : 12) : (dir === 'vertical' ? 5 : 4)\n                ]\n    }\n\n    function readPosition($el, dir) {\n        if (CSS3) {\n            return +readTransform($el.css('transform'), dir);\n        } else {\n            return +$el.css(dir === 'vertical' ? 'top' : 'left').replace('px', '');\n        }\n    }\n\n    function getTranslate(pos, direction) {\n        var obj = {};\n\n        if (CSS3) {\n\n            switch (direction) {\n                case 'vertical':\n                    obj.transform = 'translate3d(0, ' + (pos) + 'px,0)';\n                    break;\n                case 'list':\n                    break;\n                default :\n                    obj.transform = 'translate3d(' + (pos) + 'px,0,0)';\n                    break;\n            }\n        } else {\n            direction === 'vertical' ?\n                obj.top = pos :\n                obj.left = pos;\n        }\n        return obj;\n    }\n\n    function getDuration(time) {\n        return {'transition-duration': time + 'ms'};\n    }\n\n    function unlessNaN(value, alternative) {\n        return isNaN(value) ? alternative : value;\n    }\n\n    function numberFromMeasure(value, measure) {\n        return unlessNaN(+String(value).replace(measure || 'px', ''));\n    }\n\n    function numberFromPercent(value) {\n        return /%$/.test(value) ? numberFromMeasure(value, '%') : undefined;\n    }\n\n    function numberFromWhatever(value, whole) {\n        return unlessNaN(numberFromPercent(value) / 100 * whole, numberFromMeasure(value));\n    }\n\n    function measureIsValid(value) {\n        return (!isNaN(numberFromMeasure(value)) || !isNaN(numberFromMeasure(value, '%'))) && value;\n    }\n\n    function getPosByIndex(index, side, margin, baseIndex) {\n\n        return (index - (baseIndex || 0)) * (side + (margin || 0));\n    }\n\n    function getIndexByPos(pos, side, margin, baseIndex) {\n        return -Math.round(pos / (side + (margin || 0)) - (baseIndex || 0));\n    }\n\n    function bindTransitionEnd($el) {\n        var elData = $el.data();\n\n        if (elData.tEnd) return;\n\n        var el = $el[0],\n            transitionEndEvent = {\n                WebkitTransition: 'webkitTransitionEnd',\n                MozTransition: 'transitionend',\n                OTransition: 'oTransitionEnd otransitionend',\n                msTransition: 'MSTransitionEnd',\n                transition: 'transitionend'\n            };\n        addEvent(el, transitionEndEvent[Modernizr.prefixed('transition')], function (e) {\n            elData.tProp && e.propertyName.match(elData.tProp) && elData.onEndFn();\n        });\n        elData.tEnd = true;\n    }\n\n    function afterTransition($el, property, fn, time) {\n        var ok,\n            elData = $el.data();\n\n        if (elData) {\n            elData.onEndFn = function () {\n                if (ok) return;\n                ok = true;\n                clearTimeout(elData.tT);\n                fn();\n            };\n            elData.tProp = property;\n\n            // Passive call, just in case of fail of native transition-end event\n            clearTimeout(elData.tT);\n            elData.tT = setTimeout(function () {\n                elData.onEndFn();\n            }, time * 1.5);\n\n            bindTransitionEnd($el);\n        }\n    }\n\n\n    function stop($el, pos/*, _001*/) {\n        var dir = $el.navdir || 'horizontal';\n        if ($el.length) {\n            var elData = $el.data();\n            if (CSS3) {\n                $el.css(getDuration(0));\n                elData.onEndFn = noop;\n                clearTimeout(elData.tT);\n            } else {\n                $el.stop();\n            }\n            var lockedPos = getNumber(pos, function () {\n                return readPosition($el, dir);\n            });\n\n            $el.css(getTranslate(lockedPos, dir/*, _001*/));//.width(); // `.width()` for reflow\n            return lockedPos;\n        }\n    }\n\n    function getNumber() {\n        var number;\n        for (var _i = 0, _l = arguments.length; _i < _l; _i++) {\n            number = _i ? arguments[_i]() : arguments[_i];\n            if (typeof number === 'number') {\n                break;\n            }\n        }\n\n        return number;\n    }\n\n    function edgeResistance(pos, edge) {\n        return Math.round(pos + ((edge - pos) / 1.5));\n    }\n\n    function getProtocol() {\n        getProtocol.p = getProtocol.p || (location.protocol === 'https:' ? 'https://' : 'http://');\n        return getProtocol.p;\n    }\n\n    function parseHref(href) {\n        var a = document.createElement('a');\n        a.href = href;\n        return a;\n    }\n\n    function findVideoId(href, forceVideo) {\n        if (typeof href !== 'string') return href;\n        href = parseHref(href);\n\n        var id,\n            type;\n\n        if (href.host.match(/youtube\\.com/) && href.search) {\n            //.log();\n            id = href.search.split('v=')[1];\n            if (id) {\n                var ampersandPosition = id.indexOf('&');\n                if (ampersandPosition !== -1) {\n                    id = id.substring(0, ampersandPosition);\n                }\n                type = 'youtube';\n            }\n        } else if (href.host.match(/youtube\\.com|youtu\\.be|youtube-nocookie.com/)) {\n            id = href.pathname.replace(/^\\/(embed\\/|v\\/)?/, '').replace(/\\/.*/, '');\n            type = 'youtube';\n        } else if (href.host.match(/vimeo\\.com/)) {\n            type = 'vimeo';\n            id = href.pathname.replace(/^\\/(video\\/)?/, '').replace(/\\/.*/, '');\n        }\n\n        if ((!id || !type) && forceVideo) {\n            id = href.href;\n            type = 'custom';\n        }\n\n        return id ? {id: id, type: type, s: href.search.replace(/^\\?/, ''), p: getProtocol()} : false;\n    }\n\n    function getVideoThumbs(dataFrame, data, fotorama) {\n        var img, thumb, video = dataFrame.video;\n        if (video.type === 'youtube') {\n            thumb = getProtocol() + 'img.youtube.com/vi/' + video.id + '/default.jpg';\n            img = thumb.replace(/\\/default.jpg$/, '/hqdefault.jpg');\n            dataFrame.thumbsReady = true;\n        } else if (video.type === 'vimeo') {\n            $.ajax({\n                url: getProtocol() + 'vimeo.com/api/oembed.json',\n                data: {\n                    url: 'https://vimeo.com/' + video.id\n                },\n                dataType: 'jsonp',\n                success: function (json) {\n                    dataFrame.thumbsReady = true;\n                    updateData(data, {\n                        img: json[0].thumbnail_url,\n                        thumb: json[0].thumbnail_url\n                    }, dataFrame.i, fotorama);\n                }\n            });\n        } else {\n            dataFrame.thumbsReady = true;\n        }\n\n        return {\n            img: img,\n            thumb: thumb\n        }\n    }\n\n    function updateData(data, _dataFrame, i, fotorama) {\n        for (var _i = 0, _l = data.length; _i < _l; _i++) {\n            var dataFrame = data[_i];\n\n            if (dataFrame.i === i && dataFrame.thumbsReady) {\n                var clear = {videoReady: true};\n                clear[STAGE_FRAME_KEY] = clear[NAV_THUMB_FRAME_KEY] = clear[NAV_DOT_FRAME_KEY] = false;\n\n                fotorama.splice(_i, 1, $.extend(\n                    {},\n                    dataFrame,\n                    clear,\n                    _dataFrame\n                ));\n\n                break;\n            }\n        }\n    }\n\n    function getDataFromHtml($el) {\n        var data = [];\n\n        function getDataFromImg($img, imgData, checkVideo) {\n            var $child = $img.children('img').eq(0),\n                _imgHref = $img.attr('href'),\n                _imgSrc = $img.attr('src'),\n                _thumbSrc = $child.attr('src'),\n                _video = imgData.video,\n                video = checkVideo ? findVideoId(_imgHref, _video === true) : false;\n\n            if (video) {\n                _imgHref = false;\n            } else {\n                video = _video;\n            }\n\n            getDimensions($img, $child, $.extend(imgData, {\n                video: video,\n                img: imgData.img || _imgHref || _imgSrc || _thumbSrc,\n                thumb: imgData.thumb || _thumbSrc || _imgSrc || _imgHref\n            }));\n        }\n\n        function getDimensions($img, $child, imgData) {\n            var separateThumbFLAG = imgData.thumb && imgData.img !== imgData.thumb,\n                width = numberFromMeasure(imgData.width || $img.attr('width')),\n                height = numberFromMeasure(imgData.height || $img.attr('height'));\n\n            $.extend(imgData, {\n                width: width,\n                height: height,\n                thumbratio: getRatio(imgData.thumbratio || (numberFromMeasure(imgData.thumbwidth || ($child && $child.attr('width')) || separateThumbFLAG || width) / numberFromMeasure(imgData.thumbheight || ($child && $child.attr('height')) || separateThumbFLAG || height)))\n            });\n        }\n\n        $el.children().each(function () {\n            var $this = $(this),\n                dataFrame = optionsToLowerCase($.extend($this.data(), {id: $this.attr('id')}));\n            if ($this.is('a, img')) {\n                getDataFromImg($this, dataFrame, true);\n            } else if (!$this.is(':empty')) {\n                getDimensions($this, null, $.extend(dataFrame, {\n                    html: this,\n                    _html: $this.html() // Because of IE\n                }));\n            } else return;\n\n            data.push(dataFrame);\n        });\n\n        return data;\n    }\n\n    function isHidden(el) {\n        return el.offsetWidth === 0 && el.offsetHeight === 0;\n    }\n\n    function isDetached(el) {\n        return !$.contains(document.documentElement, el);\n    }\n\n    function waitFor(test, fn, timeout, i) {\n        if (!waitFor.i) {\n            waitFor.i = 1;\n            waitFor.ii = [true];\n        }\n\n        i = i || waitFor.i;\n\n        if (typeof waitFor.ii[i] === 'undefined') {\n            waitFor.ii[i] = true;\n        }\n\n        if (test()) {\n            fn();\n        } else {\n            waitFor.ii[i] && setTimeout(function () {\n                waitFor.ii[i] && waitFor(test, fn, timeout, i);\n            }, timeout || 100);\n        }\n\n        return waitFor.i++;\n    }\n\n    waitFor.stop = function (i) {\n        waitFor.ii[i] = false;\n    };\n\n    function fit($el, measuresToFit) {\n        var elData = $el.data(),\n            measures = elData.measures;\n\n        if (measures && (!elData.l ||\n            elData.l.W !== measures.width ||\n            elData.l.H !== measures.height ||\n            elData.l.r !== measures.ratio ||\n            elData.l.w !== measuresToFit.w ||\n            elData.l.h !== measuresToFit.h)) {\n\n            var height = minMaxLimit(measuresToFit.h, 0, measures.height),\n                width = height * measures.ratio;\n\n            UTIL.setRatio($el, width, height);\n\n            elData.l = {\n                W: measures.width,\n                H: measures.height,\n                r: measures.ratio,\n                w: measuresToFit.w,\n                h: measuresToFit.h\n            };\n        }\n\n        return true;\n    }\n\n    function setStyle($el, style) {\n        var el = $el[0];\n        if (el.styleSheet) {\n            el.styleSheet.cssText = style;\n        } else {\n            $el.html(style);\n        }\n    }\n\n    function findShadowEdge(pos, min, max, dir) {\n        return min === max ? false :\n            dir === 'vertical' ?\n                (pos <= min ? 'top' : pos >= max ? 'bottom' : 'top bottom') :\n                (pos <= min ? 'left' : pos >= max ? 'right' : 'left right');\n    }\n\n    function smartClick($el, fn, _options) {\n        _options = _options || {};\n\n        $el.each(function () {\n            var $this = $(this),\n                thisData = $this.data(),\n                startEvent;\n\n            if (thisData.clickOn) return;\n\n            thisData.clickOn = true;\n\n            $.extend(touch($this, {\n                onStart: function (e) {\n                    startEvent = e;\n                    (_options.onStart || noop).call(this, e);\n                },\n                onMove: _options.onMove || noop,\n                onTouchEnd: _options.onTouchEnd || noop,\n                onEnd: function (result) {\n                    if (result.moved) return;\n                    fn.call(this, startEvent);\n                }\n            }), {noMove: true});\n        });\n    }\n\n    function div(classes, child) {\n        return '<div class=\"' + classes + '\">' + (child || '') + '</div>';\n    }\n\n\n    /**\n     * Function transforming into valid classname\n     * @param className - name of the class\n     * @returns {string} - dom format of class name\n     */\n    function cls(className) {\n        return \".\" + className;\n    }\n\n    /**\n     *\n     * @param {json-object} videoItem Parsed object from data.video item or href from link a in input dates\n     * @returns {string} DOM view of video iframe\n     */\n    function createVideoFrame(videoItem) {\n        var frame = '<iframe src=\"' + videoItem.p + videoItem.type + '.com/embed/' + videoItem.id + '\" frameborder=\"0\" allowfullscreen></iframe>';\n        return frame;\n    }\n\n// Fisher\u2013Yates Shuffle\n// http://bost.ocks.org/mike/shuffle/\n    function shuffle(array) {\n        // While there remain elements to shuffle\n        var l = array.length;\n        while (l) {\n            // Pick a remaining element\n            var i = Math.floor(Math.random() * l--);\n\n            // And swap it with the current element\n            var t = array[l];\n            array[l] = array[i];\n            array[i] = t;\n        }\n\n        return array;\n    }\n\n    function clone(array) {\n        return Object.prototype.toString.call(array) == '[object Array]'\n            && $.map(array, function (frame) {\n                return $.extend({}, frame);\n            });\n    }\n\n    function lockScroll($el, left, top) {\n        $el\n            .scrollLeft(left || 0)\n            .scrollTop(top || 0);\n    }\n\n    function optionsToLowerCase(options) {\n        if (options) {\n            var opts = {};\n            $.each(options, function (key, value) {\n                opts[key.toLowerCase()] = value;\n            });\n\n            return opts;\n        }\n    }\n\n    function getRatio(_ratio) {\n        if (!_ratio) return;\n        var ratio = +_ratio;\n        if (!isNaN(ratio)) {\n            return ratio;\n        } else {\n            ratio = _ratio.split('/');\n            return +ratio[0] / +ratio[1] || undefined;\n        }\n    }\n\n    function addEvent(el, e, fn, bool) {\n        if (!e) return;\n        el.addEventListener ? el.addEventListener(e, fn, !!bool) : el.attachEvent('on' + e, fn);\n    }\n\n    /**\n     *\n     * @param position guess position for navShaft\n     * @param restriction object contains min and max values for position\n     * @returns {*} filtered value of position\n     */\n    function validateRestrictions(position, restriction) {\n        if (position > restriction.max) {\n            position = restriction.max;\n        } else {\n            if (position < restriction.min) {\n                position = restriction.min;\n            }\n        }\n        return position;\n    }\n\n    function validateSlidePos(opt, navShaftTouchTail, guessIndex, offsetNav, $guessNavFrame, $navWrap, dir) {\n        var position,\n            size,\n            wrapSize;\n        if (dir === 'horizontal') {\n            size = opt.thumbwidth;\n            wrapSize = $navWrap.width();\n        } else {\n            size = opt.thumbheight;\n            wrapSize = $navWrap.height();\n        }\n        if ( (size + opt.margin) * (guessIndex + 1) >= (wrapSize - offsetNav) ) {\n            if (dir === 'horizontal') {\n                position = -$guessNavFrame.position().left;\n            } else {\n                position = -$guessNavFrame.position().top;\n            }\n        } else {\n            if ((size + opt.margin) * (guessIndex) <= Math.abs(offsetNav)) {\n                if (dir === 'horizontal') {\n                    position = -$guessNavFrame.position().left + wrapSize - (size + opt.margin);\n                } else {\n                    position = -$guessNavFrame.position().top + wrapSize - (size + opt.margin);\n                }\n            } else {\n                position = offsetNav;\n            }\n        }\n        position = validateRestrictions(position, navShaftTouchTail);\n\n        return position || 0;\n    }\n\n    function elIsDisabled(el) {\n        return !!el.getAttribute('disabled');\n    }\n\n    function disableAttr(FLAG, disable) {\n        if (disable) {\n            return {disabled: FLAG};\n        } else {\n            return {tabindex: FLAG * -1 + '', disabled: FLAG};\n\n        }\n    }\n\n    function addEnterUp(el, fn) {\n        addEvent(el, 'keyup', function (e) {\n            elIsDisabled(el) || e.keyCode == 13 && fn.call(el, e);\n        });\n    }\n\n    function addFocus(el, fn) {\n        addEvent(el, 'focus', el.onfocusin = function (e) {\n            fn.call(el, e);\n        }, true);\n    }\n\n    function stopEvent(e, stopPropagation) {\n        e.preventDefault ? e.preventDefault() : (e.returnValue = false);\n        stopPropagation && e.stopPropagation && e.stopPropagation();\n    }\n\n    function getDirectionSign(forward) {\n        return forward ? '>' : '<';\n    }\n\n    var UTIL = (function () {\n\n        function setRatioClass($el, wh, ht) {\n            var rateImg = wh / ht;\n\n            if (rateImg <= 1) {\n                $el.parent().removeClass(horizontalImageClass);\n                $el.parent().addClass(verticalImageClass);\n            } else {\n                $el.parent().removeClass(verticalImageClass);\n                $el.parent().addClass(horizontalImageClass);\n            }\n        }\n\n        /**\n         * Set specific attribute in thumbnail template\n         * @param $frame DOM item of specific thumbnail\n         * @param value Value which must be setted into specific attribute\n         * @param searchAttr Name of attribute where value must be included\n         */\n        function setThumbAttr($frame, value, searchAttr) {\n            var attr = searchAttr;\n\n            if (!$frame.attr(attr) && $frame.attr(attr) !== undefined) {\n                $frame.attr(attr, value);\n            }\n\n            if ($frame.find(\"[\" + attr + \"]\").length) {\n                $frame.find(\"[\" + attr + \"]\")\n                    .each(function () {\n                        $(this).attr(attr, value);\n                    });\n            }\n        }\n\n        /**\n         * Method describe behavior need to render caption on preview or not\n         * @param frameItem specific item from data\n         * @param isExpected {bool} if items with caption need render them or not\n         * @returns {boolean} if true then caption should be rendered\n         */\n        function isExpectedCaption(frameItem, isExpected, undefined) {\n            var expected = false,\n                frameExpected;\n\n            frameItem.showCaption === undefined || frameItem.showCaption === true ? frameExpected = true : frameExpected = false;\n\n            if (!isExpected) {\n                return false;\n            }\n\n            if (frameItem.caption && frameExpected) {\n                expected = true;\n            }\n\n            return expected;\n        }\n\n        return {\n            setRatio: setRatioClass,\n            setThumbAttr: setThumbAttr,\n            isExpectedCaption: isExpectedCaption\n        };\n\n    }(UTIL || {}, jQuery));\n\n    function slide($el, options) {\n        var elData = $el.data(),\n            elPos = Math.round(options.pos),\n            onEndFn = function () {\n                if (elData && elData.sliding) {\n                    elData.sliding = false;\n                }\n                (options.onEnd || noop)();\n            };\n\n        if (typeof options.overPos !== 'undefined' && options.overPos !== options.pos) {\n            elPos = options.overPos;\n        }\n\n        var translate = $.extend(getTranslate(elPos, options.direction), options.width && {width: options.width}, options.height && {height: options.height});\n        if (elData && elData.sliding) {\n            elData.sliding = true;\n        }\n\n        if (CSS3) {\n            $el.css($.extend(getDuration(options.time), translate));\n\n            if (options.time > 10) {\n                afterTransition($el, 'transform', onEndFn, options.time);\n            } else {\n                onEndFn();\n            }\n        } else {\n            $el.stop().animate(translate, options.time, BEZIER, onEndFn);\n        }\n    }\n\n    function fade($el1, $el2, $frames, options, fadeStack, chain) {\n        var chainedFLAG = typeof chain !== 'undefined';\n        if (!chainedFLAG) {\n            fadeStack.push(arguments);\n            Array.prototype.push.call(arguments, fadeStack.length);\n            if (fadeStack.length > 1) return;\n        }\n\n        $el1 = $el1 || $($el1);\n        $el2 = $el2 || $($el2);\n\n        var _$el1 = $el1[0],\n            _$el2 = $el2[0],\n            crossfadeFLAG = options.method === 'crossfade',\n            onEndFn = function () {\n                if (!onEndFn.done) {\n                    onEndFn.done = true;\n                    var args = (chainedFLAG || fadeStack.shift()) && fadeStack.shift();\n                    args && fade.apply(this, args);\n                    (options.onEnd || noop)(!!args);\n                }\n            },\n            time = options.time / (chain || 1);\n\n        $frames.removeClass(fadeRearClass + ' ' + fadeFrontClass);\n\n        $el1\n            .stop()\n            .addClass(fadeRearClass);\n        $el2\n            .stop()\n            .addClass(fadeFrontClass);\n\n        crossfadeFLAG && _$el2 && $el1.fadeTo(0, 0);\n\n        $el1.fadeTo(crossfadeFLAG ? time : 0, 1, crossfadeFLAG && onEndFn);\n        $el2.fadeTo(time, 0, onEndFn);\n\n        (_$el1 && crossfadeFLAG) || _$el2 || onEndFn();\n    }\n\n    var lastEvent,\n        moveEventType,\n        preventEvent,\n        preventEventTimeout,\n        dragDomEl;\n\n    function extendEvent(e) {\n        var touch = (e.touches || [])[0] || e;\n        e._x = touch.pageX || touch.originalEvent.pageX;\n        e._y = touch.clientY || touch.originalEvent.clientY;\n        e._now = $.now();\n    }\n\n    function touch($el, options) {\n        var el = $el[0],\n            tail = {},\n            touchEnabledFLAG,\n            startEvent,\n            $target,\n            controlTouch,\n            touchFLAG,\n            targetIsSelectFLAG,\n            targetIsLinkFlag,\n            isDisabledSwipe,\n            tolerance,\n            moved;\n\n        function onStart(e) {\n            $target = $(e.target);\n            tail.checked = targetIsSelectFLAG = targetIsLinkFlag = isDisabledSwipe = moved = false;\n\n            if (touchEnabledFLAG\n                || tail.flow\n                || (e.touches && e.touches.length > 1)\n                || e.which > 1\n                || (lastEvent && lastEvent.type !== e.type && preventEvent)\n                || (targetIsSelectFLAG = options.select && $target.is(options.select, el))) return targetIsSelectFLAG;\n\n            touchFLAG = e.type === 'touchstart';\n            targetIsLinkFlag = $target.is('a, a *', el);\n            isDisabledSwipe = $target.hasClass('disableSwipe');\n            controlTouch = tail.control;\n\n            tolerance = (tail.noMove || tail.noSwipe || controlTouch) ? 16 : !tail.snap ? 4 : 0;\n\n            extendEvent(e);\n\n            startEvent = lastEvent = e;\n            moveEventType = e.type.replace(/down|start/, 'move').replace(/Down/, 'Move');\n\n            (options.onStart || noop).call(el, e, {control: controlTouch, $target: $target});\n\n            touchEnabledFLAG = tail.flow = true;\n\n            if (!isDisabledSwipe && (!touchFLAG || tail.go)) stopEvent(e);\n        }\n\n        function onMove(e) {\n            if ((e.touches && e.touches.length > 1)\n                || (MS_POINTER && !e.isPrimary)\n                || moveEventType !== e.type\n                || !touchEnabledFLAG) {\n                touchEnabledFLAG && onEnd();\n                (options.onTouchEnd || noop)();\n                return;\n            }\n\n            isDisabledSwipe = $(e.target).hasClass('disableSwipe');\n\n            if (isDisabledSwipe) {\n                return;\n            }\n\n            extendEvent(e);\n\n            var xDiff = Math.abs(e._x - startEvent._x), // opt _x \u2192 _pageX\n                yDiff = Math.abs(e._y - startEvent._y),\n                xyDiff = xDiff - yDiff,\n                xWin = (tail.go || tail.x || xyDiff >= 0) && !tail.noSwipe,\n                yWin = xyDiff < 0;\n\n            if (touchFLAG && !tail.checked) {\n                if (touchEnabledFLAG = xWin) {\n                    stopEvent(e);\n                }\n            } else {\n                stopEvent(e);\n                if (movedEnough(xDiff,yDiff)) {\n                    (options.onMove || noop).call(el, e, {touch: touchFLAG});\n                }\n            }\n\n            if (!moved && movedEnough(xDiff, yDiff) && Math.sqrt(Math.pow(xDiff, 2) + Math.pow(yDiff, 2)) > tolerance) {\n                moved = true;\n            }\n\n            tail.checked = tail.checked || xWin || yWin;\n        }\n\n        function movedEnough(xDiff, yDiff) {\n            return xDiff > yDiff && xDiff > 1.5;\n        }\n\n        function onEnd(e) {\n            (options.onTouchEnd || noop)();\n\n            var _touchEnabledFLAG = touchEnabledFLAG;\n            tail.control = touchEnabledFLAG = false;\n\n            if (_touchEnabledFLAG) {\n                tail.flow = false;\n            }\n\n            if (!_touchEnabledFLAG || (targetIsLinkFlag && !tail.checked)) return;\n\n            e && stopEvent(e);\n\n            preventEvent = true;\n            clearTimeout(preventEventTimeout);\n            preventEventTimeout = setTimeout(function () {\n                preventEvent = false;\n            }, 1000);\n\n            (options.onEnd || noop).call(el, {\n                moved: moved,\n                $target: $target,\n                control: controlTouch,\n                touch: touchFLAG,\n                startEvent: startEvent,\n                aborted: !e || e.type === 'MSPointerCancel'\n            });\n        }\n\n        function onOtherStart() {\n            if (tail.flow) return;\n            tail.flow = true;\n        }\n\n        function onOtherEnd() {\n            if (!tail.flow) return;\n            tail.flow = false;\n        }\n\n        if (MS_POINTER) {\n            addEvent(el, 'MSPointerDown', onStart);\n            addEvent(document, 'MSPointerMove', onMove);\n            addEvent(document, 'MSPointerCancel', onEnd);\n            addEvent(document, 'MSPointerUp', onEnd);\n        } else {\n            addEvent(el, 'touchstart', onStart);\n            addEvent(el, 'touchmove', onMove);\n            addEvent(el, 'touchend', onEnd);\n\n            addEvent(document, 'touchstart', onOtherStart, true);\n            addEvent(document, 'touchend', onOtherEnd);\n            addEvent(document, 'touchcancel', onOtherEnd);\n\n            $WINDOW.on('scroll', onOtherEnd);\n\n            $el.on('mousedown', onStart);\n            $DOCUMENT\n                .on('mousemove', onMove)\n                .on('mouseup', onEnd);\n        }\n        if (Modernizr.touch) {\n            dragDomEl = 'a';\n        } else {\n            dragDomEl = 'div';\n        }\n        $el.on('click', dragDomEl, function (e) {\n            tail.checked && stopEvent(e);\n        });\n\n        return tail;\n    }\n\n    function moveOnTouch($el, options) {\n        var el = $el[0],\n            elData = $el.data(),\n            tail = {},\n            startCoo,\n            coo,\n            startElPos,\n            moveElPos,\n            edge,\n            moveTrack,\n            startTime,\n            endTime,\n            min,\n            max,\n            snap,\n            dir,\n            slowFLAG,\n            controlFLAG,\n            moved,\n            tracked;\n\n        function startTracking(e, noStop) {\n            tracked = true;\n            startCoo = coo = (dir === 'vertical') ? e._y : e._x;\n            startTime = e._now;\n\n            moveTrack = [\n                [startTime, startCoo]\n            ];\n\n            startElPos = moveElPos = tail.noMove || noStop ? 0 : stop($el, (options.getPos || noop)()/*, options._001*/);\n\n            (options.onStart || noop).call(el, e);\n        }\n\n        function onStart(e, result) {\n            min = tail.min;\n            max = tail.max;\n            snap = tail.snap,\n                dir = tail.direction || 'horizontal',\n                $el.navdir = dir;\n\n            slowFLAG = e.altKey;\n            tracked = moved = false;\n\n            controlFLAG = result.control;\n\n            if (!controlFLAG && !elData.sliding) {\n                startTracking(e);\n            }\n        }\n\n        function onMove(e, result) {\n            if (!tail.noSwipe) {\n                if (!tracked) {\n                    startTracking(e);\n                }\n                coo = (dir === 'vertical') ? e._y : e._x;\n\n                moveTrack.push([e._now, coo]);\n\n                moveElPos = startElPos - (startCoo - coo);\n\n                edge = findShadowEdge(moveElPos, min, max, dir);\n\n                if (moveElPos <= min) {\n                    moveElPos = edgeResistance(moveElPos, min);\n                } else if (moveElPos >= max) {\n                    moveElPos = edgeResistance(moveElPos, max);\n                }\n\n                if (!tail.noMove) {\n                    $el.css(getTranslate(moveElPos, dir));\n                    if (!moved) {\n                        moved = true;\n                        // only for mouse\n                        result.touch || MS_POINTER || $el.addClass(grabbingClass);\n                    }\n\n                    (options.onMove || noop).call(el, e, {pos: moveElPos, edge: edge});\n                }\n            }\n        }\n\n        function onEnd(result) {\n            if (tail.noSwipe && result.moved) return;\n\n            if (!tracked) {\n                startTracking(result.startEvent, true);\n            }\n\n            result.touch || MS_POINTER || $el.removeClass(grabbingClass);\n\n            endTime = $.now();\n\n            var _backTimeIdeal = endTime - TOUCH_TIMEOUT,\n                _backTime,\n                _timeDiff,\n                _timeDiffLast,\n                backTime = null,\n                backCoo,\n                virtualPos,\n                limitPos,\n                newPos,\n                overPos,\n                time = TRANSITION_DURATION,\n                speed,\n                friction = options.friction;\n\n            for (var _i = moveTrack.length - 1; _i >= 0; _i--) {\n                _backTime = moveTrack[_i][0];\n                _timeDiff = Math.abs(_backTime - _backTimeIdeal);\n                if (backTime === null || _timeDiff < _timeDiffLast) {\n                    backTime = _backTime;\n                    backCoo = moveTrack[_i][1];\n                } else if (backTime === _backTimeIdeal || _timeDiff > _timeDiffLast) {\n                    break;\n                }\n                _timeDiffLast = _timeDiff;\n            }\n\n            newPos = minMaxLimit(moveElPos, min, max);\n\n            var cooDiff = backCoo - coo,\n                forwardFLAG = cooDiff >= 0,\n                timeDiff = endTime - backTime,\n                longTouchFLAG = timeDiff > TOUCH_TIMEOUT,\n                swipeFLAG = !longTouchFLAG && moveElPos !== startElPos && newPos === moveElPos;\n\n            if (snap) {\n                newPos = minMaxLimit(Math[swipeFLAG ? (forwardFLAG ? 'floor' : 'ceil') : 'round'](moveElPos / snap) * snap, min, max);\n                min = max = newPos;\n            }\n\n            if (swipeFLAG && (snap || newPos === moveElPos)) {\n                speed = -(cooDiff / timeDiff);\n                time *= minMaxLimit(Math.abs(speed), options.timeLow, options.timeHigh);\n                virtualPos = Math.round(moveElPos + speed * time / friction);\n\n                if (!snap) {\n                    newPos = virtualPos;\n                }\n\n                if (!forwardFLAG && virtualPos > max || forwardFLAG && virtualPos < min) {\n                    limitPos = forwardFLAG ? min : max;\n                    overPos = virtualPos - limitPos;\n                    if (!snap) {\n                        newPos = limitPos;\n                    }\n                    overPos = minMaxLimit(newPos + overPos * .03, limitPos - 50, limitPos + 50);\n                    time = Math.abs((moveElPos - overPos) / (speed / friction));\n                }\n            }\n\n            time *= slowFLAG ? 10 : 1;\n\n            (options.onEnd || noop).call(el, $.extend(result, {\n                moved: result.moved || longTouchFLAG && snap,\n                pos: moveElPos,\n                newPos: newPos,\n                overPos: overPos,\n                time: time,\n                dir: dir\n            }));\n        }\n\n        tail = $.extend(touch(options.$wrap, $.extend({}, options, {\n            onStart: onStart,\n            onMove: onMove,\n            onEnd: onEnd\n        })), tail);\n\n        return tail;\n    }\n\n    function wheel($el, options) {\n        var el = $el[0],\n            lockFLAG,\n            lastDirection,\n            lastNow,\n            tail = {\n                prevent: {}\n            };\n\n        addEvent(el, WHEEL, function (e) {\n            var yDelta = e.wheelDeltaY || -1 * e.deltaY || 0,\n                xDelta = e.wheelDeltaX || -1 * e.deltaX || 0,\n                xWin = Math.abs(xDelta) && !Math.abs(yDelta),\n                direction = getDirectionSign(xDelta < 0),\n                sameDirection = lastDirection === direction,\n                now = $.now(),\n                tooFast = now - lastNow < TOUCH_TIMEOUT;\n\n            lastDirection = direction;\n            lastNow = now;\n\n            if (!xWin || !tail.ok || tail.prevent[direction] && !lockFLAG) {\n                return;\n            } else {\n                stopEvent(e, true);\n                if (lockFLAG && sameDirection && tooFast) {\n                    return;\n                }\n            }\n\n            if (options.shift) {\n                lockFLAG = true;\n                clearTimeout(tail.t);\n                tail.t = setTimeout(function () {\n                    lockFLAG = false;\n                }, SCROLL_LOCK_TIMEOUT);\n            }\n\n            (options.onEnd || noop)(e, options.shift ? direction : xDelta);\n\n        });\n\n        return tail;\n    }\n\n    jQuery.Fotorama = function ($fotorama, opts) {\n        $HTML = $('html');\n        $BODY = $('body');\n\n        var that = this,\n            stamp = $.now(),\n            stampClass = _fotoramaClass + stamp,\n            fotorama = $fotorama[0],\n            data,\n            dataFrameCount = 1,\n            fotoramaData = $fotorama.data(),\n            size,\n\n            $style = $('<style></style>'),\n\n            $anchor = $(div(hiddenClass)),\n            $wrap = $fotorama.find(cls(wrapClass)),\n            $stage = $wrap.find(cls(stageClass)),\n            stage = $stage[0],\n\n            $stageShaft = $fotorama.find(cls(stageShaftClass)),\n            $stageFrame = $(),\n            $arrPrev = $fotorama.find(cls(arrPrevClass)),\n            $arrNext = $fotorama.find(cls(arrNextClass)),\n            $arrs = $fotorama.find(cls(arrClass)),\n            $navWrap = $fotorama.find(cls(navWrapClass)),\n            $nav = $navWrap.find(cls(navClass)),\n            $navShaft = $nav.find(cls(navShaftClass)),\n            $navFrame,\n            $navDotFrame = $(),\n            $navThumbFrame = $(),\n\n            stageShaftData = $stageShaft.data(),\n            navShaftData = $navShaft.data(),\n\n            $thumbBorder = $fotorama.find(cls(thumbBorderClass)),\n            $thumbArrLeft = $fotorama.find(cls(thumbArrLeft)),\n            $thumbArrRight = $fotorama.find(cls(thumbArrRight)),\n\n            $fullscreenIcon = $fotorama.find(cls(fullscreenIconClass)),\n            fullscreenIcon = $fullscreenIcon[0],\n            $videoPlay = $(div(videoPlayClass)),\n            $videoClose = $fotorama.find(cls(videoCloseClass)),\n            videoClose = $videoClose[0],\n\n            $spinner = $fotorama.find(cls(fotoramaSpinnerClass)),\n\n            $videoPlaying,\n\n            activeIndex = false,\n            activeFrame,\n            activeIndexes,\n            repositionIndex,\n            dirtyIndex,\n            lastActiveIndex,\n            prevIndex,\n            nextIndex,\n            nextAutoplayIndex,\n            startIndex,\n\n            o_loop,\n            o_nav,\n            o_navThumbs,\n            o_navTop,\n            o_allowFullScreen,\n            o_nativeFullScreen,\n            o_fade,\n            o_thumbSide,\n            o_thumbSide2,\n            o_transitionDuration,\n            o_transition,\n            o_shadows,\n            o_rtl,\n            o_keyboard,\n            lastOptions = {},\n\n            measures = {},\n            measuresSetFLAG,\n\n            stageShaftTouchTail = {},\n            stageWheelTail = {},\n            navShaftTouchTail = {},\n            navWheelTail = {},\n\n            scrollTop,\n            scrollLeft,\n\n            showedFLAG,\n            pausedAutoplayFLAG,\n            stoppedAutoplayFLAG,\n\n            toDeactivate = {},\n            toDetach = {},\n\n            measuresStash,\n\n            touchedFLAG,\n\n            hoverFLAG,\n\n            navFrameKey,\n            stageLeft = 0,\n\n            fadeStack = [];\n\n        $wrap[STAGE_FRAME_KEY] = $('<div class=\"' + stageFrameClass + '\"></div>');\n        $wrap[NAV_THUMB_FRAME_KEY] = $($.Fotorama.jst.thumb());\n        $wrap[NAV_DOT_FRAME_KEY] = $($.Fotorama.jst.dots());\n\n        toDeactivate[STAGE_FRAME_KEY] = [];\n        toDeactivate[NAV_THUMB_FRAME_KEY] = [];\n        toDeactivate[NAV_DOT_FRAME_KEY] = [];\n        toDetach[STAGE_FRAME_KEY] = {};\n\n        $wrap.addClass(CSS3 ? wrapCss3Class : wrapCss2Class);\n\n        fotoramaData.fotorama = this;\n\n        /**\n         * Search video items in incoming data and transform object for video layout.\n         *\n         */\n        function checkForVideo() {\n            $.each(data, function (i, dataFrame) {\n                if (!dataFrame.i) {\n                    dataFrame.i = dataFrameCount++;\n                    var video = findVideoId(dataFrame.video, true);\n                    if (video) {\n                        var thumbs = {};\n                        dataFrame.video = video;\n                        if (!dataFrame.img && !dataFrame.thumb) {\n                            thumbs = getVideoThumbs(dataFrame, data, that);\n                        } else {\n                            dataFrame.thumbsReady = true;\n                        }\n                        updateData(data, {img: thumbs.img, thumb: thumbs.thumb}, dataFrame.i, that);\n                    }\n                }\n            });\n        }\n\n        /**\n         * Checks if current media object is YouTube or Vimeo video stream\n         * @returns {boolean}\n         */\n        function isVideo() {\n            return $((that.activeFrame || {}).$stageFrame || {}).hasClass('fotorama-video-container');\n        }\n\n        function allowKey(key) {\n            return o_keyboard[key];\n        }\n\n        function setStagePosition() {\n            if ($stage !== undefined) {\n\n                if (opts.navdir == 'vertical') {\n                    var padding = opts.thumbwidth + opts.thumbmargin;\n\n                    $stage.css('left', padding);\n                    $arrNext.css('right', padding);\n                    $fullscreenIcon.css('right', padding);\n                    $wrap.css('width', $wrap.css('width') + padding);\n                    $stageShaft.css('max-width', $wrap.width() - padding);\n                } else {\n                    $stage.css('left', '');\n                    $arrNext.css('right', '');\n                    $fullscreenIcon.css('right', '');\n                    $wrap.css('width', $wrap.css('width') + padding);\n                    $stageShaft.css('max-width', '');\n                }\n            }\n        }\n\n        function bindGlobalEvents(FLAG) {\n            var keydownCommon = 'keydown.' + _fotoramaClass,\n                localStamp = _fotoramaClass + stamp,\n                keydownLocal = 'keydown.' + localStamp,\n                keyupLocal = 'keyup.' + localStamp,\n                resizeLocal = 'resize.' + localStamp + ' ' + 'orientationchange.' + localStamp,\n                showParams;\n\n            if (FLAG) {\n                $DOCUMENT\n                    .on(keydownLocal, function (e) {\n                        var catched,\n                            index;\n\n                        if ($videoPlaying && e.keyCode === 27) {\n                            catched = true;\n                            unloadVideo($videoPlaying, true, true);\n                        } else if (that.fullScreen || (opts.keyboard && !that.index)) {\n                            if (e.keyCode === 27) {\n                                catched = true;\n                                that.cancelFullScreen();\n                            } else if ((e.shiftKey && e.keyCode === 32 && allowKey('space')) || (!e.altKey && !e.metaKey && e.keyCode === 37 && allowKey('left')) || (e.keyCode === 38 && allowKey('up') && $(':focus').attr('data-gallery-role'))) {\n                                that.longPress.progress();\n                                index = '<';\n                            } else if ((e.keyCode === 32 && allowKey('space')) || (!e.altKey && !e.metaKey && e.keyCode === 39 && allowKey('right')) || (e.keyCode === 40 && allowKey('down') && $(':focus').attr('data-gallery-role'))) {\n                                that.longPress.progress();\n                                index = '>';\n                            } else if (e.keyCode === 36 && allowKey('home')) {\n                                that.longPress.progress();\n                                index = '<<';\n                            } else if (e.keyCode === 35 && allowKey('end')) {\n                                that.longPress.progress();\n                                index = '>>';\n                            }\n                        }\n\n                        (catched || index) && stopEvent(e);\n                        showParams = {index: index, slow: e.altKey, user: true};\n                        index && (that.longPress.inProgress ?\n                            that.showWhileLongPress(showParams) :\n                            that.show(showParams));\n                    });\n\n                if (FLAG) {\n                    $DOCUMENT\n                        .on(keyupLocal, function (e) {\n                            if (that.longPress.inProgress) {\n                                that.showEndLongPress({user: true});\n                            }\n                            that.longPress.reset();\n                        });\n                }\n\n                if (!that.index) {\n                    $DOCUMENT\n                        .off(keydownCommon)\n                        .on(keydownCommon, 'textarea, input, select', function (e) {\n                            !$BODY.hasClass(_fullscreenClass) && e.stopPropagation();\n                        });\n                }\n\n                $WINDOW.on(resizeLocal, that.resize);\n            } else {\n                $DOCUMENT.off(keydownLocal);\n                $WINDOW.off(resizeLocal);\n            }\n        }\n\n        function appendElements(FLAG) {\n            if (FLAG === appendElements.f) return;\n\n            if (FLAG) {\n                $fotorama\n                    .addClass(_fotoramaClass + ' ' + stampClass)\n                    .before($anchor)\n                    .before($style);\n                addInstance(that);\n            } else {\n                $anchor.detach();\n                $style.detach();\n                $fotorama\n                    .html(fotoramaData.urtext)\n                    .removeClass(stampClass);\n\n                hideInstance(that);\n            }\n\n            bindGlobalEvents(FLAG);\n            appendElements.f = FLAG;\n        }\n\n        /**\n         * Set and install data from incoming @param {JSON} options or takes data attr from data-\"name\"=... values.\n         */\n        function setData() {\n            data = that.data = data || clone(opts.data) || getDataFromHtml($fotorama);\n            size = that.size = data.length;\n\n            ready.ok && opts.shuffle && shuffle(data);\n\n            checkForVideo();\n\n            activeIndex = limitIndex(activeIndex);\n\n            size && appendElements(true);\n        }\n\n        function stageNoMove() {\n            var _noMove = size < 2 || $videoPlaying;\n            stageShaftTouchTail.noMove = _noMove || o_fade;\n            stageShaftTouchTail.noSwipe = _noMove || !opts.swipe;\n\n            !o_transition && $stageShaft.toggleClass(grabClass, !opts.click && !stageShaftTouchTail.noMove && !stageShaftTouchTail.noSwipe);\n            MS_POINTER && $wrap.toggleClass(wrapPanYClass, !stageShaftTouchTail.noSwipe);\n        }\n\n        function setAutoplayInterval(interval) {\n            if (interval === true) interval = '';\n            opts.autoplay = Math.max(+interval || AUTOPLAY_INTERVAL, o_transitionDuration * 1.5);\n        }\n\n        function updateThumbArrow(opt) {\n            if (opt.navarrows && opt.nav === 'thumbs') {\n                $thumbArrLeft.show();\n                $thumbArrRight.show();\n            } else {\n                $thumbArrLeft.hide();\n                $thumbArrRight.hide();\n            }\n\n        }\n\n        function getThumbsInSlide($el, opts) {\n            return Math.floor($wrap.width() / (opts.thumbwidth + opts.thumbmargin));\n        }\n\n        /**\n         * Options on the fly\n         * */\n        function setOptions() {\n            if (!opts.nav || opts.nav === 'dots') {\n                opts.navdir = 'horizontal'\n            }\n\n            that.options = opts = optionsToLowerCase(opts);\n            thumbsPerSlide = getThumbsInSlide($wrap, opts);\n\n            o_fade = (opts.transition === 'crossfade' || opts.transition === 'dissolve');\n\n            o_loop = opts.loop && (size > 2 || (o_fade && (!o_transition || o_transition !== 'slide')));\n\n            o_transitionDuration = +opts.transitionduration || TRANSITION_DURATION;\n\n            o_rtl = opts.direction === 'rtl';\n\n            o_keyboard = $.extend({}, opts.keyboard && KEYBOARD_OPTIONS, opts.keyboard);\n            updateThumbArrow(opts);\n            var classes = {add: [], remove: []};\n\n            function addOrRemoveClass(FLAG, value) {\n                classes[FLAG ? 'add' : 'remove'].push(value);\n            }\n\n            if (size > 1) {\n                o_nav = opts.nav;\n                o_navTop = opts.navposition === 'top';\n                classes.remove.push(selectClass);\n\n                $arrs.toggle(!!opts.arrows);\n            } else {\n                o_nav = false;\n                $arrs.hide();\n            }\n\n            arrsUpdate();\n            stageWheelUpdate();\n            thumbArrUpdate();\n            if (opts.autoplay) setAutoplayInterval(opts.autoplay);\n\n            o_thumbSide = numberFromMeasure(opts.thumbwidth) || THUMB_SIZE;\n            o_thumbSide2 = numberFromMeasure(opts.thumbheight) || THUMB_SIZE;\n\n            stageWheelTail.ok = navWheelTail.ok = opts.trackpad && !SLOW;\n\n            stageNoMove();\n\n            extendMeasures(opts, [measures]);\n\n            o_navThumbs = o_nav === 'thumbs';\n\n            if ($navWrap.filter(':hidden') && !!o_nav) {\n                $navWrap.show();\n            }\n            if (o_navThumbs) {\n                frameDraw(size, 'navThumb');\n\n                $navFrame = $navThumbFrame;\n                navFrameKey = NAV_THUMB_FRAME_KEY;\n\n                setStyle($style, $.Fotorama.jst.style({\n                    w: o_thumbSide,\n                    h: o_thumbSide2,\n                    b: opts.thumbborderwidth,\n                    m: opts.thumbmargin,\n                    s: stamp,\n                    q: !COMPAT\n                }));\n\n                $nav\n                    .addClass(navThumbsClass)\n                    .removeClass(navDotsClass);\n            } else if (o_nav === 'dots') {\n                frameDraw(size, 'navDot');\n\n                $navFrame = $navDotFrame;\n                navFrameKey = NAV_DOT_FRAME_KEY;\n\n                $nav\n                    .addClass(navDotsClass)\n                    .removeClass(navThumbsClass);\n            } else {\n                $navWrap.hide();\n                o_nav = false;\n                $nav.removeClass(navThumbsClass + ' ' + navDotsClass);\n            }\n\n            if (o_nav) {\n                if (o_navTop) {\n                    $navWrap.insertBefore($stage);\n                } else {\n                    $navWrap.insertAfter($stage);\n                }\n                frameAppend.nav = false;\n\n                frameAppend($navFrame, $navShaft, 'nav');\n            }\n\n            o_allowFullScreen = opts.allowfullscreen;\n\n            if (o_allowFullScreen) {\n                $fullscreenIcon.prependTo($stage);\n                o_nativeFullScreen = FULLSCREEN && o_allowFullScreen === 'native';\n            } else {\n                $fullscreenIcon.detach();\n                o_nativeFullScreen = false;\n            }\n\n            addOrRemoveClass(o_fade, wrapFadeClass);\n            addOrRemoveClass(!o_fade, wrapSlideClass);\n            addOrRemoveClass(!opts.captions, wrapNoCaptionsClass);\n            addOrRemoveClass(o_rtl, wrapRtlClass);\n            addOrRemoveClass(opts.arrows, wrapToggleArrowsClass);\n\n            o_shadows = opts.shadows && !SLOW;\n            addOrRemoveClass(!o_shadows, wrapNoShadowsClass);\n\n            $wrap\n                .addClass(classes.add.join(' '))\n                .removeClass(classes.remove.join(' '));\n\n            lastOptions = $.extend({}, opts);\n            setStagePosition();\n        }\n\n        function normalizeIndex(index) {\n            return index < 0 ? (size + (index % size)) % size : index >= size ? index % size : index;\n        }\n\n        function limitIndex(index) {\n            return minMaxLimit(index, 0, size - 1);\n        }\n\n        function edgeIndex(index) {\n            return o_loop ? normalizeIndex(index) : limitIndex(index);\n        }\n\n        function getPrevIndex(index) {\n            return index > 0 || o_loop ? index - 1 : false;\n        }\n\n        function getNextIndex(index) {\n            return index < size - 1 || o_loop ? index + 1 : false;\n        }\n\n        function setStageShaftMinmaxAndSnap() {\n            stageShaftTouchTail.min = o_loop ? -Infinity : -getPosByIndex(size - 1, measures.w, opts.margin, repositionIndex);\n            stageShaftTouchTail.max = o_loop ? Infinity : -getPosByIndex(0, measures.w, opts.margin, repositionIndex);\n            stageShaftTouchTail.snap = measures.w + opts.margin;\n        }\n\n        function setNavShaftMinMax() {\n\n            var isVerticalDir = (opts.navdir === 'vertical');\n            var param = isVerticalDir ? $navShaft.height() : $navShaft.width();\n            var mainParam = isVerticalDir ? measures.h : measures.nw;\n            navShaftTouchTail.min = Math.min(0, mainParam - param);\n            navShaftTouchTail.max = 0;\n            navShaftTouchTail.direction = opts.navdir;\n            $navShaft.toggleClass(grabClass, !(navShaftTouchTail.noMove = navShaftTouchTail.min === navShaftTouchTail.max));\n        }\n\n        function eachIndex(indexes, type, fn) {\n            if (typeof indexes === 'number') {\n                indexes = new Array(indexes);\n                var rangeFLAG = true;\n            }\n            return $.each(indexes, function (i, index) {\n                if (rangeFLAG) index = i;\n                if (typeof index === 'number') {\n                    var dataFrame = data[normalizeIndex(index)];\n\n                    if (dataFrame) {\n                        var key = '$' + type + 'Frame',\n                            $frame = dataFrame[key];\n\n                        fn.call(this, i, index, dataFrame, $frame, key, $frame && $frame.data());\n                    }\n                }\n            });\n        }\n\n        function setMeasures(width, height, ratio, index) {\n            if (!measuresSetFLAG || (measuresSetFLAG === '*' && index === startIndex)) {\n\n                width = measureIsValid(opts.width) || measureIsValid(width) || WIDTH;\n                height = measureIsValid(opts.height) || measureIsValid(height) || HEIGHT;\n                that.resize({\n                    width: width,\n                    ratio: opts.ratio || ratio || width / height\n                }, 0, index !== startIndex && '*');\n            }\n        }\n\n        function loadImg(indexes, type, specialMeasures, again) {\n\n            eachIndex(indexes, type, function (i, index, dataFrame, $frame, key, frameData) {\n\n                if (!$frame) return;\n\n                var fullFLAG = that.fullScreen && !frameData.$full && type === 'stage';\n\n                if (frameData.$img && !again && !fullFLAG) return;\n\n                var img = new Image(),\n                    $img = $(img),\n                    imgData = $img.data();\n\n                frameData[fullFLAG ? '$full' : '$img'] = $img;\n\n                var srcKey = type === 'stage' ? (fullFLAG ? 'full' : 'img') : 'thumb',\n                    src = dataFrame[srcKey],\n                    dummy = fullFLAG ? dataFrame['img'] : dataFrame[type === 'stage' ? 'thumb' : 'img'];\n\n                if (type === 'navThumb') $frame = frameData.$wrap;\n\n                function triggerTriggerEvent(event) {\n                    var _index = normalizeIndex(index);\n                    triggerEvent(event, {\n                        index: _index,\n                        src: src,\n                        frame: data[_index]\n                    });\n                }\n\n                function error() {\n                    $img.remove();\n\n                    $.Fotorama.cache[src] = 'error';\n\n                    if ((!dataFrame.html || type !== 'stage') && dummy && dummy !== src) {\n                        dataFrame[srcKey] = src = dummy;\n                        frameData.$full = null;\n                        loadImg([index], type, specialMeasures, true);\n                    } else {\n                        if (src && !dataFrame.html && !fullFLAG) {\n                            $frame\n                                .trigger('f:error')\n                                .removeClass(loadingClass)\n                                .addClass(errorClass);\n\n                            triggerTriggerEvent('error');\n                        } else if (type === 'stage') {\n                            $frame\n                                .trigger('f:load')\n                                .removeClass(loadingClass + ' ' + errorClass)\n                                .addClass(loadedClass);\n\n                            triggerTriggerEvent('load');\n                            setMeasures();\n                        }\n\n                        frameData.state = 'error';\n\n                        if (size > 1 && data[index] === dataFrame && !dataFrame.html && !dataFrame.deleted && !dataFrame.video && !fullFLAG) {\n                            dataFrame.deleted = true;\n                            that.splice(index, 1);\n                        }\n                    }\n                }\n\n                function loaded() {\n                    $.Fotorama.measures[src] = imgData.measures = $.Fotorama.measures[src] || {\n                            width: img.width,\n                            height: img.height,\n                            ratio: img.width / img.height\n                        };\n\n                    setMeasures(imgData.measures.width, imgData.measures.height, imgData.measures.ratio, index);\n\n                    $img\n                        .off('load error')\n                        .addClass('' + (fullFLAG ? imgFullClass: imgClass))\n                        .attr('aria-hidden', 'false')\n                        .prependTo($frame);\n\n                    if ($frame.hasClass(stageFrameClass) && !$frame.hasClass(videoContainerClass)) {\n                        $frame.attr(\"href\", $img.attr(\"src\"));\n                    }\n\n                    fit($img, (\n                            $.isFunction(specialMeasures) ? specialMeasures() : specialMeasures) || measures);\n\n                    $.Fotorama.cache[src] = frameData.state = 'loaded';\n\n                    setTimeout(function () {\n                        $frame\n                            .trigger('f:load')\n                            .removeClass(loadingClass + ' ' + errorClass)\n                            .addClass(loadedClass + ' ' + (fullFLAG ? loadedFullClass : loadedImgClass));\n\n                        if (type === 'stage') {\n                            triggerTriggerEvent('load');\n                        } else if (dataFrame.thumbratio === AUTO || !dataFrame.thumbratio && opts.thumbratio === AUTO) {\n                            // danger! reflow for all thumbnails\n                            dataFrame.thumbratio = imgData.measures.ratio;\n                            reset();\n                        }\n                    }, 0);\n                }\n\n                if (!src) {\n                    error();\n                    return;\n                }\n\n                function waitAndLoad() {\n                    var _i = 10;\n                    waitFor(function () {\n                        return !touchedFLAG || !_i-- && !SLOW;\n                    }, function () {\n                        loaded();\n                    });\n                }\n\n                if (!$.Fotorama.cache[src]) {\n                    $.Fotorama.cache[src] = '*';\n\n                    $img\n                        .on('load', waitAndLoad)\n                        .on('error', error);\n                } else {\n                    (function justWait() {\n                        if ($.Fotorama.cache[src] === 'error') {\n                            error();\n                        } else if ($.Fotorama.cache[src] === 'loaded') {\n                            setTimeout(waitAndLoad, 0);\n                        } else {\n                            setTimeout(justWait, 100);\n                        }\n                    })();\n                }\n\n                frameData.state = '';\n                img.src = src;\n\n                if (frameData.data.caption) {\n                    img.alt = frameData.data.caption || \"\";\n                }\n\n                if (frameData.data.full) {\n                    $(img).data('original', frameData.data.full);\n                }\n\n                if (UTIL.isExpectedCaption(dataFrame, opts.showcaption)) {\n                    $(img).attr('aria-labelledby', dataFrame.labelledby);\n                }\n            });\n        }\n\n        function updateFotoramaState() {\n            var $frame = activeFrame[STAGE_FRAME_KEY];\n\n            if ($frame && !$frame.data().state) {\n                $spinner.addClass(spinnerShowClass);\n                $frame.on('f:load f:error', function () {\n                    $frame.off('f:load f:error');\n                    $spinner.removeClass(spinnerShowClass);\n                });\n            }\n        }\n\n        function addNavFrameEvents(frame) {\n            addEnterUp(frame, onNavFrameClick);\n            addFocus(frame, function () {\n\n                setTimeout(function () {\n                    lockScroll($nav);\n                }, 0);\n                slideNavShaft({time: o_transitionDuration, guessIndex: $(this).data().eq, minMax: navShaftTouchTail});\n            });\n        }\n\n        function frameDraw(indexes, type) {\n            eachIndex(indexes, type, function (i, index, dataFrame, $frame, key, frameData) {\n                if ($frame) return;\n\n                $frame = dataFrame[key] = $wrap[key].clone();\n                frameData = $frame.data();\n                frameData.data = dataFrame;\n                var frame = $frame[0],\n                    labelledbyValue = \"labelledby\" + $.now();\n\n                if (type === 'stage') {\n\n                    if (dataFrame.html) {\n                        $('<div class=\"' + htmlClass + '\"></div>')\n                            .append(\n                            dataFrame._html ? $(dataFrame.html)\n                                .removeAttr('id')\n                                .html(dataFrame._html) // Because of IE\n                                : dataFrame.html\n                        )\n                            .appendTo($frame);\n                    }\n\n                    if (dataFrame.id) {\n                        labelledbyValue = dataFrame.id || labelledbyValue;\n                    }\n                    dataFrame.labelledby = labelledbyValue;\n\n                    if (UTIL.isExpectedCaption(dataFrame, opts.showcaption)) {\n                        $($.Fotorama.jst.frameCaption({\n                            caption: dataFrame.caption,\n                            labelledby: labelledbyValue\n                        })).appendTo($frame);\n                    }\n\n                    dataFrame.video && $frame\n                        .addClass(stageFrameVideoClass)\n                        .append($videoPlay.clone());\n\n                    // This solves tabbing problems\n                    addFocus(frame, function (e) {\n                        setTimeout(function () {\n                            lockScroll($stage);\n                        }, 0);\n                        clickToShow({index: frameData.eq, user: true}, e);\n                    });\n\n                    $stageFrame = $stageFrame.add($frame);\n                } else if (type === 'navDot') {\n                    addNavFrameEvents(frame);\n                    $navDotFrame = $navDotFrame.add($frame);\n                } else if (type === 'navThumb') {\n                    addNavFrameEvents(frame);\n                    frameData.$wrap = $frame.children(':first');\n\n                    $navThumbFrame = $navThumbFrame.add($frame);\n                    if (dataFrame.video) {\n                        frameData.$wrap.append($videoPlay.clone());\n                    }\n                }\n            });\n        }\n\n        function callFit($img, measuresToFit) {\n            return $img && $img.length && fit($img, measuresToFit);\n        }\n\n        function stageFramePosition(indexes) {\n            eachIndex(indexes, 'stage', function (i, index, dataFrame, $frame, key, frameData) {\n                if (!$frame) return;\n\n                var normalizedIndex = normalizeIndex(index);\n                frameData.eq = normalizedIndex;\n\n                toDetach[STAGE_FRAME_KEY][normalizedIndex] = $frame.css($.extend({left: o_fade ? 0 : getPosByIndex(index, measures.w, opts.margin, repositionIndex)}, o_fade && getDuration(0)));\n\n                if (isDetached($frame[0])) {\n                    $frame.appendTo($stageShaft);\n                    unloadVideo(dataFrame.$video);\n                }\n\n                callFit(frameData.$img, measures);\n                callFit(frameData.$full, measures);\n\n                if ($frame.hasClass(stageFrameClass) && !($frame.attr('aria-hidden') === \"false\" && $frame.hasClass(activeClass))) {\n                    $frame.attr('aria-hidden', 'true');\n                }\n            });\n        }\n\n        function thumbsDraw(pos, loadFLAG) {\n            var leftLimit,\n                rightLimit,\n                exceedLimit;\n\n\n            if (o_nav !== 'thumbs' || isNaN(pos)) return;\n\n            leftLimit = -pos;\n            rightLimit = -pos + measures.nw;\n\n            if (opts.navdir === 'vertical') {\n                pos = pos - opts.thumbheight;\n                rightLimit = -pos + measures.h;\n            }\n\n            $navThumbFrame.each(function () {\n                var $this = $(this),\n                    thisData = $this.data(),\n                    eq = thisData.eq,\n                    getSpecialMeasures = function () {\n                        return {\n                            h: o_thumbSide2,\n                            w: thisData.w\n                        }\n                    },\n                    specialMeasures = getSpecialMeasures(),\n                    exceedLimit = opts.navdir === 'vertical' ?\n                    thisData.t > rightLimit : thisData.l > rightLimit;\n                specialMeasures.w = thisData.w;\n\n                if ((opts.navdir !== 'vertical' && thisData.l + thisData.w < leftLimit)\n                    || exceedLimit\n                    || callFit(thisData.$img, specialMeasures)) return;\n\n                loadFLAG && loadImg([eq], 'navThumb', getSpecialMeasures);\n            });\n        }\n\n        function frameAppend($frames, $shaft, type) {\n            if (!frameAppend[type]) {\n\n                var thumbsFLAG = type === 'nav' && o_navThumbs,\n                    left = 0,\n                    top = 0;\n\n                $shaft.append(\n                    $frames\n                        .filter(function () {\n                            var actual,\n                                $this = $(this),\n                                frameData = $this.data();\n                            for (var _i = 0, _l = data.length; _i < _l; _i++) {\n                                if (frameData.data === data[_i]) {\n                                    actual = true;\n                                    frameData.eq = _i;\n                                    break;\n                                }\n                            }\n                            return actual || $this.remove() && false;\n                        })\n                        .sort(function (a, b) {\n                            return $(a).data().eq - $(b).data().eq;\n                        })\n                        .each(function () {\n                            var $this = $(this),\n                                frameData = $this.data();\n                            UTIL.setThumbAttr($this, frameData.data.caption, \"aria-label\");\n                        })\n                        .each(function () {\n\n                            if (!thumbsFLAG) return;\n\n                            var $this = $(this),\n                                frameData = $this.data(),\n                                thumbwidth = Math.round(o_thumbSide2 * frameData.data.thumbratio) || o_thumbSide,\n                                thumbheight = Math.round(o_thumbSide / frameData.data.thumbratio) || o_thumbSide2;\n                            frameData.t = top;\n                            frameData.h = thumbheight;\n                            frameData.l = left;\n                            frameData.w = thumbwidth;\n\n                            $this.css({width: thumbwidth});\n\n                            top += thumbheight + opts.thumbmargin;\n                            left += thumbwidth + opts.thumbmargin;\n                        })\n                );\n\n                frameAppend[type] = true;\n            }\n        }\n\n        function getDirection(x) {\n            return x - stageLeft > measures.w / 3;\n        }\n\n        function disableDirrection(i) {\n            return !o_loop && (!(activeIndex + i) || !(activeIndex - size + i)) && !$videoPlaying;\n        }\n\n        function arrsUpdate() {\n            var disablePrev = disableDirrection(0),\n                disableNext = disableDirrection(1);\n            $arrPrev\n                .toggleClass(arrDisabledClass, disablePrev)\n                .attr(disableAttr(disablePrev, false));\n            $arrNext\n                .toggleClass(arrDisabledClass, disableNext)\n                .attr(disableAttr(disableNext, false));\n        }\n\n        function thumbArrUpdate() {\n            var isLeftDisable = false,\n                isRightDisable = false;\n            if (opts.navtype === 'thumbs' && !opts.loop) {\n                (activeIndex == 0) ? isLeftDisable = true : isLeftDisable = false;\n                (activeIndex == opts.data.length - 1) ? isRightDisable = true : isRightDisable = false;\n            }\n            if (opts.navtype === 'slides') {\n                var pos = readPosition($navShaft, opts.navdir);\n                pos >= navShaftTouchTail.max ? isLeftDisable = true : isLeftDisable = false;\n                pos <= Math.round(navShaftTouchTail.min) ? isRightDisable = true : isRightDisable = false;\n            }\n            $thumbArrLeft\n                .toggleClass(arrDisabledClass, isLeftDisable)\n                .attr(disableAttr(isLeftDisable, true));\n            $thumbArrRight\n                .toggleClass(arrDisabledClass, isRightDisable)\n                .attr(disableAttr(isRightDisable, true));\n        }\n\n        function stageWheelUpdate() {\n            if (stageWheelTail.ok) {\n                stageWheelTail.prevent = {'<': disableDirrection(0), '>': disableDirrection(1)};\n            }\n        }\n\n        function getNavFrameBounds($navFrame) {\n            var navFrameData = $navFrame.data(),\n                left,\n                top,\n                width,\n                height;\n\n            if (o_navThumbs) {\n                left = navFrameData.l;\n                top = navFrameData.t;\n                width = navFrameData.w;\n                height = navFrameData.h;\n            } else {\n                left = $navFrame.position().left;\n                width = $navFrame.width();\n            }\n\n            var horizontalBounds = {\n                c: left + width / 2,\n                min: -left + opts.thumbmargin * 10,\n                max: -left + measures.w - width - opts.thumbmargin * 10\n            };\n\n            var verticalBounds = {\n                c: top + height / 2,\n                min: -top + opts.thumbmargin * 10,\n                max: -top + measures.h - height - opts.thumbmargin * 10\n            };\n\n            return opts.navdir === 'vertical' ? verticalBounds : horizontalBounds;\n        }\n\n        function slideThumbBorder(time) {\n            var navFrameData = activeFrame[navFrameKey].data();\n            slide($thumbBorder, {\n                time: time * 1.2,\n                pos: (opts.navdir === 'vertical' ? navFrameData.t : navFrameData.l),\n                width: navFrameData.w,\n                height: navFrameData.h,\n                direction: opts.navdir\n            });\n        }\n\n        function slideNavShaft(options) {\n            var $guessNavFrame = data[options.guessIndex][navFrameKey],\n                typeOfAnimation = opts.navtype;\n\n            var overflowFLAG,\n                time,\n                minMax,\n                boundTop,\n                boundLeft,\n                l,\n                pos,\n                x;\n\n            if ($guessNavFrame) {\n                if (typeOfAnimation === 'thumbs') {\n                    overflowFLAG = navShaftTouchTail.min !== navShaftTouchTail.max;\n                    minMax = options.minMax || overflowFLAG && getNavFrameBounds(activeFrame[navFrameKey]);\n                    boundTop = overflowFLAG && (options.keep && slideNavShaft.t ? slideNavShaft.l : minMaxLimit((options.coo || measures.nw / 2) - getNavFrameBounds($guessNavFrame).c, minMax.min, minMax.max));\n                    boundLeft = overflowFLAG && (options.keep && slideNavShaft.l ? slideNavShaft.l : minMaxLimit((options.coo || measures.nw / 2) - getNavFrameBounds($guessNavFrame).c, minMax.min, minMax.max));\n                    l = (opts.navdir === 'vertical' ? boundTop : boundLeft);\n                    pos = overflowFLAG && minMaxLimit(l, navShaftTouchTail.min, navShaftTouchTail.max) || 0;\n                    time = options.time * 1.1;\n                    slide($navShaft, {\n                        time: time,\n                        pos: pos,\n                        direction: opts.navdir,\n                        onEnd: function () {\n                            thumbsDraw(pos, true);\n                            thumbArrUpdate();\n                        }\n                    });\n\n                    setShadow($nav, findShadowEdge(pos, navShaftTouchTail.min, navShaftTouchTail.max, opts.navdir));\n                    slideNavShaft.l = l;\n                } else {\n                    x = readPosition($navShaft, opts.navdir);\n                    time = options.time * 1.11;\n\n                    pos = validateSlidePos(opts, navShaftTouchTail, options.guessIndex, x, $guessNavFrame, $navWrap, opts.navdir);\n\n                    slide($navShaft, {\n                        time: time,\n                        pos: pos,\n                        direction: opts.navdir,\n                        onEnd: function () {\n                            thumbsDraw(pos, true);\n                            thumbArrUpdate();\n                        }\n                    });\n                    setShadow($nav, findShadowEdge(pos, navShaftTouchTail.min, navShaftTouchTail.max, opts.navdir));\n                }\n            }\n        }\n\n        function navUpdate() {\n            deactivateFrames(navFrameKey);\n            toDeactivate[navFrameKey].push(activeFrame[navFrameKey].addClass(activeClass).attr('data-active', true));\n        }\n\n        function deactivateFrames(key) {\n            var _toDeactivate = toDeactivate[key];\n\n            while (_toDeactivate.length) {\n                _toDeactivate.shift().removeClass(activeClass).attr('data-active', false);\n            }\n        }\n\n        function detachFrames(key) {\n            var _toDetach = toDetach[key];\n\n            $.each(activeIndexes, function (i, index) {\n                delete _toDetach[normalizeIndex(index)];\n            });\n\n            $.each(_toDetach, function (index, $frame) {\n                delete _toDetach[index];\n                $frame.detach();\n            });\n        }\n\n        function stageShaftReposition(skipOnEnd) {\n\n            repositionIndex = dirtyIndex = activeIndex;\n\n            var $frame = activeFrame[STAGE_FRAME_KEY];\n\n            if ($frame) {\n                deactivateFrames(STAGE_FRAME_KEY);\n                toDeactivate[STAGE_FRAME_KEY].push($frame.addClass(activeClass).attr('data-active', true));\n\n                if ($frame.hasClass(stageFrameClass)) {\n                    $frame.attr('aria-hidden', 'false');\n                }\n\n                skipOnEnd || that.showStage.onEnd(true);\n                stop($stageShaft, 0, true);\n\n                detachFrames(STAGE_FRAME_KEY);\n                stageFramePosition(activeIndexes);\n                setStageShaftMinmaxAndSnap();\n                setNavShaftMinMax();\n                addEnterUp($stageShaft[0], function () {\n                    if (!$fotorama.hasClass(fullscreenClass)) {\n                        that.requestFullScreen();\n                        $fullscreenIcon.focus();\n                    }\n                });\n            }\n        }\n\n        function extendMeasures(options, measuresArray) {\n            if (!options) return;\n\n            $.each(measuresArray, function (i, measures) {\n                if (!measures) return;\n\n                $.extend(measures, {\n                    width: options.width || measures.width,\n                    height: options.height,\n                    minwidth: options.minwidth,\n                    maxwidth: options.maxwidth,\n                    minheight: options.minheight,\n                    maxheight: options.maxheight,\n                    ratio: getRatio(options.ratio)\n                })\n            });\n        }\n\n        function triggerEvent(event, extra) {\n            $fotorama.trigger(_fotoramaClass + ':' + event, [that, extra]);\n        }\n\n        function onTouchStart() {\n            clearTimeout(onTouchEnd.t);\n            touchedFLAG = 1;\n\n            if (opts.stopautoplayontouch) {\n                that.stopAutoplay();\n            } else {\n                pausedAutoplayFLAG = true;\n            }\n        }\n\n        function onTouchEnd() {\n            if (!touchedFLAG) return;\n            if (!opts.stopautoplayontouch) {\n                releaseAutoplay();\n                changeAutoplay();\n            }\n\n            onTouchEnd.t = setTimeout(function () {\n                touchedFLAG = 0;\n            }, TRANSITION_DURATION + TOUCH_TIMEOUT);\n        }\n\n        function releaseAutoplay() {\n            pausedAutoplayFLAG = !!($videoPlaying || stoppedAutoplayFLAG);\n        }\n\n        function changeAutoplay() {\n\n            clearTimeout(changeAutoplay.t);\n            waitFor.stop(changeAutoplay.w);\n\n            if (!opts.autoplay || pausedAutoplayFLAG) {\n                if (that.autoplay) {\n                    that.autoplay = false;\n                    triggerEvent('stopautoplay');\n                }\n\n                return;\n            }\n\n            if (!that.autoplay) {\n                that.autoplay = true;\n                triggerEvent('startautoplay');\n            }\n\n            var _activeIndex = activeIndex;\n\n\n            var frameData = activeFrame[STAGE_FRAME_KEY].data();\n            changeAutoplay.w = waitFor(function () {\n                return frameData.state || _activeIndex !== activeIndex;\n            }, function () {\n                changeAutoplay.t = setTimeout(function () {\n\n                    if (pausedAutoplayFLAG || _activeIndex !== activeIndex) return;\n\n                    var _nextAutoplayIndex = nextAutoplayIndex,\n                        nextFrameData = data[_nextAutoplayIndex][STAGE_FRAME_KEY].data();\n\n                    changeAutoplay.w = waitFor(function () {\n\n                        return nextFrameData.state || _nextAutoplayIndex !== nextAutoplayIndex;\n                    }, function () {\n                        if (pausedAutoplayFLAG || _nextAutoplayIndex !== nextAutoplayIndex) return;\n                        that.show(o_loop ? getDirectionSign(!o_rtl) : nextAutoplayIndex);\n                    });\n                }, opts.autoplay);\n            });\n\n        }\n\n        that.startAutoplay = function (interval) {\n            if (that.autoplay) return this;\n            pausedAutoplayFLAG = stoppedAutoplayFLAG = false;\n            setAutoplayInterval(interval || opts.autoplay);\n            changeAutoplay();\n\n            return this;\n        };\n\n        that.stopAutoplay = function () {\n            if (that.autoplay) {\n                pausedAutoplayFLAG = stoppedAutoplayFLAG = true;\n                changeAutoplay();\n            }\n            return this;\n        };\n\n        that.showSlide = function (slideDir) {\n            var currentPosition = readPosition($navShaft, opts.navdir),\n                pos,\n                time = 500 * 1.1,\n                size = opts.navdir === 'horizontal' ? opts.thumbwidth : opts.thumbheight,\n                onEnd = function () {\n                    thumbArrUpdate();\n                };\n            if (slideDir === 'next') {\n                pos = currentPosition - (size + opts.margin) * thumbsPerSlide;\n            }\n            if (slideDir === 'prev') {\n                pos = currentPosition + (size + opts.margin) * thumbsPerSlide;\n            }\n            pos = validateRestrictions(pos, navShaftTouchTail);\n            thumbsDraw(pos, true);\n            slide($navShaft, {\n                time: time,\n                pos: pos,\n                direction: opts.navdir,\n                onEnd: onEnd\n            });\n        };\n\n        that.showWhileLongPress = function (options) {\n            if (that.longPress.singlePressInProgress) {\n                return;\n            }\n\n            var index = calcActiveIndex(options);\n            calcGlobalIndexes(index);\n            var time = calcTime(options) / 50;\n            var _activeFrame = activeFrame;\n            that.activeFrame = activeFrame = data[activeIndex];\n            var silent = _activeFrame === activeFrame && !options.user;\n\n            that.showNav(silent, options, time);\n\n            return this;\n        };\n\n        that.showEndLongPress = function (options) {\n            if (that.longPress.singlePressInProgress) {\n                return;\n            }\n\n            var index = calcActiveIndex(options);\n            calcGlobalIndexes(index);\n            var time = calcTime(options) / 50;\n            var _activeFrame = activeFrame;\n            that.activeFrame = activeFrame = data[activeIndex];\n\n            var silent = _activeFrame === activeFrame && !options.user;\n\n            that.showStage(silent, options, time);\n\n            showedFLAG = typeof lastActiveIndex !== 'undefined' && lastActiveIndex !== activeIndex;\n            lastActiveIndex = activeIndex;\n            return this;\n        };\n\n        function calcActiveIndex (options) {\n            var index;\n\n            if (typeof options !== 'object') {\n                index = options;\n                options = {};\n            } else {\n                index = options.index;\n            }\n\n            index = index === '>' ? dirtyIndex + 1 : index === '<' ? dirtyIndex - 1 : index === '<<' ? 0 : index === '>>' ? size - 1 : index;\n            index = isNaN(index) ? undefined : index;\n            index = typeof index === 'undefined' ? activeIndex || 0 : index;\n\n            return index;\n        }\n\n        function calcGlobalIndexes (index) {\n            that.activeIndex = activeIndex = edgeIndex(index);\n            prevIndex = getPrevIndex(activeIndex);\n            nextIndex = getNextIndex(activeIndex);\n            nextAutoplayIndex = normalizeIndex(activeIndex + (o_rtl ? -1 : 1));\n            activeIndexes = [activeIndex, prevIndex, nextIndex];\n\n            dirtyIndex = o_loop ? index : activeIndex;\n        }\n\n        function calcTime (options) {\n            var diffIndex = Math.abs(lastActiveIndex - dirtyIndex),\n                time = getNumber(options.time, function () {\n                    return Math.min(o_transitionDuration * (1 + (diffIndex - 1) / 12), o_transitionDuration * 2);\n                });\n\n            if (options.slow) {\n                time *= 10;\n            }\n\n            return time;\n        }\n\n        that.showStage = function (silent, options, time, e) {\n            if (e !== undefined && e.target.tagName == 'IFRAME') {\n                return;\n            }\n            unloadVideo($videoPlaying, activeFrame.i !== data[normalizeIndex(repositionIndex)].i);\n            frameDraw(activeIndexes, 'stage');\n            stageFramePosition(SLOW ? [dirtyIndex] : [dirtyIndex, getPrevIndex(dirtyIndex), getNextIndex(dirtyIndex)]);\n            updateTouchTails('go', true);\n\n            silent || triggerEvent('show', {\n                user: options.user,\n                time: time\n            });\n\n            pausedAutoplayFLAG = true;\n\n            var overPos = options.overPos;\n            var onEnd = that.showStage.onEnd = function (skipReposition) {\n                if (onEnd.ok) return;\n                onEnd.ok = true;\n\n                skipReposition || stageShaftReposition(true);\n\n                if (!silent) {\n                    triggerEvent('showend', {\n                        user: options.user\n                    });\n                }\n\n                if (!skipReposition && o_transition && o_transition !== opts.transition) {\n                    that.setOptions({transition: o_transition});\n                    o_transition = false;\n                    return;\n                }\n\n                updateFotoramaState();\n                loadImg(activeIndexes, 'stage');\n\n                updateTouchTails('go', false);\n                stageWheelUpdate();\n\n                stageCursor();\n                releaseAutoplay();\n                changeAutoplay();\n\n                if (that.fullScreen) {\n                    activeFrame[STAGE_FRAME_KEY].find('.' + imgFullClass).attr('aria-hidden', false);\n                    activeFrame[STAGE_FRAME_KEY].find('.' + imgClass).attr('aria-hidden', true)\n                } else {\n                    activeFrame[STAGE_FRAME_KEY].find('.' + imgFullClass).attr('aria-hidden', true);\n                    activeFrame[STAGE_FRAME_KEY].find('.' + imgClass).attr('aria-hidden', false)\n                }\n            };\n\n            if (!o_fade) {\n                slide($stageShaft, {\n                    pos: -getPosByIndex(dirtyIndex, measures.w, opts.margin, repositionIndex),\n                    overPos: overPos,\n                    time: time,\n                    onEnd: onEnd\n                });\n            } else {\n                var $activeFrame = activeFrame[STAGE_FRAME_KEY],\n                    $prevActiveFrame = data[lastActiveIndex] && activeIndex !== lastActiveIndex ? data[lastActiveIndex][STAGE_FRAME_KEY] : null;\n\n                fade($activeFrame, $prevActiveFrame, $stageFrame, {\n                    time: time,\n                    method: opts.transition,\n                    onEnd: onEnd\n                }, fadeStack);\n            }\n\n            arrsUpdate();\n        };\n\n        that.showNav = function(silent, options, time){\n            thumbArrUpdate();\n            if (o_nav) {\n                navUpdate();\n\n                var guessIndex = limitIndex(activeIndex + minMaxLimit(dirtyIndex - lastActiveIndex, -1, 1));\n                slideNavShaft({\n                    time: time,\n                    coo: guessIndex !== activeIndex && options.coo,\n                    guessIndex: typeof options.coo !== 'undefined' ? guessIndex : activeIndex,\n                    keep: silent\n                });\n                if (o_navThumbs) slideThumbBorder(time);\n            }\n        };\n\n        that.show = function (options, e) {\n            that.longPress.singlePressInProgress = true;\n\n            var index = calcActiveIndex(options);\n            calcGlobalIndexes(index);\n            var time = calcTime(options);\n            var _activeFrame = activeFrame;\n            that.activeFrame = activeFrame = data[activeIndex];\n\n            var silent = _activeFrame === activeFrame && !options.user;\n\n            that.showStage(silent, options, time, e);\n            that.showNav(silent, options, time);\n\n            showedFLAG = typeof lastActiveIndex !== 'undefined' && lastActiveIndex !== activeIndex;\n            lastActiveIndex = activeIndex;\n            that.longPress.singlePressInProgress = false;\n\n            return this;\n        };\n\n        that.requestFullScreen = function () {\n            if (o_allowFullScreen && !that.fullScreen) {\n\n                //check that this is not video\n                if(isVideo()) {\n                    return;\n                }\n\n                scrollTop = $WINDOW.scrollTop();\n                scrollLeft = $WINDOW.scrollLeft();\n\n                lockScroll($WINDOW);\n\n                updateTouchTails('x', true);\n\n                measuresStash = $.extend({}, measures);\n\n                $fotorama\n                    .addClass(fullscreenClass)\n                    .appendTo($BODY.addClass(_fullscreenClass));\n\n                $HTML.addClass(_fullscreenClass);\n\n                unloadVideo($videoPlaying, true, true);\n\n                that.fullScreen = true;\n\n                if (o_nativeFullScreen) {\n                    fullScreenApi.request(fotorama);\n                }\n\n                loadImg(activeIndexes, 'stage');\n                updateFotoramaState();\n                triggerEvent('fullscreenenter');\n                that.resize();\n\n                if (!('ontouchstart' in window)) {\n                    $fullscreenIcon.focus();\n                }\n            }\n\n            return this;\n        };\n\n        function cancelFullScreen() {\n            if (that.fullScreen) {\n                that.fullScreen = false;\n\n                if (FULLSCREEN) {\n                    fullScreenApi.cancel(fotorama);\n                }\n\n                $BODY.removeClass(_fullscreenClass);\n                $HTML.removeClass(_fullscreenClass);\n\n                $fotorama\n                    .removeClass(fullscreenClass)\n                    .insertAfter($anchor);\n\n                measures = $.extend({}, measuresStash);\n\n                unloadVideo($videoPlaying, true, true);\n\n                updateTouchTails('x', false);\n\n                that.resize();\n                loadImg(activeIndexes, 'stage');\n\n                lockScroll($WINDOW, scrollLeft, scrollTop);\n\n                triggerEvent('fullscreenexit');\n            }\n        }\n\n        that.cancelFullScreen = function () {\n            if (o_nativeFullScreen && fullScreenApi.is()) {\n                fullScreenApi.cancel(document);\n            } else {\n                cancelFullScreen();\n            }\n\n            return this;\n        };\n\n        that.toggleFullScreen = function () {\n            return that[(that.fullScreen ? 'cancel' : 'request') + 'FullScreen']();\n        };\n\n        that.resize = function (options) {\n            if (!data) return this;\n\n            var time = arguments[1] || 0,\n                setFLAG = arguments[2];\n\n            thumbsPerSlide = getThumbsInSlide($wrap, opts);\n            extendMeasures(!that.fullScreen ? optionsToLowerCase(options) : {\n                width: $(window).width(),\n                maxwidth: null,\n                minwidth: null,\n                height: $(window).height(),\n                maxheight: null,\n                minheight: null\n            }, [measures, setFLAG || that.fullScreen || opts]);\n\n            var width = measures.width,\n                height = measures.height,\n                ratio = measures.ratio,\n                windowHeight = $WINDOW.height() - (o_nav ? $nav.height() : 0);\n\n            if (measureIsValid(width)) {\n                $wrap.css({width: ''});\n                $stage.css({width: ''});\n                $stageShaft.css({width: ''});\n                $nav.css({width: ''});\n                $wrap.css({minWidth: measures.minwidth || 0, maxWidth: measures.maxwidth || MAX_WIDTH});\n\n                if (o_nav === 'dots') {\n                    $navWrap.hide();\n                }\n                width = measures.W = measures.w = $wrap.width();\n                measures.nw = o_nav && numberFromWhatever(opts.navwidth, width) || width;\n\n                $stageShaft.css({width: measures.w, marginLeft: (measures.W - measures.w) / 2});\n\n                height = numberFromWhatever(height, windowHeight);\n\n                height = height || (ratio && width / ratio);\n\n                if (height) {\n                    width = Math.round(width);\n                    height = measures.h = Math.round(minMaxLimit(height, numberFromWhatever(measures.minheight, windowHeight), numberFromWhatever(measures.maxheight, windowHeight)));\n                    $stage.css({'width': width, 'height': height});\n\n                    if (opts.navdir === 'vertical' && !that.fullscreen) {\n                        $nav.width(opts.thumbwidth + opts.thumbmargin * 2);\n                    }\n\n                    if (opts.navdir === 'horizontal' && !that.fullscreen) {\n                        $nav.height(opts.thumbheight + opts.thumbmargin * 2);\n                    }\n\n                    if (o_nav === 'dots') {\n                        $nav.width(width)\n                            .height('auto');\n                        $navWrap.show();\n                    }\n\n                    if (opts.navdir === 'vertical' && that.fullScreen) {\n                        $stage.css('height', $WINDOW.height());\n                    }\n\n                    if (opts.navdir === 'horizontal' && that.fullScreen) {\n                        $stage.css('height', $WINDOW.height() - $nav.height());\n                    }\n\n                    if (o_nav) {\n                        switch (opts.navdir) {\n                            case 'vertical':\n                                $navWrap.removeClass(navShafthorizontalClass);\n                                $navWrap.removeClass(navShaftListClass);\n                                $navWrap.addClass(navShaftVerticalClass);\n                                $nav\n                                    .stop()\n                                    .animate({height: measures.h, width: opts.thumbwidth}, time);\n                                break;\n                            case 'list':\n                                $navWrap.removeClass(navShaftVerticalClass);\n                                $navWrap.removeClass(navShafthorizontalClass);\n                                $navWrap.addClass(navShaftListClass);\n                                break;\n                            default:\n                                $navWrap.removeClass(navShaftVerticalClass);\n                                $navWrap.removeClass(navShaftListClass);\n                                $navWrap.addClass(navShafthorizontalClass);\n                                $nav\n                                    .stop()\n                                    .animate({width: measures.nw}, time);\n                                break;\n                        }\n\n                        stageShaftReposition();\n                        slideNavShaft({guessIndex: activeIndex, time: time, keep: true});\n                        if (o_navThumbs && frameAppend.nav) slideThumbBorder(time);\n                    }\n\n                    measuresSetFLAG = setFLAG || true;\n\n                    ready.ok = true;\n                    ready();\n                }\n            }\n\n            stageLeft = $stage.offset().left;\n            setStagePosition();\n\n            return this;\n        };\n\n        that.setOptions = function (options) {\n            $.extend(opts, options);\n            reset();\n            return this;\n        };\n\n        that.shuffle = function () {\n            data && shuffle(data) && reset();\n            return this;\n        };\n\n        function setShadow($el, edge) {\n            if (o_shadows) {\n                $el.removeClass(shadowsLeftClass + ' ' + shadowsRightClass);\n                $el.removeClass(shadowsTopClass + ' ' + shadowsBottomClass);\n                edge && !$videoPlaying && $el.addClass(edge.replace(/^|\\s/g, ' ' + shadowsClass + '--'));\n            }\n        }\n\n        that.longPress = {\n            threshold: 1,\n            count: 0,\n            thumbSlideTime: 20,\n            progress: function(){\n                if (!this.inProgress) {\n                    this.count++;\n                    this.inProgress = this.count > this.threshold;\n                }\n            },\n            end: function(){\n                if(this.inProgress) {\n                    this.isEnded = true\n                }\n            },\n            reset: function(){\n                this.count = 0;\n                this.inProgress = false;\n                this.isEnded = false;\n            }\n        };\n\n        that.destroy = function () {\n            that.cancelFullScreen();\n            that.stopAutoplay();\n\n            data = that.data = null;\n\n            appendElements();\n\n            activeIndexes = [];\n            detachFrames(STAGE_FRAME_KEY);\n\n            reset.ok = false;\n\n            return this;\n        };\n\n        /**\n         *\n         * @returns {jQuery.Fotorama}\n         */\n        that.playVideo = function () {\n            var dataFrame = activeFrame,\n                video = dataFrame.video,\n                _activeIndex = activeIndex;\n\n            if (typeof video === 'object' && dataFrame.videoReady) {\n                o_nativeFullScreen && that.fullScreen && that.cancelFullScreen();\n\n                waitFor(function () {\n                    return !fullScreenApi.is() || _activeIndex !== activeIndex;\n                }, function () {\n                    if (_activeIndex === activeIndex) {\n                        dataFrame.$video = dataFrame.$video || $(div(videoClass)).append(createVideoFrame(video));\n                        dataFrame.$video.appendTo(dataFrame[STAGE_FRAME_KEY]);\n\n                        $wrap.addClass(wrapVideoClass);\n                        $videoPlaying = dataFrame.$video;\n\n                        stageNoMove();\n\n                        $arrs.blur();\n                        $fullscreenIcon.blur();\n\n                        triggerEvent('loadvideo');\n                    }\n                });\n            }\n\n            return this;\n        };\n\n        that.stopVideo = function () {\n            unloadVideo($videoPlaying, true, true);\n            return this;\n        };\n\n        that.spliceByIndex = function (index, newImgObj) {\n            newImgObj.i = index + 1;\n            newImgObj.img && $.ajax({\n                url: newImgObj.img,\n                type: 'HEAD',\n                success: function () {\n                    data.splice(index, 1, newImgObj);\n                    reset();\n                }\n            });\n        };\n\n        function unloadVideo($video, unloadActiveFLAG, releaseAutoplayFLAG) {\n            if (unloadActiveFLAG) {\n                $wrap.removeClass(wrapVideoClass);\n                $videoPlaying = false;\n\n                stageNoMove();\n            }\n\n            if ($video && $video !== $videoPlaying) {\n                $video.remove();\n                triggerEvent('unloadvideo');\n            }\n\n            if (releaseAutoplayFLAG) {\n                releaseAutoplay();\n                changeAutoplay();\n            }\n        }\n\n        function toggleControlsClass(FLAG) {\n            $wrap.toggleClass(wrapNoControlsClass, FLAG);\n        }\n\n        function stageCursor(e) {\n            if (stageShaftTouchTail.flow) return;\n\n            var x = e ? e.pageX : stageCursor.x,\n                pointerFLAG = x && !disableDirrection(getDirection(x)) && opts.click;\n\n            if (stageCursor.p !== pointerFLAG\n                && $stage.toggleClass(pointerClass, pointerFLAG)) {\n                stageCursor.p = pointerFLAG;\n                stageCursor.x = x;\n            }\n        }\n\n        $stage.on('mousemove', stageCursor);\n\n        function clickToShow(showOptions, e) {\n            clearTimeout(clickToShow.t);\n\n            if (opts.clicktransition && opts.clicktransition !== opts.transition) {\n                setTimeout(function () {\n                    var _o_transition = opts.transition;\n\n                    that.setOptions({transition: opts.clicktransition});\n\n                    // now safe to pass base transition to o_transition, so that.show will restor it\n                    o_transition = _o_transition;\n                    // this timeout is here to prevent jerking in some browsers\n                    clickToShow.t = setTimeout(function () {\n                        that.show(showOptions);\n                    }, 10);\n                }, 0);\n            } else {\n                that.show(showOptions, e);\n            }\n        }\n\n        function onStageTap(e, toggleControlsFLAG) {\n            var target = e.target,\n                $target = $(target);\n            if ($target.hasClass(videoPlayClass)) {\n                that.playVideo();\n            } else if (target === fullscreenIcon) {\n                that.toggleFullScreen();\n            } else if ($videoPlaying) {\n                target === videoClose && unloadVideo($videoPlaying, true, true);\n            } else if (!$fotorama.hasClass(fullscreenClass)) {\n                that.requestFullScreen();\n            }\n        }\n\n        function updateTouchTails(key, value) {\n            stageShaftTouchTail[key] = navShaftTouchTail[key] = value;\n        }\n\n        stageShaftTouchTail = moveOnTouch($stageShaft, {\n            onStart: onTouchStart,\n            onMove: function (e, result) {\n                setShadow($stage, result.edge);\n            },\n            onTouchEnd: onTouchEnd,\n            onEnd: function (result) {\n                var toggleControlsFLAG;\n\n                setShadow($stage);\n                toggleControlsFLAG = (MS_POINTER && !hoverFLAG || result.touch) &&\n                    opts.arrows;\n\n                if ((result.moved || (toggleControlsFLAG && result.pos !== result.newPos && !result.control)) && result.$target[0] !== $fullscreenIcon[0]) {\n                    var index = getIndexByPos(result.newPos, measures.w, opts.margin, repositionIndex);\n\n                    that.show({\n                        index: index,\n                        time: o_fade ? o_transitionDuration : result.time,\n                        overPos: result.overPos,\n                        user: true\n                    });\n                } else if (!result.aborted && !result.control) {\n                    onStageTap(result.startEvent, toggleControlsFLAG);\n                }\n            },\n            timeLow: 1,\n            timeHigh: 1,\n            friction: 2,\n            select: '.' + selectClass + ', .' + selectClass + ' *',\n            $wrap: $stage,\n            direction: 'horizontal'\n\n        });\n\n        navShaftTouchTail = moveOnTouch($navShaft, {\n            onStart: onTouchStart,\n            onMove: function (e, result) {\n                setShadow($nav, result.edge);\n            },\n            onTouchEnd: onTouchEnd,\n            onEnd: function (result) {\n\n                function onEnd() {\n                    slideNavShaft.l = result.newPos;\n                    releaseAutoplay();\n                    changeAutoplay();\n                    thumbsDraw(result.newPos, true);\n                    thumbArrUpdate();\n                }\n\n                if (!result.moved) {\n                    var target = result.$target.closest('.' + navFrameClass, $navShaft)[0];\n                    target && onNavFrameClick.call(target, result.startEvent);\n                } else if (result.pos !== result.newPos) {\n                    pausedAutoplayFLAG = true;\n                    slide($navShaft, {\n                        time: result.time,\n                        pos: result.newPos,\n                        overPos: result.overPos,\n                        direction: opts.navdir,\n                        onEnd: onEnd\n                    });\n                    thumbsDraw(result.newPos);\n                    o_shadows && setShadow($nav, findShadowEdge(result.newPos, navShaftTouchTail.min, navShaftTouchTail.max, result.dir));\n                } else {\n                    onEnd();\n                }\n            },\n            timeLow: .5,\n            timeHigh: 2,\n            friction: 5,\n            $wrap: $nav,\n            direction: opts.navdir\n        });\n\n        stageWheelTail = wheel($stage, {\n            shift: true,\n            onEnd: function (e, direction) {\n                onTouchStart();\n                onTouchEnd();\n                that.show({index: direction, slow: e.altKey})\n            }\n        });\n\n        navWheelTail = wheel($nav, {\n            onEnd: function (e, direction) {\n                onTouchStart();\n                onTouchEnd();\n                var newPos = stop($navShaft) + direction * .25;\n                $navShaft.css(getTranslate(minMaxLimit(newPos, navShaftTouchTail.min, navShaftTouchTail.max), opts.navdir));\n                o_shadows && setShadow($nav, findShadowEdge(newPos, navShaftTouchTail.min, navShaftTouchTail.max, opts.navdir));\n                navWheelTail.prevent = {'<': newPos >= navShaftTouchTail.max, '>': newPos <= navShaftTouchTail.min};\n                clearTimeout(navWheelTail.t);\n                navWheelTail.t = setTimeout(function () {\n                    slideNavShaft.l = newPos;\n                    thumbsDraw(newPos, true)\n                }, TOUCH_TIMEOUT);\n                thumbsDraw(newPos);\n            }\n        });\n\n        $wrap.hover(\n            function () {\n                setTimeout(function () {\n                    if (touchedFLAG) return;\n                    toggleControlsClass(!(hoverFLAG = true));\n                }, 0);\n            },\n            function () {\n                if (!hoverFLAG) return;\n                toggleControlsClass(!(hoverFLAG = false));\n            }\n        );\n\n        function onNavFrameClick(e) {\n            var index = $(this).data().eq;\n\n            if (opts.navtype === 'thumbs') {\n                clickToShow({index: index, slow: e.altKey, user: true, coo: e._x - $nav.offset().left});\n            } else {\n                clickToShow({index: index, slow: e.altKey, user: true});\n            }\n        }\n\n        function onArrClick(e) {\n            clickToShow({index: $arrs.index(this) ? '>' : '<', slow: e.altKey, user: true});\n        }\n\n        smartClick($arrs, function (e) {\n            stopEvent(e);\n            onArrClick.call(this, e);\n        }, {\n            onStart: function () {\n                onTouchStart();\n                stageShaftTouchTail.control = true;\n            },\n            onTouchEnd: onTouchEnd\n        });\n\n        smartClick($thumbArrLeft, function (e) {\n            stopEvent(e);\n            if (opts.navtype === 'thumbs') {\n\n                that.show('<');\n            } else {\n                that.showSlide('prev')\n            }\n        });\n\n        smartClick($thumbArrRight, function (e) {\n            stopEvent(e);\n            if (opts.navtype === 'thumbs') {\n                that.show('>');\n            } else {\n                that.showSlide('next')\n            }\n\n        });\n\n\n        function addFocusOnControls(el) {\n            addFocus(el, function () {\n                setTimeout(function () {\n                    lockScroll($stage);\n                }, 0);\n                toggleControlsClass(false);\n            });\n        }\n\n        $arrs.each(function () {\n            addEnterUp(this, function (e) {\n                onArrClick.call(this, e);\n            });\n            addFocusOnControls(this);\n        });\n\n        addEnterUp(fullscreenIcon, function () {\n            if ($fotorama.hasClass(fullscreenClass)) {\n                that.cancelFullScreen();\n                $stageShaft.focus();\n            } else {\n                that.requestFullScreen();\n                $fullscreenIcon.focus();\n            }\n\n        });\n        addFocusOnControls(fullscreenIcon);\n\n        function reset() {\n            setData();\n            setOptions();\n\n            if (!reset.i) {\n                reset.i = true;\n                // Only once\n                var _startindex = opts.startindex;\n                activeIndex = repositionIndex = dirtyIndex = lastActiveIndex = startIndex = edgeIndex(_startindex) || 0;\n                /*(o_rtl ? size - 1 : 0)*///;\n            }\n\n            if (size) {\n                if (changeToRtl()) return;\n\n                if ($videoPlaying) {\n                    unloadVideo($videoPlaying, true);\n                }\n\n                activeIndexes = [];\n\n                if (!isVideo()) {\n                    detachFrames(STAGE_FRAME_KEY);\n                }\n\n                reset.ok = true;\n\n                that.show({index: activeIndex, time: 0});\n                that.resize();\n            } else {\n                that.destroy();\n            }\n        }\n\n        function changeToRtl() {\n\n            if (!changeToRtl.f === o_rtl) {\n                changeToRtl.f = o_rtl;\n                activeIndex = size - 1 - activeIndex;\n                that.reverse();\n\n                return true;\n            }\n        }\n\n        $.each('load push pop shift unshift reverse sort splice'.split(' '), function (i, method) {\n            that[method] = function () {\n                data = data || [];\n                if (method !== 'load') {\n                    Array.prototype[method].apply(data, arguments);\n                } else if (arguments[0] && typeof arguments[0] === 'object' && arguments[0].length) {\n                    data = clone(arguments[0]);\n                }\n                reset();\n                return that;\n            }\n        });\n\n        function ready() {\n            if (ready.ok) {\n                ready.ok = false;\n                triggerEvent('ready');\n            }\n        }\n\n        reset();\n    };\n    $.fn.fotorama = function (opts) {\n        return this.each(function () {\n            var that = this,\n                $fotorama = $(this),\n                fotoramaData = $fotorama.data(),\n                fotorama = fotoramaData.fotorama;\n\n            if (!fotorama) {\n                waitFor(function () {\n                    return !isHidden(that);\n                }, function () {\n                    fotoramaData.urtext = $fotorama.html();\n                    new $.Fotorama($fotorama,\n                        $.extend(\n                            {},\n                            OPTIONS,\n                            window.fotoramaDefaults,\n                            opts,\n                            fotoramaData\n                        )\n                    );\n                });\n            } else {\n                fotorama.setOptions(opts, true);\n            }\n        });\n    };\n    $.Fotorama.instances = [];\n\n    function calculateIndexes() {\n        $.each($.Fotorama.instances, function (index, instance) {\n            instance.index = index;\n        });\n    }\n\n    function addInstance(instance) {\n        $.Fotorama.instances.push(instance);\n        calculateIndexes();\n    }\n\n    function hideInstance(instance) {\n        $.Fotorama.instances.splice(instance.index, 1);\n        calculateIndexes();\n    }\n\n    $.Fotorama.cache = {};\n    $.Fotorama.measures = {};\n    $ = $ || {};\n    $.Fotorama = $.Fotorama || {};\n    $.Fotorama.jst = $.Fotorama.jst || {};\n\n    $.Fotorama.jst.dots = function (v) {\n        var __t, __p = '', __e = _.escape;\n        __p += '<div class=\"fotorama__nav__frame fotorama__nav__frame--dot\" tabindex=\"0\" role=\"button\" data-gallery-role=\"nav-frame\" data-nav-type=\"thumb\" aria-label>\\r\\n    <div class=\"fotorama__dot\"></div>\\r\\n</div>';\n        return __p\n    };\n\n    $.Fotorama.jst.frameCaption = function (v) {\n        var __t, __p = '', __e = _.escape;\n        __p += '<div class=\"fotorama__caption\" aria-hidden=\"true\">\\r\\n    <div class=\"fotorama__caption__wrap\" id=\"' +\n            ((__t = ( v.labelledby )) == null ? '' : __t) +\n            '\">' +\n            ((__t = ( v.caption )) == null ? '' : __t) +\n            '</div>\\r\\n</div>\\r\\n';\n        return __p\n    };\n\n    $.Fotorama.jst.style = function (v) {\n        var __t, __p = '', __e = _.escape;\n        __p += '.fotorama' +\n            ((__t = ( v.s )) == null ? '' : __t) +\n            ' .fotorama__nav--thumbs .fotorama__nav__frame{\\r\\npadding:' +\n            ((__t = ( v.m )) == null ? '' : __t) +\n            'px;\\r\\nheight:' +\n            ((__t = ( v.h )) == null ? '' : __t) +\n            'px}\\r\\n.fotorama' +\n            ((__t = ( v.s )) == null ? '' : __t) +\n            ' .fotorama__thumb-border{\\r\\nheight:' +\n            ((__t = ( v.h )) == null ? '' : __t) +\n            'px;\\r\\nborder-width:' +\n            ((__t = ( v.b )) == null ? '' : __t) +\n            'px;\\r\\nmargin-top:' +\n            ((__t = ( v.m )) == null ? '' : __t) +\n            'px}';\n        return __p\n    };\n\n    $.Fotorama.jst.thumb = function (v) {\n        var __t, __p = '', __e = _.escape;\n        __p += '<div class=\"fotorama__nav__frame fotorama__nav__frame--thumb\" tabindex=\"0\" role=\"button\" data-gallery-role=\"nav-frame\" data-nav-type=\"thumb\" aria-label>\\r\\n    <div class=\"fotorama__thumb\">\\r\\n    </div>\\r\\n</div>';\n        return __p\n    };\n})(window, document, location, typeof jQuery !== 'undefined' && jQuery);\n","Magento_Multishipping/js/multi-shipping-balance.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/dataPost',\n    'jquery-ui-modules/widget'\n], function ($, dataPost) {\n    'use strict';\n\n    $.widget('mage.multiShippingBalance', {\n        options: {\n            changeUrl: ''\n        },\n\n        /**\n         * Initialize balance checkbox events.\n         *\n         * @private\n         */\n        _create: function () {\n            this.element.on('change', $.proxy(function (event) {\n                dataPost().postData({\n                    action: this.options.changeUrl,\n                    data: {\n                        useBalance: +$(event.target).is(':checked')\n                    }\n                });\n            }, this));\n        }\n    });\n\n    return $.mage.multiShippingBalance;\n});\n","Magento_Multishipping/js/payment.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/template',\n    'Magento_Ui/js/modal/alert',\n    'jquery-ui-modules/widget',\n    'mage/translate'\n], function ($, mageTemplate, alert) {\n    'use strict';\n\n    $.widget('mage.payment', {\n        options: {\n            continueSelector: '#payment-continue',\n            methodsContainer: '#payment-methods',\n            minBalance: 0,\n            tmpl: '<input id=\"hidden-free\" type=\"hidden\" name=\"payment[method]\" value=\"free\">'\n        },\n\n        /** @inheritdoc */\n        _create: function () {\n            this.element.find('dd [name^=\"payment[\"]').prop('disabled', true).end()\n                .on('click', this.options.continueSelector, $.proxy(this._submitHandler, this))\n                .on('updateCheckoutPrice', $.proxy(function (event, data) {\n                    //updating the checkoutPrice\n                    if (data.price) {\n                        this.options.checkoutPrice += data.price;\n                    }\n\n                    //updating total price\n                    if (data.totalPrice) {\n                        data.totalPrice = this.options.checkoutPrice;\n                    }\n\n                    if (this.options.checkoutPrice <= this.options.minBalance) {\n                        // Add free input field, hide and disable unchecked\n                        // checkbox payment method and all radio button payment methods\n                        this._disablePaymentMethods();\n                    } else {\n                        // Remove free input field, show all payment method\n                        this._enablePaymentMethods();\n                    }\n                }, this))\n                .on('click', 'dt input:radio', $.proxy(this._paymentMethodHandler, this));\n\n            if (this.options.checkoutPrice < this.options.minBalance) {\n                this._disablePaymentMethods();\n            } else {\n                this._enablePaymentMethods();\n            }\n        },\n\n        /**\n         * Display payment details when payment method radio button is checked\n         * @private\n         * @param {EventObject} e\n         */\n        _paymentMethodHandler: function (e) {\n            var element = $(e.target),\n                parentsDl = element.closest('dl');\n\n            parentsDl.find('dt input:radio').prop('checked', false);\n            parentsDl.find('dd').addClass('no-display').end()\n                .find('.items').hide()\n                .find('[name^=\"payment[\"]').prop('disabled', true);\n            element.prop('checked', true).parent()\n                .next('dd').removeClass('no-display')\n                .find('.items').show().find('[name^=\"payment[\"]').prop('disabled', false);\n        },\n\n        /**\n         * make sure one payment method is selected\n         * @private\n         * @return {Boolean}\n         */\n        _validatePaymentMethod: function () {\n            var methods = this.element.find('[name^=\"payment[\"]'),\n                isValid = false;\n\n            if (methods.length === 0) {\n                alert({\n                    content: $.mage.__('We can\\'t complete your order because you don\\'t have a payment method set up.')\n                });\n            } else if (this.options.checkoutPrice <= this.options.minBalance) {\n                isValid = true;\n            } else if (methods.filter('input:radio:checked').length) {\n                isValid = true;\n            } else {\n                alert({\n                    content: $.mage.__('Please choose a payment method.')\n                });\n            }\n\n            return isValid;\n        },\n\n        /**\n         * Disable and enable payment methods\n         * @private\n         */\n        _disablePaymentMethods: function () {\n            var tmpl = mageTemplate(this.options.tmpl, {\n                data: {}\n            });\n\n            this.element.find('input[name=\"payment[method]\"]').prop('disabled', true).end()\n                .find('input[id^=\"use\"][name^=\"payment[use\"]:not(:checked)').prop('disabled', true).parent().hide();\n            this.element.find('[name=\"payment[method]\"][value=\"free\"]').parent('dt').remove();\n            this.element.find(this.options.methodsContainer).hide().find('[name^=\"payment[\"]').prop('disabled', true);\n\n            $(tmpl).appendTo(this.element);\n        },\n\n        /**\n         * Enable and enable payment methods\n         * @private\n         */\n        _enablePaymentMethods: function () {\n            this.element.find('input[name=\"payment[method]\"]').prop('disabled', false).end()\n                .find('dt input:radio:checked').trigger('click').end()\n                .find('input[id^=\"use\"][name^=\"payment[use\"]:not(:checked)').prop('disabled', false).parent().show();\n            this.element.find(this.options.methodsContainer).show();\n        },\n\n        /**\n         * Returns checked payment method.\n         *\n         * @private\n         */\n        _getSelectedPaymentMethod: function () {\n            return this.element.find('input[name=\\'payment[method]\\']:checked');\n        },\n\n        /**\n         * Validate  before form submit\n         * @private\n         * @param {EventObject} e\n         */\n        _submitHandler: function (e) {\n            var currentMethod,\n                submitButton;\n\n            e.preventDefault();\n\n            if (this._validatePaymentMethod()) {\n                currentMethod = this._getSelectedPaymentMethod();\n                submitButton = currentMethod.parent().next('dd').find('button[type=submit]');\n\n                if (submitButton.length) {\n                    submitButton.first().trigger('click');\n                } else {\n                    this.element.trigger('submit');\n                }\n            }\n        }\n    });\n\n    return $.mage.payment;\n});\n","Magento_Multishipping/js/overview.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery-ui-modules/widget',\n    'mage/translate'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.orderOverview', {\n        options: {\n            opacity: 0.5, // CSS opacity for the 'Place Order' button when it's clicked and then disabled.\n            pleaseWaitLoader: 'span.please-wait', // 'Submitting order information...' Ajax loader.\n            placeOrderSubmit: 'button[type=\"submit\"]', // The 'Place Order' button.\n            agreements: '.checkout-agreements' // Container for all of the checkout agreements and terms/conditions\n        },\n\n        /**\n         * Bind a submit handler to the form.\n         * @private\n         */\n        _create: function () {\n            this.element.on('submit', $.proxy(this._showLoader, this));\n        },\n\n        /**\n         * Verify that all agreements and terms/conditions are checked. Show the Ajax loader. Disable\n         * the submit button (i.e. Place Order).\n         * @return {Boolean}\n         * @private\n         */\n        _showLoader: function () {\n            if ($(this.options.agreements).find('input[type=\"checkbox\"]:not(:checked)').length > 0) {\n                return false;\n            }\n            this.element.find(this.options.pleaseWaitLoader).show().end()\n                .find(this.options.placeOrderSubmit).prop('disabled', true).css('opacity', this.options.opacity);\n\n            return true;\n        }\n    });\n\n    return $.mage.orderOverview;\n});\n","Magento_Multishipping/js/multi-shipping.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Customer/js/customer-data',\n    'jquery-ui-modules/widget'\n], function ($, customerData) {\n    'use strict';\n\n    $.widget('mage.multiShipping', {\n        options: {\n            itemsQty: 0,\n            addNewAddressBtn: 'button[data-role=\"add-new-address\"]', // Add a new multishipping address.\n            addNewAddressFlag: '#add_new_address_flag', // Hidden input field with value 0 or 1.\n            canContinueBtn: 'button[data-role=\"can-continue\"]', // Continue (update quantity or go to shipping).\n            canContinueFlag: '#can_continue_flag' // Hidden input field with value 0 or 1.\n        },\n\n        /**\n         * Bind event handlers to click events for corresponding buttons.\n         * @private\n         */\n        _create: function () {\n            this._prepareCartData();\n            $(this.options.addNewAddressBtn).on('click', $.proxy(this._addNewAddress, this));\n            $(this.options.canContinueBtn).on('click', $.proxy(this._canContinue, this));\n        },\n\n        /**\n         * Takes cart items qty from current cart data and compare it with current items qty\n         * Reloads cart data if cart items qty is wrong\n         * @private\n         */\n        _prepareCartData: function () {\n            var cartData = customerData.get('cart');\n\n            if (cartData()['summary_count'] !== this.options.itemsQty) {\n                customerData.reload(['cart'], false);\n            }\n        },\n\n        /**\n         * Add a new address. Set the hidden input field and submit the form. Then enter a new shipping address.\n         * @private\n         */\n        _addNewAddress: function () {\n            $(this.options.addNewAddressFlag).val(1);\n            this.element.submit();\n        },\n\n        /**\n         * Can the user continue to the next step? The data-flag attribute holds either 0 (no) or 1 (yes).\n         * @private\n         * @param {Event} event - Click event on the corresponding button.\n         */\n        _canContinue: function (event) {\n            $(this.options.canContinueFlag).val(parseInt($(event.currentTarget).data('flag'), 10));\n        }\n    });\n\n    return $.mage.multiShipping;\n});\n","Mageplaza_Core/js/jquery.autocomplete.min.js":"/**\r\n *  Ajax Autocomplete for jQuery, version 1.3.0\r\n *  (c) 2017 Tomas Kirda\r\n *\r\n *  Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.\r\n *  For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete\r\n */\r\n!function(a){\"use strict\";\"function\"==typeof define&&define.amd?define([\"jquery\"],a):a(\"object\"==typeof exports&&\"function\"==typeof require?require(\"jquery\"):jQuery)}(function(a){\"use strict\";function b(c,d){var e=a.noop,f=this,g={ajaxSettings:{},autoSelectFirst:!1,appendTo:document.body,serviceUrl:null,lookup:null,onSelect:null,width:\"auto\",minChars:1,maxHeight:300,deferRequestBy:0,params:{},formatResult:b.formatResult,formatGroup:b.formatGroup,delimiter:null,zIndex:9999,type:\"GET\",noCache:!1,onSearchStart:e,onSearchComplete:e,onSearchError:e,preserveInput:!1,containerClass:\"autocomplete-suggestions\",tabDisabled:!1,dataType:\"text\",currentRequest:null,triggerSelectOnValidInput:!0,preventBadQueries:!0,lookupFilter:function(a,b,c){return-1!==a.value.toLowerCase().indexOf(c)},paramName:\"query\",transformResult:function(b){return\"string\"==typeof b?a.parseJSON(b):b},showNoSuggestionNotice:!1,noSuggestionNotice:\"No results\",orientation:\"bottom\",forceFixPosition:!1};f.element=c,f.el=a(c),f.suggestions=[],f.badQueries=[],f.selectedIndex=-1,f.currentValue=f.element.value,f.intervalId=0,f.cachedResponse={},f.onChangeInterval=null,f.onChange=null,f.isLocal=!1,f.suggestionsContainer=null,f.noSuggestionsContainer=null,f.options=a.extend({},g,d),f.classes={selected:\"autocomplete-selected\",suggestion:\"autocomplete-suggestion\"},f.hint=null,f.hintValue=\"\",f.selection=null,f.initialize(),f.setOptions(d)}var c=function(){return{escapeRegExChars:function(a){return a.replace(/[|\\\\{}()[\\]^$+*?.]/g,\"\\\\$&\")},createNode:function(a){var b=document.createElement(\"div\");return b.className=a,b.style.position=\"absolute\",b.style.display=\"none\",b}}}(),d={ESC:27,TAB:9,RETURN:13,LEFT:37,UP:38,RIGHT:39,DOWN:40};b.utils=c,a.Autocomplete=b,b.formatResult=function(a,b){if(!b)return a.value;var d=\"(\"+c.escapeRegExChars(b)+\")\";return a.value.replace(new RegExp(d,\"gi\"),\"<strong>$1</strong>\").replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/\"/g,\"&quot;\").replace(/&lt;(\\/?strong)&gt;/g,\"<$1>\")},b.formatGroup=function(a,b){return'<div class=\"autocomplete-group\"><strong>'+b+\"</strong></div>\"},b.prototype={killerFn:null,initialize:function(){var c,d=this,e=\".\"+d.classes.suggestion,f=d.classes.selected,g=d.options;d.element.setAttribute(\"autocomplete\",\"off\"),d.killerFn=function(b){a(b.target).closest(\".\"+d.options.containerClass).length||(d.killSuggestions(),d.disableKillerFn())},d.noSuggestionsContainer=a('<div class=\"autocomplete-no-suggestion\"></div>').html(this.options.noSuggestionNotice).get(0),d.suggestionsContainer=b.utils.createNode(g.containerClass),c=a(d.suggestionsContainer),c.appendTo(g.appendTo),\"auto\"!==g.width&&c.css(\"width\",g.width),c.on(\"mouseover.autocomplete\",e,function(){d.activate(a(this).data(\"index\"))}),c.on(\"mouseout.autocomplete\",function(){d.selectedIndex=-1,c.children(\".\"+f).removeClass(f)}),c.on(\"click.autocomplete\",e,function(){return d.select(a(this).data(\"index\")),!1}),d.fixPositionCapture=function(){d.visible&&d.fixPosition()},a(window).on(\"resize.autocomplete\",d.fixPositionCapture),d.el.on(\"keydown.autocomplete\",function(a){d.onKeyPress(a)}),d.el.on(\"keyup.autocomplete\",function(a){d.onKeyUp(a)}),d.el.on(\"blur.autocomplete\",function(){d.onBlur()}),d.el.on(\"focus.autocomplete\",function(){d.onFocus()}),d.el.on(\"change.autocomplete\",function(a){d.onKeyUp(a)}),d.el.on(\"input.autocomplete\",function(a){d.onKeyUp(a)})},onFocus:function(){var a=this;a.fixPosition(),a.el.val().length>=a.options.minChars&&a.onValueChange()},onBlur:function(){this.enableKillerFn()},abortAjax:function(){var a=this;a.currentRequest&&(a.currentRequest.abort(),a.currentRequest=null)},setOptions:function(b){var c=this,d=c.options;a.extend(d,b),c.isLocal=a.isArray(d.lookup),c.isLocal&&(d.lookup=c.verifySuggestionsFormat(d.lookup)),d.orientation=c.validateOrientation(d.orientation,\"bottom\"),a(c.suggestionsContainer).css({\"max-height\":d.maxHeight+\"px\",width:d.width+\"px\",\"z-index\":d.zIndex})},clearCache:function(){this.cachedResponse={},this.badQueries=[]},clear:function(){this.clearCache(),this.currentValue=\"\",this.suggestions=[]},disable:function(){var a=this;a.disabled=!0,clearInterval(a.onChangeInterval),a.abortAjax()},enable:function(){this.disabled=!1},fixPosition:function(){var b=this,c=a(b.suggestionsContainer),d=c.parent().get(0);if(d===document.body||b.options.forceFixPosition){var e=b.options.orientation,f=c.outerHeight(),g=b.el.outerHeight(),h=b.el.offset(),i={top:h.top,left:h.left};if(\"auto\"===e){var j=a(window).height(),k=a(window).scrollTop(),l=-k+h.top-f,m=k+j-(h.top+g+f);e=Math.max(l,m)===l?\"top\":\"bottom\"}if(\"top\"===e?i.top+=-f:i.top+=g,d!==document.body){var n,o=c.css(\"opacity\");b.visible||c.css(\"opacity\",0).show(),n=c.offsetParent().offset(),i.top-=n.top,i.left-=n.left,b.visible||c.css(\"opacity\",o).hide()}\"auto\"===b.options.width&&(i.width=b.el.outerWidth()+\"px\"),c.css(i)}},enableKillerFn:function(){var b=this;a(document).on(\"click.autocomplete\",b.killerFn)},disableKillerFn:function(){var b=this;a(document).off(\"click.autocomplete\",b.killerFn)},killSuggestions:function(){var a=this;a.stopKillSuggestions(),a.intervalId=window.setInterval(function(){a.visible&&(a.options.preserveInput||a.el.val(a.currentValue),a.hide()),a.stopKillSuggestions()},50)},stopKillSuggestions:function(){window.clearInterval(this.intervalId)},isCursorAtEnd:function(){var a,b=this,c=b.el.val().length,d=b.element.selectionStart;return\"number\"==typeof d?d===c:document.selection?(a=document.selection.createRange(),a.moveStart(\"character\",-c),c===a.text.length):!0},onKeyPress:function(a){var b=this;if(!b.disabled&&!b.visible&&a.which===d.DOWN&&b.currentValue)return void b.suggest();if(!b.disabled&&b.visible){switch(a.which){case d.ESC:b.el.val(b.currentValue),b.hide();break;case d.RIGHT:if(b.hint&&b.options.onHint&&b.isCursorAtEnd()){b.selectHint();break}return;case d.TAB:if(b.hint&&b.options.onHint)return void b.selectHint();if(-1===b.selectedIndex)return void b.hide();if(b.select(b.selectedIndex),b.options.tabDisabled===!1)return;break;case d.RETURN:if(-1===b.selectedIndex)return void b.hide();b.select(b.selectedIndex);break;case d.UP:b.moveUp();break;case d.DOWN:b.moveDown();break;default:return}a.stopImmediatePropagation(),a.preventDefault()}},onKeyUp:function(a){var b=this;if(!b.disabled){switch(a.which){case d.UP:case d.DOWN:return}clearInterval(b.onChangeInterval),b.currentValue!==b.el.val()&&(b.findBestHint(),b.options.deferRequestBy>0?b.onChangeInterval=setInterval(function(){b.onValueChange()},b.options.deferRequestBy):b.onValueChange())}},onValueChange:function(){var b=this,c=b.options,d=b.el.val(),e=b.getQuery(d);return b.selection&&b.currentValue!==e&&(b.selection=null,(c.onInvalidateSelection||a.noop).call(b.element)),clearInterval(b.onChangeInterval),b.currentValue=d,b.selectedIndex=-1,c.triggerSelectOnValidInput&&b.isExactMatch(e)?void b.select(0):void(e.length<c.minChars?b.hide():b.getSuggestions(e))},isExactMatch:function(a){var b=this.suggestions;return 1===b.length&&b[0].value.toLowerCase()===a.toLowerCase()},getQuery:function(b){var c,d=this.options.delimiter;return d?(c=b.split(d),a.trim(c[c.length-1])):b},getSuggestionsLocal:function(b){var c,d=this,e=d.options,f=b.toLowerCase(),g=e.lookupFilter,h=parseInt(e.lookupLimit,10);return c={suggestions:a.grep(e.lookup,function(a){return g(a,b,f)})},h&&c.suggestions.length>h&&(c.suggestions=c.suggestions.slice(0,h)),c},getSuggestions:function(b){var c,d,e,f,g=this,h=g.options,i=h.serviceUrl;if(h.params[h.paramName]=b,d=h.ignoreParams?null:h.params,h.onSearchStart.call(g.element,h.params)!==!1){if(a.isFunction(h.lookup))return void h.lookup(b,function(a){g.suggestions=a.suggestions,g.suggest(),h.onSearchComplete.call(g.element,b,a.suggestions)});g.isLocal?c=g.getSuggestionsLocal(b):(a.isFunction(i)&&(i=i.call(g.element,b)),e=i+\"?\"+a.param(d||{}),c=g.cachedResponse[e]),c&&a.isArray(c.suggestions)?(g.suggestions=c.suggestions,g.suggest(),h.onSearchComplete.call(g.element,b,c.suggestions)):g.isBadQuery(b)?h.onSearchComplete.call(g.element,b,[]):(g.abortAjax(),f={url:i,data:d,type:h.type,dataType:h.dataType},a.extend(f,h.ajaxSettings),g.currentRequest=a.ajax(f).done(function(a){var c;g.currentRequest=null,c=h.transformResult(a,b),g.processResponse(c,b,e),h.onSearchComplete.call(g.element,b,c.suggestions)}).fail(function(a,c,d){h.onSearchError.call(g.element,b,a,c,d)}))}},isBadQuery:function(a){if(!this.options.preventBadQueries)return!1;for(var b=this.badQueries,c=b.length;c--;)if(0===a.indexOf(b[c]))return!0;return!1},hide:function(){var b=this,c=a(b.suggestionsContainer);a.isFunction(b.options.onHide)&&b.visible&&b.options.onHide.call(b.element,c),b.visible=!1,b.selectedIndex=-1,clearInterval(b.onChangeInterval),a(b.suggestionsContainer).hide(),b.signalHint(null)},suggest:function(){if(!this.suggestions.length)return void(this.options.showNoSuggestionNotice?this.noSuggestions():this.hide());var b,c=this,d=c.options,e=d.groupBy,f=d.formatResult,g=c.getQuery(c.currentValue),h=c.classes.suggestion,i=c.classes.selected,j=a(c.suggestionsContainer),k=a(c.noSuggestionsContainer),l=d.beforeRender,m=\"\",n=function(a,c){var f=a.data[e];return b===f?\"\":(b=f,d.formatGroup(a,b))};return d.triggerSelectOnValidInput&&c.isExactMatch(g)?void c.select(0):(a.each(c.suggestions,function(a,b){e&&(m+=n(b,g,a)),m+='<div class=\"'+h+'\" data-index=\"'+a+'\">'+f(b,g,a)+\"</div>\"}),this.adjustContainerWidth(),k.detach(),j.html(m),a.isFunction(l)&&l.call(c.element,j,c.suggestions),c.fixPosition(),j.show(),d.autoSelectFirst&&(c.selectedIndex=0,j.scrollTop(0),j.children(\".\"+h).first().addClass(i)),c.visible=!0,void c.findBestHint())},noSuggestions:function(){var b=this,c=a(b.suggestionsContainer),d=a(b.noSuggestionsContainer);this.adjustContainerWidth(),d.detach(),c.empty(),c.append(d),b.fixPosition(),c.show(),b.visible=!0},adjustContainerWidth:function(){var b,c=this,d=c.options,e=a(c.suggestionsContainer);\"auto\"===d.width?(b=c.el.outerWidth(),e.css(\"width\",b>0?b:300)):\"flex\"===d.width&&e.css(\"width\",\"\")},findBestHint:function(){var b=this,c=b.el.val().toLowerCase(),d=null;c&&(a.each(b.suggestions,function(a,b){var e=0===b.value.toLowerCase().indexOf(c);return e&&(d=b),!e}),b.signalHint(d))},signalHint:function(b){var c=\"\",d=this;b&&(c=d.currentValue+b.value.substr(d.currentValue.length)),d.hintValue!==c&&(d.hintValue=c,d.hint=b,(this.options.onHint||a.noop)(c))},verifySuggestionsFormat:function(b){return b.length&&\"string\"==typeof b[0]?a.map(b,function(a){return{value:a,data:null}}):b},validateOrientation:function(b,c){return b=a.trim(b||\"\").toLowerCase(),-1===a.inArray(b,[\"auto\",\"bottom\",\"top\"])&&(b=c),b},processResponse:function(a,b,c){var d=this,e=d.options;a.suggestions=d.verifySuggestionsFormat(a.suggestions),e.noCache||(d.cachedResponse[c]=a,e.preventBadQueries&&!a.suggestions.length&&d.badQueries.push(b)),b===d.getQuery(d.currentValue)&&(d.suggestions=a.suggestions,d.suggest())},activate:function(b){var c,d=this,e=d.classes.selected,f=a(d.suggestionsContainer),g=f.find(\".\"+d.classes.suggestion);return f.find(\".\"+e).removeClass(e),d.selectedIndex=b,-1!==d.selectedIndex&&g.length>d.selectedIndex?(c=g.get(d.selectedIndex),a(c).addClass(e),c):null},selectHint:function(){var b=this,c=a.inArray(b.hint,b.suggestions);b.select(c)},select:function(a){var b=this;b.hide(),b.onSelect(a),b.disableKillerFn()},moveUp:function(){var b=this;if(-1!==b.selectedIndex)return 0===b.selectedIndex?(a(b.suggestionsContainer).children().first().removeClass(b.classes.selected),b.selectedIndex=-1,b.el.val(b.currentValue),void b.findBestHint()):void b.adjustScroll(b.selectedIndex-1)},moveDown:function(){var a=this;a.selectedIndex!==a.suggestions.length-1&&a.adjustScroll(a.selectedIndex+1)},adjustScroll:function(b){var c=this,d=c.activate(b);if(d){var e,f,g,h=a(d).outerHeight();e=d.offsetTop,f=a(c.suggestionsContainer).scrollTop(),g=f+c.options.maxHeight-h,f>e?a(c.suggestionsContainer).scrollTop(e):e>g&&a(c.suggestionsContainer).scrollTop(e-c.options.maxHeight+h),c.options.preserveInput||c.el.val(c.getValue(c.suggestions[b].value)),c.signalHint(null)}},onSelect:function(b){var c=this,d=c.options.onSelect,e=c.suggestions[b];c.currentValue=c.getValue(e.value),c.currentValue===c.el.val()||c.options.preserveInput||c.el.val(c.currentValue),c.signalHint(null),c.suggestions=[],c.selection=e,a.isFunction(d)&&d.call(c.element,e)},getValue:function(a){var b,c,d=this,e=d.options.delimiter;return e?(b=d.currentValue,c=b.split(e),1===c.length?a:b.substr(0,b.length-c[c.length-1].length)+a):a},dispose:function(){var b=this;b.el.off(\".autocomplete\").removeData(\"autocomplete\"),b.disableKillerFn(),a(window).off(\"resize.autocomplete\",b.fixPositionCapture),a(b.suggestionsContainer).remove()}},a.fn.autocomplete=a.fn.devbridgeAutocomplete=function(c,d){var e=\"autocomplete\";return arguments.length?this.each(function(){var f=a(this),g=f.data(e);\"string\"==typeof c?g&&\"function\"==typeof g[c]&&g[c](d):(g&&g.dispose&&g.dispose(),g=new b(this,c),f.data(e,g))}):this.first().data(e)}});"}
}});