From 4a47af2d141fc89abef90c25e102bdc5295b60b3 Mon Sep 17 00:00:00 2001 From: Gautam Sheth Date: Mon, 10 Sep 2018 15:36:51 +0530 Subject: [PATCH] SPFx React Accordion sample (#599) * React Accordion Webpart added * Updated to imgur image url --- samples/react-accordion/.editorconfig | 25 +++ samples/react-accordion/.gitignore | 32 ++++ samples/react-accordion/.yo-rc.json | 11 ++ samples/react-accordion/README.md | 72 +++++++ .../assets/previewAccordion.PNG | Bin 0 -> 57412 bytes samples/react-accordion/config/config.json | 19 ++ .../react-accordion/config/copy-assets.json | 4 + .../config/deploy-azure-storage.json | 7 + .../config/package-solution.json | 12 ++ samples/react-accordion/config/serve.json | 10 + samples/react-accordion/config/tslint.json | 45 +++++ .../config/write-manifests.json | 4 + samples/react-accordion/gulpfile.js | 7 + samples/react-accordion/package.json | 36 ++++ .../ReactAccordionWebPart.manifest.json | 33 ++++ .../reactAccordion/ReactAccordionWebPart.ts | 83 ++++++++ .../components/IReactAccordionProps.ts | 12 ++ .../components/IReactAccordionState.ts | 9 + .../components/ReactAccordion.module.scss | 73 +++++++ .../components/ReactAccordion.tsx | 180 ++++++++++++++++++ .../reactAccordion/components/accordion.css | 109 +++++++++++ .../src/webparts/reactAccordion/loc/en-us.js | 8 + .../reactAccordion/loc/mystrings.d.ts | 11 ++ .../models/IAccordionListItem.ts | 6 + samples/react-accordion/tsconfig.json | 26 +++ samples/react-accordion/tslint.json | 3 + 26 files changed, 837 insertions(+) create mode 100644 samples/react-accordion/.editorconfig create mode 100644 samples/react-accordion/.gitignore create mode 100644 samples/react-accordion/.yo-rc.json create mode 100644 samples/react-accordion/README.md create mode 100644 samples/react-accordion/assets/previewAccordion.PNG create mode 100644 samples/react-accordion/config/config.json create mode 100644 samples/react-accordion/config/copy-assets.json create mode 100644 samples/react-accordion/config/deploy-azure-storage.json create mode 100644 samples/react-accordion/config/package-solution.json create mode 100644 samples/react-accordion/config/serve.json create mode 100644 samples/react-accordion/config/tslint.json create mode 100644 samples/react-accordion/config/write-manifests.json create mode 100644 samples/react-accordion/gulpfile.js create mode 100644 samples/react-accordion/package.json create mode 100644 samples/react-accordion/src/webparts/reactAccordion/ReactAccordionWebPart.manifest.json create mode 100644 samples/react-accordion/src/webparts/reactAccordion/ReactAccordionWebPart.ts create mode 100644 samples/react-accordion/src/webparts/reactAccordion/components/IReactAccordionProps.ts create mode 100644 samples/react-accordion/src/webparts/reactAccordion/components/IReactAccordionState.ts create mode 100644 samples/react-accordion/src/webparts/reactAccordion/components/ReactAccordion.module.scss create mode 100644 samples/react-accordion/src/webparts/reactAccordion/components/ReactAccordion.tsx create mode 100644 samples/react-accordion/src/webparts/reactAccordion/components/accordion.css create mode 100644 samples/react-accordion/src/webparts/reactAccordion/loc/en-us.js create mode 100644 samples/react-accordion/src/webparts/reactAccordion/loc/mystrings.d.ts create mode 100644 samples/react-accordion/src/webparts/reactAccordion/models/IAccordionListItem.ts create mode 100644 samples/react-accordion/tsconfig.json create mode 100644 samples/react-accordion/tslint.json diff --git a/samples/react-accordion/.editorconfig b/samples/react-accordion/.editorconfig new file mode 100644 index 000000000..8ffcdc4ec --- /dev/null +++ b/samples/react-accordion/.editorconfig @@ -0,0 +1,25 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + + +[*] + +# change these settings to your own preference +indent_style = space +indent_size = 2 + +# we recommend you to keep these unchanged +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[{package,bower}.json] +indent_style = space +indent_size = 2 \ No newline at end of file diff --git a/samples/react-accordion/.gitignore b/samples/react-accordion/.gitignore new file mode 100644 index 000000000..b19bbe123 --- /dev/null +++ b/samples/react-accordion/.gitignore @@ -0,0 +1,32 @@ +# Logs +logs +*.log +npm-debug.log* + +# Dependency directories +node_modules + +# Build generated files +dist +lib +solution +temp +*.sppkg + +# Coverage directory used by tools like istanbul +coverage + +# OSX +.DS_Store + +# Visual Studio files +.ntvs_analysis.dat +.vs +bin +obj + +# Resx Generated Code +*.resx.ts + +# Styles Generated Code +*.scss.ts diff --git a/samples/react-accordion/.yo-rc.json b/samples/react-accordion/.yo-rc.json new file mode 100644 index 000000000..d4eb46a46 --- /dev/null +++ b/samples/react-accordion/.yo-rc.json @@ -0,0 +1,11 @@ +{ + "@microsoft/generator-sharepoint": { + "isCreatingSolution": true, + "environment": "spo", + "version": "1.5.1", + "libraryName": "react-accordion", + "libraryId": "6d6cf05b-cfe5-4d12-af19-19ec3aedcaf9", + "packageManager": "npm", + "componentType": "webpart" + } +} \ No newline at end of file diff --git a/samples/react-accordion/README.md b/samples/react-accordion/README.md new file mode 100644 index 000000000..f43949517 --- /dev/null +++ b/samples/react-accordion/README.md @@ -0,0 +1,72 @@ +## Using React Accordion plugin with SPFx + +## Summary + +This is a sample web Part that illustrates the use of React Accessible Accordion plugin for building SharePoint Framework client-side web parts to show SharePoint list data in Accordion format. + +![Sample Web Part built using SPFx with React Framework showing list data in accordion format](https://i.stack.imgur.com/QsZ6o.png) + +## Used SharePoint Framework Version +![drop](https://img.shields.io/badge/drop-1.5.1-green.svg) + +## Applies to + +* [SharePoint Framework Developer Preview](http://dev.office.com/sharepoint/docs/spfx/sharepoint-framework-overview) +* [Office 365 developer tenant](http://dev.office.com/sharepoint/docs/spfx/set-up-your-developer-tenant) + +## Solution + +Solution|Author(s) +--------|--------- +react-accordion | Gautam Sheth (SharePoint Consultant, RapidCircle) + +## Version history + +Version|Date|Comments +-------|----|-------- +1.0|August 17, 2018|Initial release + +## Disclaimer +**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.** + +--- + +## Minimal Path to Awesome + +- clone this repo +- in the command line run: + - `npm i` + - `gulp serve --nobrowser` +- in your SharePoint Site create a custom list named FAQ +- in the FAQ list, create a column Description(internal name) of type Enhanced rich text +- add some list items with Title and Description values + +- navigate to the hosted version of SharePoint workbench, eg. **https://contoso.sharepoint.com/sites/test/_layouts/15/workbench.aspx** +- add the Web Part to canvas and in its configuration specify: +- name of the list where list items are stored, eg. **FAQ** + + +## Features + +This project contains sample client-side web part built on the SharePoint Framework illustrating how to show list data in Accordion format using React framework. + +This sample illustrates the following concepts on top of the SharePoint Framework: + +- general + - performing SharePoint GET operation in React using inbuilt SP Http Client + - Using Fabric UI button component for pagination + - optimizing REST responses for performance using nometadata option of JSON light + - using PnP Webpart title control of @pnp/spfx-controls-react library + - showing SharePoint list data in Accordion format using React Accessible Accordion plugin + - searching in the fetched data by making use of Search Box from Office Fabric UI + + + + +### Build options + +gulp clean - TODO +gulp test - TODO +gulp serve - TODO +gulp bundle - TODO +gulp package-solution - TODO diff --git a/samples/react-accordion/assets/previewAccordion.PNG b/samples/react-accordion/assets/previewAccordion.PNG new file mode 100644 index 0000000000000000000000000000000000000000..c37f9040f4eb4281026e326a7914e5e79c8826c2 GIT binary patch literal 57412 zcmeFZ2UJsew>Qi@J~I{sX2g!b%%B3&RH~t5#)h<@pdc*~1QDqMp_4dQfk8?J=|W%- zLnbPO-XTf`5JDLt5PA$nOehHn5JK8}Vwv%IuJeBHd)NBbx_5nF))G%n{&nyD-}|@A zIf)k`<}y1D?vRp_lCijO)=o<5E4Y-@Kc=>Q1>A{Q%ish5eGy`3ep;%m?+_jM@=xy{ zZGM!Jsz6B#+`k0AZx6cQ6e1VvR5mHjrQH!%bUXFk+3dN{Ha1WiRc_iCb zaOd7`^?|fX5Lh$n@wxj2=L{{4E)7Qo2VC4063jgH&5rE+-p%0pL(I`_4hjZ`<83@D z!(aR|Lp<>X%x^fU1xnN$Np=@{EhZlrPhNTbg3BRO3Z5)KS+?aylynT?vsd@lZ|Y7C z4GozNtra}ktXc4eZPRH!?j{m3#bzQdK+HV*#>u=F4D7ASb?nrnSf zQGNIb)UnJ}T_h(}OR>iEQH7J#ID0H4j+CvFpwqhXeazaBWBcS6K(FLm$Gjf01)P3E zNZ@_Dgfca_)Z1=+EL?Z=>qdj4j(zv)6z-$tRU!ARvbE##34~{pq;ZxDfmhwPqD@({kf(5Jua1Z1~RzOgR`AWw1 z0hNfck|inudAw9J&I8-BF`abRr!J5hfL`A=K!`aFI5)ZQi<=)85%Of29G`-oR< z#dQ5iUYG4xgANW3&e#@qx5izc!r1lE z%Y)F^wV@Z)PaW~K5aS5e>uY0dcJM+q1sd&tT+8%|`*<}4hKxO~HK~?=V+<_jfaOXs z=6y9be5P1PkSo#B(yDxJrKbChgJ z?CLA?(!o?kV}qP^T7ojrVltenXw9F~L5_l!uwWtm+E`oL>4oZ^JBeWBrKr zsu$HupuOE87}x$0H!kK@3f3&4-UlfA$dFr%<#*g#7ddlh1Z zw5_$VLK3nD2dGVh)>cS-HgLuD9~@Y^2P|Irhk@4QvKkgMt^)j67Y?i}?BaNJC?A)f z72sH7V^!BFx#cXmRR-MR+UROcmT3a*^CUx%B}0r!hR_0T5hX*^k%0CQlJ+e?drF;+ z6+sTz6LUN8BOyU@r3&<9>I3WMLx6Qh+X1T;k%84}J3y=m#lQr@R^VU|wgT%WfPr;0 zGbJ60fez6OJ>cqvr0Z=-SNN%=K=FE@0yeYT$H&rUFzi97sdDzMB6*iZHTYZ0&1gBP z#^Zx@%D`jehyk56dVKRBUZNsq^fFI+J=}plX){9t8s4|tdZ(
    Bm^eD0xTuAa@g zzMzK)?Uaw&!x{sLQj3WKrLU5=)4yZWX|I8%QvN{G-t)LKju{}SP_Gg@Ra0tcloEIK z5Se}|F%tx|cy45a>A6u%F4C}6lxjR_k4uND8MbWmk4o!X{l^1(yMkmfW58na{+x=8 z=|cfZA_$Pk#VC+r;8af;wwNqw*Wq)_%Rm7m>voAD^+zVo3T-$Qp%Nol>2&wPB-q%Xs$C{9IJVHBATkvvG_GfhY5M(8))Pth~_}zTe>(CLU!;sN4dLbzJ0c~o|6yHzNL-cip?X(AQz-9;5p%&p15$kH6Q1sKVC;BvR0fu&+&rHUoGC)kKp z>L%m$vIW~f{^Huz%Q#Lrk{eDdt()qGG=;4(hFI@sdJ_dK1AWnjFJdp-n^9{A@iqM}KE;O*9^{iD zr<@d@`*mc2==z}p_GK9Jw~yl>QHtpCx+w5&@f@3S1}L|v1gb14C6A(eY-=uecj{X!oU+3fk<|;V{GEw{EYt}Q z*yhML&s&Ns$h=o5#O|qxnUr_zKM10$Q-E#mekV$r8KBj!RBgC(hqrn6Zj439Pj&~j z6VK1Zb-lelJ2+#R!4N#2wnWEF9kj|Vnx8a45mC}X_%2KI>cdk=F&C)}jhxF2nthq} ztj7Y?=j80XgHq;3Dl3}F@CA1B{F!8Uh&H@(;8D>pxINnKue4LzZ7%(uoL^Sz@wi!C zFB{a$F*7mXb06Dz_XuTB{;h=d$gTB`g0Zf2RU*zF+qP9X=Ig%vQ|XGiAw2e6d1d7T zbifixhp-bCyOw!c!kC;~y9Be*L<+gfD(BH_3+cR$o%^(9235_bcE@#1YQsDF^6a+e z$PvQm1DI#OTi|m!quzya3WfomSZ6EJA@g})45{$Dl0hzEAYuIT7O%n{Lz*hL9aFl# z`09AW+cr--oP7i84L|g;?DKM%m302<>aDtf$?p64tBt3IR6^d<@`gIVIz@ZNZu9Y- zmZ;zTFz42878ZSv`7zXe;5f43)xx?Sb)MCnoLg5kx7!pY#m$inRr&j+S;+!ie#D(A zT)bzes-yaFM{4uNes#SEe06+!m4H39DU<=9UuPEaTVuXm)DkJW{`c@-kp- z$NcEU>FOSr>kSz47g291_r(&F<97ff8(S&FK%D<$C#I-;(K}UC zn-8!+qK5Wh-YZQ&coHQ_6gZoIO)4e9O~7}*Q@{p+j=xH@pp?`#5aWqrL$>1!%@k zCdv7a|5lBRelgbE*01FL-eCxAD~}dE=l7A0i@(^- zbBQQKq{=fboqNblu=uc`OCBkYh>FyjFj^C`@=|8TbrVwpfsO`5Zucmli{6oR^a~8+ z(%WaHanfS;QpzrGsx2|4CXQ7+Hq!OEc|u(o8Rl;VCW2nMDOr-QVO!jpa~0`XAVZ{5 zE10c2^SLSL^_q&1@h;HuZt!gzctkcmpO6kUFVQOtGCe z0HZm1;El-oirT#a0=7Agt1)=}vjYQ?y8}%E%TSe%g@!GO@&wz^2c*$@=_4C}vvW;1 z2A>a@$#-&>>8}m1t^LE|bHj{w*m*DfUAJTKjy)i%9JnPWe8=C6tOl>e|INtLcHYtN zM=r1hEUIi%EBsr{ed1+&x_cnoY=jS8=~whp?N^YJ`km7f3|PF)vl7ptwwlZnB`UZt zy$O!s<6AEg{FB~KUSMm9M*jdDk{`gIO0dgShMEyP3va!a38=zQe z$>crFE5fO%j!uQX)qpEStGHfu z*(qKP437&GzycHIYUWt$AucX&ALn|8VEWFuGhbY%jTkSTigbS(He7YUxR~7V4OCd{ zMr-9WrMbfPigJD5?n4xf3LnP-4B@bTv1ria!E)rJ#w3$IuV%M-#f zMmRvWT%kKx80i%9I$QpJ66qW-M0|#p%iX+GI~BnkWxXwI1%;W4g3nd#lqw&}0R5?U zD!nj$T-(yPnoMb08$0D$k5f~{A?-u_JT0xz0qaL(dU2Q63y2zAyLmNeWUW_7Ys>Cz zOXo6opp+)=7pq6PGF****#|-fee1gMB*&o3(Xg!otF*Ie*>^Xo1V+;FXi z>?FIjHM6;s&}x|9>|}j^Z7442wcIi(i`!Y@^@l8AhonXhd^!!BLZ+*wtHC$lDyhLC zV1-r((>dpLW&%;vglNe|WPxC<9MAed3gtl|dWGykh%qp!Uub2`8gtiiT@scV-?j7p zQ}Q!F6*n~Dw~XDhQE~I)RT}FD1H9b5PEmt9Wicg=#c1tpQ-SsC{Id|cDllwaxj7OY z^xZ^GXvPbGAZ;(a+pZJ1*H-p7wZ)3x6tUjg#!Zb83TkhUuSFHJ-oiMF?-h^5W z6T!eDY;UDX$oioj3aYMrqeXG48_l<0Yqwa5*`WiIi59bpSPI;I{Y;ATPLzPIOB>Q9 z9%szo-zDu>3>C#WUe$uXK@{7a~{`&V1{Fh`LQqNSk6Y?)i$XWBjW+wF7*+Uq+eI zLKy6>pw~Ea;+eaY`i=Yu4`hVz?Ve`YNiI8j>n#qtWf*Li9xXI?-y0*^jz*}mKIx9mUU@Gz*&`BiZpB9 zoa%IsJfc|l^;A@3V8kqC&^K{WPPq;p#b_&HdBbcwVrD8>f*0w$>(4Y3P}FFB6T*B^ z5ETzT2yF@Sv$8@v%_A??PnaAi;B{=NDTF~y4nT!Z&D*v#J>XA zeT&jv&D3zhr>z3yY3V49 z??bBmUB2jKzI6d}%MfLg-AS8$;mui_Rp>ey;B5PV%boI6jC{>qkKe*1Q}C1G8=L(O zQg^h~;S%rgovA#BllQg9^i|PDP37WlV^cTT^Zoa>GLdQ~gJJ(XS8-<5*H&ha0*-{g zvF{foOK0kq(3h*gT$YhTaA>Tc%H-NdKa@HCxJTt}S>R)g7w z#U+TBXFM#=g;7!WT5OkO<%C#AVq6Jjv!kM%>)X|MJouku*|ZVZM0RiVOh0DOd00{E z4*J5siMl#`nV@4bQmxyZQ82Zzz>S*(=LQ`<9j2H?i@acK1BcZ!<($K^9AX6Fa^9qy zq1eq?yTcSahTknwl2?X_=q}NGn(VrbPiWAX$WA_>?}D>e`jPYY#X5SzeQt>LwhSNV zZM#og;C%b+#YpnG-r3@~EaU_2yq^c$e|2|?iTZZ2Rs0j{t*vwGq90?;$_n3GhLrEw zm{NEZ3eMAl5BRQ45R98a?o*Y6Oqo*TAfZ-k;r38H&)T+W-));mI#e5Ja{Pj+7Z)AV zhY;ol1@}yPn*S=J{7t4{A$PW=cC@$@09ZRPeSZQ)HMobDF)~j%M5WmHCZ}z>s2o|5 z^T)Tw9*3v(T)&&8ghehEY8*McLJ?iUoT;#156A}PJrtj9O+H#UrD+`NFeAHkzzTh~ zwn~VC%J|nnYVU65@rgY!`AV-T(dLBF#!dEwvUGy;jn^Gua8{{f=OdKIe&@ZTKH`qu zphTM%gnR+aW?|FtMXDB@U2NOB?)VMm+@_cF&qJ_zI&9p@3O%isdtxEd4f<=UD-#zX z?8y2R*DjgtA&O9}L>WN$`T>eEzWD0fRRW#Un>v9UavtBWka<1lkVo&%^d;yNe zr8E5kjgEbn&iuKcUOqZGk?6$vHN!3A)La8&B;4Tjb9sH0({dWCIUO+zMob@uiH@C60@>T%jvrndS07x zR`Kr_leh)jYN;pxYw)9sZ;8x9dCO)+ElPJ4SlL&|%$k5in>u)B41zD!8H zKW2@yKh!W#pX_{6FoBKsSDDf%<(!(-PwX!K`4$O7Z&j#i?t{5)!;4;Rai<97;=s{# z&-&vW{tl^Mqb<=A2O}L~iN?3?+&49#I*k`T zmgUf@sU+CE>rM$YIgl!&wQ$MUU6}W+akp2aip@h!6K+lULfv|Tb9*h_Za%GCoGnB8 z?Fh_3v0{&K?0mDM^L$8me_6>~<)|IDT+mnL&LuSHG>Eshso1t0+`HT!s3`S(!u~z` z{GxFoA>WyZqvdwiJu$7Fwd7M;bH_MLcP}C3{a*Rq2)e z2K%(p`rS@;v9ahTawFn#wR%>2Q~RZFV76J55f5+GXUOzf&VI3xjhQST=}URL7HHtc zunzxc&sBNY_|II+g&0WqS#01&rsy579p z1~xevwfbWoKDB1iPb=xpbYUrbFfql|-di4EW;0nG)r~uJ`$3BMjVO`A^I4m#V9g3w zC^KED-yaBHLc5db^r5gg{`stEFQ*KJSo!nkT`^x^T!^V-><2A%ZIF~w!yD1Sg# z9)GVZyTYviTj5O)8->3NHS(w@an1V9*-G4LTyzRs2!g7 zXkHg4Hcve?{=iN(6Dc~Yi2F*a{EXUrEK!RmcZr{eJpqUItQQ^zbI4sRz{{aktnMDk zWIli)HXR~rgWU@FqTVyKR|L@BEDdTMhxvjRdpUD(D?k1iYEKp_&RhK2uq~EOKnh=^ z@%>J!!J(~RYYWaGsB+6zZ<^{`D##5LUqdIkS0g-w7!6z7?jkq*j2wiOt}b6~ZA+*2 zbegexRf#|8(p!)R_CljHO#}<{e(FBNj9fgzY-KJN5J+&$abvfr_5Flw!J-axT}kQ= zT^%rHgq`1qLmjOrw&xv7Wkj$VitNv{UkJadN|;z6upT}({*`kEo)=bo1G^)yd@!8W zu(hgCSsQMkFHZc;E2A5F7YM_{zM4rro3pXMJvfHF#@wg#9p)AeVKG&5<*MYfk*E753G> zdD|>|d!Mx{mCX<4&1#=(SQeFVkq%!4v|l=!g7?4lJjGRvdsG_1o2%-oj6UwPo=z#N zzSxNOiS&2Er58e(zPbp6lvL=C?-5I-KL)b0wRXk3>q16chkP_~>e<(pc8l^B{hn!v zI*8T%1aW9!#0_eCJKQ!rj^DZ>c)jy``)rVy-US??_E@uu=!^SJbFz-{UY-XKZ7>oR zo4=$mdWBzL>df%uuomPJIz{YUPf_9aXs$`dJ_{H={|ih$K5z+A00V^uMm$ps0|2pS z#5!K7ugtf}Fj9o_Y=?kq?PB(j)RoiCAgB6rkKS2+&ym{S$QGL7!{9Gp6$&{yG6NEa z-ZllQr!79G`^KBl_|0BXKzPJkTnnxLffu>HN`IWr2cRSR4SL*gYEnUIjN=y(Hv16N z(A$GtJlPEcnB;w`d2_1_#R~UxWb$H$eKb@ip`bBvG1g|4E@H9D_-*M-Ys!wf1bYgq zufAgAHVIY}b0AeXM>%-EK1-2dm@ZR%qP?$VnBX~i!PbA>a{+#dZSQBAq$8&u$Fz1fkWxCJ#bHQIL37g_l zz{#4T-*mN(-a@WAHr%k~nWMZS<=q&IQAQ@nqlFn3gat2@z9`zWlx*R}$3F0(PAHr8 zy@{>{PG0@-)mTujm}=8`xlGkK2R}RCjY|B{C*yI{lg-7(Zr+IF;ONH5$e!w*R#}lt ze&4kp2rA*LK<_l!;^Z~>USC(8snTvNzYrcnSiKqXt?_I~pixl7cdl0(z6o#@8ReVA zd~1>}9D1>ZmPT;8DQLec#bpe~(NBtml{Tuh|p z66ql@S!F^M_|OwS>$9fkFLgZT>Mqo{*g2ijC8e3Q$2+h6mgd(wNHF8QcuJd{4rV_* z+`rV~NaWDj&4fz#lgHoaw?>{c;iS}hU>DYOpiv{Mg%~dz1H5hgJPe_6D0+V6TYT$f z-a?+ZU$@uGW++>l#uFdWLMm;KPUkys=;d-VrQK;P(d=!dZE_g%7bzNg18thd2j3dD zEq6zIN3M8AEX)Cs2&anG3lXC1wIharOsJ(EjADV8$i0!KZ2~ps2k5>R-pQ z38`{oA2z7PzPW=Q5~~_H0gg3_lu4HnWt#=Wq!>Cf9uLM3mwHZ70XKU+8sIJA zzIFddnze0!LY?xp$7Bn{@@(t0^@&lhf3TT3ME-1+E#crg)2dZ0hF0#puaa^LHFOd- zH#21W1vKk)`}GVGPU{k%CsmsY7`-gOcq$|XN+LCBFLY)X^U;L0n-Odb5H?5;gTTxj z#G`zqipgq%ZM=|~fijE4ZnBO0RS92{IC0B6IXv626nA(vv9QF19ib+NT5rNF3t#u4?$#;sF_q5=K(*6@DF zKo-8M)sc95hMmtkNVN{I#p?_P|K2wV6H7ekc06+MrNQfh2tAX_P6l^*fJtXLRGN8W zefddsM+=CCE`8wrAY~@gbZ>zU)i`}e3O?W-N{&J`rt|Jraj7&^p6x!vHD8zgX67p) zs)obaKTjWtO{to57=7ET%zeI5Txf8GaTvuXITCfRgA1jkmK8r9W(|02jD|^WY`8Dj z_l(o!BN{v+PLG2=AAjH_z9>=?{>{M@at|A`y2%CscvpEap0gLGx zeP`1IJzHS5tzu@h*&!prt&zMGpQ~S;;S6m=w2R7KT+aaW&HE{$pF@8sgs~D5f52vd zLgtp2FEi1PemM{wyJuP5a4PnwNvOCih^h=kXbjzKw@FFe_z=Avt+i8?D9Upp^GJV6 z6@c&Jld^(0>s8?Q?UQOUL8G{ZbUGkUK|krKSuRWW3z~DtzczSU6u_feD4v_K?HH-A z;z-jX*2T>T!dlGjsM^cCtKm)L1IQ&GNqXlE;HKm+KH^s88>A>Mkp}zY69zdO2w@k? zAy(lVU>%R%N0CQc?Nm?Ho7qHlFLvt(+reTFOl>B`6ps9E=RK_tUzSD*LoQvxN)d;e}T?u$CYczk1|3f6bgIs+C>`LhFY=K)~88P~r<^ z%^Q5efIVuSGRRALQT?->YDLWPmZJd(WjQf@iq+GqN?e{^o#3qnCH-{wA8NUx-p;lu zzlk&MT;=LRI8JW@kw}MM7qfF&J@QRSyhfcxQP;*-k6XwVt_b+W;mgw5V2x#dktt6A zW(O+mlqEko}`o9+3~!uiQ3T@2fbBkM~A0f0B5?M2md`Kz{Q351YyWeTk8MUi)su zzUSN1M;T? z#s?}#84GTvV?FXdlQZ=5!Rgk=L!!EC;>Ue?b;w;Jy0+`}&o15z195r_XLjfG>&gzaD$RN4^1D`xR+>I~!}EmKh@|Z4cHNesI(4|SpBJub zvnsr8ii$8b;cnVp)hQW@{id%u)W~GTSZvxH;Zd3cq`aRy0HJ9KX@di^L8`>5mn(Pe zu<&LeMA0M}#0ggwX3$*Dzc#|1u^CBxPxw9TVn4_Y^NF2a*5B!>!M_rNO_Xgg5a_`gaL0Mv<-Ec`#S6|sFy=`VqxwK9 z5dX;BXH@eKFCf=}ED58knDhKH%QHe2-I$HBc({X_eZv0!RRC;wi00 z9CW-nNKf?rsdw_bRP?YJAf$Q zjU=KBUH!gT%>fS9Fd%)jx8lg-i<8KT4esIawnV1VPFs_vs{+X>Fa2;VJm-~xS{LhA zm5Fw$Y1ukw%$dn14kubhVA)<5_4L7r!RskNd0mLV^Iqbd+z&_zw{39pZKW#aZSqaj z?W)7~x6e$tZbJ%<@d-$yJxEVEfEqw{`kk~?&fszO)+BDW{=OqXz-X?2{#@TpoIO+( z>s;3d1|;!VFnHi#gPSQVuJS$+o+n-J6FzUY_xc-(G2Dd>h+ftE;(RA~+l{jPaKS@x({ z9JQe%?o4A%S9Ml4vycL=pHg9jprt&h*GEzxS^GiNq@!IKnuO*$v#{Cu@v^(Rw_I_$ zYQ6&*+$%j+HKFRZonhgY=->%fziK}n#}<9D>7QqX4os-a1`vh@U{_}=zQ=3E*N_4e zz=4Oru}A4;l8PAR*h|(favI*?op>SZLc}syz%A#31y&KX1XW@p=fu7VK!?2!_;92p z1z#LQ`LmJz>TveJbrqSoi)&_`8OAeK=IXSeS;sW;%_(@+E2*mukV`5d7;2KU)s~r}^?*V3*}U_Wqrg9vudh_OaSpGLI^9 z*}%^1Ya8o69WnD99EW_EQy4D|l>4-a1y~kUR2R=rdU<#p#(0(xvURsaRU4x}(aNKn zgLol;bzBg}F-`Q^G=ZAtGp&R=@gsU|y>(>^rtf?aXAHa0t_O4s`~DNw*<2Z@FYB~F_HpXxHf~06{S^xjQcKlb3oM#hIWyv{z z_UvY6uN~vxEZDdcP$#F%y@unc(#$*ew)u)FWh|Hkc*L&Qwv~w&YRZEa&1trk^?kqBj-b?Z}hrw$0yYKXcm_XfhlG zPRj+Vj)12pd3o5N6*vGRJO3&V>p6`Z{N+Exn4CB}?05eeU>%pnK+gPUH1vKw{|Q7r2kK>I z{tec3wOnE3?~G1ZFU%a}L(R(Gw6yS+Y|)xWtBrZ&x3SBJ$cFkocibiW``7Vip_*_H zQdaeEqr%e3uKr~kL}mNj7WeQ*on@D;rWC(kob?aMWNfz|Z^`-1+g$`$|pE)?F%Lhu{F{dyF(^R3{%W`x2<;y=D&# z{n!qB4g`7M?2X0=kIqYyn$9RkhUc73xPI&lrV>{g7_lm0TJ8?4iSIqn- zsf87)!|%7<2nxo&N>f=dG6^b~rPg<({$1|Bca+~}C9#{R>x~4}1WnS038x#r`{x|ckG?e{s z=KY`3HGN4Fe)jBR*r+BT7_=|7-g8c9`+<(>OUK|+*8r$?4qgoXAdxB`CGvw~@u=~V z&Ig94ePlR*3W4HhpG%X!?fbx)3!iWXC}pnxEr9&-=p6oVbUxHXJ6|?ryf0_=H2Zi) z-W7%dj?oi^wGRTR{81p^mrA4e4y8nW5E0ZTA_CN0Ly{QhTRxm^^N(j+Qb7&4cK^5A zLMzU)e=3ju;Jzp>&e}J%mAUz>$EUaJ-SGi{=V#U~sWa!Uzd853PWIlMhg}|^w7jo} z6HI(OQ4=Z{h{Id!D4DAHN{z)>{D$EVTi&nNx-Zd+Zs#JSdNAO8P_DGJ9M zLQuU`;+3Tiy78%xjI1S)M-{`6zK$bn7J&^2MAl{5k z(e7U~8|c)^`f)};N!F$^Vr9WotR?*+APymhiAOg>l*KWI(BiRrc8!t=p`_4e=cJj> zshwHltQf<+c0`ij+g63)gj%mGE$ZTlqZ8h@W>4wkRfD%v46e^@ArI^`5Pm&hNbnO;Ix5C0yu{7h-_qE48fT=tF{MM^t_ z`y%I7+Als+Ke^RaY-s^$QxCMBK>BlBVj;OdeseL`Vet-CSUPL=)e-XB>lt7E5H;4o z;An=|J7V?4e#DRqN+IEMCtNZ)SKS=uLU6*Eo|87o&3oH9`_<3iuPg?&9R0@!7F+)WmdK{pQp?cjp}PC>}~r2FJ1@XMCLt6OQuO79GRGRh2sr7C0bf zRr;F*4JGqm>-T?yKQZy;d&yj~1fF49^)L$YF@1*hzGXEDl_O#I5|hr%tP5ElS2v%X zT<(jyYMP16z15V}&vsek-|TK>%9x7AoQ=dCT|tedapN;tT9!m8{N?ynB2>nn>aK?Dm(j2Hl-Iv%+g# z#|w!pfsJ$awWolu4(N(H4S6dx7P%)YQ1wgzJ`Q8w4v*-Y|FU-zo8%5Vwaj;X5N$Ex zD&t+bz}Acl$$oHqo>Lsm_T{;5C;4{e_-eG*L~F;_5nz$eN-|JLZ&OWVd4{m3ZR=Co zFxuGN6m4e04EI5B4#}xj`pO;wM=wR4&~6~K*OUj}DmwWdVk|q9sE2J{eEayLLLG3! z={DLow{B_mHxG0A<+9y)1$6gr+a;MfTu+C>*a5SPNWn0AA_dd;cE(_@6w#RMf-txe zE7%Nvl2abzk`g)bic+)$KQM4{uU>Ds0ZPVv*HCsi$CoU4xU&~lYyD8U*k;^hh}jfb z@Svfa($Ah($U2iZOo4BhS+&PHQl;lO0m!8Vl4_XSe*h5xi4mceCF{Ub=deaioO4FP zQ1~WodVaVq*PG*mM?=IdN_{Pt6~m94a5vJr30NQ~zp^nZR4SXSWhR_cx6k7?858jN z7ZiT`Iv}>Z{L)v668-ctOSNQ#ZdH_i^n>-W$i_fo6Syo0y9mum^fQMKR@2Y}?Lvpn z8sG6#)N)RALI!9q_-0>6zxRwscXEX>D*=}9ih_B?3b9JwyG`axH?8m@vc(>b9icyL ziBuX)t>OD!C?)&2)WS=@v}(xzij&cAF4TW&#?0EKW)Cx~SlH$F-aHAzy!>z+G^YH) zL?dE-@vXm(n@rt<@$NxvOVDc4s`@<_<(T~i3QEQ=GcbJxNux6fwqPH%E3yfLqX}2M zrkD)DUQX1KWdvp=?41o9?e=W%Yk%W`wFOH3KiXt;7AO8SD3z$Y4@9_k_Aoezy<+MPM8=F&KECO-B4dLCZg`9&VzydsA*ge-wjQLc_}|g`7-UDA@Q?%cpsgV z1U&ymnq2r~Ka)U)%42M~8?rF*M<1`lPF2}{Qr&Ix6}6cYeRaH#m(!`E1Sl{sRm4p5 z&V9=5gay)f`qk;JUeNfOYnR6Z_Bb*0_URHI!iwJ%qVpyo%Sd<1CxV)J0FUKwtXTN+% zIoGT@q_v3kGQ8C>EC{uG`-v~ljzdJW!d|i4crJADTYPUc2_o>ZMAN*|!2OKs;9Qxd zYFh+?$zmrSgYP05^X=OO{oH~XZF?%V+s=D&Mp;^VbpE|S9u-66W*fqeG*29V4;*WCY}z3(;7Oj3 zsH0H_ejiO%nL86ZA5$`t2t7L41y-|q7}luTtvE-Fdmb;ieLgTSLcl)J{TQV$$afB# z?gY|3{Q-+H{ewZjpYynAR-K&pglr)LCLF#*!gR4hNEu(Ae#kia1fnx=@%+wyD_5NT z?jv`TTMdZaa|VK{l>P?y+>|oibYL(Vdq6%PVJHv}-@?6vBb7IKUS#YRPaW+2@_-~* z4`6D7+W{EkFf1Q>tjs>$E&K+~C}q^nsBYt2J$&hw(dA^)@;qlKXnAt_vNzU&SXwRb z1l^${yUYx_-Cb?$J{NlO&Ex`YB2NJ|l(BEhwU?AP?(0s!jG%h&rL=7>4V4R=qRzxh zRL3#^ukM4tYKGHqT~%W)2%N8;nydDEhqT7g)gwL+5qQ{q=2M5@@a21J)n7->2w%L?)@g3tdV#hcb(Qxvoi+BF?0c?2bXYUf z+vdXZyx>LAxB`3ng@!wilfrLZ8(j<9Oz`?q55x?IBb1Tge5k8*UBJGXUG!Kq@Alf5 z$$RKu^)IWr#CVL2RY1tL$#;zY6CIVKyhuw^8?wd-ct3(pLfVk;(>yRqI9Li5Z3D#i!B>Njxa9^F&J$Sa~S2Z z_4P6k_x_CY*JT1cJMKe%a->)CUK8&lki6B}Q0q1C{QEN3IDaz{3IkbtnOFTR@rqX1 z0AK26*vZAo8jZz+T~o7rpZraqK%kErx;p1T_`SaJP`{e5fyB)pnmX|HR!2d)!#jxj zpZv(&Iy-M_YwTUSqb<VZOaq^OB13^=jpS0G{snabYl$G%A4yurskCQ###U?co%c_6Jc`~EhQ^@aKf`1Qv zcotZpFGn4$p{d+{_#pLmxBi``zY#eOl#wyeb_0-9r%29A6_lriSPaN%*~zWfl0HB7 z|4U(&|D&|}|JX*K3(o$3FckLR-yZ&#B7FbkKL$wtia2j-+4Mk${N`_LBL(VD z)SjuzG^X0RT4tYz_UTPR`*qrKed!x(_B@lfBU1dmx+2?|$!`Qr)Dmh|E$_!v4 zHql}M6B?MWl;*I;ot6ULVhtZ_>k=zlNXt-=aE#^=Sr(_;UprA7rW$$V%+;utx%I3zZ;eOf2GVGso%h&- z5~2#cAUfu^$JVwQIZ6{0JH-8;e_lP|Rb>CLcEmy&J<#H?_%YV^{w*t#h`%rkc(NM~ zys!!66vnl~Ro$-c?QS}QeKgLoxZ0TBe7_JXr_r@kjJ@g76A);sKfYJ8{bF)rPeu7J zt+-4eWPZ||heyU32^Qk|(_wcMJd)72iqb&>l(IqUIPP<@(0kMhJrAwlpJnDEw=g%S zygaeJ&a6oZA}(iVziEeGIv>`Zjh#9;rB0al0DSm(6A{9wrG9UKj1riz{yVJ}&5VY` z7fYPE)kY1>YSbP{Saj(2^<9pP-TnSoovQVgjw@Lk?}8fJ<#x`VD$T#uSkOUZu@@X~ zQKqhn{f-knb3?}iU8_ibZ#3s=W&yLn;Rlx=P(x>d=6w5E1@ zVZhEP=2sdAyJ3B6v$-qVd@vf{EbbN@CL!s)>0SO>%yx?}Ee4}k>9ef^UdU*z{778o zR0iJ4E7r-ac|UaAUbOgTN|g^imX!{`*`HtLd;MEf_)|%_0p$LZx>o%ttfiXr&|@v@ z#P)L5k6v3@*RbwxCU- zY6qilCisEO(5T-_trRFvuQp~e6Ws`_Pk-}JEhF>JMHsh;tLOz2o~xrVynIoY4tu;4 zc-cnw158wie!lt}d~-oZ_p8k`&AW4j$)?-@P?&nY6>>cc(O8MIM3bJn!cbnsN3G9tEeVN@}qe08`n0Ura zj|IDSPoWm*3&+(Gfz0F^)xq7yv1)&X{Xb=J$;eL!i)+)@j0rnPbOgB{AAg2ue2_%A zfnWT?Z%n;Vu_nl0%h*DF)&Zk!#kHq1bTQ_z@1yQMw9#BmuTwUFAg??Q6djYtGLq zbDVqSQ>Yz~OiI1%EccY2D!jGALkr+A(=;Xj2LgUv)<4!)RAkI=%V1;B>5=$MLyL#Q z_~4kz7?d1=kOVKr{Zk92hAWjWok883DSSgh>SFpdoEoyJ=Kewj$Y6AU>ysIc_FfiS z;aSs}L70i%p;-Ge7u{yt^_Gl@ti2#0l9|0nq6a$@fdqlwUkQRw?O*S;1mBfxzKwdS z0dDz!vG?X-O{M9+Xm?k)mZd^jq9|jPpok0+lrccs5t)L3GLy&{5d>rogruubC>e_> z$PiMB5RoCwV}Mo!gaA4@Z^4QQ=bE9b&Uw0%J1Yuiqt>HS=jwIy?0TsptEvzq z(BV?Dhi81G{h2K9zMqxV?fN3@N~pC)*GG2C;lw4124wcEfIs^-pJU*C&Eh_=$m5|> zgiZ73gedU(VAWg3#Fin`HyUO&S3`4uzC7{vLtDb-h~@2K3LYp}X5{vCEjF>sYmWWU zWh^Xq^oZ}F^H2$^ zvNI9z{W=#5s^vHM10%vOGqrf&xBlP~0We08bF#6jDr_owbHZ#QIKN`( z_6c>2VIY@+FilkEwGi~{#@~4|y>Flo2 z0|isDh~~vaf0r-*n0OPGi2;Dox}QA?9Kw+Gsd#{LVrYJ@-|bx3c!7h4=QKQ7wTp<# zg{yrWA>c2nGiNv3QFZ*Y-4_{Qwbhnflb*zZ7q88)UiC`(k3;|eX)7faK_?e!apBDf zhE+3Qu;^}#x>vqIcUlLW8DB&#nT8*t7vN95Z2m%zbJ1zo4_E7@l4%G+(2n#ROqr=- z98sKbS<00D!P;8sw$w$xera@|1-iK^6n8E>Q4+k>TwP#v?dWtK*<;7Vf<`oBIB6+5xnD%NP&Xfsk0idO z5^t}T8r8XY+PGxO)OD-EGpKA@Hxe`9Usi ztRHJQQ3J~|%~vl1Z(uG6wd{I_EE=HE_RfEHrRZg;%&vWnGj zIW>X4J{n=^&rMH02S;>#>SiFr?*KgbJFv#k%5c!^;?8!m{KDg6J3nuMWu8THS7zsR z&IL6^_1g*W^5MF{u8K*y5-nilLda$k-SGO{Dq-Y>eQFhr2)*f!0 zUt*NKX;C@`ox2YTOGg^wV1--ZhHxusG(L0oORQz^?qLF!d@%FYgpE4Df7UI&zZj(x znG`zp0{h3#G{|D=8Lo?9S7G3Lq8+~7&&mxI|%WTaqM75)DxfUYk zMTW&gCo^w9&MTdnY~jb?ocgTobe%Wsu@r^}pA@Z=$8*VUySptcDVrdx@we@09rvnX z(;s20#xSTlF$e2)XATUjGKx0ufQT*q%kg|5uh9y@9VGpdxr)*O5+y;>GO z+*uUV=&cfh9IsF7R)dxgN3A4dmjyGOl^ae~u?AIQ{yqJWwa6-J)6;LqxM=+XSgP{G zfjkS$!lW$Q6aa_9ua{&jMCwP~3!7{5B8xpD%Z(VcdO!)xvT^+q9n}AmY6d>{-1~6D z(%Bd3X@!paR2QNz6hYI0qMg7w=_4_m)s}T?e&8#^GL)7%t*rEyFnGLgQu}+dTma^DccN4b% ztZei>Ez;-~KO+SKM^^a3ABMy-=#{I+u*uzb90+&LGwVTo$J3*5|4Br3O0u!H3ss<{ z@l(R=gUyZWRWOS3I;P6ju`CWBJ$n3^u<=U#bqZtvA4vX#HgoNM8G<540>=EERKKE_G z1}X#6YAZ}y$9meqRr0`(wggrr9{9#L{D1pc{x2TgKfF;t2MPRBSM?c$=vVF1f1Hv3 zdgXiq3AO*fp$GokIO=~d*5iNnvj7tNuVknH^trWs^(&`Upq=~g`l8w!-JcjkKmI$( z`(I1()W3Gv|C7Ap|7?eS4l(~fdJ$^7?alP7|IB{K&`Z^sZfg>rQzwAl6~T2T&rEsk zZ$A@Qe&#~G!oW&kqt)uVoP?<~TUk-ZZ>H}pE80j-^dYgbU^3qs9kRWJ!wQWRm$PIv;NI~Zs-vI{M{H>!*staw8r-<1b{GT*qgaw3Aj^8%Nnasc2&-!kXBqIU9 z1{Xrq`OChVVK9R<^u9+yEMZpA&Qw-qP$gR6lYu!ieSnFXLivid=D4lphu$?zQIIfpIEWRlt@db>;?VK>d!_!lYhIdM{O%Mh znd-@1#-Lgr>_DNvZKMKyUxEc7_#x26d&Rp8Fcu#L3Ey@GHLEHz4n{Jj=K3Kmb2Z7to;?TwNliNm=q9fcs)lmH zk?bEyiUTnPq-B@woLZ0zaoqfgr~7x&SCp~YGA2~=ghR(;V@54tqzprcoGzOtnK(~- zQDy?N03q+=8o!wl!eRU$xf=@kTTQDEy)y!0Ct(N4it3E^RA_me%a~6b#p*~;#&JWY zNu!K-y+uVP5T7YYZ;`8jw}w%Ufq&cPwHE=8Y@2nVpk8Nvt|(5+yDdbkOt~;%%F^OV zOJhfoI@ZL^zi9=kjpy z$N*;Y!F+%aw=oy0M(Z~2G^B6jI8I_?is?-XDfN>u5Q^jLVzV?~6mtcc(OMr-I`oOw z9zm<^V=fv;g3u-_dry>^iO4N^QbFIauA;%2Q(*1?6y_*Cdo2Lx*7H@~+MEU(j_x1%oFII;9BOnuw-}+zKl5Z|B$^rLq z67@HyQ~Gt=&hTb|(V#LQ*s1r7QBSQuDYBF!0kJTr1njrK@Yp&~@(RJnZfWCG3?H>K zU@P9QY%ZVHM8SyWI%eRY=ke_Ufd3ajtXNuuphxus2%p_W-X+{um-P$W2s4R6&5Pr@ z(I!2+J3^{;0xnb*`~yrschyL4+RSmGgH*Z4Ak+??xX$srdWh|MuA(7BtP@qGREU=#QCub5f(Y5WLgQ#)ExIM#;eM=>s@eH?ZSbb|rOJ=!m z`cSJiV0ib8l%RW2WrPfYIjwyHC_fg%Ok`uEaJk^ZruPH&{DCcNWr%|-^Qsj6RjHkZjQWMSnRS+OXz92m}X9mlP)ZFBdkK)SI$tIS)1#aD+RVxHo2J3Efprc zbkp;v2xc~BovUDH(kVX-cP7r%joW-7>-{QmKQS(gbOmY>&zXonn0PdsGr5lik-_j%bq+ZXEj-15`0-Lg@ThF0s|b+}iAQjLX9CpM>Flzf>r@kL{0auvU(HMc`) z;>0O!dQQ=36AiF%|J>#+0jSu!dMmDd5eYzfl*|MNp98!0zD7h6f^q@y!yu~6B<3t1 zo~@GVrV;lNQ|_`FS%G_2uHXNDElepl{MIq5z2<2y8o*u5C{vhub4ShasKXR`V$Zfe z&slqGvSo1;m>Y=3CL%bCSHNfX&js$0^Z9l6jt?e65a610k$Imb=rV$I2S2p^4X*Af(*anB3w+M7ur4OzbeR`9 zY_9glWOl|Wq}I4?ug}D-*Gzk*^)Qt=(EYN~Sjyjm-9Qy{VP~S@<&U^y)i*d9^_-WE5Vcf1M!{d5Uc4tq z>KUD{F^ZXv^+s!v+zQNVBPHw6Tas=TWy1WiZMn1E*A?D78co}3vsqb``d5N^?!1V$ zX8L6*EgdNw6Kq1x-=I-LbCmay4MlzJ_9*)zZ_hAcQmUIkJqaC{$=Y>xgu>=rm|Xh) z*sz5`TgMy4gwAMPy02Civ^~aHPX1iHZm>RSD`3YlBAvz%jTFXR^Ac-YRZ-)AXEgV+ z2+F6eE=sf)x7&llmvuzPR%TK;@)4VU9Jzs1aZ`w~T;SAWyXWfnt8r=kTA{}W29%L3 zUlWTx(6rI`+PPZ=FcN*S zd`KG-;C%#Men z8J>5iJBFMVn5DGX)xYaA(i*H_8m_D|#kyta+%t0^UH7iaQp~bb zWhFdAZR~j4wb=*44m0CZTzy+4%(>e4-X0vLU&~rdRrJ+Q57zIjexboVRfF1sw>iSQ zsl0%w-42$$U2nGqJo_o7UYdSi|7D#Vy;5SHyb9&C$(fknE&Ovu7Dp>pR5R0E(cV5w zmt~9s5N%Bs5>o%*&Gg(}R1lGnA8*i)+AVJsy)*mFJjf;2 zxx|j|$Lmc~>o5&H6uxsSqV_n?4%|yPdv64iz`uMuQ#T9uHkSJ3vE2b{z1sE0WNuoq zyXozw8b8L37}MboAetKZIxh=M%uTtY3N^buh1|YeRa3U|WA-Z)fUT)P8)_e1y(Fe> zs<8|DBjhB)8;^s(Q3DG&oMp}BjdM)**GFz`N`cYwsY&Ow^=I!?9wnZ@08kDI+R|4X zW7XTOFm@^5$4fLi>JF~@aBuI*%Iyvc+-HJ!#!v6zSZ^ECaO_yQfy9yCog7eJRL}Xd zf0gvN^y@n_(uz{ZBPWNNaOInZal94c?uS;PZOqP%V%KRaMsS-_lVQ1jZjrCC=15WU zX0fBh@a*$+Vcn0aVY>Y0Ik@vhEeYyrj(blL&qhEQb^Un1&5yOoS0SmK_3J4oEbOFGhZ&QGn9iv2t)^Sz z@80lxLkbqFN{K6gB}#BkQd=sS!b{_y?WGqhjr1x}1_g>RASUN?%9wwj64D0`Wf>NN z8}(AARju7Fj;7g7^yo$1BM39^uY zO`CMV5QDY?k5ZFX8|5G-W>tmv`TfD;??T8a`n?#F2{RWH!t9r^;}W9;$N`H*R)(|7 zK??|27M2sW|E|;Dl_|)N#HMZ)%xdyAv-J0Xyhd0{_8+HtEt68p4)RCS{Q56?_eBjo z@fYHP)LKlsah0Jj_|0?*(%a#?(!aht}WNN*Xe++xjH+OiUW=Ezjg#ypmq7==xnY7Em)Cm1MqgU{cJa1zku>A6- z0y_lJUeSf=X-EJdg4$JuJgCxl@cvymu-IM2VspnJHZc-Es{bcMB{%#o(_)3$E1#rg z3dt;4-B5>?+wUfFdf`X1O%X}?*Uy?!2cBwylg7<)JE{Y{Nvo9_-QCBfd|#S==M8}u zjHpbQd&XsdAm+$`H?8k(?^v(k?u)w`(2`@(Peo3&)@Z=> z&7}O!I{!B0wHltdNp_IMhNQg;gLh^A#f-z0b6WD}g!x(WVNeA>_@<0ktky8q{y3!w z)#{hCP-mzB%?Fu82LKiyTpE|9*6QSHarYxq4^+6dEZDlNFM2QilyqZvhyR``O7`hv zUG$N^Ctik2TA0R<#9uNw5I=5G)0^amkcGvLtanBkT9jPidRlX*PjJV5coS=41&5_1 z*A9!T&y4}4PKo5Nq*lM)AQxA>N|rYQo6ii~VXmyD6wWfMspZH1(jQ9TjgKydUW`t9 zj}yl#S;j#RI9O0q%C*2PaS_YIsV8L2kyZ)4109Wak8hJxlw;)``61K#@>XadZHx}M z_ZSR2+U~33M6Es5 z0p9BMPA>>95lhdSzJA{sD*k2|7oX*K=@2}>dHvb0Z-RVq!*QZYs_T>uZ25UB%2@q0 z=v9{l&xm4df-=U==Bm}<7UwcRb69UZ-A?G6TGTcyhA`7M`}XA?#0ie-UOrn8o?|7* z%>-YiDoMTM0jw{Wi?oC^`T61x^H)?O?Cn#UW%95$GhJt5?|%stNUCB&685VanjKcK(H+m$apRA-#k4H&xIZh>*0u9kkChsLqR$ zwl=wjc-81vIRxBLh70X`hXAkQB-EBPCh7c+!G&uHjI85IAX)*Xi`h5G%JSCp5$~hj zl;yjgvzRRwnD+@ssU$r>s680-pFywV;nkVoDOs_0JK%7czOvnVbRv-l9`A)N97awZ-nRqCISD;QGMhRO0 zx*%uL0V^9Gz&68LtaleI))^hI7Qnw^4iFz@*=6xT3uYEM1dLb&jBfqpREI~NzMmeYM9kzc~Nez3Xa zCSZzBs*wU0*LYKdy=DIal16LP6l;XlQRP}Xl!iMu#7KFTP zi!EmY9sszH5xcW0^ECyvR~7g|IcO7 z0s55C$=+fsvNNocza!60D|nqR&A zTl5;;&3q*MQ}<$Li39YOrcl#35x}}h;mwU7gyYh{d@D`*r|f~bu)M;vz`bo=^S`5( z;QuV}_FvG_o(b2lw#g>~!T%k6b1&5Oe;2U(wdGK~xm_mUG`r)IXif8!OZpYXG8HxnnCs8foA_+-6#xi4 z1AZ|Au+0%|R%LKYE0;q`vAAjz2DeIKz)F-Gp7SVZ)kk|G8$BG9_oIK5H9??! zydr*L(cg`fvmaxv`$sLSGZ(X~=)GaH2*x(XA&aR#G z18ftj>BAG@UIRhJps)Zp7xG9N0JqCFr~zkm{WG1QMzSqJGb7uubOz--`mio&LC`-} zFbW9V%&iR~!cUhyhX78o3unW;+JL{7^_4@aoZiQ^Q`QUHLm-(zx-Z~>eC9%?p<;f& zwc-eV#p{$k%SPg?mgNop9QsWC1QAYx@2mt-o=otCkMjZeY#&(;s30kt? zXE1QJ^Q0-i2-63B`N~Mg3Y<=-t!%V?6EV`!TOw&%vH$$&Obyd3MjW^YutFt7MZQ#$ zzh(65qeOQ;mm`txOLllY(_IR|Bj~*29XS?R)G;8To7>}w(@em=z*(oZD?&jP_l?@$ zlru_aK2i^R%GzQLRTAt<%P|}7bBzwrBJkSapbDm-5F9bcKpB@!PexA9_z3*)nuSG_ za}?1Y_)CR9%9ic2zfj#bhzDb|NV*%eS!!#6Z!aIzbvnS!`Kx$IOQ)qwV)q^KNC$^v zawxur?>qW^9U@e??H31oUlG)l2ojk1>pUP(*B4y*CeGnGPnwBQb`0CtFp zO$5KJ@H@;B?DPY=vUyP&KR*(#H1?z+22w_f&tTZ2eTIrvaBlNnSr#fMX&j~Z7?be=fR##PqNklrsK^9*o{mD12V=gZEVvBf0 z+IEMtp2m>-3DbmIlsfFF~@4vI9on-MNTYwG$QOZAH9#_$JdZndLag z9H^Z`sD`D7F&DjzEwlX$>B;R8x!4Zfa>yy(&CeB^3xMr=u&+iLi1=_%d-~e6v&1nS zv`V0Ymh=+2ZS5`J*w@IP_DuOhNzv$$u=^U5&45s?^w@V+;F1JD_G7Pkdx7~jtI~DZ z%gw-f*8|VK<9Lvqy?UsC)+LmL2NwIn5`42AI?6+t{UySD9%2Atapoaen#F7bMT9^1 zggEwgX`+4-`*XI(Jav~*_ioe|5~36p83dyP`0f>dAgX)uT2qanSs^8L`AhNneCvod z1m!zSff6{Pnt?OgwQz{XPJM*tNoQ1z8BN0uT66{*?r8XbQ6z`zNaN`$!_FpaP1u^AvQ zA^c{9tSgUf`2{7K^a!HFG?D}Mj$4o-8&wZI=J%2DfiZkNtBFYBZIi&nO^?O?U{|q0>v~g|k(_Z}|0PFb zE-{je*{%G)!<67Km#lBKhpMPXESDGP8$1~)K$+eOsX9-}c$x0O zgx+WV)d26?WYbC{WOJzThecrz40c)B=-bgS0h*M~wtOKPMo>voT$Abx^O25k0~`+` z_F-b+QfHMsGrHBpxuIT6I}2z&?4;p2W{`gKlhwr=>=wgTgF0OBeh#yl6Cfg{z~5rM zn~v5+7Ic6krb#jblA=0JTP&?cP^v))R@q!*eUtU5a_#-#yZ8HhI3o4d4$$kx-i;C% z#bZiQAy0gJYu%p^{YG%gO#B4U&bwT})ESRHaD<1J-Ur0pnGrgwN zr<5nCF?$GArkW6m9^Pb*ZHU?x?5Pa0dh3QMn&d@@od<@(NF832F&3LS0*SN)*WJ94Dh|)O+GrnR zr*@9KX^eF9^UTw(UX_z1fK-mg6@;`U#bGrh1&3${&cUkuu{3?{x7D_(RDRxs%IxPN-f!&TZdU-fu@G)l#Cx($BI4 z3d_st5zt#9jiZ0Gr8nu_PGG_c2Jg9YaLx?RW8e~+{p*=mPdvu&?6=lpYk?zVx)#Vy z$ary?@3_ImewIOaL4v&5QMxn(N*qtAOimh@8xwvc^rjt%m15@<19Syc62&L`c1ST& zb1ovTVZfq_+Riu5crFwgio|!E1>AcU6QpC{Kg)`H!I-3|ruD6{(5E`0Ymw{I3X_-z zf1U)SNKqeuEYb$aY3%kIZ`IzBJ&7zQh$dCB{I`gx+}Ri{@r4CPG(M~S31(($p0B)X zk{fgVzIsCpaQ@AkifKeg`Z>JXn8?R_a&44@K1cEEr62Bp3<}%Fdi#(Tc%7LE^R$NzrJ9U?!g~aIiaBBJD^172Gir0(%@$6xH_Mg7j^zs_&D&;?w6Df< z(A^GL#v#0FzbY)_)sFrO`-jFPwJ^>m1W+*cQ>$C0#) zpo|4#^%u2{_V=0Lfw}D?%Ld0K_-1+>y)+%#^?jxRc7ZE+7)Df@+PGs{t;gItZgm^5Rcg@oXNy#uQ<%SYmg0p z(?uGgqF1Hnx^rqx7Qm@wp5Gh%gcETk#Dgw- z)C7L62Y*FWWm;^7Qp{8}Nj0%HNu=(gcY5BYNqQdLY;wrNWifRZnu>4{Og?1YW(TpH)h(OxzWXH%LfEztOwc;sze*VvB1hm9 zfa%5epo{>WB1#;E))eY-S%1IPoid@Nqq?~0U{8%V1LczPjpzWvb4=Zfw*8`ggi0## zWU6k(XoXMRAOAip72b~0X`jAqhqe`!&aU$y`Q^@^u4NM4VAK%Ai1t~sRhf;sctb#{ zYgI9Y(>#_}fX=;`@e{*e1lm^Iy{3=8r&G2NIPrDGX>yCb*K=?>pu#6FdKN7a!V=J* zHYiQhSMhh;iL!r;L&E8G$a$>7t1#8eX-w`q=%+YY%2w&%S z(~95n)S!x;d;ky1x@b&K^F0dm2U2)xAmy*|VIClw8du#oqr4Ep1~Y6LWlfvCC}Fuc z4kPL(-0@QVZwmEa>Oo%XAXj^$zY{dg2&R_V+a;fh?=iB;PQ)eGu5wd;%<8hO3iz~F z{a?9&PuBnPI@TOjvHI0@JkfH&D{?>idTzLce^fl>TPrX-cOj&YlnuVoo6dNIa?;s7 z9f*8MC`Ohb)=2ThR2$cBuXVjD0St!0>+VrZ)Y1aFk+l z&Oi3rIv#07iSTk>&$TqcEp{5$zX7ItD#B23oa+^*bRpEbpe8 zZBAzoUd>J%a2L89tt7rcT;!)f)gW}0R@zc~>fmLKRzlaoIX&;mt-sH)0h?f(JBL}3 z51I!aNH@c+M^?ruQmJ*MC#1mi%@5mm#2jywT24Wm%04iQ?7tHs%*3m{Z)YZOp3b22 z_AX`%rGB&A=-$i4O^wu#<*+%#`1(MiWaw^-=ftE zIn(cu)zc#CE#C?|C}hXxaLbXG%^iJsv*xn4p*8top&?;VwY&M=y4&d2+# zZnUVmGq!N^{9>L1@B|ZWoZ-8evi_zk2HuZllv}{xw1Nhu*x!f3>`feHjEF9abvHFr z2j;pKx#`TxCwOf&mvF@*!mLaI&!a6v;AoybwwP7neVvLbw&X?!jMM*eq^E%TWb^*ojy;fV)EDZ^A;l+*Eq0~u zPF56!xl~#P!#mj%?-`YDEJ~H|R@C0OQWd^GP4n}$0{$lPms){h+71o;?Lp@a?A*-9 z{qT9PyzQbyx)NL3)cH_9b!v1bqsW)(Mn$FM@cd!dEwI3_<^bTTWqpP}26Qe|i281C zgD)(OT4{vda*wQFtmh8yIF7;F^lEPeUQa!046KhqM$|isna?AaD-v zD54wR=4TC%Y+?`E5rH{XV7@x6WyjBWij||>%I>U7_Rblglyt6nEDN5!ZBqnt^wuu%g$QE-8blZ2lp=lJgvt(o%AiFUo^h9wPMi*W=j3jnF)8-8zUvdo%1nTqfX6V zLnT2(ub2{(Y-t$$BobeS+AxbOZ;lO4pc(ep;=z>Gn{WcvkN2F5Tuq*@iMZ<@(pwmp zE>IZ%E)SpU-?-d!K@{bLuJDS;X^Bzct2fJ}s89mW2kbT7IjgNlxH+^9)CBg`+h~o} z0$Yw@!3h*hPh?^!CxO#6`RnzHiHn(+RBamCuoW1KnH6?&8%)+f4i@csnjdq1!xeJE zIZ&;~x@EXh!ArW)TAAIG7Pb-~O2N-w@Xn=&P{o>0GM5dk9O;0}{#JA#VdBr5lzgY| zy+w0+A!6Z<=$^C0M3wk#*!;BlZ-q@{qxql*=1-o;Ck7L}DwP6*zDK0tr0`$>=L2i~ zmZkv;`Dr#vcagsg4`_BLEGL3?P=56HM6Cjv@=2H9j)J2WtznU(dyae|RCH=_>>7g-m)-65cjxec zE%+faei+nBvX4KK^IsUD@?R%)iB^C##4g7N8} zrR8teL*Q*dpl33O3lewtH?*TXH1e{CkE+N9VpcYy!Ucn@&RR`#+_Dy+NGqQ3x)?nz z*$r_#+z@~Ox%r5=!<9iFZg3+%S-4C5Us2WF-tvBQ)`EI_Sfj3S%QQ6V;XsYUW#_y@>@|$QKWd=j>7Nicmw;YazQnbG0mO#z?`V-6 z`Fx|r#ytsExR^M(Ct`~2-tQ?9^Ao%QG0Ji2;N9*i_=VjR<{1zJ_&x>zdZzZacXyj^ zn}|O&U#eS_o#SGNaYq3QvJi47w*-50&zEnpWZ)cE3Q&bH><*K?CxeYP-6I1cg@K9^ zpmy|Wbxd2891Y@fpu0Un3zGY?Yv`Sm# zua6Hm&PE^G$};U4g1!&e&Tqn6x&Y2slEtT0dw5 zko!mm!&NQ(j7E21w{F)Nq}EBiNtEILtd|0^o@ds^Tj0u`tIEWF!6x$f-fkKDV-AqF zapm*wSGw1HL%4vcJ=6kJjJI?KD9w_b!r*hJRZ;}jOX*8y3F&801(Ob&%^KFybMeF} z?!s_TTktJt?gFbN$v`w71bfSjnZM<+Cjxn0l+Ka4G|bGDFRBG*f|rY%Q3*`A@un;C zDrKnz?k_~G)Pvpmf-)_?w1_|FJ$RA44(>q_K$Nx7-WWYl!~E7!Kc}ZPD6ba} zKbiNBUHW|sv~nnHybN%#TmYmTJ@xBs&W-`YMqQ9F=)RqK-}_`0Fw2WVt`ywU8q9s> zT5{}&U8W(u>4~)BFOOJ_tvcPW7dN8sFg_MaPXjVb-uq?bef3l!UuCyKP9szLEMVeq zAxj04@Qn9n{Uuf)TdWyVjZz+FaNP9E+gMM&^N{&d?dSyW_qCG=O0|O=i>IGrlEB9Q zYsWF8YrYwZIn>Hv%3 z?G9KARV&>bv`b(NQgOJ*MaNqY(z5gyg$M$goP8yHyl&4c>}}C9U-H;3WC;+};s$m; zW7W32Li~4fpsI^wEh-ImnCp z{6aB`HaTG7n-jd~;10LBGh_|7mogr+QNMOT3w5sUqFv?@YvI;<&@Afxhe_9iWG0bG zi$#W<2LIp%gqc&?0znU{iZMq5j!9Ob(I1<2ta_jg_WAbZXREP*vQ;hRC$ns8El|g4 zD_F%vw+2KsAU@Gn?SBH~pmPA28KRJ@xmSX#W2yfky5mi2JX)FJbsWf*k{5n)xFZ~&5FTkOga@tA3 zG;yMui5G*_(ATp8BdMdvow}tuRIy_UkanZkP?WDqjJZe-{uFmK_7t#B`yF$>l^e*V zs;rHdf-G&%pPoH*5|y2e$c0YmSe0;n48ws60P^9c-8~0bqSw@Vf1*j-sDX}g3lzS$ z!%hEGo$q9BUA48SBKyd0OGpDAK(#T4$%NJ+gA)>%Oa;wQ6`(AmKGt`1Ql<`A5FM}` zz%Kf`xwiHL{_MN78+(-V+4HB1Qugk{8^C_>U@n(nR&Ia(x}NSV>DJC3q$V9s<)4Sl zDre#1?r(1?Q!|gyRa4$JwI0Vp-3}2_T@N7!i1C0|BRe_?)at`5YR_l{F+L;^ z+i>`_1|0BTVn|}E1x7J|s1thd=|=MfYrP~zs12-W$#hG~bn>~eSqJB&!;(=I;=6n` z@lWSlyC|2n;1)E_p!fXUB46wr;Bl4T6(Abl3@Q$$v$E}FvEFI3$O@3AE@@=%`kw+r ze5bKT!R}lH6C@O zHn{FzShRj^i;Q~&j(E+F&6;@0AMnuM9gA`V`RK?;`yl~CSNCP<~fn_&pB7;f7Da zes5Dg(|aY>0%x7?Z(NoSKY&PaJw(V*M^(z$*RWWV2TCC>cehV|YCy+6xQ#JTn47=C4z&<6@E_za+zfKi6!3`p&1g|J!F1{?|3uznsB;Illb= z#PJ2-Xx{m%&0*j=kWu>!6Z5}qmcnPg_+CP;cz0!r9Vq8ez~=2fNc;02fB0~!iK}cK z{2=WQ2R6Qadks}1S-p1j3kT_aU0?k93k`pWV{~%PXxCRY+Wvp4e)^as=3e_{qauh{<5jgtN#0_E{h8Lq9Z!4RnE7Qnw!4pptZ|?WJ z{Njs0ocQV~^oPis*6F~1xk`q-y&tc6Sw88&Q;9#^Is4G?!0aVs;4Nms#(m#4$Txo( zcK*ym!$17(>DNojKknb$`?Q|T^YN46A5RUvdh#`3d=+>3MaH)ZLm8hA)bXza{p-~I zYcc$?k3`qjc^IR!Bf_)G==Cr*i?F#68%(k6=r5qX?X{S2=Tv_@W33QZ8bfTi5zB=q z-kxf2-AwRB6mprNZCDX6&+Li9qo77^NaG;S5a~05*O_@md0*={vlIUQkEs%`r+9Pq zh!5b2ndty6c7j%nga$7sW_s><1vAnJNLetLufHPwRHEzQ&HaBkFLfFB=k=e(B$C*! z>3Lx#*KC)iNLNpk{LV5EJt5dZ+a1L z+^;t0YN|m)e8b5}gVe7-SkJ6x1iQz(^F~CKVTf-kc=atmYX0-^VMb_Nk$!8{?S3xReg3 zG3llJ3)T2asg-i^CAG%JwH^JN5XY$LTDbIeQ>7~{@32Yz0Q+;<^PZ~-fyt(pX z!^=1d9&7Pc3w(WK;)EP+Y3vo+OVtw(AjAoq)BnVU^Sa&NG)ZqWIB8l?zo>NYjGjs z_MMp*Pohq&cJh3QU+I$6sO-Umt^* zE_rJV@(b9q2fYXIu6mza-%UGthP4ME_f4so7YCEQ*UL5Dgay3Eet84>W!RR26l4o; z-7%Fca1WVtAHAPoA5CK_92X8yHe**)6BPLkD%U0i?yRkg%Zl=kI$nNx-ogLgM10}- zDYRo9UAXYxU+n#~NJCxR7WLQl$sN%>ux0M+&S|~%<{_#iX8Wl)q6P0WasB|W_x||e z@i$Sex0X8)!>3-0V@=)FqITyK>)mSbaE1TT-j|0peXW1e-cl75Y-Q0ZL~Sc7n~Lm9 zDu_Fq2#72J6cGiYVAw*EiUusGw4!W*L|oVcggrnYsUV^tL}d#Ek^({?3n2+vNJuiF z_uiTQ?$CRmXP)`Z+}}L&Z@%Yy-gC~ozn}MfbLVXpUnrZ5@%~hRxRM-XW4oT9-SfVb zHro`Pcwj?7*HYaTKhshZ^rHcg)20!7*Y0cepTAR>_u0Yf^+gr1B$c4=iJ?Z+6T6_j z(Wq#@S}rT~lNUvP$Ski>KDYA>hK*zi)W=0OqG-eiYeLs#c2v&5zH?Rsh8~&WJCN=6 zZlu;Y&!x1~r-1IR`d$pMssylLC99dkWp}$OuWI~CQU=*ZV|rou?5Jv!KuKGE!Vnp=MHVgiS%UnbWii`s(KZ-IbozjBumU@78kk7$ zR$sKRPk+$966*c_f#|q!S!$Bpbi#YdDTRM?K>$;PE=CM^^cxQ*4JCnE-nCG!)sKTp zLX#JFvs1hm$f7vB4bCb9=D)yVO58f!YgZo5_W>b{`d77RVbK(U72MJ$B4BO499p{P zSvr=*v;AOL9|4nDi99B;u^@$Ksbm1agiNdi)jRe{LZr_r7{p4t+Q< zG2-jlxm|XzZ=JNjwXf@9^&KoUKt0ut%ApRy5oD)q3nGg~)3END(Zc}4Wkr1X3y#&% z?j;Gu0FcGkYb>gH>QA2Lrp^j>C4=Sp0;UssAcB#_FeZ`QdA6}Lod7I^QkBYVzf2Q% z`f;4h$e7pw&CB$x89QLPY&rCUzPkOV+O-^NO0-7wjY;gjkBz&I!+hLtW;WrCLUDm_ zr`9QWDH{42x}1j8I?0xF4envVoK6TSMk8L}I_=RpL$@kERZ4jj15)@b^p&i)FdjQh z9a=uEsGtOVxv2|Lu^F3B(+M!bj3^aR_4|u-dLx6uDcq|2{UrT%y=vvT>h6>`2f4nK zR*QVuHSYFM)(zfp7#)0UfO?>0W8ni$6Ap229(4qg2Wc~X+(*3Yg6m0GNNzzslvi3WLP%8QaO(_HMu40qvUWW*#BcdYnj7(f~FjCg1!aUxeGpTwX_ zmzIE8^61B=-$wR@nBx)NXjc+3zBG`Q0wCzc9QHG$<Zwj@A>@$TNF z{$XsXN5idHIxjCNhv7N>f^(oegU}`I14VC^DZXQ;SS0wk^Ol3F1m@yr^D5b7UVQW+ zOB36aU+mtWgh7~-;Dgsxd3Q0m~c>J8c2pMa6@z zQZL%k%`>=MCbA_C3@^MnBOyp6?Z__5Q|_r*%8HXciROs0cpSmA{U|mF3?M%Pn+*1o zY|^Xa$)>SIeQV@ZjOZXwl=%Q36bbDYFeB{iv7)XPCe$evSXef`1>q&LiaXzP>Rg48E%2R1Qf&LW-XeJR$~WGa~(n6*wv8^%q-mCW2pnB_!Kzwb3AK7jk~K<3yBX zgzZDY-}~c;N$)(aeO^~a?vLuv^{0lDF?XVYr*uay%eklQqg&)CzKK+5(%h~aH2S{q zwj2-44CD!nuyo>t1-B`L?oSKDl!;ICl2ShEsz)Si4K-l|SY3aa^wsE6wm<_C45OLf zFxyj=OWi~`g-S9{L0ieqwBD##oJ*}K=WcD1JAOMj53$mkONyqQqkfX?{3drvBoj52 ze@HHw9a_2dxjOYLAZ#+Rr07rQ5muC64k7;kXxY;2D6oq zBly3wacqe^lIcCHJcw#e3KqH8tZ}dAZzdRbWQl@NeGuoVI?)$vN z(o843AeHURYq~Kist-GT?z=Kg*Di;Oni8`^=eRfx;PFsKc5Lz%8^^oV<1G!k3%&?` zpyx!|EaSQmcPOI>7ufv<-xDz8ppjh^DRjt@#(R7}Aeu|})zJtgDpeQGMm|oYh##KyjDxsxxIU2$gSuS zdQr+o6emA`K@%)~9GPSerH7VEV#c7pJLpqe@g{}2u#*1CtI0QFM1dSZ1ssHn;L)rC zV;GhQw2{nLDJne!cltgnGL#-~Udd>@F1#FvYEI=hU9twQ*lqiG^PQxc3F5x8!@Omj zU^?J(N4IbFvEo8SdsBvGb}jI=qV71nJd-zdTrx9jZb<-+qn?!RuQ?2Cv&Y|#WE)pJ z*DytvhxssZjoF;s^^h?&Y^$5QP$9~AF5PA~6mN}qNwA^UoksxK?+h0w61M+h3#xUi zn&Dh3nK`%@@OiuaCPD%eIsx_(*Krp}mu{5fempl;>5_5=3tQ&9Hjj)8;2!|Nyp+3J zG#Xy?weFxln7bq5NTbD7$2s@4sTXU%a*_z~lhd}qJl#5JPIfID={$5yB3GRoKB>gj z#x9T0=w9)2!nfn&ku<@|PWFO>DtP9($~WF#uv_Z82*2RHUN+;!g_lQRIExv?rt6CD zDrFJGOE;Y^AXg89(!0$F%CVUUA$4j8I7WO9WXXfT)L(Zbn~HwA+S2~==%>PLGSy`>f}fjM5yj(e-T<-12FTgz+l}iXSIw0}zLYk>?m@Dt@dcgfoHj;p z;Y!dDiS`r3DVzMuU{bKTcbUs9$|c7B=2y&+GwUI0YA(A5Pj1#`lIe4}H`r7cXje~d zJv9;*45SywL7xp1!(1!gpKbQ6ltLW23V_`0hE)vx3(vO!C`1xEpEu_W-A5BqLM zIaA{~pYF35#|M>x;P^Zb{~z~`FrGh+sCP4>PraB>3dFTp8h#%Xr}c8B8Yf;jx>kJ} z@*OS7{P~3dzhqzg1UhvCG)$Z+tYKez$)$*^b>x-fh5b#$r+alhv#ZB$&iA@!b|nye>pt=mwJrB+#zpN$gGUtKXFD03F@eVp_R`Cu9&lhsHu zV#Zn0=#J=l+jFR7EzfSz{(jH`S@(&|3D94HF-ZXzhSYIRG2~w}!alxY9OEh~f)=24 z*I*m%^Bq~f~pFHZLvCsm?|)DZymzv~jFrtfhs zanlICH~cY|rQGN~D*huE&`Gk!cht#WSRq<1ocFF}w-4?b{7h{l($naOLm9%LNerhO zgAeNIpSpnRc(Zh4%fgcGchU@9Bb@_!nlWw%pBRlN;*#E{;9-K1g_#wGhWn827Hw&U zv)jSB(SZX=XWyA>lrpKi+Sh0EKYQ;*@opClzjnTUPXBbUS5%RsNekE@fTSr#>$=Tq zCg&FHelz|Do`@=L#a5*$wySN-XZ3E`u%OAE~eZ}Z+yquhngmdEN+Uk3YiUcqEh;KJQ za%_kD;6WQFtU82zX!WIq#CMo*UQ?+%SEcw6b@C+iM)q%duODlu2a9 zmbgpwiY!+!f?Z29?^=lw3TmU>bDG&q=DO<*(WF3NQ z{Znzz=X)Lf#^0eoYq*XSG+uVhxs(0>7)_O3)&I=a~wsWL!G|uiY`(8%cq+Q52Hl1II&KgXncp0@QI~6(Tuv z9j4z=Mge z-gcXh%grKZUPgBrXV-Z|Eg-A-TN`hk7)SI5%sJYYk#YShQTYqBL@2_95ffDD)Ab&K z(d0T;PyvQK%$cR=30g<@NlaH`WH(YwrACJ^uDrrHeir1Ra;X8WbSpnCA963Vy`u)_ z(V$LFWprbX%<%FSoC;09g$5OnrG<Obo8>Kh0%N2;kko&pQVfQC&oNGYTgvrs&q0KitSh3C+!7>?AwbmICmdXpg8YlESj8(*xf>0%N37Y6zCVImxqC5BYkhF z7ngK>&LVR<&fQqJ?Ey%ei0G@+5CMRy@=~;>x+AhafrvvpT0m_Qjx3|Avc4u0B0EvY z&&Tk6PUi#Z#uzSgUU22J8Ns&;D_fmT%hhFtGn}ynr@O;L53H%!yJj$btLbPP zoAvexNz=YJH%CfIC%h?sKkRqYZS0}8J=%4~=XuoLrfaQ^8%Bbc{aU-#$HYzrI^9?} z^dz+HEQc_V1>^R}4sKAc4=+ z4PQuK$I7f{@`bD(k)RURI*op(;EQ=53CIkah+Vo@Es7pT;yA*XG1veOQUQ2s3rvCR3&DFab4@L~3 ziS&s%c)uTm$8*X98fG#=c?znzv#c_=f&z+SLCXboN z5$Y{CC8|Ux~@|jg`3AYn}SLA;RN3-EZu$zj%9MYR3hMR?y*6a*30lHy!k% zRAB~ZbRUT9{-O(-;B-IO__dvNPsBP`R{M(Bp~Y|wDM{w{3GRGuYTN9V_%IpX`Aq;) z5QooIp;q9WH4=Mtia>|CxTz`0u$w0IqlZPcSK^MnYuTOl-AS#8HN2S--2rKr;vH>x z1+jE^{7swV)L3G9%Iv^NJYlzrMCzZD5XetbM%w@j3xniT3iX78cjk8|`J1fQg4n=l zX9Hqra5>;^uu~qCJDZapll|RW&1-9|XBES%PG5`cDp0rf39TZ6pOW*|h?-Vsd&mm? z&nJ}5XL35j+_XB|#WE10eq2M0*2l_zW1vTZan^uG$FF}ABWkm11Ex>J3J-|}xXMJ& z!w#y-e9DAOin=u6Hw{zFF0EVL`+`ykOrhC3j)0V0kkB2Gy;k1svTxA8ulA0eANan> zV9Qca^9|@XB2bR~li9`5!%?t?8{;a5KLp)DR$rKT>m7eKsJ#9w8exza3|$^5b=B4mRf>Eg>{M(@ z7XszDkq(TK6w!5plQ$k>q;>ODwY*Q<&Y_)KtA4w>*wtxqri1eW&Pj@K!3M~Qhu_g1 z{5Hg!B|q^lSVJ7h6MuyViix^DFF%A*H*u`=B-C{w3z`^C%3q&k*C1Sv;BVxN3V6XHYt%}Fa%F2N{_-aC`ExClfFTYo5gS6#LjYZlIrH9whM+`Q%siU1~{n0Bg1{j65 zUSl97&~K7OcDom@Ie zvz}?Ct%gh)Rr?cdH(A?Hp0voyT^AaQjU;$CZcMial83SUB1~sYi($Chu*0)(Y|472 zS8er>bOvcRFMXqw2r&OLH)CY+~;mF{yXYL5-> zYUAdxymlxjVoAE}Af>dK12)uy7KaR1`=^J2d~u|9-58w#t{(MV4Ap(8WHAA8b@ms8 zLyk728c8N5c}2bTqR3_mXwQ4AdX!=Nvj6<&MIYBf=g`Ali_dCgGxry+f#qBGI2OCt z$=Ma@oA>ykHZ#t~VR4wIEULWKWC@TKx$QTHtkld|tMdaWdjD9HAoKRqkG&YSZrt9x z465HNaP=4Y2*mu1HVS(bE%q}+6k$K(LNhTaZO2SoR;hWTIn7K2waq-Vl^NCBxHww1=hLY)gJ0fymWIG- z+`(>hhor4eF(t4j|7!mP`%`r2wPyluGF2+_Tj0&1x=$9nfA9n6O!|MwvX)lIs@%XQ z)MZ`vI9EIVwa(n5HC&WbP`@t)sDhU0g5;pRS(#GcouWfqPBdVUHk`*>Nm9G091>2I zNBFs+jOlG<3Rt_wIu#5I8W}LhD-~`QxQMU z{JErg)^#DXv&P#5%=NEryM3s*+N?n+5} zN|`r3#&i(xbFKPQeo8QLIB=Br8{>LQ5`85lcf+Cn-GlqUZ>>x%?(#!d2m>|HQuyol zzQP^3SAY%0{T)O58%K-XWr65ad3P6IRrAo9X!EA;<}?($r$Fm2f-aVMCz%E=FTyFK zrX%H-c*C&r=w2s7WTxOeTiXI?juGC}iFe9JxvLs z-aIptk&g$l99ShAz!~AHf6`Tbm9vZPBPQWH$JH{g^yDA0s}dG7E;J)RE21K=`$bllhjy_#MF0^NAM@k|kD&rwy`* z@^1%soqV{15MDE2Eq}UZ>1oJHZGCzuSM;3NKEzoC;&1U!dq-tyN^+Z+VbGU~+tT<@ z)OPL8PbUrZRM;E5>E5BTyNEpH*l<7kb!qJC%hQA1}v$k4{Lsrv*5Z*`m{y=2?1y5z#G!34BL!8GB}Y0zSyh z`~)Vm7ue#y`zQ0FhFMMTc<1*IMoOnA8kr_7xS<%WuxuyI%|A);Zw; zK8)m}KUciqcHFmDrPb_Wp%A(tpClaprLDa+Y^;UjJ1^uji&A4K-h{xPf7w3;(!|I^ z&DoB)zocg5&bY`B8!>&rxDrZrUs30Eik0K<`Iwa|K9DShQeg28ba}T&r|QB#79$;o z(zZ`ZIbp!2`n|UsfN)jkgY$zSm!gkhwD7wh4WEV41~{@VD-tn+8MvHceug2E(TdRW z;7ZngPMK2vew+yYX}Y!<@mI;sTf=rI{~H9)|Hq>A|4(SOn+mOx^?%c1k7RL#F? zYUe*E8T+~Xk7Ds^8?D-p-!BqkE&tH?wEE-!gG0Z5#5p0-RBf%&;`J-+u0QtJnuTPu zHU4Wq`S9hzh;q+$Dk$b}FhJn1dq#Cv85wc!C%2X@^o#VZHKp(L&)(G2W##m=Ww!KtFf>!185>t$=s%d$G)jo&*L z?W+2`XdMvXA&b3W@Ho?ut$It1b?+eW>Jsu$sZZH$RloJ$TC2@MKqd$+LZ8*(dPv&R zY_8Xn0e9ouXhv4YP|N(kAQuinx^MaPN=YBdxt%B!g?{KPnY>KCrtkVs7m4*`+&`yk z6jxIVj9Qy5vX1?ONq?DGEzTI2!2A2vbyS1@jEBDuo~}ff#=XRS-1pB|Lafn%&~~ae z>qGvgo2Q!cPnq}o$c@-(&&3t5<}tDKUoK!9&Ab$n-ufH)eZKy`SnD=Q)pc&thx}uD zbB{h(jr~)$oJZPq+D*x|RbzhF)(`qUg}%jFs)qQ#HQ6`+2n*F^ZoJm09AMLFOaxth z^FN{eZz}8m*Ocr(iLil+1!`(JzjAy2(JK7G(foroQCS(4722>;9r%w{X!XHg-OxW+ zum3eNA)A&*5b}}yag!@$=1MQ8wfV5Lx-}viI4VBb=b>ru_ z#Kf(^#FTAXT3Q_n1w2u)viwfpJowx|&q$9|^qX&g`%F!>RiF9)XaLu#{b;#UD{gFO zgk4dZkq7$D@hn3h;3=c*lZlJJ9SL7n&NT2F>q5>pnbN(#Jkp`ExUJI(GgsfOI}}m; zcQe{`Ax)LXRil&)k{r>2Sm7e{6_vd0kA6qVA;}K}O2G=d6?3IfX`m=o@<%4= zN_}n`Lad+Lsg&p|%lUM97oxgEPF4;Ss-r|0R0p=4 z^;aNlIoTdg(m}m VyIx&kg|3R|Nmuuy)y^TQ{|%3GaRLAU literal 0 HcmV?d00001 diff --git a/samples/react-accordion/config/config.json b/samples/react-accordion/config/config.json new file mode 100644 index 000000000..55814e677 --- /dev/null +++ b/samples/react-accordion/config/config.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json", + "version": "2.0", + "bundles": { + "react-accordion-web-part": { + "components": [ + { + "entrypoint": "./lib/webparts/reactAccordion/ReactAccordionWebPart.js", + "manifest": "./src/webparts/reactAccordion/ReactAccordionWebPart.manifest.json" + } + ] + } + }, + "externals": {}, + "localizedResources": { + "ReactAccordionWebPartStrings": "lib/webparts/reactAccordion/loc/{locale}.js", + "ControlStrings": "node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js" + } +} \ No newline at end of file diff --git a/samples/react-accordion/config/copy-assets.json b/samples/react-accordion/config/copy-assets.json new file mode 100644 index 000000000..3771fd04a --- /dev/null +++ b/samples/react-accordion/config/copy-assets.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json", + "deployCdnPath": "temp/deploy" +} diff --git a/samples/react-accordion/config/deploy-azure-storage.json b/samples/react-accordion/config/deploy-azure-storage.json new file mode 100644 index 000000000..0ceafe571 --- /dev/null +++ b/samples/react-accordion/config/deploy-azure-storage.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json", + "workingDir": "./temp/deploy/", + "account": "", + "container": "react-accordion", + "accessKey": "" +} \ No newline at end of file diff --git a/samples/react-accordion/config/package-solution.json b/samples/react-accordion/config/package-solution.json new file mode 100644 index 000000000..fd5d55eab --- /dev/null +++ b/samples/react-accordion/config/package-solution.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json", + "solution": { + "name": "react-accordion-client-side-solution", + "id": "6d6cf05b-cfe5-4d12-af19-19ec3aedcaf9", + "version": "1.0.0.0", + "includeClientSideAssets": true + }, + "paths": { + "zippedPackage": "solution/react-accordion.sppkg" + } +} diff --git a/samples/react-accordion/config/serve.json b/samples/react-accordion/config/serve.json new file mode 100644 index 000000000..090cfe9e6 --- /dev/null +++ b/samples/react-accordion/config/serve.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json", + "port": 4321, + "https": true, + "initialPage": "https://localhost:5432/workbench", + "api": { + "port": 5432, + "entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/" + } +} diff --git a/samples/react-accordion/config/tslint.json b/samples/react-accordion/config/tslint.json new file mode 100644 index 000000000..b17194770 --- /dev/null +++ b/samples/react-accordion/config/tslint.json @@ -0,0 +1,45 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/core-build/tslint.schema.json", + // Display errors as warnings + "displayAsWarning": true, + // The TSLint task may have been configured with several custom lint rules + // before this config file is read (for example lint rules from the tslint-microsoft-contrib + // project). If true, this flag will deactivate any of these rules. + "removeExistingRules": true, + // When true, the TSLint task is configured with some default TSLint "rules.": + "useDefaultConfigAsBase": false, + // Since removeExistingRules=true and useDefaultConfigAsBase=false, there will be no lint rules + // which are active, other than the list of rules below. + "lintConfig": { + // Opt-in to Lint rules which help to eliminate bugs in JavaScript + "rules": { + "class-name": false, + "export-name": false, + "forin": false, + "label-position": false, + "member-access": true, + "no-arg": false, + "no-console": false, + "no-construct": false, + "no-duplicate-case": true, + "no-duplicate-variable": true, + "no-eval": false, + "no-function-expression": true, + "no-internal-module": true, + "no-shadowed-variable": true, + "no-switch-case-fall-through": true, + "no-unnecessary-semicolons": true, + "no-unused-expression": true, + "no-use-before-declare": true, + "no-with-statement": true, + "semicolon": true, + "trailing-comma": false, + "typedef": false, + "typedef-whitespace": false, + "use-named-parameter": true, + "valid-typeof": true, + "variable-name": false, + "whitespace": false + } + } +} \ No newline at end of file diff --git a/samples/react-accordion/config/write-manifests.json b/samples/react-accordion/config/write-manifests.json new file mode 100644 index 000000000..bad352605 --- /dev/null +++ b/samples/react-accordion/config/write-manifests.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json", + "cdnBasePath": "" +} \ No newline at end of file diff --git a/samples/react-accordion/gulpfile.js b/samples/react-accordion/gulpfile.js new file mode 100644 index 000000000..7958fd5d8 --- /dev/null +++ b/samples/react-accordion/gulpfile.js @@ -0,0 +1,7 @@ +'use strict'; + +const gulp = require('gulp'); +const build = require('@microsoft/sp-build-web'); +build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`); + +build.initialize(gulp); diff --git a/samples/react-accordion/package.json b/samples/react-accordion/package.json new file mode 100644 index 000000000..40a0971a4 --- /dev/null +++ b/samples/react-accordion/package.json @@ -0,0 +1,36 @@ +{ + "name": "react-accordion", + "version": "0.0.1", + "private": true, + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "build": "gulp bundle", + "clean": "gulp clean", + "test": "gulp test" + }, + "dependencies": { + "@microsoft/sp-core-library": "1.5.1", + "@microsoft/sp-lodash-subset": "1.5.1", + "@microsoft/sp-office-ui-fabric-core": "1.5.1", + "@microsoft/sp-webpart-base": "1.5.1", + "@pnp/spfx-controls-react": "1.7.0", + "@types/es6-promise": "0.0.33", + "@types/react": "15.6.6", + "@types/react-dom": "15.5.6", + "@types/webpack-env": "1.13.1", + "react": "15.6.2", + "react-accessible-accordion": "1.0.2", + "react-dom": "15.6.2" + }, + "devDependencies": { + "@microsoft/sp-build-web": "1.5.1", + "@microsoft/sp-module-interfaces": "1.5.1", + "@microsoft/sp-webpart-workbench": "1.5.1", + "gulp": "~3.9.1", + "@types/chai": "3.4.34", + "@types/mocha": "2.2.38", + "ajv": "~5.2.2" + } +} diff --git a/samples/react-accordion/src/webparts/reactAccordion/ReactAccordionWebPart.manifest.json b/samples/react-accordion/src/webparts/reactAccordion/ReactAccordionWebPart.manifest.json new file mode 100644 index 000000000..1de3bd6f8 --- /dev/null +++ b/samples/react-accordion/src/webparts/reactAccordion/ReactAccordionWebPart.manifest.json @@ -0,0 +1,33 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json", + "id": "97a28c00-64ee-4ec7-b373-723e39069a96", + "alias": "ReactAccordionWebPart", + "componentType": "WebPart", + // The "*" signifies that the version should be taken from the package.json + "version": "*", + "manifestVersion": 2, + // If true, the component can only be installed on sites where Custom Script is allowed. + // Components that allow authors to embed arbitrary script code should set this to true. + // https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f + "requiresCustomScript": false, + "preconfiguredEntries": [ + { + "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other + "group": { + "default": "Other" + }, + "title": { + "default": "React Accordion App" + }, + "description": { + "default": "SPFx webpart which shows SharePoint list data in Accordion format" + }, + "officeFabricIconFontName": "Questionnaire", + "properties": { + "description": "SPFx webpart which shows SharePoint list data in Accordion format", + "listName": "FAQ", + "maxItemsPerPage": 5 + } + } + ] +} \ No newline at end of file diff --git a/samples/react-accordion/src/webparts/reactAccordion/ReactAccordionWebPart.ts b/samples/react-accordion/src/webparts/reactAccordion/ReactAccordionWebPart.ts new file mode 100644 index 000000000..464e528c1 --- /dev/null +++ b/samples/react-accordion/src/webparts/reactAccordion/ReactAccordionWebPart.ts @@ -0,0 +1,83 @@ +import * as React from 'react'; +import * as ReactDom from 'react-dom'; +import { Version, DisplayMode } from '@microsoft/sp-core-library'; +import { + BaseClientSideWebPart, + IPropertyPaneConfiguration, + PropertyPaneTextField, + PropertyPaneSlider +} from '@microsoft/sp-webpart-base'; + +import * as strings from 'ReactAccordionWebPartStrings'; +import ReactAccordion from './components/ReactAccordion'; +import { IReactAccordionProps } from './components/IReactAccordionProps'; + +export interface IReactAccordionWebPartProps { + listName: string; + choice: string; + title: string; + displayMode: DisplayMode; + maxItemsPerPage: number; + updateProperty: (value: string) => void; +} + +export default class ReactAccordionWebPart extends BaseClientSideWebPart { + + public render(): void { + const element: React.ReactElement = React.createElement( + ReactAccordion, + { + listName: this.properties.listName, + spHttpClient: this.context.spHttpClient, + siteUrl: this.context.pageContext.web.absoluteUrl, + title: this.properties.title, + displayMode: this.displayMode, + maxItemsPerPage: this.properties.maxItemsPerPage, + updateProperty: (value: string) => { + this.properties.title = value; + } + } + ); + + ReactDom.render(element, this.domElement); + } + + protected onDispose(): void { + ReactDom.unmountComponentAtNode(this.domElement); + } + + protected get dataVersion(): Version { + return Version.parse('1.0'); + } + + protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { + return { + pages: [ + { + header: { + description: strings.PropertyPaneDescription + }, + groups: [ + { + groupName: strings.BasicGroupName, + groupFields: [ + PropertyPaneTextField('listName', { + label: strings.ListNameLabel + }), + PropertyPaneSlider('maxItemsPerPage', { + label: strings.MaxItemsPerPageLabel, + ariaLabel: strings.MaxItemsPerPageLabel, + min: 3, + max: 20, + value: 5, + showValue: true, + step: 1 + }), + ] + } + ] + } + ] + }; + } +} diff --git a/samples/react-accordion/src/webparts/reactAccordion/components/IReactAccordionProps.ts b/samples/react-accordion/src/webparts/reactAccordion/components/IReactAccordionProps.ts new file mode 100644 index 000000000..aa64ca72b --- /dev/null +++ b/samples/react-accordion/src/webparts/reactAccordion/components/IReactAccordionProps.ts @@ -0,0 +1,12 @@ +import { SPHttpClient } from '@microsoft/sp-http'; +import { DisplayMode } from '@microsoft/sp-core-library'; + +export interface IReactAccordionProps { + listName: string; + spHttpClient: SPHttpClient; + siteUrl: string; + title: string, + displayMode: DisplayMode, + maxItemsPerPage: number, + updateProperty: (value: string) => void; +} diff --git a/samples/react-accordion/src/webparts/reactAccordion/components/IReactAccordionState.ts b/samples/react-accordion/src/webparts/reactAccordion/components/IReactAccordionState.ts new file mode 100644 index 000000000..9ad6c65af --- /dev/null +++ b/samples/react-accordion/src/webparts/reactAccordion/components/IReactAccordionState.ts @@ -0,0 +1,9 @@ +import IAccordionListItem from '../models/IAccordionListItem'; + +export interface IReactAccordionState { + status: string; + items: IAccordionListItem[]; + listItems: IAccordionListItem[]; + isLoading: boolean; + loaderMessage: string; +} \ No newline at end of file diff --git a/samples/react-accordion/src/webparts/reactAccordion/components/ReactAccordion.module.scss b/samples/react-accordion/src/webparts/reactAccordion/components/ReactAccordion.module.scss new file mode 100644 index 000000000..2526d496f --- /dev/null +++ b/samples/react-accordion/src/webparts/reactAccordion/components/ReactAccordion.module.scss @@ -0,0 +1,73 @@ +@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss'; + +.reactAccordion { + .container { + max-width: 100%; + margin: 0px auto; + } + + .row { + @include ms-Grid-row; + @include ms-fontColor-white; + background-color: $ms-color-themeDark; + padding: 20px; + } + + .column { + @include ms-Grid-col; + @include ms-lg10; + @include ms-xl8; + @include ms-xlPush2; + @include ms-lgPush1; + } + + .title { + @include ms-font-xl; + @include ms-fontColor-white; + } + + .subTitle { + @include ms-font-l; + @include ms-fontColor-white; + } + + .description { + @include ms-font-l; + @include ms-fontColor-white; + } + + .button { + // Our button + text-decoration: none; + height: 32px; + + // Primary Button + min-width: 80px; + background-color: $ms-color-themePrimary; + border-color: $ms-color-themePrimary; + color: $ms-color-white; + + // Basic Button + outline: transparent; + position: relative; + font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif; + -webkit-font-smoothing: antialiased; + font-size: $ms-font-size-m; + font-weight: $ms-font-weight-regular; + border-width: 0; + text-align: center; + cursor: pointer; + display: inline-block; + padding: 0 16px; + + .label { + font-weight: $ms-font-weight-semibold; + font-size: $ms-font-size-m; + height: 32px; + line-height: 32px; + margin: 0 4px; + vertical-align: top; + display: inline-block; + } + } +} \ No newline at end of file diff --git a/samples/react-accordion/src/webparts/reactAccordion/components/ReactAccordion.tsx b/samples/react-accordion/src/webparts/reactAccordion/components/ReactAccordion.tsx new file mode 100644 index 000000000..95671e6bb --- /dev/null +++ b/samples/react-accordion/src/webparts/reactAccordion/components/ReactAccordion.tsx @@ -0,0 +1,180 @@ +import * as React from 'react'; +import styles from './ReactAccordion.module.scss'; +import { IReactAccordionProps } from './IReactAccordionProps'; +import { SPHttpClient, SPHttpClientResponse, ISPHttpClientOptions } from '@microsoft/sp-http'; +import { PrimaryButton } from 'office-ui-fabric-react/lib/Button'; +import { SearchBox } from 'office-ui-fabric-react/lib/SearchBox'; +import { + Spinner, + SpinnerSize +} from 'office-ui-fabric-react/lib/Spinner'; +import { + Accordion, + AccordionItem, + AccordionItemTitle, + AccordionItemBody, +} from 'react-accessible-accordion'; +import 'react-accessible-accordion/dist/react-accessible-accordion.css'; +import { IReactAccordionState } from "./IReactAccordionState"; +import IAccordionListItem from "../models/IAccordionListItem"; +import { WebPartTitle } from "@pnp/spfx-controls-react/lib/WebPartTitle"; +import './accordion.css'; + +export default class ReactAccordion extends React.Component { + + constructor(props: IReactAccordionProps, state: IReactAccordionState) { + super(props); + this.state = { + status: this.listNotConfigured(this.props) ? 'Please configure list in Web Part properties' : 'Ready', + items: [], + listItems: [], + isLoading: false, + loaderMessage: '' + }; + + if (!this.listNotConfigured(this.props)) { + this.readItems(); + } + + this.searchTextChange = this.searchTextChange.bind(this); + + } + + private listNotConfigured(props: IReactAccordionProps): boolean { + return props.listName === undefined || + props.listName === null || + props.listName.length === 0; + } + + private searchTextChange(event) { + + if (event === undefined || + event === null || + event === "") { + let listItemsCollection = [...this.state.listItems]; + this.setState({ items: listItemsCollection.splice(0, this.props.maxItemsPerPage) }); + } + else { + var updatedList = [...this.state.listItems]; + updatedList = updatedList.filter((item) => { + return item.Title.toLowerCase().search( + event.toLowerCase()) !== -1 || item.Description.toLowerCase().search( + event.toLowerCase()) !== -1; + }); + this.setState({ items: updatedList }); + } + } + + private readItems(): void { + let restAPI = this.props.siteUrl + `/_api/web/Lists/GetByTitle('${this.props.listName}')/items?$select=Title,Description`; + + this.props.spHttpClient.get(restAPI, SPHttpClient.configurations.v1, { + headers: { + 'Accept': 'application/json;odata=nometadata', + 'odata-version': '' + } + }) + .then((response: SPHttpClientResponse): Promise<{ value: IAccordionListItem[] }> => { + return response.json(); + }) + .then((response: { value: IAccordionListItem[] }): void => { + + let listItemsCollection = [...response.value]; + + this.setState({ + status: "", + items: listItemsCollection.splice(0, this.props.maxItemsPerPage), + listItems: response.value, + isLoading: false, + loaderMessage: "" + }); + }, (error: any): void => { + this.setState({ + status: 'Loading all items failed with error: ' + error, + items: [], + isLoading: false, + loaderMessage: "" + }); + }); + + } + + public render(): React.ReactElement { + let displayLoader; + let faqTitle; + let { listItems } = this.state; + let pageCountDivisor: number = this.props.maxItemsPerPage; + let pageCount: number; + let pageButtons = []; + + let _pagedButtonClick = (pageNumber: number, listData: any) => { + let startIndex: number = (pageNumber - 1) * pageCountDivisor; + let listItemsCollection = [...listData]; + this.setState({ items: listItemsCollection.splice(startIndex, pageCountDivisor) }); + }; + + const items: JSX.Element[] = this.state.items.map((item: IAccordionListItem, i: number): JSX.Element => { + return ( + + +

    {item.Title}

    +
    + + +
    +
    +
    + + ); + }); + + if (this.state.isLoading) { + displayLoader = (
    +
    + +
    +
    ); + } + else { + displayLoader = (null); + } + + if (this.state.listItems.length > 0) { + pageCount = Math.ceil(this.state.listItems.length / pageCountDivisor); + } + for (let i = 0; i < pageCount; i++) { + pageButtons.push( { _pagedButtonClick(i + 1, listItems); }}> {i + 1} ); + } + return ( +
    +
    + {faqTitle} + {displayLoader} + +
    +
    + +
    +
    +
    +
    + {this.state.status} + + {items} + +
    +
    +
    +
    + {pageButtons} +
    +
    +
    +
    + ); + } +} diff --git a/samples/react-accordion/src/webparts/reactAccordion/components/accordion.css b/samples/react-accordion/src/webparts/reactAccordion/components/accordion.css new file mode 100644 index 000000000..5e8a0c4af --- /dev/null +++ b/samples/react-accordion/src/webparts/reactAccordion/components/accordion.css @@ -0,0 +1,109 @@ +.accordion__title > *:last-child, +.accordion__body > *:last-child { + margin-bottom: 0; +} + + .accordion__arrow { + display: inline-block; + position: relative; + width: 24px; + height: 12px; + right: 10px; + margin-top: -28px; + color: white !important; + + float: right; + } + + + .accordion__arrow::after, + .accordion__arrow::before { + display: block; + position: absolute; + width: 10px; + height: 2px; + background-color: currentColor; + content: ''; + } + + .accordion__arrow::before { + left: 4px; + transform: rotate(45deg); + } + + [aria-expanded="true"] .accordion__arrow::before { + transform: rotate(-45deg); + } + + .accordion__arrow::after { + right: 4px; + transform: rotate(-45deg); + } + + [aria-expanded="true"] .accordion__arrow::after { + transform: rotate(45deg); + } + + .accordion__arrow::before, .accordion__arrow::after { + transition: transform .25s ease, -webkit-transform .25s ease; + } + +.accordion__item { +background-color: "[theme: themePrimary, default: #0078d7]"; +margin-bottom: 10px; +} +.accordion { + padding-top: 10px; + +} +.accordion__item .accordion__title { +padding: 5px 20px;; +background-color: "[theme: themePrimary, default: #0078d7]"; +} +.accordion__item .accordion__title h3 { + font-weight: normal; + width: 88%; +} +.accordion__item .accordion__body { +padding: 15px 20px; +background-color: "[theme: themeLighterAlt, default: #0078d7]"; +color: "[theme: bodyText, default: #333333]"; +} + +.accordion__item .accordion__body a { + color: "[theme: themePrimary, default: #0078d7]" !important; +} +.accordion__item .accordion__body p { +color: "[theme: bodyText, default: #333333]"; +} + + +/* -------------------------------------------------- */ +/* ---------------- Animation part ------------------ */ +/* -------------------------------------------------- */ + +@keyframes move-down { +0% { transform: translateY(0); } +10% { transform: translateY(0); } +20% { transform: translateY(5px); } +30% { transform: translateY(0); } +100% { transform: translateY(0); } +} + +@keyframes move-up { +0% { transform: translateY(0); } +10% { transform: translateY(0); } +20% { transform: translateY(-5px); } +30% { transform: translateY(0); } +100% { transform: translateY(0); } +} + +.accordion__title--animated:hover .accordion__arrow { +animation-name: move-down; +animation-duration: 1.5s; +} + +.accordion__title--animated[aria-expanded="true"]:hover .accordion__arrow { +animation-name: move-up; +animation-duration: 1.5s; +} diff --git a/samples/react-accordion/src/webparts/reactAccordion/loc/en-us.js b/samples/react-accordion/src/webparts/reactAccordion/loc/en-us.js new file mode 100644 index 000000000..f6c53fd3d --- /dev/null +++ b/samples/react-accordion/src/webparts/reactAccordion/loc/en-us.js @@ -0,0 +1,8 @@ +define([], function () { + return { + "PropertyPaneDescription": "Description", + "BasicGroupName": "Group Name", + "ListNameLabel": "List Name", + "MaxItemsPerPageLabel": "Max number of items per page" + } +}); \ No newline at end of file diff --git a/samples/react-accordion/src/webparts/reactAccordion/loc/mystrings.d.ts b/samples/react-accordion/src/webparts/reactAccordion/loc/mystrings.d.ts new file mode 100644 index 000000000..fdaea494e --- /dev/null +++ b/samples/react-accordion/src/webparts/reactAccordion/loc/mystrings.d.ts @@ -0,0 +1,11 @@ +declare interface IReactAccordionWebPartStrings { + PropertyPaneDescription: string; + BasicGroupName: string; + ListNameLabel: string; + MaxItemsPerPageLabel: string +} + +declare module 'ReactAccordionWebPartStrings' { + const strings: IReactAccordionWebPartStrings; + export = strings; +} diff --git a/samples/react-accordion/src/webparts/reactAccordion/models/IAccordionListItem.ts b/samples/react-accordion/src/webparts/reactAccordion/models/IAccordionListItem.ts new file mode 100644 index 000000000..20153f2a3 --- /dev/null +++ b/samples/react-accordion/src/webparts/reactAccordion/models/IAccordionListItem.ts @@ -0,0 +1,6 @@ +interface IAccordionListItem { + Id: number; + Title: string; + Description: string; +} +export default IAccordionListItem; \ No newline at end of file diff --git a/samples/react-accordion/tsconfig.json b/samples/react-accordion/tsconfig.json new file mode 100644 index 000000000..0c292a892 --- /dev/null +++ b/samples/react-accordion/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es5", + "forceConsistentCasingInFileNames": true, + "module": "esnext", + "moduleResolution": "node", + "jsx": "react", + "declaration": true, + "sourceMap": true, + "experimentalDecorators": true, + "skipLibCheck": true, + "typeRoots": [ + "./node_modules/@types", + "./node_modules/@microsoft" + ], + "types": [ + "es6-promise", + "webpack-env" + ], + "lib": [ + "es5", + "dom", + "es2015.collection" + ] + } +} diff --git a/samples/react-accordion/tslint.json b/samples/react-accordion/tslint.json new file mode 100644 index 000000000..37c5004a3 --- /dev/null +++ b/samples/react-accordion/tslint.json @@ -0,0 +1,3 @@ +{ + "rulesDirectory": "./config" +} \ No newline at end of file