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/matrivandana.org/www/wp-content/plugins/nextgen-gallery/
Upload File :
Current File : /home/matrivandana.org/www/wp-content/plugins/nextgen-gallery/nggallery.php
<?php
/**
 * Plugin Name: NextGEN Gallery
 * Description: The most popular gallery plugin for WordPress and one of the most popular plugins of all time with over 30 million downloads.
 * Version: 3.59.2
 * Author: Imagely
 * Plugin URI: https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/
 * Author URI: https://www.imagely.com
 * License: GPLv3
 * Text Domain: nggallery
 * Domain Path: /static/I18N/
 * Requires PHP: 7.0
 *
 * @package Nextgen Gallery
 */

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use Imagely\NGG\Admin\AMNotifications;
use Imagely\NGG\Admin\About;
use Imagely\NGG\Admin\Ecommerce_Preview;

/**
 * @deprecated
 */
class E_Clean_Exit extends RuntimeException {}

/**
 * @deprecated
 */
class E_NggErrorException extends RuntimeException {}

/**
 * Thrown when a datamapper entity does not exist
 *
 * @deprecated
 */
class E_EntityNotFoundException extends RuntimeException {}

/**
 * @deprecated
 */
class E_ColumnsNotDefinedException extends RuntimeException {}

/**
 * Thrown when an invalid data type is used as an entity, such as an associative array which is not supported.
 */
class E_InvalidEntityException extends RuntimeException {

	public function __construct( $message = false, $code = 0 ) {
		// If no message was provided, create a default message.
		if ( ! $message ) {
			$message = 'Invalid data type used for entity. Please use stdClass or a subclass of \Imagely\NGG\DataMapper\Model';
		}
		parent::__construct( $message, $code );
	}
}

class E_UploadException extends RuntimeException {

	public function __construct( $message = '', $code = 0, $previous = null ) {
		if ( ! $message ) {
			$message = 'There was a problem uploading the file.';
		}
		parent::__construct( $message, $code, $previous );
	}
}

class E_InsufficientWriteAccessException extends RuntimeException {

	public function __construct( $message = false, $filename = null, $code = 0, $previous = null ) {
		if ( ! $message ) {
			$message = 'Could not write to file. Please check filesystem permissions.';
		}
		if ( $filename ) {
			$message .= " Filename: {$filename}";
		}
		parent::__construct( $message, $code, $previous );
	}
}

class E_NoSpaceAvailableException extends RuntimeException {

	public function __construct( $message = '', $code = 0, $previous = null ) {
		if ( ! $message ) {
			$message = 'You have exceeded your storage capacity. Please remove some files and try again.';
		}
		parent::__construct( $message, $code, $previous );
	}
}

class E_No_Image_Library_Exception extends RuntimeException {

	public function __construct( $message = '', $code = 0, $previous = null ) {
		if ( ! $message ) {
			$message = 'The site does not support the GD Image library. Please ask your hosting provider to enable it.';
		}
		parent::__construct( $message, $code, $previous );
	}
}

/**
 * Initializes all plugin hooks, actions, namespace autoloader, and defines constants.
 */
class C_NextGEN_Bootstrap {

	protected static $pope_loaded = false;

	public static $debug = false;

	public $minimum_ngg_pro_version  = '2.0.5';
	public $minimum_ngg_plus_version = '1.0.1';

	/**
	 * Holds Notifications Object
	 */
	public $notifications = null;

	public function __construct() {

		if ( defined( 'NGG_ENABLE_SHUTDOWN_EXCEPTION_HANDLER' ) && NGG_ENABLE_SHUTDOWN_EXCEPTION_HANDLER ) {
			set_exception_handler( __CLASS__ . '::shutdown' );
		}
		// NextGEN Pro still throws E_Clean_Exit rather than calling exit(), which must be handled by the shutdown handler.
		elseif ( self::get_pro_api_version() < 4.0 && ( ! defined( 'NGG_DISABLE_SHUTDOWN_EXCEPTION_HANDLER' ) || ! NGG_DISABLE_SHUTDOWN_EXCEPTION_HANDLER ) ) {
			set_exception_handler( __CLASS__ . '::shutdown' );
		}

		spl_autoload_register( [ $this, 'autoloader' ] );

		// Allow Composer dependencies to be found and loaded.
		require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor/autoload.php';

		// If another plugin or theme with the POPE library (such as the legacy Photocrati theme) is active during.
		// the NextGEN activation process, it may produce warnings that can stop this plugin from activating.
		if ( ! $this->is_activating() && ! $this->is_topscorer_request() ) {
			$this->define_constants();
			$this->add_legacy_pro_compat();
			$this->register_hooks();

			include_once NGG_PLUGIN_DIR . '/src/Functions/deprecated.php';
			include_once NGG_PLUGIN_DIR . '/src/Functions/admin.php';
			include_once NGG_PLUGIN_DIR . '/src/Functions/compat.php';

			// Legacy NGG 1x code was not namespaced and must be loaded manually before POPE.
			include_once NGG_PLUGIN_DIR . '/src/Legacy/nggallery.php';

			$this->notifications = new AMNotifications();
			$this->notifications->hooks();

			if ( is_admin() ) {
				( new About() )->hooks();
				( new Ecommerce_Preview() )->hooks();
			}

			$this->load_pope();

			do_action( 'ngg_initialized' );
		}
	}

	/**
	 * @deprecated This class will be removed if there's no complaints made after defaulting to the NGG_ENABLE_SHUTDOWN_EXCEPTION_HANDLER constant
	 * @param Exception $exception
	 */
	public static function shutdown( $exception = null ) {
		if ( is_null( $exception ) ) {
			$name = php_sapi_name();
			if ( false === strpos( $name, 'cgi' )
			&& version_compare( PHP_VERSION, '5.3.3' ) >= 0 ) {
				$status = session_status();
				if ( in_array( $status, [ PHP_SESSION_DISABLED, PHP_SESSION_NONE ], true ) ) {
					session_write_close();
				}
				fastcgi_finish_request();
			} else {
				exit();
			}
		} elseif ( ! ( $exception instanceof E_Clean_Exit ) ) {
			if ( ob_get_level() > 0 ) {
				ob_end_clean();
			}
			self::print_exception( $exception );
		}
	}

