lk|P9&2K6J(aJ>(PXMsl{f!=G&c6IxS@)&}W0T}a#mxRpXz`2>&d<
zue1vAOc#_na3SBR;0LJ#-BcbKb(M$m6zElUS_R_pLON8BNgkcAIMrg}%I=FI5oq+9
ziQgDiJ@!vzl66ZW5hgOSKG*!jQ^RPI2q)%ki*9Ganldw4=t4S>#Wc~?lW5A(L85Dm
z@n$MJA+LE@<8qgyNf81E&(Z`{^mb0&bz-@Xh}7g$_ns*&_j)xAw&jv28Hq&!id7s6y9Juzvcw3jiZXeDf$U*g
z9_6Gg+7FqXd$hD_+R1Q2$~aIvh;^v?f>s_MfiR!(@gahkR8GKS2#M42@;i=ytb%N(Jd1^a~H_6+*?qZ$A&k>;0s+eGQF!jxfS
zUaCgY?|z!5BXG!N$5HS|XvOjUA;rt0&II?l{unNDJAdp}~SP`%s)o@>7QD93@Xl
z=t(#%iKVSoCdW^dW!4JJ%+&?K`9Y{k?08-vEbms%F7A$Fplpw;trLM8)P?H6^ncHb
znV%Bl-e(%~-D<1Sz+T#Ews=9&6xn&(>}^9#Nc8t>M&U#*SRfw}x{LexG5j1^ru`Mh
z>NUHHmcQ8-xlrd1b0yKm23)U>2=j89Pgx0)uTOuOw4ok7_OgbbL-;c+$!-w9b!5Pj
z|83Iac}B!<;2I!kKpFVZ3y{IE9Nsr-=ohmI{jJjQOGX;-{JR`$BT+
zM76DuN#W+xG;!j#C$A>1g0#Z){WsaHY<{pqs49$!vzT@4VEr;q|u?c*kDcwd2LE4{&H)2$e4;NlziH%JAJk
z8{R&SwE?&?n9qf!X3We>R6T7T&O0t?@)i0h!^({26EhgSHre>%)|{FutlUU(vU`b+
zrv`Jdf>dowiZ-cM)iUo@XWx#5GM|qx4n5CY#LpZ^JY65K4-DCSv7bboq>B~{w8j<-
zj)mX`rDih9C^N^ed8eumCCUS1dCowUd2_Imcmucm
z9RfF3yo>I;Uh0y0IB6kyA(_6SkD0#8bFDC~!P5?6Qvfv;zcl;D$yI+uCya96LE-4P
z(|i7XOlzfyTgQTZJAd$qIBTmJhgpIT*m2$X=nT)2e7DGnbHkb(sr3&STK0_QX^`q32QZy#oi9C
z(DKK*MPDBcYVITrsWWui=O;%cdX0CB9oTB`_bhj#bMcBqI4DTJvN(xviUrG1rO5gC
zG2ZC{=Q7LI!;A8z?FO)ra#XDN8DeghklE@0SYAFqv?X->XH&rtihMYA97Dq~`fB`%
zTxvTgm~s)jA^TgSyu_beU!BfdA_OsWAh`7ca1`xCbF#O^BK7Z(qH}om?F5gU3*=(u
z(z5kE{=7icHLIoAIWbU#z+mpeqIEq$hYwfd&~i{%a?pvziX5UjIL?L+3^*Oq`Me^R
z>Mmv_Dw$1(MS1uNSyRS2m#5YLjtRSZJ{NjCS+d3CzSf;mUz9Z(mv48EKqZh;h`+9Zm-g}M*D}g|P6fBrC@!CZBla~n4IYouesKJMJ{ws)3W%X6F}0<+A|92Bn@V<
z&Wde-Zy0OouMa<)03$R2kX_alGPSvqyXL?(b*qB5(<=|AI
z!Dvnk1^&}~38wrpe<3h{YsfPj_Fim8cX7)X_A0d2X6GQZPUmr9otGyKj6RWrbU!86
zYzLZuT4d25W>>RT^?Y$0*VLAfp2hAl(W623^Ut=c(>C9;7cZ~eHHro&mUx%`0GGs3
z46Q|wa~WFlzha|&=`KpGAXm6v;9SC)Wcg)(RTkKPn0QnTZ;p@0
zITZ~(=&sru_f6}E;TzyI&D^3o`K11yYZ-af(99KlLOqUp7|mbqpQ+&6Wz70$=AAjg
zRR=mxOF~J95vQp7NWlh?DAd#aOEaR=-ifkxA{fmJ{B#gnT
z;_lZmFK8puo%t>>h3qL+MeKmgax#2Dfl?|hEqCgg5D1dIBO)frfX@Bt2`|3HdbNb$
zfrpEU40`O81h%a{8n%
zz|R-3)GWjh&UU=`M&?gV`|-b<#dW%38jX?3>1|_aS}0=m1f|{a$|+a&sCz&J_gQMq
z=mMDN8T7RifQ9UlQykKfQ$X?NM5_DSmG{M&Q~avb@EXsziPa&*NwIvu4T(Z;F;?1b
zH26#0lf{)Y=Gx8M&57kas?q02Piv9lR`7ZMaUAgp`@~^Ss9n&jI@(AR?Z^)mpKJyn
zmAS`ClpOIB+Du%?0+KJGb{`Cs5NY>fRM1bAXFLCO%mKE?IB5{Kg(Yhz!Rn1U5&uqXgTdVX2}>eg
z7DB3$_n&T-xK7m}jBJDhAN6}oK`@u%k
zy|zfRdNx=V5^AXYT|fU$uiRyw2RPkJq^Yeg+1^lRFZL|GW=hARp@t`AKhb46rd0%x
zd-^$HCZMgxX$a?~ozvau=2gU#ev{n5QbfqsD1N}DKELQ$x6UMj)eoI}YtDOI>(etiic)uJ(4HK-ByvT}M+-R!i6
z|Jh)qw@%rfG17b)$Jlneadyw1SZHnz0~wLmBT-tiy)<$&su13T$emJDSn;MbHa-Ba#>pvx$Ua&hO1V4k2-(#1G;l^Do)EmPD=i3f?P9uLJJ514=&39p6>ZP3
z0?JuX8uRfvVWf|LXD_p4tdj(jqY&`qmWB%nYeIyRf=zY5`$g|`$bB|-HT!puFJ;+s
z+F*DS9+34quoBV0+4NB*-e5fXMxvQ}MRsem5^vE(pWqlV2g<52GGYo!7iAcw;7VnD
z;7mREtthc6W_xfX;~8eXiLBGe#U@O4`B7wWDEHUa!8r2K$W%LU>|5jDqW)+`#vcm~
z@;I$%RHEb91F5cK0JbYc6@OGs#09D#mg`fkdKOE8>5^8zz5Tq-(vEUpmsF9#jJC9{
zi##D!qrtPWx$XQww#saUSf~0~OHv{L9VY#S-nc5vC&X=Ld~6=4q*iTp2vxp*he_|$
zmjGD}=cjA~6SCmKId31HwN8$~ncM|D)B>rs@HWwo;LiJ*d%-!Zb93$2&^Usi?9ih4
zY@G3l?q?^_{Ni8yratZ1K()sdX=af*j84_V9V$Axu=euj16llN2-sp`pUttRd&{ba
z*aMzc1`>mclmXln;U9UJcjy74;SGoJY)&MyUZ{8SoYyu#fH?;&(+=r-iImS}Wmh_E
zd~hVKj)UgvZ;#wjYzg%-Fy*?fgSgk5Puxsc4JgHH-ytOmbjA-Q!uvO
zN~eoTqaCI1J%e5I2$dQJ
zqY0|8o7WgFoJ;owO&-Y#?e{fp;B}ceoq~DS*MP`h5JZ%ep@@Z0w}v*~@}{tDeih1C
zIvKnyy=1Iq{pn2SJvd$B{j;PZ_db};YqrnP`7~~)+xhf)l`_+7J>9_lQR{i%)|rb5
zyT)LH*|~M^YA`NLZ#fq9OiSw<^#R;KS}h`y?G#p#R!+n8sn5vju2lVE&+}@Lf5w4Q46HaY=
zj5!U5x^dQZ4{XxJ-i1=1e(H{hjlgd&vQ(hle5jdtTNkrPuT#-kC)r7=e3;6jbY*LUY$g+`DeC1k@wycL_1vn8$8`9osDozR!cG
z#$weV8XV`iX}mc>Y3<*3H`Q{ZgKzqP$;Xv^)rs(UnJMqJ-)diMI1LMj?-aJ>fz;Iq
zd}B(d&8$Wlv1=vF?v(1Ba=E6a#rJGLOO0C?v1scU9PW$U=IVOkYZcx?U%Ry4BX&-h
zfv_wgW94h9|4r4o7Tb+y0+!q0h!q->6(&?u8>Y3pbN?h~;2ei=MQg=TptcdAihCun
z+rC>bLYa^l<8GZQ50z1T|9Lfcs)a7|yU~kHO-+`f3Y`WNT>H$=o!Pc$kmnCt>c*{}
z)?ee1zqzGCV_;Dw_+v6_U>YBIdD!*Dv3Ui2g<*;&9FF*#wQrc{0wDSNUj=;RElF++
zX}4;NXRhSIuvl~~MXqlzc5=|{ShMyk3e2MAxpLmtu3saK8-@m3c%J{jEo=@^L+^5t%Zqz!M>`2v?
z2;ld0AxN4d8;@^`#qeFhs3PFMragMZVxaYrnrUrnJw#WY^bV`K6JiBE1+W8=pF+K4
z`eU2lh)kuutx-2#=Ub`TgG(L6k_i+9FZ|jz0)LK^KyxG02A
z!ntcuj{Euqt4_e{K=5cWa^I72hJyWJQMA9XuI6*hcd&fLGy0NImeX&-@zz6J1r-U4
zmz_i3L|q(1YQ2URBBK$Fgy9WJlE&PFsHTcKChvoH{C;OAuzpu%GBVHEW=0h%9Z7wn
zLsIfMCEP5WLVkGJvis+!mY6J!2ePB0(O;kcit5w>5A?!+O{n@qE3UZFI`|B1H8k
zv=oP>7hgA`)wYQ+La`8mh8&^)6h_74Ky+b(qyDXgV{!1c_erSQb?r^Rh3T|l>{p&O
zi{yZd*Ux;TRI#Rhq_(yj-@4S6wNRb98unpVBN@3WX;q=GOm_)53iwLTM-DQt2#uVu
zuzCz)a?OeJb+B%6^hIk;P1jd?VgBz*W_eXAgo^LGG1p75TRjPilETbY^gdMO7#1CXn&1bJw|V;ctv*C9
z>xy6zcv~Vvx^cxDobE7(m$Y>9HM!)yN>#pM^vf>#uAJq|~y{&IYIaHoDW5WA-x9
zHcfsHcih|&1PFcP`6ABj&%)!e3KGpO;PvpoL)2NKy*aNAmE^^IQ;_i$h6~Y4eNT*Y
z@g9}PMb2+tC7Wv2P6~Sb5XbS1S(cX`s+@@c-ePRGIlg*mc&yv*)b0w$|DhdIdL`
zc4Nw1p`R+)IvDafHCjiX`rH*->Q|S)@A)+JO$)yy)b-880i3vxVlh$-Q*EX(qG|ho
zI$($m@{C>eh$z*#IeeJon)*|CTq|81w~+e$Gcn=`sP$XkLIr_xon@Hn#smZk2gNHP
zNhD9o)i;wL?lBW4eU4;W65#iO7($ecIJ*MQVFiJ&hDGyXZ(2K~I*+
z=`^F$YU*Qbd
zSK<6cFEY0YihDv1LpxvyvWK)K+Kx18?R=fim2Jcv^_7y#F+WT@uV_$)5FCPIi
zT|~8Z8zXF3uLiA=C-lsSN8Q#S-l%IU@sjghev4DE=cU+X6{s7`TmOuDr?Ra}%O`Pn
ze8zb?;b7GLnNw2j#O(oL1Lqn!mpZcDMYW;45#`$T8(v8UF*Tw9=XXu;gn2|9`9`E*
zWcXo5OlBp1BiG7R62{>3J#MLvbcaTHodtDYhneVPDS;P_lgnsf)AA5ntbpzmQqt%7
z`^`$WaCrbyEdCo9!D|OtR1U4!S{KA3j|g>+3ckzfHfzS^b{{c7894{3Y`*>6$URfm
zGH)<+kf)BwkjzSWZ-I4}piuGpGm@fX5@fbu+PJ4NOQ(?5`$S
zkMU*_LVy`OhSP7Y-bNb0@B35()i%!9%D8Qg(TV$>Vp&Gb6Bf5J9(?aVvE5L1DP-D%
zB`JJHuC#lBvrQx>Bj=_12YDY?*f}HNiMT6QiN`!4Ip5~906E&_ZrvGn{qzikh+b!y
z{m4UmS{NF`U-NQXZo7?YjP4NWU<>y-@5dk{)FmCGD2udrpK}AX2?kNKS}kfcM$t3=
zgSXW_*(nc!aspW2yLZ0Gq6BE)S&_0%qkdc|ego7!l&2dVc@9{O#^>#gN00%JU6<1a
z|6PmCd}+AGCWJknlC8`%WW75{N9fPfF%(kNyS;ke&tr0a3zgMOom}@JlFSXP#tjFI
zNV}%V;~?RdGKe6F?qlot!;pql&S!t^n`3A0?e<|QMVi>PshgHzy*#&wcCwOWdDyi4
zf_Rz7(hE;d2Yw>s1R4zw9I3&s$tdycKxIEix%EzBm$7AkwYER5%krh+OoVux7zESK{Ep%$**OL^
zt3qGsTA$QDrQ^_~Wk(6E^cc?(PMb?dR_FE62c&FuknPq?WEe*&DQM&fft*X7kto==
zY|K>a+^OvMmz{9&l57OiTJliy4oI@ZCATHbP@(W-nAz{U2IPW{BkgNN;VaYZe)c
z7gyS$bj&>FN_1m=?pS(PX`3&Z-N!P0kN``;bubOYQ#z9xV`-+5z~7+CJa?~&*47hU
zGwhdxFTH7tJ9NIin_m^)--wdE1fcVD7wnMk9LiPQWplbo%P|;Ot}5(Ne5$qSQ19FF
z=1@8EdAwjtTqO@$3jk)q5WIj|^805bK>L0pwH?`>o$5qa$|SqCMs
zmCFH%GNN;Wx3BRn_DQdB*?$m}Jb~3D-Lq)K0}IJPpk^`-Bp6X
zZb5ct3zK*2yXS3}BR9~}%OE5?s*d1qcMejF5jAC#YA1hDWwuT4F}|zRJyx_<)DzU@
z4!pIZ+oP{qQ9dlhR?7@@kB(h`h{bDn;|a7C)56v9vOaS-X95vJ2;p`SO2`fTz=k;FfF}76=CK{b$pUJ`~6M@wFS9kxFsh3KWLBLz}w|Pc^6*
zHRA9tzicc+Qesw^JU4xy(UWBh`(DCdacfsQJ9&;AQ96pg6#Ej(X*jHY7{`8RG!
z40M+hxE;Q(vb(#`xG~(`U5CRb!y7-5_$ZvbwVewRCSw$k#X4d$|3LHRmrIRv$w^ZoHg86mDv6Zck<9B;ZkD0AJ_SQDIPs4)!=r
z>es(3&ip1fETLLnJvO$Ej2>Vi?($rLJMd)G)~JUH!9IKJDb{vAC!Bl4-6(dTQ(O
z&d*{%WeO`4mbY6wLV+rwemnv$;Et^14
zVpi+906cTPLn$7>Q+f+6eP>*_91?DwG@+P#2U>a4lML;;_e7o<-x7O$9Wp>Y>WNHP
zmnqoLGc+qCqT=TLi^UwSyu~?;Lu3#O2U^tu+bl8C>^wj1A76$%YkQ7LHMYVZP*dXf
zl=A>(cpEaP8+|#@-E(eFo4Kp=ZpYa&WKFP4jvs`x!d6O*qL+Nh0*7$XcOo%MEL-J7WNR3pMtMFBmDIO$aNeld3`P5l)
zsi*S7M)Bdd-NvqW($?bq548#|p^Ke!DceYG%&mb!%e{<6jMk#DTaJ1k_GyQsbBoq0
zg;yxloz=5QT3|HHG6b38K~^vHF@>^)kH$?XS!zTe335r@(l*1ctT|GK)eMjXIRpFV0VH
z+{4Q**OD!aaXOV|1t60zaynNuOPfY`1T%dP_V2$Js~z%-FzvXju~XO57B5Kk&39ns
z_YV$+JobDz7-$%RR+>hi2JgM+W*==~2ofC!9rg`$&1@---LZKqu8&s5j*nj7Rc~DQ
z9J4F3ep>1kAKGi*@?|%2;7`z7OJ<*$ue7uLUDE+$#i}l(>tK1S_Ni0ll~ZOy>j5s5
z^HgNc7R|ot)E6aRs@f*dJ7ww_1f<@d{@PT&87ziJ@8U@MGJLewUz+V+;rqfa7lv;G
zSx{M?(3K}X0Y$Iq9w(dsbRP{|6Mq7SdB4G~#l`0ZIn}
zBTBCsHxV`NnZKr@4R8Iq9ig3KeoJAdSLPBDygUFeE(Ys8F}(MK4b>R)H+<>Vn>EHo
zJ2PH#C~=9D>C^q0qBd%ok0d3#`cGA@XDh`F2<9HDsJiDc_+{8Km~KNOQi@X5!}-)3
zV1jstw7kE=4mLZJD(e{k+zunSLh=u`bTin;E0DL{K`piFtigOQ$dFG`6G|mS^J@7r
z1h!<+rev*cz4kpHV)-$(V!Ww
zbM*l`UKbu>+mZJ%1??asv7G4qFycpG+AF8xR!p&aXpcyp2gG5_TlW(EmTf`E2z)um
z48FJSWfO+^f4aEps3@3sjerU&pe&)Z@X?5rbk~BExFES7AqXNM0@5J@0!v9Q-Hm{B
zgXGfPDels-MXt+o(Ri^Mr^s2xAM&&Trbz(4X!3
zS`hoo>9}2P`4cnIl+?sf8C9w*Vr+Tl1q}gCN0k>;R;sa-QBE!4PJ36DD-N@q;opr{
z)fyk0`78Idrbwgc5^H@9CA_8H+-n!oEq~-k9XZm=OMe7hA2n3Xkjmv@3WY>_n$q$7
zTJETy7CwGF`$V&fT+jN{2?`r_hF3jhpVpHL!tX(aEU-$9W60=Gt?Os6^vbs#kC_AX
z8=va7#o_nWe}`&xDp#fz%s!1yJiesvyAphwpZ(pr(9tewz24?A3+pP_1hr@)JJi6i
z0aHiwUm#p7VuRVoY%uwLk(mN+EIhL`8
z0C+2}pY~90Of5ch?_6*iT|8!2;vvIz_C&KKXy9!DU=DjSt$WP~ko!L@0o!3*2osd`
z-^IL_8#HdPtX7%yZozu#t6)6iR2`wrJ3&yC#g5lAY}7c^7dNCelh3mU4;?(^+#jrx
z)sn`f?s?@#!A6{tB%g`B(|Lpw>7hssBOoMG%RB)-lmXLLG
z5Bwh~MgFT=;c?iq1|`-B@jc$JGiK7Slk0$8ZKuG(qKI3%#=KNM^z&9F_ZA#7Z8}*9
zM9);{5h$0oVfDfFv&j4|+zP}w?25@&AvZcaC69mOT=h`N4@C%*JV)EvdpiKlR|@Yg
zVNa8kOd1wuh^ekTT5Y}e`5c-k;+~ZW0^vDreWX@JK)mK&tsV%bj|9`J&KuBuj*GY(M-zzPEQE93o9l$
zfP8xQ@Wn!H$Uivzbq=Q-USUvvAxf^)pXA
zV4hWVO-Ka%Ek3gI{`M@g>6=^p;YC>ldX+|=Yja}eymB6T{=|OV=OYKM-xIv!L`FfO
zGr3b?3P;6U>?r6yiwO_VzUtKXyI22o`fvt`p9qnSWDxnY2XXtC>Vwi8=%tJVr8m(c
znV4`3BEF&3@HCQodo?#)gOj~3Yh!7|r@UAhu4Sm|>i^NkG;Yc-MAv4`E_0yZ*#y4W
zh2QDC9Gk3uux1)fDJK{+qI51hV9=gEp_RhmN!rklqX1nxbgKpQ+CY35ua$!%eG!fo
zgw`j2v2EOmyf&|8fshU|RSBgj0mAZmY1P@kxiGUi7vm4*;x~xf6pQJ1^-wy!ZK
z2mWMoiw>CBkDM=@zgf`MY@pC#nKWF^*1zj;CKGx>_Tsn|1}g_;6VxHW9-
zoL=tR!B-#m)tu=81hN`YV^_CX10yWFXCFIadd9pEm3=Rx6NBObleP=@21{0Q|I$cI)!ixc46$sZJA>ODf)~nw27Ems&MmN6Y*Q
z8}&q+;?dQ*the)pcg8|)zq0PP+`=gZxOhoVeh5Fhc=p#D?HnX1pKbdYqTrr>5)rYy
zQguCsur)%XbjLF60YpK%v^G&-kGbf(hqH5reIaIzMxI>{bT~}I+?5b&
zPd!LPS0`CrvS9K}Gj@Q6y%hBKly>3pNwwOBc=wRlOwI&nrP5%c^erGl2D9-p>cCT&
zI_mHrP+gy?5h(h}(`0LhU9SC#!B4xcC%!o}vG?8_Q3$+Y)LcAvJCF>dzW5$x8nb)S
z_oS&Q!;K|r6?6nL0J)>Ya+f5kk569lu=sd?-ejrh(64u8P#5qQfp|PcgWN}s{aT}Gn5V2bs3iC;0Oc1~F_M3|nLYsT|Vy9;354vko&+_VOyv>DN
z8aQnIGlv+KHS65!^Ln4=y~j52)rd9Wv=Zk3n?hvEfz~Y(R?_}4w%|Zm?*4h
zF#Lv{KIRpdYa|0O_cO78wST-xlKa%Lv`fveTSA$hOdtl(+Z9dJainwVB6V*x#T(lj#rM%RCN#Lna!IaC25=Fr?Nx2NOOmoKBoM&<{2h{A
zkk!)?3!cJCzu%R{2#+v%CXE)khp&hV^zRo_cI_Dd{`oq81lBu^XmW(hn;_p{Cx?03gLyx@Nabq;t|ck2G}m_6?ojQI{=bnq6N`ZCzueLK
z#lEF{H&BX2ZakvZ_Wt_bTkU^O2VBjM2Qn6Ht&hj7+8t~BQxok>`VC-rFIA0Ho~>qn
zzy`l{UvZ9mEIj_R=JFM(gLUl96>*
z*oloSg;3P7q5_K|9g>nSs0bJP{o>-HY24~Ek^iu})*4DL53rga`lCS9h!aeLrTc7$%Yw8IP!)HRfVDDf>%vT14
zah>c^_!+;2ib-g#ZJc&`M6u8)QV!+gcZH`s=L#?80PbikKlU@fINn2Fs&^yU>#Z8^snAvGAm%sU
zoKcO4@8!QQ7AP`1Jq2~&L&E^Ea>+~5CX<0a_htSyi)}oU=v0PcD~_51Ai%1l;2N5}
z%;}*wl2tjPf~`BPl5iPs$&C;Iio&{xa|6Gaz24LCag%qj#@Y($Qf(tXoaV5W=YMr(
zxVvN!^*tYxMI&(JW75HR%f
z!dG58_Z4Q!{Iv1m?N_Rv#6cAZS$>kf{LmjQp6l!xz8*3euAepZF7e!~)@RAC4*P2!
zXHp7Q@%xYEs=`l4k8?NP=dJT-MbZ_g>o(2j=!>y5M$SmYh{Ycq{IlrI&-_w-O0~a2
zI2hGF9aD%FgN*KPiUs1RPc5X`7PG3jFbOi)YV!mY=5og?@zB`PQ(H)krn%0Dk_JRQOqzBh$Z^~#JvUs5?gsH6m;e=MJg
zj)gWg^b(F}&Dgt!iGqlNs_qe+fDTUiQbRYOjT~%x%1TzZ-%04Qnf*=nKZ~VOG)V}u
zHe!DuOLA?g{{|^>v$zF?1E(U}HGYYx@j5Agw7{sF!wQ
z4wr6mIbisG7j|62703?(w~YEouD)^d+)W*nB{BWqiTY339I042YUD;=`l;ntsN2#Gj7lw8Z;
z4`C`)M8l-xP*|opM*2?oDVdEM$IepnzpK{-2_hhxWgwSSv3FFMhGgC>NojG5AdHoJnLW_}GCo{oOi~*>$
z2qNgZ;jm7)RjNWDtf%XYhnNY#LWvTNjqMfl@&U5FgMg6&w}k({KmNCGb{vqo6h5RH
zc13&2;tlbF!-)~xu$VC0f3F+8y`E3zqU|O5qu3i2CwW`%JsDo%DtxEV{{{5xpAT9z
M)pS)Wl`TL24{iKN9{>OV
diff --git a/dlp/src/test/resources/test.txt b/dlp/src/test/resources/test.txt
index c2ee3815bc9..f30af240c72 100644
--- a/dlp/src/test/resources/test.txt
+++ b/dlp/src/test/resources/test.txt
@@ -1 +1 @@
-My phone number is (223) 456-7890 and my email address is gary@somedomain.com.
\ No newline at end of file
+My phone number is (223) 456-7890 and my email address is gary@example.com.
\ No newline at end of file
From a045ec4d4733d3045400ecbfb8b04264c0dae001 Mon Sep 17 00:00:00 2001
From: Kurtis Van Gent
Date: Fri, 15 Feb 2019 13:01:49 -0800
Subject: [PATCH 09/14] Updated Redact sample to new format.
---
.../java/dlp/snippets/RedactImageFile.java | 86 ++++++++++++++++++
.../test/java/dlp/snippets/RedactTests.java | 91 +++++++++++++++++++
2 files changed, 177 insertions(+)
create mode 100644 dlp/src/main/java/dlp/snippets/RedactImageFile.java
create mode 100644 dlp/src/test/java/dlp/snippets/RedactTests.java
diff --git a/dlp/src/main/java/dlp/snippets/RedactImageFile.java b/dlp/src/main/java/dlp/snippets/RedactImageFile.java
new file mode 100644
index 00000000000..f0d18f929a3
--- /dev/null
+++ b/dlp/src/main/java/dlp/snippets/RedactImageFile.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dlp.snippets;
+
+import com.google.cloud.dlp.v2.DlpServiceClient;
+import com.google.privacy.dlp.v2.ByteContentItem;
+import com.google.privacy.dlp.v2.ByteContentItem.BytesType;
+import com.google.privacy.dlp.v2.InfoType;
+import com.google.privacy.dlp.v2.InspectConfig;
+import com.google.privacy.dlp.v2.Likelihood;
+import com.google.privacy.dlp.v2.ProjectName;
+import com.google.privacy.dlp.v2.RedactImageRequest;
+import com.google.privacy.dlp.v2.RedactImageResponse;
+import com.google.protobuf.ByteString;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+class RedactImageFile {
+
+ static void redactImageFile(String projectId, String filePath) {
+ // String projectId = "my-project-id";
+ // String filePath = "path/to/image.png";
+
+ // Initialize client that will be used to send requests. This client only needs to be created
+ // once, and can be reused for multiple requests. After completing all of your requests, call
+ // the "close" method on the client to safely clean up any remaining background resources.
+ try (DlpServiceClient dlp = DlpServiceClient.create()) {
+ // Specify the project used for request.
+ ProjectName project = ProjectName.of(projectId);
+
+ // Specify the content to be inspected.
+ ByteString fileBytes = ByteString.readFrom(new FileInputStream(filePath));
+ ByteContentItem byteItem =
+ ByteContentItem.newBuilder().setType(BytesType.IMAGE).setData(fileBytes).build();
+
+ // Specify the type of info and likelihood necessary to redact.
+ List infoTypes = new ArrayList<>();
+ // See https://cloud.google.com/dlp/docs/infotypes-reference for complete list of info types
+ for (String typeName : new String[] {"PHONE_NUMBER", "EMAIL_ADDRESS", "CREDIT_CARD_NUMBER"}) {
+ infoTypes.add(InfoType.newBuilder().setName(typeName).build());
+ }
+ InspectConfig config =
+ InspectConfig.newBuilder()
+ .addAllInfoTypes(infoTypes)
+ .setMinLikelihood(Likelihood.LIKELY)
+ .build();
+
+ // Construct the Redact request to be sent by the client.
+ RedactImageRequest request =
+ RedactImageRequest.newBuilder()
+ .setParent(project.toString())
+ .setByteItem(byteItem)
+ .setInspectConfig(config)
+ .build();
+
+ // Use the client to send the API request.
+ RedactImageResponse response = dlp.redactImage(request);
+
+ // Parse the response and process results.
+ String outputPath = "redacted.png";
+ FileOutputStream redacted = new FileOutputStream(outputPath);
+ redacted.write(response.getRedactedImage().toByteArray());
+ redacted.close();
+ System.out.println("Redacted image written to " + outputPath);
+
+ } catch (Exception e) {
+ System.out.println("Error during inspectFile: \n" + e.toString());
+ }
+ }
+}
diff --git a/dlp/src/test/java/dlp/snippets/RedactTests.java b/dlp/src/test/java/dlp/snippets/RedactTests.java
new file mode 100644
index 00000000000..3d0299019fc
--- /dev/null
+++ b/dlp/src/test/java/dlp/snippets/RedactTests.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dlp.snippets;
+
+import static junit.framework.TestCase.assertNotNull;
+import static org.junit.Assert.assertThat;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import org.hamcrest.CoreMatchers;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class RedactTests {
+
+ private ByteArrayOutputStream bout;
+
+ private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT");
+
+ private static void requireEnvVar(String varName) {
+ assertNotNull(
+ System.getenv(varName),
+ "Environment variable '%s' is required to perform these tests.".format(varName)
+ );
+ }
+
+ @BeforeClass
+ public static void checkRequirements() {
+ requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS");
+ requireEnvVar("GOOGLE_CLOUD_PROJECT");
+ }
+
+ @Before
+ public void beforeTest() {
+ bout = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(bout));
+ }
+
+ @After
+ public void tearDown() {
+ System.setOut(null);
+ bout.reset();
+ }
+
+ @Test
+ public void testInspectString() {
+ InspectString.inspectString(PROJECT_ID, "I'm Gary and my email is gary@example.com");
+
+ String output = bout.toString();
+ assertThat(output, CoreMatchers.containsString("Info type: EMAIL_ADDRESS"));
+ }
+
+ @Test
+ public void textInspectTestFile() {
+ InspectTextFile.inspectTextFile(PROJECT_ID, "src/test/resources/test.txt");
+
+ String output = bout.toString();
+ assertThat(output, CoreMatchers.containsString("Info type: PHONE_NUMBER"));
+ assertThat(output, CoreMatchers.containsString("Info type: EMAIL_ADDRESS"));
+ }
+
+
+ @Test
+ public void testInspectImageFile() {
+ InspectImageFile.inspectImageFile(PROJECT_ID, "src/test/resources/test.png");
+
+ String output = bout.toString();
+ assertThat(output, CoreMatchers.containsString("Info type: PHONE_NUMBER"));
+ assertThat(output, CoreMatchers.containsString("Info type: EMAIL_ADDRESS"));
+ }
+
+}
From d7ac740a2204e685b1c9ceae879dd49766b27cde Mon Sep 17 00:00:00 2001
From: Kurtis Van Gent
Date: Fri, 15 Feb 2019 13:06:29 -0800
Subject: [PATCH 10/14] Clean up comments.
---
.../java/dlp/snippets/InspectImageFile.java | 23 +++++++++--------
.../main/java/dlp/snippets/InspectString.java | 18 +++++++------
.../java/dlp/snippets/InspectTextFile.java | 19 +++++++-------
.../test/java/dlp/snippets/RedactTests.java | 25 +++----------------
4 files changed, 35 insertions(+), 50 deletions(-)
diff --git a/dlp/src/main/java/dlp/snippets/InspectImageFile.java b/dlp/src/main/java/dlp/snippets/InspectImageFile.java
index 0b7f8778019..7c8dd6d0bd5 100644
--- a/dlp/src/main/java/dlp/snippets/InspectImageFile.java
+++ b/dlp/src/main/java/dlp/snippets/InspectImageFile.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Google LLC
+ * Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,14 +38,15 @@ public class InspectImageFile {
public static void inspectImageFile(String projectId, String filePath) {
// String projectId = "my-project-id";
// String filePath = "path/to/image.png";
- // String fileType = "IMAGE"
- // Initialize client with try-with-resources for automatic cleanup of background resources
+ // Initialize client that will be used to send requests. This client only needs to be created
+ // once, and can be reused for multiple requests. After completing all of your requests, call
+ // the "close" method on the client to safely clean up any remaining background resources.
try (DlpServiceClient dlp = DlpServiceClient.create()) {
- // Set project for request
+ // Specify the project used for request.
ProjectName project = ProjectName.of(projectId);
- // Set content for request
+ // Specify the type and content to be inspected.
ByteString fileBytes = ByteString.readFrom(new FileInputStream(filePath));
ByteContentItem byteItem = ByteContentItem.newBuilder()
.setType(BytesType.IMAGE)
@@ -55,30 +56,30 @@ public static void inspectImageFile(String projectId, String filePath) {
.setByteItem(byteItem)
.build();
- // Set required InfoTypes for inspection config
+ // Specify the type of info the inspection will look for.
List infoTypes = new ArrayList<>();
// See https://cloud.google.com/dlp/docs/infotypes-reference for complete list of info types
for (String typeName : new String[] {"PHONE_NUMBER", "EMAIL_ADDRESS", "CREDIT_CARD_NUMBER"}) {
infoTypes.add(InfoType.newBuilder().setName(typeName).build());
}
- // Set the inspect configuration for request
+ // Construct the configuration for the Inspect request.
InspectConfig config = InspectConfig.newBuilder()
.addAllInfoTypes(infoTypes)
.setIncludeQuote(true)
.build();
- // Construct the request to be sent by the client
+ // Construct the Inspect request to be sent by the client.
InspectContentRequest request = InspectContentRequest.newBuilder()
.setParent(project.toString())
.setItem(item)
.setInspectConfig(config)
.build();
- // Use the client to send the API request
+ // Use the client to send the API request.
InspectContentResponse response = dlp.inspectContent(request);
- // Parse the response and process results
+ // Parse the response and process results.
System.out.println("Findings: " + response.getResult().getFindingsCount());
for (Finding f : response.getResult().getFindingsList()) {
System.out.println("\tQuote: " + f.getQuote());
@@ -86,7 +87,7 @@ public static void inspectImageFile(String projectId, String filePath) {
System.out.println("\tLikelihood: " + f.getLikelihood());
}
} catch (Exception e) {
- System.out.println("Error during inspectFile: \n" + e.toString());
+ System.out.println("Error during inspectImageFile: \n" + e.toString());
}
}
}
diff --git a/dlp/src/main/java/dlp/snippets/InspectString.java b/dlp/src/main/java/dlp/snippets/InspectString.java
index 2e8452762b3..a6a178dd529 100644
--- a/dlp/src/main/java/dlp/snippets/InspectString.java
+++ b/dlp/src/main/java/dlp/snippets/InspectString.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Google LLC
+ * Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,39 +38,41 @@ public static void inspectString(String projectId, String textToInspect) {
// String projectId = "my-project-id";
// String textToInspect = "My name is Gary and my email is gary@example.com";
- // Initialize client with try-with-resources for automatic cleanup of background resources
+ // Initialize client that will be used to send requests. This client only needs to be created
+ // once, and can be reused for multiple requests. After completing all of your requests, call
+ // the "close" method on the client to safely clean up any remaining background resources.
try (DlpServiceClient dlp = DlpServiceClient.create()) {
- // Set project for request
+ // Specify the project used for request.
ProjectName project = ProjectName.of(projectId);
- // Set content for request
+ // Specify the type and content to be inspected.
ByteContentItem byteItem = ByteContentItem.newBuilder()
.setType(BytesType.TEXT_UTF8)
.setData(ByteString.copyFromUtf8(textToInspect))
.build();
ContentItem item = ContentItem.newBuilder().setByteItem(byteItem).build();
- // Set required InfoTypes for inspection config
+ // Specify the type of info the inspection will look for.
List infoTypes = new ArrayList<>();
// See https://cloud.google.com/dlp/docs/infotypes-reference for complete list of info types
for (String typeName : new String[] {"PHONE_NUMBER", "EMAIL_ADDRESS", "CREDIT_CARD_NUMBER"}) {
infoTypes.add(InfoType.newBuilder().setName(typeName).build());
}
- // Set the inspect configuration for request
+ // Construct the configuration for the Inspect request.
InspectConfig config = InspectConfig.newBuilder()
.addAllInfoTypes(infoTypes)
.setIncludeQuote(true)
.build();
- // Construct request
+ // Construct the Inspect request to be sent by the client.
InspectContentRequest request = InspectContentRequest.newBuilder()
.setParent(project.toString())
.setItem(item)
.setInspectConfig(config)
.build();
- // Use the client to send the API request
+ // Use the client to send the API request.
InspectContentResponse response = dlp.inspectContent(request);
// Parse the response and process results
diff --git a/dlp/src/main/java/dlp/snippets/InspectTextFile.java b/dlp/src/main/java/dlp/snippets/InspectTextFile.java
index f15d756f2ff..335e2fcbe47 100644
--- a/dlp/src/main/java/dlp/snippets/InspectTextFile.java
+++ b/dlp/src/main/java/dlp/snippets/InspectTextFile.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Google LLC
+ * Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,14 +38,15 @@ public class InspectTextFile {
public static void inspectTextFile(String projectId, String filePath) {
// String projectId = "my-project-id";
// String filePath = "path/to/image.png";
- // String fileType = "IMAGE"
- // Initialize client with try-with-resources for automatic cleanup of background resources
+ // Initialize client that will be used to send requests. This client only needs to be created
+ // once, and can be reused for multiple requests. After completing all of your requests, call
+ // the "close" method on the client to safely clean up any remaining background resources.
try (DlpServiceClient dlp = DlpServiceClient.create()) {
- // Set project for request
+ // Specify the project used for request.
ProjectName project = ProjectName.of(projectId);
- // Set content for request
+ // Specify the type and content to be inspected.
ByteString fileBytes = ByteString.readFrom(new FileInputStream(filePath));
ByteContentItem byteItem = ByteContentItem.newBuilder()
.setType(BytesType.TEXT_UTF8)
@@ -55,27 +56,27 @@ public static void inspectTextFile(String projectId, String filePath) {
.setByteItem(byteItem)
.build();
- // Set required InfoTypes for inspection config
+ // Specify the type of info the inspection will look for.
List infoTypes = new ArrayList<>();
// See https://cloud.google.com/dlp/docs/infotypes-reference for complete list of info types
for (String typeName : new String[] {"PHONE_NUMBER", "EMAIL_ADDRESS", "CREDIT_CARD_NUMBER"}) {
infoTypes.add(InfoType.newBuilder().setName(typeName).build());
}
- // Set the inspect configuration for request
+ // Construct the configuration for the Inspect request.
InspectConfig config = InspectConfig.newBuilder()
.addAllInfoTypes(infoTypes)
.setIncludeQuote(true)
.build();
- // Construct the request to be sent by the client
+ // Construct the Inspect request to be sent by the client.
InspectContentRequest request = InspectContentRequest.newBuilder()
.setParent(project.toString())
.setItem(item)
.setInspectConfig(config)
.build();
- // Use the client to send the API request
+ // Use the client to send the API request.
InspectContentResponse response = dlp.inspectContent(request);
// Parse the response and process results
diff --git a/dlp/src/test/java/dlp/snippets/RedactTests.java b/dlp/src/test/java/dlp/snippets/RedactTests.java
index 3d0299019fc..defbfd3db5e 100644
--- a/dlp/src/test/java/dlp/snippets/RedactTests.java
+++ b/dlp/src/test/java/dlp/snippets/RedactTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Google LLC
+ * Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -62,30 +62,11 @@ public void tearDown() {
}
@Test
- public void testInspectString() {
- InspectString.inspectString(PROJECT_ID, "I'm Gary and my email is gary@example.com");
+ public void testRedactImage() {
+ RedactImageFile.redactImageFile(PROJECT_ID, "src/test/resources/test.png");
String output = bout.toString();
assertThat(output, CoreMatchers.containsString("Info type: EMAIL_ADDRESS"));
}
- @Test
- public void textInspectTestFile() {
- InspectTextFile.inspectTextFile(PROJECT_ID, "src/test/resources/test.txt");
-
- String output = bout.toString();
- assertThat(output, CoreMatchers.containsString("Info type: PHONE_NUMBER"));
- assertThat(output, CoreMatchers.containsString("Info type: EMAIL_ADDRESS"));
- }
-
-
- @Test
- public void testInspectImageFile() {
- InspectImageFile.inspectImageFile(PROJECT_ID, "src/test/resources/test.png");
-
- String output = bout.toString();
- assertThat(output, CoreMatchers.containsString("Info type: PHONE_NUMBER"));
- assertThat(output, CoreMatchers.containsString("Info type: EMAIL_ADDRESS"));
- }
-
}
From e0edee30294201b7dfe276022bc553d5e0ce12f7 Mon Sep 17 00:00:00 2001
From: Kurtis Van Gent
Date: Fri, 15 Feb 2019 13:09:05 -0800
Subject: [PATCH 11/14] Bump license year.
---
dlp/src/test/java/dlp/snippets/InspectTests.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlp/src/test/java/dlp/snippets/InspectTests.java b/dlp/src/test/java/dlp/snippets/InspectTests.java
index e91eb66dc75..6c64a19b9c5 100644
--- a/dlp/src/test/java/dlp/snippets/InspectTests.java
+++ b/dlp/src/test/java/dlp/snippets/InspectTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Google LLC
+ * Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
From 6f1b07672ce99a4b1f96ded0e774666961c2c55a Mon Sep 17 00:00:00 2001
From: Kurtis Van Gent
Date: Fri, 15 Feb 2019 13:11:35 -0800
Subject: [PATCH 12/14] Fixed redact test.
---
dlp/src/test/java/dlp/snippets/RedactTests.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlp/src/test/java/dlp/snippets/RedactTests.java b/dlp/src/test/java/dlp/snippets/RedactTests.java
index defbfd3db5e..c55f78d7b41 100644
--- a/dlp/src/test/java/dlp/snippets/RedactTests.java
+++ b/dlp/src/test/java/dlp/snippets/RedactTests.java
@@ -66,7 +66,7 @@ public void testRedactImage() {
RedactImageFile.redactImageFile(PROJECT_ID, "src/test/resources/test.png");
String output = bout.toString();
- assertThat(output, CoreMatchers.containsString("Info type: EMAIL_ADDRESS"));
+ assertThat(output, CoreMatchers.containsString("Redacted image written"));
}
}
From e74f484405550feb04a2ab8b08dda664ce3034db Mon Sep 17 00:00:00 2001
From: Kurtis Van Gent
Date: Fri, 15 Feb 2019 13:29:05 -0800
Subject: [PATCH 13/14] Remove old redact snippet and move region tags.
---
dlp/src/main/java/com/example/dlp/Redact.java | 189 ------------------
.../main/java/com/example/dlp/Templates.java | 2 +-
.../java/dlp/snippets/RedactImageFile.java | 2 +
.../test/java/com/example/dlp/RedactIT.java | 75 -------
.../test/java/dlp/snippets/RedactTests.java | 1 +
5 files changed, 4 insertions(+), 265 deletions(-)
delete mode 100644 dlp/src/main/java/com/example/dlp/Redact.java
delete mode 100644 dlp/src/test/java/com/example/dlp/RedactIT.java
diff --git a/dlp/src/main/java/com/example/dlp/Redact.java b/dlp/src/main/java/com/example/dlp/Redact.java
deleted file mode 100644
index 1ffd49fc90c..00000000000
--- a/dlp/src/main/java/com/example/dlp/Redact.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.dlp;
-
-import com.google.cloud.ServiceOptions;
-import com.google.cloud.dlp.v2.DlpServiceClient;
-import com.google.privacy.dlp.v2.ByteContentItem;
-import com.google.privacy.dlp.v2.InfoType;
-import com.google.privacy.dlp.v2.InspectConfig;
-import com.google.privacy.dlp.v2.Likelihood;
-import com.google.privacy.dlp.v2.ProjectName;
-import com.google.privacy.dlp.v2.RedactImageRequest;
-import com.google.privacy.dlp.v2.RedactImageResponse;
-import com.google.protobuf.ByteString;
-import java.io.FileOutputStream;
-import java.net.URLConnection;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-import javax.activation.MimetypesFileTypeMap;
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.CommandLineParser;
-import org.apache.commons.cli.DefaultParser;
-import org.apache.commons.cli.HelpFormatter;
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
-
-public class Redact {
-
- // [START dlp_redact_image]
- /*
- * Redact sensitive data from an image using the Data Loss Prevention API.
- *
- * @param filePath The path to a local file to inspect. Can be a JPG or PNG image file.
- * @param minLikelihood The minimum likelihood required before redacting a match.
- * @param infoTypes The infoTypes of information to redact.
- * @param outputPath The local path to save the resulting image to.
- * @param projectId The project ID to run the API call under.
- */
- private static void redactImage(
- String filePath,
- Likelihood minLikelihood,
- List infoTypes,
- String outputPath,
- String projectId)
- throws Exception {
-
- // Instantiate the DLP client
- try (DlpServiceClient dlpClient = DlpServiceClient.create()) {
- String mimeType = URLConnection.guessContentTypeFromName(filePath);
- if (mimeType == null) {
- mimeType = MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(filePath);
- }
-
- ByteContentItem.BytesType bytesType;
- switch (mimeType) {
- case "image/jpeg":
- bytesType = ByteContentItem.BytesType.IMAGE_JPEG;
- break;
- case "image/bmp":
- bytesType = ByteContentItem.BytesType.IMAGE_BMP;
- break;
- case "image/png":
- bytesType = ByteContentItem.BytesType.IMAGE_PNG;
- break;
- case "image/svg":
- bytesType = ByteContentItem.BytesType.IMAGE_SVG;
- break;
- default:
- bytesType = ByteContentItem.BytesType.BYTES_TYPE_UNSPECIFIED;
- break;
- }
-
- byte[] data = Files.readAllBytes(Paths.get(filePath));
-
- InspectConfig inspectConfig =
- InspectConfig.newBuilder()
- .addAllInfoTypes(infoTypes)
- .setMinLikelihood(minLikelihood)
- .build();
-
- ByteContentItem byteContentItem =
- ByteContentItem.newBuilder()
- .setType(bytesType)
- .setData(ByteString.copyFrom(data))
- .build();
-
- List imageRedactionConfigs =
- infoTypes
- .stream()
- .map(
- infoType ->
- RedactImageRequest.ImageRedactionConfig.newBuilder()
- .setInfoType(infoType)
- .build())
- .collect(Collectors.toList());
-
- RedactImageRequest redactImageRequest =
- RedactImageRequest.newBuilder()
- .setParent(ProjectName.of(projectId).toString())
- .addAllImageRedactionConfigs(imageRedactionConfigs)
- .setByteItem(byteContentItem)
- .setInspectConfig(inspectConfig)
- .build();
-
- RedactImageResponse redactImageResponse = dlpClient.redactImage(redactImageRequest);
-
- // redacted image data
- ByteString redactedImageData = redactImageResponse.getRedactedImage();
- FileOutputStream outputStream = new FileOutputStream(outputPath);
- outputStream.write(redactedImageData.toByteArray());
- outputStream.close();
- }
- }
- // [END dlp_redact_image]
-
- /** Command line application to redact strings, images using the Data Loss Prevention API. */
- public static void main(String[] args) throws Exception {
-
- Options commandLineOptions = new Options();
-
- Option minLikelihoodOption =
- Option.builder("minLikelihood").hasArg(true).required(false).build();
-
- commandLineOptions.addOption(minLikelihoodOption);
-
- Option infoTypesOption = Option.builder("infoTypes").hasArg(true).required(false).build();
- infoTypesOption.setArgs(Option.UNLIMITED_VALUES);
- commandLineOptions.addOption(infoTypesOption);
-
- Option inputFilePathOption =
- Option.builder("f").hasArg(true).longOpt("inputFilePath").required(false).build();
- commandLineOptions.addOption(inputFilePathOption);
-
- Option outputFilePathOption =
- Option.builder("o").hasArg(true).longOpt("outputFilePath").required(false).build();
-
- commandLineOptions.addOption(outputFilePathOption);
-
- Option projectIdOption = Option.builder("projectId").hasArg(true).required(false).build();
- CommandLineParser parser = new DefaultParser();
- HelpFormatter formatter = new HelpFormatter();
- CommandLine cmd;
-
- try {
- cmd = parser.parse(commandLineOptions, args);
- } catch (ParseException e) {
- System.out.println(e.getMessage());
- formatter.printHelp(Redact.class.getName(), commandLineOptions);
- System.exit(1);
- return;
- }
-
- List infoTypesList = new ArrayList<>();
- String[] infoTypes = cmd.getOptionValues(infoTypesOption.getOpt());
- if (infoTypes != null) {
- for (String infoType : infoTypes) {
- infoTypesList.add(InfoType.newBuilder().setName(infoType).build());
- }
- }
- Likelihood minLikelihood =
- Likelihood.valueOf(
- cmd.getOptionValue(
- minLikelihoodOption.getOpt(), Likelihood.LIKELIHOOD_UNSPECIFIED.name()));
-
- String inputFilePath = cmd.getOptionValue(inputFilePathOption.getOpt());
- String outputFilePath = cmd.getOptionValue(outputFilePathOption.getOpt());
- String projectId =
- cmd.getOptionValue(projectIdOption.getOpt(), ServiceOptions.getDefaultProjectId());
- redactImage(inputFilePath, minLikelihood, infoTypesList, outputFilePath, projectId);
- }
-}
diff --git a/dlp/src/main/java/com/example/dlp/Templates.java b/dlp/src/main/java/com/example/dlp/Templates.java
index da4c5eb88c6..72e2cb6cf6d 100644
--- a/dlp/src/main/java/com/example/dlp/Templates.java
+++ b/dlp/src/main/java/com/example/dlp/Templates.java
@@ -218,7 +218,7 @@ public static void main(String[] args) throws Exception {
cmd = parser.parse(commandLineOptions, args);
} catch (ParseException e) {
System.out.println(e.getMessage());
- formatter.printHelp(Redact.class.getName(), commandLineOptions);
+ formatter.printHelp("dlp_snippets", commandLineOptions);
System.exit(1);
return;
}
diff --git a/dlp/src/main/java/dlp/snippets/RedactImageFile.java b/dlp/src/main/java/dlp/snippets/RedactImageFile.java
index f0d18f929a3..bbf4bc53184 100644
--- a/dlp/src/main/java/dlp/snippets/RedactImageFile.java
+++ b/dlp/src/main/java/dlp/snippets/RedactImageFile.java
@@ -16,6 +16,7 @@
package dlp.snippets;
+// [START dlp_redact_image]
import com.google.cloud.dlp.v2.DlpServiceClient;
import com.google.privacy.dlp.v2.ByteContentItem;
import com.google.privacy.dlp.v2.ByteContentItem.BytesType;
@@ -84,3 +85,4 @@ static void redactImageFile(String projectId, String filePath) {
}
}
}
+// [END dlp_redact_image]
diff --git a/dlp/src/test/java/com/example/dlp/RedactIT.java b/dlp/src/test/java/com/example/dlp/RedactIT.java
deleted file mode 100644
index 5708fae6211..00000000000
--- a/dlp/src/test/java/com/example/dlp/RedactIT.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.dlp;
-
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.not;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-// CHECKSTYLE OFF: AbbreviationAsWordInName
-public class RedactIT {
-
- // CHECKSTYLE ON: AbbreviationAsWordInName
- private ByteArrayOutputStream bout;
- private PrintStream out;
-
- @Before
- public void setUp() {
- bout = new ByteArrayOutputStream();
- out = new PrintStream(bout);
- System.setOut(out);
- assertNotNull(System.getenv("GOOGLE_APPLICATION_CREDENTIALS"));
- }
-
- @Test
- public void testRedactImage() throws Exception {
- // InspectIT Tests verify original has PII present
- String outputFilePath = "src/test/resources/output.png";
-
- // Restrict phone number, but not email
- Redact.main(
- new String[] {
- "-f", "src/test/resources/test.png",
- "-infoTypes", "PHONE_NUMBER",
- "-o", outputFilePath
- });
- bout.reset();
-
- // Verify that phone_number is missing but email is present
- Inspect.main(
- new String[] {"-f", outputFilePath, "-infoTypes", "PHONE_NUMBER", "EMAIL_ADDRESS"});
- String output = bout.toString();
- assertThat(output, not(containsString("PHONE_NUMBER")));
- assertThat(output, containsString("EMAIL_ADDRESS"));
- }
-
- @After
- public void tearDown() {
- System.setOut(null);
- bout.reset();
- }
-}
diff --git a/dlp/src/test/java/dlp/snippets/RedactTests.java b/dlp/src/test/java/dlp/snippets/RedactTests.java
index c55f78d7b41..548ad35effa 100644
--- a/dlp/src/test/java/dlp/snippets/RedactTests.java
+++ b/dlp/src/test/java/dlp/snippets/RedactTests.java
@@ -16,6 +16,7 @@
package dlp.snippets;
+// [START dlp_redact_image]
import static junit.framework.TestCase.assertNotNull;
import static org.junit.Assert.assertThat;
From e2386838b6549ddb668752e0b7529347b491b5c3 Mon Sep 17 00:00:00 2001
From: Kurtis Van Gent
Date: Mon, 25 Feb 2019 13:50:39 -0800
Subject: [PATCH 14/14] Remove region tag.
---
dlp/src/test/java/dlp/snippets/RedactTests.java | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/dlp/src/test/java/dlp/snippets/RedactTests.java b/dlp/src/test/java/dlp/snippets/RedactTests.java
index 548ad35effa..475b9485a8d 100644
--- a/dlp/src/test/java/dlp/snippets/RedactTests.java
+++ b/dlp/src/test/java/dlp/snippets/RedactTests.java
@@ -16,7 +16,6 @@
package dlp.snippets;
-// [START dlp_redact_image]
import static junit.framework.TestCase.assertNotNull;
import static org.junit.Assert.assertThat;
@@ -40,8 +39,7 @@ public class RedactTests {
private static void requireEnvVar(String varName) {
assertNotNull(
System.getenv(varName),
- "Environment variable '%s' is required to perform these tests.".format(varName)
- );
+ "Environment variable '%s' is required to perform these tests.".format(varName));
}
@BeforeClass
@@ -64,10 +62,9 @@ public void tearDown() {
@Test
public void testRedactImage() {
- RedactImageFile.redactImageFile(PROJECT_ID, "src/test/resources/test.png");
+ RedactImageFile.redactImageFile(PROJECT_ID, "src/test/resources/test.png");
String output = bout.toString();
assertThat(output, CoreMatchers.containsString("Redacted image written"));
}
-
}