From 1afd458ceaccf9eec8167d581a65926e4abe9303 Mon Sep 17 00:00:00 2001 From: Eli Ma Date: Fri, 29 Nov 2024 20:47:54 +0800 Subject: [PATCH 1/2] Add aria module Signed-off-by: Eli Ma --- aria/.eslintrc.json | 3 + aria/.gitignore | 42 ++ aria/LICENSE | 21 + aria/README.md | 100 ++++ aria/app/blog/[slug]/page.tsx | 112 ++++ aria/app/blog/layout.tsx | 9 + aria/app/blog/page.tsx | 96 ++++ aria/app/docs/[[...slug]]/page.tsx | 63 +++ aria/app/docs/layout.tsx | 14 + aria/app/error.tsx | 44 ++ aria/app/favicon.ico | Bin 0 -> 15086 bytes aria/app/layout.tsx | 59 +++ aria/app/not-found.tsx | 19 + aria/app/opengraph-image.jpg | Bin 0 -> 76350 bytes aria/app/page.tsx | 47 ++ aria/components.json | 17 + aria/components/anchor.tsx | 38 ++ aria/components/contexts/theme-provider.tsx | 9 + aria/components/docs-breadcrumb.tsx | 47 ++ aria/components/docs-menu.tsx | 24 + aria/components/footer.tsx | 63 +++ aria/components/leftbar.tsx | 55 ++ aria/components/logo.jsx | 9 + aria/components/markdown/copy.tsx | 33 ++ aria/components/markdown/image.tsx | 25 + aria/components/markdown/link.tsx | 14 + aria/components/markdown/note.tsx | 35 ++ aria/components/markdown/outlet.tsx | 29 ++ aria/components/markdown/pre.tsx | 19 + aria/components/markdown/stepper.tsx | 41 ++ aria/components/navbar.tsx | 112 ++++ aria/components/pagination.tsx | 49 ++ aria/components/search.tsx | 123 +++++ aria/components/sublink.tsx | 88 ++++ aria/components/theme-toggle.tsx | 40 ++ aria/components/toc-observer.tsx | 70 +++ aria/components/toc.tsx | 18 + aria/components/typography.tsx | 9 + aria/components/ui/accordion.tsx | 58 +++ aria/components/ui/avatar.tsx | 50 ++ aria/components/ui/breadcrumb.tsx | 115 +++++ aria/components/ui/button.tsx | 57 ++ aria/components/ui/collapsible.tsx | 11 + aria/components/ui/dialog.tsx | 124 +++++ aria/components/ui/dropdown-menu.tsx | 200 ++++++++ aria/components/ui/input.tsx | 24 + aria/components/ui/scroll-area.tsx | 48 ++ aria/components/ui/sheet.tsx | 140 +++++ aria/components/ui/table.tsx | 117 +++++ aria/components/ui/tabs.tsx | 55 ++ aria/contents/blogs/file-rec.mdx | 170 ++++++ aria/contents/blogs/next-react.mdx | 121 +++++ .../components/code-block/index.mdx | 41 ++ .../components/custom/index.mdx | 38 ++ .../components/image-link/index.mdx | 57 ++ .../docs/getting-started/components/index.mdx | 9 + .../getting-started/components/note/index.mdx | 44 ++ .../components/stepper/index.mdx | 38 ++ .../getting-started/components/tabs/index.mdx | 68 +++ .../docs/getting-started/customize/index.mdx | 93 ++++ .../getting-started/installation/index.mdx | 72 +++ .../getting-started/introduction/index.mdx | 58 +++ .../project-structure/index.mdx | 95 ++++ .../quick-start-guide/index.mdx | 80 +++ .../docs/getting-started/themes/index.mdx | 485 ++++++++++++++++++ aria/images/logo.svg | 26 + aria/lib/markdown.ts | 218 ++++++++ aria/lib/routes-config.ts | 61 +++ aria/lib/utils.ts | 80 +++ aria/next.config.ts | 17 + aria/package.json | 52 ++ aria/postcss.config.mjs | 8 + aria/public/halloween.png | Bin 0 -> 148694 bytes aria/public/nebula.png | Bin 0 -> 149560 bytes aria/public/ocean.png | Bin 0 -> 149992 bytes aria/public/public-og.png | Bin 0 -> 3454883 bytes aria/styles/globals.css | 120 +++++ aria/styles/syntax.css | 72 +++ aria/tailwind.config.ts | 86 ++++ aria/tsconfig.json | 27 + 80 files changed, 4831 insertions(+) create mode 100644 aria/.eslintrc.json create mode 100644 aria/.gitignore create mode 100644 aria/LICENSE create mode 100644 aria/README.md create mode 100644 aria/app/blog/[slug]/page.tsx create mode 100644 aria/app/blog/layout.tsx create mode 100644 aria/app/blog/page.tsx create mode 100644 aria/app/docs/[[...slug]]/page.tsx create mode 100644 aria/app/docs/layout.tsx create mode 100644 aria/app/error.tsx create mode 100644 aria/app/favicon.ico create mode 100644 aria/app/layout.tsx create mode 100644 aria/app/not-found.tsx create mode 100644 aria/app/opengraph-image.jpg create mode 100644 aria/app/page.tsx create mode 100644 aria/components.json create mode 100644 aria/components/anchor.tsx create mode 100644 aria/components/contexts/theme-provider.tsx create mode 100644 aria/components/docs-breadcrumb.tsx create mode 100644 aria/components/docs-menu.tsx create mode 100644 aria/components/footer.tsx create mode 100644 aria/components/leftbar.tsx create mode 100644 aria/components/logo.jsx create mode 100644 aria/components/markdown/copy.tsx create mode 100644 aria/components/markdown/image.tsx create mode 100644 aria/components/markdown/link.tsx create mode 100644 aria/components/markdown/note.tsx create mode 100644 aria/components/markdown/outlet.tsx create mode 100644 aria/components/markdown/pre.tsx create mode 100644 aria/components/markdown/stepper.tsx create mode 100644 aria/components/navbar.tsx create mode 100644 aria/components/pagination.tsx create mode 100644 aria/components/search.tsx create mode 100644 aria/components/sublink.tsx create mode 100644 aria/components/theme-toggle.tsx create mode 100644 aria/components/toc-observer.tsx create mode 100644 aria/components/toc.tsx create mode 100644 aria/components/typography.tsx create mode 100644 aria/components/ui/accordion.tsx create mode 100644 aria/components/ui/avatar.tsx create mode 100644 aria/components/ui/breadcrumb.tsx create mode 100644 aria/components/ui/button.tsx create mode 100644 aria/components/ui/collapsible.tsx create mode 100644 aria/components/ui/dialog.tsx create mode 100644 aria/components/ui/dropdown-menu.tsx create mode 100644 aria/components/ui/input.tsx create mode 100644 aria/components/ui/scroll-area.tsx create mode 100644 aria/components/ui/sheet.tsx create mode 100644 aria/components/ui/table.tsx create mode 100644 aria/components/ui/tabs.tsx create mode 100644 aria/contents/blogs/file-rec.mdx create mode 100644 aria/contents/blogs/next-react.mdx create mode 100644 aria/contents/docs/getting-started/components/code-block/index.mdx create mode 100644 aria/contents/docs/getting-started/components/custom/index.mdx create mode 100644 aria/contents/docs/getting-started/components/image-link/index.mdx create mode 100644 aria/contents/docs/getting-started/components/index.mdx create mode 100644 aria/contents/docs/getting-started/components/note/index.mdx create mode 100644 aria/contents/docs/getting-started/components/stepper/index.mdx create mode 100644 aria/contents/docs/getting-started/components/tabs/index.mdx create mode 100644 aria/contents/docs/getting-started/customize/index.mdx create mode 100644 aria/contents/docs/getting-started/installation/index.mdx create mode 100644 aria/contents/docs/getting-started/introduction/index.mdx create mode 100644 aria/contents/docs/getting-started/project-structure/index.mdx create mode 100644 aria/contents/docs/getting-started/quick-start-guide/index.mdx create mode 100644 aria/contents/docs/getting-started/themes/index.mdx create mode 100644 aria/images/logo.svg create mode 100644 aria/lib/markdown.ts create mode 100644 aria/lib/routes-config.ts create mode 100644 aria/lib/utils.ts create mode 100644 aria/next.config.ts create mode 100644 aria/package.json create mode 100644 aria/postcss.config.mjs create mode 100644 aria/public/halloween.png create mode 100644 aria/public/nebula.png create mode 100644 aria/public/ocean.png create mode 100644 aria/public/public-og.png create mode 100644 aria/styles/globals.css create mode 100644 aria/styles/syntax.css create mode 100644 aria/tailwind.config.ts create mode 100644 aria/tsconfig.json diff --git a/aria/.eslintrc.json b/aria/.eslintrc.json new file mode 100644 index 000000000..372241854 --- /dev/null +++ b/aria/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": ["next/core-web-vitals", "next/typescript"] +} diff --git a/aria/.gitignore b/aria/.gitignore new file mode 100644 index 000000000..d44b53b1f --- /dev/null +++ b/aria/.gitignore @@ -0,0 +1,42 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# package manager +package-lock.json + +# IDE +.idea +.vscode \ No newline at end of file diff --git a/aria/LICENSE b/aria/LICENSE new file mode 100644 index 000000000..ab7a1dac9 --- /dev/null +++ b/aria/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Mohd. Nisab + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/aria/README.md b/aria/README.md new file mode 100644 index 000000000..84abdf728 --- /dev/null +++ b/aria/README.md @@ -0,0 +1,100 @@ +## AriaDocs - Documentation Template + +This feature-packed documentation template, built with Next.js, offers a sleek and responsive design, perfect for all your project documentation needs. + + + +
+ +Here are all versions of the AriaDocs template, each crafted for specific use cases: + + +- **Advanced Docs:** A comprehensive template offering extensive features for in-depth documentation needs. Perfect for larger projects that require detailed explanations and advanced configurations. + [Explore the Advanced Docs](https://github.com/nisabmohd/Aria-Docs/tree/master) + +- **Lite Version:** A streamlined, no-frills template perfect for straightforward documentation needs. + [Explore the Lite Version](https://github.com/nisabmohd/Aria-Docs/tree/minimal-docs) + +- **Version with Versioning:** A powerful option for projects that require historical documentation tracking. Manage multiple versions of your docs effortlessly. + [Check out the Versioning Feature](https://github.com/nisabmohd/Aria-Docs/tree/version_docs) + +- **i18n Support Version (WIP):** Designed for international audiences, this version will offer comprehensive multilingual support. + [Preview the i18n Support](https://github.com/nisabmohd/Aria-Docs/tree/i18n-support) + +### Quick Start + +You can create a new Ariadocs project using the command: + +```plaintext +npx create-aria-doc +``` + +### Expected Output + +When you run the CLI, you can expect an output similar to this: + +``` +Creating a new Ariadocs project in /path/to/your/project from the master branch... +Cloning Master (Full Documentation)... +Ariadocs project successfully created in /path/to/your/project! + +Next steps: +1. Navigate to your project directory: + cd +2. Install dependencies: + // To support React 19, package maintainers will need to test and update their packages to include React 19 as a peer dependency. This is already in progress. + npm install --force +3. Start the development server: + npm run dev +``` + +## Getting Started + +First, run the development server: + +```plaintext +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/nisabmohd/Aria-Docs) + +## Key Features + +| **Feature** | **Description** | +|-------------------------------|----------------------------------------------------------| +| MDX Support | Write interactive documentation with MDX. | +| Nested Pages | Organize content in a nested, hierarchical structure. | +| Blog Section | Include a dedicated blog section. | +| Table of Contents | Auto-generated TOC for easy navigation. | +| Pagination | Split content across multiple pages. | +| Syntax Highlighting | Highlight code for better readability. | +| Code Line Highlighting & Titles | Highlight specific lines with descriptive titles. | +| Interactive Code Blocks | Language-specific and interactive code display. | +| Custom Components | Embed custom, reusable components in your docs. | +| Light & Dark Mode | Toggle between light and dark themes. | +| Search Functionality | Quickly find content with a built-in search. | +| Code Switcher | Switch between code languages or variations. | +| Code Copy | Copy code blocks with a single click. | +| TOC Observer Highlight | Highlight active sections in the TOC as you scroll. | +| Static Site Generation | Generate a static, high-performance site. | +| SEO-Optimized | Structured for optimal search engine indexing. | + + +## Additional Themes + +halloween +halloween +halloween \ No newline at end of file diff --git a/aria/app/blog/[slug]/page.tsx b/aria/app/blog/[slug]/page.tsx new file mode 100644 index 000000000..166727e5d --- /dev/null +++ b/aria/app/blog/[slug]/page.tsx @@ -0,0 +1,112 @@ +import { Typography } from "@/components/typography"; +import { buttonVariants } from "@/components/ui/button"; +import { Author, getAllBlogStaticPaths, getBlogForSlug } from "@/lib/markdown"; +import { ArrowLeftIcon } from "lucide-react"; +import Link from "next/link"; +import { notFound } from "next/navigation"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { formatDate } from "@/lib/utils"; +import Image from "next/image"; + +type PageProps = { + params: Promise<{ slug: string }>; +}; + +export async function generateMetadata(props: PageProps) { + const params = await props.params; + + const { + slug + } = params; + + const res = await getBlogForSlug(slug); + if (!res) return null; + const { frontmatter } = res; + return { + title: frontmatter.title, + description: frontmatter.description, + }; +} + +export async function generateStaticParams() { + const val = await getAllBlogStaticPaths(); + if (!val) return []; + return val.map((it) => ({ slug: it })); +} + +export default async function BlogPage(props: PageProps) { + const params = await props.params; + + const { + slug + } = params; + + const res = await getBlogForSlug(slug); + if (!res) notFound(); + return ( +
+ + Back to blog + +
+

+ {formatDate(res.frontmatter.date)} +

+

+ {res.frontmatter.title} +

+
+

Posted by

+ +
+
+
+
+ cover +
+ {res.content} +
+
+ ); +} + +function Authors({ authors }: { authors: Author[] }) { + return ( +
+ {authors.map((author) => { + return ( + + + + + {author.username.slice(0, 2).toUpperCase()} + + +
+

{author.username}

+

+ @{author.handle} +

+
+ + ); + })} +
+ ); +} diff --git a/aria/app/blog/layout.tsx b/aria/app/blog/layout.tsx new file mode 100644 index 000000000..6211155f1 --- /dev/null +++ b/aria/app/blog/layout.tsx @@ -0,0 +1,9 @@ +import { PropsWithChildren } from "react"; + +export default function BlogLayout({ children }: PropsWithChildren) { + return ( +
+ {children} +
+ ); +} diff --git a/aria/app/blog/page.tsx b/aria/app/blog/page.tsx new file mode 100644 index 000000000..7202d2c33 --- /dev/null +++ b/aria/app/blog/page.tsx @@ -0,0 +1,96 @@ +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { Author, BlogMdxFrontmatter, getAllBlogs } from "@/lib/markdown"; +import { formatDate2, stringToDate } from "@/lib/utils"; +import { Metadata } from "next"; +import Image from "next/image"; +import Link from "next/link"; + +export const metadata: Metadata = { + title: "AriaDocs - Blog", +}; + +export default async function BlogIndexPage() { + const blogs = (await getAllBlogs()).sort( + (a, b) => stringToDate(b.date).getTime() - stringToDate(a.date).getTime() + ); + return ( +
+
+

+ The latest blogs of this product +

+

+ All the latest blogs and news, straight from the team. +

+
+
+ {blogs.map((blog) => ( + + ))} +
+
+ ); +} + +function BlogCard({ + date, + title, + description, + slug, + cover, + authors, +}: BlogMdxFrontmatter & { slug: string }) { + return ( + +

{title}

+
+ {title} +
+

{description}

+
+

+ Published on {formatDate2(date)} +

+ +
+ + ); +} + +function AvatarGroup({ users, max = 4 }: { users: Author[]; max?: number }) { + const displayUsers = users.slice(0, max); + const remainingUsers = Math.max(users.length - max, 0); + + return ( +
+ {displayUsers.map((user, index) => ( + + + + {user.username.slice(0, 2).toUpperCase()} + + + ))} + {remainingUsers > 0 && ( + + +{remainingUsers} + + )} +
+ ); +} diff --git a/aria/app/docs/[[...slug]]/page.tsx b/aria/app/docs/[[...slug]]/page.tsx new file mode 100644 index 000000000..f28ba38f8 --- /dev/null +++ b/aria/app/docs/[[...slug]]/page.tsx @@ -0,0 +1,63 @@ +import DocsBreadcrumb from "@/components/docs-breadcrumb"; +import Pagination from "@/components/pagination"; +import Toc from "@/components/toc"; +import { page_routes } from "@/lib/routes-config"; +import { notFound } from "next/navigation"; +import { getDocsForSlug } from "@/lib/markdown"; +import { Typography } from "@/components/typography"; + +type PageProps = { + params: Promise<{ slug: string[] }>; +}; + +export default async function DocsPage(props: PageProps) { + const params = await props.params; + + const { + slug = [] + } = params; + + const pathName = slug.join("/"); + const res = await getDocsForSlug(pathName); + + if (!res) notFound(); + return ( +
+
+ + +

{res.frontmatter.title}

+

+ {res.frontmatter.description} +

+
{res.content}
+ +
+
+ +
+ ); +} + +export async function generateMetadata(props: PageProps) { + const params = await props.params; + + const { + slug = [] + } = params; + + const pathName = slug.join("/"); + const res = await getDocsForSlug(pathName); + if (!res) return null; + const { frontmatter } = res; + return { + title: frontmatter.title, + description: frontmatter.description, + }; +} + +export function generateStaticParams() { + return page_routes.map((item) => ({ + slug: item.href.split("/").slice(1), + })); +} diff --git a/aria/app/docs/layout.tsx b/aria/app/docs/layout.tsx new file mode 100644 index 000000000..ef73ca474 --- /dev/null +++ b/aria/app/docs/layout.tsx @@ -0,0 +1,14 @@ +import { Leftbar } from "@/components/leftbar"; + +export default function DocsLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( +
+ +
{children}
+
+ ); +} diff --git a/aria/app/error.tsx b/aria/app/error.tsx new file mode 100644 index 000000000..8a8ae0bc4 --- /dev/null +++ b/aria/app/error.tsx @@ -0,0 +1,44 @@ +"use client"; // Error components must be Client Components + +import { Button, buttonVariants } from "@/components/ui/button"; +import Link from "next/link"; +import { useEffect } from "react"; + +export default function Error({ + error, + reset, +}: { + error: Error & { digest?: string }; + reset: () => void; +}) { + useEffect(() => { + console.error(error); + }, [error]); + + return ( +
+
+

