PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i5h-3LL

HOME


5h-3LL 1.0
DIR: /srv/http/adent.cz/kvfinal.cz/wp-content/plugins/wordfence/js
/srv/http/adent.cz/kvfinal.cz/wp-content/plugins/wordfence/js/
Upload File:
Current File : /srv/http/adent.cz/kvfinal.cz/wp-content/plugins/wordfence/js/admin.liveTraffic.1744125809.js
(function($) {
	var __ = window.wfi18n.__;
	var sprintf = window.wfi18n.sprintf;

	var LISTING_LIMIT = 50;

	LiveTrafficViewModel = function(listings, filters) {
		var self = this;
		var listingIDTable = {};
		self.listings = ko.observableArray(listings);
		self.listings.subscribe(function(items) {
			listingIDTable = {};
			for (var i = 0; i < items.length; i++) {
				listingIDTable[items[i].id()] = 1;
			}
			//console.log(items);
		});
		self.hasListing = function(id) {
			return id in listingIDTable;
		};
		self.filters = ko.observableArray(filters);

		var urlGroupBy = new GroupByModel('url', __('URL'));
		var groupBys = [
			new GroupByModel('type', __('Type')),
			new GroupByModel('user_login', __('Username')),
			new GroupByModel('statusCode', __('HTTP Response Code')),
			new GroupByModel('action', __('Firewall Response'), 'enum', ['ok', 'throttled', 'lockedOut', 'blocked', 'blocked:waf']),
			new GroupByModel('ip', __('IP')),
			urlGroupBy
		];

		self.presetFiltersOptions = ko.observableArray([
			new PresetFilterModel(__('All Hits'), "all", []),
			new PresetFilterModel(__('Humans'), "humans", [new ListingsFilterModel(self, 'type', 'human')]),
			new PresetFilterModel(__('Registered Users'), "users", [new ListingsFilterModel(self, 'userID', '0', '!=')]),
			new PresetFilterModel(__('Crawlers'), "crawlers", [new ListingsFilterModel(self, 'type', 'bot')]),
			new PresetFilterModel(__('Google Crawlers'), "google", [new ListingsFilterModel(self, 'isGoogle', '1')]),
			new PresetFilterModel(__('Pages Not Found'), "404s", [new ListingsFilterModel(self, 'statusCode', '404')]),
			new PresetFilterModel(__('Logins and Logouts'), "logins", [
				new ListingsFilterModel(self, 'action', 'login', 'contains'),
				new ListingsFilterModel(self, 'action', 'logout', 'contains')
			]),
			//new PresetFilterModel('Top Consumers', "top_consumers", [new ListingsFilterModel(self, 'statusCode', '200')], urlGroupBy),
			//new PresetFilterModel('Top 404s', "top_404s", [new ListingsFilterModel(self, 'statusCode', '404')], urlGroupBy),
			new PresetFilterModel(__('Locked Out'), "lockedOut", [new ListingsFilterModel(self, 'action', 'lockedOut')]),
			new PresetFilterModel(__('Blocked'), "blocked", [new ListingsFilterModel(self, 'action', 'blocked', 'contains')]),
			new PresetFilterModel(__('Blocked By Firewall'), "blocked:waf", [new ListingsFilterModel(self, 'action', 'blocked:waf')])
		]);

		self.showAdvancedFilters = ko.observable(false);
		self.showAdvancedFilters.subscribe(function(val) {
			if (val && self.filters().length == 0) {
				self.addFilter();
			}
		});

		self.presetFiltersOptionsText = function(item) {
			return item.text();
		};

		self.selectedPresetFilter = ko.observable();
		self.selectedPresetFilter.subscribe(function(item) {
			var clonedFilters = ko.toJS(item.filters());
			var newFilters = [];
			for (var i = 0; i < clonedFilters.length; i++) {
				newFilters.push(new ListingsFilterModel(self, clonedFilters[i].param, clonedFilters[i].value, clonedFilters[i].operator));
			}
			self.filters(newFilters);
			self.groupBy(item.groupBy());
		});

		self.filters.subscribe(function() {
			self.checkQueryAndReloadListings();
		});

		self.addFilter = function() {
			self.filters.push(new ListingsFilterModel(self));
		};

		self.removeFilter = function(item) {
			self.filters.remove(item);
		};

		var currentFilterQuery = '';
		var getURLEncodedFilters = function() {
			var dataString = '';
			ko.utils.arrayForEach(self.filters(), function(filter) {
				if (filter.getValue() !== false) {
					dataString += filter.urlEncoded() + '&';
				}
			});
			var groupBy = self.groupBy();
			if (groupBy) {
				dataString += 'groupby=' + encodeURIComponent(groupBy.param()) + '&';
			}
			var startDate = self.startDate();
			if (startDate) {
				dataString += 'startDate=' + encodeURIComponent(startDate) + '&';
			}
			var endDate = self.endDate();
			if (endDate) {
				dataString += 'endDate=' + encodeURIComponent(endDate) + '&';
			}
			if (dataString.length > 1) {
				return dataString.substring(0, dataString.length - 1);
			}
			return '';
		};

		self.filterGroupByOptions = ko.observableArray(groupBys);

		self.filterGroupByOptionsText = function(item) {
			return item.text() || item.param();
		};

		self.groupBy = ko.observable();
		self.groupBy.subscribe(function() {
			self.checkQueryAndReloadListings();
		});

		self.startDate = ko.observable();
		self.startDate.subscribe(function() {
			// console.log('start date change ' + self.startDate());
			self.checkQueryAndReloadListings();
		});

		self.endDate = ko.observable();
		self.endDate.subscribe(function() {
			// console.log('end date change ' + self.endDate());
			self.checkQueryAndReloadListings();
		});

		/**
		 * Pulls down fresh traffic data and resets the list.
		 *
		 * @param options
		 */
		self.checkQueryAndReloadListings = function(options) {
			if (currentFilterQuery !== getURLEncodedFilters()) {
				self.reloadListings(options);
			}
		};
		self.reloadListings = function(options) {
			pullDownListings(options, function(listings) {
				var groupByKO = self.groupBy();
				var groupBy = '';
				if (groupByKO) {
					groupBy = groupByKO.param();
					WFAD.mode = 'liveTraffic_paused';
				}
				else {
					WFAD.mode = 'liveTraffic';
				}

				var newListings = [];
				for (var i = 0; i < listings.length; i++) {
					newListings.push(new ListingModel(listings[i], groupBy));
				}
				self.listings(newListings);
			})
		};

		/**
		 * Used in the infinite scroll
		 */
		self.loadNextListings = function(callback) {
			var lastTimestamp = self.filters[0];
			pullDownListings({
				since: lastTimestamp,
				limit: LISTING_LIMIT,
				offset: self.listings().length
			}, function() {
				self.appendListings.apply(this, arguments);
				typeof callback === 'function' && callback.apply(this, arguments);
			});
		};

		self.getCurrentQueryString = function(options) {
			var queryOptions = {
				since: null,
				limit: LISTING_LIMIT,
				offset: 0
			};
			for (var prop in queryOptions) {
				if (queryOptions.hasOwnProperty(prop) && options && prop in options) {
					queryOptions[prop] = options[prop];
				}
			}
			currentFilterQuery = getURLEncodedFilters();
			var data = currentFilterQuery;
			for (prop in queryOptions) {
				if (queryOptions.hasOwnProperty(prop)) {
					var val = queryOptions[prop];
					if (val === null || val === undefined) {
						val = '';
					}
					data += '&' + encodeURIComponent(prop) + '=' + encodeURIComponent(val);
				}
			}
			return data;
		};

		var pullDownListings = function(options, callback) {
			var data = self.getCurrentQueryString(options);

			WFAD.ajax('wordfence_loadLiveTraffic', data, function(response) {
				if (!response || !response.success) {
					return;
				}
				callback && callback(response.data, response);
				self.sql(response.sql);
			});
		};

		self.prependListings = function(listings, response) {
			for (var i = listings.length - 1; i >= 0; i--) {
				// Prevent duplicates
				if (self.hasListing(listings[i].id)) {
					continue;
				}
				var listing = new ListingModel(listings[i]);
				listing.highlighted(true);
				self.listings.unshift(listing);
			}

			//self.listings.sort(function(a, b) {
			//	if (a.ctime() < b.ctime()) {
			//		return 1;
			//	} else if (a.ctime() > b.ctime()) {
			//		return -1;
			//	}
			//	return 0;
			//});
		};

		self.appendListings = function(listings, response) {
			var highlight = 3;
			for (var i = 0; i < listings.length; i++) {
				// Prevent duplicates
				if (self.hasListing(listings[i].id)) {
					continue;
				}
				var listing = new ListingModel(listings[i]);
				listing.highlighted(highlight-- > 0);
				self.listings.push(listing);
			}

			//self.listings.sort(function(a, b) {
			//	if (a.ctime() < b.ctime()) {
			//		return 1;
			//	} else if (a.ctime() > b.ctime()) {
			//		return -1;
			//	}
			//	return 0;
			//});
		};

		self.whitelistWAFParamKey = function(path, paramKey, failedRules) {
			WFAD.ajax('wordfence_whitelistWAFParamKey', {
				path: path,
				paramKey: paramKey,
				failedRules: failedRules
			}, function(response) {

			});
		};

		self.trimIP = function(ip) {
			if (ip && ip.length > 16) {
				return ip.substring(0, 16) + "\u2026";
			}
			return ip;
		};

		$(window).on('wf-live-traffic-ip-blocked', function(e, ip) {
			ko.utils.arrayForEach(self.listings(), function(listing) {
				if (listing.IP() === ip) {
					listing.blocked(true);
				}
			});
		}).on('wf-live-traffic-ip-unblocked', function(e, ip) {
			ko.utils.arrayForEach(self.listings(), function(listing) {
				if (listing.IP() === ip) {
					listing.blocked(false);
				}
			});
		});

		// For debuggering-a-ding
		self.sql = ko.observable('');
	};

	LiveTrafficViewModel.truncateText = function(text, maxLength) {
		maxLength = maxLength || 100;
		if (text && text.length > maxLength) {
			return text.substring(0, Math.round(maxLength)) + "\u2026";
			// return text.substring(0, Math.round(maxLength / 2)) + " ... " + text.substring(text.length - Math.round(maxLength / 2));
		}
		return text;
	};

	var ListingModel = function(data, groupBy) {
		var self = this;

		self.id = ko.observable(0);
		self.ctime = ko.observable(0);
		self.IP = ko.observable('');
		self.jsRun = ko.observable(0);
		self.statusCode = ko.observable(200);
		self.isGoogle = ko.observable(0);
		self.userID = ko.observable(0);
		self.URL = ko.observable('');
		self.referer = ko.observable('');
		self.UA = ko.observable('');
		self.loc = ko.observable();
		self.type = ko.observable('');
		self.blocked = ko.observable(false);
		self.rangeBlocked = ko.observable(false);
		self.ipRangeID = ko.observable(-1);
		self.extReferer = ko.observable();
		self.browser = ko.observable();
		self.user = ko.observable();
		self.hitCount = ko.observable();
		self.username = ko.observable('');

		// New fields/columns
		self.action = ko.observable('');
		self.actionDescription = ko.observable(false);
		self.actionData = ko.observable();

		self.highlighted = ko.observable(false);
		self.showDetails = ko.observable(false);
		self.toggleDetails = function() {
			self.showDetails(!self.showDetails());
		};
		//self.highlighted.subscribe(function(val) {
		//	if (val) {
		//		_classes += ' highlighted';
		//		self.cssClasses(_classes);
		//	} else {
		//		_classes.replace(/  highlighted(\s*|$)/, ' ');
		//		self.cssClasses(_classes);
		//	}
		//});

		for (var prop in data) {
			if (data.hasOwnProperty(prop)) {
				if (prop === 'blocked' || prop === 'rangeBlocked') {
					data[prop] = !!data[prop];
				}
				self[prop] !== undefined && self[prop](data[prop]);
			}
		}

		if (data['lastHit'] !== undefined) {
			self['ctime'](data['lastHit']);
		}

		self.timestamp = ko.pureComputed(function() {
			var date = new Date(self.ctime() * 1000);
			return date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
		}, self);

		// Use the same format as these update.
		self.timeAgo = ko.pureComputed(function() {
			var serverTime = WFAD.serverMicrotime;
			return $(WFAD.showTimestamp(this.ctime(), serverTime)).text();
		}, self);

		self.displayURL = ko.pureComputed(function() {
			return LiveTrafficViewModel.truncateText(self.URL(), 105);
		});

		self.displayURLShort = ko.pureComputed(function() {
			var a = document.createElement('a');
			if (!self.URL()) {
				return '';
			}
			a.href = self.URL();
			if (a.host !== location.host) {
				return LiveTrafficViewModel.truncateText(self.URL(), 30);
			}
			var url = a.pathname + (typeof a.search === 'string' ? a.search : '');
			return LiveTrafficViewModel.truncateText(url, 30);
		});

		self.firewallAction = ko.pureComputed(function() {
			//Grouped by firewall action listing
			if (groupBy == 'action') {
				switch (self.action()) {
					case 'lockedOut':
						return __('Locked out from logging in');
					case 'blocked:waf-always':
						return __('Blocked by the Wordfence Application Firewall and plugin settings');
					case 'blocked:wordfence':
						return __('Blocked by Wordfence plugin settings');
					case 'blocked:wfsnrepeat':
					case 'blocked:wfsn':
						return __('Blocked by the Wordfence Security Network');
					case 'blocked:waf':
						return __('Blocked by the Wordfence Web Application Firewall');
					case 'cbl:redirect':
						return __('Redirected by Country Blocking bypass URL');
					default:
						return __('Blocked by Wordfence');
				}
			}

			//Standard listing
			var desc = '';
			switch (self.action()) {
				case 'lockedOut':
					return __('locked out from logging in');

				case 'blocked:waf-always':
				case 'blocked:wordfence':
				case 'blocked:wfsnrepeat':
					desc = self.actionDescription();
					if (desc && desc.toLowerCase().indexOf('block') === 0) {
						return 'b' + desc.substring(1);
					}
					return sprintf(__('blocked for %s'), desc);

				case 'blocked:wfsn':
					return __('blocked by the Wordfence Security Network');

				case 'blocked:waf':
					var data = self.actionData();
					if (typeof data === 'object') {
						var paramKey = data.paramKey ? WFAD.base64_decode(data.paramKey) : null;
						var paramValue = data.paramKey ? WFAD.base64_decode(data.paramValue) : null;
						// var category = data.category;

						var matches = paramKey !== null && paramKey.match(/([a-z0-9_]+\.[a-z0-9_]+)(?:\[(.+?)\](.*))?/i);
						desc = self.actionDescription();
						if (matches) {
							switch (matches[1]) {
								case 'request.queryString':
									desc = sprintf(__('%s in query string: %s'), self.actionDescription(), matches[2] + '=' + LiveTrafficViewModel.truncateText(encodeURIComponent(paramValue)));
									break;
								case 'request.body':
									desc = sprintf(__('%s in POST body: %s'), self.actionDescription(), matches[2] + '=' + LiveTrafficViewModel.truncateText(encodeURIComponent(paramValue)));
									break;
								case 'request.cookie':
									desc = sprintf(__('%s in cookie: %s'), self.actionDescription(), matches[2] + '=' + LiveTrafficViewModel.truncateText(encodeURIComponent(paramValue)));
									break;
								case 'request.fileNames':
									desc = sprintf(__('%s in file: %s'), self.actionDescription(), matches[2] + '=' + LiveTrafficViewModel.truncateText(encodeURIComponent(paramValue)));
									break;
							}
						}
						if (desc) {
							return sprintf(__('blocked by firewall for %s'), desc);
						}
						if (data.failedRules == 'blocked') {
							return __('blocked by real-time IP blocklist');
						}
						return __('blocked by firewall');
					}
					return sprintf(__('blocked by firewall for %s'), self.actionDescription());
				case 'cbl:redirect':
					desc = self.actionDescription();
					return desc;
			}
			return desc;
		});

		self.cssClasses = ko.pureComputed(function() {
			var classes = 'wf-live-traffic-hit-type';
			if (self.statusCode() == 403 || self.statusCode() == 503) {
				classes += ' wfActionBlocked';
			}
			if (self.statusCode() == 404) {
				classes += ' wf404';
			}
			if (self.jsRun() == 1) {
				classes += ' wfHuman';
			}
			if (self.actionData() && self.actionData().learningMode) {
				classes += ' wfWAFLearningMode';
			}
			if (self.action() == 'loginFailValidUsername' || self.action() == 'loginFailInvalidUsername') {
				classes += ' wfFailedLogin';
			}
			// if (self.highlighted()) {
			// 	classes += ' highlighted';
			// }
			return classes;
		});

		self.typeIconClass = ko.pureComputed(function() {
			var classes = 'wf-live-traffic-type-icon';
			if (self.statusCode() == 403 || self.statusCode() == 503) {
				classes += ' wf-icon-blocked wf-ion-android-cancel';
			} else if (self.statusCode() == 404 || self.action() == 'loginFailValidUsername' || self.action() == 'loginFailInvalidUsername') {
				classes += ' wf-icon-warning wf-ion-alert-circled';
			} else if (self.jsRun() == 1) {
				classes += ' wf-icon-human wf-ion-ios-person';
			} else {
				// classes += ' wf-ion-soup-can';
				classes += ' wf-ion-bug';
			}
			return classes;
		});

		self.typeText = ko.pureComputed(function() {
			var type = '';
			if (self.action() == 'loginFailValidUsername' || self.action() == 'loginFailInvalidUsername') {
				type = __('Failed Login');
			} else if (self.statusCode() == 403 || self.statusCode() == 503) {
				type = __('Blocked');
			} else if (self.statusCode() == 404) {
				type = __('404 Not Found');
			} else if (self.statusCode() == 302) {
				type = __('Redirected');
			} else if (self.jsRun() == 1) {
				type = __('Human');
			} else {
				type = __('Bot');
			}
			return sprintf(__('Type: %s'), type);
		});

		function slideInDrawer() {
			overlayWrapper.fadeIn(400);
			overlay.css({
				right: '-800px'
			})
			.stop()
			.animate({
				right: 0
			}, 500);
		}

		self.showWhoisOverlay = function() {
			slideInDrawer();
			overlayHeader.html($('#wfActEvent_' + self.id()).html());
			overlayBody.html('').css('opacity', 0);

			WFAD.ajax('wordfence_whois', {
				val: self.IP()
			}, function(result) {
				var whoisHTML = WFAD.completeWhois(result, true);
				overlayBody.stop()
				.animate({
					opacity: 1
				}, 200)
				.html('<h4 style=\'margin-top:0;\'>' + __('WHOIS LOOKUP') + '</h4>' + whoisHTML);
				$(window).trigger('wf-live-traffic-overlay-bind', self);
			});
		};

		self.showRecentTraffic = function() {
			slideInDrawer();
			overlayHeader.html($('#wfActEvent_' + self.id()).html());
			overlayBody.html('').css('opacity', 0);

			WFAD.ajax('wordfence_recentTraffic', {
				ip: self.IP()
			}, function(result) {
				overlayBody.stop()
				.animate({
					opacity: 1
				}, 200)
				.html('<h3 style=\'margin-top:0;\'>' + __('Recent Activity') + '</h3>' + result.result);
				$(window).trigger('wf-live-traffic-overlay-bind', self);
				WFAD.avatarLookup();
			});
		};

		/*
			Blocking functions
		*/
		self.unblockIP = function() {
			WFAD.unblockIP(self.IP(), function() {
				$(window).trigger('wf-live-traffic-ip-unblocked', self.IP());
			});
		};
		self.unblockNetwork = function() {
			WFAD.unblockNetwork(self.ipRangeID());
		};
		self.blockIP = function() {
			WFAD.blockIP(self.IP(), __('Manual block by administrator'), function() {
				$(window).trigger('wf-live-traffic-ip-blocked', self.IP());
			});
		};
	};

	var ListingsFilterModel = function(viewModel, param, value, operator) {
		var self = this;
		self.viewModel = viewModel;
		self.param = ko.observable('');
		self.value = ko.observable('');
		self.operator = ko.observable('');

		self.param(param);
		self.value(value);
		self.operator(operator || '=');

		var filterChanged = function() {
			self.viewModel && self.viewModel.checkQueryAndReloadListings && self.viewModel.checkQueryAndReloadListings();
		};
		self.param.subscribe(filterChanged);
		self.operator.subscribe(filterChanged);
		self.value.subscribe(function(value) {
			if (value instanceof FilterParamEnumOptionModel && value.operator()) {
				self.selectedFilterOperatorOptionValue(value.operator());
			}
			filterChanged();
		});

		var equalsOperator = new FilterOperatorModel('=');
		var notEqualsOperator = new FilterOperatorModel('!=', '\u2260');
		var containsOperator = new FilterOperatorModel('contains');
		var matchOperator = new FilterOperatorModel('match');
		self.filterOperatorOptions = ko.observableArray([
			equalsOperator,
			notEqualsOperator,
			containsOperator,
			matchOperator
		]);

		self.filterParamOptions = ko.observableArray([
			new FilterParamModel('type', __('Type'), 'enum', [
				new FilterParamEnumOptionModel('human', __('Human')),
				new FilterParamEnumOptionModel('bot', __('Bot'))
			]),
			new FilterParamModel('user_login', __('Username')),
			new FilterParamModel('userID', __('User ID')),
			new FilterParamModel('isGoogle', __('Google Bot'), 'bool'),
			new FilterParamModel('ip', __('IP')),
			new FilterParamModel('ua', __('User Agent')),
			new FilterParamModel('referer', __('Referer')),
			new FilterParamModel('url', __('URL')),
			new FilterParamModel('statusCode', __('HTTP Response Code')),
			new FilterParamModel('action', __('Firewall Response'), 'enum', [
				new FilterParamEnumOptionModel('', __('OK')),
				new FilterParamEnumOptionModel('throttled', __('Throttled')),
				new FilterParamEnumOptionModel('lockedOut', __('Locked Out')),
				new FilterParamEnumOptionModel('blocked', __('Blocked'), containsOperator),
				new FilterParamEnumOptionModel('blocked:waf', __('Blocked WAF'))
			]),
			new FilterParamModel('action', __('Logins'), 'enum', [
				new FilterParamEnumOptionModel('loginOK', __('Logged In')),
				new FilterParamEnumOptionModel('loginFail', __('Failed Login')),
				new FilterParamEnumOptionModel('loginFailInvalidUsername', __('Failed Login: Invalid Username')),
				new FilterParamEnumOptionModel('loginFailValidUsername', __('Failed Login: Valid Username'))
			]),
			new FilterParamModel('action', __('Security Event'))
		]);

		self.filterParamOptionsText = function(item) {
			return item.text() || item.param();
		};

		self.selectedFilterParamOptionValue = ko.observable();
		self.selectedFilterParamOptionValue.subscribe(function(item) {
			self.param(item && item.param ? item.param() : '');
		});

		ko.utils.arrayForEach(self.filterParamOptions(), function(item) {
			if (self.param() == item.param()) {
				switch (item.type()) {
					case 'enum':
						// console.log(self.param(), item.param(), self.value(), values);
						switch (self.operator()) {
							case '=':
								ko.utils.arrayForEach(item.values(), function(enumOption) {
									if (enumOption.value() == self.value()) {
										self.selectedFilterParamOptionValue(item);
									}
								});
								break;
						}
						break;

					default:
						self.selectedFilterParamOptionValue(item);
						break;
				}
			}
		});

		self.filterOperatorOptionsText = function(item) {
			return item.text() || item.operator();
		};

		self.selectedFilterOperatorOptionValue = ko.observable();
		self.selectedFilterOperatorOptionValue.subscribe(function(item) {
			self.operator(item.operator());
		});

		ko.utils.arrayForEach(self.filterOperatorOptions(), function(item) {
			if (self.operator() == item.operator()) {
				self.selectedFilterOperatorOptionValue(item);
			}
		});

		self.getValue = function() {
			var value = self.value() instanceof FilterParamEnumOptionModel ? self.value().value() : self.value();
			return (typeof value === 'string' || typeof value === 'number') ? value : false;
		};
		self.urlEncoded = function() {
			var value = self.getValue();
			return 'param[]=' + encodeURIComponent(self.param()) + '&value[]=' + encodeURIComponent(value) +
				'&operator[]=' + encodeURIComponent(self.operator());
		};
	};

	var PresetFilterModel = function(text, value, filters, groupBy) {
		this.text = ko.observable('');
		this.value = ko.observable('');
		this.filters = ko.observableArray(filters);
		this.groupBy = ko.observable(groupBy);

		this.text(text);
		this.value(value);
	};

	var FilterParamModel = function(param, text, type, values) {
		this.text = ko.observable('');
		this.param = ko.observable('');
		this.type = ko.observable('');
		this.values = ko.observableArray(values);

		this.text(text);
		this.param(param);
		this.type(type || 'text');

		this.optionsText = function(item) {
			if (item instanceof FilterParamEnumOptionModel) {
				return item.label() || item.value();
			}
			return item;
		}
	};

	var FilterParamEnumOptionModel = function(value, label, operator) {
		this.value = ko.observable('');
		this.label = ko.observable('');
		this.operator = ko.observable('');

		this.value = ko.observable(value);
		this.label = ko.observable(label);
		this.operator = ko.observable(operator);

		this.toString = function() {
			return this.value();
		}
	};

	var FilterOperatorModel = function(operator, text) {
		this.text = ko.observable('');
		this.operator = ko.observable('');

		this.text(text);
		this.operator(operator);
	};

	var GroupByModel = function(param, text) {
		this.text = ko.observable('');
		this.param = ko.observable('');

		this.text(text);
		this.param(param);
	};

	ko.bindingHandlers.datetimepicker = {
		init: function(element, valueAccessor, allBindingsAccessor) {
			//initialize datepicker with some optional options
			var options = allBindingsAccessor().datepickerOptions || {},
				$el = $(element);

			$el.datetimepicker(options);

			//handle the field changing by registering datepicker's changeDate event
			ko.utils.registerEventHandler(element, "changeDate", function() {
				var observable = valueAccessor();
				observable($el.datetimepicker("getDate"));
			});

			//handle disposal (if KO removes by the template binding)
			ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
				$el.datetimepicker("destroy");
			});

		},
		update: function(element, valueAccessor) {
			var value = ko.utils.unwrapObservable(valueAccessor()),
				$el = $(element);

			//handle date data coming via json from Microsoft
			if (String(value).indexOf('/Date(') == 0) {
				value = new Date(parseInt(value.replace(/\/Date\((.*?)\)\//gi, "$1")));
			}

			var current = $el.datetimepicker("getDate");

			if (value - current !== 0) {
				$el.datetimepicker("setDate", value);
			}
		}
	};

	var overlayWrapper = null,
		overlay = null,
		overlayCloseButton = null,
		overlayHeader = null,
		overlayBody = null;
	$(function() {

		var liveTrafficWrapper = $('#wf-live-traffic');
		$('#wf-lt-preset-filters').wfselect2({
			templateSelection: function(value) {
				return $('<span><em>' + __('Filter Traffic') + '</em>: ' + value.text + '</span>');
			}
		});

		overlayWrapper = $('#wf-live-traffic-util-overlay-wrapper').on('click', function(evt) {
			if (evt.target === this) {
				overlayCloseButton.trigger('click');
			}
		});
		overlay = overlayWrapper.find('.wf-live-traffic-util-overlay');
		overlayCloseButton = overlayWrapper.find('.wf-live-traffic-util-overlay-close').on('click', function() {
			overlayWrapper.fadeOut(250);
			overlay
			.stop()
			.animate({
				right: '-800px'
			}, 250);
			overlayHeader.html('');
			overlayBody.html('').css('opacity', 0);
			$(window).trigger('wf-live-traffic-overlay-unbind');
		});
		overlayHeader = overlayWrapper.find('.wf-live-traffic-util-overlay-header');
		overlayBody = overlayWrapper.find('.wf-live-traffic-util-overlay-body');
		$([overlayHeader, overlayBody]).on('click', function() {
			return false;
		});

		// liveTrafficWrapper.find('#wf-lt-advanced-filters select').wfselect2({
		//
		// });

		WFAD.wfLiveTraffic = new LiveTrafficViewModel();
		ko.applyBindings(WFAD.wfLiveTraffic, liveTrafficWrapper.get(0));
		liveTrafficWrapper.find('form').submit();
		WFAD.mode = 'liveTraffic';

		var legendWrapper = $('#wf-live-traffic-legend-wrapper');
		var placeholder = $('#wf-live-traffic-legend-placeholder');
		var legend = $('#wf-live-traffic-legend');
		var adminBar = $('#wpadminbar');
		var liveTrafficListings = $('#wf-lt-listings');
		var groupedListings = $('div#wf-live-traffic-group-by'); 

		var hasScrolled = false;
		var loadingListings = false;
		$(window).on('scroll', function() {
			var win = $(this);
			var needsSticky = (WFAD.isSmallScreen ? (legendWrapper.offset().top < win.scrollTop() + 10) : (legendWrapper.offset().top < win.scrollTop() + adminBar.outerHeight() + 10));
			if (needsSticky) {
				var legendWidth = legend.width();
				var legendHeight = legend.height();

				legend.addClass('sticky');
				legend.css('width', legendWidth);
				legend.css('height', legendHeight);
				placeholder.addClass('sticky');
				placeholder.css('width', legendWidth);
				placeholder.css('height', legendHeight);
			} else {
				legend.removeClass('sticky');
				legend.css('width', 'auto');
				legend.css('height', 'auto');
				placeholder.removeClass('sticky');
			}

			var firstLTRow = liveTrafficListings.children().filter(':visible').first();
			if ((firstLTRow.length > 0 && firstLTRow.offset().top + firstLTRow.height() < win.scrollTop() + adminBar.outerHeight() + 20) ||
				(groupedListings.filter(':visible').length > 0)) {
				if (WFAD.mode != 'liveTraffic_paused') {
					WFAD.mode = 'liveTraffic_paused';
				}
			} else {
				if (WFAD.mode != 'liveTraffic') {
					WFAD.mode = 'liveTraffic';
				}
			}

			// console.log(win.scrollTop() + window.innerHeight, liveTrafficWrapper.outerHeight() + liveTrafficWrapper.offset().top);
			var currentScrollBottom = win.scrollTop() + window.innerHeight;
			var scrollThreshold = liveTrafficWrapper.outerHeight() + liveTrafficWrapper.offset().top;
			if (hasScrolled && !loadingListings && currentScrollBottom >= scrollThreshold) {
				// console.log('infinite scroll');

				loadingListings = true;
				hasScrolled = false;
				WFAD.wfLiveTraffic.loadNextListings(function() {
					loadingListings = false;
					WFAD.reverseLookupIPs();
					WFAD.avatarLookup();
				});
			} else if (currentScrollBottom < scrollThreshold) {
				hasScrolled = true;
				// console.log('no infinite scroll');
			}
		})
		.on('wf-live-traffic-overlay-bind', function(e, item) {
			ko.applyBindings(item, overlayHeader.get(0));
		})
		.on('wf-live-traffic-overlay-unbind', function(e, item) {
			ko.cleanNode(overlayHeader.get(0));
		});

		$([liveTrafficWrapper.find('.wf-filtered-traffic'), overlayWrapper]).tooltip({
			tooltipClass: "wf-tooltip",
			track: true
		});
	});
})
(jQuery);