	public static function print_exception( $exception ) {
		$klass = get_class( $exception );
		echo "<h1>{$klass} thrown</h1>";
		echo "<p>{$exception->getMessage()}</p>";
		if ( self::$debug or ( defined( 'NGG_DEBUG' ) and NGG_DEBUG == true ) ) {
			echo '<h3>Where:</h3>';
			echo "<p>On line <strong>{$exception->getLine()}</strong> of <strong>{$exception->getFile()}</strong></p>";
			echo '<h3>Trace:</h3>';
			echo "<pre>{$exception->getTraceAsString()}</pre>";
			if ( method_exists( $exception, 'getPrevious' ) ) {
				if ( ( $previous = $exception->getPrevious() ) ) {
					self::print_exception( $previous );
				}
			}
		}
	}

	public function autoloader( $class ) {
		$prefix = 'Imagely\\NGG\\';

		$base_dir = __DIR__ . '/src/';

		$len = strlen( $prefix );
		if ( strncmp( $prefix, $class, $len ) !== 0 ) {
			return;
		}

		$relative_class = substr( $class, $len );

		$file = $base_dir . str_replace( '\\', DIRECTORY_SEPARATOR, $relative_class ) . '.php';

		if ( file_exists( $file ) ) {
			require $file;
		}
	}

	public function is_topscorer_request() {
		// Nonce verification is not necessary here: NextGEN skips loading certain components based on the URL in order
		// to maintain compatibility with the Top Scorer plugin.
		//
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		return strpos( $_SERVER['REQUEST_URI'], 'topscorer/v1' ) !== false;
	}

	public function is_activating(): bool {
		// Nonce verification is not necessary here: NextGEN will not load various components if the current URL
		// indicates that WordPress is in the process of activating a plugin.
		//
		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		$retval = strpos( $_SERVER['REQUEST_URI'], 'plugins.php' ) !== false && isset( $_REQUEST['action'] ) && in_array( $_REQUEST['action'], [ 'activate-selected' ] );

		if ( ! $retval && strpos( $_SERVER['REQUEST_URI'], 'update.php' ) !== false && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'install-plugin' && isset( $_REQUEST['plugin'] ) && strpos( $_REQUEST['plugin'], 'nextgen-gallery' ) === 0 ) {
			$retval = true;
		}

		if ( ! $retval && strpos( $_SERVER['REQUEST_URI'], 'update.php' ) !== false && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'activate-plugin' && isset( $_REQUEST['plugin'] ) && strpos( $_REQUEST['plugin'], 'nextgen-gallery' ) === 0 ) {
			$retval = true;
		}

		return $retval;
		// phpcs:enable WordPress.Security.NonceVerification.Recommended
	}

	/**
	 * These methods will be removed over time once the announcement of their deprecation has been made public. In
	 * order to allow third party code to remain compatible this is not being placed behind a compatibility level
	 * check.
	 */
	public function add_legacy_pro_compat() {
		class_alias( '\Imagely\NGG\Admin\FormManager', 'C_Form_Manager' );
		class_alias( '\Imagely\NGG\Admin\Notifications\Manager', 'C_Admin_Notification_Manager' );
		class_alias( '\Imagely\NGG\Admin\RequirementsManager', 'C_Admin_Requirements_Manager' );
		class_alias( '\Imagely\NGG\DataMappers\Album', 'C_Album_Mapper' );
		class_alias( '\Imagely\NGG\DataMappers\Gallery', 'C_Gallery_Mapper' );
		class_alias( '\Imagely\NGG\DataMappers\Image', 'C_Image_Mapper' );
		class_alias( '\Imagely\NGG\DataStorage\MetaData', 'C_NextGen_Metadata' );
		class_alias( '\Imagely\NGG\DataTypes\LegacyImage', 'C_Image_Wrapper' );
		class_alias( '\Imagely\NGG\DataTypes\Lightbox', 'C_NGG_Lightbox' );
		class_alias( '\Imagely\NGG\DisplayType\Installer', 'C_Display_Type_Installer' );
		class_alias( '\Imagely\NGG\DisplayType\InstallerProxy', 'C_Gallery_Display_Installer' );
		class_alias( '\Imagely\NGG\DisplayTypes\Taxonomy', 'C_Taxonomy_Controller' );
		class_alias( '\Imagely\NGG\Display\I18N', 'M_I18N' );
		class_alias( '\Imagely\NGG\Display\Shortcodes', 'C_NextGen_Shortcode_Manager' );
		class_alias( '\Imagely\NGG\DisplayedGallery\Renderer', 'C_Displayed_Gallery_Renderer' );
		class_alias( '\Imagely\NGG\DisplayedGallery\TriggerManager', 'C_Displayed_Gallery_Trigger_Manager' );
		class_alias( '\Imagely\NGG\DynamicStylesheets\Manager', 'C_Dynamic_Stylesheet_Controller' );
		class_alias( '\Imagely\NGG\DynamicThumbnails\Manager', 'C_Dynamic_Thumbnails_Manager' );
		class_alias( '\Imagely\NGG\IGW\ATPManager', 'M_Attach_To_Post' );
		class_alias( '\Imagely\NGG\IGW\Controller', 'C_Attach_Controller' );
		class_alias( '\Imagely\NGG\Settings\Settings', 'C_NextGen_Settings' );
		class_alias( '\Imagely\NGG\Settings\Settings', 'C_Photocrati_Settings_Manager' );
		class_alias( '\Imagely\NGG\Util\Filesystem', 'C_Fs' );
		class_alias( '\Imagely\NGG\Util\Installer', 'C_Photocrati_Installer' );
		class_alias( '\Imagely\NGG\Util\Router', 'C_Router' );
		class_alias( '\Imagely\NGG\Util\RoutingApp', 'C_Routing_App' );
		class_alias( '\Imagely\NGG\Util\Serializable', 'C_NextGen_Serializable' );
		class_alias( '\Imagely\NGG\Util\Transient', 'C_Photocrati_Transient_Manager' );
	}