Oops!

+

+ Something went wrong {":`("} +

+

+ We're sorry, but an error occurred while processing your request. +

+
+
+ + + Back to homepage + +
+
+ ); +} diff --git a/aria/app/favicon.ico b/aria/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..56276eba52863caaef12b1e3790667e3e8f1e6dc GIT binary patch literal 15086 zcmeI3XOL9K5y$s9;K+Aiay)VrATpFp5*Z1QL=ZViB$1&IU||kKkR?E51PG2K3E9H_ zppTYaS7kogRW64wmhCc>gXC0B>i5^i^XEa#TCy*vDnY_u1GoG*VK;14yiydl~I-0G7;~6>Q{i?`L$}f+WGk|zZwuY^78Ub zE@Yq|f~l?^PKm6Ht5;Cq8rH90ZKzJ|+Hq{c`8`o^HkzvEKPTX?TesR^M~@-=$Z}ki zFKQtAswgO*tCuDI2KDMWsJ{9U;&(RvnFRl@gqgW@jOh2d#BX@pwQlVm>C?w`>)hED zHEx`h97*t_Z`OxHVeC9tMgOMn4(-~x*)wOlBL@z+(sSqB`Qyjk*7fV%-~j_%lSYlI zBu5JTKNi++W{cl&w`kVPO&mMceQE!G_wJP|?$(VPaeD9ib$9v98Mk`*a@V~}7jH}T zGq9-?`00Z?RmE?(3#HSck3Q&-XaEn)r2wQKIo(W7p|s#WfbJ9fAmyq7$@ zKmFQkZtkpE4*N1&t88pU;7_{FR%So&g=f!h-Q2q8p7Xjz$6n88&w4%g(ziwp8o1{4 z%eZmw@ZP=gez~ds;dz4kt65P|rE)~zrw{IlEFh`xm!t zal-};O0aXQgTCiI^;ANg8y7FS7dLNqLk13XjT<&hDMv2wgQKWP6K~_Ml$6AEiLD=! zE+Wqz)L4-~YiZ1EfRMRVu6>(ZIo z@+sN!yr-Xb^hY|jOgofg9zy54wr+Lw0qwn~vB8|xw^uJ;CYSi(IehS7clC`oyw0v@ zUR=9!rPn2VylyktZ;d*Ed%G73(VdtI4uYAR#MK$;<)`FmIpda*9qyOaRp&I*%-apjX zPjb7l`KZQzK3n#4;p9ob@5z;q#oLeO=m)v}!ei0Ad4BKqmi9kW9)G<2449>Ffp%HP z+qZ4&_U_#2*Wa_pj=3(KIwh>{+3bH9XYd#~bf~*_;ewZeJ&H&lshhJ0iTDf?!WBHgJlP#PbjagJ zj(09!_I>}@h!K9@PG2RH!?0r;%NH*6`#^vGQX9yyY3*9azLRp{`nkYwGSD`5vvk3N z`!H-=v&KErySG2Ln;eF_b<37+=Co;EcKi^?{ zN8tZjw)l-N{Q+@yT`c=KDc=OX3jBt0K#b`p{3gAYaVKFHPH>;d7&=S+M$m{#iH?;XZ|oCdM9>=m%_x z*iv=DPHdO>G%@yc6LK;y{Zw?{`k;3YLpI`~#CC~K6JyUb5g$el);QMbABvLhm-Idt z@-X)9h=?g37L5^M(u+!CZPXJz~J<)$4h$R9+_axpLzu)~B(e_&u#6Jyf3hstED#Ux?IF zPUw$n=Uve_QK~yvb@XkS=tEJi_=em0joRKX3TpyP+eLpBh3n+{`4jQDBno1fqi26l z#jno~Xl-Wi!u=!h0t0%GW%;@D+seJ1>C^I0F2^aZ~gSkztCw-(-A=yHA}s(Y>;7pDR^N{;*=k_`RA(#E8)k^+Wvs zAl@HU#^3l7n;kJ^i1&#QnGWwIv)-fo48&4X-6cuFAGxuGl=9nMjy^ql zxQ(kzfj3+K#n z_(t(9y!_Hj-meB<+BV&ozm4yd<19~Hmim-Qq5lNlLH^WfBfkuHNAL}teDzf~W9rnD zJ`KZx&x3N5ryliN%TDx zx|}9kFQ`+;HLQep5EtbcBlHD+y=?eToiHKedspzIUJd^m{a4lgsE7SbsiOT+FB|)t zG=99FL-4ucce42|IL^YqZT#cI#n%S^$!aIl@dvM-T3gR4=E9sGyu)N`LYO!2;m