From a08bc5fd5112cae1a0a18d61e9497346f28ad351 Mon Sep 17 00:00:00 2001 From: "Yangkai.Shen" <237497819@qq.com> Date: Sat, 20 Aug 2022 13:59:37 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E5=85=B6=E4=BB=96=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E4=B9=8B=20https=20=E6=A1=88=E4=BE=8B=E5=AE=8C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo-https/.gitignore | 31 ----- demo-https/README.md | 110 --------------- demo-https/src/main/resources/application.yml | 11 -- demo-https/src/main/resources/server.keystore | Bin 2255 -> 0 bytes demo-https/ssl.png | Bin 78633 -> 0 bytes demo-others/demo-others-https/README.md | 148 +++++++++++++++++++++ .../demo-others-https}/pom.xml | 22 +-- .../java/com/xkcoding/https/HttpsApplication.java | 4 +- .../com/xkcoding/https/config/HttpsConfig.java | 4 +- .../src/main/resources/application.yml | 13 ++ .../src/main/resources/spring-boot-demo.key | Bin 0 -> 2812 bytes .../src/main/resources/static/index.html | 4 +- .../com/xkcoding/https/HttpsApplicationTests.java | 4 +- demo-others/pom.xml | 4 + pom.xml | 1 - 15 files changed, 184 insertions(+), 172 deletions(-) delete mode 100644 demo-https/.gitignore delete mode 100644 demo-https/README.md delete mode 100644 demo-https/src/main/resources/application.yml delete mode 100644 demo-https/src/main/resources/server.keystore delete mode 100644 demo-https/ssl.png create mode 100644 demo-others/demo-others-https/README.md rename {demo-https => demo-others/demo-others-https}/pom.xml (78%) rename demo-https/src/main/java/com/xkcoding/https/SpringBootDemoHttpsApplication.java => demo-others/demo-others-https/src/main/java/com/xkcoding/https/HttpsApplication.java (72%) rename {demo-https => demo-others/demo-others-https}/src/main/java/com/xkcoding/https/config/HttpsConfig.java (95%) create mode 100644 demo-others/demo-others-https/src/main/resources/application.yml create mode 100644 demo-others/demo-others-https/src/main/resources/spring-boot-demo.key rename {demo-https => demo-others/demo-others-https}/src/main/resources/static/index.html (61%) rename demo-https/src/test/java/com/xkcoding/https/SpringBootDemoHttpsApplicationTests.java => demo-others/demo-others-https/src/test/java/com/xkcoding/https/HttpsApplicationTests.java (69%) diff --git a/demo-https/.gitignore b/demo-https/.gitignore deleted file mode 100644 index a2a3040..0000000 --- a/demo-https/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/** -!**/src/test/** - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ - -### VS Code ### -.vscode/ diff --git a/demo-https/README.md b/demo-https/README.md deleted file mode 100644 index 042cb6f..0000000 --- a/demo-https/README.md +++ /dev/null @@ -1,110 +0,0 @@ -# spring-boot-demo-https - -> 此 demo 主要演示了 Spring Boot 如何集成 https - -## 1. 生成证书 - -首先使用 jdk 自带的 keytool 命令生成证书复制到项目的 `resources` 目录下(生成的证书一般在用户目录下 C:\Users\Administrator\server.keystore) - -> 自己生成的证书浏览器会有危险提示,去ssl网站上使用金钱申请则不会 - - - -## 2. 添加配置 - -1. 在配置文件配置生成的证书 - -```yaml -server: - ssl: - # 证书路径 - key-store: classpath:server.keystore - key-alias: tomcat - enabled: true - key-store-type: JKS - #与申请时输入一致 - key-store-password: 123456 - # 浏览器默认端口 和 80 类似 - port: 443 -``` - -2. 配置 Tomcat - -```java -/** - *
- * HTTPS 配置类 - *
- * - * @author yangkai.shen - * @date Created in 2020-01-19 10:31 - */ -@Configuration -public class HttpsConfig { - /** - * 配置 http(80) -> 强制跳转到 https(443) - */ - @Bean - public Connector connector() { - Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); - connector.setScheme("http"); - connector.setPort(80); - connector.setSecure(false); - connector.setRedirectPort(443); - return connector; - } - - @Bean - public TomcatServletWebServerFactory tomcatServletWebServerFactory(Connector connector) { - TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() { - @Override - protected void postProcessContext(Context context) { - SecurityConstraint securityConstraint = new SecurityConstraint(); - securityConstraint.setUserConstraint("CONFIDENTIAL"); - SecurityCollection collection = new SecurityCollection(); - collection.addPattern("/*"); - securityConstraint.addCollection(collection); - context.addConstraint(securityConstraint); - } - }; - tomcat.addAdditionalTomcatConnectors(connector); - return tomcat; - } -} -``` - -## 3. 测试 - -启动项目,浏览器访问 http://localhost 将自动跳转到 https://localhost - -## 4. 参考 - -- `keytool`命令参考 - -```bash -$ keytool --help -密钥和证书管理工具 - -命令: - - -certreq 生成证书请求 - -changealias 更改条目的别名 - -delete 删除条目 - -exportcert 导出证书 - -genkeypair 生成密钥对 - -genseckey 生成密钥 - -gencert 根据证书请求生成证书 - -importcert 导入证书或证书链 - -importpass 导入口令 - -importkeystore 从其他密钥库导入一个或所有条目 - -keypasswd 更改条目的密钥口令 - -list 列出密钥库中的条目 - -printcert 打印证书内容 - -printcertreq 打印证书请求的内容 - -printcrl 打印 CRL 文件的内容 - -storepasswd 更改密钥库的存储口令 - -使用 "keytool -command_name -help" 获取 command_name 的用法 -``` - -- [Java Keytool工具简介](https://blog.csdn.net/liumiaocn/article/details/61921014) diff --git a/demo-https/src/main/resources/application.yml b/demo-https/src/main/resources/application.yml deleted file mode 100644 index 21ad6fc..0000000 --- a/demo-https/src/main/resources/application.yml +++ /dev/null @@ -1,11 +0,0 @@ -server: - ssl: - # 证书路径 - key-store: classpath:server.keystore - key-alias: tomcat - enabled: true - key-store-type: JKS - #与申请时输入一致 - key-store-password: 123456 - # 浏览器默认端口 和 80 类似 - port: 443 diff --git a/demo-https/src/main/resources/server.keystore b/demo-https/src/main/resources/server.keystore deleted file mode 100644 index a6b59ffd9cdb35963cb3374ffdfd1e42fe3c151e..0000000000000000000000000000000000000000 GIT binary patch literal 0 KcmV+b0RR6000031 literal 2255 zcmV;=2r&2l?f&fm00062000310003126S(2V_|dv00D28imiqK00jXsf&~3A4h9M< z1_1;CDgqG!0R;dAf&}Swj_D63QR=C8oDOF!(Yjs*p;b7qyA_!{G!_V0^dC5mhhVw8 zH8pT}=yl4KZDXLNU{jz08nP6JJ)*#N62YOxl$bH>?+@%@aWjdUohwr8X>anQy;?F zmVWuch4C13I`v!w+dyy?CQlw>!`UnCgaTz|bwYOdd9XIErOIiZz3#XAqK zdFNcXqEi}&zEe&O3T#IxiT-GllUU$pi%-xI-gjnae9|>D%B&A^_A@0={u>&v$r;mM za<`wjbKdip@I8O85Upu`NeQM0mx|r+q<3WKdf%hfK^d`CNV08@0`HN0X1xvyyf+*$ zct`>yKmsK2GZDD?^Upt_uikYxi)p Q0%hUvVK zNS}77#9>uISEz4!YX%-m^>w6gFkS73@n$o#-7bvbCJR6ijLh)6k`@E4#!;*B4tsQ4 zzBRwa)3G9%dWLEe)(Y_&6*IJwrf%M`czxk|vH3sfZE<$Ydk`B$(!MXct;RYhh(vGa z9paa4ij&)>SxQIbzS{36<5u6ynSXZPRIO9qG|U2`2hFS}$5@lqk*diG9Z%gkmJE4@ zoOXQZyx*K>U%Mi6?5Xw2bjbQ)T~li!(ckmU)jIWxXXirTccc=DTo%P-4!5hG8a6f8 zo6x*=K9a7xuAyvwKale))@gNh|4H%Qli{2%cpsg-+b?{VS!xD9zxKYe{{Ec&tAhJS z%(&%}t+(^9cQ`9s#Zy|@9bR?dyRWYK4h>(?nXB)3%Ll$wPA${1qQjrQ ytLwi*FTC4N-8rZJ5;}A~EY9 bokic`Rwm-Z~V^Jmun{h z5+H%EPvCmRO0BiRA$jYLowm+=-RGZC=dVliYiov|`w+c?Utf`6?fo7NpT5?E^Levs zhalagQq^)1p)Jmg6+d3jUySpQ2l(60_(6Bhmwl&v)`k8c&Y!iM@Oe?hmv)M9M9#Cn z)xF_dIFCty1W14cz8Zn+dsTe36;dA(a1xM|83@!tos5T{-lf7^7k)0z9|Hg+(q_4E z1yVVe|HF=dJ @UN#+N72(lw!YuZrPtvB14MOHR%2shwV2Pl 27%^NDBeQUOCnf3-^H z+SOF!LcAx$v6%!&fCNZ@1W14cNPq-LfCNZ@1b%)3e?bYi>2x| > xYWbZkFPSxjG%&p)D2N z;jYxoC40}O`zgsKDb5AeM6Wkh(R8V7%o=NBvRJQ@)sgJvq0CC iu34WK)M7Lxh=dcMn+b9p5u3T)Ta7-1mh-WZV?!-t2EeKIm} zicdv%wpz#4pj_ymOU8-WqsAd2#BMDyAoE0fG>C1x)}+(^ur?ZuvfT&7rI>t^)$FdN zH~OPNbbR;tcq*kt$mKxn$qEJn^bm7NNjw~24Y5;-%1A_(ga~-+DcC8RnZ?1}@Z4*( zu)0A>8$|jK6@?e0>|{LbolD92*7-S(1W14cNPq-LfCNZ@1W14cNPq;sE`h(mvd}K2 z&59cmC=tuTX`+-%s8~#`C3VGmr({pB;DDe*A@bz`GFIqZ5`oK-;->q_aHd|Kd*fvq z$u$GJnT-fD8M*USqzau;GrJpCBs0a!OQ9xtE3~KxWZ5|^5}U@sfg(iu<)_40GloEM zFli#f#pPOYxtOy(As=xrW#rv(q}9-?+nb3kV5yn6x|40JSRbIkYNv+WAjcZ3QV#a^ z_SP}>?2PO{0wh2JBtQZrKmsH{0wh2JBtQZ`7lA({UuH`sSK>4Qe~5b2fQN#38TcY5 z;-zK{B|xygtzl<~@T}G J7@J>0Qkv*=dly4om2MT*VxWZcq$CwK`p;?XD$ z;Q25cPO`bV>CJ)tyx-daogKwWJ$m_HO5)F*ZkEL&eP~OvhnkPAaX3cs%X4S|i#6h+ zXP7Cf(Zvo*;K>Yc*OPBUQ+# -o%C zm()MsGt4W`+U=rLR2u}Uyr5nwx`|syWWUf^C+tz;E#g^2G9I(aq^|m{?i@)g#JmEn z;+8-ps<5@PMZNg|C~W@>90$tLMiZvY3}nMb5+DH*AOR8}0TLhq5+DH*Ac5b7fD|je zL7YRXfUFShlH{sDdIY6Qc8XU;p^%dZjPno4c_FzXy-76T4bhtH)AbQ@PB^9LAP&_1 zn8L6jHA=0AY~!Q#W;t&)Ks{)2>|nPCAHW7-dVd6;wptPYvE3ZQNgTCBtR9DF7%z}6 z!qfN>FU8Pf=i2;;2`G~UNPq-LfCNZ@1W14cNPq-LfCPR90)I%*L9?0JF2=)tV-x+B zHBfj0jX8u&T ^IF2X7R%hB;e!?d2bCGiyrkN^pg011!)36KB@kN^pg015m? z1dvwqxrcHTddWB5eY+dPcDHsnn6I>*qN!RBk0*Q+Fh&2N8%3#)`rxUw9Jd-~w1q?1 zA#H@C#eKM6%(bJ3yVZV`EOg3QW7wGG+k@@+F089LCK26^8!Peba9a|vmSX^j?s_^3 zWV@NoLTn=bpc7kN9LUtY#~BiBHb>u)ZnIh;001BWNkl ~9{!w$dJ; zVhV#q{A}1l0wh2JBtQZrKmsH{0wh2JB=Cz6kN}WN9%9jWgx`aeFVh+$c8Yd+(>mkw zAazC_DwDm6AaP|P=`6r$NqYNpy55Wr8}Qf2w@a#f-0(xUK%t0L$*Pk@Oah1a8@E=f z3;(G@%WgRiwXdL?*emYuD~nh$oz9dGrC3i2 <$4Y4r59(Q7bnyX_OIBYH8SZmSi=)8%ojDH$TK~ zbAM(uoF>lnuug+ZWz!kdi-Y#&Hni*qOdF54tP5g+<1-16011!)36KB@kN^pg011%5 zuSmdUs=xw|z5?6DX0}4k%W7%A7)nS5JOCQALVKhpLo~}noC4ed6lVLY{$I_8U4?2J z4ngjq3yI0_)bFq+(B==Z8Qc_VRW*d$hjm7tb&SQdpQ??T(Q)ITGh8ZQU2*2ca1N2< z?a~Mgbn*7P=4+TB?o?-#y{1gcA^{R00TLhq5+DH*AOR8}0TLjApOL`LpMU=OGwMy9 zNq_`MfCNZ@1W14cNPq-LfCNZ@1b#^Zm*%SYB^S>{kpKyh011!)36KB@kN^pg011!) z34ApI|K)G~=5GRZLLQ3FKmWsi{;&TLc-q~F1eUd@fByUb-2bnCyQI5&u )FcCp@H~(0Tf& Wz|8M_sUS&b`FaP+Tf1QV;0@BpY|2{7+ zWIfkDC0Dug&wn?c|Jymq2OR(YI{gvF)A?`z=YNKC@l7qDQvcU~{KtQ!3WfjszXd)1 z;h+9T_n-d$|NCpWWUTF9{t?&k-!Hg^J|#Y;K?4`1!Zi<^TwkjF 1 za*^~%I-5Wd*7JP@m0GN=f~u($QkMpd%9iTs$g+EPENBwY=^9M{o6iSn;1eFt){AMS zM%DF0-_B9$>t!}XV%dbZ66}etcJs@$H>^E9bx_TAX3B?d)zKic?b -(Lvf~Ve#metsB z8Z;nex7^26qEN6Eif2p3H0E%dIbdHv%FKmtxKm+_j2fs6a%KmLt(u58; 1 zZqil1wHOTsZFSgS>l }T?MHGRDIZsq|N?WUgIJHIAkP zZ`XIemc93Kq4Hw?(MBIsTK#GpzkIt1M+VbafNSyW-T=Q7K;UpOj eTPmd2%k;4oe;PEabL}J|HFMwnKqSzhuDX@G zM_oO4R3CIUZ`{~JR6Py1ni(uE?RIs2?w-t-%W=bF@-rqArSf^Ft z&%GH#wKUOaM`0 zsL=1JX~XE?o(zeCLH}%QH=NC!@PjoJOXJY#XMt=K*&W=D^sP9X??y1MRN#e_td^tW z2iROh&TI&8mp7YT{F< S#ttKsd^Mh=V$D9|@oFj+>egrYZc7$jnr_5i{ z`(ES1$Nju7tAnA!nh`X{*{7$PD^rH8Gd8Yye{P9*77J6k{4rn!FAu35GI1+tMfTp& z@na9aUEA{H0H&gm-eDhGgQ9GXXFu#nZ}nZKC>X7JkB?%8_*M!DXAlDuQgHYl&(mH5 zF&d-Mb}_!lV1c_4u^Hw~md~d5lS+`K0v3>*nm=ljnYJ|PD=3aU;$s8nAZPT9gdIf< z+fIT0N!KMz=&KgjP8D{fgS`@c6_?$Ll|I8h;Xg=LOX>Y$Xx+IWcYp8ib-qPbG!mP~ z{q#k@85>jW0MZ=AP1B)YL>`6> yGTp23ZsN8Qw*$Wxy{fFkCJ)Yxy`sTpRHgC zf+5KE_rXP(kGm@9S_IF;RuUiq5+DH*AOR8}0TLhq5_kuJLjZ{R!*aEn==G*5nl6=% zSz~QXko_@ F0~zR z;_-Fg5v^eRmmHRy%*TyJa9m6zrq+(1#6{rpWZ**}!S^)k-FvQF%BXQ`xRwAMNJ|_o zGV!=tEceB9aqvCrOJHG6d`R`-a;Y%SV8{OOuxWp*4>H+_GckldU8vR8ealK@4$%M0 zwz-sEj>TyL*;1TvaNaUzNY|ve#4Nilnc8;bk=PJywS(*n*mbXF>iNaz83d<_`OLOx zXf4FM0hboRB(@>XZ1?{Ug~eF2-JI>|AM0r`18@$vdNf@x=hs+B?|vM88jPZo@v!Gk zyn?Bf(XFg!aC&kX%N%kKaUVYZNM+iyyWt`twWcu_vm-2279qJ7nr6?D^THm)0}>zs z5+DH*AOR8}0TLhq61X~ngQ-H~Vxtl@4*Qnf8auk#JkcHvkY3OFNqO2I)<%O-){$Pp z{GC=d`XiKFxO;q@9(O*MDvN}aD|7#^H>hyY5Nn9bJL6-LOu|mlv||>YdyN)WHz;X? zNdKXt@M4tp?+pFRN}9m~Yn9C<)#=O*&JDIH1nWf#($#vm_Y3`jEx6Vy-jw<$rKZ|$ zcarj8jm>Rl*F}1QgCf12_*O&%)Y4Z?93UKK8dtZMmuce;K`-?pD#|!&nqXi&sse&8 zFj}&w99$}9>-edV95|#Lub^wrcr2aCC1-(GL)PngNVb)QGvTY_{6z^ eK?Q8cTY=p#ZNzr{8^i=XknF(r;SV~0 zY{QTCw{9a-A*(WOGlKLvjyN8{uK~FroV)AeIqOKQ6 fVYMFX7jw1`@D^G zn?vV)?oju5C?O=v?(Gz6`#m#YP%`72UJ(v+6wM ~&3 zVzcN $?i} z*()CS12G^RMlSd@;8qEl2ni9Y2#uLOcH@P$mC6DACAq_P{3tdr*JyLwd`Rf1&*-|F z&D#8!X939|C0@t6MP1`x`NF({aN&^pFQd`Z)?)&Ag~=llJDN_O%?cw~l+rnKdBmVl z&BZtK-l<#1u_E~9Jj~|F aW<7I=$r=fyK5|tO}?G2Vs5$)xNHHzKT#jHf;#EI zb^`N(Y}svrNKaXUKmD~5RcK4f+T0V~tl(Pj+OwJK6{E?hjukKFi03%Bf0XQxhh&PY z`6AXlxSSl&1wHAX>OCiRb62hk)UY_%gFO8{;-xTgWtx;pJeN=Zo~~3@nMF)ZH3XED zi8#1F1nQ<8c8U?WXdu0)9Zq7}IMBTG4uavvEYj&Zp=}jW+!*?DA+2U&-f(&!+@w-S zBjOrzVcdpkG0|5Lt~C9J)}}o`4$(>XK|S;7=SBu>AE)n==T*}_d&F zwXVguUZB6d*1&6L_SU`-yMSV)X&5DrX)SC~S+dLcx%F#xXiKp&n zU{C02XMaQo302sB4{@w8g-F1N%GL_&Lw>~Bu(CdejR0LWs|>r6MBv0%Z4@SU<^xNz zTq|c*)S#;XUx0Zd*iI4Ab_GdqIexgHt8DQI4C`fIHiyq=RaDnGM zwv<-U1kuF1n>|hiqd+0$juSYZyylS^(Qt{KLT1(3ABWZ!8Vv}LiPcB7)2fOUCWasJ z8=GwNsU|$J@I=`$BpJ`7GjWmr)gQQVoK6I`x(G>u^M$rkAOi|YeZoV*YZVetf=ADA zBxfxtxHGtJgQ%ppkg6ZJJ3Ph?X&38;*eOs0 bx$Qhe>|;MWZs)V!Lla~V|fkgA8F57Vha zh8*)Wm;;UhAo}$o3dEzHK83gwcV$!ej4+vaaydHB!*C$^HKRL27hx4IiE|MR_HZ5A zfb5UMT)Uk!4kaYvSkanf2F>>7p%J|NB+x8cE46Bjv)=}tjig RkVbjq{No zSgF)r&UFuTQpq%`h+5@i&Wlgin@UP%xbB(Y#G95dv4$Y~YqxT5?ze|s 0h8FEIP%H @fnG^kEDmXBA2GmroYkN^pg011!)36KB@kie0E(^P@hbAAvf3p$z-lZ8$>YYZE+ ze0#7R-yMJDK2GR9N<_Eg#!CBBxK4=cffZ3=o^boEJ3DVTv#?wM{-6`*V41r2I74uL zbM#$pCtIb4Crk{^Vdjtdx=tqcr8kWsYPEhxnNw|RK$(Va^m~2OR;`BLPXv~T?f5}& zU#G^ho;AhdCwVhuLbk_h;`GyS&-=Nr#FSG_I8#pe^?~`IipnXm?W9}rJ5vPo*Vdv8 z(pF5or9I^~h#|-8!HDA-E2g4m6xm;G$cSS>9|`F|U6nqP#KKKuR33Z9nsQ_~tQ?Nw zsb2XqyVM``w4Zv32qqY*pzX%2wp*x`Br&VQ<>u7LFWDZDGWSdBNu@}D1W14cNPq-L zfCNZ@1b#gN9#h4;7KmTPca;YeZa|(sxbfRQ1=w)HBH$Md*L~z #%A#gq>4 s(mp56_Z`5amnVWiNExhe}vB5xr~eMo0CuuA(wT7=pIQ terlBhmEe?YfSChAR`A5gx1XBk z%?fjavv}_5#aL%B9q!1U_3|pumbcBN!sJ?%GBH%~iJ)%Ir7j_U>B3WDqvT91q89!h zY#{*>AOR8}0TLhq5+DH*Ac2n|aP#M%f0~kIXOhSMG{F7g&_RBPR?dB(U!|Kut*YjM zZvUR&vEe>Yt)4812xU+?b%R(8N8$|sbRW?IQ_Co8+*{jP=M >|yD7#;)-DYv$g?Cs0wh2JBtQZrKmsH{0@ovOG*w(rCMA&o36KB@kN^pg z011!)36KB@kN^pgz#9qt<&EPwj08x41W14cNPq-LfCNZ@1W14cNPq-BfWXmIfmD&T zS^@D0o>>s7(Ru3Ngs0vA5)wL3PrC2<&i>(MiwNn|{AvXDhj)7IsROM8&%U-16N@Y# zf!E4;ZGYkW8S}nYPxdDP5+DH*AOR8}0TLhq5+DH*Ab}r1;ApB)iEOc$P59 xnuVkN5X2BikH}I)#g@6|gm=+(r-xF%%M8=6&LW8l*-;S||QHo-K5~Kh=MTXx6~Y^=36`HORAHL+9D|AH&!JzF5Ognz7>j1So+7NPq-LfCNZ@ z1W14cNPq-LfCQWbjuk-i+4O!=F$+4vd|=jVl;WC2l%c3>vhBjmTXVrF$UcU>;$c>3 zf4i)IGFQ$e46hwzzgKZs8f=+z5YN_&u}S4nAJjZ0mI|rSAhk$gQ*h+4Ts!lFq9|&8 zzq6`y$WU~yj>>9mY)nDc|GVWrrV@pMt&mxs6JT8PnkhmTzTuV_dB(`7fl4SR)0CQ> z^WY2dMjV!uH)KzA&d6gDAOR8}0TLhq5+DH*AOR8}0TTEH2>gLfdp?hyc|052Z+Egw z*Sqs=_f8BG`F1^xdYRMbo0-ubRo9mm6j<-}^-?uCJy$gV8+B#eO{Xs=O0A57Z^qPz z7S0Fz<#_IHM}5`(RwZNsT5AQ9Lf_pb hTG zK0tmwz2B{mM4`+~m7gS5L*hqZxv1&96-Z!_Q!Nw_HGMtI0eYXm95?#V`JnYZ{1OgU zkE77bjxblQIl#=9b-$?Bb|dZ{ryiKG+AOL`OO$?j?i
jIv`f2j3yn#*8{kpRs_|Hr2H$iN$j~i4 zf=SeJxy|HUX&=0_UZ#(gyJKKQp@!t0DK#^;FmfctPLXd9im^;CpM*K3=X1~yohL)v zuff(_ritbpnJNnTc+5Mu|Fr~@EXRGXaRCeW_q|GstPX|>Yevuj-Rs&)uA(P}kN^pg z011!)36KB@kN^pg011%5k0c C?x!S|q&OE;6TRM4Mbo9SF>9=i$zr`q zR!6dvhcYXbuXS>pVSoC3^q7z&8nCX64|yf*@Q*{fhuz$pt0EIfHF-=+k%gsVq4IfG zhKy{fo|aS+aMuVN|K>(iE~!iAjXoCIX(Fk`5FR75Mk_uVJVm>$hLHCQhj&SP08bPd z7}&u-ge@dM0wh2JBtQZrKmsH{0wh2JB=B<)&}lW1F=A`n!fF8B5wwuZ=hyRHww%i= zF;QT 5e^?t0M%nHI;!@0x$!d1j(i{EJAUeK#e4HL6n5QrLAF(GZ7zof;%q1o9aDX+$ zPAMuf5Lt4OsMmFZouZjp9Lx>Ry+#YG8 3vZl$@`dmAy%T1W14c zNPq-LfCNZ@1W14cNZ@B6@E2GX+NHEvaYF(nVp%v%lyV6bi>bAwu2}Ds?CBL85OgR+ zzC1w23Y|+LaDh_XbUzu+)XQ^kyi6mxW?(n75n(1HcfN{Lp)+b`cjJm=rg(WN)Ff|( z78QXkJBLML(>OR#gh;>qlo)Hq5GW2NO+>i3Tq`aYbG9esBhICayc>?R8hUkmGqD9M zHS<8)Q}tGSoT%Q!QS59I>w%zksU~Y1W14cNPq-LfCNZ@1W14cNZ{up z@Q38fY^mf*oF=5GXVid)f_NGDA|~RcW(_4ku)eKfXNd5u)+%m#2v3+9%X&TBv0}66 zR_40eC`3hy&GKa2(t#&<2{q!;C=THHFdI&?xw+}hf&IMS+X0;Y#PT`Cm%n&z)|T z#Ug!ZOR|TWkF9YyM)1pXXaI{f;-Y7mDXQh{X4n`e^2fjvbEq*k6dKK%tP =zk ze{g2GXaaU30TLhq5+DH*AOR8}0TLhq5+H$}pMV5_VB;T{i6NTH7f=NhwgPicFTo)w z?h&?VajB5vrdFN>7#K=}dOJUT3=X8g)O}T`w#&_!+HUtSR>U%;W~OwQBNB+#%?~7+zs)P&%wesKsO+oqgmW`?~d*XQiHQK$qee9!pu%HVGhQ& zJfF|S)n>Dn4ZNLcLfWf|^?c^6OX{ER8RnH|?RHTrstp2FUQn+T-NdaUvR~+|6ZRIH#`%ZjypUXx-XxmvhG