/
opt
/
canhelp
/
node_modules
/
better-auth
/
node_modules
/
zod
/
src
/
v4
/
classic
/
tests
/
/opt/canhelp/node_modules/better-auth/node_modules/zod/src/v4/classic/tests
mkdir
upload
Name
Size
Mode
Actions
anyunknown.test.ts
639
0644
edit
dl
rm
apply.test.ts
1509
0644
edit
dl
rm
array.test.ts
7248
0644
edit
dl
rm
assignability.test.ts
6790
0644
edit
dl
rm
async-parsing.test.ts
12311
0644
edit
dl
rm
async-refinements.test.ts
1867
0644
edit
dl
rm
base.test.ts
179
0644
edit
dl
rm
bigint.test.ts
1956
0644
edit
dl
rm
brand.test.ts
3574
0644
edit
dl
rm
catch.test.ts
7831
0644
edit
dl
rm
coalesce.test.ts
743
0644
edit
dl
rm
codec-examples.test.ts
19030
0644
edit
dl
rm
codec.test.ts
18853
0644
edit
dl
rm
coerce.test.ts
7736
0644
edit
dl
rm
continuability.test.ts
8020
0644
edit
dl
rm
custom.test.ts
1215
0644
edit
dl
rm
date.test.ts
1671
0644
edit
dl
rm
datetime.test.ts
11932
0644
edit
dl
rm
default.test.ts
9226
0644
edit
dl
rm
describe-meta-checks.test.ts
965
0644
edit
dl
rm
description.test.ts
1294
0644
edit
dl
rm
discriminated-unions.test.ts
17665
0644
edit
dl
rm
enum.test.ts
8488
0644
edit
dl
rm
error-utils.test.ts
13744
0644
edit
dl
rm
error.test.ts
19502
0644
edit
dl
rm
file.test.ts
2641
0644
edit
dl
rm
firstparty.test.ts
3045
0644
edit
dl
rm
fix-json-issue.test.ts
771
0644
edit
dl
rm
from-json-schema.test.ts
21498
0644
edit
dl
rm
function.test.ts
8344
0644
edit
dl
rm
generics.test.ts
2162
0644
edit
dl
rm
hash.test.ts
3204
0644
edit
dl
rm
index.test.ts
31191
0644
edit
dl
rm
instanceof.test.ts
1658
0644
edit
dl
rm
intersection.test.ts
5555
0644
edit
dl
rm
json.test.ts
3327
0644
edit
dl
rm
lazy.test.ts
4756
0644
edit
dl
rm
literal.test.ts
3095
0644
edit
dl
rm
map.test.ts
7622
0644
edit
dl
rm
nan.test.ts
645
0644
edit
dl
rm
nested-refine.test.ts
3623
0644
edit
dl
rm
nonoptional.test.ts
2841
0644
edit
dl
rm
nullable.test.ts
591
0644
edit
dl
rm
number.test.ts
8644
0644
edit
dl
rm
object.test.ts
18481
0644
edit
dl
rm
optional.test.ts
7332
0644
edit
dl
rm
partial.test.ts
12973
0644
edit
dl
rm
pickomit.test.ts
6885
0644
edit
dl
rm
pipe.test.ts
2338
0644
edit
dl
rm
prefault.test.ts
2063
0644
edit
dl
rm
preprocess.test.ts
6522
0644
edit
dl
rm
primitive.test.ts
7649
0644
edit
dl
rm
promise.test.ts
2324
0644
edit
dl
rm
prototypes.test.ts
498
0644
edit
dl
rm
readonly.test.ts
11786
0644
edit
dl
rm
record.test.ts
17226
0644
edit
dl
rm
recursive-types.test.ts
12693
0644
edit
dl
rm
refine.test.ts
15649
0644
edit
dl
rm
registries.test.ts
7391
0644
edit
dl
rm
set.test.ts
5622
0644
edit
dl
rm
standard-schema.test.ts
3770
0644
edit
dl
rm
string-formats.test.ts
3700
0644
edit
dl
rm
string.test.ts
78069
0644
edit
dl
rm
stringbool.test.ts
3536
0644
edit
dl
rm
template-literal.test.ts
35894
0644
edit
dl
rm
to-json-schema-methods.test.ts
10100
0644
edit
dl
rm
to-json-schema.test.ts
78639
0644
edit
dl
rm
transform.test.ts
8298
0644
edit
dl
rm
tuple.test.ts
5532
0644
edit
dl
rm
union.test.ts
5936
0644
edit
dl
rm
url.test.ts
402
0644
edit
dl
rm
validations.test.ts
6736
0644
edit
dl
rm
void.test.ts
306
0644
edit
dl
rm
Edit:
/opt/canhelp/node_modules/better-auth/node_modules/zod/src/v4/classic/tests/string.test.ts
(78069B)
import { randomBytes } from "node:crypto"; import { expect, test } from "vitest"; import * as z from "zod/v4"; const minFive = z.string().min(5, "min5"); const maxFive = z.string().max(5, "max5"); const justFive = z.string().length(5); const nonempty = z.string().min(1, "nonempty"); const includes = z.string().includes("includes"); const includesFromIndex2 = z.string().includes("includes", { position: 2 }); const startsWith = z.string().startsWith("startsWith"); const endsWith = z.string().endsWith("endsWith"); test("length checks", () => { minFive.parse("12345"); minFive.parse("123456"); maxFive.parse("12345"); maxFive.parse("1234"); nonempty.parse("1"); justFive.parse("12345"); expect(() => minFive.parse("1234")).toThrow(); expect(() => maxFive.parse("123456")).toThrow(); expect(() => nonempty.parse("")).toThrow(); expect(() => justFive.parse("1234")).toThrow(); expect(() => justFive.parse("123456")).toThrow(); }); test("includes", () => { includes.parse("XincludesXX"); includesFromIndex2.parse("XXXincludesXX"); expect(() => includes.parse("XincludeXX")).toThrow(); expect(() => includesFromIndex2.parse("XincludesXX")).toThrow(); }); test("includes with string error message", () => { const schema = z.string().includes("test", "must contain test"); schema.parse("this is a test"); expect(schema.safeParse("this is invalid")).toMatchInlineSnapshot(` { "error": [ZodError: [ { "origin": "string", "code": "invalid_format", "format": "includes", "includes": "test", "path": [], "message": "must contain test" } ]], "success": false, } `); }); test("startswith/endswith", () => { startsWith.parse("startsWithX"); endsWith.parse("XendsWith"); expect(() => startsWith.parse("x")).toThrow(); expect(() => endsWith.parse("x")).toThrow(); }); test("email validations", () => { const validEmails = [ `email@domain.com`, `firstname.lastname@domain.com`, `email@subdomain.domain.com`, `firstname+lastname@domain.com`, `1234567890@domain.com`, `email@domain-one.com`, `_______@domain.com`, `email@domain.name`, `email@domain.co.jp`, `firstname-lastname@domain.com`, `very.common@example.com`, `disposable.style.email.with+symbol@example.com`, `other.email-with-hyphen@example.com`, `fully-qualified-domain@example.com`, `user.name+tag+sorting@example.com`, `x@example.com`, `mojojojo@asdf.example.com`, `example-indeed@strange-example.com`, `example@s.example`, `user-@example.org`, `user@my-example.com`, `a@b.cd`, `work+user@mail.com`, `tom@test.te-st.com`, `something@subdomain.domain-with-hyphens.tld`, `common'name@domain.com`, `francois@etu.inp-n7.fr`, ]; const invalidEmails = [ // no "printable characters" // `user%example.com@example.org`, // `mailhost!username@example.org`, // `test/test@test.com`, // double @ `francois@@etu.inp-n7.fr`, // do not support quotes `"email"@domain.com`, `"e asdf sadf ?<>ail"@domain.com`, `" "@example.org`, `"john..doe"@example.org`, `"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com`, // do not support comma `a,b@domain.com`, // do not support IPv4 `email@123.123.123.123`, `email@[123.123.123.123]`, `postmaster@123.123.123.123`, `user@[68.185.127.196]`, `ipv4@[85.129.96.247]`, `valid@[79.208.229.53]`, `valid@[255.255.255.255]`, `valid@[255.0.55.2]`, `valid@[255.0.55.2]`, // do not support ipv6 `hgrebert0@[IPv6:4dc8:ac7:ce79:8878:1290:6098:5c50:1f25]`, `bshapiro4@[IPv6:3669:c709:e981:4884:59a3:75d1:166b:9ae]`, `jsmith@[IPv6:2001:db8::1]`, `postmaster@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]`, `postmaster@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:192.168.1.1]`, // microsoft test cases `plainaddress`, `#@%^%#$@#$@#.com`, `@domain.com`, `Joe Smith <email@domain.com>`, `email.domain.com`, `email@domain@domain.com`, `.email@domain.com`, `email.@domain.com`, `email..email@domain.com`, `ใใใใใ@domain.com`, `email@domain.com (Joe Smith)`, `email@domain`, `email@-domain.com`, `email@111.222.333.44444`, `email@domain..com`, `Abc.example.com`, `A@b@c@example.com`, `colin..hacks@domain.com`, `a"b(c)d,e:f;g<h>i[j\k]l@example.com`, `just"not"right@example.com`, `this is"not\allowed@example.com`, `this\ still\"not\\allowed@example.com`, // random `i_like_underscore@but_its_not_allowed_in_this_part.example.com`, `QA[icon]CHOCOLATE[icon]@test.com`, `invalid@-start.com`, `invalid@end.com-`, `a.b@c.d`, `invalid@[1.1.1.-1]`, `invalid@[68.185.127.196.55]`, `temp@[192.168.1]`, `temp@[9.18.122.]`, `double..point@test.com`, `asdad@test..com`, `asdad@hghg...sd...au`, `asdad@hghg........au`, `invalid@[256.2.2.48]`, `invalid@[256.2.2.48]`, `invalid@[999.465.265.1]`, `jkibbey4@[IPv6:82c4:19a8::70a9:2aac:557::ea69:d985:28d]`, `mlivesay3@[9952:143f:b4df:2179:49a1:5e82:b92e:6b6]`, `gbacher0@[IPv6:bc37:4d3f:5048:2e26:37cc:248e:df8e:2f7f:af]`, `invalid@[IPv6:5348:4ed3:5d38:67fb:e9b:acd2:c13:192.168.256.1]`, `test@.com`, `aaaaaaaaaaaaaaalongemailthatcausesregexDoSvulnerability@test.c`, ]; const emailSchema = z.string().email(); expect( validEmails.every((email) => { return emailSchema.safeParse(email).success; }) ).toBe(true); expect( invalidEmails.every((email) => { return emailSchema.safeParse(email).success === false; }) ).toBe(true); }); test("base64 validations", () => { const validBase64Strings = [ "SGVsbG8gV29ybGQ=", // "Hello World" "VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw==", // "This is an encoded string" "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcms=", // "Many hands make light work" "UGF0aWVuY2UgaXMgdGhlIGtleSB0byBzdWNjZXNz", // "Patience is the key to success" "QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg==", // "Base64 encoding is fun" "MTIzNDU2Nzg5MA==", // "1234567890" "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=", // "abcdefghijklmnopqrstuvwxyz" "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=", // "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "ISIkJSMmJyonKCk=", // "!\"#$%&'()*" "", // Empty string is technically a valid base64 ]; for (const str of validBase64Strings) { expect(str + z.string().base64().safeParse(str).success).toBe(`${str}true`); } const invalidBase64Strings = [ "12345", // Not padded correctly, not a multiple of 4 characters "SGVsbG8gV29ybGQ", // Missing padding "VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw", // Missing padding "!UGF0aWVuY2UgaXMgdGhlIGtleSB0byBzdWNjZXNz", // Invalid character '!' "?QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg==", // Invalid character '?' ".MTIzND2Nzg5MC4=", // Invalid character '.' "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo", // Missing padding ]; for (const str of invalidBase64Strings) { expect(str + z.string().base64().safeParse(str).success).toBe(`${str}false`); } }); test("base64url validations", () => { const base64url = z.string().base64url(); const validBase64URLStrings = [ "SGVsbG8gV29ybGQ", // "Hello World" "VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw", // "This is an encoded string" "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcms", // "Many hands make light work" "UGF0aWVuY2UgaXMgdGhlIGtleSB0byBzdWNjZXNz", // "Patience is the key to success" "QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg", // "Base64 encoding is fun" "MTIzNDU2Nzg5MA", // "1234567890" "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo", // "abcdefghijklmnopqrstuvwxyz" "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo", // "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "ISIkJSMmJyonKCk", // "!\"#$%&'()*" "", // Empty string is technically valid base64url "w7_Dv8O-w74K", // รฟรฟรพรพ "123456", ]; for (const str of validBase64URLStrings) { expect(str + base64url.safeParse(str).success).toBe(`${str}true`); } const invalidBase64URLStrings = [ "w7/Dv8O+w74K", // Has + and / characters (is base64) "12345", // Invalid length (not a multiple of 4 characters when adding allowed number of padding characters) "12345===", // Not padded correctly "!UGF0aWVuY2UgaXMgdGhlIGtleSB0byBzdWNjZXNz", // Invalid character '!' "?QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg==", // Invalid character '?' ".MTIzND2Nzg5MC4=", // Invalid character '.' // disallow valid padding "SGVsbG8gV29ybGQ=", // "Hello World" with padding "VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw==", // "This is an encoded string" with padding "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcms=", // "Many hands make light work" with padding "QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg==", // "Base64 encoding is fun" with padding "MTIzNDU2Nzg5MA==", // "1234567890" with padding "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=", // "abcdefghijklmnopqrstuvwxyz with padding" "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=", // "ABCDEFGHIJKLMNOPQRSTUVWXYZ" with padding "ISIkJSMmJyonKCk=", // "!\"#$%&'()*" with padding ]; for (const str of invalidBase64URLStrings) { expect(str + base64url.safeParse(str).success).toBe(`${str}false`); } }); test("big base64 and base64url", () => { const bigbase64 = randomBytes(1024 * 1024 * 10).toString("base64"); z.base64().parse(bigbase64); const bigbase64url = randomBytes(1024 * 1024 * 10).toString("base64url"); z.base64url().parse(bigbase64url); }); function makeJwt(header: object, payload: object) { const headerBase64 = Buffer.from(JSON.stringify(header)).toString("base64url"); const payloadBase64 = Buffer.from(JSON.stringify(payload)).toString("base64url"); const signature = "signature"; // Placeholder for the signature return `${headerBase64}.${payloadBase64}.${signature}`; } test("jwt token", () => { const jwt = z.string().jwt(); expect(() => jwt.parse("invalid")).toThrow(); expect(() => jwt.parse("invalid.invalid")).toThrow(); expect(() => jwt.parse("invalid.invalid.invalid")).toThrow(); // Valid JWTs const es256jwt = z.string().jwt({ alg: "ES256" }); const d1 = makeJwt({ typ: "JWT", alg: "ES256" }, {}); jwt.parse(d1); es256jwt.parse(d1); // Invalid header const d2 = makeJwt({}, {}); expect(() => jwt.parse(d2)).toThrow(); // Wrong algorithm const d3 = makeJwt({ typ: "JWT", alg: "RS256" }, {}); expect(() => es256jwt.parse(d3)).toThrow(); // missing typ is fine const d4 = makeJwt({ alg: "HS256" }, {}); jwt.parse(d4); // type isn't JWT const d5 = makeJwt({ typ: "SUP", alg: "HS256" }, { foo: "bar" }); expect(() => jwt.parse(d5)).toThrow(); }); test("url validations", () => { const url = z.string().url(); url.parse("http://google.com"); url.parse("https://google.com/asdf?asdf=ljk3lk4&asdf=234#asdf"); url.parse("https://anonymous:flabada@developer.mozilla.org/en-US/docs/Web/API/URL/password"); url.parse("https://localhost"); url.parse("https://my.local"); url.parse("http://aslkfjdalsdfkjaf"); url.parse("http://localhost"); url.parse("c:"); expect(() => url.parse("asdf")).toThrow(); expect(() => url.parse("https:/")).toThrow(); expect(() => url.parse("asdfj@lkjsdf.com")).toThrow(); expect(() => url.parse("https://")).toThrow(); }); test("url preserves original input", () => { const url = z.string().url(); // Test the specific case from the user report const input = "https://example.com?key=NUXOmHqWNVTapJkJJHw8BfD155AuqhH_qju_5fNmQ4ZHV7u8"; const output = url.parse(input); expect(output).toBe(input); // Should preserve the original input exactly // Test other cases where URL constructor would normalize expect(url.parse("https://example.com?foo=bar")).toBe("https://example.com?foo=bar"); expect(url.parse("http://example.com?test=123")).toBe("http://example.com?test=123"); expect(url.parse("https://sub.example.com?param=value&other=data")).toBe( "https://sub.example.com?param=value&other=data" ); // Test cases with trailing slashes are preserved expect(url.parse("https://example.com/")).toBe("https://example.com/"); expect(url.parse("https://example.com/path/")).toBe("https://example.com/path/"); // Test cases with paths and query parameters expect(url.parse("https://example.com/path?query=param")).toBe("https://example.com/path?query=param"); }); test("url trims whitespace", () => { const url = z.string().url(); // Test trimming whitespace from URLs expect(url.parse(" https://example.com ")).toBe("https://example.com"); expect(url.parse(" https://example.com/path?query=param ")).toBe("https://example.com/path?query=param"); expect(url.parse("\t\nhttps://example.com\t\n")).toBe("https://example.com"); expect(url.parse(" https://example.com?key=value ")).toBe("https://example.com?key=value"); // Test that URLs without extra whitespace are unchanged expect(url.parse("https://example.com")).toBe("https://example.com"); expect(url.parse("https://example.com/path")).toBe("https://example.com/path"); }); test("url normalize flag", () => { const normalizeUrl = z.url({ normalize: true }); const preserveUrl = z.url(); // normalize: false/undefined by default // Test that normalize flag causes URL normalization expect(normalizeUrl.parse("https://example.com?key=value")).toBe("https://example.com/?key=value"); expect(normalizeUrl.parse("http://example.com?test=123")).toBe("http://example.com/?test=123"); // Test with already normalized URLs expect(normalizeUrl.parse("https://example.com/")).toBe("https://example.com/"); expect(normalizeUrl.parse("https://example.com/path?query=param")).toBe("https://example.com/path?query=param"); // Test complex URLs with normalization expect(normalizeUrl.parse("https://example.com/../?key=value")).toBe("https://example.com/?key=value"); expect(normalizeUrl.parse("https://example.com/./path?key=value")).toBe("https://example.com/path?key=value"); // Compare with non-normalize behavior expect(preserveUrl.parse("https://example.com?key=value")).toBe("https://example.com?key=value"); expect(preserveUrl.parse("http://example.com?test=123")).toBe("http://example.com?test=123"); // Test trimming with normalize expect(normalizeUrl.parse(" https://example.com?key=value ")).toBe("https://example.com/?key=value"); expect(preserveUrl.parse(" https://example.com?key=value ")).toBe("https://example.com?key=value"); }); test("url normalize with hostname and protocol constraints", () => { const constrainedNormalizeUrl = z.url({ normalize: true, protocol: /^https$/, hostname: /^example\.com$/, }); // Test that normalization works with constraints expect(constrainedNormalizeUrl.parse("https://example.com?key=value")).toBe("https://example.com/?key=value"); // Test that constraints are still enforced expect(() => constrainedNormalizeUrl.parse("http://example.com?key=value")).toThrow(); expect(() => constrainedNormalizeUrl.parse("https://other.com?key=value")).toThrow(); }); test("httpurl", () => { const httpUrl = z.url({ protocol: /^https?$/, hostname: z.regexes.domain, // /^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/ }); httpUrl.parse("https://example.com"); httpUrl.parse("http://example.com"); // ports httpUrl.parse("https://example.com:8080"); httpUrl.parse("http://example.com:8080"); // subdomains httpUrl.parse("https://sub.example.com"); httpUrl.parse("http://sub.example.com"); // paths httpUrl.parse("https://example.com/path/to/resource"); httpUrl.parse("http://example.com/path/to/resource"); // query parameters httpUrl.parse("https://example.com/path?query=param"); httpUrl.parse("http://example.com/path?query=param"); // fragment identifiers httpUrl.parse("https://example.com/path#fragment"); httpUrl.parse("http://example.com/path#fragment"); // fails expect(() => httpUrl.parse("ftp://example.com")).toThrow(); expect(() => httpUrl.parse("shttp://example.com")).toThrow(); expect(() => httpUrl.parse("httpz://example.com")).toThrow(); expect(() => httpUrl.parse("http://")).toThrow(); expect(() => httpUrl.parse("http://localhost")).toThrow(); expect(() => httpUrl.parse("http://-asdf.com")).toThrow(); expect(() => httpUrl.parse( "http://asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf.com" ) ).toThrow(); expect(() => httpUrl.parse("http://asdf.c")).toThrow(); expect(() => httpUrl.parse("mailto:asdf@lckj.com")).toThrow(); }); test("url error overrides", () => { try { z.string().url().parse("https"); } catch (err) { expect((err as z.ZodError).issues[0].message).toEqual("Invalid URL"); } try { z.string().url("badurl").parse("https"); } catch (err) { expect((err as z.ZodError).issues[0].message).toEqual("badurl"); } try { z.string().url({ message: "badurl" }).parse("https"); } catch (err) { expect((err as z.ZodError).issues[0].message).toEqual("badurl"); } }); test("emoji validations", () => { const emoji = z.string().emoji(); emoji.parse("๐๐๐๐"); emoji.parse("๐บ๐ฉโ๐๐ซก"); emoji.parse("๐๐๐๐โค๏ธ"); emoji.parse("๐๐๐๐ก๐ฆ๐ข๐จ๐ซ๐โ๐ก๐น๐๐ฌโก๏ธ๐น๐๐จโ๐ใฝ๏ธ๐ฆ๐๐ด๐๐๐ฐ๐ณ๐บ๐"); emoji.parse("๐น๐ท๐คฝ๐ฟโโ๏ธ"); emoji.parse( "๐๐๐๐คฃ๐๐๐ ๐๐๐๐๐๐๐๐ฅฐ๐๐๐โบ๏ธโบ๐๐ค๐คฉ๐ค๐คจ๐๐๐ถ๐๐๐ฃ๐ฅ๐ฎ๐ค๐ฏ๐ช๐ซ๐ด๐๐๐๐๐คค๐๐๐๐๐๐ค๐ฒโน๏ธโน๐๐๐๐๐ค๐ข๐ญ๐ฆ๐ง๐จ๐ฉ๐คฏ๐ฌ๐ฐ๐ฑ๐ฅต๐ฅถ๐ณ๐คช๐ต๐ก๐ ๐คฌ๐ท๐ค๐ค๐คข๐คฎ๐คง๐๐ค ๐ฅณ๐ฅด๐ฅบ๐คฅ๐คซ๐คญ๐ง๐ค๐๐ฟ๐คก๐น๐บ๐โ ๏ธโ ๐ป๐ฝ๐พ๐ค๐ฉ๐บ๐ธ๐น๐ป๐ผ๐ฝ๐๐ฟ๐พ๐๐๐๐ป๐ผ๐ฝ๐พ๐ฟ๐ถ๐ถ๐ป๐ถ๐ผ๐ถ๐ฝ๐ถ๐พ๐ถ๐ฟ๐ง๐ง๐ป๐ง๐ผ๐ง๐ฝ๐ง๐พ๐ง๐ฟ๐ฆ๐ฆ๐ป๐ฆ๐ผ๐ฆ๐ฝ๐ฆ๐พ๐ฆ๐ฟ๐ง๐ง๐ป๐ง๐ผ๐ง๐ฝ๐ง๐พ๐ง๐ฟ๐ง๐ง๐ป๐ง๐ผ๐ง๐ฝ๐ง๐พ๐ง๐ฟ๐จ๐จ๐ป๐จ๐ผ๐จ๐ฝ๐จ๐พ๐จ๐ฟ๐ฉ๐ฉ๐ป๐ฉ๐ผ๐ฉ๐ฝ๐ฉ๐พ๐ฉ๐ฟ๐ง๐ง๐ป๐ง๐ผ๐ง๐ฝ๐ง๐พ๐ง๐ฟ๐ด๐ด๐ป๐ด๐ผ๐ด๐ฝ๐ด๐พ๐ด๐ฟ๐ต๐ต๐ป๐ต๐ผ๐ต๐ฝ๐ต๐พ๐ต๐ฟ๐จโโ๏ธ๐จโโ๐จ๐ปโโ๏ธ๐จ๐ปโโ๐จ๐ผโโ๏ธ๐จ๐ผโโ๐จ๐ฝโโ๏ธ๐จ๐ฝโโ๐จ๐พโโ๏ธ๐จ๐พโโ๐จ๐ฟโโ๏ธ๐จ๐ฟโโ๐ฉโโ๏ธ๐ฉโโ๐ฉ๐ปโโ๏ธ๐ฉ๐ปโโ๐ฉ๐ผโโ๏ธ๐ฉ๐ผโโ๐ฉ๐ฝโโ๏ธ๐ฉ๐ฝโโ๐ฉ๐พโโ๏ธ๐ฉ๐พโโ๐ฉ๐ฟโโ๏ธ๐ฉ๐ฟโโ๐จโ๐๐จ๐ปโ๐๐จ๐ผโ๐๐จ๐ฝโ๐๐จ๐พโ๐๐จ๐ฟโ๐๐ฉโ๐๐ฉ๐ปโ๐๐ฉ๐ผโ๐๐ฉ๐ฝโ๐๐ฉ๐พโ๐๐ฉ๐ฟโ๐๐จโ๐ซ๐จ๐ปโ๐ซ๐จ๐ผโ๐ซ๐จ๐ฝโ๐ซ๐จ๐พโ๐ซ๐จ๐ฟโ๐ซ๐ฉโ๐ซ๐ฉ๐ปโ๐ซ๐ฉ๐ผโ๐ซ๐ฉ๐ฝโ๐ซ๐ฉ๐พโ๐ซ๐ฉ๐ฟโ๐ซ๐จโโ๏ธ๐จโโ๐จ๐ปโโ๏ธ๐จ๐ปโโ๐จ๐ผโโ๏ธ๐จ๐ผโโ๐จ๐ฝโโ๏ธ๐จ๐ฝโโ๐จ๐พโโ๏ธ๐จ๐พโโ๐จ๐ฟโโ๏ธ๐จ๐ฟโโ๐ฉโโ๏ธ๐ฉโโ๐ฉ๐ปโโ๏ธ๐ฉ๐ปโโ๐ฉ๐ผโโ๏ธ๐ฉ๐ผโโ๐ฉ๐ฝโโ๏ธ๐ฉ๐ฝโโ๐ฉ๐พโโ๏ธ๐ฉ๐พโโ๐ฉ๐ฟโโ๏ธ๐ฉ๐ฟโโ๐จโ๐พ๐จ๐ปโ๐พ๐จ๐ผโ๐พ๐จ๐ฝโ๐พ๐จ๐พโ๐พ๐จ๐ฟโ๐พ๐ฉโ๐พ๐ฉ๐ปโ๐พ๐ฉ๐ผโ๐พ๐ฉ๐ฝโ๐พ๐ฉ๐พโ๐พ๐ฉ๐ฟโ๐พ๐จโ๐ณ๐จ๐ปโ๐ณ๐จ๐ผโ๐ณ๐จ๐ฝโ๐ณ๐จ๐พโ๐ณ๐จ๐ฟโ๐ณ๐ฉโ๐ณ๐ฉ๐ปโ๐ณ๐ฉ๐ผโ๐ณ๐ฉ๐ฝโ๐ณ๐ฉ๐พโ๐ณ๐ฉ๐ฟโ๐ณ๐จโ๐ง๐จ๐ปโ๐ง๐จ๐ผโ๐ง๐จ๐ฝโ๐ง๐จ๐พโ๐ง๐จ๐ฟโ๐ง๐ฉโ๐ง๐ฉ๐ปโ๐ง๐ฉ๐ผโ๐ง๐ฉ๐ฝโ๐ง๐ฉ๐พโ๐ง๐ฉ๐ฟโ๐ง๐จโ๐ญ๐จ๐ปโ๐ญ๐จ๐ผโ๐ญ๐จ๐ฝโ๐ญ๐จ๐พโ๐ญ๐จ๐ฟโ๐ญ๐ฉโ๐ญ๐ฉ๐ปโ๐ญ๐ฉ๐ผโ๐ญ๐ฉ๐ฝโ๐ญ๐ฉ๐พโ๐ญ๐ฉ๐ฟโ๐ญ๐จโ๐ผ๐จ๐ปโ๐ผ๐จ๐ผโ๐ผ๐จ๐ฝโ๐ผ๐จ๐พโ๐ผ๐จ๐ฟโ๐ผ๐ฉโ๐ผ๐ฉ๐ปโ๐ผ๐ฉ๐ผโ๐ผ๐ฉ๐ฝโ๐ผ๐ฉ๐พโ๐ผ๐ฉ๐ฟโ๐ผ๐จโ๐ฌ๐จ๐ปโ๐ฌ๐จ๐ผโ๐ฌ๐จ๐ฝโ๐ฌ๐จ๐พโ๐ฌ๐จ๐ฟโ๐ฌ๐ฉโ๐ฌ๐ฉ๐ปโ๐ฌ๐ฉ๐ผโ๐ฌ๐ฉ๐ฝโ๐ฌ๐ฉ๐พโ๐ฌ๐ฉ๐ฟโ๐ฌ๐จโ๐ป๐จ๐ปโ๐ป๐จ๐ผโ๐ป๐จ๐ฝโ๐ป๐จ๐พโ๐ป๐จ๐ฟโ๐ป๐ฉโ๐ป๐ฉ๐ปโ๐ป๐ฉ๐ผโ๐ป๐ฉ๐ฝโ๐ป๐ฉ๐พโ๐ป๐ฉ๐ฟโ๐ป๐จโ๐ค๐จ๐ปโ๐ค๐จ๐ผโ๐ค๐จ๐ฝโ๐ค๐จ๐พโ๐ค๐จ๐ฟโ๐ค๐ฉโ๐ค๐ฉ๐ปโ๐ค๐ฉ๐ผโ๐ค๐ฉ๐ฝโ๐ค๐ฉ๐พโ๐ค๐ฉ๐ฟโ๐ค๐จโ๐จ๐จ๐ปโ๐จ๐จ๐ผโ๐จ๐จ๐ฝโ๐จ๐จ๐พโ๐จ๐จ๐ฟโ๐จ๐ฉโ๐จ๐ฉ๐ปโ๐จ๐ฉ๐ผโ๐จ๐ฉ๐ฝโ๐จ๐ฉ๐พโ๐จ๐ฉ๐ฟโ๐จ๐จโโ๏ธ๐จโโ๐จ๐ปโโ๏ธ๐จ๐ปโโ๐จ๐ผโโ๏ธ๐จ๐ผโโ๐จ๐ฝโโ๏ธ๐จ๐ฝโโ๐จ๐พโโ๏ธ๐จ๐พโโ๐จ๐ฟโโ๏ธ๐จ๐ฟโโ๐ฉโโ๏ธ๐ฉโโ๐ฉ๐ปโโ๏ธ๐ฉ๐ปโโ๐ฉ๐ผโโ๏ธ๐ฉ๐ผโโ๐ฉ๐ฝโโ๏ธ๐ฉ๐ฝโโ๐ฉ๐พโโ๏ธ๐ฉ๐พโโ๐ฉ๐ฟโโ๏ธ๐ฉ๐ฟโโ๐จโ๐๐จ๐ปโ๐๐จ๐ผโ๐๐จ๐ฝโ๐๐จ๐พโ๐๐จ๐ฟโ๐๐ฉโ๐๐ฉ๐ปโ๐๐ฉ๐ผโ๐๐ฉ๐ฝโ๐๐ฉ๐พโ๐๐ฉ๐ฟโ๐๐จโ๐๐จ๐ปโ๐๐จ๐ผโ๐๐จ๐ฝโ๐๐จ๐พโ๐๐จ๐ฟโ๐๐ฉโ๐๐ฉ๐ปโ๐๐ฉ๐ผโ๐๐ฉ๐ฝโ๐๐ฉ๐พโ๐๐ฉ๐ฟโ๐๐ฎ๐ฎ๐ป๐ฎ๐ผ๐ฎ๐ฝ๐ฎ๐พ๐ฎ๐ฟ๐ฎโโ๏ธ๐ฎโโ๐ฎ๐ปโโ๏ธ๐ฎ๐ปโโ๐ฎ๐ผโโ๏ธ๐ฎ๐ผโโ๐ฎ๐ฝโโ๏ธ๐ฎ๐ฝโโ๐ฎ๐พโโ๏ธ๐ฎ๐พโโ๐ฎ๐ฟโโ๏ธ๐ฎ๐ฟโโ๐ฎโโ๏ธ๐ฎโโ๐ฎ๐ปโโ๏ธ๐ฎ๐ปโโ๐ฎ๐ผโโ๏ธ๐ฎ๐ผโโ๐ฎ๐ฝโโ๏ธ๐ฎ๐ฝโโ๐ฎ๐พโโ๏ธ๐ฎ๐พโโ๐ฎ๐ฟโโ๏ธ๐ฎ๐ฟโโ๐ต๏ธ๐ต๐ต๐ป๐ต๐ผ๐ต๐ฝ๐ต๐พ๐ต๐ฟ๐ต๏ธโโ๏ธ๐ตโโ๏ธ๐ต๏ธโโ๐ตโโ๐ต๐ปโโ๏ธ๐ต๐ปโโ๐ต๐ผโโ๏ธ๐ต๐ผโโ๐ต๐ฝโโ๏ธ๐ต๐ฝโโ๐ต๐พโโ๏ธ๐ต๐พโโ๐ต๐ฟโโ๏ธ๐ต๐ฟโโ๐ต๏ธโโ๏ธ๐ตโโ๏ธ๐ต๏ธโโ๐ตโโ๐ต๐ปโโ๏ธ๐ต๐ปโโ๐ต๐ผโโ๏ธ๐ต๐ผโโ๐ต๐ฝโโ๏ธ๐ต๐ฝโโ๐ต๐พโโ๏ธ๐ต๐พโโ๐ต๐ฟโโ๏ธ๐ต๐ฟโโ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐ท๐ท๐ป๐ท๐ผ๐ท๐ฝ๐ท๐พ๐ท๐ฟ๐ทโโ๏ธ๐ทโโ๐ท๐ปโโ๏ธ๐ท๐ปโโ๐ท๐ผโโ๏ธ๐ท๐ผโโ๐ท๐ฝโโ๏ธ๐ท๐ฝโโ๐ท๐พโโ๏ธ๐ท๐พโโ๐ท๐ฟโโ๏ธ๐ท๐ฟโโ๐ทโโ๏ธ๐ทโโ๐ท๐ปโโ๏ธ๐ท๐ปโโ๐ท๐ผโโ๏ธ๐ท๐ผโโ๐ท๐ฝโโ๏ธ๐ท๐ฝโโ๐ท๐พโโ๏ธ๐ท๐พโโ๐ท๐ฟโโ๏ธ๐ท๐ฟโโ๐คด๐คด๐ป๐คด๐ผ๐คด๐ฝ๐คด๐พ๐คด๐ฟ๐ธ๐ธ๐ป๐ธ๐ผ๐ธ๐ฝ๐ธ๐พ๐ธ๐ฟ๐ณ๐ณ๐ป๐ณ๐ผ๐ณ๐ฝ๐ณ๐พ๐ณ๐ฟ๐ณโโ๏ธ๐ณโโ๐ณ๐ปโโ๏ธ๐ณ๐ปโโ๐ณ๐ผโโ๏ธ๐ณ๐ผโโ๐ณ๐ฝโโ๏ธ๐ณ๐ฝโโ๐ณ๐พโโ๏ธ๐ณ๐พโโ๐ณ๐ฟโโ๏ธ๐ณ๐ฟโโ๐ณโโ๏ธ๐ณโโ๐ณ๐ปโโ๏ธ๐ณ๐ปโโ๐ณ๐ผโโ๏ธ๐ณ๐ผโโ๐ณ๐ฝโโ๏ธ๐ณ๐ฝโโ๐ณ๐พโโ๏ธ๐ณ๐พโโ๐ณ๐ฟโโ๏ธ๐ณ๐ฟโโ๐ฒ๐ฒ๐ป๐ฒ๐ผ๐ฒ๐ฝ๐ฒ๐พ๐ฒ๐ฟ๐ง๐ง๐ป๐ง๐ผ๐ง๐ฝ๐ง๐พ๐ง๐ฟ๐ง๐ง๐ป๐ง๐ผ๐ง๐ฝ๐ง๐พ๐ง๐ฟ๐ฑ๐ฑ๐ป๐ฑ๐ผ๐ฑ๐ฝ๐ฑ๐พ๐ฑ๐ฟ๐ฑโโ๏ธ๐ฑโโ๐ฑ๐ปโโ๏ธ๐ฑ๐ปโโ๐ฑ๐ผโโ๏ธ๐ฑ๐ผโโ๐ฑ๐ฝโโ๏ธ๐ฑ๐ฝโโ๐ฑ๐พโโ๏ธ๐ฑ๐พโโ๐ฑ๐ฟโโ๏ธ๐ฑ๐ฟโโ๐ฑโโ๏ธ๐ฑโโ๐ฑ๐ปโโ๏ธ๐ฑ๐ปโโ๐ฑ๐ผโโ๏ธ๐ฑ๐ผโโ๐ฑ๐ฝโโ๏ธ๐ฑ๐ฝโโ๐ฑ๐พโโ๏ธ๐ฑ๐พโโ๐ฑ๐ฟโโ๏ธ๐ฑ๐ฟโโ๐จโ๐ฆฐ๐จ๐ปโ๐ฆฐ๐จ๐ผโ๐ฆฐ๐จ๐ฝโ๐ฆฐ๐จ๐พโ๐ฆฐ๐จ๐ฟโ๐ฆฐ๐ฉโ๐ฆฐ๐ฉ๐ปโ๐ฆฐ๐ฉ๐ผโ๐ฆฐ๐ฉ๐ฝโ๐ฆฐ๐ฉ๐พโ๐ฆฐ๐ฉ๐ฟโ๐ฆฐ๐จโ๐ฆฑ๐จ๐ปโ๐ฆฑ๐จ๐ผโ๐ฆฑ๐จ๐ฝโ๐ฆฑ๐จ๐พโ๐ฆฑ๐จ๐ฟโ๐ฆฑ๐ฉโ๐ฆฑ๐ฉ๐ปโ๐ฆฑ๐ฉ๐ผโ๐ฆฑ๐ฉ๐ฝโ๐ฆฑ๐ฉ๐พโ๐ฆฑ๐ฉ๐ฟโ๐ฆฑ๐จโ๐ฆฒ๐จ๐ปโ๐ฆฒ๐จ๐ผโ๐ฆฒ๐จ๐ฝโ๐ฆฒ๐จ๐พโ๐ฆฒ๐จ๐ฟโ๐ฆฒ๐ฉโ๐ฆฒ๐ฉ๐ปโ๐ฆฒ๐ฉ๐ผโ๐ฆฒ๐ฉ๐ฝโ๐ฆฒ๐ฉ๐พโ๐ฆฒ๐ฉ๐ฟโ๐ฆฒ๐จโ๐ฆณ๐จ๐ปโ๐ฆณ๐จ๐ผโ๐ฆณ๐จ๐ฝโ๐ฆณ๐จ๐พโ๐ฆณ๐จ๐ฟโ๐ฆณ๐ฉโ๐ฆณ๐ฉ๐ปโ๐ฆณ๐ฉ๐ผโ๐ฆณ๐ฉ๐ฝโ๐ฆณ๐ฉ๐พโ๐ฆณ๐ฉ๐ฟโ๐ฆณ๐คต๐คต๐ป๐คต๐ผ๐คต๐ฝ๐คต๐พ๐คต๐ฟ๐ฐ๐ฐ๐ป๐ฐ๐ผ๐ฐ๐ฝ๐ฐ๐พ๐ฐ๐ฟ๐คฐ๐คฐ๐ป๐คฐ๐ผ๐คฐ๐ฝ๐คฐ๐พ๐คฐ๐ฟ๐คฑ๐คฑ๐ป๐คฑ๐ผ๐คฑ๐ฝ๐คฑ๐พ๐คฑ๐ฟ๐ผ๐ผ๐ป๐ผ๐ผ๐ผ๐ฝ๐ผ๐พ๐ผ๐ฟ๐ ๐ ๐ป๐ ๐ผ๐ ๐ฝ๐ ๐พ๐ ๐ฟ๐คถ๐คถ๐ป๐คถ๐ผ๐คถ๐ฝ๐คถ๐พ๐คถ๐ฟ๐ฆธ๐ฆธ๐ป๐ฆธ๐ผ๐ฆธ๐ฝ๐ฆธ๐พ๐ฆธ๐ฟ๐ฆธโโ๏ธ๐ฆธโโ๐ฆธ๐ปโโ๏ธ๐ฆธ๐ปโโ๐ฆธ๐ผโโ๏ธ๐ฆธ๐ผโโ๐ฆธ๐ฝโโ๏ธ๐ฆธ๐ฝโโ๐ฆธ๐พโโ๏ธ๐ฆธ๐พโโ๐ฆธ๐ฟโโ๏ธ๐ฆธ๐ฟโโ๐ฆธโโ๏ธ๐ฆธโโ๐ฆธ๐ปโโ๏ธ๐ฆธ๐ปโโ๐ฆธ๐ผโโ๏ธ๐ฆธ๐ผโโ๐ฆธ๐ฝโโ๏ธ๐ฆธ๐ฝโโ๐ฆธ๐พโโ๏ธ๐ฆธ๐พโโ๐ฆธ๐ฟโโ๏ธ๐ฆธ๐ฟโโ๐ฆน๐ฆน๐ป๐ฆน๐ผ๐ฆน๐ฝ๐ฆน๐พ๐ฆน๐ฟ๐ฆนโโ๏ธ๐ฆนโโ๐ฆน๐ปโโ๏ธ๐ฆน๐ปโโ๐ฆน๐ผโโ๏ธ๐ฆน๐ผโโ๐ฆน๐ฝโโ๏ธ๐ฆน๐ฝโโ๐ฆน๐พโโ๏ธ๐ฆน๐พโโ๐ฆน๐ฟโโ๏ธ๐ฆน๐ฟโโ๐ฆนโโ๏ธ๐ฆนโโ๐ฆน๐ปโโ๏ธ๐ฆน๐ปโโ๐ฆน๐ผโโ๏ธ๐ฆน๐ผโโ๐ฆน๐ฝโโ๏ธ๐ฆน๐ฝโโ๐ฆน๐พโโ๏ธ๐ฆน๐พโโ๐ฆน๐ฟโโ๏ธ๐ฆน๐ฟโโ๐ง๐ง๐ป๐ง๐ผ๐ง๐ฝ๐ง๐พ๐ง๐ฟ๐งโโ๏ธ๐งโโ๐ง๐ปโโ๏ธ๐ง๐ปโโ๐ง๐ผโโ๏ธ๐ง๐ผโโ๐ง๐ฝโโ๏ธ๐ง๐ฝโโ๐ง๐พโโ๏ธ๐ง๐พโโ๐ง๐ฟโโ๏ธ๐ง๐ฟโโ๐งโโ๏ธ๐งโโ๐ง๐ปโโ๏ธ๐ง๐ปโโ๐ง๐ผโโ๏ธ๐ง๐ผโโ๐ง๐ฝโโ๏ธ๐ง๐ฝโโ๐ง๐พโโ๏ธ๐ง๐พโโ๐ง๐ฟโโ๏ธ๐ง๐ฟโโ๐ง๐ง๐ป๐ง๐ผ๐ง๐ฝ๐ง๐พ๐ง๐ฟ๐งโโ๏ธ๐งโโ๐ง๐ปโโ๏ธ๐ง๐ปโโ๐ง๐ผโโ๏ธ๐ง๐ผโโ๐ง๐ฝโโ๏ธ๐ง๐ฝโโ๐ง๐พโโ๏ธ๐ง๐พโโ๐ง๐ฟโโ๏ธ๐ง๐ฟโโ๐งโโ๏ธ๐งโโ๐ง๐ปโโ๏ธ๐ง๐ปโโ๐ง๐ผโโ๏ธ๐ง๐ผโโ๐ง๐ฝโโ๏ธ๐ง๐ฝโโ๐ง๐พโโ๏ธ๐ง๐พโโ๐ง๐ฟโโ๏ธ๐ง๐ฟโโ๐ง๐ง๐ป๐ง๐ผ๐ง๐ฝ๐ง๐พ๐ง๐ฟ๐งโโ๏ธ๐งโโ๐ง๐ปโโ๏ธ๐ง๐ปโโ๐ง๐ผโโ๏ธ๐ง๐ผโโ๐ง๐ฝโโ๏ธ๐ง๐ฝโโ๐ง๐พโโ๏ธ๐ง๐พโโ๐ง๐ฟโโ๏ธ๐ง๐ฟโโ๐งโโ๏ธ๐งโโ๐ง๐ปโโ๏ธ๐ง๐ปโโ๐ง๐ผโโ๏ธ๐ง๐ผโโ๐ง๐ฝโโ๏ธ๐ง๐ฝโโ๐ง๐พโโ๏ธ๐ง๐พโโ๐ง๐ฟโโ๏ธ๐ง๐ฟโโ๐ง๐ง๐ป๐ง๐ผ๐ง๐ฝ๐ง๐พ๐ง๐ฟ๐งโโ๏ธ๐งโโ๐ง๐ปโโ๏ธ๐ง๐ปโโ๐ง๐ผโโ๏ธ๐ง๐ผโโ๐ง๐ฝโโ๏ธ๐ง๐ฝโโ๐ง๐พโโ๏ธ๐ง๐พโโ๐ง๐ฟโโ๏ธ๐ง๐ฟโโ๐งโโ๏ธ๐งโโ๐ง๐ปโโ๏ธ๐ง๐ปโโ๐ง๐ผโโ๏ธ๐ง๐ผโโ๐ง๐ฝโโ๏ธ๐ง๐ฝโโ๐ง๐พโโ๏ธ๐ง๐พโโ๐ง๐ฟโโ๏ธ๐ง๐ฟโโ๐ง๐ง๐ป๐ง๐ผ๐ง๐ฝ๐ง๐พ๐ง๐ฟ๐งโโ๏ธ๐งโโ๐ง๐ปโโ๏ธ๐ง๐ปโโ๐ง๐ผโโ๏ธ๐ง๐ผโโ๐ง๐ฝโโ๏ธ๐ง๐ฝโโ๐ง๐พโโ๏ธ๐ง๐พโโ๐ง๐ฟโโ๏ธ๐ง๐ฟโโ๐งโโ๏ธ๐งโโ๐ง๐ปโโ๏ธ๐ง๐ปโโ๐ง๐ผโโ๏ธ๐ง๐ผโโ๐ง๐ฝโโ๏ธ๐ง๐ฝโโ๐ง๐พโโ๏ธ๐ง๐พโโ๐ง๐ฟโโ๏ธ๐ง๐ฟโโ๐ง๐งโโ๏ธ๐งโโ๐งโโ๏ธ๐งโโ๐ง๐งโโ๏ธ๐งโโ๐งโโ๏ธ๐งโโ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐ ๐ ๐ป๐ ๐ผ๐ ๐ฝ๐ ๐พ๐ ๐ฟ๐ โโ๏ธ๐ โโ๐ ๐ปโโ๏ธ๐ ๐ปโโ๐ ๐ผโโ๏ธ๐ ๐ผโโ๐ ๐ฝโโ๏ธ๐ ๐ฝโโ๐ ๐พโโ๏ธ๐ ๐พโโ๐ ๐ฟโโ๏ธ๐ ๐ฟโโ๐ โโ๏ธ๐ โโ๐ ๐ปโโ๏ธ๐ ๐ปโโ๐ ๐ผโโ๏ธ๐ ๐ผโโ๐ ๐ฝโโ๏ธ๐ ๐ฝโโ๐ ๐พโโ๏ธ๐ ๐พโโ๐ ๐ฟโโ๏ธ๐ ๐ฟโโ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐คฆ๐คฆ๐ป๐คฆ๐ผ๐คฆ๐ฝ๐คฆ๐พ๐คฆ๐ฟ๐คฆโโ๏ธ๐คฆโโ๐คฆ๐ปโโ๏ธ๐คฆ๐ปโโ๐คฆ๐ผโโ๏ธ๐คฆ๐ผโโ๐คฆ๐ฝโโ๏ธ๐คฆ๐ฝโโ๐คฆ๐พโโ๏ธ๐คฆ๐พโโ๐คฆ๐ฟโโ๏ธ๐คฆ๐ฟโโ๐คฆโโ๏ธ๐คฆโโ๐คฆ๐ปโโ๏ธ๐คฆ๐ปโโ๐คฆ๐ผโโ๏ธ๐คฆ๐ผโโ๐คฆ๐ฝโโ๏ธ๐คฆ๐ฝโโ๐คฆ๐พโโ๏ธ๐คฆ๐พโโ๐คฆ๐ฟโโ๏ธ๐คฆ๐ฟโโ๐คท๐คท๐ป๐คท๐ผ๐คท๐ฝ๐คท๐พ๐คท๐ฟ๐คทโโ๏ธ๐คทโโ๐คท๐ปโโ๏ธ๐คท๐ปโโ๐คท๐ผโโ๏ธ๐คท๐ผโโ๐คท๐ฝโโ๏ธ๐คท๐ฝโโ๐คท๐พโโ๏ธ๐คท๐พโโ๐คท๐ฟโโ๏ธ๐คท๐ฟโโ๐คทโโ๏ธ๐คทโโ๐คท๐ปโโ๏ธ๐คท๐ปโโ๐คท๐ผโโ๏ธ๐คท๐ผโโ๐คท๐ฝโโ๏ธ๐คท๐ฝโโ๐คท๐พโโ๏ธ๐คท๐พโโ๐คท๐ฟโโ๏ธ๐คท๐ฟโโ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐ถ๐ถ๐ป๐ถ๐ผ๐ถ๐ฝ๐ถ๐พ๐ถ๐ฟ๐ถโโ๏ธ๐ถโโ๐ถ๐ปโโ๏ธ๐ถ๐ปโโ๐ถ๐ผโโ๏ธ๐ถ๐ผโโ๐ถ๐ฝโโ๏ธ๐ถ๐ฝโโ๐ถ๐พโโ๏ธ๐ถ๐พโโ๐ถ๐ฟโโ๏ธ๐ถ๐ฟโโ๐ถโโ๏ธ๐ถโโ๐ถ๐ปโโ๏ธ๐ถ๐ปโโ๐ถ๐ผโโ๏ธ๐ถ๐ผโโ๐ถ๐ฝโโ๏ธ๐ถ๐ฝโโ๐ถ๐พโโ๏ธ๐ถ๐พโโ๐ถ๐ฟโโ๏ธ๐ถ๐ฟโโ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐บ๐บ๐ป๐บ๐ผ๐บ๐ฝ๐บ๐พ๐บ๐ฟ๐ฏ๐ฏโโ๏ธ๐ฏโโ๐ฏโโ๏ธ๐ฏโโ๐ง๐ง๐ป๐ง๐ผ๐ง๐ฝ๐ง๐พ๐ง๐ฟ๐งโโ๏ธ๐งโโ๐ง๐ปโโ๏ธ๐ง๐ปโโ๐ง๐ผโโ๏ธ๐ง๐ผโโ๐ง๐ฝโโ๏ธ๐ง๐ฝโโ๐ง๐พโโ๏ธ๐ง๐พโโ๐ง๐ฟโโ๏ธ๐ง๐ฟโโ๐งโโ๏ธ๐งโโ๐ง๐ปโโ๏ธ๐ง๐ปโโ๐ง๐ผโโ๏ธ๐ง๐ผโโ๐ง๐ฝโโ๏ธ๐ง๐ฝโโ๐ง๐พโโ๏ธ๐ง๐พโโ๐ง๐ฟโโ๏ธ๐ง๐ฟโโ๐ง๐ง๐ป๐ง๐ผ๐ง๐ฝ๐ง๐พ๐ง๐ฟ๐งโโ๏ธ๐งโโ๐ง๐ปโโ๏ธ๐ง๐ปโโ๐ง๐ผโโ๏ธ๐ง๐ผโโ๐ง๐ฝโโ๏ธ๐ง๐ฝโโ๐ง๐พโโ๏ธ๐ง๐พโโ๐ง๐ฟโโ๏ธ๐ง๐ฟโโ๐งโโ๏ธ๐งโโ๐ง๐ปโโ๏ธ๐ง๐ปโโ๐ง๐ผโโ๏ธ๐ง๐ผโโ๐ง๐ฝโโ๏ธ๐ง๐ฝโโ๐ง๐พโโ๏ธ๐ง๐พโโ๐ง๐ฟโโ๏ธ๐ง๐ฟโโ๐ง๐ง๐ป๐ง๐ผ๐ง๐ฝ๐ง๐พ๐ง๐ฟ๐งโโ๏ธ๐งโโ๐ง๐ปโโ๏ธ๐ง๐ปโโ๐ง๐ผโโ๏ธ๐ง๐ผโโ๐ง๐ฝโโ๏ธ๐ง๐ฝโโ๐ง๐พโโ๏ธ๐ง๐พโโ๐ง๐ฟโโ๏ธ๐ง๐ฟโโ๐งโโ๏ธ๐งโโ๐ง๐ปโโ๏ธ๐ง๐ปโโ๐ง๐ผโโ๏ธ๐ง๐ผโโ๐ง๐ฝโโ๏ธ๐ง๐ฝโโ๐ง๐พโโ๏ธ๐ง๐พโโ๐ง๐ฟโโ๏ธ๐ง๐ฟโโ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐ด๏ธ๐ด๐ด๐ป๐ด๐ผ๐ด๐ฝ๐ด๐พ๐ด๐ฟ๐ฃ๏ธ๐ฃ๐ค๐ฅ๐คบ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟโท๏ธโท๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐๏ธ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐๏ธโโ๏ธ๐โโ๏ธ๐๏ธโโ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐๏ธโโ๏ธ๐โโ๏ธ๐๏ธโโ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐ฃ๐ฃ๐ป๐ฃ๐ผ๐ฃ๐ฝ๐ฃ๐พ๐ฃ๐ฟ๐ฃโโ๏ธ๐ฃโโ๐ฃ๐ปโโ๏ธ๐ฃ๐ปโโ๐ฃ๐ผโโ๏ธ๐ฃ๐ผโโ๐ฃ๐ฝโโ๏ธ๐ฃ๐ฝโโ๐ฃ๐พโโ๏ธ๐ฃ๐พโโ๐ฃ๐ฟโโ๏ธ๐ฃ๐ฟโโ๐ฃโโ๏ธ๐ฃโโ๐ฃ๐ปโโ๏ธ๐ฃ๐ปโโ๐ฃ๐ผโโ๏ธ๐ฃ๐ผโโ๐ฃ๐ฝโโ๏ธ๐ฃ๐ฝโโ๐ฃ๐พโโ๏ธ๐ฃ๐พโโ๐ฃ๐ฟโโ๏ธ๐ฃ๐ฟโโ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐โโ๏ธ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโโน๏ธโนโน๐ปโน๐ผโน๐ฝโน๐พโน๐ฟโน๏ธโโ๏ธโนโโ๏ธโน๏ธโโโนโโโน๐ปโโ๏ธโน๐ปโโโน๐ผโโ๏ธโน๐ผโโโน๐ฝโโ๏ธโน๐ฝโโโน๐พโโ๏ธโน๐พโโโน๐ฟโโ๏ธโน๐ฟโโโน๏ธโโ๏ธโนโโ๏ธโน๏ธโโโนโโโน๐ปโโ๏ธโน๐ปโโโน๐ผโโ๏ธโน๐ผโโโน๐ฝโโ๏ธโน๐ฝโโโน๐พโโ๏ธโน๐พโโโน๐ฟโโ๏ธโน๐ฟโโ๐๏ธ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐๏ธโโ๏ธ๐โโ๏ธ๐๏ธโโ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐๏ธโโ๏ธ๐โโ๏ธ๐๏ธโโ๐โโ๐๐ปโโ๏ธ๐๐ปโโ๐๐ผโโ๏ธ๐๐ผโโ๐๐ฝโโ๏ธ๐๐ฝโโ๐๐พโโ๏ธ๐๐พโโ๐๐ฟโโ๏ธ๐๐ฟโโ๐ด๐ด๐ป๐ด๐ผ๐ด๐ฝ๐ด๐พ๐ด๐ฟ๐ดโโ๏ธ๐ดโโ๐ด๐ปโโ๏ธ๐ด๐ปโโ๐ด๐ผโโ๏ธ๐ด๐ผโโ๐ด๐ฝโโ๏ธ๐ด๐ฝโโ๐ด๐พโโ๏ธ๐ด๐พโโ๐ด๐ฟโโ๏ธ๐ด๐ฟโโ๐ดโโ๏ธ๐ดโโ๐ด๐ปโโ๏ธ๐ด๐ปโโ๐ด๐ผโโ๏ธ๐ด๐ผโโ๐ด๐ฝโโ๏ธ๐ด๐ฝโโ๐ด๐พโโ๏ธ๐ด๐พโโ๐ด๐ฟโโ๏ธ๐ด๐ฟโโ๐ต๐ต๐ป๐ต๐ผ๐ต๐ฝ๐ต๐พ๐ต๐ฟ๐ตโโ๏ธ๐ตโโ๐ต๐ปโโ๏ธ๐ต๐ปโโ๐ต๐ผโโ๏ธ๐ต๐ผโโ๐ต๐ฝโโ๏ธ๐ต๐ฝโโ๐ต๐พโโ๏ธ๐ต๐พโโ๐ต๐ฟโโ๏ธ๐ต๐ฟโโ๐ตโโ๏ธ๐ตโโ๐ต๐ปโโ๏ธ๐ต๐ปโโ๐ต๐ผโโ๏ธ๐ต๐ผโโ๐ต๐ฝโโ๏ธ๐ต๐ฝโโ๐ต๐พโโ๏ธ๐ต๐พโโ๐ต๐ฟโโ๏ธ๐ต๐ฟโโ๐๏ธ๐๐๏ธ๐๐คธ๐คธ๐ป๐คธ๐ผ๐คธ๐ฝ๐คธ๐พ๐คธ๐ฟ๐คธโโ๏ธ๐คธโโ๐คธ๐ปโโ๏ธ๐คธ๐ปโโ๐คธ๐ผโโ๏ธ๐คธ๐ผโโ๐คธ๐ฝโโ๏ธ๐คธ๐ฝโโ๐คธ๐พโโ๏ธ๐คธ๐พโโ๐คธ๐ฟโโ๏ธ๐คธ๐ฟโโ๐คธโโ๏ธ๐คธโโ๐คธ๐ปโโ๏ธ๐คธ๐ปโโ๐คธ๐ผโโ๏ธ๐คธ๐ผโโ๐คธ๐ฝโโ๏ธ๐คธ๐ฝโโ๐คธ๐พโโ๏ธ๐คธ๐พโโ๐คธ๐ฟโโ๏ธ๐คธ๐ฟโโ๐คผ๐คผโโ๏ธ๐คผโโ๐คผโโ๏ธ๐คผโโ๐คฝ๐คฝ๐ป๐คฝ๐ผ๐คฝ๐ฝ๐คฝ๐พ๐คฝ๐ฟ๐คฝโโ๏ธ๐คฝโโ๐คฝ๐ปโโ๏ธ๐คฝ๐ปโโ๐คฝ๐ผโโ๏ธ๐คฝ๐ผโโ๐คฝ๐ฝโโ๏ธ๐คฝ๐ฝโโ๐คฝ๐พโโ๏ธ๐คฝ๐พโโ๐คฝ๐ฟโโ๏ธ๐คฝ๐ฟโโ๐คฝโโ๏ธ๐คฝโโ๐คฝ๐ปโโ๏ธ๐คฝ๐ปโโ๐คฝ๐ผโโ๏ธ๐คฝ๐ผโโ๐คฝ๐ฝโโ๏ธ๐คฝ๐ฝโโ๐คฝ๐พโโ๏ธ๐คฝ๐พโโ๐คฝ๐ฟโโ๏ธ๐คฝ๐ฟโโ๐คพ๐คพ๐ป๐คพ๐ผ๐คพ๐ฝ๐คพ๐พ๐คพ๐ฟ๐คพโโ๏ธ๐คพโโ๐คพ๐ปโโ๏ธ๐คพ๐ปโโ๐คพ๐ผโโ๏ธ๐คพ๐ผโโ๐คพ๐ฝโโ๏ธ๐คพ๐ฝโโ๐คพ๐พโโ๏ธ๐คพ๐พโโ๐คพ๐ฟโโ๏ธ๐คพ๐ฟโโ๐คพโโ๏ธ๐คพโโ๐คพ๐ปโโ๏ธ๐คพ๐ปโโ๐คพ๐ผโโ๏ธ๐คพ๐ผโโ๐คพ๐ฝโโ๏ธ๐คพ๐ฝโโ๐คพ๐พโโ๏ธ๐คพ๐พโโ๐คพ๐ฟโโ๏ธ๐คพ๐ฟโโ๐คน๐คน๐ป๐คน๐ผ๐คน๐ฝ๐คน๐พ๐คน๐ฟ๐คนโโ๏ธ๐คนโโ๐คน๐ปโโ๏ธ๐คน๐ปโโ๐คน๐ผโโ๏ธ๐คน๐ผโโ๐คน๐ฝโโ๏ธ๐คน๐ฝโโ๐คน๐พโโ๏ธ๐คน๐พโโ๐คน๐ฟโโ๏ธ๐คน๐ฟโโ๐คนโโ๏ธ๐คนโโ๐คน๐ปโโ๏ธ๐คน๐ปโโ๐คน๐ผโโ๏ธ๐คน๐ผโโ๐คน๐ฝโโ๏ธ๐คน๐ฝโโ๐คน๐พโโ๏ธ๐คน๐พโโ๐คน๐ฟโโ๏ธ๐คน๐ฟโโ๐ซ๐ฌ๐ญ๐๐ฉโโค๏ธโ๐โ๐จ๐ฉโโคโ๐โ๐จ๐จโโค๏ธโ๐โ๐จ๐จโโคโ๐โ๐จ๐ฉโโค๏ธโ๐โ๐ฉ๐ฉโโคโ๐โ๐ฉ๐๐ฉโโค๏ธโ๐จ๐ฉโโคโ๐จ๐จโโค๏ธโ๐จ๐จโโคโ๐จ๐ฉโโค๏ธโ๐ฉ๐ฉโโคโ๐ฉ๐ช๐จโ๐ฉโ๐ฆ๐จโ๐ฉโ๐ง๐จโ๐ฉโ๐งโ๐ฆ๐จโ๐ฉโ๐ฆโ๐ฆ๐จโ๐ฉโ๐งโ๐ง๐จโ๐จโ๐ฆ๐จโ๐จโ๐ง๐จโ๐จโ๐งโ๐ฆ๐จโ๐จโ๐ฆโ๐ฆ๐จโ๐จโ๐งโ๐ง๐ฉโ๐ฉโ๐ฆ๐ฉโ๐ฉโ๐ง๐ฉโ๐ฉโ๐งโ๐ฆ๐ฉโ๐ฉโ๐ฆโ๐ฆ๐ฉโ๐ฉโ๐งโ๐ง๐จโ๐ฆ๐จโ๐ฆโ๐ฆ๐จโ๐ง๐จโ๐งโ๐ฆ๐จโ๐งโ๐ง๐ฉโ๐ฆ๐ฉโ๐ฆโ๐ฆ๐ฉโ๐ง๐ฉโ๐งโ๐ฆ๐ฉโ๐งโ๐ง๐คณ๐คณ๐ป๐คณ๐ผ๐คณ๐ฝ๐คณ๐พ๐คณ๐ฟ๐ช๐ช๐ป๐ช๐ผ๐ช๐ฝ๐ช๐พ๐ช๐ฟ๐ฆต๐ฆต๐ป๐ฆต๐ผ๐ฆต๐ฝ๐ฆต๐พ๐ฆต๐ฟ๐ฆถ๐ฆถ๐ป๐ฆถ๐ผ๐ฆถ๐ฝ๐ฆถ๐พ๐ฆถ๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟโ๏ธโโ๐ปโ๐ผโ๐ฝโ๐พโ๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟโ๏ธโโ๐ปโ๐ผโ๐ฝโ๐พโ๐ฟ๐ค๐ค๐ป๐ค๐ผ๐ค๐ฝ๐ค๐พ๐ค๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐ค๐ค๐ป๐ค๐ผ๐ค๐ฝ๐ค๐พ๐ค๐ฟ๐ค๐ค๐ป๐ค๐ผ๐ค๐ฝ๐ค๐พ๐ค๐ฟ๐๏ธ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟโโ๐ปโ๐ผโ๐ฝโ๐พโ๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟโโ๐ปโ๐ผโ๐ฝโ๐พโ๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐ค๐ค๐ป๐ค๐ผ๐ค๐ฝ๐ค๐พ๐ค๐ฟ๐ค๐ค๐ป๐ค๐ผ๐ค๐ฝ๐ค๐พ๐ค๐ฟ๐ค๐ค๐ป๐ค๐ผ๐ค๐ฝ๐ค๐พ๐ค๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐ค๐ค๐ป๐ค๐ผ๐ค๐ฝ๐ค๐พ๐ค๐ฟโ๏ธโโ๐ปโ๐ผโ๐ฝโ๐พโ๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐คฒ๐คฒ๐ป๐คฒ๐ผ๐คฒ๐ฝ๐คฒ๐พ๐คฒ๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐ค๐ ๐ ๐ป๐ ๐ผ๐ ๐ฝ๐ ๐พ๐ ๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐๐๐ป๐๐ผ๐๐ฝ๐๐พ๐๐ฟ๐ฆฐ๐ฆฑ๐ฆฒ๐ฆณ๐ฃ๐๐๏ธ๐๐๏ธโ๐จ๏ธ๐โ๐จ๏ธ๐๏ธโ๐จ๐โ๐จ๐ง ๐ฆด๐ฆท๐ ๐๐๐โค๏ธโค๐๐๐๐๐๐๐๐๐งก๐๐ค๐๐๐โฃ๏ธโฃ๐๐ค๐ข๐ฃ๐ฅ๐ฆ๐จ๐ซ๐ฌ๐จ๏ธ๐จ๐ฏ๏ธ๐ฏ๐ญ๐ณ๏ธ๐ณ๐๐ถ๏ธ๐ถ๐ฅฝ๐ฅผ๐๐๐๐งฃ๐งค๐งฅ๐งฆ๐๐๐๐๐๐๐๐๏ธ๐๐๐๐๐ฅพ๐ฅฟ๐ ๐ก๐ข๐๐๐ฉ๐๐งขโ๏ธโ๐ฟ๐๐๐๐ต๐๐ฆ๐ถ๐๐ฉ๐บ๐ฆ๐ฆ๐ฑ๐๐ฆ๐ฏ๐ ๐๐ด๐๐ฆ๐ฆ๐ฆ๐ฎ๐๐๐๐ท๐๐๐ฝ๐๐๐๐ช๐ซ๐ฆ๐ฆ๐๐ฆ๐ฆ๐ญ๐๐๐น๐ฐ๐๐ฟ๏ธ๐ฟ๐ฆ๐ฆ๐ป๐จ๐ผ๐ฆ๐ฆก๐พ๐ฆ๐๐๐ฃ๐ค๐ฅ๐ฆ๐ง๐๏ธ๐๐ฆ ๐ฆ๐ฆข๐ฆ๐ฆ๐ฆ๐ธ๐๐ข๐ฆ๐๐ฒ๐๐ฆ๐ฆ๐ณ๐๐ฌ๐๐ ๐ก๐ฆ๐๐๐ฆ๐ฆ๐ฆ๐ฆ๐๐ฆ๐๐๐๐๐ฆ๐ท๏ธ๐ท๐ธ๏ธ๐ธ๐ฆ๐ฆ๐ฆ ๐๐ธ๐ฎ๐ต๏ธ๐ต๐น๐ฅ๐บ๐ป๐ผ๐ท๐ฑ๐ฒ๐ณ๐ด๐ต๐พ๐ฟโ๏ธโ๐๐๐๐๐๐๐๐๐๐๐๐ฅญ๐๐๐๐๐๐๐ฅ๐ ๐ฅฅ๐ฅ๐๐ฅ๐ฅ๐ฝ๐ถ๏ธ๐ถ๐ฅ๐ฅฌ๐ฅฆ๐๐ฅ๐ฐ๐๐ฅ๐ฅ๐ฅจ๐ฅฏ๐ฅ๐ง๐๐๐ฅฉ๐ฅ๐๐๐๐ญ๐ฅช๐ฎ๐ฏ๐ฅ๐ฅ๐ณ๐ฅ๐ฒ๐ฅฃ๐ฅ๐ฟ๐ง๐ฅซ๐ฑ๐๐๐๐๐๐๐ ๐ข๐ฃ๐ค๐ฅ๐ฅฎ๐ก๐ฅ๐ฅ ๐ฅก๐ฆ๐ง๐จ๐ฉ๐ช๐๐ฐ๐ง๐ฅง๐ซ๐ฌ๐ญ๐ฎ๐ฏ๐ผ๐ฅโ๐ต๐ถ๐พ๐ท๐ธ๐น๐บ๐ป๐ฅ๐ฅ๐ฅค๐ฅข๐ฝ๏ธ๐ฝ๐ด๐ฅ๐ช๐บ๐๐๐๐๐บ๏ธ๐บ๐พ๐งญ๐๏ธ๐โฐ๏ธโฐ๐๐ป๐๏ธ๐๐๏ธ๐๐๏ธ๐๐๏ธ๐๐๏ธ๐๐๏ธ๐๐๏ธ๐๐๏ธ๐๐งฑ๐๏ธ๐๐๏ธ๐๐ ๐ก๐ข๐ฃ๐ค๐ฅ๐ฆ๐จ๐ฉ๐ช๐ซ๐ฌ๐ญ๐ฏ๐ฐ๐๐ผ๐ฝโช๐๐โฉ๏ธโฉ๐โฒโบ๐๐๐๏ธ๐๐๐ ๐๐๐โจ๏ธโจ๐๐ ๐ก๐ข๐๐ช๐๐๐๐ ๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐ฒ๐ด๐น๐ต๐๐ฃ๏ธ๐ฃ๐ค๏ธ๐ค๐ข๏ธ๐ขโฝ๐จ๐ฅ๐ฆ๐๐งโโต๐ถ๐ค๐ณ๏ธ๐ณโด๏ธโด๐ฅ๏ธ๐ฅ๐ขโ๏ธโ๐ฉ๏ธ๐ฉ๐ซ๐ฌ๐บ๐๐๐ ๐ก๐ฐ๏ธ๐ฐ๐๐ธ๐๏ธ๐๐งณโโณโโฐโฑ๏ธโฑโฒ๏ธโฒ๐ฐ๏ธ๐ฐ๐๐ง๐๐๐๐๐๐๐๐๐๐ ๐๐ก๐๐ข๐๐ฃ๐๐ค๐๐ฅ๐๐ฆ๐๐๐๐๐๐๐๐๐๐๐๐๐ก๏ธ๐กโ๏ธโ๐๐โญ๐๐ โ๏ธโโ โ๏ธโ๐ค๏ธ๐ค๐ฅ๏ธ๐ฅ๐ฆ๏ธ๐ฆ๐ง๏ธ๐ง๐จ๏ธ๐จ๐ฉ๏ธ๐ฉ๐ช๏ธ๐ช๐ซ๏ธ๐ซ๐ฌ๏ธ๐ฌ๐๐๐โ๏ธโโโฑ๏ธโฑโกโ๏ธโโ๏ธโโโ๏ธโ๐ฅ๐ง๐๐๐๐๐๐งจโจ๐๐๐๐๐๐๐๐๐๐งง๐๐๐๏ธ๐๐๏ธ๐๐ซ๐๏ธ๐๐๐ ๐ฅ๐ฅ๐ฅโฝโพ๐ฅ๐๐๐๐๐พ๐ฅ๐ณ๐๐๐๐ฅ๐๐ธ๐ฅ๐ฅ๐ฅ โณโธ๏ธโธ๐ฃ๐ฝ๐ฟ๐ท๐ฅ๐ฏ๐ฑ๐ฎ๐งฟ๐ฎ๐น๏ธ๐น๐ฐ๐ฒ๐งฉ๐งธโ ๏ธโ โฅ๏ธโฅโฆ๏ธโฆโฃ๏ธโฃโ๏ธโ๐๐๐ด๐ญ๐ผ๏ธ๐ผ๐จ๐งต๐งถ๐๐๐๐๐ข๐ฃ๐ฏ๐๐๐ผ๐ต๐ถ๐๏ธ๐๐๏ธ๐๐๏ธ๐๐ค๐ง๐ป๐ท๐ธ๐น๐บ๐ป๐ฅ๐ฑ๐ฒโ๏ธโ๐๐๐ ๐๐๐ป๐ฅ๏ธ๐ฅ๐จ๏ธ๐จโจ๏ธโจ๐ฑ๏ธ๐ฑ๐ฒ๏ธ๐ฒ๐ฝ๐พ๐ฟ๐๐งฎ๐ฅ๐๏ธ๐๐ฝ๏ธ๐ฝ๐ฌ๐บ๐ท๐ธ๐น๐ผ๐๐๐ฏ๏ธ๐ฏ๐ก๐ฆ๐ฎ๐๐๐๐๐๐๐๐๐๐๐๐๐ฐ๐๏ธ๐๐๐๐ท๏ธ๐ท๐ฐ๐ด๐ต๐ถ๐ท๐ธ๐ณ๐งพ๐น๐ฑ๐ฒโ๏ธโ๐ง๐จ๐ฉ๐ค๐ฅ๐ฆ๐ซ๐ช๐ฌ๐ญ๐ฎ๐ณ๏ธ๐ณโ๏ธโโ๏ธโ๐๏ธ๐๐๏ธ๐๐๏ธ๐๐๏ธ๐๐๐ผ๐๐๐๏ธ๐๐ ๐๐๏ธ๐๐๏ธ๐๐๐๐๐๐๐๐๐๐๏ธ๐๐๐โ๏ธโ๐๏ธ๐๐๏ธ๐๐๏ธ๐๐๐๐๐๐๐๏ธ๐๐จโ๏ธโโ๏ธโ๐ ๏ธ๐ ๐ก๏ธ๐กโ๏ธโ๐ซ๐น๐ก๏ธ๐ก๐ง๐ฉโ๏ธโ๐๏ธ๐โ๏ธโ๐โ๏ธโ๐งฐ๐งฒโ๏ธโ๐งช๐งซ๐งฌ๐ฌ๐ญ๐ก๐๐๐ช๐๏ธ๐๐๏ธ๐๐ฝ๐ฟ๐๐งด๐งท๐งน๐งบ๐งป๐งผ๐งฝ๐งฏ๐๐ฌโฐ๏ธโฐโฑ๏ธโฑ๐ฟ๐ง๐ฎ๐ฐโฟ๐น๐บ๐ป๐ผ๐พ๐๐๐๐ โ ๏ธโ ๐ธโ๐ซ๐ณ๐ญ๐ฏ๐ฑ๐ท๐ต๐โข๏ธโขโฃ๏ธโฃโฌ๏ธโฌโ๏ธโโก๏ธโกโ๏ธโโฌ๏ธโฌโ๏ธโโฌ ๏ธโฌ โ๏ธโโ๏ธโโ๏ธโโฉ๏ธโฉโช๏ธโชโคด๏ธโคดโคต๏ธโคต๐๐๐๐๐๐๐๐โ๏ธโ๐๏ธ๐โก๏ธโกโธ๏ธโธโฏ๏ธโฏโ๏ธโโฆ๏ธโฆโช๏ธโชโฎ๏ธโฎ๐๐ฏโโโโโโโโโโโโโ๐๐๐โถ๏ธโถโฉโญ๏ธโญโฏ๏ธโฏโ๏ธโโชโฎ๏ธโฎ๐ผโซ๐ฝโฌโธ๏ธโธโน๏ธโนโบ๏ธโบโ๏ธโ๐ฆ๐ ๐๐ถ๐ณ๐ดโ๏ธโโ๏ธโโ๏ธโโพ๏ธโพโป๏ธโปโ๏ธโ๐ฑ๐๐ฐโญโ โ๏ธโโ๏ธโโ๏ธโโโโโโโฐโฟใฝ๏ธใฝโณ๏ธโณโด๏ธโดโ๏ธโโผ๏ธโผโ๏ธโโโโโใฐ๏ธใฐยฉ๏ธยฉยฎ๏ธยฎโข๏ธโข#๏ธโฃ#โฃ*๏ธโฃ*โฃ0๏ธโฃ0โฃ1๏ธโฃ1โฃ2๏ธโฃ2โฃ3๏ธโฃ3โฃ4๏ธโฃ4โฃ5๏ธโฃ5โฃ6๏ธโฃ6โฃ7๏ธโฃ7โฃ8๏ธโฃ8โฃ9๏ธโฃ9โฃ๐๐ฏ๐ ๐ก๐ข๐ฃ๐ค๐ ฐ๏ธ๐ ฐ๐๐ ฑ๏ธ๐ ฑ๐๐๐โน๏ธโน๐โ๏ธโ๐๐๐ พ๏ธ๐ พ๐๐ ฟ๏ธ๐ ฟ๐๐๐๐๐๏ธ๐๐ท๏ธ๐ท๐ถ๐ฏ๐๐น๐๐ฒ๐๐ธ๐ด๐ณใ๏ธใใ๏ธใ๐บ๐ตโช๏ธโชโซ๏ธโซโป๏ธโปโผ๏ธโผโฝโพโฌโฌ๐ถ๐ท๐ธ๐น๐บ๐ป๐ ๐๐ฒ๐ณโชโซ๐ด๐ต๐๐ฉ๐๐ด๐ณ๏ธ๐ณ๐ณ๏ธโ๐๐ณโ๐๐ดโโ ๏ธ๐ดโโ ๐ฆ๐จ๐ฆ๐ฉ๐ฆ๐ช๐ฆ๐ซ๐ฆ๐ฌ๐ฆ๐ฎ๐ฆ๐ฑ๐ฆ๐ฒ๐ฆ๐ด๐ฆ๐ถ๐ฆ๐ท๐ฆ๐ธ๐ฆ๐น๐ฆ๐บ๐ฆ๐ผ๐ฆ๐ฝ๐ฆ๐ฟ๐ง๐ฆ๐ง๐ง๐ง๐ฉ๐ง๐ช๐ง๐ซ๐ง๐ฌ๐ง๐ญ๐ง๐ฎ๐ง๐ฏ๐ง๐ฑ๐ง๐ฒ๐ง๐ณ๐ง๐ด๐ง๐ถ๐ง๐ท๐ง๐ธ๐ง๐น๐ง๐ป๐ง๐ผ๐ง๐พ๐ง๐ฟ๐จ๐ฆ๐จ๐จ๐จ๐ฉ๐จ๐ซ๐จ๐ฌ๐จ๐ญ๐จ๐ฎ๐จ๐ฐ๐จ๐ฑ๐จ๐ฒ๐จ๐ณ๐จ๐ด๐จ๐ต๐จ๐ท๐จ๐บ๐จ๐ป๐จ๐ผ๐จ๐ฝ๐จ๐พ๐จ๐ฟ๐ฉ๐ช๐ฉ๐ฌ๐ฉ๐ฏ๐ฉ๐ฐ๐ฉ๐ฒ๐ฉ๐ด๐ฉ๐ฟ๐ช๐ฆ๐ช๐จ๐ช๐ช๐ช๐ฌ๐ช๐ญ๐ช๐ท๐ช๐ธ๐ช๐น๐ช๐บ๐ซ๐ฎ๐ซ๐ฏ๐ซ๐ฐ๐ซ๐ฒ๐ซ๐ด๐ซ๐ท๐ฌ๐ฆ๐ฌ๐ง๐ฌ๐ฉ๐ฌ๐ช๐ฌ๐ซ๐ฌ๐ฌ๐ฌ๐ญ๐ฌ๐ฎ๐ฌ๐ฑ๐ฌ๐ฒ๐ฌ๐ณ๐ฌ๐ต๐ฌ๐ถ๐ฌ๐ท๐ฌ๐ธ๐ฌ๐น๐ฌ๐บ๐ฌ๐ผ๐ฌ๐พ๐ญ๐ฐ๐ญ๐ฒ๐ญ๐ณ๐ญ๐ท๐ญ๐น๐ญ๐บ๐ฎ๐จ๐ฎ๐ฉ๐ฎ๐ช๐ฎ๐ฑ๐ฎ๐ฒ๐ฎ๐ณ๐ฎ๐ด๐ฎ๐ถ๐ฎ๐ท๐ฎ๐ธ๐ฎ๐น๐ฏ๐ช๐ฏ๐ฒ๐ฏ๐ด๐ฏ๐ต๐ฐ๐ช๐ฐ๐ฌ๐ฐ๐ญ๐ฐ๐ฎ๐ฐ๐ฒ๐ฐ๐ณ๐ฐ๐ต๐ฐ๐ท๐ฐ๐ผ๐ฐ๐พ๐ฐ๐ฟ๐ฑ๐ฆ๐ฑ๐ง๐ฑ๐จ๐ฑ๐ฎ๐ฑ๐ฐ๐ฑ๐ท๐ฑ๐ธ๐ฑ๐น๐ฑ๐บ๐ฑ๐ป๐ฑ๐พ๐ฒ๐ฆ๐ฒ๐จ๐ฒ๐ฉ๐ฒ๐ช๐ฒ๐ซ๐ฒ๐ฌ๐ฒ๐ญ๐ฒ๐ฐ๐ฒ๐ฑ๐ฒ๐ฒ๐ฒ๐ณ๐ฒ๐ด๐ฒ๐ต๐ฒ๐ถ๐ฒ๐ท๐ฒ๐ธ๐ฒ๐น๐ฒ๐บ๐ฒ๐ป๐ฒ๐ผ๐ฒ๐ฝ๐ฒ๐พ๐ฒ๐ฟ๐ณ๐ฆ๐ณ๐จ๐ณ๐ช๐ณ๐ซ๐ณ๐ฌ๐ณ๐ฎ๐ณ๐ฑ๐ณ๐ด๐ณ๐ต๐ณ๐ท๐ณ๐บ๐ณ๐ฟ๐ด๐ฒ๐ต๐ฆ๐ต๐ช๐ต๐ซ๐ต๐ฌ๐ต๐ญ๐ต๐ฐ๐ต๐ฑ๐ต๐ฒ๐ต๐ณ๐ต๐ท๐ต๐ธ๐ต๐น๐ต๐ผ๐ต๐พ๐ถ๐ฆ๐ท๐ช๐ท๐ด๐ท๐ธ๐ท๐บ๐ท๐ผ๐ธ๐ฆ๐ธ๐ง๐ธ๐จ๐ธ๐ฉ๐ธ๐ช๐ธ๐ฌ๐ธ๐ญ๐ธ๐ฎ๐ธ๐ฏ๐ธ๐ฐ๐ธ๐ฑ๐ธ๐ฒ๐ธ๐ณ๐ธ๐ด๐ธ๐ท๐ธ๐ธ๐ธ๐น๐ธ๐ป๐ธ๐ฝ๐ธ๐พ๐ธ๐ฟ๐น๐ฆ๐น๐จ๐น๐ฉ๐น๐ซ๐น๐ฌ๐น๐ญ๐น๐ฏ๐น๐ฐ๐น๐ฑ๐น๐ฒ๐น๐ณ๐น๐ด๐น๐ท๐น๐น๐น๐ป๐น๐ผ๐น๐ฟ๐บ๐ฆ๐บ๐ฌ๐บ๐ฒ๐บ๐ณ๐บ๐ธ๐บ๐พ๐บ๐ฟ๐ป๐ฆ๐ป๐จ๐ป๐ช๐ป๐ฌ๐ป๐ฎ๐ป๐ณ๐ป๐บ๐ผ๐ซ๐ผ๐ธ๐ฝ๐ฐ๐พ๐ช๐พ๐น๐ฟ๐ฆ๐ฟ๐ฒ๐ฟ๐ผ๐ด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ๐ด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ๐ด๓ ง๓ ข๓ ท๓ ฌ๓ ณ๓ ฟ" ); expect(() => emoji.parse(":-)")).toThrow(); expect(() => emoji.parse("๐ is an emoji")).toThrow(); expect(() => emoji.parse("๐stuff")).toThrow(); expect(() => emoji.parse("stuff๐")).toThrow(); }); test("nanoid", () => { const nanoid = z.string().nanoid("custom error"); nanoid.parse("lfNZluvAxMkf7Q8C5H-QS"); nanoid.parse("mIU_4PJWikaU8fMbmkouz"); nanoid.parse("Hb9ZUtUa2JDm_dD-47EGv"); nanoid.parse("5Noocgv_8vQ9oPijj4ioQ"); const result = nanoid.safeParse("Xq90uDyhddC53KsoASYJGX"); expect(result).toMatchObject({ success: false }); expect(result.error!.issues[0].message).toEqual("custom error"); expect(result.error).toMatchInlineSnapshot(` [ZodError: [ { "origin": "string", "code": "invalid_format", "format": "nanoid", "pattern": "/^[a-zA-Z0-9_-]{21}$/", "path": [], "message": "custom error" } ]] `); }); test("bad nanoid", () => { const nanoid = z.string().nanoid("custom error"); nanoid.parse("ySh_984wpDUu7IQRrLXAp"); const result = nanoid.safeParse("invalid nanoid"); expect(result).toMatchObject({ success: false }); expect(result.error!.issues[0].message).toEqual("custom error"); expect(result.error).toMatchInlineSnapshot(` [ZodError: [ { "origin": "string", "code": "invalid_format", "format": "nanoid", "pattern": "/^[a-zA-Z0-9_-]{21}$/", "path": [], "message": "custom error" } ]] `); }); test("good uuid", () => { const uuid = z.string().uuid("custom error"); const goodUuids = [ "9491d710-3185-1e06-bea0-6a2f275345e0", "9491d710-3185-2e06-bea0-6a2f275345e0", "9491d710-3185-3e06-bea0-6a2f275345e0", "9491d710-3185-4e06-bea0-6a2f275345e0", "9491d710-3185-5e06-bea0-6a2f275345e0", "9491d710-3185-5e06-aea0-6a2f275345e0", "9491d710-3185-5e06-8ea0-6a2f275345e0", "9491d710-3185-5e06-9ea0-6a2f275345e0", "00000000-0000-0000-0000-000000000000", "ffffffff-ffff-ffff-ffff-ffffffffffff", ]; for (const goodUuid of goodUuids) { const result = uuid.safeParse(goodUuid); expect(result.success).toEqual(true); } }); test(`bad uuid`, () => { const uuid = z.string().uuid("custom error"); for (const badUuid of [ "9491d710-3185-0e06-bea0-6a2f275345e0", "9491d710-3185-5e06-0ea0-6a2f275345e0", "d89e7b01-7598-ed11-9d7a-0022489382fd", // new sequential id "b3ce60f8-e8b9-40f5-1150-172ede56ff74", // Variant 0 - RFC 9562/4122: Reserved, NCS backward compatibility "92e76bf9-28b3-4730-cd7f-cb6bc51f8c09", // Variant 2 - RFC 9562/4122: Reserved, Microsoft Corporation backward compatibility "invalid uuid", "9491d710-3185-4e06-bea0-6a2f275345e0X", ]) { const result = uuid.safeParse(badUuid); expect(result).toMatchObject({ success: false }); expect(result.error?.issues[0].message).toEqual("custom error"); } }); test("good guid", () => { const guid = z.string().guid("custom error"); for (const goodGuid of [ "9491d710-3185-4e06-bea0-6a2f275345e0", "d89e7b01-7598-ed11-9d7a-0022489382fd", // new sequential id "b3ce60f8-e8b9-40f5-1150-172ede56ff74", // Variant 0 - RFC 9562/4122: Reserved, NCS backward compatibility "92e76bf9-28b3-4730-cd7f-cb6bc51f8c09", // Variant 2 - RFC 9562/4122: Reserved, Microsoft Corporation backward compatibility "00000000-0000-0000-0000-000000000000", "ffffffff-ffff-ffff-ffff-ffffffffffff", ]) { const result = guid.safeParse(goodGuid); expect(result.success).toEqual(true); } }); test("bad guid", () => { const guid = z.string().guid("custom error"); for (const badGuid of ["9491d710-3185-4e06-bea0-6a2f275345e0X"]) { const result = guid.safeParse(badGuid); expect(result).toMatchObject({ success: false }); expect(result.error?.issues[0].message).toEqual("custom error"); } }); test("cuid", () => { const cuid = z.string().cuid(); cuid.parse("ckopqwooh000001la8mbi2im9"); const result = cuid.safeParse("cifjhdsfhsd-invalid-cuid"); expect(result).toMatchObject({ success: false }); expect(result.error!.issues[0].message).toEqual("Invalid cuid"); expect(result.error).toMatchInlineSnapshot(` [ZodError: [ { "origin": "string", "code": "invalid_format", "format": "cuid", "pattern": "/^[cC][^\\\\s-]{8,}$/", "path": [], "message": "Invalid cuid" } ]] `); }); test("cuid2", () => { const cuid2 = z.string().cuid2(); const validStrings = [ "a", // short string "tz4a98xxat96iws9zmbrgj3a", // normal string "kf5vz6ssxe4zjcb409rjgo747tc5qjazgptvotk6", // longer than require("@paralleldrive/cuid2").bigLength ]; for (const s of validStrings) { cuid2.parse(s); } const invalidStrings = [ "", // empty string "tz4a98xxat96iws9zMbrgj3a", // include uppercase "tz4a98xxat96iws-zmbrgj3a", // involve symbols ]; const results = invalidStrings.map((s) => cuid2.safeParse(s)); expect(results.every((r) => !r.success)).toEqual(true); if (!results[0].success) { expect(results[0].error.issues[0].message).toEqual("Invalid cuid2"); } }); test("ulid", () => { const ulid = z.string().ulid(); ulid.parse("01ARZ3NDEKTSV4RRFFQ69G5FAV"); const result = ulid.safeParse("invalidulid"); expect(result).toMatchObject({ success: false }); const tooLong = "01ARZ3NDEKTSV4RRFFQ69G5FAVA"; expect(ulid.safeParse(tooLong)).toMatchObject({ success: false }); const caseInsensitive = ulid.safeParse("01arZ3nDeKTsV4RRffQ69G5FAV"); expect(caseInsensitive.success).toEqual(true); expect(result.error!.issues[0].message).toEqual("Invalid ULID"); expect(result.error).toMatchInlineSnapshot(` [ZodError: [ { "origin": "string", "code": "invalid_format", "format": "ulid", "pattern": "/^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/", "path": [], "message": "Invalid ULID" } ]] `); }); test("xid", () => { const xid = z.string().xid(); xid.parse("9m4e2mr0ui3e8a215n4g"); const result = xid.safeParse("invalidxid"); expect(result).toMatchObject({ success: false }); expect(result.error!.issues[0].message).toEqual("Invalid XID"); expect(result.error).toMatchInlineSnapshot(` [ZodError: [ { "origin": "string", "code": "invalid_format", "format": "xid", "pattern": "/^[0-9a-vA-V]{20}$/", "path": [], "message": "Invalid XID" } ]] `); }); test("ksuid", () => { const ksuid = z.string().ksuid(); ksuid.parse("0o0t9hkGxgFLtd3lmJ4TSTeY0Vb"); const result = ksuid.safeParse("invalidksuid"); expect(result).toMatchObject({ success: false }); const tooLong = "0o0t9hkGxgFLtd3lmJ4TSTeY0VbA"; expect(ksuid.safeParse(tooLong)).toMatchObject({ success: false }); expect(result.error!.issues).toMatchInlineSnapshot(` [ { "code": "invalid_format", "format": "ksuid", "message": "Invalid KSUID", "origin": "string", "path": [], "pattern": "/^[A-Za-z0-9]{27}$/", }, ] `); }); test("regex", () => { z.string() .regex(/^moo+$/) .parse("mooooo"); expect(() => z.string().uuid().parse("purr")).toThrow(); }); test("regexp error message", () => { const result = z .string() .regex(/^moo+$/) .safeParse("boooo"); expect(result.error!.issues).toMatchInlineSnapshot(` [ { "code": "invalid_format", "format": "regex", "message": "Invalid string: must match pattern /^moo+$/", "origin": "string", "path": [], "pattern": "/^moo+$/", }, ] `); expect(() => z.string().uuid().parse("purr")).toThrow(); }); test("regexp error custom message", () => { const result = z .string() .regex(/^moo+$/, { message: "Custom error message" }) .safeParse("boooo"); expect(result.error!.issues).toMatchInlineSnapshot(` [ { "code": "invalid_format", "format": "regex", "message": "Custom error message", "origin": "string", "path": [], "pattern": "/^moo+$/", }, ] `); expect(() => z.string().uuid().parse("purr")).toThrow(); }); test("regex lastIndex reset", () => { const schema = z.string().regex(/^\d+$/g); expect(schema.safeParse("123").success).toEqual(true); expect(schema.safeParse("123").success).toEqual(true); expect(schema.safeParse("123").success).toEqual(true); expect(schema.safeParse("123").success).toEqual(true); expect(schema.safeParse("123").success).toEqual(true); }); test("format", () => { expect(z.string().email().format).toEqual("email"); expect(z.string().url().format).toEqual("url"); expect(z.string().jwt().format).toEqual("jwt"); expect(z.string().emoji().format).toEqual("emoji"); expect(z.string().guid().format).toEqual("guid"); expect(z.string().uuid().format).toEqual("uuid"); expect(z.string().uuidv4().format).toEqual("uuid"); expect(z.string().uuidv6().format).toEqual("uuid"); expect(z.string().uuidv7().format).toEqual("uuid"); expect(z.string().nanoid().format).toEqual("nanoid"); expect(z.string().guid().format).toEqual("guid"); expect(z.string().cuid().format).toEqual("cuid"); expect(z.string().cuid2().format).toEqual("cuid2"); expect(z.string().ulid().format).toEqual("ulid"); expect(z.string().base64().format).toEqual("base64"); // expect(z.string().jsonString().format).toEqual("json_string"); // expect(z.string().json().format).toEqual("json_string"); expect(z.string().xid().format).toEqual("xid"); expect(z.string().ksuid().format).toEqual("ksuid"); // expect(z.string().ip().format).toEqual("ip"); expect(z.string().ipv4().format).toEqual("ipv4"); expect(z.string().ipv6().format).toEqual("ipv6"); expect(z.string().e164().format).toEqual("e164"); expect(z.string().datetime().format).toEqual("datetime"); expect(z.string().date().format).toEqual("date"); expect(z.string().time().format).toEqual("time"); expect(z.string().duration().format).toEqual("duration"); expect(z.mac().format).toEqual("mac"); }); test("min max getters", () => { expect(z.string().min(5).minLength).toEqual(5); expect(z.string().min(5).min(10).minLength).toEqual(10); expect(z.string().minLength).toEqual(null); expect(z.string().max(5).maxLength).toEqual(5); expect(z.string().max(5).max(1).maxLength).toEqual(1); expect(z.string().max(5).max(10).maxLength).toEqual(5); expect(z.string().maxLength).toEqual(null); }); test("trim", () => { expect(z.string().trim().min(2).parse(" 12 ")).toEqual("12"); // ordering of methods is respected expect(z.string().min(2).trim().parse(" 1 ")).toEqual("1"); expect(() => z.string().trim().min(2).parse(" 1 ")).toThrow(); }); test("lowerCase", () => { expect(z.string().toLowerCase().parse("ASDF")).toEqual("asdf"); expect(z.string().toUpperCase().parse("asdf")).toEqual("ASDF"); }); test("slugify", () => { expect(z.string().slugify().parse("Hello World")).toEqual("hello-world"); expect(z.string().slugify().parse(" Hello World ")).toEqual("hello-world"); expect(z.string().slugify().parse("Hello@World#123")).toEqual("helloworld123"); expect(z.string().slugify().parse("Hello-World")).toEqual("hello-world"); expect(z.string().slugify().parse("Hello_World")).toEqual("hello-world"); expect(z.string().slugify().parse("---Hello---World---")).toEqual("hello-world"); expect(z.string().slugify().parse("Hello World")).toEqual("hello-world"); expect(z.string().slugify().parse("Hello!@#$%^&*()World")).toEqual("helloworld"); // can be used with check expect(z.string().check(z.slugify()).parse("Hello World")).toEqual("hello-world"); // can be chained with other methods expect(z.string().slugify().min(5).parse("Hello World")).toEqual("hello-world"); expect(() => z.string().slugify().min(20).parse("Hello World")).toThrow(); }); // test("IP validation", () => { // const ipSchema = z.string().ip(); // // General IP validation (accepts both v4 and v6) // expect(ipSchema.safeParse("114.71.82.94").success).toBe(true); // expect(ipSchema.safeParse("0.0.0.0").success).toBe(true); // expect(ipSchema.safeParse("37.85.236.115").success).toBe(true); // expect(ipSchema.safeParse("1e5e:e6c8:daac:514b:114b:e360:d8c0:682c").success).toBe(true); // expect(ipSchema.safeParse("9d4:c956:420f:5788:4339:9b3b:2418:75c3").success).toBe(true); // expect(ipSchema.safeParse("a6ea::2454:a5ce:94.105.123.75").success).toBe(true); // expect(ipSchema.safeParse("474f:4c83::4e40:a47:ff95:0cda").success).toBe(true); // expect(ipSchema.safeParse("d329:0:25b4:db47:a9d1:0:4926:0000").success).toBe(true); // expect(ipSchema.safeParse("e48:10fb:1499:3e28:e4b6:dea5:4692:912c").success).toBe(true); // expect(ipSchema.safeParse("d329:1be4:25b4:db47:a9d1:dc71:4926:992c:14af").success).toBe(false); // expect(ipSchema.safeParse("d5e7:7214:2b78::3906:85e6:53cc:709:32ba").success).toBe(false); // expect(ipSchema.safeParse("8f69::c757:395e:976e::3441").success).toBe(false); // expect(ipSchema.safeParse("54cb::473f:d516:0.255.256.22").success).toBe(false); // expect(ipSchema.safeParse("54cb::473f:d516:192.168.1").success).toBe(false); // expect(ipSchema.safeParse("256.0.4.4").success).toBe(false); // expect(ipSchema.safeParse("-1.0.555.4").success).toBe(false); // expect(ipSchema.safeParse("0.0.0.0.0").success).toBe(false); // expect(ipSchema.safeParse("1.1.1").success).toBe(false); // }); test("IPv4 validation", () => { const ipv4 = z.string().ipv4(); // Valid IPv4 addresses expect(ipv4.safeParse("114.71.82.94").success).toBe(true); expect(ipv4.safeParse("0.0.0.0").success).toBe(true); expect(ipv4.safeParse("37.85.236.115").success).toBe(true); expect(ipv4.safeParse("192.168.0.1").success).toBe(true); expect(ipv4.safeParse("255.255.255.255").success).toBe(true); expect(ipv4.safeParse("1.2.3.4").success).toBe(true); // Invalid IPv4 addresses expect(ipv4.safeParse("256.0.4.4").success).toBe(false); expect(ipv4.safeParse("-1.0.555.4").success).toBe(false); expect(ipv4.safeParse("0.0.0.0.0").success).toBe(false); expect(ipv4.safeParse("1.1.1").success).toBe(false); expect(ipv4.safeParse("1e5e:e6c8:daac:514b:114b:e360:d8c0:682c").success).toBe(false); expect(ipv4.safeParse("a6ea::2454:a5ce:94.105.123.75").success).toBe(false); expect(ipv4.safeParse("not an ip").success).toBe(false); expect(ipv4.safeParse("1.2.3").success).toBe(false); expect(ipv4.safeParse("1.2.3.4.5").success).toBe(false); expect(ipv4.safeParse("1.2.3.256").success).toBe(false); // Test specific error expect(() => ipv4.parse("6097:adfa:6f0b:220d:db08:5021:6191:7990")).toThrow(); }); test("IPv6 validation", () => { const ipv6 = z.string().ipv6(); // Valid IPv6 addresses expect(ipv6.safeParse("1e5e:e6c8:daac:514b:114b:e360:d8c0:682c").success).toBe(true); expect(ipv6.safeParse("9d4:c956:420f:5788:4339:9b3b:2418:75c3").success).toBe(true); expect(ipv6.safeParse("a6ea::2454:a5ce:94.105.123.75").success).toBe(true); expect(ipv6.safeParse("474f:4c83::4e40:a47:ff95:0cda").success).toBe(true); expect(ipv6.safeParse("d329:0:25b4:db47:a9d1:0:4926:0000").success).toBe(true); expect(ipv6.safeParse("e48:10fb:1499:3e28:e4b6:dea5:4692:912c").success).toBe(true); expect(ipv6.safeParse("::1").success).toBe(true); expect(ipv6.safeParse("2001:db8::").success).toBe(true); expect(ipv6.safeParse("2001:0db8:85a3:0000:0000:8a2e:0370:7334").success).toBe(true); expect(ipv6.safeParse("2001:db8::192.168.0.1").success).toBe(true); expect(ipv6.safeParse("::ffff:192.168.0.1").success).toBe(true); expect(ipv6.safeParse("::ffff:c000:0280").success).toBe(true); // IPv4-mapped IPv6 address expect(ipv6.safeParse("64:ff9b::192.168.0.1").success).toBe(true); // IPv4/IPv6 translation // Invalid IPv6 addresses expect(ipv6.safeParse("d329:1be4:25b4:db47:a9d1:dc71:4926:992c:14af").success).toBe(false); expect(ipv6.safeParse("d5e7:7214:2b78::3906:85e6:53cc:709:32ba").success).toBe(false); expect(ipv6.safeParse("8f69::c757:395e:976e::3441").success).toBe(false); expect(ipv6.safeParse("54cb::473f:d516:0.255.256.22").success).toBe(false); expect(ipv6.safeParse("54cb::473f:d516:192.168.1").success).toBe(false); expect(ipv6.safeParse("114.71.82.94").success).toBe(false); expect(ipv6.safeParse("not an ip").success).toBe(false); expect(ipv6.safeParse("g123::1234:5678").success).toBe(false); // Test specific error expect(() => ipv6.parse("254.164.77.1")).toThrow(); }); test("MAC validation", () => { const mac = z.mac(); // Valid MAC addresses expect(mac.safeParse("00:1A:2B:3C:4D:5E").success).toBe(true); expect(mac.safeParse("FF:FF:FF:FF:FF:FF").success).toBe(true); expect(mac.safeParse("00:11:22:33:44:55").success).toBe(true); expect(mac.safeParse("A1:B2:C3:D4:E5:F6").success).toBe(true); expect(mac.safeParse("10:20:30:40:50:60").success).toBe(true); expect(mac.safeParse("0a:1b:2c:3d:4e:5f").success).toBe(true); expect(mac.safeParse("12:34:56:78:9A:BC").success).toBe(true); // Invalid MAC addresses expect(mac.safeParse("00:1A-2B:3C-4D:5E").success).toBe(false); expect(mac.safeParse("00:1A:2B:3C:4D").success).toBe(false); expect(mac.safeParse("00:1A:2B:3C:4D").success).toBe(false); expect(mac.safeParse("00-1A-2B-3C-4D").success).toBe(false); expect(mac.safeParse("01-23-45-67-89-AB").success).toBe(false); // Dash delimiter not accepted by default expect(mac.safeParse("AA-BB-CC-DD-EE-FF").success).toBe(false); // Dash delimiter not accepted by default expect(mac.safeParse("DE-AD-BE-EF-00-01").success).toBe(false); // Dash delimiter not accepted by default expect(mac.safeParse("98-76-54-32-10-FF").success).toBe(false); // Dash delimiter not accepted by default expect(mac.safeParse("00:1A:2B:3C:4D:GZ").success).toBe(false); expect(mac.safeParse("00:1A:2B:3C:4D:5E:GG").success).toBe(false); expect(mac.safeParse("123:45:67:89:AB:CD").success).toBe(false); expect(mac.safeParse("00--1A:2B:3C:4D:5E").success).toBe(false); expect(mac.safeParse("00:1A::2B:3C:4D:5E").success).toBe(false); expect(mac.safeParse("00:1A:2B:3C:3C:2B:1A:00").success).toBe(false); // Disallow EUI-64 expect(mac.safeParse("00:1a:2B:3c:4D:5e").success).toBe(false); // Disallow mixed-case // MAC formats that are nonstandard but occassionally referenced, ex. https://www.postgresql.org/docs/17/datatype-net-types.html#DATATYPE-MACADDR expect(mac.safeParse("00:1A:2B:3C:4D:5E:FF").success).toBe(false); expect(mac.safeParse("001A2B:3C4D5E").success).toBe(false); expect(mac.safeParse("001A:2B3C:4D5E").success).toBe(false); expect(mac.safeParse("001A.2B3C.4D5E").success).toBe(false); expect(mac.safeParse("001A2B3C4D5E").success).toBe(false); expect(mac.safeParse("00.1A.2B.3C.4D.5E").success).toBe(false); }); test("MAC validation with custom delimiter", () => { const colonMac = z.mac({ delimiter: ":" }); expect(colonMac.safeParse("00:1A:2B:3C:4D:5E").success).toBe(true); expect(colonMac.safeParse("00-1A-2B-3C-4D-5E").success).toBe(false); const dashMac = z.mac({ delimiter: "-" }); expect(dashMac.safeParse("00-1A-2B-3C-4D-5E").success).toBe(true); expect(dashMac.safeParse("00:1A:2B:3C:4D:5E").success).toBe(false); const colonOnlyMac = z.mac({ delimiter: ":" }); expect(colonOnlyMac.safeParse("00:1A:2B:3C:4D:5E").success).toBe(true); expect(colonOnlyMac.safeParse("00-1A-2B-3C-4D-5E").success).toBe(false); }); test("CIDR v4 validation", () => { const cidrV4 = z.string().cidrv4(); // Valid CIDR v4 addresses expect(cidrV4.safeParse("192.168.0.0/24").success).toBe(true); expect(cidrV4.safeParse("10.0.0.0/8").success).toBe(true); expect(cidrV4.safeParse("172.16.0.0/12").success).toBe(true); expect(cidrV4.safeParse("0.0.0.0/0").success).toBe(true); expect(cidrV4.safeParse("255.255.255.255/32").success).toBe(true); // Invalid CIDR v4 addresses expect(cidrV4.safeParse("192.168.0.0").success).toBe(false); // Missing prefix expect(cidrV4.safeParse("192.168.0.0/33").success).toBe(false); // Invalid prefix length expect(cidrV4.safeParse("256.0.0.0/24").success).toBe(false); // Invalid IP expect(cidrV4.safeParse("192.168.0.0/-1").success).toBe(false); // Negative prefix length expect(cidrV4.safeParse("not a cidr").success).toBe(false); // Invalid format }); test("CIDR v6 validation", () => { const cidrV6 = z.string().cidrv6(); // Valid CIDR v6 addresses expect(cidrV6.safeParse("2001:db8::/32").success).toBe(true); expect(cidrV6.safeParse("::/0").success).toBe(true); expect(cidrV6.safeParse("fe80::/10").success).toBe(true); expect(cidrV6.safeParse("::1/128").success).toBe(true); expect(cidrV6.safeParse("2001:0db8:85a3::/64").success).toBe(true); // Invalid CIDR v6 addresses expect(cidrV6.safeParse("2001:db8::").success).toBe(false); // Missing prefix expect(cidrV6.safeParse("2001:db8::/129").success).toBe(false); // Invalid prefix length expect(cidrV6.safeParse("2001:db8::/abc").success).toBe(false); // Invalid prefix format expect(cidrV6.safeParse("not a cidr").success).toBe(false); // Invalid format expect(cidrV6.safeParse("192.168.0.0/24").success).toBe(false); // IPv4 CIDR in v6 validation expect(cidrV6.safeParse("2001:0db8:85a3::/64/whatever-after").success).toBe(false); expect(cidrV6.safeParse("22d9:f4a8:6a90:f3bf:dcaa:2beb:5fba:0000/112").success).toBe(true); expect(cidrV6.safeParse("22d9:f4a8:6a90:f3bf:dcaa:2beb:5fba:0000/112/268").success).toBe(false); }); test("E.164 validation", () => { const e164Number = z.string().e164(); expect(e164Number.safeParse("+1555555").success).toBe(true); const validE164Numbers = [ "+1555555", // min-length (7 digits + '+') "+15555555", "+155555555", "+1555555555", "+15555555555", "+155555555555", "+1555555555555", "+15555555555555", "+155555555555555", "+105555555555555", "+100555555555555", // max-length (15 digits + '+') ]; const invalidE164Numbers = [ "", // empty "+", // only plus sign "-", // wrong sign " 555555555", // starts with space "555555555", // missing plus sign "+1 555 555 555", // space after plus sign "+1555 555 555", // space between numbers "+1555+555", // multiple plus signs "+0000000", // leading zero country code "+0123456789", // leading zero with more digits "+1555555555555555", // too long "+115abc55", // non numeric characters in number part "+1555555 ", // space after number ]; expect(validE164Numbers.every((number) => e164Number.safeParse(number).success)).toBe(true); expect(invalidE164Numbers.every((number) => e164Number.safeParse(number).success === false)).toBe(true); }); test("hostname", () => { const hostname = z.hostname(); // Valid hostnames hostname.parse("localhost"); hostname.parse("example.com"); hostname.parse("sub.example.com"); hostname.parse("a-b-c.example.com"); hostname.parse("123.example.com"); hostname.parse("example-123.com"); hostname.parse("example-123.1234"); hostname.parse("developer.mozilla.org"); hostname.parse("hello.world.example.com"); hostname.parse("www.google.com"); hostname.parse("192.168.1.1"); hostname.parse("xn--d1acj3b.com"); hostname.parse("xn--d1acj3b.org"); hostname.parse("xn--d1acj3b"); // Invalid hostnames expect(() => hostname.parse("")).toThrow(); expect(() => hostname.parse("example..com")).toThrow(); expect(() => hostname.parse("example-.com")).toThrow(); expect(() => hostname.parse("-example.com")).toThrow(); expect(() => hostname.parse("example.com-")).toThrow(); expect(() => hostname.parse("example_com")).toThrow(); expect(() => hostname.parse("example.com:8080")).toThrow(); expect(() => hostname.parse("http://example.com")).toThrow(); expect(() => hostname.parse("ht!tp://invalid.com")).toThrow(); expect(() => hostname.parse("xn--d1acj3b..com")).toThrow(); expect(() => hostname.parse("ex@mple.com")).toThrow(); expect(() => hostname.parse("[2001:db8::zzzz]")).toThrow(); expect(() => hostname.parse("exa mple.com")).toThrow(); expect(() => hostname.parse("-example.com")).toThrow(); expect(() => hostname.parse("example..com")).toThrow(); }); test("hash validation", () => { // MD5 tests const md5hex = z.hash("md5"); const md5base64 = z.hash("md5", { enc: "base64" }); const md5base64url = z.hash("md5", { enc: "base64url" }); // Valid MD5 hashes expect(md5hex.parse("5d41402abc4b2a76b9719d911017c592")).toBe("5d41402abc4b2a76b9719d911017c592"); expect(md5hex.parse("5D41402ABC4B2A76B9719D911017C592")).toBe("5D41402ABC4B2A76B9719D911017C592"); // uppercase expect(md5base64.parse("XUFAKrxLKna5cZ2REBfFkg==")).toBe("XUFAKrxLKna5cZ2REBfFkg=="); expect(md5base64url.parse("XUFAKrxLKna5cZ2REBfFkg")).toBe("XUFAKrxLKna5cZ2REBfFkg"); // Invalid MD5 hashes expect(() => md5hex.parse("5d41402abc4b2a76b9719d911017c59")).toThrow(); // too short expect(() => md5hex.parse("5d41402abc4b2a76b9719d911017c592x")).toThrow(); // too long expect(() => md5base64.parse("XUFAKrxLKna5cZ2REBfFkg=")).toThrow(); // wrong padding expect(() => md5base64url.parse("XUFAKrxLKna5cZ2REBfFkg=")).toThrow(); // has padding // SHA1 tests const sha1hex = z.hash("sha1"); const sha1base64 = z.hash("sha1", { enc: "base64" }); const sha1base64url = z.hash("sha1", { enc: "base64url" }); // Valid SHA1 hashes expect(sha1hex.parse("aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d")).toBe("aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"); expect(sha1base64.parse("qvTGHdzF6KLavt4PO0gs2a6pQ00=")).toBe("qvTGHdzF6KLavt4PO0gs2a6pQ00="); expect(sha1base64url.parse("qvTGHdzF6KLavt4PO0gs2a6pQ00")).toBe("qvTGHdzF6KLavt4PO0gs2a6pQ00"); // SHA256 tests const sha256hex = z.hash("sha256"); const sha256base64 = z.hash("sha256", { enc: "base64" }); const sha256base64url = z.hash("sha256", { enc: "base64url" }); // Valid SHA256 hashes expect(sha256hex.parse("2cf24dba4f21d4288094c4a2e2c2d6c6b0c3e0c8f0e0c8f0e0c8f0e0c8f0e0c8")).toBe( "2cf24dba4f21d4288094c4a2e2c2d6c6b0c3e0c8f0e0c8f0e0c8f0e0c8f0e0c8" ); expect(sha256base64.parse("LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=")).toBe( "LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=" ); expect(sha256base64url.parse("LPJNul-wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ")).toBe( "LPJNul-wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ" ); // SHA384 tests (no padding in base64) const sha384hex = z.hash("sha384"); const sha384base64 = z.hash("sha384", { enc: "base64" }); expect( sha384hex.parse("59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcdb9c666fa90125a3c79f90397bdf5f6a13de828684f") ).toBe("59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcdb9c666fa90125a3c79f90397bdf5f6a13de828684f"); expect(sha384base64.parse("WeF0h3dEjGneawDXozO7+5/xtGPkQ1TDVTvNucZm+pASWjx5+QOXvfX2oT3oKGhP")).toBe( "WeF0h3dEjGneawDXozO7+5/xtGPkQ1TDVTvNucZm+pASWjx5+QOXvfX2oT3oKGhP" ); // SHA512 tests const sha512hex = z.hash("sha512"); const sha512base64 = z.hash("sha512", { enc: "base64" }); expect( sha512hex.parse( "9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043" ) ).toBe( "9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043" ); expect( sha512base64.parse("m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw==") ).toBe("m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw=="); // Test default encoding (hex) const defaultHash = z.hash("sha256"); expect(defaultHash.parse("2cf24dba4f21d4288094c4a2e2c2d6c6b0c3e0c8f0e0c8f0e0c8f0e0c8f0e0c8")).toBe( "2cf24dba4f21d4288094c4a2e2c2d6c6b0c3e0c8f0e0c8f0e0c8f0e0c8f0e0c8" ); // Test with custom error message const hashWithMessage = z.hash("md5", { message: "Invalid MD5 hash" }); expect(() => hashWithMessage.parse("invalid")).toThrow("Invalid MD5 hash"); });
Save
cmd:
run