	public function fix_loading_order() {
		// If a plugin wasn't activated/deactivated siliently, we can listen for these things.
		if ( did_action( 'activate_plugin' ) || did_action( 'deactivate_plugin' ) ) {
			return;
		} elseif ( strpos( $_SERVER['REQUEST_URI'], 'plugins' ) !== false ) {
			return;
		} elseif ( ! $this->is_page_request() ) {
			return;
		}

		$plugins = get_option( 'active_plugins' );

		// Remove NGG from the list.
		$ngg   = basename( __DIR__ ) . '/' . basename( __FILE__ );
		$order = [];
		foreach ( $plugins as $plugin ) {
			if ( $plugin != $ngg ) {
				$order[] = $plugin;
			}
		}

		// Get the position of either NGG Pro or NGG Plus.
		$insert_at = false;
		for ( $i = 0; $i < count( $order ); $i++ ) {
			$plugin = $order[ $i ];
			if ( strpos( $plugin, 'nggallery-pro' ) !== false ) {
				$insert_at = $i + 1;
			} elseif ( strpos( $plugin, 'ngg-plus' ) !== false ) {
				$insert_at = $i + 1;
			}
		}

		// Re-insert NGG after Pro or Plus.
		if ( $insert_at === false || $insert_at === count( $order ) ) {
			$order[] = $ngg;
		} elseif ( $insert_at === 0 ) {
			array_unshift( $order, $ngg );
		} else {
			array_splice( $order, $insert_at, 0, [ $ngg ] );
		}

		if ( $order != $plugins ) {
			$order = array_filter( $order );
			update_option( 'active_plugins', $order );
		}
	}

