From 4f31794d4fd9c6b3d86411529a4f990f21d78f7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vagner=20Jos=C3=A9=20Nicolodi?= Date: Wed, 5 Jan 2022 17:00:58 -0300 Subject: [PATCH 1/2] feat(CheckableTag): Added new CheckableTag component STC-825 --- src/components/CheckableTag/CheckableTag.md | 28 ++++ .../CheckableTag/CheckableTag.stories.tsx | 40 ++++++ .../CheckableTag/CheckableTag.test.tsx | 63 +++++++++ src/components/CheckableTag/CheckableTag.tsx | 128 ++++++++++++++++++ src/components/Checkbox/Checkbox.stories.tsx | 1 + src/components/Checkbox/Checkbox.tsx | 6 +- .../CheckableTag/Default/chrome.png | Bin 0 -> 279 bytes .../CheckableTag/Default/firefox.png | Bin 0 -> 192 bytes .../CheckableTag/Disabled/chrome.png | Bin 0 -> 1242 bytes .../CheckableTag/Disabled/firefox.png | Bin 0 -> 949 bytes .../CheckableTag/Labeled/chrome.png | Bin 0 -> 1412 bytes .../CheckableTag/Labeled/firefox.png | Bin 0 -> 1088 bytes 12 files changed, 264 insertions(+), 2 deletions(-) create mode 100644 src/components/CheckableTag/CheckableTag.md create mode 100644 src/components/CheckableTag/CheckableTag.stories.tsx create mode 100644 src/components/CheckableTag/CheckableTag.test.tsx create mode 100644 src/components/CheckableTag/CheckableTag.tsx create mode 100644 tests/images/Design System/CheckableTag/Default/chrome.png create mode 100644 tests/images/Design System/CheckableTag/Default/firefox.png create mode 100644 tests/images/Design System/CheckableTag/Disabled/chrome.png create mode 100644 tests/images/Design System/CheckableTag/Disabled/firefox.png create mode 100644 tests/images/Design System/CheckableTag/Labeled/chrome.png create mode 100644 tests/images/Design System/CheckableTag/Labeled/firefox.png diff --git a/src/components/CheckableTag/CheckableTag.md b/src/components/CheckableTag/CheckableTag.md new file mode 100644 index 00000000..82a9493f --- /dev/null +++ b/src/components/CheckableTag/CheckableTag.md @@ -0,0 +1,28 @@ +Default CheckableTag example: + +```js +const [checked, setChecked] = React.useState(false) + +; setChecked((previousState) => !previousState)} +/> +``` + +Labeled CheckableTag example: + +```js +const [checked, setChecked] = React.useState(false) + +; setChecked((previousState) => !previousState)} +/> +``` + +Disabled CheckableTag state example: + +```js +; +``` diff --git a/src/components/CheckableTag/CheckableTag.stories.tsx b/src/components/CheckableTag/CheckableTag.stories.tsx new file mode 100644 index 00000000..464824b4 --- /dev/null +++ b/src/components/CheckableTag/CheckableTag.stories.tsx @@ -0,0 +1,40 @@ +import React, { useState } from "react" +import { Meta, Story } from "@storybook/react/types-6-0" + +import CheckableTag, { CheckableTagProps } from "./CheckableTag" + +export default { + title: "Design System/CheckableTag", + component: CheckableTag, +} as Meta + +const Template: Story = (props) => { + const [checked, setChecked] = useState(false) + + return ( + setChecked((previousState) => !previousState)} + /> + ) +} + +export const Default = Template.bind({}) + +Default.args = {} + +export const Labeled = Template.bind({}) + +Labeled.args = { + label: "Check me", +} + +export const Disabled = Template.bind({}) + +Disabled.args = { + label: "I'm disabled", + disabled: true, +} diff --git a/src/components/CheckableTag/CheckableTag.test.tsx b/src/components/CheckableTag/CheckableTag.test.tsx new file mode 100644 index 00000000..f3a902f5 --- /dev/null +++ b/src/components/CheckableTag/CheckableTag.test.tsx @@ -0,0 +1,63 @@ +import "@testing-library/jest-dom/extend-expect" +import React, { useState } from "react" +import { fireEvent, render } from "@testing-library/react" + +import CheckableTag, { CheckableTagProps } from "./CheckableTag" +import { axe } from "jest-axe" + +const CheckableTagTemplate = (props: CheckableTagProps) => { + const [checked, setChecked] = useState(false) + + return ( + setChecked((previous) => !previous)} + {...props} + /> + ) +} + +describe("CheckableTag", () => { + it("can be checked", () => { + const mockedFunction = jest.fn() + const { getByRole } = render( + + ) + + const checkbox = getByRole("checkbox") + + expect(checkbox).toBeInTheDocument() + + fireEvent.click(checkbox) + + expect(mockedFunction).toHaveBeenCalled() + }) + + it("renders the label succesfully", () => { + const label = "Check me" + const { getByText } = render() + + expect(getByText(label)).toBeInTheDocument() + }) + + it("can be disabled", () => { + const mockedFunction = jest.fn() + const { getByRole } = render( + mockedFunction()} /> + ) + + const checkbox = getByRole("checkbox") + + fireEvent.click(checkbox) + + expect(mockedFunction).not.toHaveBeenCalled() + }) + it("passes a11y check", async () => { + // Arrange + const { container } = render() + const results = await axe(container) + + // Assert + expect(results).toHaveNoViolations() + }) +}) diff --git a/src/components/CheckableTag/CheckableTag.tsx b/src/components/CheckableTag/CheckableTag.tsx new file mode 100644 index 00000000..a593253d --- /dev/null +++ b/src/components/CheckableTag/CheckableTag.tsx @@ -0,0 +1,128 @@ +/** @jsxImportSource theme-ui */ +import React, { forwardRef, HTMLProps } from "react" +import Icon from "../Icon/Icon" + +export interface CheckableTagProps + extends Omit, "label" | "ref"> { + label?: React.ReactNode +} + +const stateStyles = { + resting: { + backgroundColor: "text.alpha.95", + color: "text.40", + }, + hover: { + backgroundColor: "text.alpha.90", + }, + active: { + backgroundColor: "text.alpha.90", + outline: "none", + }, + filled: { + backgroundColor: "secondary.alpha.90", + color: "secondary", + }, + filledHover: { + backgroundColor: "secondary.alpha.85", + color: "secondary", + outline: "none", + }, +} + +const CheckableTag = forwardRef( + function CheckableTag(props: CheckableTagProps, ref) { + const { + checked = false, + disabled = false, + id, + label, + name, + onChange, + ...restProps + } = props + + return ( + + ) + } +) + +export default CheckableTag diff --git a/src/components/Checkbox/Checkbox.stories.tsx b/src/components/Checkbox/Checkbox.stories.tsx index 6262848c..c100f38a 100644 --- a/src/components/Checkbox/Checkbox.stories.tsx +++ b/src/components/Checkbox/Checkbox.stories.tsx @@ -14,6 +14,7 @@ const Template: Story = (props) => { return ( setChecked((previousState) => !previousState)} diff --git a/src/components/Checkbox/Checkbox.tsx b/src/components/Checkbox/Checkbox.tsx index 5a049adc..3317046c 100644 --- a/src/components/Checkbox/Checkbox.tsx +++ b/src/components/Checkbox/Checkbox.tsx @@ -6,6 +6,7 @@ export interface ICheckboxProps { checked?: boolean indeterminate?: boolean disabled?: boolean + id?: string label?: React.ReactNode name?: string onChange?(event: React.ChangeEvent): void @@ -35,6 +36,7 @@ const Checkbox = React.forwardRef( checked = false, disabled = false, indeterminate = false, + id, label, name, onChange, @@ -54,7 +56,7 @@ const Checkbox = React.forwardRef( { @@ -134,7 +136,7 @@ const Checkbox = React.forwardRef( width: "auto", cursor: disabled ? "auto" : "pointer", }} - htmlFor={name} + htmlFor={id} > {label} diff --git a/tests/images/Design System/CheckableTag/Default/chrome.png b/tests/images/Design System/CheckableTag/Default/chrome.png new file mode 100644 index 0000000000000000000000000000000000000000..2d57ce3b8502e9d3d52fb8191e39d7f7cf368d16 GIT binary patch literal 279 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`T=aBt42fuc zdt>*yBMLmO7n|jk{{P?VD3RWkv8XaOa#xTO*ZXN{CmkMd%Dvq-{f=x}n<3jV2@B;k zHe+WO2bcWxr=nM?-Lv0{9EragwQ$w_1*NfxY15PDb#hEgWn>W8;GZVO#&Cvb?|0cJ z@21CJULTcRP=4Xe$(ppZ1)J+G)k`Jc5ipVd7}>N)NM!1Q6)di*8d{EloLyc4As`{w zGd8yij+`-P={%8heB!F64vwwYZi-!r3iP@uzjam8vn4K1ZV28jPyG7k)YN&a7ESq7 b_Kl%WA;Vx&Z23N*=NLR){an^LB{Ts5>mzeO literal 0 HcmV?d00001 diff --git a/tests/images/Design System/CheckableTag/Default/firefox.png b/tests/images/Design System/CheckableTag/Default/firefox.png new file mode 100644 index 0000000000000000000000000000000000000000..c68e226a0c7c1f95f64a5d342948af61ea149d93 GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB+C5zyLn2z=-q^@>#DIr6;Q#;k zY>jF!mo=MhDe&H4DRN|*Pc(!)sq$_ht?Ij1OM9z2VeY(7^P{&w-IuB%qv$>&1VE$Hx{F rHb2@CSaoMp;uEX1Cx^05dA(Px(lu1NERA_9g6FF&WLO4ZLTUEX5|Njk0k*KPwwTNN|fpdU@ z6KoFSypeDLI{KqXqtu) zBKhBK1D4ArN~zyoz&{C1)5zs=@wJFnuvjcoEY_cguIsB_0c5Q{1=cawlv0@iDX^Yr zwQQnI52e(q2V|r}6h*5!AR`?z1O5kO2Bb`8K+62G0rUBscDv2_`8h!l&~CSxPNz>^ zurFV}aB^~jQi@KeL%-jDl-}|2@lQ3n-7dCmKS*0CMZ4YR^78VRpM6vh&~-iW`y2=% zFbv~a^MF+l(^wHcs#fbgjoW)0PmK_Qw{PD*n||6n$^an*A3uHs!1FxL&dxYEIAAas zkjv$0G#Z?rpEDkh$>;Mln@x(v;)c$0xx{r{Mxzk``}_Neo!H~!V=T*}QmHT+jW|0y zV>X+yy}eDN(LhR>(9kpu(=?e(CKL(MjRd<(r7fezP{d= zn>^1$DMhtfrBEo~I1a<%a3i0Kiwj)WWoKuHdcBSiBCd;43fs1sPN!5V6-?8_ahwOo z?8yh#qoX6Fln5bk9EWDJNj{%P*L6-#PFO4!iSc|kn=u>?sn_dqYuw%4<BpP`+ZE)Or#qO2JG$a zQLoqI@^m^KE-x?9b)7H_dH?=Bg+c*VBwD=FKgA@b-`FtK&jn(t{{ND7XQi%^AJ}{k5 z>2|xgu1mAo1mNc8CZQ3AVIoj>gMEE{jbRvxd+SwKp-@PS?NJmVrDQUh#N}HzuE#9H zQ#Zgc3{2DH^z=0D9fQGu<#M@^HV6VffBuYVnv~1s)o!Au#Tt&|pp-&NNx$FUSXTPJ z&)2VC+1}p9_kF&9|IX3T(MCR&W#KqZY=rOoOePcFy?cjgn)Lg9Y}=+%si2gi*XupF z{;3-P&}cMpT^Gl3$mMdFrg^Uc`Fx&gwTkC?42MI?dz}lHtRgWl&aHnX{8?H%zA)~%bk3CCz&zn;moJ1 zDwJi3q9~B(xzsHiiK?p34K;f2AIh@qJmCLbWm%pFAhZ2?DvF{FKxY2+RaZh! zW`8%TtDsj^Rp-IntE#F(PiB92DvCk^=o~=TLEO6}014o}B>~(TfHX}(M2MmYyWI{% zgxA;CFAvNx3``~yWLX9w1U%3CCqGqH;rsr@_R(kr+qVD8`*=Kph!Dr|bpad>2M`g` zH2qcpmSz1_=l%qM<2V=&hqnbF&vOtFj>qG-0r)Dv{}w>4APAr+3Ovt)s;c0e-U^1DY-|s_JRm|t}7J&DIw_dL?7!1G|gKgV591bTQoO8IY3tiV+ z9%&hT%m3K@dO)0mc{%!@$eSOVgGl35LTV6h#5&9B~}~3;;v~%d!xLA%qYh zBABMxJP!tgv!3Je7>qHvt_$Dyo9})EkY!mj@U`b+v1mM0RYe@f*lad1P4mQqh%g)u z;rl*p+XfL~wOXA3h@uEY1lM&D$1zOPgsQ4I91b`hj}SsY(=>RVhuLff#@NpRP-kQq zh9Dv&NrF7jv0N@&?X~v%J&354jr;u`ilUqapePDPqY?J|{fWnNxoqCOy}f}k*77h- zv-R7K0-S>T{s@ejOWf_R*tftc` z9v>f}X65t^rAsG=myN5jf|~-up zJRU>SG^Aru~;+}d9wiC?_e}d!)!J?nLg?Y2!a5brhzfmWdHAaxULJw zaeiwT6h#qqT?b`Kki#QHu!*8$y|>iYunczOpqIi4;rXk1ShFKEasO5dZ;t|Px)K1oDDRA_RnS7AK&e#v&mH`eaX1_} z91f!_=(?_Jn#PweU-&9mEp~_~iqzHBA&Md*fTAdtn7@FgX();UfT*gf^_iQ%=C~tT z(P<94u2U+N$`NW|4w|MRYMS=D{rGFpG!60Rk6G*#UDqu^&BhYcWbCyzeE04hPo6v> znM|T63SO_5lP6Eo+1Uxe)YKG;qHy{0Wz(GfH|?55O%a+(rMP+XCW%CX!-o&k-Q7*0 zP#_!*^Z4;&vwi%ds5(LwMPYh+8d;VZ9UaBxaslNL?*9Gzq|<5s&ohUr1zlQNBA?GQ zGBRR_3FY-{Fc?G-1mm8fD1^gdmX?-qxm*km4${`v20$j0Args@NF=b^?HoON6u;kZ z?A|OaEHF1WM?RmYsi}!TAi%+c2P=G8U0vnYty}nfKKlFnE9$1Err6lnprN6GSFc{- z^?LF9{mjhFu)e-ddwV;hdVhlAeUURGCE86O|Vw*bt}&eGl8&A`9_09{>OjE#-)?AbGV zdU~qrbJc=2HZ}r~OeQ&UpWj zThWpF`g&SgT8#4Y@-nKbGCVwt)9L)KuUk`+)9FN(Wy2q*(@C*dMAI~~*(~vRoOnE5 z(LS9{|5%J~P_>{P9UaKBOe7M)C&Yi+Ss#a4*(-0BkbP28z@Je z&1OTEW!!Ezi9~{9$BqH8v9ZC24$?E*FiBjr8^P z8TVCHMV962?N!^rZnrZuG(;|!(^OaT%@U~Y1`idU(?yyiQDaF zW@d&|D#h#9ubG~n=EaK_h@!};Q>S?T{5f~-+#wo`GCn@e#KZ*oeBQ8e?%X-*>+6kq z>95e!)5FV`FM0a(DJv^0%+1Xa3WdI#N`6F5^U&7TR<2&X%ArGtNTpINE-q46SI5PR z7c1WK_mCusD_5?tfB$}Bu^6#fjOONMd_Et5k2Lqmm);o)Jj z*(~?&-K(V=2FH&dXK-+kWHL!45@BU!1;5{4Q-lh+T+Z4IH4$qqZ!(skCSwU|GM1nw zV+m?9mY^mh)-rju_%?zdApUGsW3h8YQAD)aY`@!&zXqGlhA2r=O>0(*N(4bDA8*{e zu=q6`4o5kMZWgRuT05JEZ{e#0x5Z+SVzKz!9QzZIB&lMPTd`*g#QB>SRMQn SR@6}d0000Ynxvp;el1i{6iAXZ_29lLk|e3KRj19&$uO9yIz>^Y9?W+^Q55K8S)O_z-vwEgq0@5b zCifVH)?i3j{q z{Z3Wr`T02*hQa*&JfhJkc6N5)bUHx@K`NEfg#HUW&%Cc{+PdBD$c_7aK7_+z&@>H)!+~nGsiPM69xTg3uh+xl@!;y}>T`sqQYjEZz;WCkXA&U<;cys*LIF;v6DE@h zJkNvUIN0rWI2;ZXi$(11?SZCgq|<4LqKJco0}w(G2n3MHWU#cf1cqVI>2y?~?RFa$ ziv@naf8;^F9DieD1N-~?(ChUegdi4+A)C#DVHhM5iIMTPx3_V4cnF`*2cywAB77!< zvMj6K?Ah5F2qCz+xk0&H21QXLDI=H5!C)|;+wH<;vmqLds%;Ms52)2@YQH~z{D9Z% zh0Eo_)6>&0$9Fg!>TxI(g4t|V<4GhEaJgI%MG-ce4V#;r>bV@p!DKQam&<+LD}Qow z@~Un4m3^7(8jS`BA-K4>KsucUA!IDgW)l=ep;RjUQq*9!9UmY6_JIzMACJeeva+Hc zCzDB7tyTzv0E(i<#xgAV!-VoYkHy8sv5QhH7DFHq7`rG93oVz+Y96lF>!{c3sMTty z*Xs}j0XCZrkw`?n_VMxYRSpe>LaJuU$I!f z-=BIgU!8uxKUyEE< Date: Wed, 5 Jan 2022 17:17:29 -0300 Subject: [PATCH 2/2] chore(CheckableTag): Added new storyshots STC-825 --- .../CheckableTag/CheckableTag.stories.tsx | 17 +++++++++++++++-- .../CheckableTag/Default Checked/chrome.png | Bin 0 -> 438 bytes .../CheckableTag/Default Checked/firefox.png | Bin 0 -> 266 bytes .../CheckableTag/Labeled Checked/chrome.png | Bin 0 -> 1467 bytes .../CheckableTag/Labeled Checked/firefox.png | Bin 0 -> 1198 bytes 5 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 tests/images/Design System/CheckableTag/Default Checked/chrome.png create mode 100644 tests/images/Design System/CheckableTag/Default Checked/firefox.png create mode 100644 tests/images/Design System/CheckableTag/Labeled Checked/chrome.png create mode 100644 tests/images/Design System/CheckableTag/Labeled Checked/firefox.png diff --git a/src/components/CheckableTag/CheckableTag.stories.tsx b/src/components/CheckableTag/CheckableTag.stories.tsx index 464824b4..e16f17c4 100644 --- a/src/components/CheckableTag/CheckableTag.stories.tsx +++ b/src/components/CheckableTag/CheckableTag.stories.tsx @@ -8,8 +8,8 @@ export default { component: CheckableTag, } as Meta -const Template: Story = (props) => { - const [checked, setChecked] = useState(false) +const Template: Story = (props: CheckableTagProps) => { + const [checked, setChecked] = useState(props?.checked || false) return ( Px$a7jc#R9J=Wm``fLKop0+dHDlTEOg!O+C_RWhhbNF8#GT8or4s*AMec@!cQ4v3^jHd(j2k^at-?6sXL+|5{LsxA_(R1xvC3o zGx+%OE6^l2h@l_V%Gw;GF{1l{q{E73+?n}+jNXgX3wvrdDkiy zZR{{fR&=dWkrg1h?pmWF*C4*{85gwKPuVqb6Kdin)WlhY7AwPI)oy%4&o0cDhUYiU z;~h+f!O8o*R;ZK#czJ5~>Q=iJE5pNU!F*Y@r7klY3)7KmCFImHDmBIKL@aZ|f+6Kdl6gv8IZdO;LObVW6a z1SCHF58-UY0Z02 gE*a_dBHN}q-+a-LgdMv0od5s;07*qoM6N<$f_KxvY5)KL literal 0 HcmV?d00001 diff --git a/tests/images/Design System/CheckableTag/Default Checked/firefox.png b/tests/images/Design System/CheckableTag/Default Checked/firefox.png new file mode 100644 index 0000000000000000000000000000000000000000..800d64f2c4de1cc73e7e6091b1f488309aae1781 GIT binary patch literal 266 zcmV+l0rmcgP))fkq@#ONuy*$E4x_kc4#dlxXDalw}-1 zqY-6I&;(7;UxJj5P&�ty=^wjLVhBgA#@o#=8A5A*JI-(-xS+pxb@lycOouC(9A7 zFsEmzWim}bX`YV$;$1+kYl0?dg1UpmtwG`zMRBXNxMPFJbBxG?m6Vg-3phzoTmwrt Q%>V!Z07*qoM6N<$f`yuHuK)l5 literal 0 HcmV?d00001 diff --git a/tests/images/Design System/CheckableTag/Labeled Checked/chrome.png b/tests/images/Design System/CheckableTag/Labeled Checked/chrome.png new file mode 100644 index 0000000000000000000000000000000000000000..7f5da2c00ce94ba915a81d75a8265aa39d4ed9db GIT binary patch literal 1467 zcmV;s1w{IZP)Px)bxA})RA_E8U+_Bjn}v|KOPCKV~tlyfXbjNj*|!~qX~cv*l;n>yajTJ zVvoLP0&E5jd1Kk7}eFYZ- zFmsFI-2?8dqbZ5ngQ{xa`R{Bx`C#oNi%ve1ZfltLgW^<)xprw9q84b!Y0V!Mu9dhF;P;u@BbL>=OOJ+BeK z;LedRyE4UJXnq$Amq-D#wkWDbGHrk)`=}=Cpb3wwb2STgDS9Od zUKk{~6oe_?*j%Wr&->gZ$jq@Bo+4Oqf5X-A7n)*aVO->g`)yK$kv(UXMh;nqa>bgc2Jo^2#g zZcyZv7?JbKz@J$kBI7)gB?lFAhrrT9ipP2hJ{e;ge%b(wQzej8+uMUS%*e4x@WRJq zjQ9=FGYQ@sW%9^9Cpc83$$G@t=a&k8Dl|QN=^;f%s$g-Nv7OM{VsN(2SI0EZ4UE3m zUuNBL&7AEY6AJXjV>;B*z)6fDK*?+P8v~MA&y$^GrW;ue=&gUZ8Fax-UiG z^TMk?Dh710NRErP7WG&Hx+Fqsvf#yg>w9^?HiAZj5k!Vu-wV$bEMyjAHC|Q0)u{U4SHyPGUv}oTdJdYLQEgoHCGjF@%qcM$NxIWuo5MxO` zKcZNhtLfx}SB6PCMBzb32-&3K0Eoge?XFsykQ_x9Ki1kbdwd5MP)Y0Qlp{|ks$QJAZ1~*AR(v_f`UHyA$xnB`W|*>7^)f6e56_~DEH&>EswG9U2&o#++gB0-QS z=(?Qw;4Fr&%b>JNP|wxO2W3g5=jwGqqTrkd0E@pZ*Uu-b*!B~0m+2rZH^vI`I98Cyv4T8K%7PBH!;4!K(@KS@#lq8H3Dr${=zM;y z;<-&K?E&Aaa=l7Qf_Aq;PC&S;RCsy2;_dy4xs`&?FT8tDSwWc;)E0&N*9woU7fwc; z|2z8N)m@6E+Y}vrR*;*TW=&1APU+rp3#x9?`20fMsgV_)9hS%iHA2BwMRq`VbiJ^% z)w$P);hC?6{bxoB`r&WL4hZiY7%41X|4Z8x zxh2Bj>5x1VNRt`d{py6NRu59-Vd2XmmMloyntR<-?i6Ktprf+sY0tWNAAR~^yhmYC~j z14o{Hwuqc31=>jUjLj*=dCT+s<>~h49Q%+S23^3oSzjG-q_>R z7mmX8GGWz`n@egmwb}o7F2Ph2Rq2>I<1Vv(y7ZjFkQA4rB<8im}v2aUCmzYvQ4YD$qQJAR+L+>;Twca8AM_T;m;n-vs)Ddts~S>x<=LPd%R zp2(Cst%5AK2P??qSV11g3i3EskjJrtJdRy7;$b@b!DpBJdYA42yKvFd#0KrsU(YhM z^cSGlE}r)sy;ohk8??6DPrO9;fU`%)Zs775NjGrWEs&XGtSylL0d<7&%#pX06aWAK M07*qoM6N<$g6CRV+W-In literal 0 HcmV?d00001