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/sharklogisticsinc.com/www/wp-content/plugins/security-ninja/
Upload File :
Current File : //home/sharklogisticsinc.com/www/wp-content/plugins/security-ninja/security-ninja.php
<?php
/*
Plugin Name: Security Ninja
Plugin URI: https://wpsecurityninja.com/
Description: Check your site for <strong>security vulnerabilities</strong> and get precise suggestions for corrective actions on passwords, user accounts, file permissions, database security, version hiding, plugins, themes and other security aspects.
Author: Web factory Ltd
Version: 2.45
Author URI: http://www.webfactoryltd.com/


  Copyright 2012 - 2018  Web factory Ltd  (email : securityninja@webfactoryltd.com)

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License, version 2, as
  published by the Free Software Foundation.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/


// this is an include only WP file
if (!defined('ABSPATH')) {
  die;
}

// constants
define('WF_SN_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('WF_SN_PLUGIN_URL', plugin_dir_url(__FILE__));
define('WF_SN_BASE_FILE', basename(__FILE__));
define('WF_SN_RESULTS_KEY', 'wf_sn_results');
define('WF_SN_OPTIONS_KEY', 'wf_sn_options');
define('WF_SN_POINTERS_KEY', 'wf_sn_pointers');
define('WF_SN_MAX_EXEC_SEC', 200);


require_once WF_SN_PLUGIN_DIR . 'sn-tests.php';
require_once WF_SN_PLUGIN_DIR . 'modules/malware-scanner/malware-scanner.php';
require_once WF_SN_PLUGIN_DIR . 'modules/database-optimizer/database-optimizer.php';


class wf_sn {
  static $version;
  static $skip_tests = array();
  static $hash_storage = 'https://api.wordpress.org/core/checksums/1.0/';

  // get plugin version from header
  static function get_plugin_version() {
    $plugin_data = get_file_data(__FILE__, array('version' => 'Version'), 'plugin');
    wf_sn::$version = $plugin_data['version'];

    return $plugin_data['version'];
  } // get_plugin_version


  // init plugin
  static function init() {
    if (!version_compare(get_bloginfo('version'), '4.0',  '>=')) {
      add_action('admin_notices', array(__CLASS__, 'min_version_notice'));
      return;
    }

    // does the user have enough privilages to use the plugin?
    if (is_admin() && current_user_can('administrator')) {
      // add menu item to tools
      add_action('admin_menu', array(__CLASS__, 'admin_menu'));

      // aditional links in plugin description
      add_filter('plugin_action_links_' . basename(dirname(__FILE__)) . '/' . basename(__FILE__),
                 array(__CLASS__, 'plugin_action_links'));
      add_filter('plugin_row_meta', array(__CLASS__, 'plugin_meta_links'), 10, 2);
      add_filter('admin_footer_text', array(__CLASS__, 'admin_footer_text'));

      // enqueue scripts
      add_action('admin_enqueue_scripts', array(__CLASS__, 'enqueue_scripts'));

      // register endpoints
      add_action('wp_ajax_sn_run_tests', array(__CLASS__, 'run_tests'));
      add_action('wp_ajax_sn_hide_tab', array(__CLASS__, 'hide_tab'));
      add_action('wp_ajax_sn_dismiss_pointer', array(__CLASS__, 'dismiss_pointer_ajax'));

      // warn if tests were not run
      add_action('admin_notices', array(__CLASS__, 'run_tests_notice'));

      // promo notices
      add_action('admin_notices', array(__CLASS__, 'promo_notice'));

      // warn if Wordfence is active
      add_action('admin_notices', array(__CLASS__, 'wordfence_notice'));

      // add_markup for UI overlay
      add_action('admin_footer', array(__CLASS__, 'admin_footer'));
    } // if is_admin
  } // init


  // some things have to be loaded earlier
  static function plugins_loaded() {
    wf_sn::get_plugin_version();
  } // plugins_loaded


  // add links to plugin's description in plugins table
  static function plugin_meta_links($links, $file) {
    $support = '<a target="_blank" href="https://wordpress.org/support/plugin/security-ninja" title="Problems? We\'re here to help">Support</a>';
    $buy = '<a target="_blank" href="' . self::generate_sn_web_link('plugins_table') . '" title="Security Ninja PRO has 7 extra modules, check them out"><b>Buy PRO</b></a>';

    if ($file == plugin_basename(__FILE__)) {
      $links[] = $support;
      $links[] = $buy;
    }

    return $links;
  } // plugin_meta_links


  // add settings link to plugins page
  static function plugin_action_links($links) {
    $settings_link = '<a href="tools.php?page=wf-sn" title="Security Ninja">Analyze Site</a>';
    $pro_link = '<a target="_blank" href="' . self::generate_sn_web_link('plugins_table_left') . '" title="Security Ninja PRO has 7 extra modules, check them out">Get <b>PRO</b></a>';

    array_unshift($links, $pro_link);
    array_unshift($links, $settings_link);

    return $links;
  } // plugin_action_links


  // test if we're on plugin's page
  static function is_plugin_page() {
    $current_screen = get_current_screen();

    if ($current_screen->id == 'tools_page_wf-sn') {
      return true;
    } else {
      return false;
    }
  } // is_plugin_page


  // hide any add-on tab
  static function hide_tab() {
    check_ajax_referer('wf_sn_hide_tab');

    $tab = trim(@$_POST['tab']);
    $tabs = get_transient('wf_sn_hidden_tabs');
    $tabs[] = $tab;

    set_transient('wf_sn_hidden_tabs', $tabs, DAY_IN_SECONDS * 120);

    wp_send_json_success();
  } // hide_tab


  // enqueue CSS and JS scripts on plugin's pages
  static function enqueue_scripts() {
    $options = get_option(WF_SN_OPTIONS_KEY);
    if (wf_sn::is_plugin_page()) {
      wp_enqueue_script('jquery-ui-tabs');
      wp_enqueue_script('jquery-ui-dialog');
      wp_enqueue_script('sn-jquery-plugins', WF_SN_PLUGIN_URL . 'js/sn-jquery-plugins.js', array(), wf_sn::$version, true);
      wp_enqueue_script('sn-js', WF_SN_PLUGIN_URL . 'js/sn-common.js', array(), wf_sn::$version, true);
      wp_enqueue_style('sn-css', WF_SN_PLUGIN_URL . 'css/sn-style.css', array(), wf_sn::$version);
      wp_enqueue_style('wp-jquery-ui-dialog');
    } // if SN page

    $pointers = get_option(WF_SN_POINTERS_KEY);
    if (!empty($pointers) && !wf_sn::is_plugin_page()) {
      wp_enqueue_script('wp-pointer');
      wp_enqueue_script('wf-sn-pointers', plugins_url('js/sn-pointers.js', __FILE__), array('jquery'), wf_sn::$version, true);
      wp_enqueue_style('wp-pointer');
      wp_localize_script('wp-pointer', 'wf_sn_pointers', $pointers);
    }

    if (!isset($options['first_install_gmt']) || ($options['first_install_gmt'] + HOUR_IN_SECONDS) < time()) {
      $promo_countdown = 0;
    } else {
      $promo_countdown = $options['first_install_gmt'] + HOUR_IN_SECONDS;
    }

    if (wf_sn::is_plugin_page() || $pointers) {
      $js_vars = array('sn_plugin_url' => WF_SN_PLUGIN_URL,
                       'promo_countdown' => $promo_countdown,
                       'nonce_run_tests' => wp_create_nonce('wf_sn_run_tests'),
                       'nonce_refresh_update' => wp_create_nonce('wf_sn_refresh_update'),
                       'nonce_dismiss_pointer' => wp_create_nonce('wf_sn_dismiss_pointer'),
                       'nonce_hide_tab' => wp_create_nonce('wf_sn_hide_tab'));

      wp_localize_script('jquery', 'wf_sn', $js_vars);
    }
  } // enqueue_scripts


  // permanently dismiss pointer
  static function dismiss_pointer_ajax() {
    check_ajax_referer('wf_sn_dismiss_pointer');

    $pointers = get_option(WF_SN_POINTERS_KEY);
    $pointer = trim($_POST['pointer']);

    if (empty($pointers) || empty($pointers[$pointer])) {
      wp_send_json_error();
    }

    unset($pointers[$pointer]);
    update_option(WF_SN_POINTERS_KEY, $pointers);

    wp_send_json_success();
  } // dismiss_pointer_ajax


  // add entry to admin menu
  static function admin_menu() {
    add_management_page('Security Ninja', 'Security Ninja', 'manage_options', 'wf-sn', array(__CLASS__, 'main_page'));
  } // admin_menu


  // display warning if test were never run
  static function run_tests_notice() {
    if (!wf_sn::is_plugin_page()) {
      return;
    }

    $tests = get_option(WF_SN_RESULTS_KEY, array());

    // temporarily disabled
    if (0 && empty($tests['last_run'])) {
      echo '<div class="notice notice-error"><p>Security Ninja <strong>tests were never run.</strong> Click "Analyze Site" to run them now and analyze your site for security vulnerabilities.</p></div>';
    } elseif (!empty($tests['last_run']) && (current_time('timestamp') - DAY_IN_SECONDS * 30) > $tests['last_run']) {
      echo '<div class="notice notice-error"><p>Security Ninja <strong>tests were not run for more than 30 days.</strong> It\'s advisable to run them once in a while. Click "Analyze Site" to run them now and analyze your site for security vulnerabilities.</p></div>';
    }
  } // run_tests_notice


  // display warning if Wordfence plugin is active
  static function wordfence_notice() {
    if (!wf_sn::is_plugin_page()) {
      return;
    }

    if (defined('WORDFENCE_VERSION') && WORDFENCE_VERSION) {
      echo '<div class="notice notice-error"><p>Please <strong>temporarily deactivate Wordfence</strong> before running Security Ninja tests. Some tests are detected as site attacks by Wordfence and hence can\'t be performed properly. Activate Wordfence once you\'re done testing.</p></div>';
    }
  } // wordfence_notice


  // display promo offer for a short period of time
  static function promo_notice() {
    $hidden_tabs = get_transient('wf_sn_hidden_tabs');
    if (!$hidden_tabs) {
      $hidden_tabs = array();
    }
    $promo_shown = false;

    $options = get_option(WF_SN_OPTIONS_KEY);
    $promo_delta = 1 * HOUR_IN_SECONDS;
    $promo_delta2 = DAY_IN_SECONDS * 30;

    if (wf_sn::is_plugin_page() && current_time('timestamp') - $options['first_install'] < $promo_delta && !in_array('welcome', $hidden_tabs)) {
      echo '<div class="notice notice-error notice-promo"><p>We\'ve prepared a special <b>25% welcoming discount</b> for you on <a href="' . wf_sn::generate_sn_web_link('welcome_link', '/', array('coupon' => 'welcome')) . '" target="_blank">Security Ninja PRO</a> available only for another <b class="wf-sn-countdown">59 min</b>.';
      echo '<br>Security Ninja PRO will instantly <b>boost your security</b> with its 7 modules - Cloud Firewall, Core Scanner, Malware Scanner, Auto Fixer, Database Optimizer, Events Logger &amp; Scheduled Scanner!<br><br><a class="button button-primary" href="' . wf_sn::generate_sn_web_link('welcome_button', '/', array('coupon' => 'welcome')) . '" target="_blank">BUY Security Ninja NOW with 25% OFF &amp; secure your site</a> <a href="#" class="hide_tab" data-tab-id="welcome"><small><i>I\'m not interested (remove notice)</i></small></a></p></div>';
      $promo_shown = true;
    }

    if (wf_sn::is_plugin_page() && current_time('timestamp') - $options['first_install'] > $promo_delta2 && !in_array('olduser', $hidden_tabs) && !$promo_shown) {
      echo '<div class="notice notice-error notice-promo">';

      echo '<p style="font-size: 14px;">We have a <b>special offer</b> only for long-time Security Ninja users like <b>you</b> - a <b>25% discount</b> on all PRO licenses! Protect your site for <b>only $21</b>.<br><a target="_blank" href="' . wf_sn::generate_sn_web_link('olduser_notification', '/', array('coupon' => 'olduser')) . '">Upgrade now</a> &amp; protect your site with 7 extra modules including Cloud Firewall that <b>blocks 600 million bad IPs</b> from accessing to your site!';
      echo '<br><br><a class="button button-primary" href="' . wf_sn::generate_sn_web_link('olduser_notification_button', '/', array('coupon' => 'olduser')) . '" target="_blank">BUY Security Ninja NOW with 25% OFF &amp; secure your site</a> <a href="#" class="hide_tab" data-tab-id="olduser"><small><i>I\'m not interested in extra protection for my site (remove notice)</i></small></a></p></div>';
      $promo_shown = true;
    }
  } // promo_notice


  // display warning if test were never run
  static function min_version_notice() {
    echo '<div class="notice notice-error"><p>Security Ninja <b>requires WordPress version 4.0</b> or higher to function properly. You\'re using WordPress version ' . get_bloginfo('version') . '. Please <a href="' . admin_url('update-core.php') . '" title="Update WP core">update</a>.</p></div>';
  } // min_version_error


  // additional powered by text in admin footer; only on SN page
  static function admin_footer_text($text) {
    if (!self::is_plugin_page()) {
      return $text;
    }

    $text = '<i><a href="' . wf_sn::generate_sn_web_link('footer', '/') . '" title="Visit Security Ninja\'s site for more info" target="_blank">Security Ninja</a> v' . self::$version . ' by <a href="https://www.webfactoryltd.com/" title="Visit our site to get more great plugins" target="_blank">WebFactory Ltd</a>.</i> '. $text;

    return $text;
  } // admin_footer_text


  // add markup for UI overlay
  static function admin_footer() {
    if (wf_sn::is_plugin_page()) {
      echo '<div id="sn_overlay"><div class="sn-overlay-wrapper">';
      echo '<div class="inner">';

      // title
      echo '<div class="wf-sn-title">
             <h2><img src="' . WF_SN_PLUGIN_URL . 'images/security-ninja-logo.png" alt="Security Ninja" title="Security Ninja"></h2>
           </div>';

      // outer
      echo '<div class="wf-sn-overlay-outer">';

      // content
      echo '<div class="wf-sn-overlay-content">';
      echo '<div id="sn-site-scan" style="display: none;">';
      echo '<h3>Security Ninja is analyzing your site.<br/>It will only take a few moments ...</h3>';
      echo '</div>';

      do_action('sn_overlay_content');

      echo '<div class="loader"><img title="Loading ..." src="' . plugins_url('images/ajax-loader.gif', __FILE__) . '" alt="Loading..." /></div>';
      echo '<p><br><br><a id="abort-scan" href="#" class="button button-secondary input-button red">Stop scanning</a></p>';

      do_action('sn_overlay_content_after');

      echo '</div>'; // wf-sn-overlay-content

      echo '</div></div></div></div>';

      echo '<div id="test-details-dialog" style="display: none;" title="Test details"><p>Please wait.</p></div>';

      echo '<div id="sn_tests_descriptions" style="display: none;">';
      require_once WF_SN_PLUGIN_DIR . 'sn-tests-description.php';
      echo '</div>';
    } // if is_plugin_page
  } // admin_footer


  // get local or remote file hash definitions
  static function get_file_hashes() {
    $ver = get_bloginfo('version');

    if (get_transient('wf_sn_hashes_' . $ver)) {
      return get_transient('wf_sn_hashes_' . $ver);
    }

    $response = wp_remote_get(self::$hash_storage . '?version=' . $ver . '&time=' . time(), array('sslverify' => false, 'timeout' => 15, 'redirection' => 2));
    if(!is_wp_error($response) && $response['response']['code'] == '200') {
      $hashes = json_decode(wp_remote_retrieve_body($response), true);
      if (!empty($hashes) && is_array($hashes['checksums'][$ver])) {
        $cleaned = array();
        foreach($hashes['checksums'][$ver] as $path => $hash) {
          if (strpos($path, '/themes/') !== false || strpos($path, '/plugins/')) {
            continue;
          }
          $cleaned[$path] = $hash;
        }
        $tmp = array('version' => $ver, 'files' => $cleaned);
        set_transient('wf_sn_hashes_' . $ver, $tmp, DAY_IN_SECONDS * 5);
        return $hashes;
      }
    }

    delete_transient('wf_sn_hashes_' . $ver);
    return false;
  } // get_file_hashes


  // ad for add-on
  static function core_ad_page() {
    $files = self::get_file_hashes();
    if (!empty($files['files'])) {
      $cnt = number_format(count($files['files']), 0);
    } else {
      $cnt = '+1,200';
    }

    echo '<div class="submit-test-container"><p><b>Core Scanner</b> is a module in <b>Security Ninja PRO</b>. It compares all your core WordPress files (over 1,200) with the secure master copy maintained by WordPress.org. With one click you will know if even a byte was changed in any file. If so, you can imediatelly recover the original version. <b>Perfect for restoring hacked sites!</b></p>
<p><a target="_blank" href="' . wf_sn::generate_sn_web_link('tab_core_scanner', '/core-scanner/') . '" class="button-primary input-button">Instantly check if there is any bad code hiding in one of your ' . $cnt . ' core files</a></p></div>';

    echo '<table class="addon-ad" width="100%"><tr><td width="50%" valign="top">';
    echo '<ul class="sn-list">
<li>scan WP core files with <strong>one click</strong></li>
<li>scan takes less than 10 seconds</li>
<li>quickly identify <strong>problematic files</strong></li>
<li><strong>restore modified files</strong> with one click</li>
<li>great for removing <strong>exploits</strong> and fixing accidental file edits/deletes</li>
<li>view files\' <strong>source</strong> to take a closer look</li>
<li><strong>fix</strong> broken WP auto-updates</li>
<li>detailed help and description</li>
<li><strong>color-coded results</strong> separate files into 5 categories:
<ul>
<li>files that are modified and should not have been</li>
<li>files that are missing and should not be</li>
<li>files that are modified and they are supposed to be</li>
<li>files that are missing but they are not vital to WP</li>
<li>files that are intact</li>
</ul></li>
<li>complete integration with Ninja\'s easy-to-use GUI</li>
</ul>';

    echo '<p><a href="#" class="hide_tab" data-tab-id="core" title="Hide this tab"><i>No thank you, I\'m not interested (hide this tab)</i></a></p>';

    echo '</td><td>';
    echo '<a target="_blank" href="' . wf_sn::generate_sn_web_link('tab_core_scanner', '/core-scanner/') . '" title="Core Scanner add-on"><img style="max-width: 100%;" src="' .  plugin_dir_url(__FILE__) . 'images/core-scanner.jpg" title="Core Scanner add-on" alt="Core Scanner add-on" /></a>';
    echo '</td></tr></table>';
  } // core_ad_page

  // ad for add-on
  static function pro_ad_page() {
    echo '<div class="submit-test-container"><p>Getting hacked sucks! We created <b>Security Ninja PRO</b> more than seven years ago to <b>save you money, time and nerves</b>. With seven additional PRO modules your site will be less prone to attacks, you\'ll have a clear understanding of what\'s going on if any attacks do occur, and cleaning up a site in a worse-case scenario will be a breeze. Save yourself hours of frustration and <b>hundreds of dollars in repair fees</b> by upgrading to Security Ninja PRO.</p>
<p><a target="_blank" href="' . wf_sn::generate_sn_web_link('tab_pro', '/') . '" class="button-primary input-button">Find out more</a></p></div>';

    echo '<div class="pricing-table">
              <div class="pricing-column">
            <div class="pricing-plan">
              <div class="header">
                <h3>Forever Unlimited</h3>
                <span class="price">$199</span>
        <span class="note">Never pay us another dollar again</span>
              </div>
              <div class="body">
                <ul>
                  <li>install on 99 sites (yours &amp; client\'s)</li>
                  <li>lifetime updates</li>
          <li>lifetime premium USA based support</li>
                  <li>all PRO modules</li>
                  <li>instant download &amp; activation</li>
                  <li>secure payment</li>
                  <li>100% Money Back Guarantee</li>
                </ul>
                <div class="buy-btn"><a class="button button-primary input-button" href="https://wpsecurityninja.com/buy/?p=sn-pro-forever&r=SN-' . wf_sn::$version . '" target="_blank">Buy Now</a></div>
              </div>
            </div>
          </div>
          <div class="pricing-column">
            <div class="pricing-plan highlited">
              <div class="header">
                <h3>Multi Site</h3>
                <span class="price">$79</span>
        <span class="note">Perfect if you have more than one site</span>
              </div>
              <div class="body">
                <ul>
                  <li>install on 99 sites</li>
                  <li>1 year of updates</li>
                  <li>1 year of premium USA based support</li>
                  <li>all PRO modules</li>
                  <li>instant download &amp; activation</li>
                  <li>secure payment</li>
                  <li>100% Money Back Guarantee</li>
                </ul>
                <div class="buy-btn"><a class="button button-primary input-button" href="https://wpsecurityninja.com/buy/?p=sn-pro-multi&r=SN-' . wf_sn::$version . '" target="_blank">Buy Now</a></div>
              </div>
            </div>
          </div>

          <div class="pricing-column">
            <div class="pricing-plan">
              <div class="header">
                <h3>Single site</h3>
                <span class="price">$29</span>
        <span class="note">For single site owners</span>
              </div>
              <div class="body">
                <ul>
          <li>install on 1 site</li>
                  <li>1 year of updates</li>
          <li>1 year of premium USA based support</li>
                  <li>all PRO modules</li>
                  <li>instant download &amp; activation</li>
                  <li>secure payment</li>
                  <li>100% Money Back Guarantee</li>
                </ul>
                <div class="buy-btn"><a class="button button-primary input-button" href="https://wpsecurityninja.com/buy/?p=sn-pro-single&r=SN-' . wf_sn::$version . '" target="_blank">Buy Now</a></div>
              </div>
            </div>
          </div>
        </div>';
  } // pro_ad_page

  // ad for add-on
  static function autofixer_ad_page() {
    echo '<div class="submit-test-container"><p><b>Auto Fixer</b> is a module in <b>Security Ninja PRO</b>. If you don\'t like creating backups, editing files, messing with code and getting your hands dirty - it will do all of that for you! It fixes over 30 security issues with one click. Perfect if you\'re a <b>beginner</b> or in a <b>time crunch</b> and don\'t want to fix stuff for hours.
    </p>
<p><a target="_blank" href="' . wf_sn::generate_sn_web_link('tab_auto_fixer', '/auto-fixer/') . '" class="button-primary input-button">Find out more</a></p></div>';

    echo '<table class="addon-ad" width="100%"><tr><td width="50%" valign="top">';
    echo '<ul class="sn-list">
<li>fix more than 30 issues with <strong>one click</strong></li>
<li>quickly <strong>make your site secure</strong> without spending hours modifying PHP code</li>
<li>auto-backup in case something goes wrong</li>
<li>perfect for beginners</li>
<li>detailed explanation of all fixes</li>
<li>complete integration with Ninja\'s easy-to-use GUI</li>
</ul>';

    echo '<p><a href="#" class="hide_tab" data-tab-id="autofixer" title="Hide this tab"><i>No thank you, I\'m not interested (hide this tab)</i></a></p>';

    echo '</td><td>';
    echo '<a target="_blank" href="' . wf_sn::generate_sn_web_link('tab_auto_fixer', '/auto-fixer/') . '" title="Auto Fixer add-on"><img style="max-width: 100%;" src="' .  plugin_dir_url(__FILE__) . 'images/auto-fixer.png" title="Auto Fixer add-on" alt="Auto Fixer add-on" /></a>';
    echo '</td></tr></table>';
  } // autofixer_ad_page


  // ad for add-on
  static function firewall_ad_page() {
    echo '<div class="submit-test-container"><p><b>Cloud Firewall</b> is a module in <b>Security Ninja PRO</b>. Stay <b>one step ahead</b> of bad guys by using collective data from millions of attacked sites. <b>Ban bad guys</b> before they even open your site. Module also includes <b>brute-force protection</b> for the login form. Anybody failing to login too many times gets temporarily banned.
    </p>
<p><a target="_blank" href="' . wf_sn::generate_sn_web_link('tab_firewall') . '" class="button-primary input-button">Instantly block 600 million bad IPs from your site</a></p></div>';

    echo '<table class="addon-ad" width="100%"><tr><td width="50%" valign="top">';
    echo '<ul class="sn-list">
<li><strong>stop bad guys</strong> before they even get to your site</li>
<li><strong>ban 600 million bad IPs</strong> collected from millions of attacked sites</li>
<li>list <strong>auto-updates</strong>, no need for any maintenance or manual work</li>
<li>protect login form from <strong>brute-force attacks</strong></li>
<li>visitors who fail to login multiple times in a given timeframe get banned</li>
<li><strong>secret access link</strong> is emailed during setup in case you lock yourself out</li>
</ul>';

    echo '<p><a href="#" class="hide_tab" data-tab-id="firewall" title="Hide this tab"><i>No thank you, I\'m not interested (hide this tab)</i></a></p>';

    echo '</td><td>';
    echo '<a target="_blank" href="' . wf_sn::generate_sn_web_link('tab_firewall_img', '/cloud-firewall/') . '" title="Cloud Firewall add-on"><img style="max-width: 100%;" src="' .  plugin_dir_url(__FILE__) . 'images/cloud-firewall.jpg" title="Cloud Firewall add-on" alt="Cloud Firewall add-on" /></a>';
    echo '</td></tr></table>';
  } // firewall_ad_page


  // ad for add-on
  static function schedule_ad_page() {
    echo '<div class="submit-test-container"><p><b>Scheduled Scanner</b> is a module in <b>Security Ninja PRO</b>. It gives you an additional peace of mind by automatically running Security Ninja and Core Scanner tests every day. If any changes occur or your site gets hacked you\'ll immediately get notified via email</p>
    <p><a target="_blank" href="' . wf_sn::generate_sn_web_link('tab_scheduled_scanner', '/scheduled-scanner/') . '" class="button-primary input-button">Find out more</a></p>
    </div>';

    echo '<table class="addon-ad" width="100%"><tr><td width="50%" valign="top">';
    echo '<ul class="sn-list">
<li>give yourself a peace of mind with <strong>automated scans</strong> and email reports</li>
<li><strong>get alerted</strong> when your site is <strong>hacked</strong></li>
<li>compatible with both <strong>Security Ninja & Core Scanner add-on</strong></li>
<li>extremely <strong>easy</strong> to setup - set once and forget</li>
<li>optional <strong>email reports</strong> - get them after every scan or only after changes occur on your site</li>
<li>detailed, color-coded <strong>scan log</strong></li>
<li>complete integration with Ninja\'s easy-to-use GUI</li>
</ul>';

    echo '<p><a class="hide_tab" data-tab-id="schedule" href="#" title="Hide this tab"><i>No thank you, I\'m not interested (hide this tab)</i></a></p>';

    echo '</td><td>';
    echo '<a target="_blank" href="' . wf_sn::generate_sn_web_link('tab_scheduled_scanner', '/scheduled-scanner/') . '" title="Scheduled Scanner add-on"><img style="max-width: 100%;" src="' .  plugin_dir_url(__FILE__) . 'images/scheduled-scanner.jpg" title="Scheduled Scanner add-on" alt="Scheduled Scanner add-on" /></a>';
    echo '</td></tr></table>';
  } // schedule_ad_page


  // ad for add-on
  static function logger_ad_page() {
    echo '<div class="submit-test-container"><p><b>Events Logger</b> is a module in <b>Security Ninja PRO</b>. It monitors, tracks and reports every change on your WordPress site, both in the admin and on the frontend. More than 50 events are instantly tracked with all details!</p><p>
    <a target="_blank" href="' . wf_sn::generate_sn_web_link('tab_events_logger', '/events-logger/') . '" class="button-primary input-button">Find out more</a></p></div>';

    echo '<table class="addon-ad" width="100%"><tr><td width="50%" valign="top">';
    echo '<ul class="sn-list">';
    echo '<li>monitor, track and <b>log more than 50 events</b> on the site in great detail</li>
          <li><b>know what happened</b> on the site at any time, in the admin and on the frontend</li>
          <li>prevent <b>"I didn\'t do it"</b> conversations with clients - Events Logger doesn\'t forget or lie</li>
          <li>easily <b>filter</b> trough the data</li>
          <li>know exactly when and <b>how an action happened</b>, and who did it</li>
          <li>receive <b>email alerts</b> for selected groups of events</li>
          <li>each logged event has the following details:<ul>
             <li>date and time</li>
             <li>event description (ie: "Search widget was added to Primary sidebar" or "Failed login attempt with username asdf.")</li>
             <li>username and role of user who did the action</li>
             <li>IP and user agent of the user</li>
             <li>module</li>
             <li>WordPress action/filter</li></ul></li>
          <li>complete integration with Ninja\'s easy-to-use GUI</li>
          <li>it\'s compatible with all themes and plugins</li>';
    echo '</ul>';
    echo '<p><a class="hide_tab" data-tab-id="logger" href="#" title="Hide this tab"><i>No thank you, I\'m not interested (hide this tab)</i></a></p>';
    echo '</td><td>';
    echo '<a target="_blank" href="' . wf_sn::generate_sn_web_link('tab_events_logger', '/events-logger/') . '" title="Events Logger add-on"><img style="max-width: 100%;" src="' .  plugin_dir_url(__FILE__) . 'images/events-logger.jpg" title="Events Logger add-on" alt="Events Logger add-on" /></a>';
    echo '</td></tr></table>';
  } // logger_ad_page


  // whole options page
  static function main_page() {
    // redundant but doesn't hurt
    if (!current_user_can('administrator'))  {
      wp_die('You do not have sufficient permissions to access this page.');
    }

    $hidden_tabs = get_transient('wf_sn_hidden_tabs');
    if (!$hidden_tabs) {
      $hidden_tabs = array();
    }
    $tabs = array();
    $tabs[] = array('id' => 'sn_tests', 'class' => '', 'label' => 'Security Tests', 'callback' => array(__CLASS__, 'tests_table'));
    if (!in_array('core', $hidden_tabs)) {
      $tabs[] = array('id' => 'sn_core', 'title' => 'Core Scanner is a Security Ninja PRO module', 'class' => 'promo_tab', 'label' => 'Core Scanner', 'callback' => array(__CLASS__, 'core_ad_page'));
    }
    if (!in_array('firewall', $hidden_tabs)) {
      $tabs[] = array('id' => 'sn_firewall', 'class' => 'promo_tab', 'title' => 'Cloud Firewall is a Security Ninja PRO module', 'label' => 'Cloud Firewall', 'callback' => array(__CLASS__, 'firewall_ad_page'));
    }
    if (!in_array('autofixer', $hidden_tabs)) {
      $tabs[] = array('id' => 'sn_autofixer', 'title' => 'Auto Fixer is a Security Ninja PRO module', 'class' => 'promo_tab', 'label' => 'Auto Fixer', 'callback' => array(__CLASS__, 'autofixer_ad_page'));
    }
    if (!in_array('optimizer', $hidden_tabs)) {
      $tabs[] = array('id' => 'sn_optimizer', 'class' => 'promo_tab', 'title' => 'Database Optimizer is a Security Ninja PRO module', 'label' => 'Database Optimizer', 'callback' => array('wf_sn_do', 'do_page'));
    }
    if (!in_array('malware2', $hidden_tabs)) {
      $tabs[] = array('id' => 'sn_malware', 'title' => 'Malware Scanner is a Security Ninja PRO module', 'class' => 'promo_tab', 'label' => 'Malware Scanner', 'callback' => array('wf_sn_ms', 'malware_page'));
    }
    if (!in_array('logger', $hidden_tabs)) {
      $tabs[] = array('id' => 'sn_logger', 'class' => 'promo_tab', 'title' => 'Events Logger is a Security Ninja PRO module', 'label' => 'Events Logger', 'callback' => array(__CLASS__, 'logger_ad_page'));
    }
    if (false && !in_array('schedule', $hidden_tabs)) {
      $tabs[] = array('id' => 'sn_schedule', 'class' => 'promo_tab', 'title' => 'Scheduled Scanner is a Security Ninja PRO module', 'label' => 'Scheduled Scanner', 'callback' => array(__CLASS__, 'schedule_ad_page'));
    }
    if (sizeof($tabs) == 1) {
      $tabs[] = array('id' => 'sn_pro', 'class' => 'promo_tab', 'label' => 'Security Ninja PRO', 'callback' => array(__CLASS__, 'pro_ad_page'));
    }
    $tabs = apply_filters('sn_tabs', $tabs);

    echo '<div class="wrap">';
    echo '<div class="wf-sn-title">
           <h2><img src="' . WF_SN_PLUGIN_URL . 'images/security-ninja-logo.png" alt="Security Ninja" title="Security Ninja"></h2>
         </div>';

    echo '<div id="tabs">';
    echo '<ul>';
    foreach ($tabs as $tab) {
	    if (!empty($tab['label'])){
        echo '<li><a title="' . @$tab['title'] . '" href="#' . $tab['id'] . '" class="' . $tab['class'] . '">' . $tab['label'] . '</a></li>';
	    }
    }
    echo '</ul>';

    foreach ($tabs as $tab) {
      if(!empty($tab['callback'])) {
	      echo '<div style="display: none;" id="' . $tab['id'] . '">';
        call_user_func($tab['callback']);
		    echo '</div>';
	    }
    }

    echo '</div>'; // tabs
    echo '</div>'; // wrap
  } // main_page


  // display tests table
  static function tests_table() {
    // get test results from cache
	  $tests = get_option(WF_SN_RESULTS_KEY);

    echo '<div class="submit-test-container">
          <input type="submit" value=" Analyze Site " id="run-tests" class="button-primary" name="Submit" />';

    if (!empty($tests['last_run'])) {
      echo '<span class="sn-notice">Tests were last run on ' . date(get_option('date_format') . ' @ ' . get_option('time_format'), $tests['last_run']) . '.';
      if (!empty($tests['run_time'])) {
        echo ' It took ' . number_format($tests['run_time'], 1) . ' seconds to run them.';
      }
      echo '</span>';

      $bad = $warning = $good = $score = $total =  0;
      foreach($tests['test'] as $test_name => $test_details) {
        if (substr($test_name, 0, 3) == 'ad_') {
          continue;
        }
        $total += $test_details['score'];
        if ($test_details['status'] == 10) {
          $good++;
          $score += $test_details['score'];
        } elseif ($test_details['status'] == 0) {
          $bad++;
        } else {
          $warning++;
        }
      }

      $score = round($score / $total * 100);

      echo '<div id="counters">';
      if ($good == 1) {
        echo '<span class="good">' . $good . '<br><i>test passed</i></span>';
      } else {
        echo '<span class="good">' . $good . '<br><i>tests passed</i></span>';
      }
      if ($warning == 1) {
        echo '<span class="warning">' . $warning .'<br><i>test has warnings</i></span>';
      } else {
        echo '<span class="warning">' . $warning .'<br><i>tests have warnings</i></span>';
      }
      if ($bad == 1) {
        echo '<span class="bad">' . $bad . '<br><i>test failed</i></span>';
      } else {
        echo '<span class="bad">' . $bad . '<br><i>tests failed</i></span>';
      }
      echo '<span class="score">' . $score . '%<br><i>overall site score</i></span>';
      echo '</div>';
    }

    if (empty($tests['last_run'])) {
      echo '<p>Security Ninja <b>tests were never run</b>. Click "Analyze Site" to run them now and analyze your site for security vulnerabilities.</p>';
    }
    echo '<p><strong>Please read!</strong> These tests only serve as suggestions! Although they cover years of best practices in security getting all test <i>green</i> does not guarantee your site will not get hacked. Likewise, having them all <i>red</i> doesn\'t mean you\'ll certainly get hacked. Please read each test\'s detailed information to see if it represents a real security issue for your site. Suggestions and test results apply to public, production sites, not local, development ones.</p>';

    echo '</div>';

    $out = '';
    if (!empty($tests['last_run'])) {

      $out .= '<table class="wp-list-table widefat" cellspacing="0" id="security-ninja">';
      $out .= '<thead><tr>';
      $out .= '<th class="sn-status">Status</th>';
      $out .= '<th>Test description</th>';
      $out .= '<th>Test results</th>';
      $out .= '<th>&nbsp;</th>';
      $out .= '</tr></thead>';
      $out .= '<tbody>';

      if (is_array($tests['test'])) {
        // test results
        foreach($tests['test'] as $test_name => $details) {
          $out .= '<tr>
                  <td class="sn-status">' . wf_sn::status($details['status']) . '</td>
                  <td>' . $details['title'] . '</td>
                  <td>' . $details['msg'] . '</td>';

          if (substr($test_name, 0, 3) == 'ad_') {
            $out .= '<td class="sn-details"><a target="_blank" href="' . wf_sn::generate_sn_web_link('tests_table_' . $test_name) . '" class="button action skip-button"><b>See what PRO offers</b></a></td>';
          } elseif ($details['status'] != 10) {
            $out .= '<td class="sn-details"><a data-test-name="' . $test_name . '" href="#' . $test_name . '" class="button action">Details, Tips &amp; Auto Fixer</a></td>';
          } else {
            $out .= '<td class="sn-details"><a data-test-name="' . $test_name . '" href="#' . $test_name . '" class="button action">Details &amp; Tips</a></td>';
          }
          $out .= '</tr>';
        } // foreach ($tests)
      } else { // no test results
        $out .= '<tr>
                <td colspan="4">No test results are available. Click "Analyze Site" to run tests now.</td>
              </tr>';
      } // if tests

      $out .= '</tbody>';
      $out .= '<tfoot><tr>';
      $out .= '<th class="sn-status">Status</th>';
      $out .= '<th>Test description</th>';
      $out .= '<th>Test results</th>';
      $out .= '<th>&nbsp;</th>';
      $out .= '</tr></tfoot>';
      $out .= '</table>';
    } // if $results

    $out = apply_filters('sn_tests_table', $out, $tests);
    echo $out;
  } // tests_table


  // helper function to generate tagged buy links
  static function generate_sn_web_link($placement = '', $page = '/', $params = array(), $anchor = '') {
    $base_url = 'https://wpsecurityninja.com';
    if ('/' != $page) {
      $page = '/' . trim($page, '/') . '/';
    }

    $promo_delta = 1 * HOUR_IN_SECONDS;
    $options = get_option(WF_SN_OPTIONS_KEY);
    $default_params = array('utm_source' => 'security_ninja', 'utm_medium' => 'plugin', 'utm_content' => $placement, 'utm_campaign' => 'security_ninja_v' . wf_sn::$version);

    $parts = array_merge($default_params, $params);
    if (!empty($anchor)) {
      $anchor = '#' . trim($anchor, '#');
    }

    $out = $base_url . $page . '?' . http_build_query($parts, '', '&amp;') . $anchor;

    return $out;
  } // generate_sn_web_link


  // run all tests; via AJAX
  static function run_tests($return = false) {
    if (defined('DOING_AJAX') && DOING_AJAX) {
      check_ajax_referer('wf_sn_run_tests');
    }

    @set_time_limit(WF_SN_MAX_EXEC_SEC);
    $test_count = 0;
    $start_time = microtime(true);
    $test_description['last_run'] = current_time('timestamp');

    foreach(wf_sn_tests::$security_tests as $test_name => $test){
      if ($test_name[0] == '_' || in_array($test_name, self::$skip_tests)) {
        continue;
      }
      $response = wf_sn_tests::$test_name();

      $test_description['test'][$test_name]['title'] = $test['title'];
      $test_description['test'][$test_name]['status'] = $response['status'];
      $test_description['test'][$test_name]['score'] = $test['score'];

      if (!isset($response['msg'])) {
        $response['msg'] = '';
      }

      if ($response['status'] == 10) {
        $test_description['test'][$test_name]['msg'] = sprintf($test['msg_ok'], $response['msg']);
      } elseif ($response['status'] == 0) {
        $test_description['test'][$test_name]['msg'] = sprintf($test['msg_bad'], $response['msg']);
      } else {
        $test_description['test'][$test_name]['msg'] = sprintf($test['msg_warning'], $response['msg']);
      }
      $test_count++;
    } // foreach

    $test_description['run_time'] = microtime(true) - $start_time;

    do_action('security_ninja_done_testing', $test_description, microtime(true) - $start_time);

    $pointers = get_option(WF_SN_POINTERS_KEY);
    if (!empty($pointers['welcome'])) {
      unset($pointers['welcome']);
      update_option(WF_SN_POINTERS_KEY, $pointers);
    }


    if ($return) {
      return $test_description;
    } else {
      update_option(WF_SN_RESULTS_KEY, $test_description);
      die('1');
    }
  } // run_test


  // convert status integer to button
  static function status($int) {
    if ($int == 0) {
      $string = '<span class="sn-error">Failed</span>';
    } elseif ($int == 10) {
      $string = '<span class="sn-success">Passed</span>';
    } else {
      $string = '<span class="sn-warning">Warning</span>';
    }

    return $string;
  } // status


  // reset pointers on activation and save some info
  static function activate() {
    $pointers = array();
    $pointers['welcome'] = array('target' => '#menu-tools', 'edge' => 'left', 'align' => 'right', 'content' => 'Thank you for installing <b>Security Ninja</b>! Open <a href="tools.php?page=wf-sn">Tools - Security Ninja</a> to analyze your site.');
    update_option(WF_SN_POINTERS_KEY, $pointers);

    $options = get_option(WF_SN_OPTIONS_KEY, array());
    if (!isset($options['first_version']) || !isset($options['first_install'])) {
      $options['first_version'] = wf_sn::get_plugin_version();
      $options['first_install'] = current_time('timestamp');
      $options['first_install_gmt'] = time();
      update_option(WF_SN_OPTIONS_KEY, $options);
    }
  } // activate


  // clean-up when deactivated
  static function deactivate() {
    delete_option(WF_SN_RESULTS_KEY);
    delete_option(WF_SN_POINTERS_KEY);
    delete_transient('wf_sn_hidden_tabs');
  } // deactivate


  // clean-up when deleted
  static function uninstall() {
    delete_option(WF_SN_RESULTS_KEY);
    delete_option(WF_SN_OPTIONS_KEY);
    delete_option(WF_SN_POINTERS_KEY);
    delete_transient('wf_sn_hidden_tabs');
  } // delete
} // wf_sn class


// hook everything up
register_activation_hook(__FILE__, array('WF_SN', 'activate'));
register_deactivation_hook(__FILE__, array('WF_SN', 'deactivate'));
register_uninstall_hook(__FILE__, array('GMW', 'uninstall'));
add_action('init', array('WF_SN', 'init'));
add_action('plugins_loaded', array('WF_SN', 'plugins_loaded'));