	public static function get_legacy_module_directory( $module_id ) {
		// POPE is not loaded; return the result from a manual mapping of id -> directory name.
		$module_dir = null;

		if ( $module_id === 'photocrati-nextgen_pagination' ) {
			$module_dir = 'nextgen_pagination';
		}

		if ( $module_id === 'photocrati-attach_to_post' ) {
			$module_dir = 'attach_to_post';
		}
		if ( $module_id === 'photocrati-cache' ) {
			$module_dir = 'cache';
		}
		if ( $module_id === 'photocrati-dynamic_stylesheet' ) {
			$module_dir = 'dynamic_stylesheet';
		}
		if ( $module_id === 'photocrati-dynamic_thumbnails' ) {
			$module_dir = 'dynamic_thumbnails';
		}
		if ( $module_id === 'photocrati-frame_communication' ) {
			$module_dir = 'frame_communication';
		}
		if ( $module_id === 'photocrati-fs' ) {
			$module_dir = 'fs';
		}
		if ( $module_id === 'photocrati-i18n' ) {
			$module_dir = 'i18n';
		}
		if ( $module_id === 'photocrati-lightbox' ) {
			$module_dir = 'lightbox';
		}
		if ( $module_id === 'photocrati-nextgen-data' ) {
			$module_dir = 'nextgen_data';
		}
		if ( $module_id === 'photocrati-nextgen-legacy' ) {
			$module_dir = 'ngglegacy';
		}
		if ( $module_id === 'photocrati-nextgen_basic_gallery' ) {
			$module_dir = 'nextgen_basic_gallery';
		}
		if ( $module_id === 'photocrati-nextgen_basic_thumbnails' ) {
			$module_dir = 'nextgen_basic_gallery';
		}
		if ( $module_id === 'photocrati-nextgen_basic_slideshow' ) {
			$module_dir = 'nextgen_basic_gallery';
		}
		if ( $module_id === 'photocrati-nextgen_basic_imagebrowser' ) {
			$module_dir = 'nextgen_basic_imagebrowser';
		}
		if ( $module_id === 'photocrati-nextgen_basic_singlepic' ) {
			$module_dir = 'nextgen_basic_singlepic';
		}
		if ( $module_id === 'photocrati-nextgen_basic_tagcloud' ) {
			$module_dir = 'nextgen_basic_tagcloud';
		}
		if ( $module_id === 'photocrati-nextgen_basic_templates' ) {
			$module_dir = 'nextgen_basic_templates';
		}
		if ( $module_id === 'photocrati-nextgen_block' ) {
			$module_dir = 'nextgen_block';
		}
		if ( $module_id === 'photocrati-nextgen_gallery_display' ) {
			$module_dir = 'nextgen_gallery_display';
		}
		if ( $module_id === 'photocrati-ajax' ) {
			$module_dir = 'ajax';
		}

		if ( $module_dir ) {
			return NGG_MODULE_DIR . DIRECTORY_SEPARATOR . $module_dir;
		}

		if ( defined( 'NGG_PRO_MODULES_DIR' ) ) {
			// This is a bit of a hack, but it's easiest to just dump all of these here in one place.
			// The following are all Starter/Plus/Pro modules.
			if ( $module_id === 'photocrati-nextgen_pro_captions' ) {
				$module_dir = 'nextgen_pro_captions';
			}
			if ( $module_id === 'photocrati-nextgen_pro_ecommerce' ) {
				$module_dir = 'ecommerce';
			}
			if ( $module_id === 'photocrati-auto_update' ) {
				$module_dir = 'autoupdate';
			}
			if ( $module_id === 'photocrati-auto_update-admin' ) {
				$module_dir = 'autoupdate_admin';
			}
			if ( $module_id === 'imagely-braintree' ) {
				$module_dir = 'braintree';
			}
			if ( $module_id === 'photocrati-cheque' ) {
				$module_dir = 'cheque';
			}
			if ( $module_id === 'photocrati-comments' ) {
				$module_dir = 'comments';
			}
			if ( $module_id === 'photocrati-coupons' ) {
				$module_dir = 'coupons';
			}
			if ( $module_id === 'photocrati-free_gateway' ) {
				$module_dir = 'free_gateway';
			}
			if ( $module_id === 'photocrati-galleria' ) {
				$module_dir = 'galleria';
			}
			if ( $module_id === 'photocrati-image_protection' ) {
				$module_dir = 'image_protection';
			}
			if ( $module_id === 'imagely-licensing' ) {
				$module_dir = 'licensing';
			}
			if ( $module_id === 'photocrati-nextgen_pro_albums' ) {
				$module_dir = 'nextgen_pro_albums';
			}
			if ( $module_id === 'photocrati-nextgen_pro_blog_gallery' ) {
				$module_dir = 'nextgen_pro_blog_gallery';
			}
			if ( $module_id === 'photocrati-nextgen_pro_film' ) {
				$module_dir = 'nextgen_pro_film';
			}
			if ( $module_id === 'photocrati-nextgen_pro_horizontal_filmstrip' ) {
				$module_dir = 'nextgen_pro_horizontal_filmstrip';
			}
			if ( $module_id === 'photocrati-nextgen_pro_i18n' ) {
				$module_dir = 'nextgen_pro_i18n';
			}
			if ( $module_id === 'photocrati-nextgen_pro_imagebrowser' ) {
				$module_dir = 'nextgen_pro_imagebrowser';
			}
			if ( $module_id === 'photocrati-nextgen_pro_lightbox' ) {
				$module_dir = 'nextgen_pro_lightbox';
			}
			if ( $module_id === 'photocrati-nextgen_pro_marketing' ) {
				$module_dir = 'nextgen_pro_marketing';
			}
			if ( $module_id === 'photocrati-nextgen_pro_masonry' ) {
				$module_dir = 'nextgen_pro_masonry';
			}
			if ( $module_id === 'photocrati-nextgen_pro_mosaic' ) {
				$module_dir = 'nextgen_pro_mosaic';
			}
			if ( $module_id === 'photocrati-nextgen_pro_proofing' ) {
				$module_dir = 'nextgen_pro_proofing';
			}
			if ( $module_id === 'photocrati-nextgen_pro_settings' ) {
				$module_dir = 'nextgen_pro_settings';
			}
			if ( $module_id === 'photocrati-nextgen_pro_sidescroll' ) {
				$module_dir = 'nextgen_pro_sidescroll';
			}
			if ( $module_id === 'photocrati-nextgen_pro_slideshow' ) {
				$module_dir = 'nextgen_pro_slideshow';
			}
			if ( $module_id === 'photocrati-nextgen_pro_thumbnail_grid' ) {
				$module_dir = 'nextgen_pro_thumbnail_grid';
			}
			if ( $module_id === 'photocrati-nextgen_pro_tile' ) {
				$module_dir = 'nextgen_pro_tile';
			}
			if ( $module_id === 'photocrati-pro-wpcli' ) {
				$module_dir = 'nextgen_pro_wpcli';
			}
			if ( $module_id === 'photocrati-paypal_checkout' ) {
				$module_dir = 'paypal_checkout';
			}
			if ( $module_id === 'photocrati-paypal_express_checkout' ) {
				$module_dir = 'paypal_express_checkout';
			}
			if ( $module_id === 'photocrati-paypal_standard' ) {
				$module_dir = 'paypal_standard';
			}
			if ( $module_id === 'photocrati-nextgen_picturefill' ) {
				$module_dir = 'picturefill';
			}
			if ( $module_id === 'imagely-pro-search' ) {
				$module_dir = 'search';
			}
			if ( $module_id === 'photocrati-stripe' ) {
				$module_dir = 'stripe';
			}
			if ( $module_id === 'photocrati-test_gateway' ) {
				$module_dir = 'test_gateway';
			}

			if ( $module_dir ) {
				return NGG_PRO_MODULES_DIR . DIRECTORY_SEPARATOR . $module_dir;
			}
		}

		// The module was not in the list above, consult POPE if possible.
		if ( self::$pope_loaded ) {
			return \C_Component_Registry::get_instance()->get_module_dir( $module_id );
		}

		return $module_dir;
	}

	public function load_pope( $force = false ) {
		// We allow POPE to load if the requested URL/POST includes photocrati_ajax as it is still used by a few NextGEN
		// modules for XHR such as uploading images.
		//
		// Nonce verification is not necessary here.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( ! $force
			&& empty( $_REQUEST['photocrati_ajax'] )
			&& ( self::get_pro_api_version() >= 4.0 && ! is_admin() )
			&& ! defined( 'EWWW_IMAGE_OPTIMIZER_VERSION' ) // EWWW uses I_Gallery_Storage.
			&& ! defined( 'WP_SMUSH_VERSION' ) // WP_SMUSH_VERSION uses I_Gallery_Storage.
			&& ! defined( 'IMAGIFY_VERSION' ) // Imagify adds their own mixin to C_Gallery_Storage.
			|| self::$pope_loaded ) {
			return;
		}

		// Pope requires a higher limit.
		$tmp = ini_get( 'xdebug.max_nesting_level' );
		if ( $tmp && (int) $tmp <= 300 ) {
			@ini_set( 'xdebug.max_nesting_level', 300 );
		}

		// Enforce interfaces.
		if ( property_exists( 'ExtensibleObject', 'enforce_interfaces' ) ) {
			ExtensibleObject::$enforce_interfaces = EXTENSIBLE_OBJECT_ENFORCE_INTERFACES;
		}

		// Get the component registry.
		$registry = C_Component_Registry::get_instance();

		// Add the default Pope factory utility, C_Component_Factory.
		$registry->add_utility( 'I_Component_Factory', 'C_Component_Factory' );

		// Load embedded products. Each product is expected to load any modules required.
		$registry->add_module_path( NGG_PRODUCT_DIR, 2 );
		$registry->load_all_products();

		// Give third-party plugins that opportunity to include their own products and modules.
		do_action( 'load_nextgen_gallery_modules', $registry );

