Brunobkr/llama.cpp_AlgMor24_github
ΩFFFΣLLIa • llama.cpp • AlgMor24 ██████╗ ███████╗███████╗███████╗██╗ ██╗ ██╗ █████╗ ██╔═══██╗██╔════╝██╔════╝██╔════╝██║ ██║ ██║██╔══██╗ ██║ ██║█████╗ █████╗ █████╗ ██║ ██║ ██║███████║ ██║ ██║██╔══╝ ██╔══╝ ██╔══╝ ██║ ██║ ██║██╔══██║ ╚██████╔╝██║ ██║ ███████╗███████╗███████╗██║██║ ██║ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝╚══════╝╚═╝╚═╝ ╚═╝ High-Performance LLM / VLM Inference & Autonomous Agentic Ecosystem… See the full description on the dataset page: https://huggingface.co/datasets/Brunobkr/llama.cpp_AlgMor24_github.
03.1k
1import { Buffer } from "node:buffer";2// @ts-ignore TS61333import { expect, test } from "vitest";4 5import * as z from "zod/v3";6 7const minFive = z.string().min(5, "min5");8const maxFive = z.string().max(5, "max5");9const justFive = z.string().length(5);10const nonempty = z.string().nonempty("nonempty");11const includes = z.string().includes("includes");12const includesFromIndex2 = z.string().includes("includes", { position: 2 });13const startsWith = z.string().startsWith("startsWith");14const endsWith = z.string().endsWith("endsWith");15 16test("passing validations", () => {17 minFive.parse("12345");18 minFive.parse("123456");19 maxFive.parse("12345");20 maxFive.parse("1234");21 nonempty.parse("1");22 justFive.parse("12345");23 includes.parse("XincludesXX");24 includesFromIndex2.parse("XXXincludesXX");25 startsWith.parse("startsWithX");26 endsWith.parse("XendsWith");27});28 29test("failing validations", () => {30 expect(() => minFive.parse("1234")).toThrow();31 expect(() => maxFive.parse("123456")).toThrow();32 expect(() => nonempty.parse("")).toThrow();33 expect(() => justFive.parse("1234")).toThrow();34 expect(() => justFive.parse("123456")).toThrow();35 expect(() => includes.parse("XincludeXX")).toThrow();36 expect(() => includesFromIndex2.parse("XincludesXX")).toThrow();37 expect(() => startsWith.parse("x")).toThrow();38 expect(() => endsWith.parse("x")).toThrow();39});40 41test("email validations", () => {42 const validEmails = [43 `email@domain.com`,44 `firstname.lastname@domain.com`,45 `email@subdomain.domain.com`,46 `firstname+lastname@domain.com`,47 `1234567890@domain.com`,48 `email@domain-one.com`,49 `_______@domain.com`,50 `email@domain.name`,51 `email@domain.co.jp`,52 `firstname-lastname@domain.com`,53 `very.common@example.com`,54 `disposable.style.email.with+symbol@example.com`,55 `other.email-with-hyphen@example.com`,56 `fully-qualified-domain@example.com`,57 `user.name+tag+sorting@example.com`,58 `x@example.com`,59 `mojojojo@asdf.example.com`,60 `example-indeed@strange-example.com`,61 `example@s.example`,62 `user-@example.org`,63 `user@my-example.com`,64 `a@b.cd`,65 `work+user@mail.com`,66 `tom@test.te-st.com`,67 `something@subdomain.domain-with-hyphens.tld`,68 `common'name@domain.com`,69 `francois@etu.inp-n7.fr`,70 ];71 const invalidEmails = [72 // no "printable characters"73 // `user%example.com@example.org`,74 // `mailhost!username@example.org`,75 // `test/test@test.com`,76 77 // double @78 `francois@@etu.inp-n7.fr`,79 // do not support quotes80 `"email"@domain.com`,81 `"e asdf sadf ?<>ail"@domain.com`,82 `" "@example.org`,83 `"john..doe"@example.org`,84 `"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com`,85 // do not support comma86 `a,b@domain.com`,87 88 // do not support IPv489 `email@123.123.123.123`,90 `email@[123.123.123.123]`,91 `postmaster@123.123.123.123`,92 `user@[68.185.127.196]`,93 `ipv4@[85.129.96.247]`,94 `valid@[79.208.229.53]`,95 `valid@[255.255.255.255]`,96 `valid@[255.0.55.2]`,97 `valid@[255.0.55.2]`,98 99 // do not support ipv6100 `hgrebert0@[IPv6:4dc8:ac7:ce79:8878:1290:6098:5c50:1f25]`,101 `bshapiro4@[IPv6:3669:c709:e981:4884:59a3:75d1:166b:9ae]`,102 `jsmith@[IPv6:2001:db8::1]`,103 `postmaster@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]`,104 `postmaster@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:192.168.1.1]`,105 106 // microsoft test cases107 `plainaddress`,108 `#@%^%#$@#$@#.com`,109 `@domain.com`,110 `Joe Smith <email@domain.com>`,111 `email.domain.com`,112 `email@domain@domain.com`,113 `.email@domain.com`,114 `email.@domain.com`,115 `email..email@domain.com`,116 `あいうえお@domain.com`,117 `email@domain.com (Joe Smith)`,118 `email@domain`,119 `email@-domain.com`,120 `email@111.222.333.44444`,121 `email@domain..com`,122 `Abc.example.com`,123 `A@b@c@example.com`,124 `colin..hacks@domain.com`,125 `a"b(c)d,e:f;g<h>i[j\k]l@example.com`,126 `just"not"right@example.com`,127 `this is"not\allowed@example.com`,128 `this\ still\"not\\allowed@example.com`,129 130 // random131 `i_like_underscore@but_its_not_allowed_in_this_part.example.com`,132 `QA[icon]CHOCOLATE[icon]@test.com`,133 `invalid@-start.com`,134 `invalid@end.com-`,135 `a.b@c.d`,136 `invalid@[1.1.1.-1]`,137 `invalid@[68.185.127.196.55]`,138 `temp@[192.168.1]`,139 `temp@[9.18.122.]`,140 `double..point@test.com`,141 `asdad@test..com`,142 `asdad@hghg...sd...au`,143 `asdad@hghg........au`,144 `invalid@[256.2.2.48]`,145 `invalid@[256.2.2.48]`,146 `invalid@[999.465.265.1]`,147 `jkibbey4@[IPv6:82c4:19a8::70a9:2aac:557::ea69:d985:28d]`,148 `mlivesay3@[9952:143f:b4df:2179:49a1:5e82:b92e:6b6]`,149 `gbacher0@[IPv6:bc37:4d3f:5048:2e26:37cc:248e:df8e:2f7f:af]`,150 `invalid@[IPv6:5348:4ed3:5d38:67fb:e9b:acd2:c13:192.168.256.1]`,151 `test@.com`,152 `aaaaaaaaaaaaaaalongemailthatcausesregexDoSvulnerability@test.c`,153 ];154 const emailSchema = z.string().email();155 156 expect(157 validEmails.every((email) => {158 return emailSchema.safeParse(email).success;159 })160 ).toBe(true);161 expect(162 invalidEmails.every((email) => {163 return emailSchema.safeParse(email).success === false;164 })165 ).toBe(true);166});167 168const validBase64Strings = [169 "SGVsbG8gV29ybGQ=", // "Hello World"170 "VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw==", // "This is an encoded string"171 "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcms=", // "Many hands make light work"172 "UGF0aWVuY2UgaXMgdGhlIGtleSB0byBzdWNjZXNz", // "Patience is the key to success"173 "QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg==", // "Base64 encoding is fun"174 "MTIzNDU2Nzg5MA==", // "1234567890"175 "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=", // "abcdefghijklmnopqrstuvwxyz"176 "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=", // "ABCDEFGHIJKLMNOPQRSTUVWXYZ"177 "ISIkJSMmJyonKCk=", // "!\"#$%&'()*"178 "", // Empty string is technically valid base64179 "w7/Dv8O+w74K", // ÿÿþþ180];181 182for (const str of validBase64Strings) {183 test(`base64 should accept ${str}`, () => {184 expect(z.string().base64().safeParse(str).success).toBe(true);185 });186}187 188const invalidBase64Strings = [189 "12345", // Not padded correctly, not a multiple of 4 characters190 "12345===", // Not padded correctly191 "SGVsbG8gV29ybGQ", // Missing padding192 "VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw", // Missing padding193 "!UGF0aWVuY2UgaXMgdGhlIGtleSB0byBzdWNjZXNz", // Invalid character '!'194 "?QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg==", // Invalid character '?'195 ".MTIzND2Nzg5MC4=", // Invalid character '.'196 "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo", // Missing padding197 "w7_Dv8O-w74K", // Has - and _ characters (is base64url)198];199 200for (const str of invalidBase64Strings) {201 test(`base64 should reject ${str}`, () => {202 expect(z.string().base64().safeParse(str).success).toBe(false);203 });204}205 206const validBase64URLStrings = [207 "SGVsbG8gV29ybGQ", // "Hello World"208 "SGVsbG8gV29ybGQ=", // "Hello World" with padding209 "VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw", // "This is an encoded string"210 "VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw==", // "This is an encoded string" with padding211 "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcms", // "Many hands make light work"212 "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcms=", // "Many hands make light work" with padding213 "UGF0aWVuY2UgaXMgdGhlIGtleSB0byBzdWNjZXNz", // "Patience is the key to success"214 "QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg", // "Base64 encoding is fun"215 "QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg==", // "Base64 encoding is fun" with padding216 "MTIzNDU2Nzg5MA", // "1234567890"217 "MTIzNDU2Nzg5MA==", // "1234567890" with padding218 "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo", // "abcdefghijklmnopqrstuvwxyz"219 "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=", // "abcdefghijklmnopqrstuvwxyz with padding"220 "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo", // "ABCDEFGHIJKLMNOPQRSTUVWXYZ"221 "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=", // "ABCDEFGHIJKLMNOPQRSTUVWXYZ" with padding222 "ISIkJSMmJyonKCk", // "!\"#$%&'()*"223 "ISIkJSMmJyonKCk=", // "!\"#$%&'()*" with padding224 "", // Empty string is technically valid base64url225 "w7_Dv8O-w74K", // ÿÿþþ226 "123456",227];228 229for (const str of validBase64URLStrings) {230 test(`base64url should accept ${str}`, () => {231 expect(z.string().base64url().safeParse(str).success).toBe(true);232 });233}234 235const invalidBase64URLStrings = [236 "w7/Dv8O+w74K", // Has + and / characters (is base64)237 "12345", // Invalid length (not a multiple of 4 characters when adding allowed number of padding characters)238 "12345===", // Not padded correctly239 "!UGF0aWVuY2UgaXMgdGhlIGtleSB0byBzdWNjZXNz", // Invalid character '!'240 "?QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg==", // Invalid character '?'241 ".MTIzND2Nzg5MC4=", // Invalid character '.'242];243 244for (const str of invalidBase64URLStrings) {245 test(`base64url should reject ${str}`, () => {246 expect(z.string().base64url().safeParse(str).success).toBe(false);247 });248}249 250function makeJwt(header: object, payload: object) {251 const headerBase64 = Buffer.from(JSON.stringify(header)).toString("base64url");252 const payloadBase64 = Buffer.from(JSON.stringify(payload)).toString("base64url");253 const signature = "signature"; // Placeholder for the signature254 return `${headerBase64}.${payloadBase64}.${signature}`;255}256 257test("jwt validations", () => {258 const jwt = z.string().jwt();259 const jwtWithAlg = z.string().jwt({ alg: "HS256" });260 261 expect(() => jwt.parse("invalid")).toThrow();262 expect(() => jwt.parse("invalid.invalid")).toThrow();263 expect(() => jwt.parse("invalid.invalid.invalid")).toThrow();264 265 // Valid JWTs266 const d1 = makeJwt({ typ: "JWT", alg: "HS256" }, {});267 expect(() => jwt.parse(d1)).not.toThrow();268 expect(() => jwtWithAlg.parse(d1)).not.toThrow();269 270 // Invalid header271 const d2 = makeJwt({}, {});272 expect(() => jwt.parse(d2)).toThrow();273 274 // Wrong algorithm275 const d3 = makeJwt({ typ: "JWT", alg: "RS256" }, {});276 expect(() => jwtWithAlg.parse(d3)).toThrow();277 278 // missing typ is fine279 const d4 = makeJwt({ alg: "HS256" }, {});280 jwt.parse(d4);281 282 // type isn't JWT283 const d5 = makeJwt({ typ: "SUP", alg: "HS256" }, { foo: "bar" });284 expect(() => jwt.parse(d5)).toThrow();285 286 // Custom error message287 const customMsg = "Invalid JWT token";288 const jwtWithMsg = z.string().jwt({ message: customMsg });289 try {290 jwtWithMsg.parse("invalid");291 } catch (error) {292 expect((error as z.ZodError).issues[0].message).toBe(customMsg);293 }294});295 296test("url validations", () => {297 const url = z.string().url();298 url.parse("http://google.com");299 url.parse("https://google.com/asdf?asdf=ljk3lk4&asdf=234#asdf");300 expect(() => url.parse("asdf")).toThrow();301 expect(() => url.parse("https:/")).toThrow();302 expect(() => url.parse("asdfj@lkjsdf.com")).toThrow();303});304 305test("url error overrides", () => {306 try {307 z.string().url().parse("https");308 } catch (err) {309 expect((err as z.ZodError).issues[0].message).toEqual("Invalid url");310 }311 try {312 z.string().url("badurl").parse("https");313 } catch (err) {314 expect((err as z.ZodError).issues[0].message).toEqual("badurl");315 }316 try {317 z.string().url({ message: "badurl" }).parse("https");318 } catch (err) {319 expect((err as z.ZodError).issues[0].message).toEqual("badurl");320 }321});322 323test("emoji validations", () => {324 const emoji = z.string().emoji();325 326 emoji.parse("👋👋👋👋");327 emoji.parse("🍺👩🚀🫡");328 emoji.parse("💚💙💜💛❤️");329 emoji.parse("🐛🗝🐏🍡🎦🚢🏨💫🎌☘🗡😹🔒🎬➡️🍹🗂🚨⚜🕑〽️🚦🌊🍴💍🍌💰😳🌺🍃");330 emoji.parse("🇹🇷🤽🏿♂️");331 emoji.parse(332 "😀😁😂🤣😃😄😅😆😉😊😋😎😍😘🥰😗😙😚☺️☺🙂🤗🤩🤔🤨😐😑😶🙄😏😣😥😮🤐😯😪😫😴😌😛😜😝🤤😒😓😔😕🙃🤑😲☹️☹🙁😖😞😟😤😢😭😦😧😨😩🤯😬😰😱🥵🥶😳🤪😵😡😠🤬😷🤒🤕🤢🤮🤧😇🤠🥳🥴🥺🤥🤫🤭🧐🤓😈👿🤡👹👺💀☠️☠👻👽👾🤖💩😺😸😹😻😼😽🙀😿😾🙈🙉🙊🏻🏼🏽🏾🏿👶👶🏻👶🏼👶🏽👶🏾👶🏿🧒🧒🏻🧒🏼🧒🏽🧒🏾🧒🏿👦👦🏻👦🏼👦🏽👦🏾👦🏿👧👧🏻👧🏼👧🏽👧🏾👧🏿🧑🧑🏻🧑🏼🧑🏽🧑🏾🧑🏿👨👨🏻👨🏼👨🏽👨🏾👨🏿👩👩🏻👩🏼👩🏽👩🏾👩🏿🧓🧓🏻🧓🏼🧓🏽🧓🏾🧓🏿👴👴🏻👴🏼👴🏽👴🏾👴🏿👵👵🏻👵🏼👵🏽👵🏾👵🏿👨⚕️👨⚕👨🏻⚕️👨🏻⚕👨🏼⚕️👨🏼⚕👨🏽⚕️👨🏽⚕👨🏾⚕️👨🏾⚕👨🏿⚕️👨🏿⚕👩⚕️👩⚕👩🏻⚕️👩🏻⚕👩🏼⚕️👩🏼⚕👩🏽⚕️👩🏽⚕👩🏾⚕️👩🏾⚕👩🏿⚕️👩🏿⚕👨🎓👨🏻🎓👨🏼🎓👨🏽🎓👨🏾🎓👨🏿🎓👩🎓👩🏻🎓👩🏼🎓👩🏽🎓👩🏾🎓👩🏿🎓👨🏫👨🏻🏫👨🏼🏫👨🏽🏫👨🏾🏫👨🏿🏫👩🏫👩🏻🏫👩🏼🏫👩🏽🏫👩🏾🏫👩🏿🏫👨⚖️👨⚖👨🏻⚖️👨🏻⚖👨🏼⚖️👨🏼⚖👨🏽⚖️👨🏽⚖👨🏾⚖️👨🏾⚖👨🏿⚖️👨🏿⚖👩⚖️👩⚖👩🏻⚖️👩🏻⚖👩🏼⚖️👩🏼⚖👩🏽⚖️👩🏽⚖👩🏾⚖️👩🏾⚖👩🏿⚖️👩🏿⚖👨🌾👨🏻🌾👨🏼🌾👨🏽🌾👨🏾🌾👨🏿🌾👩🌾👩🏻🌾👩🏼🌾👩🏽🌾👩🏾🌾👩🏿🌾👨🍳👨🏻🍳👨🏼🍳👨🏽🍳👨🏾🍳👨🏿🍳👩🍳👩🏻🍳👩🏼🍳👩🏽🍳👩🏾🍳👩🏿🍳👨🔧👨🏻🔧👨🏼🔧👨🏽🔧👨🏾🔧👨🏿🔧👩🔧👩🏻🔧👩🏼🔧👩🏽🔧👩🏾🔧👩🏿🔧👨🏭👨🏻🏭👨🏼🏭👨🏽🏭👨🏾🏭👨🏿🏭👩🏭👩🏻🏭👩🏼🏭👩🏽🏭👩🏾🏭👩🏿🏭👨💼👨🏻💼👨🏼💼👨🏽💼👨🏾💼👨🏿💼👩💼👩🏻💼👩🏼💼👩🏽💼👩🏾💼👩🏿💼👨🔬👨🏻🔬👨🏼🔬👨🏽🔬👨🏾🔬👨🏿🔬👩🔬👩🏻🔬👩🏼🔬👩🏽🔬👩🏾🔬👩🏿🔬👨💻👨🏻💻👨🏼💻👨🏽💻👨🏾💻👨🏿💻👩💻👩🏻💻👩🏼💻👩🏽💻👩🏾💻👩🏿💻👨🎤👨🏻🎤👨🏼🎤👨🏽🎤👨🏾🎤👨🏿🎤👩🎤👩🏻🎤👩🏼🎤👩🏽🎤👩🏾🎤👩🏿🎤👨🎨👨🏻🎨👨🏼🎨👨🏽🎨👨🏾🎨👨🏿🎨👩🎨👩🏻🎨👩🏼🎨👩🏽🎨👩🏾🎨👩🏿🎨👨✈️👨✈👨🏻✈️👨🏻✈👨🏼✈️👨🏼✈👨🏽✈️👨🏽✈👨🏾✈️👨🏾✈👨🏿✈️👨🏿✈👩✈️👩✈👩🏻✈️👩🏻✈👩🏼✈️👩🏼✈👩🏽✈️👩🏽✈👩🏾✈️👩🏾✈👩🏿✈️👩🏿✈👨🚀👨🏻🚀👨🏼🚀👨🏽🚀👨🏾🚀👨🏿🚀👩🚀👩🏻🚀👩🏼🚀👩🏽🚀👩🏾🚀👩🏿🚀👨🚒👨🏻🚒👨🏼🚒👨🏽🚒👨🏾🚒👨🏿🚒👩🚒👩🏻🚒👩🏼🚒👩🏽🚒👩🏾🚒👩🏿🚒👮👮🏻👮🏼👮🏽👮🏾👮🏿👮♂️👮♂👮🏻♂️👮🏻♂👮🏼♂️👮🏼♂👮🏽♂️👮🏽♂👮🏾♂️👮🏾♂👮🏿♂️👮🏿♂👮♀️👮♀👮🏻♀️👮🏻♀👮🏼♀️👮🏼♀👮🏽♀️👮🏽♀👮🏾♀️👮🏾♀👮🏿♀️👮🏿♀🕵️🕵🕵🏻🕵🏼🕵🏽🕵🏾🕵🏿🕵️♂️🕵♂️🕵️♂🕵♂🕵🏻♂️🕵🏻♂🕵🏼♂️🕵🏼♂🕵🏽♂️🕵🏽♂🕵🏾♂️🕵🏾♂🕵🏿♂️🕵🏿♂🕵️♀️🕵♀️🕵️♀🕵♀🕵🏻♀️🕵🏻♀🕵🏼♀️🕵🏼♀🕵🏽♀️🕵🏽♀🕵🏾♀️🕵🏾♀🕵🏿♀️🕵🏿♀💂💂🏻💂🏼💂🏽💂🏾💂🏿💂♂️💂♂💂🏻♂️💂🏻♂💂🏼♂️💂🏼♂💂🏽♂️💂🏽♂💂🏾♂️💂🏾♂💂🏿♂️💂🏿♂💂♀️💂♀💂🏻♀️💂🏻♀💂🏼♀️💂🏼♀💂🏽♀️💂🏽♀💂🏾♀️💂🏾♀💂🏿♀️💂🏿♀👷👷🏻👷🏼👷🏽👷🏾👷🏿👷♂️👷♂👷🏻♂️👷🏻♂👷🏼♂️👷🏼♂👷🏽♂️👷🏽♂👷🏾♂️👷🏾♂👷🏿♂️👷🏿♂👷♀️👷♀👷🏻♀️👷🏻♀👷🏼♀️👷🏼♀👷🏽♀️👷🏽♀👷🏾♀️👷🏾♀👷🏿♀️👷🏿♀🤴🤴🏻🤴🏼🤴🏽🤴🏾🤴🏿👸👸🏻👸🏼👸🏽👸🏾👸🏿👳👳🏻👳🏼👳🏽👳🏾👳🏿👳♂️👳♂👳🏻♂️👳🏻♂👳🏼♂️👳🏼♂👳🏽♂️👳🏽♂👳🏾♂️👳🏾♂👳🏿♂️👳🏿♂👳♀️👳♀👳🏻♀️👳🏻♀👳🏼♀️👳🏼♀👳🏽♀️👳🏽♀👳🏾♀️👳🏾♀👳🏿♀️👳🏿♀👲👲🏻👲🏼👲🏽👲🏾👲🏿🧕🧕🏻🧕🏼🧕🏽🧕🏾🧕🏿🧔🧔🏻🧔🏼🧔🏽🧔🏾🧔🏿👱👱🏻👱🏼👱🏽👱🏾👱🏿👱♂️👱♂👱🏻♂️👱🏻♂👱🏼♂️👱🏼♂👱🏽♂️👱🏽♂👱🏾♂️👱🏾♂👱🏿♂️👱🏿♂👱♀️👱♀👱🏻♀️👱🏻♀👱🏼♀️👱🏼♀👱🏽♀️👱🏽♀👱🏾♀️👱🏾♀👱🏿♀️👱🏿♀👨🦰👨🏻🦰👨🏼🦰👨🏽🦰👨🏾🦰👨🏿🦰👩🦰👩🏻🦰👩🏼🦰👩🏽🦰👩🏾🦰👩🏿🦰👨🦱👨🏻🦱👨🏼🦱👨🏽🦱👨🏾🦱👨🏿🦱👩🦱👩🏻🦱👩🏼🦱👩🏽🦱👩🏾🦱👩🏿🦱👨🦲👨🏻🦲👨🏼🦲👨🏽🦲👨🏾🦲👨🏿🦲👩🦲👩🏻🦲👩🏼🦲👩🏽🦲👩🏾🦲👩🏿🦲👨🦳👨🏻🦳👨🏼🦳👨🏽🦳👨🏾🦳👨🏿🦳👩🦳👩🏻🦳👩🏼🦳👩🏽🦳👩🏾🦳👩🏿🦳🤵🤵🏻🤵🏼🤵🏽🤵🏾🤵🏿👰👰🏻👰🏼👰🏽👰🏾👰🏿🤰🤰🏻🤰🏼🤰🏽🤰🏾🤰🏿🤱🤱🏻🤱🏼🤱🏽🤱🏾🤱🏿👼👼🏻👼🏼👼🏽👼🏾👼🏿🎅🎅🏻🎅🏼🎅🏽🎅🏾🎅🏿🤶🤶🏻🤶🏼🤶🏽🤶🏾🤶🏿🦸🦸🏻🦸🏼🦸🏽🦸🏾🦸🏿🦸♀️🦸♀🦸🏻♀️🦸🏻♀🦸🏼♀️🦸🏼♀🦸🏽♀️🦸🏽♀🦸🏾♀️🦸🏾♀🦸🏿♀️🦸🏿♀🦸♂️🦸♂🦸🏻♂️🦸🏻♂🦸🏼♂️🦸🏼♂🦸🏽♂️🦸🏽♂🦸🏾♂️🦸🏾♂🦸🏿♂️🦸🏿♂🦹🦹🏻🦹🏼🦹🏽🦹🏾🦹🏿🦹♀️🦹♀🦹🏻♀️🦹🏻♀🦹🏼♀️🦹🏼♀🦹🏽♀️🦹🏽♀🦹🏾♀️🦹🏾♀🦹🏿♀️🦹🏿♀🦹♂️🦹♂🦹🏻♂️🦹🏻♂🦹🏼♂️🦹🏼♂🦹🏽♂️🦹🏽♂🦹🏾♂️🦹🏾♂🦹🏿♂️🦹🏿♂🧙🧙🏻🧙🏼🧙🏽🧙🏾🧙🏿🧙♀️🧙♀🧙🏻♀️🧙🏻♀🧙🏼♀️🧙🏼♀🧙🏽♀️🧙🏽♀🧙🏾♀️🧙🏾♀🧙🏿♀️🧙🏿♀🧙♂️🧙♂🧙🏻♂️🧙🏻♂🧙🏼♂️🧙🏼♂🧙🏽♂️🧙🏽♂🧙🏾♂️🧙🏾♂🧙🏿♂️🧙🏿♂🧚🧚🏻🧚🏼🧚🏽🧚🏾🧚🏿🧚♀️🧚♀🧚🏻♀️🧚🏻♀🧚🏼♀️🧚🏼♀🧚🏽♀️🧚🏽♀🧚🏾♀️🧚🏾♀🧚🏿♀️🧚🏿♀🧚♂️🧚♂🧚🏻♂️🧚🏻♂🧚🏼♂️🧚🏼♂🧚🏽♂️🧚🏽♂🧚🏾♂️🧚🏾♂🧚🏿♂️🧚🏿♂🧛🧛🏻🧛🏼🧛🏽🧛🏾🧛🏿🧛♀️🧛♀🧛🏻♀️🧛🏻♀🧛🏼♀️🧛🏼♀🧛🏽♀️🧛🏽♀🧛🏾♀️🧛🏾♀🧛🏿♀️🧛🏿♀🧛♂️🧛♂🧛🏻♂️🧛🏻♂🧛🏼♂️🧛🏼♂🧛🏽♂️🧛🏽♂🧛🏾♂️🧛🏾♂🧛🏿♂️🧛🏿♂🧜🧜🏻🧜🏼🧜🏽🧜🏾🧜🏿🧜♀️🧜♀🧜🏻♀️🧜🏻♀🧜🏼♀️🧜🏼♀🧜🏽♀️🧜🏽♀🧜🏾♀️🧜🏾♀🧜🏿♀️🧜🏿♀🧜♂️🧜♂🧜🏻♂️🧜🏻♂🧜🏼♂️🧜🏼♂🧜🏽♂️🧜🏽♂🧜🏾♂️🧜🏾♂🧜🏿♂️🧜🏿♂🧝🧝🏻🧝🏼🧝🏽🧝🏾🧝🏿🧝♀️🧝♀🧝🏻♀️🧝🏻♀🧝🏼♀️🧝🏼♀🧝🏽♀️🧝🏽♀🧝🏾♀️🧝🏾♀🧝🏿♀️🧝🏿♀🧝♂️🧝♂🧝🏻♂️🧝🏻♂🧝🏼♂️🧝🏼♂🧝🏽♂️🧝🏽♂🧝🏾♂️🧝🏾♂🧝🏿♂️🧝🏿♂🧞🧞♀️🧞♀🧞♂️🧞♂🧟🧟♀️🧟♀🧟♂️🧟♂🙍🙍🏻🙍🏼🙍🏽🙍🏾🙍🏿🙍♂️🙍♂🙍🏻♂️🙍🏻♂🙍🏼♂️🙍🏼♂🙍🏽♂️🙍🏽♂🙍🏾♂️🙍🏾♂🙍🏿♂️🙍🏿♂🙍♀️🙍♀🙍🏻♀️🙍🏻♀🙍🏼♀️🙍🏼♀🙍🏽♀️🙍🏽♀🙍🏾♀️🙍🏾♀🙍🏿♀️🙍🏿♀🙎🙎🏻🙎🏼🙎🏽🙎🏾🙎🏿🙎♂️🙎♂🙎🏻♂️🙎🏻♂🙎🏼♂️🙎🏼♂🙎🏽♂️🙎🏽♂🙎🏾♂️🙎🏾♂🙎🏿♂️🙎🏿♂🙎♀️🙎♀🙎🏻♀️🙎🏻♀🙎🏼♀️🙎🏼♀🙎🏽♀️🙎🏽♀🙎🏾♀️🙎🏾♀🙎🏿♀️🙎🏿♀🙅🙅🏻🙅🏼🙅🏽🙅🏾🙅🏿🙅♂️🙅♂🙅🏻♂️🙅🏻♂🙅🏼♂️🙅🏼♂🙅🏽♂️🙅🏽♂🙅🏾♂️🙅🏾♂🙅🏿♂️🙅🏿♂🙅♀️🙅♀🙅🏻♀️🙅🏻♀🙅🏼♀️🙅🏼♀🙅🏽♀️🙅🏽♀🙅🏾♀️🙅🏾♀🙅🏿♀️🙅🏿♀🙆🙆🏻🙆🏼🙆🏽🙆🏾🙆🏿🙆♂️🙆♂🙆🏻♂️🙆🏻♂🙆🏼♂️🙆🏼♂🙆🏽♂️🙆🏽♂🙆🏾♂️🙆🏾♂🙆🏿♂️🙆🏿♂🙆♀️🙆♀🙆🏻♀️🙆🏻♀🙆🏼♀️🙆🏼♀🙆🏽♀️🙆🏽♀🙆🏾♀️🙆🏾♀🙆🏿♀️🙆🏿♀💁💁🏻💁🏼💁🏽💁🏾💁🏿💁♂️💁♂💁🏻♂️💁🏻♂💁🏼♂️💁🏼♂💁🏽♂️💁🏽♂💁🏾♂️💁🏾♂💁🏿♂️💁🏿♂💁♀️💁♀💁🏻♀️💁🏻♀💁🏼♀️💁🏼♀💁🏽♀️💁🏽♀💁🏾♀️💁🏾♀💁🏿♀️💁🏿♀🙋🙋🏻🙋🏼🙋🏽🙋🏾🙋🏿🙋♂️🙋♂🙋🏻♂️🙋🏻♂🙋🏼♂️🙋🏼♂🙋🏽♂️🙋🏽♂🙋🏾♂️🙋🏾♂🙋🏿♂️🙋🏿♂🙋♀️🙋♀🙋🏻♀️🙋🏻♀🙋🏼♀️🙋🏼♀🙋🏽♀️🙋🏽♀🙋🏾♀️🙋🏾♀🙋🏿♀️🙋🏿♀🙇🙇🏻🙇🏼🙇🏽🙇🏾🙇🏿🙇♂️🙇♂🙇🏻♂️🙇🏻♂🙇🏼♂️🙇🏼♂🙇🏽♂️🙇🏽♂🙇🏾♂️🙇🏾♂🙇🏿♂️🙇🏿♂🙇♀️🙇♀🙇🏻♀️🙇🏻♀🙇🏼♀️🙇🏼♀🙇🏽♀️🙇🏽♀🙇🏾♀️🙇🏾♀🙇🏿♀️🙇🏿♀🤦🤦🏻🤦🏼🤦🏽🤦🏾🤦🏿🤦♂️🤦♂🤦🏻♂️🤦🏻♂🤦🏼♂️🤦🏼♂🤦🏽♂️🤦🏽♂🤦🏾♂️🤦🏾♂🤦🏿♂️🤦🏿♂🤦♀️🤦♀🤦🏻♀️🤦🏻♀🤦🏼♀️🤦🏼♀🤦🏽♀️🤦🏽♀🤦🏾♀️🤦🏾♀🤦🏿♀️🤦🏿♀🤷🤷🏻🤷🏼🤷🏽🤷🏾🤷🏿🤷♂️🤷♂🤷🏻♂️🤷🏻♂🤷🏼♂️🤷🏼♂🤷🏽♂️🤷🏽♂🤷🏾♂️🤷🏾♂🤷🏿♂️🤷🏿♂🤷♀️🤷♀🤷🏻♀️🤷🏻♀🤷🏼♀️🤷🏼♀🤷🏽♀️🤷🏽♀🤷🏾♀️🤷🏾♀🤷🏿♀️🤷🏿♀💆💆🏻💆🏼💆🏽💆🏾💆🏿💆♂️💆♂💆🏻♂️💆🏻♂💆🏼♂️💆🏼♂💆🏽♂️💆🏽♂💆🏾♂️💆🏾♂💆🏿♂️💆🏿♂💆♀️💆♀💆🏻♀️💆🏻♀💆🏼♀️💆🏼♀💆🏽♀️💆🏽♀💆🏾♀️💆🏾♀💆🏿♀️💆🏿♀💇💇🏻💇🏼💇🏽💇🏾💇🏿💇♂️💇♂💇🏻♂️💇🏻♂💇🏼♂️💇🏼♂💇🏽♂️💇🏽♂💇🏾♂️💇🏾♂💇🏿♂️💇🏿♂💇♀️💇♀💇🏻♀️💇🏻♀💇🏼♀️💇🏼♀💇🏽♀️💇🏽♀💇🏾♀️💇🏾♀💇🏿♀️💇🏿♀🚶🚶🏻🚶🏼🚶🏽🚶🏾🚶🏿🚶♂️🚶♂🚶🏻♂️🚶🏻♂🚶🏼♂️🚶🏼♂🚶🏽♂️🚶🏽♂🚶🏾♂️🚶🏾♂🚶🏿♂️🚶🏿♂🚶♀️🚶♀🚶🏻♀️🚶🏻♀🚶🏼♀️🚶🏼♀🚶🏽♀️🚶🏽♀🚶🏾♀️🚶🏾♀🚶🏿♀️🚶🏿♀🏃🏃🏻🏃🏼🏃🏽🏃🏾🏃🏿🏃♂️🏃♂🏃🏻♂️🏃🏻♂🏃🏼♂️🏃🏼♂🏃🏽♂️🏃🏽♂🏃🏾♂️🏃🏾♂🏃🏿♂️🏃🏿♂🏃♀️🏃♀🏃🏻♀️🏃🏻♀🏃🏼♀️🏃🏼♀🏃🏽♀️🏃🏽♀🏃🏾♀️🏃🏾♀🏃🏿♀️🏃🏿♀💃💃🏻💃🏼💃🏽💃🏾💃🏿🕺🕺🏻🕺🏼🕺🏽🕺🏾🕺🏿👯👯♂️👯♂👯♀️👯♀🧖🧖🏻🧖🏼🧖🏽🧖🏾🧖🏿🧖♀️🧖♀🧖🏻♀️🧖🏻♀🧖🏼♀️🧖🏼♀🧖🏽♀️🧖🏽♀🧖🏾♀️🧖🏾♀🧖🏿♀️🧖🏿♀🧖♂️🧖♂🧖🏻♂️🧖🏻♂🧖🏼♂️🧖🏼♂🧖🏽♂️🧖🏽♂🧖🏾♂️🧖🏾♂🧖🏿♂️🧖🏿♂🧗🧗🏻🧗🏼🧗🏽🧗🏾🧗🏿🧗♀️🧗♀🧗🏻♀️🧗🏻♀🧗🏼♀️🧗🏼♀🧗🏽♀️🧗🏽♀🧗🏾♀️🧗🏾♀🧗🏿♀️🧗🏿♀🧗♂️🧗♂🧗🏻♂️🧗🏻♂🧗🏼♂️🧗🏼♂🧗🏽♂️🧗🏽♂🧗🏾♂️🧗🏾♂🧗🏿♂️🧗🏿♂🧘🧘🏻🧘🏼🧘🏽🧘🏾🧘🏿🧘♀️🧘♀🧘🏻♀️🧘🏻♀🧘🏼♀️🧘🏼♀🧘🏽♀️🧘🏽♀🧘🏾♀️🧘🏾♀🧘🏿♀️🧘🏿♀🧘♂️🧘♂🧘🏻♂️🧘🏻♂🧘🏼♂️🧘🏼♂🧘🏽♂️🧘🏽♂🧘🏾♂️🧘🏾♂🧘🏿♂️🧘🏿♂🛀🛀🏻🛀🏼🛀🏽🛀🏾🛀🏿🛌🛌🏻🛌🏼🛌🏽🛌🏾🛌🏿🕴️🕴🕴🏻🕴🏼🕴🏽🕴🏾🕴🏿🗣️🗣👤👥🤺🏇🏇🏻🏇🏼🏇🏽🏇🏾🏇🏿⛷️⛷🏂🏂🏻🏂🏼🏂🏽🏂🏾🏂🏿🏌️🏌🏌🏻🏌🏼🏌🏽🏌🏾🏌🏿🏌️♂️🏌♂️🏌️♂🏌♂🏌🏻♂️🏌🏻♂🏌🏼♂️🏌🏼♂🏌🏽♂️🏌🏽♂🏌🏾♂️🏌🏾♂🏌🏿♂️🏌🏿♂🏌️♀️🏌♀️🏌️♀🏌♀🏌🏻♀️🏌🏻♀🏌🏼♀️🏌🏼♀🏌🏽♀️🏌🏽♀🏌🏾♀️🏌🏾♀🏌🏿♀️🏌🏿♀🏄🏄🏻🏄🏼🏄🏽🏄🏾🏄🏿🏄♂️🏄♂🏄🏻♂️🏄🏻♂🏄🏼♂️🏄🏼♂🏄🏽♂️🏄🏽♂🏄🏾♂️🏄🏾♂🏄🏿♂️🏄🏿♂🏄♀️🏄♀🏄🏻♀️🏄🏻♀🏄🏼♀️🏄🏼♀🏄🏽♀️🏄🏽♀🏄🏾♀️🏄🏾♀🏄🏿♀️🏄🏿♀🚣🚣🏻🚣🏼🚣🏽🚣🏾🚣🏿🚣♂️🚣♂🚣🏻♂️🚣🏻♂🚣🏼♂️🚣🏼♂🚣🏽♂️🚣🏽♂🚣🏾♂️🚣🏾♂🚣🏿♂️🚣🏿♂🚣♀️🚣♀🚣🏻♀️🚣🏻♀🚣🏼♀️🚣🏼♀🚣🏽♀️🚣🏽♀🚣🏾♀️🚣🏾♀🚣🏿♀️🚣🏿♀🏊🏊🏻🏊🏼🏊🏽🏊🏾🏊🏿🏊♂️🏊♂🏊🏻♂️🏊🏻♂🏊🏼♂️🏊🏼♂🏊🏽♂️🏊🏽♂🏊🏾♂️🏊🏾♂🏊🏿♂️🏊🏿♂🏊♀️🏊♀🏊🏻♀️🏊🏻♀🏊🏼♀️🏊🏼♀🏊🏽♀️🏊🏽♀🏊🏾♀️🏊🏾♀🏊🏿♀️🏊🏿♀⛹️⛹⛹🏻⛹🏼⛹🏽⛹🏾⛹🏿⛹️♂️⛹♂️⛹️♂⛹♂⛹🏻♂️⛹🏻♂⛹🏼♂️⛹🏼♂⛹🏽♂️⛹🏽♂⛹🏾♂️⛹🏾♂⛹🏿♂️⛹🏿♂⛹️♀️⛹♀️⛹️♀⛹♀⛹🏻♀️⛹🏻♀⛹🏼♀️⛹🏼♀⛹🏽♀️⛹🏽♀⛹🏾♀️⛹🏾♀⛹🏿♀️⛹🏿♀🏋️🏋🏋🏻🏋🏼🏋🏽🏋🏾🏋🏿🏋️♂️🏋♂️🏋️♂🏋♂🏋🏻♂️🏋🏻♂🏋🏼♂️🏋🏼♂🏋🏽♂️🏋🏽♂🏋🏾♂️🏋🏾♂🏋🏿♂️🏋🏿♂🏋️♀️🏋♀️🏋️♀🏋♀🏋🏻♀️🏋🏻♀🏋🏼♀️🏋🏼♀🏋🏽♀️🏋🏽♀🏋🏾♀️🏋🏾♀🏋🏿♀️🏋🏿♀🚴🚴🏻🚴🏼🚴🏽🚴🏾🚴🏿🚴♂️🚴♂🚴🏻♂️🚴🏻♂🚴🏼♂️🚴🏼♂🚴🏽♂️🚴🏽♂🚴🏾♂️🚴🏾♂🚴🏿♂️🚴🏿♂🚴♀️🚴♀🚴🏻♀️🚴🏻♀🚴🏼♀️🚴🏼♀🚴🏽♀️🚴🏽♀🚴🏾♀️🚴🏾♀🚴🏿♀️🚴🏿♀🚵🚵🏻🚵🏼🚵🏽🚵🏾🚵🏿🚵♂️🚵♂🚵🏻♂️🚵🏻♂🚵🏼♂️🚵🏼♂🚵🏽♂️🚵🏽♂🚵🏾♂️🚵🏾♂🚵🏿♂️🚵🏿♂🚵♀️🚵♀🚵🏻♀️🚵🏻♀🚵🏼♀️🚵🏼♀🚵🏽♀️🚵🏽♀🚵🏾♀️🚵🏾♀🚵🏿♀️🚵🏿♀🏎️🏎🏍️🏍🤸🤸🏻🤸🏼🤸🏽🤸🏾🤸🏿🤸♂️🤸♂🤸🏻♂️🤸🏻♂🤸🏼♂️🤸🏼♂🤸🏽♂️🤸🏽♂🤸🏾♂️🤸🏾♂🤸🏿♂️🤸🏿♂🤸♀️🤸♀🤸🏻♀️🤸🏻♀🤸🏼♀️🤸🏼♀🤸🏽♀️🤸🏽♀🤸🏾♀️🤸🏾♀🤸🏿♀️🤸🏿♀🤼🤼♂️🤼♂🤼♀️🤼♀🤽🤽🏻🤽🏼🤽🏽🤽🏾🤽🏿🤽♂️🤽♂🤽🏻♂️🤽🏻♂🤽🏼♂️🤽🏼♂🤽🏽♂️🤽🏽♂🤽🏾♂️🤽🏾♂🤽🏿♂️🤽🏿♂🤽♀️🤽♀🤽🏻♀️🤽🏻♀🤽🏼♀️🤽🏼♀🤽🏽♀️🤽🏽♀🤽🏾♀️🤽🏾♀🤽🏿♀️🤽🏿♀🤾🤾🏻🤾🏼🤾🏽🤾🏾🤾🏿🤾♂️🤾♂🤾🏻♂️🤾🏻♂🤾🏼♂️🤾🏼♂🤾🏽♂️🤾🏽♂🤾🏾♂️🤾🏾♂🤾🏿♂️🤾🏿♂🤾♀️🤾♀🤾🏻♀️🤾🏻♀🤾🏼♀️🤾🏼♀🤾🏽♀️🤾🏽♀🤾🏾♀️🤾🏾♀🤾🏿♀️🤾🏿♀🤹🤹🏻🤹🏼🤹🏽🤹🏾🤹🏿🤹♂️🤹♂🤹🏻♂️🤹🏻♂🤹🏼♂️🤹🏼♂🤹🏽♂️🤹🏽♂🤹🏾♂️🤹🏾♂🤹🏿♂️🤹🏿♂🤹♀️🤹♀🤹🏻♀️🤹🏻♀🤹🏼♀️🤹🏼♀🤹🏽♀️🤹🏽♀🤹🏾♀️🤹🏾♀🤹🏿♀️🤹🏿♀👫👬👭💏👩❤️💋👨👩❤💋👨👨❤️💋👨👨❤💋👨👩❤️💋👩👩❤💋👩💑👩❤️👨👩❤👨👨❤️👨👨❤👨👩❤️👩👩❤👩👪👨👩👦👨👩👧👨👩👧👦👨👩👦👦👨👩👧👧👨👨👦👨👨👧👨👨👧👦👨👨👦👦👨👨👧👧👩👩👦👩👩👧👩👩👧👦👩👩👦👦👩👩👧👧👨👦👨👦👦👨👧👨👧👦👨👧👧👩👦👩👦👦👩👧👩👧👦👩👧👧🤳🤳🏻🤳🏼🤳🏽🤳🏾🤳🏿💪💪🏻💪🏼💪🏽💪🏾💪🏿🦵🦵🏻🦵🏼🦵🏽🦵🏾🦵🏿🦶🦶🏻🦶🏼🦶🏽🦶🏾🦶🏿👈👈🏻👈🏼👈🏽👈🏾👈🏿👉👉🏻👉🏼👉🏽👉🏾👉🏿☝️☝☝🏻☝🏼☝🏽☝🏾☝🏿👆👆🏻👆🏼👆🏽👆🏾👆🏿🖕🖕🏻🖕🏼🖕🏽🖕🏾🖕🏿👇👇🏻👇🏼👇🏽👇🏾👇🏿✌️✌✌🏻✌🏼✌🏽✌🏾✌🏿🤞🤞🏻🤞🏼🤞🏽🤞🏾🤞🏿🖖🖖🏻🖖🏼🖖🏽🖖🏾🖖🏿🤘🤘🏻🤘🏼🤘🏽🤘🏾🤘🏿🤙🤙🏻🤙🏼🤙🏽🤙🏾🤙🏿🖐️🖐🖐🏻🖐🏼🖐🏽🖐🏾🖐🏿✋✋🏻✋🏼✋🏽✋🏾✋🏿👌👌🏻👌🏼👌🏽👌🏾👌🏿👍👍🏻👍🏼👍🏽👍🏾👍🏿👎👎🏻👎🏼👎🏽👎🏾👎🏿✊✊🏻✊🏼✊🏽✊🏾✊🏿👊👊🏻👊🏼👊🏽👊🏾👊🏿🤛🤛🏻🤛🏼🤛🏽🤛🏾🤛🏿🤜🤜🏻🤜🏼🤜🏽🤜🏾🤜🏿🤚🤚🏻🤚🏼🤚🏽🤚🏾🤚🏿👋👋🏻👋🏼👋🏽👋🏾👋🏿🤟🤟🏻🤟🏼🤟🏽🤟🏾🤟🏿✍️✍✍🏻✍🏼✍🏽✍🏾✍🏿👏👏🏻👏🏼👏🏽👏🏾👏🏿👐👐🏻👐🏼👐🏽👐🏾👐🏿🙌🙌🏻🙌🏼🙌🏽🙌🏾🙌🏿🤲🤲🏻🤲🏼🤲🏽🤲🏾🤲🏿🙏🙏🏻🙏🏼🙏🏽🙏🏾🙏🏿🤝💅💅🏻💅🏼💅🏽💅🏾💅🏿👂👂🏻👂🏼👂🏽👂🏾👂🏿👃👃🏻👃🏼👃🏽👃🏾👃🏿🦰🦱🦲🦳👣👀👁️👁👁️🗨️👁🗨️👁️🗨👁🗨🧠🦴🦷👅👄💋💘❤️❤💓💔💕💖💗💙💚💛🧡💜🖤💝💞💟❣️❣💌💤💢💣💥💦💨💫💬🗨️🗨🗯️🗯💭🕳️🕳👓🕶️🕶🥽🥼👔👕👖🧣🧤🧥🧦👗👘👙👚👛👜👝🛍️🛍🎒👞👟🥾🥿👠👡👢👑👒🎩🎓🧢⛑️⛑📿💄💍💎🐵🐒🦍🐶🐕🐩🐺🦊🦝🐱🐈🦁🐯🐅🐆🐴🐎🦄🦓🦌🐮🐂🐃🐄🐷🐖🐗🐽🐏🐑🐐🐪🐫🦙🦒🐘🦏🦛🐭🐁🐀🐹🐰🐇🐿️🐿🦔🦇🐻🐨🐼🦘🦡🐾🦃🐔🐓🐣🐤🐥🐦🐧🕊️🕊🦅🦆🦢🦉🦚🦜🐸🐊🐢🦎🐍🐲🐉🦕🦖🐳🐋🐬🐟🐠🐡🦈🐙🐚🦀🦞🦐🦑🐌🦋🐛🐜🐝🐞🦗🕷️🕷🕸️🕸🦂🦟🦠💐🌸💮🏵️🏵🌹🥀🌺🌻🌼🌷🌱🌲🌳🌴🌵🌾🌿☘️☘🍀🍁🍂🍃🍇🍈🍉🍊🍋🍌🍍🥭🍎🍏🍐🍑🍒🍓🥝🍅🥥🥑🍆🥔🥕🌽🌶️🌶🥒🥬🥦🍄🥜🌰🍞🥐🥖🥨🥯🥞🧀🍖🍗🥩🥓🍔🍟🍕🌭🥪🌮🌯🥙🥚🍳🥘🍲🥣🥗🍿🧂🥫🍱🍘🍙🍚🍛🍜🍝🍠🍢🍣🍤🍥🥮🍡🥟🥠🥡🍦🍧🍨🍩🍪🎂🍰🧁🥧🍫🍬🍭🍮🍯🍼🥛☕🍵🍶🍾🍷🍸🍹🍺🍻🥂🥃🥤🥢🍽️🍽🍴🥄🔪🏺🌍🌎🌏🌐🗺️🗺🗾🧭🏔️🏔⛰️⛰🌋🗻🏕️🏕🏖️🏖🏜️🏜🏝️🏝🏞️🏞🏟️🏟🏛️🏛🏗️🏗🧱🏘️🏘🏚️🏚🏠🏡🏢🏣🏤🏥🏦🏨🏩🏪🏫🏬🏭🏯🏰💒🗼🗽⛪🕌🕍⛩️⛩🕋⛲⛺🌁🌃🏙️🏙🌄🌅🌆🌇🌉♨️♨🌌🎠🎡🎢💈🎪🚂🚃🚄🚅🚆🚇🚈🚉🚊🚝🚞🚋🚌🚍🚎🚐🚑🚒🚓🚔🚕🚖🚗🚘🚙🚚🚛🚜🚲🛴🛹🛵🚏🛣️🛣🛤️🛤🛢️🛢⛽🚨🚥🚦🛑🚧⚓⛵🛶🚤🛳️🛳⛴️⛴🛥️🛥🚢✈️✈🛩️🛩🛫🛬💺🚁🚟🚠🚡🛰️🛰🚀🛸🛎️🛎🧳⌛⏳⌚⏰⏱️⏱⏲️⏲🕰️🕰🕛🕧🕐🕜🕑🕝🕒🕞🕓🕟🕔🕠🕕🕡🕖🕢🕗🕣🕘🕤🕙🕥🕚🕦🌑🌒🌓🌔🌕🌖🌗🌘🌙🌚🌛🌜🌡️🌡☀️☀🌝🌞⭐🌟🌠☁️☁⛅⛈️⛈🌤️🌤🌥️🌥🌦️🌦🌧️🌧🌨️🌨🌩️🌩🌪️🌪🌫️🌫🌬️🌬🌀🌈🌂☂️☂☔⛱️⛱⚡❄️❄☃️☃⛄☄️☄🔥💧🌊🎃🎄🎆🎇🧨✨🎈🎉🎊🎋🎍🎎🎏🎐🎑🧧🎀🎁🎗️🎗🎟️🎟🎫🎖️🎖🏆🏅🥇🥈🥉⚽⚾🥎🏀🏐🏈🏉🎾🥏🎳🏏🏑🏒🥍🏓🏸🥊🥋🥅⛳⛸️⛸🎣🎽🎿🛷🥌🎯🎱🔮🧿🎮🕹️🕹🎰🎲🧩🧸♠️♠♥️♥♦️♦♣️♣♟️♟🃏🀄🎴🎭🖼️🖼🎨🧵🧶🔇🔈🔉🔊📢📣📯🔔🔕🎼🎵🎶🎙️🎙🎚️🎚🎛️🎛🎤🎧📻🎷🎸🎹🎺🎻🥁📱📲☎️☎📞📟📠🔋🔌💻🖥️🖥🖨️🖨⌨️⌨🖱️🖱🖲️🖲💽💾💿📀🧮🎥🎞️🎞📽️📽🎬📺📷📸📹📼🔍🔎🕯️🕯💡🔦🏮📔📕📖📗📘📙📚📓📒📃📜📄📰🗞️🗞📑🔖🏷️🏷💰💴💵💶💷💸💳🧾💹💱💲✉️✉📧📨📩📤📥📦📫📪📬📭📮🗳️🗳✏️✏✒️✒🖋️🖋🖊️🖊🖌️🖌🖍️🖍📝💼📁📂🗂️🗂📅📆🗒️🗒🗓️🗓📇📈📉📊📋📌📍📎🖇️🖇📏📐✂️✂🗃️🗃🗄️🗄🗑️🗑🔒🔓🔏🔐🔑🗝️🗝🔨⛏️⛏⚒️⚒🛠️🛠🗡️🗡⚔️⚔🔫🏹🛡️🛡🔧🔩⚙️⚙🗜️🗜⚖️⚖🔗⛓️⛓🧰🧲⚗️⚗🧪🧫🧬🔬🔭📡💉💊🚪🛏️🛏🛋️🛋🚽🚿🛁🧴🧷🧹🧺🧻🧼🧽🧯🛒🚬⚰️⚰⚱️⚱🗿🏧🚮🚰♿🚹🚺🚻🚼🚾🛂🛃🛄🛅⚠️⚠🚸⛔🚫🚳🚭🚯🚱🚷📵🔞☢️☢☣️☣⬆️⬆↗️↗➡️➡↘️↘⬇️⬇↙️↙⬅️⬅↖️↖↕️↕↔️↔↩️↩↪️↪⤴️⤴⤵️⤵🔃🔄🔙🔚🔛🔜🔝🛐⚛️⚛🕉️🕉✡️✡☸️☸☯️☯✝️✝☦️☦☪️☪☮️☮🕎🔯♈♉♊♋♌♍♎♏♐♑♒♓⛎🔀🔁🔂▶️▶⏩⏭️⏭⏯️⏯◀️◀⏪⏮️⏮🔼⏫🔽⏬⏸️⏸⏹️⏹⏺️⏺⏏️⏏🎦🔅🔆📶📳📴♀️♀♂️♂⚕️⚕♾️♾♻️♻⚜️⚜🔱📛🔰⭕✅☑️☑✔️✔✖️✖❌❎➕➖➗➰➿〽️〽✳️✳✴️✴❇️❇‼️‼⁉️⁉❓❔❕❗〰️〰©️©®️®™️™#️⃣#⃣*️⃣*⃣0️⃣0⃣1️⃣1⃣2️⃣2⃣3️⃣3⃣4️⃣4⃣5️⃣5⃣6️⃣6⃣7️⃣7⃣8️⃣8⃣9️⃣9⃣🔟💯🔠🔡🔢🔣🔤🅰️🅰🆎🅱️🅱🆑🆒🆓ℹ️ℹ🆔Ⓜ️Ⓜ🆕🆖🅾️🅾🆗🅿️🅿🆘🆙🆚🈁🈂️🈂🈷️🈷🈶🈯🉐🈹🈚🈲🉑🈸🈴🈳㊗️㊗㊙️㊙🈺🈵▪️▪▫️▫◻️◻◼️◼◽◾⬛⬜🔶🔷🔸🔹🔺🔻💠🔘🔲🔳⚪⚫🔴🔵🏁🚩🎌🏴🏳️🏳🏳️🌈🏳🌈🏴☠️🏴☠🇦🇨🇦🇩🇦🇪🇦🇫🇦🇬🇦🇮🇦🇱🇦🇲🇦🇴🇦🇶🇦🇷🇦🇸🇦🇹🇦🇺🇦🇼🇦🇽🇦🇿🇧🇦🇧🇧🇧🇩🇧🇪🇧🇫🇧🇬🇧🇭🇧🇮🇧🇯🇧🇱🇧🇲🇧🇳🇧🇴🇧🇶🇧🇷🇧🇸🇧🇹🇧🇻🇧🇼🇧🇾🇧🇿🇨🇦🇨🇨🇨🇩🇨🇫🇨🇬🇨🇭🇨🇮🇨🇰🇨🇱🇨🇲🇨🇳🇨🇴🇨🇵🇨🇷🇨🇺🇨🇻🇨🇼🇨🇽🇨🇾🇨🇿🇩🇪🇩🇬🇩🇯🇩🇰🇩🇲🇩🇴🇩🇿🇪🇦🇪🇨🇪🇪🇪🇬🇪🇭🇪🇷🇪🇸🇪🇹🇪🇺🇫🇮🇫🇯🇫🇰🇫🇲🇫🇴🇫🇷🇬🇦🇬🇧🇬🇩🇬🇪🇬🇫🇬🇬🇬🇭🇬🇮🇬🇱🇬🇲🇬🇳🇬🇵🇬🇶🇬🇷🇬🇸🇬🇹🇬🇺🇬🇼🇬🇾🇭🇰🇭🇲🇭🇳🇭🇷🇭🇹🇭🇺🇮🇨🇮🇩🇮🇪🇮🇱🇮🇲🇮🇳🇮🇴🇮🇶🇮🇷🇮🇸🇮🇹🇯🇪🇯🇲🇯🇴🇯🇵🇰🇪🇰🇬🇰🇭🇰🇮🇰🇲🇰🇳🇰🇵🇰🇷🇰🇼🇰🇾🇰🇿🇱🇦🇱🇧🇱🇨🇱🇮🇱🇰🇱🇷🇱🇸🇱🇹🇱🇺🇱🇻🇱🇾🇲🇦🇲🇨🇲🇩🇲🇪🇲🇫🇲🇬🇲🇭🇲🇰🇲🇱🇲🇲🇲🇳🇲🇴🇲🇵🇲🇶🇲🇷🇲🇸🇲🇹🇲🇺🇲🇻🇲🇼🇲🇽🇲🇾🇲🇿🇳🇦🇳🇨🇳🇪🇳🇫🇳🇬🇳🇮🇳🇱🇳🇴🇳🇵🇳🇷🇳🇺🇳🇿🇴🇲🇵🇦🇵🇪🇵🇫🇵🇬🇵🇭🇵🇰🇵🇱🇵🇲🇵🇳🇵🇷🇵🇸🇵🇹🇵🇼🇵🇾🇶🇦🇷🇪🇷🇴🇷🇸🇷🇺🇷🇼🇸🇦🇸🇧🇸🇨🇸🇩🇸🇪🇸🇬🇸🇭🇸🇮🇸🇯🇸🇰🇸🇱🇸🇲🇸🇳🇸🇴🇸🇷🇸🇸🇸🇹🇸🇻🇸🇽🇸🇾🇸🇿🇹🇦🇹🇨🇹🇩🇹🇫🇹🇬🇹🇭🇹🇯🇹🇰🇹🇱🇹🇲🇹🇳🇹🇴🇹🇷🇹🇹🇹🇻🇹🇼🇹🇿🇺🇦🇺🇬🇺🇲🇺🇳🇺🇸🇺🇾🇺🇿🇻🇦🇻🇨🇻🇪🇻🇬🇻🇮🇻🇳🇻🇺🇼🇫🇼🇸🇽🇰🇾🇪🇾🇹🇿🇦🇿🇲🇿🇼🏴🏴🏴"333 );334 expect(() => emoji.parse(":-)")).toThrow();335 expect(() => emoji.parse("😀 is an emoji")).toThrow();336 expect(() => emoji.parse("😀stuff")).toThrow();337 expect(() => emoji.parse("stuff😀")).toThrow();338});339 340test("uuid", () => {341 const uuid = z.string().uuid("custom error");342 uuid.parse("9491d710-3185-4e06-bea0-6a2f275345e0");343 uuid.parse("d89e7b01-7598-ed11-9d7a-0022489382fd"); // new sequential id344 uuid.parse("00000000-0000-0000-0000-000000000000");345 uuid.parse("b3ce60f8-e8b9-40f5-1150-172ede56ff74"); // Variant 0 - RFC 9562/4122: Reserved, NCS backward compatibility346 uuid.parse("92e76bf9-28b3-4730-cd7f-cb6bc51f8c09"); // Variant 2 - RFC 9562/4122: Reserved, Microsoft Corporation backward compatibility347 const result = uuid.safeParse("9491d710-3185-4e06-bea0-6a2f275345e0X");348 expect(result.success).toEqual(false);349 if (!result.success) {350 expect(result.error.issues[0].message).toEqual("custom error");351 }352});353 354test("bad uuid", () => {355 const uuid = z.string().uuid("custom error");356 uuid.parse("9491d710-3185-4e06-bea0-6a2f275345e0");357 const result = uuid.safeParse("invalid uuid");358 expect(result.success).toEqual(false);359 if (!result.success) {360 expect(result.error.issues[0].message).toEqual("custom error");361 }362});363 364test("nanoid", () => {365 const nanoid = z.string().nanoid("custom error");366 nanoid.parse("lfNZluvAxMkf7Q8C5H-QS");367 nanoid.parse("mIU_4PJWikaU8fMbmkouz");368 nanoid.parse("Hb9ZUtUa2JDm_dD-47EGv");369 nanoid.parse("5Noocgv_8vQ9oPijj4ioQ");370 const result = nanoid.safeParse("Xq90uDyhddC53KsoASYJGX");371 expect(result.success).toEqual(false);372 if (!result.success) {373 expect(result.error.issues[0].message).toEqual("custom error");374 }375});376 377test("bad nanoid", () => {378 const nanoid = z.string().nanoid("custom error");379 nanoid.parse("ySh_984wpDUu7IQRrLXAp");380 const result = nanoid.safeParse("invalid nanoid");381 expect(result.success).toEqual(false);382 if (!result.success) {383 expect(result.error.issues[0].message).toEqual("custom error");384 }385});386 387test("cuid", () => {388 const cuid = z.string().cuid();389 cuid.parse("ckopqwooh000001la8mbi2im9");390 const result = cuid.safeParse("cifjhdsfhsd-invalid-cuid");391 expect(result.success).toEqual(false);392 if (!result.success) {393 expect(result.error.issues[0].message).toEqual("Invalid cuid");394 }395});396 397test("cuid2", () => {398 const cuid2 = z.string().cuid2();399 const validStrings = [400 "a", // short string401 "tz4a98xxat96iws9zmbrgj3a", // normal string402 "kf5vz6ssxe4zjcb409rjgo747tc5qjazgptvotk6", // longer than require("@paralleldrive/cuid2").bigLength403 ];404 for (const s of validStrings) {405 cuid2.parse(s);406 }407 408 const invalidStrings = [409 "", // empty string410 "tz4a98xxat96iws9zMbrgj3a", // include uppercase411 "tz4a98xxat96iws-zmbrgj3a", // involve symbols412 ];413 const results = invalidStrings.map((s) => cuid2.safeParse(s));414 expect(results.every((r) => !r.success)).toEqual(true);415 if (!results[0].success) {416 expect(results[0].error.issues[0].message).toEqual("Invalid cuid2");417 }418});419 420test("ulid", () => {421 const ulid = z.string().ulid();422 ulid.parse("01ARZ3NDEKTSV4RRFFQ69G5FAV");423 const result = ulid.safeParse("invalidulid");424 expect(result.success).toEqual(false);425 const tooLong = "01ARZ3NDEKTSV4RRFFQ69G5FAVA";426 expect(ulid.safeParse(tooLong).success).toEqual(false);427 if (!result.success) {428 expect(result.error.issues[0].message).toEqual("Invalid ulid");429 }430 const caseInsensitive = ulid.safeParse("01arZ3nDeKTsV4RRffQ69G5FAV");431 expect(caseInsensitive.success).toEqual(true);432});433 434test("regex", () => {435 z.string()436 .regex(/^moo+$/)437 .parse("mooooo");438 expect(() => z.string().uuid().parse("purr")).toThrow();439});440 441test("regexp error message", () => {442 const result = z443 .string()444 .regex(/^moo+$/)445 .safeParse("boooo");446 if (!result.success) {447 expect(result.error.issues[0].message).toEqual("Invalid");448 } else {449 throw new Error("validation should have failed");450 }451 452 expect(() => z.string().uuid().parse("purr")).toThrow();453});454 455test("regex lastIndex reset", () => {456 const schema = z.string().regex(/^\d+$/g);457 expect(schema.safeParse("123").success).toEqual(true);458 expect(schema.safeParse("123").success).toEqual(true);459 expect(schema.safeParse("123").success).toEqual(true);460 expect(schema.safeParse("123").success).toEqual(true);461 expect(schema.safeParse("123").success).toEqual(true);462});463 464test("checks getters", () => {465 expect(z.string().email().isEmail).toEqual(true);466 expect(z.string().email().isURL).toEqual(false);467 expect(z.string().email().isCUID).toEqual(false);468 expect(z.string().email().isCUID2).toEqual(false);469 expect(z.string().email().isUUID).toEqual(false);470 expect(z.string().email().isNANOID).toEqual(false);471 expect(z.string().email().isIP).toEqual(false);472 expect(z.string().email().isCIDR).toEqual(false);473 expect(z.string().email().isULID).toEqual(false);474 475 expect(z.string().url().isEmail).toEqual(false);476 expect(z.string().url().isURL).toEqual(true);477 expect(z.string().url().isCUID).toEqual(false);478 expect(z.string().url().isCUID2).toEqual(false);479 expect(z.string().url().isUUID).toEqual(false);480 expect(z.string().url().isNANOID).toEqual(false);481 expect(z.string().url().isIP).toEqual(false);482 expect(z.string().url().isCIDR).toEqual(false);483 expect(z.string().url().isULID).toEqual(false);484 485 expect(z.string().cuid().isEmail).toEqual(false);486 expect(z.string().cuid().isURL).toEqual(false);487 expect(z.string().cuid().isCUID).toEqual(true);488 expect(z.string().cuid().isCUID2).toEqual(false);489 expect(z.string().cuid().isUUID).toEqual(false);490 expect(z.string().cuid().isNANOID).toEqual(false);491 expect(z.string().cuid().isIP).toEqual(false);492 expect(z.string().cuid().isCIDR).toEqual(false);493 expect(z.string().cuid().isULID).toEqual(false);494 495 expect(z.string().cuid2().isEmail).toEqual(false);496 expect(z.string().cuid2().isURL).toEqual(false);497 expect(z.string().cuid2().isCUID).toEqual(false);498 expect(z.string().cuid2().isCUID2).toEqual(true);499 expect(z.string().cuid2().isUUID).toEqual(false);500 expect(z.string().cuid2().isNANOID).toEqual(false);501 expect(z.string().cuid2().isIP).toEqual(false);502 expect(z.string().cuid2().isCIDR).toEqual(false);503 expect(z.string().cuid2().isULID).toEqual(false);504 505 expect(z.string().uuid().isEmail).toEqual(false);506 expect(z.string().uuid().isURL).toEqual(false);507 expect(z.string().uuid().isCUID).toEqual(false);508 expect(z.string().uuid().isCUID2).toEqual(false);509 expect(z.string().uuid().isUUID).toEqual(true);510 expect(z.string().uuid().isNANOID).toEqual(false);511 expect(z.string().uuid().isIP).toEqual(false);512 expect(z.string().uuid().isCIDR).toEqual(false);513 expect(z.string().uuid().isULID).toEqual(false);514 515 expect(z.string().nanoid().isEmail).toEqual(false);516 expect(z.string().nanoid().isURL).toEqual(false);517 expect(z.string().nanoid().isCUID).toEqual(false);518 expect(z.string().nanoid().isCUID2).toEqual(false);519 expect(z.string().nanoid().isUUID).toEqual(false);520 expect(z.string().nanoid().isNANOID).toEqual(true);521 expect(z.string().nanoid().isIP).toEqual(false);522 expect(z.string().nanoid().isCIDR).toEqual(false);523 expect(z.string().nanoid().isULID).toEqual(false);524 525 expect(z.string().ip().isEmail).toEqual(false);526 expect(z.string().ip().isURL).toEqual(false);527 expect(z.string().ip().isCUID).toEqual(false);528 expect(z.string().ip().isCUID2).toEqual(false);529 expect(z.string().ip().isUUID).toEqual(false);530 expect(z.string().ip().isNANOID).toEqual(false);531 expect(z.string().ip().isIP).toEqual(true);532 expect(z.string().ip().isCIDR).toEqual(false);533 expect(z.string().ip().isULID).toEqual(false);534 535 expect(z.string().cidr().isEmail).toEqual(false);536 expect(z.string().cidr().isURL).toEqual(false);537 expect(z.string().cidr().isCUID).toEqual(false);538 expect(z.string().cidr().isCUID2).toEqual(false);539 expect(z.string().cidr().isUUID).toEqual(false);540 expect(z.string().cidr().isNANOID).toEqual(false);541 expect(z.string().cidr().isIP).toEqual(false);542 expect(z.string().cidr().isCIDR).toEqual(true);543 expect(z.string().cidr().isULID).toEqual(false);544 545 expect(z.string().ulid().isEmail).toEqual(false);546 expect(z.string().ulid().isURL).toEqual(false);547 expect(z.string().ulid().isCUID).toEqual(false);548 expect(z.string().ulid().isCUID2).toEqual(false);549 expect(z.string().ulid().isUUID).toEqual(false);550 expect(z.string().ulid().isNANOID).toEqual(false);551 expect(z.string().ulid().isIP).toEqual(false);552 expect(z.string().ulid().isCIDR).toEqual(false);553 expect(z.string().ulid().isULID).toEqual(true);554});555 556test("min max getters", () => {557 expect(z.string().min(5).minLength).toEqual(5);558 expect(z.string().min(5).min(10).minLength).toEqual(10);559 expect(z.string().minLength).toEqual(null);560 561 expect(z.string().max(5).maxLength).toEqual(5);562 expect(z.string().max(5).max(1).maxLength).toEqual(1);563 expect(z.string().maxLength).toEqual(null);564});565 566test("trim", () => {567 expect(z.string().trim().min(2).parse(" 12 ")).toEqual("12");568 569 // ordering of methods is respected570 expect(z.string().min(2).trim().parse(" 1 ")).toEqual("1");571 expect(() => z.string().trim().min(2).parse(" 1 ")).toThrow();572});573 574test("lowerCase", () => {575 expect(z.string().toLowerCase().parse("ASDF")).toEqual("asdf");576 expect(z.string().toUpperCase().parse("asdf")).toEqual("ASDF");577});578 579test("datetime", () => {580 const a = z.string().datetime({});581 expect(a.isDatetime).toEqual(true);582 583 const b = z.string().datetime({ offset: true });584 expect(b.isDatetime).toEqual(true);585 586 const c = z.string().datetime({ precision: 3 });587 expect(c.isDatetime).toEqual(true);588 589 const d = z.string().datetime({ offset: true, precision: 0 });590 expect(d.isDatetime).toEqual(true);591 592 const { isDatetime } = z.string().datetime();593 expect(isDatetime).toEqual(true);594});595 596test("datetime parsing", () => {597 const datetime = z.string().datetime();598 datetime.parse("1970-01-01T00:00:00.000Z");599 datetime.parse("2022-10-13T09:52:31.816Z");600 datetime.parse("2022-10-13T09:52:31.8162314Z");601 datetime.parse("1970-01-01T00:00:00Z");602 datetime.parse("2022-10-13T09:52:31Z");603 datetime.parse("2022-10-13T09:52Z");604 expect(() => datetime.parse("")).toThrow();605 expect(() => datetime.parse("foo")).toThrow();606 expect(() => datetime.parse("2020-10-14")).toThrow();607 expect(() => datetime.parse("T18:45:12.123")).toThrow();608 expect(() => datetime.parse("2020-10-14T17:42:29+00:00")).toThrow();609 expect(() => datetime.parse("2020-10-14T17:42.123+00:00")).toThrow();610 611 const datetimeNoMs = z.string().datetime({ precision: 0 });612 datetimeNoMs.parse("1970-01-01T00:00:00Z");613 datetimeNoMs.parse("2022-10-13T09:52:31Z");614 datetimeNoMs.parse("2022-10-13T09:52Z");615 expect(() => datetimeNoMs.parse("tuna")).toThrow();616 expect(() => datetimeNoMs.parse("1970-01-01T00:00:00.000Z")).toThrow();617 expect(() => datetimeNoMs.parse("1970-01-01T00:00:00.Z")).toThrow();618 expect(() => datetimeNoMs.parse("2022-10-13T09:52:31.816Z")).toThrow();619 620 const datetime3Ms = z.string().datetime({ precision: 3 });621 datetime3Ms.parse("1970-01-01T00:00:00.000Z");622 datetime3Ms.parse("2022-10-13T09:52:31.123Z");623 expect(() => datetime3Ms.parse("tuna")).toThrow();624 expect(() => datetime3Ms.parse("1970-01-01T00:00:00.1Z")).toThrow();625 expect(() => datetime3Ms.parse("1970-01-01T00:00:00.12Z")).toThrow();626 expect(() => datetime3Ms.parse("2022-10-13T09:52:31Z")).toThrow();627 expect(() => datetime3Ms.parse("2022-10-13T09:52Z")).toThrow();628 629 const datetimeOffset = z.string().datetime({ offset: true });630 datetimeOffset.parse("1970-01-01T00:00:00.000Z");631 datetimeOffset.parse("2022-10-13T09:52:31.816234134Z");632 datetimeOffset.parse("1970-01-01T00:00:00Z");633 datetimeOffset.parse("2022-10-13T09:52:31.4Z");634 datetimeOffset.parse("2020-10-14T17:42:29+00:00");635 datetimeOffset.parse("2020-10-14T17:42:29+03:15");636 datetimeOffset.parse("2020-10-14T17:42:29+0315");637 datetimeOffset.parse("2020-10-14T17:42+0315");638 expect(() => datetimeOffset.parse("2020-10-14T17:42:29+03"));639 expect(() => datetimeOffset.parse("tuna")).toThrow();640 expect(() => datetimeOffset.parse("2022-10-13T09:52:31.Z")).toThrow();641 642 const datetimeOffsetNoMs = z.string().datetime({ offset: true, precision: 0 });643 datetimeOffsetNoMs.parse("1970-01-01T00:00:00Z");644 datetimeOffsetNoMs.parse("2022-10-13T09:52:31Z");645 datetimeOffsetNoMs.parse("2020-10-14T17:42:29+00:00");646 datetimeOffsetNoMs.parse("2020-10-14T17:42:29+0000");647 datetimeOffsetNoMs.parse("2020-10-14T17:42+0000");648 expect(() => datetimeOffsetNoMs.parse("2020-10-14T17:42:29+00")).toThrow();649 expect(() => datetimeOffsetNoMs.parse("tuna")).toThrow();650 expect(() => datetimeOffsetNoMs.parse("1970-01-01T00:00:00.000Z")).toThrow();651 expect(() => datetimeOffsetNoMs.parse("1970-01-01T00:00:00.Z")).toThrow();652 expect(() => datetimeOffsetNoMs.parse("2022-10-13T09:52:31.816Z")).toThrow();653 expect(() => datetimeOffsetNoMs.parse("2020-10-14T17:42:29.124+00:00")).toThrow();654 655 const datetimeOffset4Ms = z.string().datetime({ offset: true, precision: 4 });656 datetimeOffset4Ms.parse("1970-01-01T00:00:00.1234Z");657 datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+00:00");658 datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+0000");659 expect(() => datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+00")).toThrow();660 expect(() => datetimeOffset4Ms.parse("tuna")).toThrow();661 expect(() => datetimeOffset4Ms.parse("1970-01-01T00:00:00.123Z")).toThrow();662 expect(() => datetimeOffset4Ms.parse("2020-10-14T17:42:29.124+00:00")).toThrow();663 expect(() => datetimeOffset4Ms.parse("2020-10-14T17:42+00:00")).toThrow();664});665 666test("date", () => {667 const a = z.string().date();668 expect(a.isDate).toEqual(true);669});670 671test("date parsing", () => {672 const date = z.string().date();673 date.parse("1970-01-01");674 date.parse("2022-01-31");675 date.parse("2022-03-31");676 date.parse("2022-04-30");677 date.parse("2022-05-31");678 date.parse("2022-06-30");679 date.parse("2022-07-31");680 date.parse("2022-08-31");681 date.parse("2022-09-30");682 date.parse("2022-10-31");683 date.parse("2022-11-30");684 date.parse("2022-12-31");685 686 date.parse("2000-02-29");687 date.parse("2400-02-29");688 expect(() => date.parse("2022-02-29")).toThrow();689 expect(() => date.parse("2100-02-29")).toThrow();690 expect(() => date.parse("2200-02-29")).toThrow();691 expect(() => date.parse("2300-02-29")).toThrow();692 expect(() => date.parse("2500-02-29")).toThrow();693 694 expect(() => date.parse("")).toThrow();695 expect(() => date.parse("foo")).toThrow();696 expect(() => date.parse("200-01-01")).toThrow();697 expect(() => date.parse("20000-01-01")).toThrow();698 expect(() => date.parse("2000-0-01")).toThrow();699 expect(() => date.parse("2000-011-01")).toThrow();700 expect(() => date.parse("2000-01-0")).toThrow();701 expect(() => date.parse("2000-01-011")).toThrow();702 expect(() => date.parse("2000/01/01")).toThrow();703 expect(() => date.parse("01-01-2022")).toThrow();704 expect(() => date.parse("01/01/2022")).toThrow();705 expect(() => date.parse("2000-01-01 00:00:00Z")).toThrow();706 expect(() => date.parse("2020-10-14T17:42:29+00:00")).toThrow();707 expect(() => date.parse("2020-10-14T17:42:29Z")).toThrow();708 expect(() => date.parse("2020-10-14T17:42:29")).toThrow();709 expect(() => date.parse("2020-10-14T17:42:29.123Z")).toThrow();710 711 expect(() => date.parse("2000-00-12")).toThrow();712 expect(() => date.parse("2000-12-00")).toThrow();713 expect(() => date.parse("2000-01-32")).toThrow();714 expect(() => date.parse("2000-13-01")).toThrow();715 expect(() => date.parse("2000-21-01")).toThrow();716 717 expect(() => date.parse("2000-02-30")).toThrow();718 expect(() => date.parse("2000-02-31")).toThrow();719 expect(() => date.parse("2000-04-31")).toThrow();720 expect(() => date.parse("2000-06-31")).toThrow();721 expect(() => date.parse("2000-09-31")).toThrow();722 expect(() => date.parse("2000-11-31")).toThrow();723});724 725test("time", () => {726 const a = z.string().time();727 expect(a.isTime).toEqual(true);728});729 730test("time parsing", () => {731 const time = z.string().time();732 time.parse("00:00:00");733 time.parse("23:00:00");734 time.parse("00:59:00");735 time.parse("00:00:59");736 time.parse("23:59:59");737 time.parse("09:52:31");738 time.parse("23:59:59.9999999");739 time.parse("23:59");740 expect(() => time.parse("")).toThrow();741 expect(() => time.parse("foo")).toThrow();742 expect(() => time.parse("00:00:00Z")).toThrow();743 expect(() => time.parse("0:00:00")).toThrow();744 expect(() => time.parse("00:0:00")).toThrow();745 expect(() => time.parse("00:00:0")).toThrow();746 expect(() => time.parse("00:00:00.000+00:00")).toThrow();747 748 expect(() => time.parse("24:00:00")).toThrow();749 expect(() => time.parse("00:60:00")).toThrow();750 expect(() => time.parse("00:00:60")).toThrow();751 expect(() => time.parse("24:60:60")).toThrow();752 expect(() => time.parse("24:60")).toThrow();753 754 const time2 = z.string().time({ precision: 2 });755 time2.parse("00:00:00.00");756 time2.parse("09:52:31.12");757 time2.parse("23:59:59.99");758 expect(() => time2.parse("")).toThrow();759 expect(() => time2.parse("foo")).toThrow();760 expect(() => time2.parse("00:00:00")).toThrow();761 expect(() => time2.parse("00:00:00.00Z")).toThrow();762 expect(() => time2.parse("00:00:00.0")).toThrow();763 expect(() => time2.parse("00:00:00.000")).toThrow();764 expect(() => time2.parse("00:00:00.00+00:00")).toThrow();765 expect(() => time2.parse("23:59")).toThrow();766 767 // const time3 = z.string().time({ offset: true });768 // time3.parse("00:00:00Z");769 // time3.parse("09:52:31Z");770 // time3.parse("00:00:00+00:00");771 // time3.parse("00:00:00+0000");772 // time3.parse("00:00:00.000Z");773 // time3.parse("00:00:00.000+00:00");774 // time3.parse("00:00:00.000+0000");775 // expect(() => time3.parse("")).toThrow();776 // expect(() => time3.parse("foo")).toThrow();777 // expect(() => time3.parse("00:00:00")).toThrow();778 // expect(() => time3.parse("00:00:00.000")).toThrow();779 780 // const time4 = z.string().time({ offset: true, precision: 0 });781 // time4.parse("00:00:00Z");782 // time4.parse("09:52:31Z");783 // time4.parse("00:00:00+00:00");784 // time4.parse("00:00:00+0000");785 // expect(() => time4.parse("")).toThrow();786 // expect(() => time4.parse("foo")).toThrow();787 // expect(() => time4.parse("00:00:00.0")).toThrow();788 // expect(() => time4.parse("00:00:00.000")).toThrow();789 // expect(() => time4.parse("00:00:00.000+00:00")).toThrow();790});791 792test("duration", () => {793 const duration = z.string().duration();794 expect(duration.isDuration).toEqual(true);795 796 const validDurations = [797 "P3Y6M4DT12H30M5S",798 "P2Y9M3DT12H31M8.001S",799 "+P3Y6M4DT12H30M5S",800 "-PT0.001S",801 "+PT0.001S",802 "PT0,001S",803 "PT12H30M5S",804 "-P2M1D",805 "P-2M-1D",806 "-P5DT10H",807 "P-5DT-10H",808 "P1Y",809 "P2MT30M",810 "PT6H",811 "P5W",812 "P0.5Y",813 "P0,5Y",814 "P42YT7.004M",815 ];816 817 const invalidDurations = ["foo bar", "", " ", "P", "T1H", "P0.5Y1D", "P0,5Y6M", "P1YT"];818 819 for (const val of validDurations) {820 const result = duration.safeParse(val);821 if (!result.success) {822 throw Error(`Valid duration could not be parsed: ${val}`);823 }824 }825 826 for (const val of invalidDurations) {827 const result = duration.safeParse(val);828 829 if (result.success) {830 throw Error(`Invalid duration was successful parsed: ${val}`);831 }832 833 expect(result.error.issues[0].message).toEqual("Invalid duration");834 }835});836 837test("IP validation", () => {838 const ip = z.string().ip();839 expect(ip.safeParse("122.122.122.122").success).toBe(true);840 841 const ipv4 = z.string().ip({ version: "v4" });842 expect(() => ipv4.parse("6097:adfa:6f0b:220d:db08:5021:6191:7990")).toThrow();843 844 const ipv6 = z.string().ip({ version: "v6" });845 expect(() => ipv6.parse("254.164.77.1")).toThrow();846 847 const validIPs = [848 "1e5e:e6c8:daac:514b:114b:e360:d8c0:682c",849 "9d4:c956:420f:5788:4339:9b3b:2418:75c3",850 "474f:4c83::4e40:a47:ff95:0cda",851 "d329:0:25b4:db47:a9d1:0:4926:0000",852 "e48:10fb:1499:3e28:e4b6:dea5:4692:912c",853 "114.71.82.94",854 "0.0.0.0",855 "37.85.236.115",856 "2001:4888:50:ff00:500:d::",857 "2001:4888:50:ff00:0500:000d:000:0000",858 "2001:4888:50:ff00:0500:000d:0000:0000",859 ];860 861 const invalidIPs = [862 "d329:1be4:25b4:db47:a9d1:dc71:4926:992c:14af",863 "d5e7:7214:2b78::3906:85e6:53cc:709:32ba",864 "8f69::c757:395e:976e::3441",865 "54cb::473f:d516:0.255.256.22",866 "54cb::473f:d516:192.168.1",867 "256.0.4.4",868 "-1.0.555.4",869 "0.0.0.0.0",870 "1.1.1",871 ];872 // no parameters check IPv4 or IPv6873 const ipSchema = z.string().ip();874 expect(validIPs.every((ip) => ipSchema.safeParse(ip).success)).toBe(true);875 expect(invalidIPs.every((ip) => ipSchema.safeParse(ip).success === false)).toBe(true);876});877 878test("CIDR validation", () => {879 const ipv4Cidr = z.string().cidr({ version: "v4" });880 expect(() => ipv4Cidr.parse("2001:0db8:85a3::8a2e:0370:7334/64")).toThrow();881 882 const ipv6Cidr = z.string().cidr({ version: "v6" });883 expect(() => ipv6Cidr.parse("192.168.0.1/24")).toThrow();884 885 const validCidrs = [886 "192.168.0.0/24",887 "10.0.0.0/8",888 "203.0.113.0/24",889 "192.0.2.0/24",890 "127.0.0.0/8",891 "172.16.0.0/12",892 "192.168.1.0/24",893 "fc00::/7",894 "fd00::/8",895 "2001:db8::/32",896 "2607:f0d0:1002:51::4/64",897 "2001:0db8:85a3:0000:0000:8a2e:0370:7334/128",898 "2001:0db8:1234:0000::/64",899 ];900 901 const invalidCidrs = [902 "192.168.1.1/33",903 "10.0.0.1/-1",904 "192.168.1.1/24/24",905 "192.168.1.0/abc",906 "2001:db8::1/129",907 "2001:db8::1/-1",908 "2001:db8::1/64/64",909 "2001:db8::1/abc",910 ];911 912 // no parameters check IPv4 or IPv6913 const cidrSchema = z.string().cidr();914 expect(validCidrs.every((ip) => cidrSchema.safeParse(ip).success)).toBe(true);915 expect(invalidCidrs.every((ip) => cidrSchema.safeParse(ip).success === false)).toBe(true);916});917 