		// Initializes all loaded modules.
		$registry->initialize_all_modules();

		self::$pope_loaded = true;
	}

	public function is_pro_compatible() {
		$retval = true;

		if ( defined( 'NEXTGEN_GALLERY_PRO_VERSION' ) ) {
			$retval = false;
		}
		if ( defined( 'NEXTGEN_GALLERY_PRO_PLUGIN_BASENAME' ) && ! defined( 'NGG_PRO_PLUGIN_VERSION' ) ) {
			$retval = false; // 1.0 - 1.0.6
		}
		if ( defined( 'NGG_PRO_PLUGIN_VERSION' ) && version_compare( NGG_PRO_PLUGIN_VERSION, $this->minimum_ngg_pro_version ) < 0 ) {
			$retval = false;
		}
		if ( defined( 'NGG_PLUS_PLUGIN_VERSION' ) && version_compare( NGG_PLUS_PLUGIN_VERSION, $this->minimum_ngg_plus_version ) < 0 ) {
			$retval = false;
		}

		return $retval;
	}

	public function render_incompatibility_warning() {
		echo '<div class="updated error"><p>';
		echo esc_html(
			sprintf(
				__(
					'NextGEN Gallery %1$s is incompatible with this version of NextGEN Pro. Please update NextGEN Pro to version %2$s or higher to restore NextGEN Pro functionality.',
					'nggallery'
				),
				NGG_PLUGIN_VERSION,
				$this->minimum_ngg_pro_version
			)
		);
		echo '</p></div>';
	}

	public function render_jquery_wp_55_warning() {
		$render = false;
		global $wp_version;

		$message     = '';
		$account_msg = '';

		if ( defined( 'NGG_PRO_PLUGIN_VERSION' ) && version_compare( NGG_PRO_PLUGIN_VERSION, '3.1' ) < 0 ) {
			$render      = true;
			$message     = __( 'Your version of NextGEN Pro is known to have some issues with NextGEN Gallery 3.4 and later.', 'nggallery' );
			$account_msg = preg_match( '#photocrati#i', wp_get_theme()->get( 'Name' ) )
				? sprintf( __( "Please download the latest version of NextGEN Pro from your <a href='%s' target='_blank'>account area</a>", 'nggallery' ), 'https://members.photocrati.com/account/' )
				: sprintf( __( "Please download the latest version of NextGEN Pro from your <a href='%s' target='_blank'>account area</a>", 'nggallery' ), 'https://www.imagely.com/account/' );
		}

		if ( defined( 'NGG_PLUS_PLUGIN_VERSION' ) && version_compare( NGG_PLUS_PLUGIN_VERSION, '1.7' ) < 0 ) {
			$render      = true;
			$message     = __( 'Your version of NextGEN Plus is known to have some issues with NextGEN Gallery 3.4 and later.', 'nggallery' );
			$account_msg = preg_match( '#photocrati#i', wp_get_theme()->get( 'Name' ) )
				? sprintf( __( "Please download the latest version of NextGEN Plus from your <a href='%s' target='_blank'>account area</a>", 'nggallery' ), 'https://members.photocrati.com/account/' )
				: sprintf( __( "Please download the latest version of NextGEN Plus from your <a href='%s' target='_blank'>account area</a>", 'nggallery' ), 'https://www.imagely.com/account/' );
		}

		if ( ! $render ) {
			return;
		}

		print '<div class="updated error"><p>';
		print $message;
		print ' ';
		print $account_msg;

		if ( version_compare( $wp_version, '5.5', '>=' ) && version_compare( $wp_version, '5.5.9', '<=' ) ) {
			$note = __( "NOTE: The autoupdater doesn't work on the version of WordPress you have installed.", 'ngallery' );
			print "<div style='font-weight: bold;'>";
			print $note;
			print '</div>';
		}
		print '</p></div>';
	}

	public function register_hooks() {
		// The core installers must be registered before the rest of the initialization is processed.
		\Imagely\NGG\Util\Installer::add_handler( 'legacy-core', 'C_NGG_Legacy_Installer' );
		\Imagely\NGG\Util\Installer::add_handler( 'settings', '\Imagely\NGG\Settings\Installer' );
		\Imagely\NGG\Util\Installer::add_handler( 'pro_display_types', '\Imagely\NGG\DisplayType\Installer' );

		// Register the (de)activation routines.
		add_action( 'deactivate_' . NGG_PLUGIN_BASENAME, [ $this, 'deactivate' ] );
		add_action( 'activate_' . NGG_PLUGIN_BASENAME, [ $this, 'activate' ], -10 );

		// Handle activation redirect to overview page.
		add_action( 'init', [ $this, 'handle_activation_redirect' ] );

		// Ensure that settings manager is saved as an array.
		add_filter( 'pre_update_option_ngg_options', [ $this, 'persist_settings' ] );
		add_filter( 'pre_update_site_option_ngg_options', [ $this, 'persist_settings' ] );

		// Delete displayed gallery transients periodically.
		if ( NGG_CRON_ENABLED ) {
			add_filter( 'cron_schedules', [ $this, 'add_ngg_schedule' ] );
			add_action( 'ngg_delete_expired_transients', [ $this, 'delete_expired_transients' ] );
			add_action( 'wp', [ $this, 'schedule_cron_jobs' ] );
		}

		// Start the plugin!
		add_action( 'init', [ $this, 'update' ], ( PHP_INT_MAX - 2 ) );
		add_action( 'init', [ $this, 'route' ], 5 );

		// NGG extension plugins should be loaded in a specific order.
		add_action( 'shutdown', [ $this, 'fix_loading_order' ] );

		if ( ! $this->is_pro_compatible() ) {
			add_action( 'all_admin_notices', [ $this, 'render_incompatibility_warning' ] );
		}

		add_action( 'admin_init', [ '\Imagely\NGG\Admin\RequirementsManager', 'register_requirements' ], -20 );
		add_action( 'all_admin_notices', [ $this, 'render_jquery_wp_55_warning' ] );

		// Necessary hack for the datamapper to order query results.
		add_filter( 'posts_orderby', [ '\Imagely\NGG\DataStorage\Manager', 'wp_query_order_by' ], 10, 2 );
		add_filter( 'init', [ '\Imagely\NGG\DataStorage\Manager', 'register_custom_post_types' ] );

		add_action( 'rest_api_init', [ '\Imagely\NGG\REST\Manager', 'rest_api_init' ] );

		// Widgets registration.
		add_action(
			'widgets_init',
			function () {
				register_widget( '\Imagely\NGG\Widget\Gallery' );
				register_widget( '\Imagely\NGG\Widget\Slideshow' );
				register_widget( '\Imagely\NGG\Widget\MediaRSS' );
			}
		);

		add_action( 'wp_enqueue_scripts', [ \Imagely\NGG\Display\LightboxManager::get_instance(), 'maybe_enqueue' ] );

		add_action(
			'ngg_delete_image',
			function () {
				\Imagely\NGG\Util\Transient::flush( 'random_widget_gallery_ids' );
			}
		);

		add_filter( 'xmlrpc_methods', [ '\Imagely\NGG\XMLRPC\Manager', 'add_methods' ] );

		// Nonce verification is not necessary here: it is performed by the notification manager's serve_ajax_request() method.
		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		add_action(
			'init',
			function () {
				if ( isset( $_REQUEST['ngg_dismiss_notice'] ) ) {
					// Admin notification handlers are registered in the nextgen_admin module.
					$this->load_pope( true );
					\Imagely\NGG\Admin\Notifications\Manager::get_instance()->serve_ajax_request();
				}
			}
		);
		// phpcs:enable WordPress.Security.NonceVerification.Recommended

		// The following is a hack: we cannot move the Lightroom XHR requests to the REST API because the URL are coded
		// into the lightroom plugin and have no autodiscovery. To avoid dependencies on the deprecated ajax POPE module
		// we only add the 'init' hook here if the URL matches.
		$lightroom_actions = [
			'enqueue_nextgen_api_task_list',
			'get_nextgen_api_path_list',
			'execute_nextgen_api_task_list',
			'get_nextgen_api_token',
		];

		// Nonce verification is not necessary here: authentication is handled by the Lightroom\Controller class.
		//
		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		if ( ! empty( $_REQUEST['photocrati_ajax'] )
		&& ! empty( $_REQUEST['action'] )
		&& '1' === (string) ( $_REQUEST['photocrati_ajax'] )
		&& in_array( $_REQUEST['action'], $lightroom_actions, true ) ) {
			add_action(
				'init',
				function() {
					$this->register_taxonomy();
					(new \Imagely\NGG\Lightroom\Controller())->run();
				},
				0
			);
		} else {
			add_action( 'init', [ $this, 'register_taxonomy' ], 9 );
		}
		// phpcs:enable WordPress.Security.NonceVerification.Recommended

		if ( defined( 'WP_CLI' ) && WP_CLI ) {
			\Imagely\NGG\WPCLI\Manager::register();
		}

		// This is necessary because NextGEN can insert singlepicture images as pre-rendered HTML without a shortcode.
		// This requires we inspect the site content and enqueue the display type's CSS if necessary.
		add_filter(
			'the_content',
			function ( $content ) {
				if ( preg_match( '#<img.*ngg-singlepic.*>#', $content, $matches ) ) {
					wp_enqueue_style(
						'nextgen_basic_singlepic_style',
						\Imagely\NGG\Display\StaticAssets::get_url(
							'SinglePicture/nextgen_basic_singlepic.css',
							'photocrati-nextgen_basic_singlepic#nextgen_basic_singlepic.css'
						),
						[],
						NGG_SCRIPT_VERSION
					);
				}
				return $content;
			},
			PHP_INT_MAX,
			1
		);

		// Component registration.
		\Imagely\NGG\DataMapper\Manager::register_hooks();
		\Imagely\NGG\DisplayType\Manager::register();
		\Imagely\NGG\Display\DisplayManager::register_hooks();
		\Imagely\NGG\Display\I18N::get_instance()->register_hooks();
		\Imagely\NGG\Display\ResourceManager::init();
		\Imagely\NGG\Display\Shortcodes::get_instance()->register_hooks();
		\Imagely\NGG\IGW\ATPManager::get_instance()->register_hooks();
		\Imagely\NGG\IGW\BlockManager::get_instance()->register_hooks();
		\Imagely\NGG\IGW\EventPublisher::get_instance()->register_hooks();
		\Imagely\NGG\Util\Router::get_instance()->register_hooks();
		\Imagely\NGG\Util\ThirdPartyCompatibility::get_instance()->register_hooks();
	}

	/**
	 * Registers the NextGEN taxonomy.
	 *
	 * @return void
	 */
	public function register_taxonomy() {
		// Register the NextGEN taxonomy.
		$args = [
			'label'    => __( 'Picture tag', 'nggallery' ),
			'template' => __( 'Picture tag: %2$l.', 'nggallery' ),
			'helps'    => __( 'Separate picture tags with commas.', 'nggallery' ),
			'sort'     => true,
			'args'     => [ 'orderby' => 'term_order' ],
		];

		register_taxonomy( 'ngg_tag', 'nggallery', $args );
	}

	public function handle_activation_redirect() {
		if ( get_transient( 'ngg-activated' ) ) {
			delete_transient( 'ngg-activated' );
			wp_redirect( admin_url( '?page=nextgen-gallery' ) );
		}
	}

	public function schedule_cron_jobs() {
		if ( ! wp_next_scheduled( 'ngg_delete_expired_transients' ) ) {
			wp_schedule_event( time(), 'ngg_custom', 'ngg_delete_expired_transients' );
		}
	}

	public function add_ngg_schedule( $schedules ) {
		$schedules['ngg_custom'] = [
			'interval' => NGG_CRON_SCHEDULE,
			// Translators: %d - NGG_CRON_SCHEDULE constant -- do not translate.
			'display'  => sprintf( esc_html__( 'Every %d seconds', 'nggallery' ), NGG_CRON_SCHEDULE ),
		];

		return $schedules;
	}

	public function delete_expired_transients() {
		\Imagely\NGG\Util\Transient::get_instance()->flush_expired();
	}

	/**
	 * Ensure that settings are persisted as an array
	 *
	 * @param Imagely\NGG\Settings\Settings|array $settings
	 * @return array
	 */
	public function persist_settings( $settings = [] ) {
		if ( $settings instanceof \Imagely\NGG\Settings\ManagerBase ) {
			$settings = $settings->to_array();
		}
		return $settings;
	}

	public function update() {
		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
			return;
		}

		// Nonce verification is not necessary here.
		//
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( isset( $_REQUEST['doing_wp_cron'] ) ) {
			return;
		}

		$this->load_pope();
		\Imagely\NGG\Util\Installer::update();
	}

	public function route() {
		$this->load_pope();
		$router = \Imagely\NGG\Util\Router::get_instance();

		// Set context to path if subdirectory install.
		$parts     = parse_url( $router->get_base_url( false ) );
		$siteparts = parse_url( get_option( 'home' ) );

		if ( isset( $parts['path'] ) && isset( $siteparts['path'] ) ) {
			if ( strpos( $parts['path'], '/index.php' ) === false ) {
				$router->context = $siteparts['path'];
			} else {
				$new_parts = explode( '/index.php', $parts['path'] );
				if ( ! empty( $new_parts[0] ) && $new_parts[0] == $siteparts['path'] ) {
					$router->context = array_shift( $new_parts );
				}
			}
		}

		$dynamic_thumbs_app = $router->create_app( '/nextgen-image' );
		$dynamic_thumbs_app->rewrite( '/{*}', '/' );
		$dynamic_thumbs_app->route(
			[ '/' ],
			[
				'controller' => '\Imagely\NGG\DynamicThumbnails\Controller',
				'action'     => 'index_action',
			]
		);

		$dynamic_styles_app = $router->create_app( '/nextgen-dcss' );
		$dynamic_styles_app->rewrite( '/{\d}/{*}', '/index--{1}/data--{2}' );
		$dynamic_styles_app->route(
			[ '/' ],
			[
				'controller' => '\Imagely\NGG\DynamicStylesheets\Controller',
				'action'     => 'index_action',
			]
		);

		$igw_app = $router->create_app( '/' . NGG_ATTACH_TO_POST_SLUG );
		$igw_app->rewrite( '/preview/{id}', '/preview/id--{id}' );
		$igw_app->rewrite( '/display_tab_js/{id}', '/display_tab_js/id--{id}' );
		$igw_app->route(
			[ '/' ],
			[
				'controller' => '\Imagely\NGG\IGW\Controller',
				'action'     => 'index_action',
			]
		);

		// Provide a means for modules/third-parties to configure routes.
		do_action_ref_array( 'ngg_routes', [ $router ] );

		// Serve the routes.
		if ( ! $router->serve_request() && $router->has_parameter_segments() ) {
			$router->passthru();
		}
	}

	public function is_page_request() {
		return ! ( defined( 'DOING_AJAX' ) && DOING_AJAX ) && ! ( defined( 'DOING_CRON' ) && DOING_CRON ) && ! ( defined( 'NGG_AJAX_SLUG' ) && strpos( $_SERVER['REQUEST_URI'], NGG_AJAX_SLUG ) !== false );
	}

	public function deactivate() {
		include_once 'products/photocrati_nextgen/class.nextgen_product_installer.php';
		\Imagely\NGG\Util\Installer::add_handler( NGG_PLUGIN_BASENAME, 'C_NextGen_Product_Installer' );
		\Imagely\NGG\Util\Installer::uninstall( NGG_PLUGIN_BASENAME );
	}

	public function activate() {
		\Imagely\NGG\Util\Installer::set_role_caps();
		set_transient( 'ngg-activated', time(), 30 );
	}

	public function define_constants() {
		define( 'NGG_PLUGIN', basename( $this->directory_path() ) );
		define( 'NGG_PLUGIN_SLUG', 'nextgen-gallery' );
		define( 'NGG_PLUGIN_FILE', __FILE__ );
		define( 'NGG_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
		define( 'NGG_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
		define( 'NGG_PLUGIN_URI', plugin_dir_url( __FILE__ ) );
		define( 'NGG_PRODUCT_DIR', implode( DIRECTORY_SEPARATOR, [ rtrim( NGG_PLUGIN_DIR, '/\\' ), 'products' ] ) );
		define( 'NGG_MODULE_DIR', implode( DIRECTORY_SEPARATOR, [ rtrim( NGG_PRODUCT_DIR, '/\\' ), 'photocrati_nextgen', 'modules' ] ) );
		define( 'NGG_PLUGIN_STARTED_AT', microtime() );
		define( 'NGG_PLUGIN_VERSION', '3.59.2' );

		define( 'NGG_SCRIPT_VERSION', defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? (string) mt_rand( 0, mt_getrandmax() ) : NGG_PLUGIN_VERSION );

		// Should we display NGG debugging information?
		if ( ! defined( 'NGG_DEBUG' ) ) {
			define( 'NGG_DEBUG', false );
		}
		self::$debug = NGG_DEBUG;

		// User definable constants.
		if ( ! defined( 'NGG_IMPORT_ROOT' ) ) {
			$path = WP_CONTENT_DIR;
			if ( defined( 'NEXTGEN_GALLERY_IMPORT_ROOT' ) ) {
				$path = NEXTGEN_GALLERY_IMPORT_ROOT;
			}
			define( 'NGG_IMPORT_ROOT', $path );
		}

		// Should the Photocrati cache be enabled.
		if ( ! defined( 'PHOTOCRATI_CACHE' ) ) {
			define( 'PHOTOCRATI_CACHE', true );
		}
		if ( ! defined( 'PHOTOCRATI_CACHE_TTL' ) ) {
			define( 'PHOTOCRATI_CACHE_TTL', 1800 );
		}

		// Cron job.
		if ( ! defined( 'NGG_CRON_SCHEDULE' ) ) {
			define( 'NGG_CRON_SCHEDULE', 900 );
		}

		if ( ! defined( 'NGG_CRON_ENABLED' ) ) {
			define( 'NGG_CRON_ENABLED', true );
		}

		// Don't enforce interfaces.
		if ( ! defined( 'EXTENSIBLE_OBJECT_ENFORCE_INTERFACES' ) ) {
			define( 'EXTENSIBLE_OBJECT_ENFORCE_INTERFACES', false );
		}

		// Where are galleries restricted to?
		if ( ! defined( 'NGG_GALLERY_ROOT_TYPE' ) ) {
			define( 'NGG_GALLERY_ROOT_TYPE', 'site' ); // "content" is the other possible value.
		}

		// Define what file extensions and mime are accepted, with optional WebP.
		$default_extensions_list = 'jpeg,jpg,png,gif';
		$default_mime_list       = 'image/gif,image/jpg,image/jpeg,image/pjpeg,image/png';
		if ( function_exists( 'imagewebp' ) ) {
			$default_extensions_list .= ',webp';
			$default_mime_list       .= ',image/webp';
		}

		if ( ! defined( 'NGG_DEFAULT_ALLOWED_FILE_TYPES' ) ) {
			define( 'NGG_DEFAULT_ALLOWED_FILE_TYPES', $default_extensions_list );
		}

		if ( ! defined( 'NGG_DEFAULT_ALLOWED_MIME_TYPES' ) ) {
			define( 'NGG_DEFAULT_ALLOWED_MIME_TYPES', $default_mime_list );
		}

		add_filter(
			'ngg_allowed_file_types',
			function ( $string ) {
				return explode( ',', $string );
			},
			-10
		);

		add_filter(
			'ngg_allowed_mime_types',
			function ( $string ) {
				return explode( ',', $string );
			},
			-10
		);

		define( 'NGG_LIGHTBOX_OPTIONS_SLUG', 'ngg_lightbox_options' );
		define( 'NGG_ATTACH_TO_POST_SLUG', 'nextgen-attach_to_post' );

		define( 'NGG_DISPLAY_SETTINGS_SLUG', 'ngg_display_settings' );
		define( 'NGG_DISPLAY_PRIORITY_BASE', 10000 );
		define( 'NGG_DISPLAY_PRIORITY_STEP', 2000 );

		define( 'NGG_BASIC_IMAGEBROWSER', 'photocrati-nextgen_basic_imagebrowser' );
		define( 'NGG_BASIC_SINGLEPIC', 'photocrati-nextgen_basic_singlepic' );
		define( 'NGG_BASIC_TAGCLOUD', 'photocrati-nextgen_basic_tagcloud' );
		define( 'NGG_BASIC_THUMBNAILS', 'photocrati-nextgen_basic_thumbnails' );
		define( 'NGG_BASIC_SLIDESHOW', 'photocrati-nextgen_basic_slideshow' );
		define( 'NGG_BASIC_COMPACT_ALBUM', 'photocrati-nextgen_basic_compact_album' );
		define( 'NGG_BASIC_EXTENDED_ALBUM', 'photocrati-nextgen_basic_extended_album' );
		define( 'NGG_BASIC_ALBUM', 'photocrati-nextgen_basic_album' );

		if ( ! defined( 'NGG_RENDERING_CACHE_TTL' ) ) {
			define( 'NGG_RENDERING_CACHE_TTL', PHOTOCRATI_CACHE_TTL );
		}
		if ( ! defined( 'NGG_DISPLAYED_GALLERY_CACHE_TTL' ) ) {
			define( 'NGG_DISPLAYED_GALLERY_CACHE_TTL', PHOTOCRATI_CACHE_TTL );
		}
		if ( ! defined( 'NGG_RENDERING_CACHE_ENABLED' ) ) {
			define( 'NGG_RENDERING_CACHE_ENABLED', PHOTOCRATI_CACHE );
		}
		if ( ! defined( 'NGG_SHOW_DISPLAYED_GALLERY_ERRORS' ) ) {
			define( 'NGG_SHOW_DISPLAYED_GALLERY_ERRORS', NGG_DEBUG );
		}

		define( 'NGG_AJAX_SLUG', 'photocrati_ajax' );
	}

	/**
	 * Returns the path to a file within the plugin root folder
	 *
	 * @param string $file_name
	 * @return string
	 */
	public function file_path( $file_name = null ) {
		$path = __DIR__;
		if ( $file_name != null ) {
			$path .= '/' . $file_name;
		}

		return str_replace( [ '/', '\\' ], DIRECTORY_SEPARATOR, $path );
	}

	/**
	 * Gets the directory path used by the plugin
	 *
	 * @param string|null $dir (optional)
	 * @return string
	 */
	public function directory_path( $dir = null ) {
		return $this->file_path( $dir );
	}

	/**
	 * Returns the level of support for the POPE removal that Pro contains if active. Zero means Pro has not been
	 * updated at all and must rely on hacks in NextGEN for basic features. As POPE is removed, the level of support
	 * will rise, with the oldest checks in NextGEN being phased out the first.
	 *
	 * @return int
	 */
	public static function get_pro_api_version() {
		if ( ! defined( 'NGG_PRO_API_VERSION' ) && ( defined( 'NGG_PLUS_PLUGIN_VERSION' ) || defined( 'NGG_STARTER_PLUGIN_VERSION' ) || defined( 'NGG_PRO_PLUGIN_VERSION' ) ) ) {
			return 3;
		}

		if ( defined( 'NGG_PRO_API_VERSION' ) ) {
			return NGG_PRO_API_VERSION;
		}

		return 10000;
	}
}

new C_NextGEN_Bootstrap();