Full Code of zeekrey/teini for AI

main 53800d9740a8 cached
44 files
235.9 KB
93.9k tokens
20 symbols
1 requests
Download .txt
Showing preview only (249K chars total). Download the full file or copy to clipboard to get everything.
Repository: zeekrey/teini
Branch: main
Commit: 53800d9740a8
Files: 44
Total size: 235.9 KB

Directory structure:
gitextract_jnytts6o/

├── .eslintrc.json
├── .gitignore
├── .prettierrc.json
├── README.md
├── __mocks__/
│   └── fileMock.js
├── __tests__/
│   ├── api/
│   │   └── products.http
│   └── unit/
│       ├── cart.test.tsx
│       ├── productsDb.test.ts
│       └── shipping.test.tsx
├── components/
│   ├── Button.tsx
│   ├── Footer.tsx
│   ├── Layout.tsx
│   ├── MenuBar.tsx
│   ├── PageHeadline.tsx
│   ├── ProductCard.tsx
│   └── ProductCardCart.tsx
├── jest.config.js
├── jest.setup.js
├── lib/
│   ├── cart.tsx
│   ├── fetcher.tsx
│   ├── mapToObject.tsx
│   └── stripeHelpers.tsx
├── license.md
├── next-env.d.ts
├── next.config.js
├── package.json
├── pages/
│   ├── _app.tsx
│   ├── _document.tsx
│   ├── api/
│   │   ├── checkout_sessions/
│   │   │   ├── [id].ts
│   │   │   └── index.ts
│   │   └── products/
│   │       └── index.ts
│   ├── cart.tsx
│   ├── confirmation.tsx
│   ├── index.tsx
│   └── products/
│       ├── [slug].tsx
│       └── index.tsx
├── prisma/
│   ├── migrations/
│   │   ├── 20210923095130_init/
│   │   │   └── migration.sql
│   │   └── migration_lock.toml
│   ├── schema.prisma
│   └── seed.ts
├── stitches.config.ts
├── tsconfig.json
├── types.d.ts
└── yarn-error.log

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintrc.json
================================================
{
  "extends": ["next", "next/core-web-vitals", "prettier"]
}


================================================
FILE: .gitignore
================================================
node_modules
# Keep environment variables out of version control
.env
.env.local

.next


================================================
FILE: .prettierrc.json
================================================
{}

================================================
FILE: README.md
================================================
# Teini

> Teini (tiny, [ˈtīnē]) is an extremely small webshop leveraging awesome and free solutions like Github and Vercel.

Main purpose is to get you started fast and cheap. Hit the deploy button to create your own version of Teini or see a working demo here: https://teini.vercel.app/

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fzeekrey%2Fteini&env=STRIPE_SECRET_KEY,NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY,SHOP_NAME,SHOP_CONTACT,SHOP_HEADLINE,SHOP_SUBHEADLINE&envDescription=You'll%20need%20Stripe%20API%20key.&envLink=https%3A%2F%2Fstripe.com%2Fdocs%2Fkeys&project-name=teini-copy&repo-name=teini-copy&redirect-url=https%3A%2F%2Fkrey.io&demo-title=Teini%20-%20The%20smallest%20eShop%20in%20the%20world&demo-description=A%20real%20online%20store.%20But%20without%20the%20costs%20and%20without%20complexity.&demo-url=https%3A%2F%2Fteini.co&demo-image=https%3A%2F%2Fimages.unsplash.com%2Fphoto-1494256997604-768d1f608cac%3Fixid%3DMnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8%26ixlib%3Drb-1.2.1%26auto%3Dformat%26fit%3Dcrop%26w%3D1829%26q%3D80)

## Installation

### ...if you're not a developer

> 💡 If you need help at any stage contact me. If you want me to setup Teini contact me as well.

#### Accounts needed

Running Teini should be easy and for free. Although you'll need to create some accounts to make it work:

| Account       | Description/What it does                                                   | Link                |
| ------------- | -------------------------------------------------------------------------- | ------------------- |
| Vercel        | Deploys and keeps the actual website running. It's awesome.                | https://vercel.com/ |
| Stripe        | Provides the whole checkout and payment infrastructure. It's awesome, too. | https://stripe.com  |
| Github/Gitlab | The place where the source code is stored. Awesome - yep.                  | https://github.com  |

> 🤑 While Vercel and Github should be free while respecting their fair use policies, Stripe will cost some money. Fortunately, these are transaction-dependent.

#### Environment Variables

To configure your store you need to set some meta data and credentials upfront. The following data needs to be set:

| Environment Variable               | Description                                                                                          | Default |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------- | ------- |
| STRIPE_SECRET_KEY                  | The Stripe secret key: https://stripe.com/docs/keys#obtain-api-keys                                  |
| NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY | The Stripe publishable key: https://stripe.com/docs/keys#obtain-api-keys                             |
| SHOP_NAME                          | Will show up in the browser tab and in the seo config.                                               |
| SHOP_CONTACT                       | A way customers can contact your. Could be an email or a Twitter handle. Will show up in the footer. |
| SHOP_HEADLINE                      | Will show up on the index (start) page and in the seo config.                                        |
| SHOP_SUBHEADLINE                   | Will show up on the index (start) page and in the seo config.                                        |

Once you got everything together you can finally deploy your own version for Teini:

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fzeekrey%2Fteini&env=STRIPE_SECRET_KEY,NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY,SHOP_NAME,SHOP_CONTACT,SHOP_HEADLINE,SHOP_SUBHEADLINE&envDescription=You'll%20need%20Stripe%20API%20key.&envLink=https%3A%2F%2Fstripe.com%2Fdocs%2Fkeys&project-name=teini-copy&repo-name=teini-copy&redirect-url=https%3A%2F%2Fkrey.io&demo-title=Teini%20-%20The%20smallest%20eShop%20in%20the%20world&demo-description=A%20real%20online%20store.%20But%20without%20the%20costs%20and%20without%20complexity.&demo-url=https%3A%2F%2Fteini.co&demo-image=https%3A%2F%2Fimages.unsplash.com%2Fphoto-1494256997604-768d1f608cac%3Fixid%3DMnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8%26ixlib%3Drb-1.2.1%26auto%3Dformat%26fit%3Dcrop%26w%3D1829%26q%3D80)

## Usage

Once your store is up and running you definitly what to add your own products. Here is how to do this:

### 1. Access the repository

To make changes you need to access the repository and change the actual source code. To do this you'll need the following tools (all of them are for free):

- Git -> https://git-scm.com/
- VSCode -> https://code.visualstudio.com/
- Prisma Studio -> https://www.prisma.io/studio

Once you got everything installed open a terminal and type the following command:

```bash
git clone https://github.com/username/reponame
```

> 💡 The repo url depends on your choosen service, username and repo name.

### 2. Make changes to the product database

Open Prisma Studio and open the product.db file. It is located at the root level of your repo and called `products.db`. Once the database add, update or delete products.

### 3. Add product images

Teini holds all its static files like product images in the `public` folder. Product images in particular are store under `public/prodcuts/[productid]`. To add product images you just need to add a folder with the corresponding product-id (see your products.db) and put all product images in there.

> 💡 Google recommends using the WebP as image format. You can convert your files here: https://cloudconvert.com/webp-converter

### 3. Make changes to the store itself

Open a terminal and navigate (cd) to your local repository copy. Run this command:

```bash
code .
```

Now VSCode should open and you can change what ever you want.

### 4.Push your changes

To make your changes visible you need to run the following commands:

```bash
git add .
git commit -m "A message describing your work like; Added images for product 1."
git push
```

If your go to https://vercel.com and open your project you should see that a deployment is started. If it is successfull you customers can see your changes. If it failed feel free to create an issue: https://github.com/zeekrey/teini/issues/new/choose

### ...if you're a developer

Clone, Edit, Push. Do what ever you want.

## Notes

Credits for the used photos:

Product photos
Photo by <a href="https://unsplash.com/@boxedwater?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Boxed Water Is Better</a> on <a href="https://unsplash.com/@boxedwater?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>

Success Page photo
Photo by <a href="https://unsplash.com/@jdent?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Jason Dent</a> on <a href="https://unsplash.com/s/photos/celebrate?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>


================================================
FILE: __mocks__/fileMock.js
================================================
module.exports = "test-file-stub";


================================================
FILE: __tests__/api/products.http
================================================
GET http://localhost:3000/api/products HTTP/1.1

###

GET http://localhost:3000/api/products?page=1 HTTP/1.1

###

================================================
FILE: __tests__/unit/cart.test.tsx
================================================
/**
 * @jest-environment jsdom
 */

/**
 * This test file should test the cart feature.
 * Currently, there are three scenarios to be tested:
 *
 * 1. Add a product to cart
 * 2. Change amount of a product in cart
 * 3. Remove product
 */

import React from "react";
import { render, fireEvent } from "@testing-library/react";
import CartPage, { getStaticProps } from "../../pages/cart";
import { Tmeta } from "../../types";

import { PrismaClient, Prisma } from "@prisma/client";
import { useCart, CartProvider } from "../../lib/cart";

const prisma = new PrismaClient();

let product: null | Required<Prisma.ProductUncheckedCreateInput>;

const TestWrapper: React.FunctionComponent<{
  product: Required<Prisma.ProductUncheckedCreateInput>;
}> = ({ children, product }) => {
  const { cart, dispatch } = useCart();

  React.useEffect(() => {
    dispatch({
      type: "addItem",
      item: { product: product, images: [], count: 1 },
    });
  }, []);

  return <>{children}</>;
};

beforeAll(() => {
  // Otherwise useEffect hooks won't work: https://github.com/testing-library/react-testing-library/issues/215
  jest.spyOn(React, "useEffect").mockImplementation(React.useLayoutEffect);

  return new Promise(async (resolve) => {
    const _product = await prisma.product.findFirst({
      where: {
        name: {
          equals: "The first product",
        },
      },
      include: {
        brand: true,
      },
    });

    product = _product;

    resolve(product);
  });
});

// @ts-ignore
afterAll(() => React.useEffect.mockRestore());

describe("Test cart", () => {
  it("should add a product to cart", async () => {
    /**
     * Get the actual cart page props.
     */
    const { props } = (await getStaticProps({
      params: undefined,
    })) as unknown as {
      props: {
        meta: Tmeta;
        shippingOptions: Required<Prisma.ShippingCodeUncheckedCreateInput>[];
      };
    };

    const { queryByText } = render(
      <TestWrapper {...props} product={product!}>
        <CartPage
          {...(props as unknown as {
            meta: Tmeta;
            shippingOptions: Required<Prisma.ShippingCodeUncheckedCreateInput>[];
          })}
        />
      </TestWrapper>,
      {
        wrapper: (props) => <CartProvider {...props} />,
      }
    );

    const productContainer = queryByText("The first product");
    expect(productContainer).toBeInTheDocument();
  });

  it("should add a product of same type (count++)", async () => {
    /**
     * Get the actual cart page props.
     */
    const { props } = (await getStaticProps({
      params: undefined,
    })) as unknown as {
      props: {
        meta: Tmeta;
        shippingOptions: Required<Prisma.ShippingCodeUncheckedCreateInput>[];
      };
    };

    const { getByText, getByTestId } = render(
      <TestWrapper {...props} product={product!}>
        <CartPage
          {...(props as unknown as {
            meta: Tmeta;
            shippingOptions: Required<Prisma.ShippingCodeUncheckedCreateInput>[];
          })}
        />
      </TestWrapper>,
      {
        wrapper: (props) => <CartProvider {...props} />,
      }
    );

    fireEvent.click(getByText("+"));

    const productCount = getByTestId("productCount");
    expect(productCount.textContent).toEqual("2");
  });

  it("should remove a product of same type (count--)", async () => {
    /**
     * Get the actual cart page props.
     */
    const { props } = (await getStaticProps({
      params: undefined,
    })) as unknown as {
      props: {
        meta: Tmeta;
        shippingOptions: Required<Prisma.ShippingCodeUncheckedCreateInput>[];
      };
    };

    const { getByText, queryByText } = render(
      <TestWrapper {...props} product={product!}>
        <CartPage
          {...(props as unknown as {
            meta: Tmeta;
            shippingOptions: Required<Prisma.ShippingCodeUncheckedCreateInput>[];
          })}
        />
      </TestWrapper>,
      {
        wrapper: (props) => <CartProvider {...props} />,
      }
    );

    fireEvent.click(getByText("-"));

    // product shouldn't be visibile because count === 0
    const productContainer = queryByText("The first product");
    expect(productContainer).not.toBeInTheDocument();
  });
});


================================================
FILE: __tests__/unit/productsDb.test.ts
================================================
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();

afterAll(async () => {
  await prisma.$disconnect();
});

test("product.db should have at least one product", async () => {
  const allProducts = await prisma.product.findMany();

  expect(allProducts.length).toBeGreaterThan(0);
});

test("product.db should have at least one product in stock", async () => {
  const productsInStock = await prisma.product.findMany({
    where: { availability: "inStock" },
  });

  expect(productsInStock.length).toBeGreaterThan(0);
});


================================================
FILE: __tests__/unit/shipping.test.tsx
================================================
/**
 * @jest-environment jsdom
 */

/**
 * This test file should test the shipping option feature.
 * Currently, there are three scenarios to be tested:
 *
 * 1. A product needs shipping
 * 2. A product doesn't need shipping
 * 3. Shipping costs are set to $0.00 because of isFreeFrom attribute
 */

import React from "react";
import { render } from "@testing-library/react";
import CartPage, { getStaticProps } from "../../pages/cart";
import { Tmeta } from "../../types";

import { PrismaClient, Prisma } from "@prisma/client";
import { useCart, CartProvider } from "../../lib/cart";

const prisma = new PrismaClient();

let products: Map<
  "productWithShipping" | "productWithoutShipping" | "productHasFreeShipping",
  Required<Prisma.ProductUncheckedCreateInput>
> = new Map();

const TestWrapper: React.FunctionComponent<{
  product: Required<Prisma.ProductUncheckedCreateInput>;
}> = ({ children, product }) => {
  const { cart, dispatch } = useCart();

  React.useEffect(() => {
    dispatch({
      type: "addItem",
      item: { product: product, images: [], count: 1 },
    });
  }, []);

  return <section>{children}</section>;
};

beforeAll(() => {
  // Otherwise useEffect hooks won't work: https://github.com/testing-library/react-testing-library/issues/215
  jest.spyOn(React, "useEffect").mockImplementation(React.useLayoutEffect);

  return new Promise(async (resolve) => {
    const productWithShipping = await prisma.product.findFirst({
      where: {
        needsShipping: {
          equals: true,
        },
      },
      include: {
        brand: true,
      },
    });

    const productWithoutShipping = await prisma.product.findFirst({
      where: {
        needsShipping: {
          equals: false,
        },
      },
      include: {
        brand: true,
      },
    });

    const productHasFreeShipping = await prisma.product.findFirst({
      where: {
        price: {
          gt: 10000,
        },
        needsShipping: {
          equals: true,
        },
      },
      include: {
        brand: true,
      },
    });

    products.set(
      "productWithShipping",
      productWithShipping as unknown as Required<Prisma.ProductUncheckedCreateInput>
    );
    products.set(
      "productWithoutShipping",
      productWithoutShipping as unknown as Required<Prisma.ProductUncheckedCreateInput>
    );
    products.set(
      "productHasFreeShipping",
      productHasFreeShipping as unknown as Required<Prisma.ProductUncheckedCreateInput>
    );

    resolve(products);
  });
});

// @ts-ignore
afterAll(() => React.useEffect.mockRestore());

describe("Test shipping methods", () => {
  it("should not show shipping options (product doesn't need shipping).", async () => {
    /**
     * Get the actual cart page props.
     */
    const { props } = (await getStaticProps({
      params: undefined,
    })) as unknown as {
      props: {
        meta: Tmeta;
        shippingOptions: Required<Prisma.ShippingCodeUncheckedCreateInput>[];
      };
    };

    const { queryByText } = render(
      <TestWrapper product={products.get("productWithoutShipping")!}>
        <CartPage
          {...(props as unknown as {
            meta: Tmeta;
            shippingOptions: Required<Prisma.ShippingCodeUncheckedCreateInput>[];
          })}
        />
      </TestWrapper>,
      {
        wrapper: CartProvider,
      }
    );

    const shippingOption = queryByText("Free Shipping");

    expect(shippingOption).not.toBeInTheDocument();
  });

  it("should show shipping options with 0.00 as price.", async () => {
    /**
     * Get the actual cart page props.
     */
    const { props } = (await getStaticProps({
      params: undefined,
    })) as unknown as {
      props: {
        meta: Tmeta;
        shippingOptions: Required<Prisma.ShippingCodeUncheckedCreateInput>[];
      };
    };

    const { queryAllByText } = render(
      <TestWrapper product={products.get("productHasFreeShipping")!}>
        <CartPage
          {...(props as unknown as {
            meta: Tmeta;
            shippingOptions: Required<Prisma.ShippingCodeUncheckedCreateInput>[];
          })}
        />
      </TestWrapper>,
      {
        wrapper: (props) => <CartProvider {...props} />,
      }
    );

    const shippingOptionPrice = queryAllByText("$ 0.00");
    expect(shippingOptionPrice[0]).toBeInTheDocument();
  });

  it("should show shipping options (product needs shipping).", async () => {
    /**
     * Get the actual cart page props.
     */
    const { props } = (await getStaticProps({
      params: undefined,
    })) as unknown as {
      props: {
        meta: Tmeta;
        shippingOptions: Required<Prisma.ShippingCodeUncheckedCreateInput>[];
      };
    };

    const { queryByText, debug } = render(
      <TestWrapper product={products.get("productWithShipping")!}>
        <CartPage
          {...(props as unknown as {
            meta: Tmeta;
            shippingOptions: Required<Prisma.ShippingCodeUncheckedCreateInput>[];
          })}
        />
      </TestWrapper>,
      {
        wrapper: (props) => <CartProvider {...props} />,
      }
    );

    const shippingOption = queryByText("Free Shipping");
    expect(shippingOption).toBeInTheDocument();
  });
});


================================================
FILE: components/Button.tsx
================================================
import { styled, keyframes } from "../stitches.config";

const Button = styled("button", {
  all: "unset",
  background: "$crimson3",
  fontFamily: "Work Sans, sans serif",
  color: "$crimson11",
  padding: "18px 24px",
  borderRadius: "1px",
  fontSize: "$3",
  cursor: "pointer",
  boxShadow:
    "0px 4px 8px rgba(0, 0, 0, 0.04), 0px 0px 2px rgba(0, 0, 0, 0.06), 0px 0px 1px rgba(0, 0, 0, 0.04)",

  "&:hover": {
    background: "$crimson4",
  },

  "&:focus": {
    boxShadow: "0px 0px 2px 0px $crimson11",
  },

  '&:disabled': {
    background: '$crimson2',
    color: '$crimson6',
    cursor: 'wait'
  }
});

export const Loading = () => {
  const skBouncedelay = keyframes({
    "0%, 80%, 100%": {
      transform: "scale(0)",
    },
    "40%": {
      transform: "scale(1.0)",
    },
  });
  const Spinner = styled("div", {
    textAlign: "center",
    margin: '0 $3',

    "& > div": {
      width: " 8px",
      height: "8px",
      backgroundColor: "$crimson11",
      marginLeft: '4px',

      borderRadius: "100%",
      display: "inline-block",
      animation: `${skBouncedelay} 1.4s infinite ease-in-out both`,
    },

    "div:nth-child(1)": {
      animationDelay: "-0.32s",
    },

    "div:nth-child(2)": {
      animationDelay: "-0.16s",
    },
  });

  return (
    <Spinner>
      {[...Array(3).keys()].map((i) => (
        <div key={i} />
      ))}
    </Spinner>
  );
};

export default Button;


================================================
FILE: components/Footer.tsx
================================================
import { styled } from "../stitches.config";
import type { Tmeta } from "../types";

const Wrapper = styled("footer", {
  padding: "$4",
});

const Footer: React.FunctionComponent<Tmeta> = ({ name, contact }) => {
  return (
    <Wrapper>
      <strong>{name}</strong>
      <p>{contact}</p>
    </Wrapper>
  );
};

export default Footer;


================================================
FILE: components/Layout.tsx
================================================
import { styled, Box } from "../stitches.config";

const LayoutWrapper = styled("div", {
  background: "$mauve1",

  "@small": {
    padding: "10% 10%",
  },

  "@medium": {
    padding: "10% 15%",
  },

  "@large": {
    padding: "5% 20%",
  },
});

const PageWrapper = styled("div", {
  margin: "0 $4",
  borderLeft: "1px solid $mauve4",
  borderRight: "1px solid $mauve4",
});

const Layout: React.FunctionComponent = ({ children }) => {
  return (
    <LayoutWrapper>
      <Box
        css={{
          height: "$4",
        }}
      >
        <Box
          css={{
            margin: "0 $4",
            height: "$4",
            borderLeft: "1px solid $mauve4",
            borderRight: "1px solid $mauve4",
          }}
        />
      </Box>
      <PageWrapper>{children}</PageWrapper>
    </LayoutWrapper>
  );
};

export default Layout;


================================================
FILE: components/MenuBar.tsx
================================================
import Link from "next/link";
import { styled, keyframes, Box } from "../stitches.config";
import { useCart } from "../lib/cart";
import {
  HomeIcon,
  ArchiveIcon,
  GearIcon,
  SunIcon,
  MoonIcon,
} from "@modulz/radix-icons";
import * as Popover from "@radix-ui/react-popover";
import * as Switch from "@radix-ui/react-switch";
import { useTheme } from "next-themes";
import { useEffect, useRef, useState } from "react";

const scaleUp = keyframes({
  "0%": { transform: "scale(1)", background: "$crimson10" },
  "50%": { transform: "scale(1.5)" },
  "100%": { transform: "scale(1)" },
});

const Wrapper = styled("div", {
  paddingLeft: "$4",
  marginLeft: "-$4",
  paddingRight: "$4",
  marginRight: "-$4",
  borderBottom: "1px solid $mauve4",
  borderTop: "1px solid $mauve4",
});

const MenuBarBox = styled("div", {
  display: "flex",
  justifyContent: "space-between",
  alignItems: "center",
  boxShadow:
    "0px 10px 20px rgba(0, 0, 0, 0.04), 0px 2px 6px rgba(0, 0, 0, 0.04), 0px 0px 1px rgba(0, 0, 0, 0.04)",
  background: "$mauve1",

  "&>svg": {
    cursor: "pointer",
    color: "$mauve11",
  },
});

const CartSizeIcon = styled("div", {
  position: "absolute",
  bottom: "-4px",
  right: "-8px",
  background: "$crimson1",
  border: "1px solid $mauve5",
  width: "16px",
  height: "16px",
  fontSize: "6px",
  borderRadius: "9999px",
  display: "grid",
  placeContent: "center",

  variants: {
    animate: {
      true: {
        animation: `${scaleUp} 200ms`,
      },
      false: {},
    },
  },

  defaultVariants: {
    animate: false,
  },
});

const Item = styled("div", {
  flex: 1,
  display: "grid",
  placeContent: "center",
  padding: "$4",
  cursor: "pointer",

  "&:hover": {
    background: "$mauve2",
  },

  "&:focus, &:active": {
    boxShadow: "0px 0px 2px 0px $mauve10",
  },
});

const StyledContent = styled(Popover.Content, {
  borderRadius: 1,
  padding: "20px",
  fontSize: 14,
  backgroundColor: "$mauve1",
  border: "1px solid $mauve4",
  color: "black",
});

const StyledTrigger = styled(Popover.Trigger, {
  all: "unset",
});

const StyledSwitch = styled(Switch.Root, {
  all: "unset",
  width: 42,
  height: 25,
  backgroundColor: "$crimson8",
  borderRadius: "9999px",
  position: "relative",
  WebkitTapHighlightColor: "rgba(0, 0, 0, 0)",
  "&:focus": { boxShadow: `0 0 0 2px $crimson9` },
  '&[data-state="checked"]': { backgroundColor: "$crimson9" },
});

const StyledThumb = styled(Switch.Thumb, {
  display: "grid",
  placeContent: "center",
  width: 21,
  height: 21,
  backgroundColor: "$crimson4",
  color: "$crimson11",
  borderRadius: "9999px",
  transition: "transform 100ms",
  transform: "translateX(2px)",
  willChange: "transform",
  '&[data-state="checked"]': { transform: "translateX(19px)" },
});

const Flex = styled("div", { display: "flex" });
const Label = styled("label", {
  color: "$crimson12",
  fontSize: 15,
  lineHeight: 1,
  userSelect: "none",
});

const MenuBar: React.FunctionComponent = () => {
  const { cart } = useCart();
  const { theme, setTheme } = useTheme();
  const [animate, setAnimate] = useState(false);

  return (
    <Wrapper>
      <Popover.Root>
        <Popover.Anchor>
          <MenuBarBox>
            <Link href="/" passHref>
              <Item as="a" aria-label="Link to Home">
                <HomeIcon />
              </Item>
            </Link>
            <Link href="/cart" passHref>
              <Item as="a" aria-label="Link to Cart">
                <Box css={{ position: "relative" }}>
                  {cart && (
                    <CartSizeIcon
                      animate={animate}
                      onAnimationEnd={() => setAnimate(false)}
                    >
                      {cart.length}
                    </CartSizeIcon>
                  )}
                  <ArchiveIcon />
                </Box>
              </Item>
            </Link>
            <Item>
              <StyledTrigger aria-label="Settings">
                <GearIcon />
              </StyledTrigger>
            </Item>
          </MenuBarBox>
          <StyledContent side="top">
            <Flex css={{ alignItems: "center" }}>
              <Label htmlFor="s1" css={{ paddingRight: 15 }}>
                Theme
              </Label>
              <StyledSwitch
                id="s1"
                onClick={() => setTheme(theme === "light" ? "dark" : "light")}
                aria-label="Theme switch"
              >
                <StyledThumb>
                  {theme === "light" ? <SunIcon /> : <MoonIcon />}
                </StyledThumb>
              </StyledSwitch>
            </Flex>
            {/* <Popover.Close /> */}
            {/* <Popover.Arrow /> */}
          </StyledContent>
        </Popover.Anchor>
      </Popover.Root>
    </Wrapper>
  );
};

export default MenuBar;


================================================
FILE: components/PageHeadline.tsx
================================================
import { styled, Box } from "../stitches.config";

const Headline = styled("h1", {
  all: "unset",
  color: "$crimson12",
  fontSize: "36px",
  lineHeight: "34px",
  fontFamily: "Work Sans, sans serif",
});

const PageHeadline: React.FunctionComponent = ({ children }) => (
  <Box
    css={{
      borderBottom: "1px solid $mauve4",
      paddingLeft: "$4",
      marginLeft: "-$4",
      paddingRight: "$4",
      marginRight: "-$4",
      marginBottom: "$4",
      paddingTop: "$4",
      paddingBottom: "$4",
    }}
  >
    <Headline>{children}</Headline>
  </Box>
);

export default PageHeadline;


================================================
FILE: components/ProductCard.tsx
================================================
import Link from "next/link";
import Image from "next/image";
import { styled, Box } from "../stitches.config";
import { Prisma } from "@prisma/client";
import { currencyCodeToSymbol } from "../lib/stripeHelpers";

import PlaceholderImage from "../public/placeholder.png";

const Wrapper = styled("div", {
  display: "flex",
  background: "$crimson1",
  cursor: "pointer",

  a: {
    flex: 1,
  },
});

const ProductName = styled("div", {
  fontFamily: "Work Sans, sans serif",
  color: "$crimson12",
  fontSize: "22px",
});

const ProductPrice = styled("div", {
  display: "grid",
  placeContent: "center",
});

const ProductBrand = styled("div", {
  color: "$crimson11",
  fontSize: '12px',
});

const ImageContainer = styled("div", {
  position: "relative",
  height: "240px",
  width: "100%",
});

const AnimatedImage = styled(Image, {
  transition: ".3s",
});

const ProductCard: React.FunctionComponent<{
  product: Required<
    Prisma.ProductUncheckedCreateInput & {
      brand: Prisma.BrandUncheckedCreateInput;
    }
  >;
  images?: {
    id: number;
    images: { paths: string[]; blurDataURLs: string[] };
  };
}> = ({ product, images }) => {
  return (
    <Wrapper>
      <Link href={`/products/${product.slug}`} passHref>
        <a>
          <ImageContainer>
            {images ? (
              <AnimatedImage
                src={images.images.paths[0]}
                layout="fill"
                objectFit="cover"
                alt={images.images.paths[0]}
                placeholder="blur"
                blurDataURL={images.images.blurDataURLs[0]}
              />
            ) : (
              <Image
                src={PlaceholderImage}
                layout="fill"
                objectFit="cover"
                alt="placeholder"
              />
            )}
          </ImageContainer>
          <Box
            css={{
              display: "flex",
              justifyContent: "space-between",
              paddingTop: "$1",
              paddingBottom: "$1",
              paddingLeft: "$4",
              marginLeft: "-$4",
              paddingRight: "$4",
              marginRight: "-$4",
              borderBottom: "1px solid $mauve4",
              borderTop: "1px solid $mauve4",
            }}
          >
            <div>
              <ProductBrand>{product.brand.name}</ProductBrand>
              <ProductName>{product.name}</ProductName>
            </div>
            <ProductPrice>
              {currencyCodeToSymbol(product.currency)} {product.price / 100}
            </ProductPrice>
          </Box>
        </a>
      </Link>
    </Wrapper>
  );
};

export default ProductCard;


================================================
FILE: components/ProductCardCart.tsx
================================================
import Link from "next/link";
import Image from "next/image";
import { styled, Box } from "../stitches.config";
import { Prisma } from "@prisma/client";
import { useCart } from "../lib/cart";
import { currencyCodeToSymbol } from "../lib/stripeHelpers";
import PlaceholderImage from "../public/placeholder.png";

import type { CartItem } from "../lib/cart";
import { useEffect, useState, useCallback } from "react";

const Wrapper = styled("div", {
  boxShadow:
    "0px 4px 8px rgba(0, 0, 0, 0.04), 0px 0px 2px rgba(0, 0, 0, 0.06), 0px 0px 1px rgba(0, 0, 0, 0.04)",
  borderRadius: "1px",
  display: "flex",
  background: "$crimson1",
});

const ProductName = styled("strong", {
  all: "unset",
  fontSize: "18px",
  lineHeight: "18px",
  color: "$crimson12",
  fontFamily: "Work Sans, sans-serif",
});

const ProductPrice = styled("div", {
  fontSize: "20px",
  lineHeight: "20px",
  color: "$crimson12",
  fontFamily: "Work Sans, sans-serif",
});

const ProductDescription = styled("p", {
  color: "$mauve10",
  fontSize: "12px",
  padding: 0,
  margin: 0,
});

const CountButton = styled("button", {
  all: "unset",
  width: 30,
  height: 30,
  background: "$mauve3",
  color: "$mauve10",
  borderRadius: "$small",
  display: "inline-grid",
  placeContent: "center",
  cursor: "pointer",

  "&:hover": {
    background: "$mauve4",
  },

  "&:focus": {
    boxShadow: "0px 0px 2px 0px $mauve10",
  },
});

const ImageContainer = styled("a", {
  all: "unset",
  position: "relative",
  height: "130px",
  width: "110px",
  cursor: "pointer",
});

const ProductCardCart: React.FunctionComponent<{
  item: CartItem;
  cart: CartItem[];
}> = ({ item }) => {
  const { cart, dispatch } = useCart();
  const { product, images } = item;

  const count = cart.find((p) => p.product.id === item.product.id)?.count ?? 0;

  const handleAddItem = () => {
    dispatch({
      type: "addItem",
      item: { product: product, images: [...(images ?? [])], count: 1 },
    });
  };

  const handleRemoveItem = () => {
    dispatch({
      type: "removeItem",
      item: { product: product, images: [...(images ?? [])], count: 1 },
    });
  };
  return (
    <Wrapper>
      <Box css={{ display: "flex", flex: 1 }}>
        <Link href={`/products/${product.slug}`} passHref>
          <ImageContainer>
            {images?.length ? (
              <Image
                src={images[0].path}
                layout="fill"
                objectFit="cover"
                alt={images[0].path}
                placeholder="blur"
                blurDataURL={images[0].blurDataURL}
              />
            ) : (
              <Image
                src={PlaceholderImage}
                layout="fill"
                objectFit="cover"
                alt="placeholder"
              />
            )}
          </ImageContainer>
        </Link>
        <Box css={{ padding: "$3", display: "flex", flex: 1 }}>
          <Box
            css={{
              display: "flex",
              flexDirection: "column",
              justifyContent: "space-between",
              marginRight: "$2",
            }}
          >
            <ProductName>{product.name}</ProductName>
            <ProductDescription>
              {product.description.substr(0, 40)}...
            </ProductDescription>
            <ProductPrice>
              {currencyCodeToSymbol(product.currency)} {product.price / 100}
            </ProductPrice>
          </Box>
          <Box
            css={{
              display: "flex",
              flexDirection: "column",
              justifyContent: "space-between",
              alignItems: "center",
            }}
          >
            <CountButton onClick={handleAddItem}>+</CountButton>
            <Box css={{ textAlign: "center" }} data-testid="productCount">
              {count}
            </Box>
            <CountButton onClick={handleRemoveItem}>-</CountButton>
          </Box>
        </Box>
      </Box>
    </Wrapper>
  );
};

export default ProductCardCart;


================================================
FILE: jest.config.js
================================================
module.exports = {
  collectCoverageFrom: [
    "**/*.{js,jsx,ts,tsx}",
    "!**/*.d.ts",
    "!**/node_modules/**",
  ],
  moduleNameMapper: {
    /* Handle CSS imports (with CSS modules)
    https://jestjs.io/docs/webpack#mocking-css-modules */
    // '^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',

    // Handle CSS imports (without CSS modules)
    // '^.+\\.(css|sass|scss)$': '<rootDir>/__mocks__/styleMock.js',

    /* Handle image imports
    https://jestjs.io/docs/webpack#handling-static-assets */
    '^.+\\.(jpg|jpeg|png|gif|webp|svg)$': '<rootDir>/__mocks__/fileMock.js',
  },
  testPathIgnorePatterns: ["<rootDir>/node_modules/", "<rootDir>/.next/"],
  transform: {
    /* Use babel-jest to transpile tests with the next/babel preset
    https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object */
    "^.+\\.(js|jsx|ts|tsx)$": ["babel-jest", { presets: ["next/babel"] }],
  },
  transformIgnorePatterns: [
    "/node_modules/",
    "^.+\\.module\\.(css|sass|scss)$",
  ],
  setupFilesAfterEnv: ['<rootDir>/jest.setup.js']
};


================================================
FILE: jest.setup.js
================================================
import "@testing-library/jest-dom/extend-expect";

jest.mock("next/image", () => ({
  __esModule: true,
  default: (props) => {
    // Use div instead of img tag. Img tag would require props.
    // eslint-disable-next-line jsx-a11y/alt-text, @next/next/no-img-element
    return <div />;
  },
}));


================================================
FILE: lib/cart.tsx
================================================
import { Prisma } from "@prisma/client";
import {
  createContext,
  useReducer,
  FunctionComponent,
  useContext,
} from "react";

export type CartItem = {
  product: Required<Prisma.ProductUncheckedCreateInput>;
  count: number;
  images?: { path: string; blurDataURL: string }[];
};

type CartAction =
  | { type: "removeItem"; item: CartItem }
  | { type: "addItem"; item: CartItem }
  | { type: "clearCart" };
type Dispatch = (action: CartAction) => void;

type CartState = CartItem[] | [];

const CartContext = createContext<
  { cart: CartState; dispatch: Dispatch } | undefined
>(undefined);

const cartReducer = (cart: CartState, action: CartAction) => {
  switch (action.type) {
    case "addItem": {
      // Find the index of the given product
      const foundProductIndex = cart.findIndex(
        (_item) => _item.product.id === action.item.product.id
      );

      // If the product was found, increse the count by 1
      if (foundProductIndex > -1) {
        cart[foundProductIndex].count++;

        // Return a copy of the array, otherwise react won't rerender.
        return [...cart];
      }
      // If the product wasn't found, add it to the cart array
      else {
        return [...cart, { ...action.item, count: 1 }];
      }
    }
    case "removeItem": {
      // Find the index of the given product
      const foundProductIndex = cart.findIndex(
        (_item) => _item.product.id === action.item.product.id
      );

      // If the product has a count > 1, reduce the count by one
      if (foundProductIndex > -1 && cart[foundProductIndex].count > 1) {
        cart[foundProductIndex].count--;
        // Return a copy of the array, otherwise react won't rerender.
        return [...cart];
      }
      // If the product has a count === 1, remove the product from cart
      else {
        cart.splice(foundProductIndex, 1);
        // Return a copy of the array, otherwise react won't rerender.
        return [...cart];
      }
    }
    case "clearCart": {
      return []
    }
    default: {
      throw new Error(`Unhandled action type: ${JSON.stringify(action)}`);
    }
  }
};

const CartProvider: FunctionComponent = ({ children }) => {
  const [cart, dispatch] = useReducer(cartReducer, []);

  const value = { cart, dispatch };

  return <CartContext.Provider value={value}>{children}</CartContext.Provider>;
};

const useCart = () => {
  const context = useContext(CartContext);

  if (context === undefined)
    throw new Error("useCart must be used within CartProvider");

  // Get the total price for all products in cart
  // @ts-ignore
  const productsTotal: number = context.cart.reduce(
    (total: number, item: CartItem) => total + item.product.price * item.count,
    0
  );

  const needsShipping = !!context.cart.filter(
    (item) => item.product.needsShipping
  ).length;

  return { ...context, productsTotal, needsShipping };
};

export { CartProvider, useCart };


================================================
FILE: lib/fetcher.tsx
================================================
export async function fetchGetJSON(url: string) {
  try {
    const data = await fetch(url).then((res) => res.json());
    return data;
  } catch (err) {
    console.error(err);
    throw new Error();
  }
}

export async function fetchPostJSON(url: string, data?: {}) {
  try {
    // Default options are marked with *
    const response = await fetch(url, {
      method: "POST", // *GET, POST, PUT, DELETE, etc.
      mode: "cors", // no-cors, *cors, same-origin
      cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
      credentials: "same-origin", // include, *same-origin, omit
      headers: {
        "Content-Type": "application/json",
        // 'Content-Type': 'application/x-www-form-urlencoded',
      },
      redirect: "follow", // manual, *follow, error
      referrerPolicy: "no-referrer", // no-referrer, *client
      body: JSON.stringify(data || {}), // body data type must match "Content-Type" header
    });
    return await response.json(); // parses JSON response into native JavaScript objects
  } catch (err) {
    console.error(err);
    throw new Error();
  }
}


================================================
FILE: lib/mapToObject.tsx
================================================
export const replacer = (key: any, value: any) => {
  if (value instanceof Map) {
    return {
      dataType: "Map",
      value: Array.from(value.entries()), // or with spread: value: [...value]
    };
  } else {
    return value;
  }
};

export const reviver = (key: any, value: any) => {
  if (typeof value === "object" && value !== null) {
    if (value.dataType === "Map") {
      return new Map(value.value);
    }
  }
  return value;
};


================================================
FILE: lib/stripeHelpers.tsx
================================================
import { Prisma } from "@prisma/client";
import type { CartItem } from "./cart";

export const cartItemToLineItem = ({
  cartItem,
  images,
}: {
  cartItem: CartItem;
  images: string[];
}) => {
  return {
    price_data: {
      currency: cartItem.product.currency, //ISO Code https://www.six-group.com/dam/download/financial-information/data-center/iso-currrency/amendments/lists/list_one.xml
      unit_amount_decimal: cartItem.product.price,
      product_data: {
        name: cartItem.product.name,
        description: cartItem.product.description,
        images: ["urlToImage"],
        // meta: { key: "value" },
        // tax_code: "dqwd", // https://stripe.com/docs/tax/tax-codes
      },
    },
    adjustable_quantity: {
      enabled: true,
    },
    // dynamic_tax_rates
    quantity: cartItem.count,
  };
};

/**
 * This is a singleton to ensure we only instantiate Stripe once.
 * Use @stripe/stripe-js/pure to delay loading of Stripe.js until Checkout.
 */
import { loadStripe } from "@stripe/stripe-js/pure";
import type { Stripe } from "@stripe/stripe-js";

let stripePromise: Promise<Stripe | null>;
export const getStripe = () => {
  if (!stripePromise) {
    stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!);
  }
  return stripePromise;
};

const currencies = new Map([
  ["usd", "$"],
  ["eur", "€"],
]);

export const currencyCodeToSymbol = (currencyCode: string) => {
  return currencies.get(currencyCode);
};


================================================
FILE: license.md
================================================
MIT License

Copyright (c) 2021 zeekrey

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.

================================================
FILE: next-env.d.ts
================================================
/// <reference types="next" />
/// <reference types="next/types/global" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.


================================================
FILE: next.config.js
================================================
/** @type {import('next').NextConfig} */
module.exports = {
  reactStrictMode: true,
  serverRuntimeConfig: {
    PROJECT_ROOT: __dirname,
  },
  swcMinify: true,
};


================================================
FILE: package.json
================================================
{
  "name": "my-app",
  "version": "0.2.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "test": "jest",
    "release:patch": "release patch",
    "release:minor": "release minor",
    "release:major": "release major",
    "gh:release": "gh release create"
  },
  "dependencies": {
    "@modulz/radix-icons": "^4.0.0",
    "@prisma/client": "^3.4.1",
    "@radix-ui/colors": "^0.1.7",
    "@radix-ui/react-popover": "^0.1.1",
    "@radix-ui/react-radio-group": "^0.1.1",
    "@radix-ui/react-switch": "^0.1.1",
    "@stitches/react": "^1.2.5",
    "@stripe/stripe-js": "^1.21.1",
    "blurhash": "^1.1.4",
    "next": "12.0.3",
    "next-seo": "^4.28.1",
    "next-themes": "^0.0.15",
    "plaiceholder": "^2.2.0",
    "react": "17.0.2",
    "react-dom": "17.0.2",
    "sharp": "^0.29.2",
    "stripe": "^8.186.1",
    "swr": "^1.0.1"
  },
  "devDependencies": {
    "@testing-library/jest-dom": "^5.15.0",
    "@testing-library/react": "^12.1.2",
    "@types/jest": "^27.0.2",
    "@types/react": "17.0.34",
    "babel-jest": "^27.3.1",
    "eslint": "7.32.0",
    "eslint-config-next": "12.0.3",
    "eslint-config-prettier": "^8.3.0",
    "jest": "^27.3.1",
    "prettier": "2.4.1",
    "prisma": "^3.4.1",
    "react-test-renderer": "^17.0.2",
    "release": "^6.3.0",
    "ts-node": "^10.4.0",
    "typescript": "4.4.4"
  },
  "prisma": {
    "seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
  }
}


================================================
FILE: pages/_app.tsx
================================================
import type { NextPage } from "next";
import type { AppProps } from "next/app";
import { globalStyles, darkTheme } from "../stitches.config";
import { ThemeProvider } from "next-themes";
import { IdProvider } from "@radix-ui/react-id";
import { CartProvider } from "../lib/cart";

type NextPageWithLayout = NextPage & {
  layout: React.FunctionComponent;
};

type AppPropsWithLayout = AppProps & {
  Component: NextPageWithLayout;
};

function MyApp({ Component, pageProps }: AppPropsWithLayout) {
  const PageLayout = Component.layout ?? (({ children }) => children);
  globalStyles();
  return (
    <IdProvider>
      <ThemeProvider
        attribute="class"
        defaultTheme="light"
        value={{
          dark: darkTheme.className,
          light: "light",
        }}
      >
        <CartProvider>
          <PageLayout>
            <Component {...pageProps} />
          </PageLayout>
        </CartProvider>
      </ThemeProvider>
    </IdProvider>
  );
}
export default MyApp;


================================================
FILE: pages/_document.tsx
================================================
// eslint-disable-next-line @next/next/no-document-import-in-page
import Document, { Html, Head, Main, NextScript } from "next/document";
import { getCssText } from "../stitches.config";

class MyDocument extends Document {
  render() {
    return (
      <Html lang="en">
        <Head>
          <link
            href="https://fonts.googleapis.com/css2?family=Roboto:wght@300&family=Work+Sans:wght@600&display=swap"
            rel="stylesheet"
          />
          <style
            id="stitches"
            dangerouslySetInnerHTML={{ __html: getCssText() }}
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;


================================================
FILE: pages/api/checkout_sessions/[id].ts
================================================
import { NextApiRequest, NextApiResponse } from "next";
import Stripe from "stripe";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: "2020-08-27",
});

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const id: string = req.query.id as string;
  try {
    if (!id.startsWith("cs_")) {
      throw Error("Incorrect CheckoutSession ID.");
    }
    const checkout_session: Stripe.Checkout.Session =
      await stripe.checkout.sessions.retrieve(id, {
        expand: ["payment_intent"],
      });

    res.status(200).json(checkout_session);
  } catch (err) {
    console.error(err);
    res.status(500).json({ statusCode: 500, message: "Something went wrong!" });
  }
}


================================================
FILE: pages/api/checkout_sessions/index.ts
================================================
import type { NextApiRequest, NextApiResponse } from "next";

const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);

type ResponseData = {
  name: string;
};

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<ResponseData>
) {
  if (req.method === "POST") {
    const { line_items } = req.body;

    try {
      const session = await stripe.checkout.sessions.create({
        line_items,
        payment_method_types: ["card"],
        mode: "payment",
        billing_address_collection: "required",
        shipping_address_collection: {
          allowed_countries: ["DE", "US"],
        },
        success_url: `${req.headers.origin}/confirmation/?success=true&session_id={CHECKOUT_SESSION_ID}`,
        cancel_url: `${req.headers.origin}/?canceled=true`,
      });

      res.status(200).json(session);
    } catch (err) {
      console.error("Something went wront during Stripe session creation.");
      console.error(err);
      res.status(500).end();
    }
  } else {
    res.setHeader("Allow", "POST");
    res.status(405).end("Method Not Allowed");
  }
}


================================================
FILE: pages/api/products/index.ts
================================================
import { NextApiRequest, NextApiResponse } from "next";
import { PrismaClient } from "@prisma/client";
import { getPlaiceholder } from "plaiceholder";
import path from "path";
import getConfig from "next/config";

import { promises as fs } from "fs";

const prisma = new PrismaClient({
  datasources: {
    db: {
      url: `file:${path.join(
        getConfig().serverRuntimeConfig.PROJECT_ROOT,
        "products.db"
      )}`,
    },
  },
});

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method === "GET") {
    const page = (req.query.page as string) || "0";

    const pageSize = 6;

    const results = await prisma.product.findMany({
      where: {
        availability: {
          not: "notVisible",
        },
      },
      include: {
        brand: true,
      },
      skip: pageSize * parseInt(page),
      take: pageSize,
    });

    let allImagePaths = [];

    for (const product of results) {
      const imagesDirectory = path.join(
        process.cwd(),
        `public/products/${product.id}`
      );

      try {
        const productImagePaths = await fs.readdir(imagesDirectory);

        const blurDataURLs = await Promise.all(
          productImagePaths.map(async (src) => {
            const { base64 } = await getPlaiceholder(
              `/products/${product.id}/${src}`
            );
            return base64;
          })
        ).then((values) => values);

        allImagePaths.push({
          id: product.id,
          images: {
            paths: productImagePaths.map(
              (path) => `/products/${product.id}/${path}`
            ),
            blurDataURLs: blurDataURLs,
          },
        });
      } catch (error) {
        console.warn(
          `Image ${product.name} has no images under /public/product/[id]!`
        );
      }
    }
    res.status(200).json(
      JSON.stringify({
        products: results.map((product) => ({
          ...product,
          // Date objects needs to be converted to strings because the props object will be serialized as JSON
          createdAt: product.createdAt.toString(),
          updatedAt: product.updatedAt.toString(),
        })),
        images: await Promise.all(allImagePaths),
      })
    );
  } else {
    // 501 Not Implemented
    res.status(501).end();
  }
}


================================================
FILE: pages/cart.tsx
================================================
import Button, { Loading } from "../components/Button";
import { styled, Box } from "../stitches.config";
import { PrismaClient, Prisma } from "@prisma/client";
import { useCart } from "../lib/cart";
import { currencyCodeToSymbol } from "../lib/stripeHelpers";
import ProductCardCart from "../components/ProductCardCart";
import { getStripe, cartItemToLineItem } from "../lib/stripeHelpers";
import Layout from "../components/Layout";
import PageHeadline from "../components/PageHeadline";
import Footer from "../components/Footer";
import { GetStaticProps, NextPage } from "next";
import { Tmeta } from "../types";
import MenuBar from "../components/MenuBar";
import { NextSeo } from "next-seo";
import { useEffect, useState } from "react";
import * as RadioGroup from "@radix-ui/react-radio-group";

const prisma = new PrismaClient();

export const getStaticProps: GetStaticProps = async () => {
  /**
   * Get shop meta data from env
   */

  const allShippingOptions = await prisma.shippingCode.findMany({});

  const {
    headline = "Teini is the most smallest shop ever",
    subheadline = "It gets you starting. Without budget. Without the ecommerce complexity you normally see.",
    contact = "Twitter: @zeekrey",
    name = "Teini",
  } = process.env;

  /**
   * Get all shipping options
   */

  return {
    props: {
      meta: {
        headline,
        subheadline,
        contact,
        name,
      },
      shippingOptions: allShippingOptions,
    },
  };
};

const ProductList = styled("div", {
  paddingBottom: "$4",
  display: "grid",
  gap: "$4",

  "@small": {
    gridTemplateColumns: "repeat(2, 1fr)",
  },

  "@medium": {
    gap: "$5",
  },

  "@large": {
    gap: "40px",
  },
});

const ShippingOptionRadioGroup = styled(RadioGroup.Root, {
  display: "flex",
  flexDirection: "column",
});

const ShippingOption = styled(RadioGroup.Item, {
  all: "unset",
  display: "flex",
  background: "$crimson1",
  flex: 1,
  padding: "$2",
  cursor: "pointer",
  alignItems: "center",

  transition: "all 0.2s",

  "&:hover": {
    background: "$crimson2",
  },

  color: "$mauve10",

  "&[data-state='checked']": {
    color: "$mauve12",
  },
});

const ProductPrice = styled("div", {
  fontSize: "20px",
  lineHeight: "20px",
  fontFamily: "Work Sans, sans-serif",
});

const ShippingOptionIndicator = styled(RadioGroup.Indicator, {
  display: "grid",
  fontSize: "$1",
  fontFamily: "Work Sans",
  borderRadius: "$small",
  background: "$mauve5",
  color: "$mauve12",
  placeContent: "center",
  padding: "$1 $2",
  marginRight: "$2",
});

const CartPage: NextPage<{
  meta: Tmeta;
  shippingOptions: Required<Prisma.ShippingCodeUncheckedCreateInput>[];
}> = ({ meta, shippingOptions }) => {
  const { cart, productsTotal, needsShipping } = useCart();
  const [isLoading, setIsLoading] = useState(false);
  const [shippingOption, setShippingOption] = useState<
    undefined | false | Required<Prisma.ShippingCodeUncheckedCreateInput>
  >(undefined);
  const [total, setTotal] = useState(productsTotal);

  useEffect(() => {
    if (shippingOption) setTotal(productsTotal + shippingOption.price);
  }, [shippingOption, productsTotal]);

  const calcShipping = (value: string) => {
    // Get the whole shippingOption object for the provided value
    const selectedShippingOption = shippingOptions.find(
      (shippingOption) => shippingOption.name === value
    );

    // If the cart sum is bigger than 'isFreeFrom' set the shipping costs to 0, otherwise set the shipping costs.
    if (productsTotal >= selectedShippingOption!.isFreeFrom)
      setShippingOption({ ...selectedShippingOption!, price: 0 });
    else setShippingOption(selectedShippingOption!);
  };

  const handleCheckout = async () => {
    setIsLoading(true);
    const stripe = await getStripe();
    const lineItems = [...cart.values()].map((item) =>
      cartItemToLineItem({ cartItem: item, images: [""] })
    );

    // Create a line item for shipping costs if they exist
    const lineItemsWithShipping = shippingOption
      ? [
          {
            price_data: {
              currency: "usd",
              unit_amount_decimal: shippingOption?.price,
              product_data: {
                name: shippingOption?.name,
              },
            },
            quantity: 1,
          },
          ...lineItems,
        ]
      : lineItems;

    const response = await fetch("/api/checkout_sessions", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        line_items: lineItemsWithShipping,
      }),
    });

    const session = await response.json();

    const { error } = await stripe!.redirectToCheckout({
      sessionId: session.id,
    });
    error && console.warn(error.message);
  };

  return (
    <>
      <NextSeo noindex={true} />
      <MenuBar />
      <PageHeadline>Cart</PageHeadline>
      <Box
        as="p"
        css={{
          color: "$crimson11",
          fontSize: "16px",
        }}
      >
        To protect you and us the checkout will be processed by Stripe.
      </Box>
      <>
        {cart.length ? (
          <>
            <ProductList>
              {cart.map((item) => (
                <ProductCardCart
                  key={item.product.id}
                  item={item}
                  cart={cart}
                />
              ))}
            </ProductList>
            {needsShipping && (
              <div>
                <Box
                  as="p"
                  css={{
                    color: "$crimson11",
                  }}
                >
                  Shipping:
                </Box>
                <ShippingOptionRadioGroup
                  onValueChange={(value) => calcShipping(value)}
                >
                  {shippingOptions.map((shippingOption) => (
                    <ShippingOption
                      key={shippingOption.id}
                      id={shippingOption.name}
                      value={shippingOption.name}
                    >
                      <Box
                        as="label"
                        css={{ flex: 1, cursor: "pointer" }}
                        htmlFor={shippingOption.name}
                      >
                        <Box as="strong" css={{ fontFamily: "Work Sans" }}>
                          {shippingOption.name}{" "}
                        </Box>
                        <Box as="small" css={{ display: "block" }}>
                          {shippingOption.description}
                        </Box>
                      </Box>
                      <ShippingOptionIndicator>
                        SELECTED
                      </ShippingOptionIndicator>
                      <ProductPrice>
                        {productsTotal >= shippingOption.isFreeFrom
                          ? "$ 0.00"
                          : `$ ${shippingOption.price / 100}`}
                      </ProductPrice>
                    </ShippingOption>
                  ))}
                </ShippingOptionRadioGroup>
              </div>
            )}
            <Box
              css={{
                display: "flex",
                justifyContent: "space-between",
                paddingLeft: "$4",
                marginLeft: "-$4",
                paddingRight: "$4",
                marginRight: "-$4",
                borderBottom: "1px solid $mauve4",
                borderTop: "1px solid $mauve4",
              }}
            >
              <div>
                <Box
                  css={{
                    color: "$crimson11",
                  }}
                >
                  Total:
                  {/* Get the currency code of the first item for now. */}
                </Box>
                <Box
                  css={{
                    fontFamily: "Work Sans, sans serif",
                    color: "$crimson12",
                    fontSize: "22px",
                  }}
                >
                  {currencyCodeToSymbol(cart[0].product.currency)} {total / 100}
                </Box>
              </div>
              <Button
                disabled={isLoading || typeof shippingOption === "undefined"}
                onClick={handleCheckout}
              >
                {isLoading ? <Loading /> : "Buy now"}
              </Button>
            </Box>
          </>
        ) : (
          <div>Go and add some items to your cart!</div>
        )}
      </>
      <Footer {...meta} />
    </>
  );
};

// @ts-ignore
CartPage.layout = Layout;

export default CartPage;


================================================
FILE: pages/confirmation.tsx
================================================
import { styled, Box } from "../stitches.config";
import useSWR from "swr";
import { useRouter } from "next/router";
import { fetchGetJSON } from "../lib/fetcher";
import { useEffect } from "react";
import { NextSeo } from "next-seo";
import { GetStaticProps, NextPage } from "next";
import Image from "next/image";
import MenuBar from "../components/MenuBar";
import { useCart } from "../lib/cart";
import { Tmeta } from "../types";
import Footer from "../components/Footer";
import SuccessImage from "../public/jason-dent-WNVGLwGMCAg-unsplash.jpg";
import PageHeadline from "../components/PageHeadline";

const ImageContainer = styled("div", {
  height: "54vh",
  position: "relative",
  marginLeft: "calc($4*-1)",
  marginRight: "calc($4*-1)",
  marginTop: "calc($4*-1)",

  transition: "1s",
});

const ProductName = styled("h1", {
  all: "unset",
  fontSize: "$4",
  lineHeight: "30px",
  color: "$crimson12",
  fontFamily: "Work Sans, sans-serif",
});

const ProductPrice = styled("div", {
  fontSize: "$4",
  color: "$mauve12",
  fontFamily: "Work Sans, sans-serif",
  display: "grid",
  placeContent: "center",
});

const ProductBrand = styled("div", {
  color: "$mauve8",
  paddingTop: "$4",
});

const ProductDescription = styled("p", {
  color: "$crimson11",
  fontSize: "16px",
  lineHeight: "24px",
});

const AnimatedImage = styled(Image, {
  transition: ".3s",
});

const LayoutWrapper = styled("div", {
  background: "$mauve1",
  padding: "$4",

  "@small": {
    padding: "10% 10%",
  },

  "@medium": {
    padding: "10% 15%",
  },

  "@large": {
    padding: "5% 25%",
  },
});

const Subheadline = styled("h1", {
  fontFamily: "Roboto, sans serif",
  fontSize: "18px",
  fontWeight: "normal",
  color: "$mauve9",
});

export const getStaticProps: GetStaticProps = async ({ params }) => {
  /**
   * Get shop meta data from env
   */

  const {
    headline = "Teini is the most smallest shop ever",
    subheadline = "It gets you starting. Without budget. Without the ecommerce complexity you normally see.",
    contact = "Twitter: @zeekrey",
    name = "Teini",
  } = process.env;

  return {
    props: {
      meta: {
        headline,
        subheadline,
        contact,
        name,
      },
    },
  };
};

const Confirmation: NextPage<{ meta: Tmeta }> = ({ meta }) => {
  const { dispatch } = useCart();
  const router = useRouter();

  const { data, error } = useSWR(
    router.query.session_id
      ? `/api/checkout_sessions/${router.query.session_id}`
      : null,
    fetchGetJSON
  );

  useEffect(() => {
    // If checkout is completed, the cart should be cleared.
    dispatch({ type: "clearCart" });
  }, []);

  /**
   * Data for buyer
   * data.payment_intent.charges.data[0].billing_details.email
   * data.payment_intent.charges.data[0].billing_details.name
   *
   */

  /**
   * Data for seller
   * data.payment_intent
   */

  return (
    <LayoutWrapper>
      <NextSeo noindex={true} />
      <ImageContainer>
        <Image
          src={SuccessImage}
          layout="fill"
          objectFit="cover"
          alt="success image"
          placeholder="blur"
        />
      </ImageContainer>
      <Box as="main" css={{ paddingBottom: "$3" }}>
        <PageHeadline>
          {error && <span>Your payment could not be verified.</span>}
          {data && <span>Awesome! That worked!</span>}
        </PageHeadline>
        {data && (
          <Subheadline>
            This is your order reference:{" "}
            <strong>{data.payment_intent.id}</strong>
          </Subheadline>
        )}
      </Box>
      <MenuBar />
      <Footer {...meta} />
    </LayoutWrapper>
  );
};

// @ts-ignore
// Confirmation.layout = Layout;

export default Confirmation;


================================================
FILE: pages/index.tsx
================================================
import { GetStaticProps } from "next";
import Link from "next/link";
import { PrismaClient, Prisma } from "@prisma/client";
import Layout from "../components/Layout";
import { styled, Box } from "../stitches.config";
import ProductCard from "../components/ProductCard";
import MenuBar from "../components/MenuBar";
import Button from "../components/Button";
import { promises as fs } from "fs";
import path from "path";
import { ArrowRightIcon } from "@modulz/radix-icons";
import PageHeadline from "../components/PageHeadline";
import type { Tmeta } from "../types";
import Footer from "../components/Footer";
import { NextSeo } from "next-seo";
import { getPlaiceholder } from "plaiceholder";

const prisma = new PrismaClient();

export const getStaticProps: GetStaticProps = async ({ params }) => {
  /**
   * Get shop meta data from env
   */

  const {
    headline = "Teini is the most smallest shop ever",
    subheadline = "It gets you starting. Without budget. Without the ecommerce complexity you normally see.",
    contact = "Twitter: @zeekrey",
    name = "Teini",
  } = process.env;

  /**
   * Get all products with
   * availability !== notVisible
   */
  const allVisibleProducts = await prisma.product.findMany({
    where: {
      availability: {
        not: "notVisible",
      },
    },
    include: {
      brand: true,
    },
  });

  /**
   * Get all images forthose products that are place under /public/products/[id]
   */

  if (allVisibleProducts) {
    let allImagePaths = [];

    for (const product of allVisibleProducts) {
      const imagesDirectory = path.join(
        process.cwd(),
        `public/products/${product.id}`
      );

      try {
        const productImagePaths = await fs.readdir(imagesDirectory);

        const blurDataURLs = await Promise.all(
          productImagePaths.map(async (src) => {
            const { base64 } = await getPlaiceholder(
              `/products/${product.id}/${src}`
            );
            return base64;
          })
        ).then((values) => values);

        allImagePaths.push({
          id: product.id,
          images: {
            paths: productImagePaths.map(
              (path) => `/products/${product.id}/${path}`
            ),
            blurDataURLs: blurDataURLs,
          },
        });
      } catch (error) {
        console.warn(
          `Image ${product.name} has no images under /public/product/[id]!`
        );
      }
    }

    return {
      props: {
        products: allVisibleProducts.map((product) => ({
          ...product,
          // Date objects needs to be converted to strings because the props object will be serialized as JSON
          createdAt: product.createdAt.toString(),
          updatedAt: product.updatedAt.toString(),
        })),
        images: await Promise.all(allImagePaths),
        meta: {
          headline,
          subheadline,
          contact,
          name,
        },
      },
    };
  } else return { props: {} };
};

const Grid = styled("div", {
  display: "grid",
  gap: "$4",

  "@small": {
    gridTemplateColumns: "repeat(2, 1fr)",
  },

  "@medium": {
    gridTemplateColumns: "repeat(3, 1fr)",
    gap: "$5",
  },

  "@large": {
    gap: "40px",
  },
});

const Home: React.FunctionComponent<{
  products: Required<
    Prisma.ProductUncheckedCreateInput & {
      brand: Prisma.BrandUncheckedCreateInput;
    }
  >[];
  images: {
    id: number;
    images: { paths: string[]; blurDataURLs: string[] };
  }[];
  meta: Tmeta;
}> = ({ products, images, meta }) => {
  return (
    <>
      <NextSeo
        title={meta.headline}
        description={meta.subheadline}
        openGraph={{
          type: "website",
          title: meta.headline,
          description: meta.subheadline,
          site_name: meta.name,
        }}
      />
      <MenuBar />
      <PageHeadline>{meta.headline}</PageHeadline>
      <Box
        as="p"
        css={{
          color: "$crimson11",
          fontSize: "16px",
          paddingBottom: "$4",
          margin: 0,
        }}
      >
        {meta.subheadline}
      </Box>
      <Grid>
        {products.map((product) => (
          <ProductCard
            key={product.id}
            product={product}
            images={images.filter((image) => image.id === product.id)[0]}
          />
        ))}
      </Grid>
      <Link href="/products" passHref>
        <Button
          as="a"
          css={{
            display: "flex",
            justifyContent: "space-between",
            alignItems: "center",
            margin: "$4 0",
          }}
        >
          <span>See all products</span>
          <ArrowRightIcon />
        </Button>
      </Link>
      <Footer {...meta} />
    </>
  );
};

// @ts-ignore
Home.layout = Layout;

export default Home;


================================================
FILE: pages/products/[slug].tsx
================================================
import { GetStaticPaths, GetStaticProps, NextPage } from "next";
import Image from "next/image";
import { promises as fs } from "fs";
import path from "path";
import { PrismaClient, Prisma } from "@prisma/client";
import Button from "../../components/Button";
import MenuBar from "../../components/MenuBar";
import { styled, Box } from "../../stitches.config";
import { useCart } from "../../lib/cart";
import { currencyCodeToSymbol } from "../../lib/stripeHelpers";
import PlaceholderImage from "../../public/placeholder.png";
import { Tmeta } from "../../types";
import Footer from "../../components/Footer";
import { NextSeo } from "next-seo";
import { getPlaiceholder } from "plaiceholder";

const prisma = new PrismaClient();

export const getStaticPaths: GetStaticPaths = async () => {
  /**
   * Get all products with
   * availability !== notVisible
   */
  const allVisibleProducts = await prisma.product.findMany({
    select: { slug: true },
    where: {
      availability: {
        not: "notVisible",
      },
    },
  });

  return {
    paths: allVisibleProducts.map((product) => ({
      params: {
        slug: product.slug,
      },
    })),
    fallback: false,
  };
};

export const getStaticProps: GetStaticProps = async ({ params }) => {
  /**
   * Get shop meta data from env
   */

  const {
    headline = "Teini is the most smallest shop ever",
    subheadline = "It gets you starting. Without budget. Without the ecommerce complexity you normally see.",
    contact = "Twitter: @zeekrey",
    name = "Teini",
  } = process.env;

  /**
   * Get the first product with
   * params.slug === product.slug
   */
  const product = await prisma.product.findFirst({
    where: {
      slug: {
        equals: params!.slug as string,
      },
    },
    include: {
      brand: true,
    },
  });

  /**
   * Get all images for this product that are place under /public/products/[id]
   */

  if (product) {
    const imagesDirectory = path.join(
      process.cwd(),
      `public/products/${product.id}`
    );

    try {
      const productImagePaths = await fs.readdir(imagesDirectory);

      /**
       * Create blurDataURLs (base64) as image placeholders
       */

      const blurDataURLs = await Promise.all(
        productImagePaths.map(async (src) => {
          const { base64 } = await getPlaiceholder(
            `/products/${product.id}/${src}`
          );
          return base64;
        })
      ).then((values) => values);

      return {
        props: {
          product: {
            ...product,
            // Date objects needs to be converted to strings because the props object will be serialized as JSON
            createdAt: product?.createdAt.toString(),
            updatedAt: product?.updatedAt.toString(),
          },
          images: productImagePaths.map((path, index) => ({
            path: `/products/${product.id}/${path}`,
            blurDataURL: blurDataURLs[index],
          })),
          meta: {
            headline,
            subheadline,
            contact,
            name,
          },
        },
      };
    } catch (error) {
      console.warn(
        `Image ${product.name} has no images under /public/product/[id]!`
      );
      console.error(error);
      return {
        props: {
          product: {
            ...product,
            // Date objects needs to be converted to strings because the props object will be serialized as JSON
            createdAt: product?.createdAt.toString(),
            updatedAt: product?.updatedAt.toString(),
          },
          images: [],
          meta: {
            headline,
            subheadline,
            contact,
            name,
          },
        },
      };
    }
  } else return { props: {} };
};

const ImageContainer = styled("div", {
  height: "54vh",
  position: "relative",
  marginLeft: "calc($4*-1)",
  marginRight: "calc($4*-1)",
  marginTop: "calc($4*-1)",

  transition: "1s",
});

const ProductName = styled("h1", {
  all: "unset",
  fontSize: "$4",
  lineHeight: "30px",
  color: "$crimson12",
  fontFamily: "Work Sans, sans-serif",
});

const ProductPrice = styled("div", {
  fontSize: "$4",
  color: "$mauve12",
  fontFamily: "Work Sans, sans-serif",
  display: "grid",
  placeContent: "center",
});

const ProductBrand = styled("div", {
  color: "$mauve8",
  paddingTop: "$4",
});

const ProductDescription = styled("p", {
  color: "$crimson11",
  fontSize: "16px",
  lineHeight: "24px",
});

const AnimatedImage = styled(Image, {
  transition: ".3s",
});

const LayoutWrapper = styled("div", {
  background: "$mauve1",
  padding: "$4",

  "@small": {
    padding: "10% 10%",
  },

  "@medium": {
    padding: "10% 15%",
  },

  "@large": {
    padding: "5% 25%",
  },
});

const ProductPage: NextPage<{
  product: Required<
    Prisma.ProductUncheckedCreateInput & {
      brand: Prisma.BrandUncheckedCreateInput;
    }
  >;
  images: { path: string; blurDataURL: string }[];
  meta: Tmeta;
}> = ({ product, images, meta }) => {
  const { cart, dispatch } = useCart();

  const handleAddToCart = () => {
    dispatch({
      type: "addItem",
      item: { product: product, images: [...images], count: 1 },
    });
  };

  return (
    <LayoutWrapper>
      <NextSeo
        title={`${product.name} - ${meta.headline}`}
        description={product.description}
        openGraph={{
          type: "website",
          title: `${product.name} - ${meta.headline}`,
          description: product.description,
          site_name: meta.name,
        }}
      />
      <ImageContainer>
        {images.length ? (
          <AnimatedImage
            src={images[0].path}
            layout="fill"
            objectFit="cover"
            alt={images[0].path}
            placeholder="blur"
            blurDataURL={images[0].blurDataURL}
          />
        ) : (
          <Image
            src={PlaceholderImage}
            layout="fill"
            objectFit="cover"
            alt="placeholder"
          />
        )}
      </ImageContainer>
      <Box as="main" css={{ paddingBottom: "$3" }}>
        <ProductBrand>{product.brand.name}</ProductBrand>
        <ProductName>{product.name}</ProductName>
        <ProductDescription>{product.description}</ProductDescription>
        <Box
          css={{
            display: "flex",
            justifyContent: "space-between",
            paddingLeft: "$4",
            marginLeft: "-$4",
            paddingRight: "$4",
            marginRight: "-$4",
            borderBottom: "1px solid $mauve4",
            borderTop: "1px solid $mauve4",
          }}
        >
          <ProductPrice>
            {currencyCodeToSymbol(product.currency)} {product.price / 100}
          </ProductPrice>
          <Button onClick={handleAddToCart}>Add to Cart</Button>
        </Box>
      </Box>
      <MenuBar />
      <Footer {...meta} />
    </LayoutWrapper>
  );
};

export default ProductPage;


================================================
FILE: pages/products/index.tsx
================================================
import { GetStaticProps } from "next";
import { promises as fs } from "fs";
import React, { useState } from "react";
import path from "path";
import { PrismaClient, Prisma } from "@prisma/client";
import Layout from "../../components/Layout";
import { styled, Box } from "../../stitches.config";
import ProductCard from "../../components/ProductCard";
import PageHeadline from "../../components/PageHeadline";
import { Tmeta } from "../../types";
import Footer from "../../components/Footer";
import MenuBar from "../../components/MenuBar";
import { NextSeo } from "next-seo";
import { getPlaiceholder } from "plaiceholder";
import Button from "../../components/Button";
import useSWR, { SWRConfig } from "swr";

const prisma = new PrismaClient();

export const getStaticProps: GetStaticProps = async ({ params }) => {
  /**
   * Get shop meta data from env
   */

  const {
    headline = "Teini is the most smallest shop ever",
    subheadline = "It gets you starting. Without budget. Without the ecommerce complexity you normally see.",
    contact = "Twitter: @zeekrey",
    name = "Teini",
  } = process.env;

  /**
   * Count the number of products to make pagination work
   */
  const {
    _count: { id: count },
  } = await prisma.product.aggregate({
    _count: {
      id: true,
    },
    where: {
      availability: {
        not: "notVisible",
      },
    },
  });

  /**
   * Get all products with
   * availability !== notVisible
   */
  const allVisibleProducts = await prisma.product.findMany({
    where: {
      availability: {
        not: "notVisible",
      },
    },
    include: {
      brand: true,
    },
    take: 6,
  });

  /**
   * Get all images forthose products that are place under /public/products/[id]
   */

  if (allVisibleProducts) {
    let allImagePaths = [];

    for (const product of allVisibleProducts) {
      const imagesDirectory = path.join(
        process.cwd(),
        `public/products/${product.id}`
      );

      try {
        const productImagePaths = await fs.readdir(imagesDirectory);

        const blurDataURLs = await Promise.all(
          productImagePaths.map(async (src) => {
            const { base64 } = await getPlaiceholder(
              `/products/${product.id}/${src}`
            );
            return base64;
          })
        ).then((values) => values);

        allImagePaths.push({
          id: product.id,
          images: {
            paths: productImagePaths.map(
              (path) => `/products/${product.id}/${path}`
            ),
            blurDataURLs: blurDataURLs,
          },
        });
      } catch (error) {
        console.warn(
          `Image ${product.name} has no images under /public/product/[id]!`
        );
      }
    }

    return {
      props: {
        products: allVisibleProducts.map((product) => ({
          ...product,
          // Date objects needs to be converted to strings because the props object will be serialized as JSON
          createdAt: product.createdAt.toString(),
          updatedAt: product.updatedAt.toString(),
        })),
        images: await Promise.all(allImagePaths),
        meta: {
          headline,
          subheadline,
          contact,
          name,
        },
        productsCount: count,
      },
    };
  } else return { props: {} };
};

const Grid = styled("main", {
  paddingBottom: "$4",
  display: "grid",
  gap: "$4",

  "@small": {
    gridTemplateColumns: "repeat(2, 1fr)",
  },

  "@medium": {
    gridTemplateColumns: "repeat(3, 1fr)",
    gap: "$5",
  },

  "@large": {
    gap: "40px",
  },
});

const ProductsGrid: React.FunctionComponent<{ page: number }> = ({ page }) => {
  const { data, error } = useSWR<{
    products: Required<
      Prisma.ProductUncheckedCreateInput & {
        brand: Prisma.BrandUncheckedCreateInput;
      }
    >[];
    images: {
      id: number;
      images: { paths: string[]; blurDataURLs: string[] };
    }[];
  }>(`/api/products?page=${page}`, (url) =>
    fetch(url).then((res) => res.json())
  );

  return (
    <Grid>
      {data?.products.map((product) => (
        <ProductCard
          key={product.id}
          product={product}
          images={data.images.filter((image) => image.id === product.id)[0]}
        />
      ))}
    </Grid>
  );
};

const Products: React.FunctionComponent<{
  products: Required<
    Prisma.ProductUncheckedCreateInput & {
      brand: Prisma.BrandUncheckedCreateInput;
    }
  >[];
  images: { id: number; images: { paths: string[]; blurDataURLs: string[] } }[];
  meta: Tmeta;
  productsCount: number;
}> = ({ products, images, meta, productsCount }) => {
  const [page, setPage] = useState(0);

  return (
    <>
      <NextSeo
        title={meta.headline}
        description={meta.subheadline}
        openGraph={{
          type: "website",
          title: meta.headline,
          description: meta.subheadline,
          site_name: meta.name,
        }}
      />
      <MenuBar />
      <PageHeadline>All Products</PageHeadline>
      <SWRConfig
        value={{ fallback: { "/api/products?page=0": { products, images } } }}
      >
        <ProductsGrid page={page} />
      </SWRConfig>
      <Box css={{ display: "flex", justifyContent: "space-between" }}>
        {page ? (
          <Button onClick={() => setPage(page - 1)}>Previous</Button>
        ) : (
          <Box css={{ flex: 1 }} />
        )}
        {(page + 1) * 6 >= productsCount ? (
          <Box css={{ flex: 1 }} />
        ) : (
          <Button
            css={{ justifySelf: "flex-end" }}
            onClick={() => setPage(page + 1)}
          >
            Next
          </Button>
        )}
      </Box>
      <Footer {...meta} />
    </>
  );
};

// @ts-ignore
Products.layout = Layout;

export default Products;


================================================
FILE: prisma/migrations/20210923095130_init/migration.sql
================================================
-- CreateTable
CREATE TABLE "Product" (
    "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updatedAt" DATETIME NOT NULL,
    "name" TEXT NOT NULL,
    "description" TEXT NOT NULL,
    "price" REAL NOT NULL,
    "availability" TEXT NOT NULL,
    "shippingCodeId" INTEGER NOT NULL,
    "brandId" INTEGER NOT NULL,
    CONSTRAINT "Product_shippingCodeId_fkey" FOREIGN KEY ("shippingCodeId") REFERENCES "ShippingCode" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
    CONSTRAINT "Product_brandId_fkey" FOREIGN KEY ("brandId") REFERENCES "Brand" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);

-- CreateTable
CREATE TABLE "Brand" (
    "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    "name" TEXT NOT NULL
);

-- CreateTable
CREATE TABLE "ShippingCode" (
    "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    "name" TEXT NOT NULL,
    "description" TEXT NOT NULL
);


================================================
FILE: prisma/migrations/migration_lock.toml
================================================
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "sqlite"

================================================
FILE: prisma/schema.prisma
================================================
datasource db {
  provider = "sqlite"
  url      = "file:../products.db"
}

generator client {
  provider = "prisma-client-js"
}

model Product {
  id            Int      @id @default(autoincrement())
  createdAt     DateTime @default(now())
  updatedAt     DateTime @updatedAt
  slug          String
  name          String
  description   String
  price         Int
  currency      String
  availability  String
  brand         Brand    @relation(fields: [brandId], references: [id])
  brandId       Int
  needsShipping Boolean
}

model Brand {
  id       Int       @id @default(autoincrement())
  name     String
  products Product[]
}

model ShippingCode {
  id          Int    @id @default(autoincrement())
  name        String
  description String
  price       Int
  isFreeFrom  Int
}


================================================
FILE: prisma/seed.ts
================================================
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();

async function main() {
  const brand = await prisma.brand.upsert({
    where: { id: 1 },
    update: {},
    create: {
      name: "The Brand",
    },
  });

  const shippingCode1 = await prisma.shippingCode.upsert({
    where: { id: 1 },
    update: {},
    create: {
      name: "Standard Shipping",
      description: "Standard international shipping",
      price: 299,
      isFreeFrom: 1000,
    },
  });

  const shippingCode2 = await prisma.shippingCode.upsert({
    where: { id: 2 },
    update: {},
    create: {
      name: "Express Shipping",
      description: "Express international shipping",
      price: 699,
      isFreeFrom: 10000,
    },
  });

  const product1 = await prisma.product.upsert({
    where: { id: 1 },
    update: {},
    create: {
      slug: "the-first-product",
      name: "The first product",
      description:
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
      price: 299,
      currency: "usd",
      availability: "inStock",
      brandId: 1,
      needsShipping: true,
    },
  });

  const product2 = await prisma.product.upsert({
    where: { id: 2 },
    update: {},
    create: {
      slug: "the-second-product",
      name: "The second product",
      description:
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
      price: 2999,
      currency: "usd",
      availability: "inStock",
      brandId: 1,
      needsShipping: true,
    },
  });

  const product3 = await prisma.product.upsert({
    where: { id: 3 },
    update: {},
    create: {
      slug: "the-third-product",
      name: "The third product",
      description:
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
      price: 29999,
      currency: "usd",
      availability: "inStock",
      brandId: 1,
      needsShipping: true,
    },
  });

  const product4 = await prisma.product.upsert({
    where: { id: 4 },
    update: {},
    create: {
      slug: "the-fourth-product",
      name: "The fourth product",
      description:
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
      price: 1,
      currency: "usd",
      availability: "inStock",
      brandId: 1,
      needsShipping: false,
    },
  });

  const product5 = await prisma.product.upsert({
    where: { id: 5 },
    update: {},
    create: {
      slug: "the-fifth-product",
      name: "The fifth product",
      description:
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
      price: 1182,
      currency: "usd",
      availability: "inStock",
      brandId: 1,
      needsShipping: false,
    },
  });

  const product6 = await prisma.product.upsert({
    where: { id: 6 },
    update: {},
    create: {
      slug: "the-sixth-product",
      name: "The sixth product",
      description:
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
      price: 1000,
      currency: "usd",
      availability: "inStock",
      brandId: 1,
      needsShipping: false,
    },
  });

  const product7 = await prisma.product.upsert({
    where: { id: 7 },
    update: {},
    create: {
      slug: "the-seventh-product",
      name: "The seventh product",
      description:
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
      price: 9999,
      currency: "usd",
      availability: "inStock",
      brandId: 1,
      needsShipping: false,
    },
  });
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });


================================================
FILE: stitches.config.ts
================================================
import { createStitches } from "@stitches/react";
import { crimson, crimsonDark, mauve, mauveDark } from "@radix-ui/colors";

export const {
  styled,
  css,
  globalCss,
  keyframes,
  getCssText,
  theme,
  createTheme,
  config,
} = createStitches({
  theme: {
    colors: {
      ...crimson,
      ...mauve,
    },
    shadows: {
      ...crimson,
      ...mauve,
    },
    space: {
      1: "5px",
      2: "10px",
      3: "15px",
      4: "20px",
      5: "25px",
    },
    sizes: {
      1: "5px",
      2: "10px",
      3: "15px",
      4: "20px",
      5: "25px",
    },
    fontSizes: {
      1: "12px",
      2: "13px",
      3: "15px",
      4: "22px",
      5: "28px",
    },
    radii: {
      small: "5px",
      medium: "15px",
      large: "40px",
    },
  },
  media: {
    small: "(min-width: 640px)",
    medium: "(min-width: 768px)",
    large: "(min-width: 1024px)",
  },
  utils: {
    marginX: (value: string | number) => ({
      marginLeft: value,
      marginRight: value,
    }),
  },
});

export const darkTheme = createTheme({
  colors: {
    ...crimsonDark,
    ...mauveDark,
  },
});

export const globalStyles = globalCss({
  html: { margin: 0, padding: 0, minHeight: "100vh" },
  body: {
    margin: 0,
    padding: 0,
    minHeight: "100vh",
    fontFamily: "Roboto, sans-serif",
  },
  a: { all: "unset" },
});

export const Box = styled("div", {});


================================================
FILE: tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "downlevelIteration": true,
    "baseUrl": ".",
    "incremental": true
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}


================================================
FILE: types.d.ts
================================================
export type Tmeta = {
  headline: string;
  subheadline: string;
  contact: string;
  name: string;
  [key: string]: string;
};


================================================
FILE: yarn-error.log
================================================
Arguments: 
  C:\Program Files\nodejs\node.exe C:\Program Files (x86)\Yarn\bin\yarn.js add -D prisma@3.1.1

PATH: 
  C:\Users\chris\Documents\Code\teini\node_modules\.bin;C:\Users\chris\Documents\Code\node_modules\.bin;C:\Users\chris\Documents\node_modules\.bin;C:\Users\chris\node_modules\.bin;C:\Users\node_modules\.bin;C:\node_modules\.bin;C:\Program Files\nodejs\node_modules\npm\node_modules\@npmcli\run-script\lib\node-gyp-bin;C:\Python39\Scripts\;C:\Python39\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\Git\cmd;C:\Program Files (x86)\Yarn\bin\;C:\ProgramData\chocolatey\bin;C:\Program Files\dotnet\;C:\Program Files\Docker\Docker\resources\bin;C:\ProgramData\DockerDesktop\version-bin;C:\Program Files\nodejs\;C:\Program Files\MySQL\MySQL Server 8.0\bin;C:\Users\chris\AppData\Local\Microsoft\WindowsApps;C:\Users\chris\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\chris\AppData\Local\Yarn\bin;C:\Program Files (x86)\GitHub CLI\;C:\Users\chris\Documents\Tools;C:\Users\chris\AppData\Roaming\npm;C:\Users\chris\Documents\Code\teini\node_modules\.bin

Yarn version: 
  1.22.5

Node version: 
  16.9.0

Platform: 
  win32 x64

Trace: 
  Error: EPERM: operation not permitted, unlink 'C:\Users\chris\Documents\Code\teini\node_modules\prisma\query_engine-windows.dll.node'

npm manifest: 
  {
    "name": "my-app",
    "version": "0.1.0",
    "private": true,
    "scripts": {
      "dev": "next dev",
      "build": "next build",
      "start": "next start",
      "lint": "next lint"
    },
    "dependencies": {
      "next": "11.1.2",
      "react": "17.0.2",
      "react-dom": "17.0.2"
    },
    "devDependencies": {
      "@types/react": "17.0.24",
      "eslint": "7.32.0",
      "eslint-config-next": "11.1.2",
      "prisma": "^3.1.1",
      "typescript": "4.4.3"
    }
  }

yarn manifest: 
  No manifest

Lockfile: 
  # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
  # yarn lockfile v1
  
  
  "@babel/code-frame@7.12.11":
    version "7.12.11"
    resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f"
    integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==
    dependencies:
      "@babel/highlight" "^7.10.4"
  
  "@babel/helper-plugin-utils@^7.14.5":
    version "7.14.5"
    resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9"
    integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==
  
  "@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9":
    version "7.15.7"
    resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389"
    integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==
  
  "@babel/highlight@^7.10.4":
    version "7.14.5"
    resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9"
    integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==
    dependencies:
      "@babel/helper-validator-identifier" "^7.14.5"
      chalk "^2.0.0"
      js-tokens "^4.0.0"
  
  "@babel/plugin-syntax-jsx@7.14.5":
    version "7.14.5"
    resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz#000e2e25d8673cce49300517a3eda44c263e4201"
    integrity sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw==
    dependencies:
      "@babel/helper-plugin-utils" "^7.14.5"
  
  "@babel/runtime-corejs3@^7.10.2":
    version "7.15.4"
    resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.15.4.tgz#403139af262b9a6e8f9ba04a6fdcebf8de692bf1"
    integrity sha512-lWcAqKeB624/twtTc3w6w/2o9RqJPaNBhPGK6DKLSiwuVWC7WFkypWyNg+CpZoyJH0jVzv1uMtXZ/5/lQOLtCg==
    dependencies:
      core-js-pure "^3.16.0"
      regenerator-runtime "^0.13.4"
  
  "@babel/runtime@7.15.3":
    version "7.15.3"
    resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b"
    integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==
    dependencies:
      regenerator-runtime "^0.13.4"
  
  "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2":
    version "7.15.4"
    resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a"
    integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==
    dependencies:
      regenerator-runtime "^0.13.4"
  
  "@babel/types@7.15.0":
    version "7.15.0"
    resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.0.tgz#61af11f2286c4e9c69ca8deb5f4375a73c72dcbd"
    integrity sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==
    dependencies:
      "@babel/helper-validator-identifier" "^7.14.9"
      to-fast-properties "^2.0.0"
  
  "@eslint/eslintrc@^0.4.3":
    version "0.4.3"
    resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c"
    integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==
    dependencies:
      ajv "^6.12.4"
      debug "^4.1.1"
      espree "^7.3.0"
      globals "^13.9.0"
      ignore "^4.0.6"
      import-fresh "^3.2.1"
      js-yaml "^3.13.1"
      minimatch "^3.0.4"
      strip-json-comments "^3.1.1"
  
  "@hapi/accept@5.0.2":
    version "5.0.2"
    resolved "https://registry.yarnpkg.com/@hapi/accept/-/accept-5.0.2.tgz#ab7043b037e68b722f93f376afb05e85c0699523"
    integrity sha512-CmzBx/bXUR8451fnZRuZAJRlzgm0Jgu5dltTX/bszmR2lheb9BpyN47Q1RbaGTsvFzn0PXAEs+lXDKfshccYZw==
    dependencies:
      "@hapi/boom" "9.x.x"
      "@hapi/hoek" "9.x.x"
  
  "@hapi/boom@9.x.x":
    version "9.1.4"
    resolved "https://registry.yarnpkg.com/@hapi/boom/-/boom-9.1.4.tgz#1f9dad367c6a7da9f8def24b4a986fc5a7bd9db6"
    integrity sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw==
    dependencies:
      "@hapi/hoek" "9.x.x"
  
  "@hapi/hoek@9.x.x":
    version "9.2.0"
    resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.0.tgz#f3933a44e365864f4dad5db94158106d511e8131"
    integrity sha512-sqKVVVOe5ivCaXDWivIJYVSaEgdQK9ul7a4Kity5Iw7u9+wBAPbX1RMSnLLmp7O4Vzj0WOWwMAJsTL00xwaNug==
  
  "@humanwhocodes/config-array@^0.5.0":
    version "0.5.0"
    resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9"
    integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==
    dependencies:
      "@humanwhocodes/object-schema" "^1.2.0"
      debug "^4.1.1"
      minimatch "^3.0.4"
  
  "@humanwhocodes/object-schema@^1.2.0":
    version "1.2.0"
    resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf"
    integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==
  
  "@napi-rs/triples@^1.0.3":
    version "1.0.3"
    resolved "https://registry.yarnpkg.com/@napi-rs/triples/-/triples-1.0.3.tgz#76d6d0c3f4d16013c61e45dfca5ff1e6c31ae53c"
    integrity sha512-jDJTpta+P4p1NZTFVLHJ/TLFVYVcOqv6l8xwOeBKNPMgY/zDYH/YH7SJbvrr/h1RcS9GzbPcLKGzpuK9cV56UA==
  
  "@next/env@11.1.2":
    version "11.1.2"
    resolved "https://registry.yarnpkg.com/@next/env/-/env-11.1.2.tgz#27996efbbc54c5f949f5e8c0a156e3aa48369b99"
    integrity sha512-+fteyVdQ7C/OoulfcF6vd1Yk0FEli4453gr8kSFbU8sKseNSizYq6df5MKz/AjwLptsxrUeIkgBdAzbziyJ3mA==
  
  "@next/eslint-plugin-next@11.1.2":
    version "11.1.2"
    resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-11.1.2.tgz#f26cf90bcb6cd2e4645e2ba253bbc9aaaa43a170"
    integrity sha512-cN+ojHRsufr9Yz0rtvjv8WI5En0RPZRJnt0y16Ha7DD+0n473evz8i1ETEJHmOLeR7iPJR0zxRrxeTN/bJMOjg==
    dependencies:
      glob "7.1.7"
  
  "@next/polyfill-module@11.1.2":
    version "11.1.2"
    resolved "https://registry.yarnpkg.com/@next/polyfill-module/-/polyfill-module-11.1.2.tgz#1fe92c364fdc81add775a16c678f5057c6aace98"
    integrity sha512-xZmixqADM3xxtqBV0TpAwSFzWJP0MOQzRfzItHXf1LdQHWb0yofHHC+7eOrPFic8+ZGz5y7BdPkkgR1S25OymA==
  
  "@next/react-dev-overlay@11.1.2":
    version "11.1.2"
    resolved "https://registry.yarnpkg.com/@next/react-dev-overlay/-/react-dev-overlay-11.1.2.tgz#73795dc5454b7af168bac93df7099965ebb603be"
    integrity sha512-rDF/mGY2NC69mMg2vDqzVpCOlWqnwPUXB2zkARhvknUHyS6QJphPYv9ozoPJuoT/QBs49JJd9KWaAzVBvq920A==
    dependencies:
      "@babel/code-frame" "7.12.11"
      anser "1.4.9"
      chalk "4.0.0"
      classnames "2.2.6"
      css.escape "1.5.1"
      data-uri-to-buffer "3.0.1"
      platform "1.3.6"
      shell-quote "1.7.2"
      source-map "0.8.0-beta.0"
      stacktrace-parser "0.1.10"
      strip-ansi "6.0.0"
  
  "@next/react-refresh-utils@11.1.2":
    version "11.1.2"
    resolved "https://registry.yarnpkg.com/@next/react-refresh-utils/-/react-refresh-utils-11.1.2.tgz#44ea40d8e773e4b77bad85e24f6ac041d5e4b4a5"
    integrity sha512-hsoJmPfhVqjZ8w4IFzoo8SyECVnN+8WMnImTbTKrRUHOVJcYMmKLL7xf7T0ft00tWwAl/3f3Q3poWIN2Ueql/Q==
  
  "@next/swc-darwin-arm64@11.1.2":
    version "11.1.2"
    resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-11.1.2.tgz#93226c38db488c4b62b30a53b530e87c969b8251"
    integrity sha512-hZuwOlGOwBZADA8EyDYyjx3+4JGIGjSHDHWrmpI7g5rFmQNltjlbaefAbiU5Kk7j3BUSDwt30quJRFv3nyJQ0w==
  
  "@next/swc-darwin-x64@11.1.2":
    version "11.1.2"
    resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-11.1.2.tgz#792003989f560c00677b5daeff360b35b510db83"
    integrity sha512-PGOp0E1GisU+EJJlsmJVGE+aPYD0Uh7zqgsrpD3F/Y3766Ptfbe1lEPPWnRDl+OzSSrSrX1lkyM/Jlmh5OwNvA==
  
  "@next/swc-linux-x64-gnu@11.1.2":
    version "11.1.2"
    resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-11.1.2.tgz#8216b2ae1f21f0112958735c39dd861088108f37"
    integrity sha512-YcDHTJjn/8RqvyJVB6pvEKXihDcdrOwga3GfMv/QtVeLphTouY4BIcEUfrG5+26Nf37MP1ywN3RRl1TxpurAsQ==
  
  "@next/swc-win32-x64-msvc@11.1.2":
    version "11.1.2"
    resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-11.1.2.tgz#e15824405df137129918205e43cb5e9339589745"
    integrity sha512-e/pIKVdB+tGQYa1cW3sAeHm8gzEri/HYLZHT4WZojrUxgWXqx8pk7S7Xs47uBcFTqBDRvK3EcQpPLf3XdVsDdg==
  
  "@node-rs/helper@1.2.1":
    version "1.2.1"
    resolved "https://registry.yarnpkg.com/@node-rs/helper/-/helper-1.2.1.tgz#e079b05f21ff4329d82c4e1f71c0290e4ecdc70c"
    integrity sha512-R5wEmm8nbuQU0YGGmYVjEc0OHtYsuXdpRG+Ut/3wZ9XAvQWyThN08bTh2cBJgoZxHQUPtvRfeQuxcAgLuiBISg==
    dependencies:
      "@napi-rs/triples" "^1.0.3"
  
  "@nodelib/fs.scandir@2.1.5":
    version "2.1.5"
    resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
    integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
    dependencies:
      "@nodelib/fs.stat" "2.0.5"
      run-parallel "^1.1.9"
  
  "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
    version "2.0.5"
    resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
    integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
  
  "@nodelib/fs.walk@^1.2.3":
    version "1.2.8"
    resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
    integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
    dependencies:
      "@nodelib/fs.scandir" "2.1.5"
      fastq "^1.6.0"
  
  "@prisma/engines@3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f":
    version "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f"
    resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f.tgz#7b45708e6a42523dc9bc2214e5c62781f608dc3a"
    integrity sha512-6NEp0VlLho3hVtIvj2P4h0e19AYqQSXtFGts8gSIXDnV+l5pRFZaDMfGo2RiLMR0Kfrs8c3ZYxYX0sWmVL0tWw==
  
  "@rushstack/eslint-patch@^1.0.6":
    version "1.0.7"
    resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.0.7.tgz#82f83dcc2eb9b1e1d559b3aca96783e285eb8592"
    integrity sha512-3Zi2LGbCLDz4IIL7ir6wD0u/ggHotLkK5SlVzFzTcYaNgPR4MAt/9JYZqXWKcofPWEoptfpnCJU8Bq9sxw8QUg==
  
  "@types/json5@^0.0.29":
    version "0.0.29"
    resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
    integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
  
  "@types/node@*":
    version "16.9.6"
    resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.6.tgz#040a64d7faf9e5d9e940357125f0963012e66f04"
    integrity sha512-YHUZhBOMTM3mjFkXVcK+WwAcYmyhe1wL4lfqNtzI0b3qAy7yuSetnM7QJazgE5PFmgVTNGiLOgRFfJMqW7XpSQ==
  
  "@types/prop-types@*":
    version "15.7.4"
    resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11"
    integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==
  
  "@types/react@17.0.24":
    version "17.0.24"
    resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.24.tgz#7e1b3f78d0fc53782543f9bce6d949959a5880bd"
    integrity sha512-eIpyco99gTH+FTI3J7Oi/OH8MZoFMJuztNRimDOJwH4iGIsKV2qkGnk4M9VzlaVWeEEWLWSQRy0FEA0Kz218cg==
    dependencies:
      "@types/prop-types" "*"
      "@types/scheduler" "*"
      csstype "^3.0.2"
  
  "@types/scheduler@*":
    version "0.16.2"
    resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
    integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
  
  "@typescript-eslint/parser@^4.20.0":
    version "4.31.2"
    resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.31.2.tgz#54aa75986e3302d91eff2bbbaa6ecfa8084e9c34"
    integrity sha512-EcdO0E7M/sv23S/rLvenHkb58l3XhuSZzKf6DBvLgHqOYdL6YFMYVtreGFWirxaU2mS1GYDby3Lyxco7X5+Vjw==
    dependencies:
      "@typescript-eslint/scope-manager" "4.31.2"
      "@typescript-eslint/types" "4.31.2"
      "@typescript-eslint/typescript-estree" "4.31.2"
      debug "^4.3.1"
  
  "@typescript-eslint/scope-manager@4.31.2":
    version "4.31.2"
    resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.31.2.tgz#1d528cb3ed3bcd88019c20a57c18b897b073923a"
    integrity sha512-2JGwudpFoR/3Czq6mPpE8zBPYdHWFGL6lUNIGolbKQeSNv4EAiHaR5GVDQaLA0FwgcdcMtRk+SBJbFGL7+La5w==
    dependencies:
      "@typescript-eslint/types" "4.31.2"
      "@typescript-eslint/visitor-keys" "4.31.2"
  
  "@typescript-eslint/types@4.31.2":
    version "4.31.2"
    resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.31.2.tgz#2aea7177d6d744521a168ed4668eddbd912dfadf"
    integrity sha512-kWiTTBCTKEdBGrZKwFvOlGNcAsKGJSBc8xLvSjSppFO88AqGxGNYtF36EuEYG6XZ9vT0xX8RNiHbQUKglbSi1w==
  
  "@typescript-eslint/typescript-estree@4.31.2":
    version "4.31.2"
    resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.2.tgz#abfd50594d8056b37e7428df3b2d185ef2d0060c"
    integrity sha512-ieBq8U9at6PvaC7/Z6oe8D3czeW5d//Fo1xkF/s9394VR0bg/UaMYPdARiWyKX+lLEjY3w/FNZJxitMsiWv+wA==
    dependencies:
      "@typescript-eslint/types" "4.31.2"
      "@typescript-eslint/visitor-keys" "4.31.2"
      debug "^4.3.1"
      globby "^11.0.3"
      is-glob "^4.0.1"
      semver "^7.3.5"
      tsutils "^3.21.0"
  
  "@typescript-eslint/visitor-keys@4.31.2":
    version "4.31.2"
    resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.2.tgz#7d5b4a4705db7fe59ecffb273c1d082760f635cc"
    integrity sha512-PrBId7EQq2Nibns7dd/ch6S6/M4/iwLM9McbgeEbCXfxdwRUNxJ4UNreJ6Gh3fI2GNKNrWnQxKL7oCPmngKBug==
    dependencies:
      "@typescript-eslint/types" "4.31.2"
      eslint-visitor-keys "^2.0.0"
  
  acorn-jsx@^5.3.1:
    version "5.3.2"
    resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
    integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
  
  acorn@^7.4.0:
    version "7.4.1"
    resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
    integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
  
  ajv@^6.10.0, ajv@^6.12.4:
    version "6.12.6"
    resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
    integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
    dependencies:
      fast-deep-equal "^3.1.1"
      fast-json-stable-stringify "^2.0.0"
      json-schema-traverse "^0.4.1"
      uri-js "^4.2.2"
  
  ajv@^8.0.1:
    version "8.6.3"
    resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.3.tgz#11a66527761dc3e9a3845ea775d2d3c0414e8764"
    integrity sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==
    dependencies:
      fast-deep-equal "^3.1.1"
      json-schema-traverse "^1.0.0"
      require-from-string "^2.0.2"
      uri-js "^4.2.2"
  
  anser@1.4.9:
    version "1.4.9"
    resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.9.tgz#1f85423a5dcf8da4631a341665ff675b96845760"
    integrity sha512-AI+BjTeGt2+WFk4eWcqbQ7snZpDBt8SaLlj0RT2h5xfdWaiy51OjYvqwMrNzJLGy8iOAL6nKDITWO+rd4MkYEA==
  
  ansi-colors@^4.1.1:
    version "4.1.1"
    resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
    integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
  
  ansi-regex@^5.0.0:
    version "5.0.1"
    resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
    integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
  
  ansi-styles@^3.2.1:
    version "3.2.1"
    resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
    integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
    dependencies:
      color-convert "^1.9.0"
  
  ansi-styles@^4.0.0, ansi-styles@^4.1.0:
    version "4.3.0"
    resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
    integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
    dependencies:
      color-convert "^2.0.1"
  
  anymatch@~3.1.1:
    version "3.1.2"
    resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
    integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
    dependencies:
      normalize-path "^3.0.0"
      picomatch "^2.0.4"
  
  argparse@^1.0.7:
    version "1.0.10"
    resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
    integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
    dependencies:
      sprintf-js "~1.0.2"
  
  aria-query@^4.2.2:
    version "4.2.2"
    resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b"
    integrity sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==
    dependencies:
      "@babel/runtime" "^7.10.2"
      "@babel/runtime-corejs3" "^7.10.2"
  
  array-includes@^3.1.1, array-includes@^3.1.3:
    version "3.1.3"
    resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.3.tgz#c7f619b382ad2afaf5326cddfdc0afc61af7690a"
    integrity sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==
    dependencies:
      call-bind "^1.0.2"
      define-properties "^1.1.3"
      es-abstract "^1.18.0-next.2"
      get-intrinsic "^1.1.1"
      is-string "^1.0.5"
  
  array-union@^2.1.0:
    version "2.1.0"
    resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
    integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
  
  array.prototype.flat@^1.2.4:
    version "1.2.4"
    resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz#6ef638b43312bd401b4c6199fdec7e2dc9e9a123"
    integrity sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==
    dependencies:
      call-bind "^1.0.0"
      define-properties "^1.1.3"
      es-abstract "^1.18.0-next.1"
  
  array.prototype.flatmap@^1.2.4:
    version "1.2.4"
    resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz#94cfd47cc1556ec0747d97f7c7738c58122004c9"
    integrity sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==
    dependencies:
      call-bind "^1.0.0"
      define-properties "^1.1.3"
      es-abstract "^1.18.0-next.1"
      function-bind "^1.1.1"
  
  asn1.js@^5.2.0:
    version "5.4.1"
    resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07"
    integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==
    dependencies:
      bn.js "^4.0.0"
      inherits "^2.0.1"
      minimalistic-assert "^1.0.0"
      safer-buffer "^2.1.0"
  
  assert@2.0.0:
    version "2.0.0"
    resolved "https://registry.yarnpkg.com/assert/-/assert-2.0.0.tgz#95fc1c616d48713510680f2eaf2d10dd22e02d32"
    integrity sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==
    dependencies:
      es6-object-assign "^1.1.0"
      is-nan "^1.2.1"
      object-is "^1.0.1"
      util "^0.12.0"
  
  assert@^1.1.1:
    version "1.5.0"
    resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb"
    integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==
    dependencies:
      object-assign "^4.1.1"
      util "0.10.3"
  
  ast-types-flow@^0.0.7:
    version "0.0.7"
    resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad"
    integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0=
  
  ast-types@0.13.2:
    version "0.13.2"
    resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.2.tgz#df39b677a911a83f3a049644fb74fdded23cea48"
    integrity sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA==
  
  astral-regex@^2.0.0:
    version "2.0.0"
    resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
    integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
  
  available-typed-arrays@^1.0.5:
    version "1.0.5"
    resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
    integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
  
  axe-core@^4.0.2:
    version "4.3.3"
    resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.3.tgz#b55cd8e8ddf659fe89b064680e1c6a4dceab0325"
    integrity sha512-/lqqLAmuIPi79WYfRpy2i8z+x+vxU3zX2uAm0gs1q52qTuKwolOj1P8XbufpXcsydrpKx2yGn2wzAnxCMV86QA==
  
  axobject-query@^2.2.0:
    version "2.2.0"
    resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
    integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==
  
  balanced-match@^1.0.0:
    version "1.0.2"
    resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
    integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
  
  base64-js@^1.0.2:
    version "1.5.1"
    resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
    integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
  
  big.js@^5.2.2:
    version "5.2.2"
    resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
    integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
  
  binary-extensions@^2.0.0:
    version "2.2.0"
    resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
    integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
  
  bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9:
    version "4.12.0"
    resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
    integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
  
  bn.js@^5.0.0, bn.js@^5.1.1:
    version "5.2.0"
    resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002"
    integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==
  
  brace-expansion@^1.1.7:
    version "1.1.11"
    resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
    integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
    dependencies:
      balanced-match "^1.0.0"
      concat-map "0.0.1"
  
  braces@^3.0.1, braces@~3.0.2:
    version "3.0.2"
    resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
    integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
    dependencies:
      fill-range "^7.0.1"
  
  brorand@^1.0.1, brorand@^1.1.0:
    version "1.1.0"
    resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
    integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=
  
  browserify-aes@^1.0.0, browserify-aes@^1.0.4:
    version "1.2.0"
    resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48"
    integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==
    dependencies:
      buffer-xor "^1.0.3"
      cipher-base "^1.0.0"
      create-hash "^1.1.0"
      evp_bytestokey "^1.0.3"
      inherits "^2.0.1"
      safe-buffer "^5.0.1"
  
  browserify-cipher@^1.0.0:
    version "1.0.1"
    resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0"
    integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==
    dependencies:
      browserify-aes "^1.0.4"
      browserify-des "^1.0.0"
      evp_bytestokey "^1.0.0"
  
  browserify-des@^1.0.0:
    version "1.0.2"
    resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c"
    integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==
    dependencies:
      cipher-base "^1.0.1"
      des.js "^1.0.0"
      inherits "^2.0.1"
      safe-buffer "^5.1.2"
  
  browserify-rsa@^4.0.0, browserify-rsa@^4.0.1:
    version "4.1.0"
    resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d"
    integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==
    dependencies:
      bn.js "^5.0.0"
      randombytes "^2.0.1"
  
  browserify-sign@^4.0.0:
    version "4.2.1"
    resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3"
    integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==
    dependencies:
      bn.js "^5.1.1"
      browserify-rsa "^4.0.1"
      create-hash "^1.2.0"
      create-hmac "^1.1.7"
      elliptic "^6.5.3"
      inherits "^2.0.4"
      parse-asn1 "^5.1.5"
      readable-stream "^3.6.0"
      safe-buffer "^5.2.0"
  
  browserify-zlib@0.2.0, browserify-zlib@^0.2.0:
    version "0.2.0"
    resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f"
    integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==
    dependencies:
      pako "~1.0.5"
  
  browserslist@4.16.6:
    version "4.16.6"
    resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2"
    integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==
    dependencies:
      caniuse-lite "^1.0.30001219"
      colorette "^1.2.2"
      electron-to-chromium "^1.3.723"
      escalade "^3.1.1"
      node-releases "^1.1.71"
  
  buffer-xor@^1.0.3:
    version "1.0.3"
    resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
    integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=
  
  buffer@5.6.0:
    version "5.6.0"
    resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786"
    integrity sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==
    dependencies:
      base64-js "^1.0.2"
      ieee754 "^1.1.4"
  
  buffer@^4.3.0:
    version "4.9.2"
    resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8"
    integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==
    dependencies:
      base64-js "^1.0.2"
      ieee754 "^1.1.4"
      isarray "^1.0.0"
  
  builtin-status-codes@^3.0.0:
    version "3.0.0"
    resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
    integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
  
  bytes@3.1.0:
    version "3.1.0"
    resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
    integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
  
  call-bind@^1.0.0, call-bind@^1.0.2:
    version "1.0.2"
    resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
    integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
    dependencies:
      function-bind "^1.1.1"
      get-intrinsic "^1.0.2"
  
  callsites@^3.0.0:
    version "3.1.0"
    resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
    integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
  
  caniuse-lite@^1.0.30001202, caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.30001228:
    version "1.0.30001260"
    resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001260.tgz#e3be3f34ddad735ca4a2736fa9e768ef34316270"
    integrity sha512-Fhjc/k8725ItmrvW5QomzxLeojewxvqiYCKeFcfFEhut28IVLdpHU19dneOmltZQIE5HNbawj1HYD+1f2bM1Dg==
    dependencies:
      nanocolors "^0.1.0"
  
  chalk@2.4.2, chalk@^2.0.0:
    version "2.4.2"
    resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
    integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
    dependencies:
      ansi-styles "^3.2.1"
      escape-string-regexp "^1.0.5"
      supports-color "^5.3.0"
  
  chalk@4.0.0:
    version "4.0.0"
    resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.0.0.tgz#6e98081ed2d17faab615eb52ac66ec1fe6209e72"
    integrity sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==
    dependencies:
      ansi-styles "^4.1.0"
      supports-color "^7.1.0"
  
  chalk@^4.0.0:
    version "4.1.2"
    resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
    integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
    dependencies:
      ansi-styles "^4.1.0"
      supports-color "^7.1.0"
  
  chokidar@3.5.1:
    version "3.5.1"
    resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a"
    integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==
    dependencies:
      anymatch "~3.1.1"
      braces "~3.0.2"
      glob-parent "~5.1.0"
      is-binary-path "~2.1.0"
      is-glob "~4.0.1"
      normalize-path "~3.0.0"
      readdirp "~3.5.0"
    optionalDependencies:
      fsevents "~2.3.1"
  
  cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
    version "1.0.4"
    resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
    integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==
    dependencies:
      inherits "^2.0.1"
      safe-buffer "^5.0.1"
  
  classnames@2.2.6:
    version "2.2.6"
    resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
    integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
  
  color-convert@^1.9.0:
    version "1.9.3"
    resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
    integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
    dependencies:
      color-name "1.1.3"
  
  color-convert@^2.0.1:
    version "2.0.1"
    resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
    integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
    dependencies:
      color-name "~1.1.4"
  
  color-name@1.1.3:
    version "1.1.3"
    resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
    integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
  
  color-name@~1.1.4:
    version "1.1.4"
    resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
    integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
  
  colorette@^1.2.2:
    version "1.4.0"
    resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40"
    integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==
  
  commondir@^1.0.1:
    version "1.0.1"
    resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
    integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
  
  concat-map@0.0.1:
    version "0.0.1"
    resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
    integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
  
  console-browserify@^1.1.0:
    version "1.2.0"
    resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336"
    integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==
  
  constants-browserify@1.0.0, constants-browserify@^1.0.0:
    version "1.0.0"
    resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
    integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=
  
  convert-source-map@1.7.0:
    version "1.7.0"
    resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
    integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
    dependencies:
      safe-buffer "~5.1.1"
  
  core-js-pure@^3.16.0:
    version "3.18.0"
    resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.18.0.tgz#e5187347bae66448c9e2d67c01c34c4df3261dc5"
    integrity sha512-ZnK+9vyuMhKulIGqT/7RHGRok8RtkHMEX/BGPHkHx+ouDkq+MUvf9mfIgdqhpmPDu8+V5UtRn/CbCRc9I4lX4w==
  
  core-util-is@~1.0.0:
    version "1.0.3"
    resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
    integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
  
  create-ecdh@^4.0.0:
    version "4.0.4"
    resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e"
    integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==
    dependencies:
      bn.js "^4.1.0"
      elliptic "^6.5.3"
  
  create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
    version "1.2.0"
    resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
    integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==
    dependencies:
      cipher-base "^1.0.1"
      inherits "^2.0.1"
      md5.js "^1.3.4"
      ripemd160 "^2.0.1"
      sha.js "^2.4.0"
  
  create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
    version "1.1.7"
    resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
    integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==
    dependencies:
      cipher-base "^1.0.3"
      create-hash "^1.1.0"
      inherits "^2.0.1"
      ripemd160 "^2.0.0"
      safe-buffer "^5.0.1"
      sha.js "^2.4.8"
  
  cross-spawn@^7.0.2:
    version "7.0.3"
    resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
    integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
    dependencies:
      path-key "^3.1.0"
      shebang-command "^2.0.0"
      which "^2.0.1"
  
  crypto-browserify@3.12.0, crypto-browserify@^3.11.0:
    version "3.12.0"
    resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
    integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==
    dependencies:
      browserify-cipher "^1.0.0"
      browserify-sign "^4.0.0"
      create-ecdh "^4.0.0"
      create-hash "^1.1.0"
      create-hmac "^1.1.0"
      diffie-hellman "^5.0.0"
      inherits "^2.0.1"
      pbkdf2 "^3.0.3"
      public-encrypt "^4.0.0"
      randombytes "^2.0.0"
      randomfill "^1.0.3"
  
  css.escape@1.5.1:
    version "1.5.1"
    resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb"
    integrity sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=
  
  cssnano-preset-simple@^3.0.0:
    version "3.0.0"
    resolved "https://registry.yarnpkg.com/cssnano-preset-simple/-/cssnano-preset-simple-3.0.0.tgz#e95d0012699ca2c741306e9a3b8eeb495a348dbe"
    integrity sha512-vxQPeoMRqUT3c/9f0vWeVa2nKQIHFpogtoBvFdW4GQ3IvEJ6uauCP6p3Y5zQDLFcI7/+40FTgX12o7XUL0Ko+w==
    dependencies:
      caniuse-lite "^1.0.30001202"
  
  cssnano-simple@3.0.0:
    version "3.0.0"
    resolved "https://registry.yarnpkg.com/cssnano-simple/-/cssnano-simple-3.0.0.tgz#a4b8ccdef4c7084af97e19bc5b93b4ecf211e90f"
    integrity sha512-oU3ueli5Dtwgh0DyeohcIEE00QVfbPR3HzyXdAl89SfnQG3y0/qcpfLVW+jPIh3/rgMZGwuW96rejZGaYE9eUg==
    dependencies:
      cssnano-preset-simple "^3.0.0"
  
  csstype@^3.0.2:
    version "3.0.9"
    resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.9.tgz#6410af31b26bd0520933d02cbc64fce9ce3fbf0b"
    integrity sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==
  
  damerau-levenshtein@^1.0.6:
    version "1.0.7"
    resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz#64368003512a1a6992593741a09a9d31a836f55d"
    integrity sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw==
  
  data-uri-to-buffer@3.0.1:
    version "3.0.1"
    resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636"
    integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==
  
  debug@2, debug@^2.6.9:
    version "2.6.9"
    resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
    integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
    dependencies:
      ms "2.0.0"
  
  debug@^3.2.7:
    version "3.2.7"
    resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
    integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
    dependencies:
      ms "^2.1.1"
  
  debug@^4.0.1, debug@^4.1.1, debug@^4.3.1:
    version "4.3.2"
    resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
    integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
    dependencies:
      ms "2.1.2"
  
  deep-is@^0.1.3:
    version "0.1.4"
    resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
    integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
  
  define-properties@^1.1.3:
    version "1.1.3"
    resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
    integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
    dependencies:
      object-keys "^1.0.12"
  
  depd@~1.1.2:
    version "1.1.2"
    resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
    integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
  
  des.js@^1.0.0:
    version "1.0.1"
    resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843"
    integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==
    dependencies:
      inherits "^2.0.1"
      minimalistic-assert "^1.0.0"
  
  diffie-hellman@^5.0.0:
    version "5.0.3"
    resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
    integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==
    dependencies:
      bn.js "^4.1.0"
      miller-rabin "^4.0.0"
      randombytes "^2.0.0"
  
  dir-glob@^3.0.1:
    version "3.0.1"
    resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
    integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
    dependencies:
      path-type "^4.0.0"
  
  doctrine@^2.1.0:
    version "2.1.0"
    resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
    integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
    dependencies:
      esutils "^2.0.2"
  
  doctrine@^3.0.0:
    version "3.0.0"
    resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
    integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
    dependencies:
      esutils "^2.0.2"
  
  domain-browser@4.19.0:
    version "4.19.0"
    resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.19.0.tgz#1093e17c0a17dbd521182fe90d49ac1370054af1"
    integrity sha512-fRA+BaAWOR/yr/t7T9E9GJztHPeFjj8U35ajyAjCDtAAnTn1Rc1f6W6VGPJrO1tkQv9zWu+JRof7z6oQtiYVFQ==
  
  domain-browser@^1.1.1:
    version "1.2.0"
    resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
    integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
  
  electron-to-chromium@^1.3.723:
    version "1.3.848"
    resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.848.tgz#94cc196e496f33c0d71cd98561448f10018584cc"
    integrity sha512-wchRyBcdcmibioggdO7CbMT5QQ4lXlN/g7Mkpf1K2zINidnqij6EVu94UIZ+h5nB2S9XD4bykqFv9LonAWLFyw==
  
  elliptic@^6.5.3:
    version "6.5.4"
    resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
    integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==
    dependencies:
      bn.js "^4.11.9"
      brorand "^1.1.0"
      hash.js "^1.0.0"
      hmac-drbg "^1.0.1"
      inherits "^2.0.4"
      minimalistic-assert "^1.0.1"
      minimalistic-crypto-utils "^1.0.1"
  
  emoji-regex@^8.0.0:
    version "8.0.0"
    resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
    integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
  
  emoji-regex@^9.0.0:
    version "9.2.2"
    resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
    integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
  
  emojis-list@^2.0.0:
    version "2.1.0"
    resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
    integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k=
  
  encoding@0.1.13:
    version "0.1.13"
    resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
    integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
    dependencies:
      iconv-lite "^0.6.2"
  
  enquirer@^2.3.5:
    version "2.3.6"
    resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
    integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
    dependencies:
      ansi-colors "^4.1.1"
  
  error-ex@^1.3.1:
    version "1.3.2"
    resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
    integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
    dependencies:
      is-arrayish "^0.2.1"
  
  es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.18.1, es-abstract@^1.18.2, es-abstract@^1.18.5:
    version "1.18.6"
    resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.6.tgz#2c44e3ea7a6255039164d26559777a6d978cb456"
    integrity sha512-kAeIT4cku5eNLNuUKhlmtuk1/TRZvQoYccn6TO0cSVdf1kzB0T7+dYuVK9MWM7l+/53W2Q8M7N2c6MQvhXFcUQ==
    dependencies:
      call-bind "^1.0.2"
      es-to-primitive "^1.2.1"
      function-bind "^1.1.1"
      get-intrinsic "^1.1.1"
      get-symbol-description "^1.0.0"
      has "^1.0.3"
      has-symbols "^1.0.2"
      internal-slot "^1.0.3"
      is-callable "^1.2.4"
      is-negative-zero "^2.0.1"
      is-regex "^1.1.4"
      is-string "^1.0.7"
      object-inspect "^1.11.0"
      object-keys "^1.1.1"
      object.assign "^4.1.2"
      string.prototype.trimend "^1.0.4"
      string.prototype.trimstart "^1.0.4"
      unbox-primitive "^1.0.1"
  
  es-to-primitive@^1.2.1:
    version "1.2.1"
    resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
    integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
    dependencies:
      is-callable "^1.1.4"
      is-date-object "^1.0.1"
      is-symbol "^1.0.2"
  
  es6-object-assign@^1.1.0:
    version "1.1.0"
    resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c"
    integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=
  
  escalade@^3.1.1:
    version "3.1.1"
    resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
    integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
  
  escape-string-regexp@^1.0.5:
    version "1.0.5"
    resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
    integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
  
  escape-string-regexp@^4.0.0:
    version "4.0.0"
    resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
    integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
  
  eslint-config-next@11.1.2:
    version "11.1.2"
    resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-11.1.2.tgz#73c918f2fa6120d5f65080bf3fcf6b154905707e"
    integrity sha512-dFutecxX2Z5/QVlLwdtKt+gIfmNMP8Qx6/qZh3LM/DFVdGJEAnUKrr4VwGmACB2kx/PQ5bx3R+QxnEg4fDPiTg==
    dependencies:
      "@next/eslint-plugin-next" "11.1.2"
      "@rushstack/eslint-patch" "^1.0.6"
      "@typescript-eslint/parser" "^4.20.0"
      eslint-import-resolver-node "^0.3.4"
      eslint-import-resolver-typescript "^2.4.0"
      eslint-plugin-import "^2.22.1"
      eslint-plugin-jsx-a11y "^6.4.1"
      eslint-plugin-react "^7.23.1"
      eslint-plugin-react-hooks "^4.2.0"
  
  eslint-import-resolver-node@^0.3.4, eslint-import-resolver-node@^0.3.6:
    version "0.3.6"
    resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd"
    integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==
    dependencies:
      debug "^3.2.7"
      resolve "^1.20.0"
  
  eslint-import-resolver-typescript@^2.4.0:
    version "2.5.0"
    resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.5.0.tgz#07661966b272d14ba97f597b51e1a588f9722f0a"
    integrity sha512-qZ6e5CFr+I7K4VVhQu3M/9xGv9/YmwsEXrsm3nimw8vWaVHRDrQRp26BgCypTxBp3vUp4o5aVEJRiy0F2DFddQ==
    dependencies:
      debug "^4.3.1"
      glob "^7.1.7"
      is-glob "^4.0.1"
      resolve "^1.20.0"
      tsconfig-paths "^3.9.0"
  
  eslint-module-utils@^2.6.2:
    version "2.6.2"
    resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz#94e5540dd15fe1522e8ffa3ec8db3b7fa7e7a534"
    integrity sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==
    dependencies:
      debug "^3.2.7"
      pkg-dir "^2.0.0"
  
  eslint-plugin-import@^2.22.1:
    version "2.24.2"
    resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.24.2.tgz#2c8cd2e341f3885918ee27d18479910ade7bb4da"
    integrity sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q==
    dependencies:
      array-includes "^3.1.3"
      array.prototype.flat "^1.2.4"
      debug "^2.6.9"
      doctrine "^2.1.0"
      eslint-import-resolver-node "^0.3.6"
      eslint-module-utils "^2.6.2"
      find-up "^2.0.0"
      has "^1.0.3"
      is-core-module "^2.6.0"
      minimatch "^3.0.4"
      object.values "^1.1.4"
      pkg-up "^2.0.0"
      read-pkg-up "^3.0.0"
      resolve "^1.20.0"
      tsconfig-paths "^3.11.0"
  
  eslint-plugin-jsx-a11y@^6.4.1:
    version "6.4.1"
    resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz#a2d84caa49756942f42f1ffab9002436391718fd"
    integrity sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==
    dependencies:
      "@babel/runtime" "^7.11.2"
      aria-query "^4.2.2"
      array-includes "^3.1.1"
      ast-types-flow "^0.0.7"
      axe-core "^4.0.2"
      axobject-query "^2.2.0"
      damerau-levenshtein "^1.0.6"
      emoji-regex "^9.0.0"
      has "^1.0.3"
      jsx-ast-utils "^3.1.0"
      language-tags "^1.0.5"
  
  eslint-plugin-react-hooks@^4.2.0:
    version "4.2.0"
    resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz#8c229c268d468956334c943bb45fc860280f5556"
    integrity sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==
  
  eslint-plugin-react@^7.23.1:
    version "7.26.0"
    resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.26.0.tgz#3ae019a35d542b98e5af9e2f96b89c232c74b55b"
    integrity sha512-dceliS5itjk4EZdQYtLMz6GulcsasguIs+VTXuiC7Q5IPIdGTkyfXVdmsQOqEhlD9MciofH4cMcT1bw1WWNxCQ==
    dependencies:
      array-includes "^3.1.3"
      array.prototype.flatmap "^1.2.4"
      doctrine "^2.1.0"
      estraverse "^5.2.0"
      jsx-ast-utils "^2.4.1 || ^3.0.0"
      minimatch "^3.0.4"
      object.entries "^1.1.4"
      object.fromentries "^2.0.4"
      object.hasown "^1.0.0"
      object.values "^1.1.4"
      prop-types "^15.7.2"
      resolve "^2.0.0-next.3"
      semver "^6.3.0"
      string.prototype.matchall "^4.0.5"
  
  eslint-scope@^5.1.1:
    version "5.1.1"
    resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
    integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
    dependencies:
      esrecurse "^4.3.0"
      estraverse "^4.1.1"
  
  eslint-utils@^2.1.0:
    version "2.1.0"
    resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
    integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
    dependencies:
      eslint-visitor-keys "^1.1.0"
  
  eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0:
    version "1.3.0"
    resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
    integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
  
  eslint-visitor-keys@^2.0.0:
    version "2.1.0"
    resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
    integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
  
  eslint@7.32.0:
    version "7.32.0"
    resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d"
    integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==
    dependencies:
      "@babel/code-frame" "7.12.11"
      "@eslint/eslintrc" "^0.4.3"
      "@humanwhocodes/config-array" "^0.5.0"
      ajv "^6.10.0"
      chalk "^4.0.0"
      cross-spawn "^7.0.2"
      debug "^4.0.1"
      doctrine "^3.0.0"
      enquirer "^2.3.5"
      escape-string-regexp "^4.0.0"
      eslint-scope "^5.1.1"
      eslint-utils "^2.1.0"
      eslint-visitor-keys "^2.0.0"
      espree "^7.3.1"
      esquery "^1.4.0"
      esutils "^2.0.2"
      fast-deep-equal "^3.1.3"
      file-entry-cache "^6.0.1"
      functional-red-black-tree "^1.0.1"
      glob-parent "^5.1.2"
      globals "^13.6.0"
      ignore "^4.0.6"
      import-fresh "^3.0.0"
      imurmurhash "^0.1.4"
      is-glob "^4.0.0"
      js-yaml "^3.13.1"
      json-stable-stringify-without-jsonify "^1.0.1"
      levn "^0.4.1"
      lodash.merge "^4.6.2"
      minimatch "^3.0.4"
      natural-compare "^1.4.0"
      optionator "^0.9.1"
      progress "^2.0.0"
      regexpp "^3.1.0"
      semver "^7.2.1"
      strip-ansi "^6.0.0"
      strip-json-comments "^3.1.0"
      table "^6.0.9"
      text-table "^0.2.0"
      v8-compile-cache "^2.0.3"
  
  espree@^7.3.0, espree@^7.3.1:
    version "7.3.1"
    resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6"
    integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==
    dependencies:
      acorn "^7.4.0"
      acorn-jsx "^5.3.1"
      eslint-visitor-keys "^1.3.0"
  
  esprima@^4.0.0:
    version "4.0.1"
    resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
    integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
  
  esquery@^1.4.0:
    version "1.4.0"
    resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5"
    integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==
    dependencies:
      estraverse "^5.1.0"
  
  esrecurse@^4.3.0:
    version "4.3.0"
    resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
    integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
    dependencies:
      estraverse "^5.2.0"
  
  estraverse@^4.1.1:
    version "4.3.0"
    resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
    integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
  
  estraverse@^5.1.0, estraverse@^5.2.0:
    version "5.2.0"
    resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
    integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
  
  esutils@^2.0.2:
    version "2.0.3"
    resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
    integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
  
  etag@1.8.1:
    version "1.8.1"
    resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
    integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
  
  events@^3.0.0:
    version "3.3.0"
    resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
    integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
  
  evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
    version "1.0.3"
    resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02"
    integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==
    dependencies:
      md5.js "^1.3.4"
      safe-buffer "^5.1.1"
  
  fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
    version "3.1.3"
    resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
    integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
  
  fast-glob@^3.1.1:
    version "3.2.7"
    resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1"
    integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==
    dependencies:
      "@nodelib/fs.stat" "^2.0.2"
      "@nodelib/fs.walk" "^1.2.3"
      glob-parent "^5.1.2"
      merge2 "^1.3.0"
      micromatch "^4.0.4"
  
  fast-json-stable-stringify@^2.0.0:
    version "2.1.0"
    resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
    integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
  
  fast-levenshtein@^2.0.6:
    version "2.0.6"
    resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
    integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
  
  fastq@^1.6.0:
    version "1.13.0"
    resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
    integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==
    dependencies:
      reusify "^1.0.4"
  
  file-entry-cache@^6.0.1:
    version "6.0.1"
    resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
    integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
    dependencies:
      flat-cache "^3.0.4"
  
  fill-range@^7.0.1:
    version "7.0.1"
    resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
    integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
    dependencies:
      to-regex-range "^5.0.1"
  
  find-cache-dir@3.3.1:
    version "3.3.1"
    resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880"
    integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==
    dependencies:
      commondir "^1.0.1"
      make-dir "^3.0.2"
      pkg-dir "^4.1.0"
  
  find-up@^2.0.0, find-up@^2.1.0:
    version "2.1.0"
    resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
    integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
    dependencies:
      locate-path "^2.0.0"
  
  find-up@^4.0.0:
    version "4.1.0"
    resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
    integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
    dependencies:
      locate-path "^5.0.0"
      path-exists "^4.0.0"
  
  flat-cache@^3.0.4:
    version "3.0.4"
    resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
    integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==
    dependencies:
      flatted "^3.1.0"
      rimraf "^3.0.2"
  
  flatted@^3.1.0:
    version "3.2.2"
    resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561"
    integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==
  
  foreach@^2.0.5:
    version "2.0.5"
    resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
    integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k=
  
  fs.realpath@^1.0.0:
    version "1.0.0"
    resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
    integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
  
  fsevents@~2.3.1:
    version "2.3.2"
    resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
    integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
  
  function-bind@^1.1.1:
    version "1.1.1"
    resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
    integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
  
  functional-red-black-tree@^1.0.1:
    version "1.0.1"
    resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
    integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
  
  get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
    version "1.1.1"
    resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
    integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==
    dependencies:
      function-bind "^1.1.1"
      has "^1.0.3"
      has-symbols "^1.0.1"
  
  get-orientation@1.1.2:
    version "1.1.2"
    resolved "https://registry.yarnpkg.com/get-orientation/-/get-orientation-1.1.2.tgz#20507928951814f8a91ded0a0e67b29dfab98947"
    integrity sha512-/pViTfifW+gBbh/RnlFYHINvELT9Znt+SYyDKAUL6uV6By019AK/s+i9XP4jSwq7lwP38Fd8HVeTxym3+hkwmQ==
    dependencies:
      stream-parser "^0.3.1"
  
  get-symbol-description@^1.0.0:
    version "1.0.0"
    resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6"
    integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==
    dependencies:
      call-bind "^1.0.2"
      get-intrinsic "^1.1.1"
  
  glob-parent@^5.1.2, glob-parent@~5.1.0:
    version "5.1.2"
    resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
    integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
    dependencies:
      is-glob "^4.0.1"
  
  glob-to-regexp@^0.4.1:
    version "0.4.1"
    resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
    integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
  
  glob@7.1.7:
    version "7.1.7"
    resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
    integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==
    dependencies:
      fs.realpath "^1.0.0"
      inflight "^1.0.4"
      inherits "2"
      minimatch "^3.0.4"
      once "^1.3.0"
      path-is-absolute "^1.0.0"
  
  glob@^7.1.3, glob@^7.1.7:
    version "7.2.0"
    resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
    integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
    dependencies:
      fs.realpath "^1.0.0"
      inflight "^1.0.4"
      inherits "2"
      minimatch "^3.0.4"
      once "^1.3.0"
      path-is-absolute "^1.0.0"
  
  globals@^13.6.0, globals@^13.9.0:
    version "13.11.0"
    resolved "https://registry.yarnpkg.com/globals/-/globals-13.11.0.tgz#40ef678da117fe7bd2e28f1fab24951bd0255be7"
    integrity sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==
    dependencies:
      type-fest "^0.20.2"
  
  globby@^11.0.3:
    version "11.0.4"
    resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5"
    integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==
    dependencies:
      array-union "^2.1.0"
      dir-glob "^3.0.1"
      fast-glob "^3.1.1"
      ignore "^5.1.4"
      merge2 "^1.3.0"
      slash "^3.0.0"
  
  graceful-fs@^4.1.2:
    version "4.2.8"
    resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a"
    integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==
  
  has-bigints@^1.0.1:
    version "1.0.1"
    resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113"
    integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==
  
  has-flag@^3.0.0:
    version "3.0.0"
    resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
    integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
  
  has-flag@^4.0.0:
    version "4.0.0"
    resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
    integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
  
  has-symbols@^1.0.1, has-symbols@^1.0.2:
    version "1.0.2"
    resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423"
    integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
  
  has-tostringtag@^1.0.0:
    version "1.0.0"
    resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25"
    integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==
    dependencies:
      has-symbols "^1.0.2"
  
  has@^1.0.3:
    version "1.0.3"
    resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
    integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
    dependencies:
      function-bind "^1.1.1"
  
  hash-base@^3.0.0:
    version "3.1.0"
    resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33"
    integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==
    dependencies:
      inherits "^2.0.4"
      readable-stream "^3.6.0"
      safe-buffer "^5.2.0"
  
  hash.js@^1.0.0, hash.js@^1.0.3:
    version "1.1.7"
    resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
    integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==
    dependencies:
      inherits "^2.0.3"
      minimalistic-assert "^1.0.1"
  
  he@1.2.0:
    version "1.2.0"
    resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
    integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
  
  hmac-drbg@^1.0.1:
    version "1.0.1"
    resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
    integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=
    dependencies:
      hash.js "^1.0.3"
      minimalistic-assert "^1.0.0"
      minimalistic-crypto-utils "^1.0.1"
  
  hosted-git-info@^2.1.4:
    version "2.8.9"
    resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
    integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
  
  http-errors@1.7.3:
    version "1.7.3"
    resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
    integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
    dependencies:
      depd "~1.1.2"
      inherits "2.0.4"
      setprototypeof "1.1.1"
      statuses ">= 1.5.0 < 2"
      toidentifier "1.0.0"
  
  https-browserify@1.0.0, https-browserify@^1.0.0:
    version "1.0.0"
    resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
    integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
  
  iconv-lite@0.4.24:
    version "0.4.24"
    resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
    integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
    dependencies:
      safer-buffer ">= 2.1.2 < 3"
  
  iconv-lite@^0.6.2:
    version "0.6.3"
    resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
    integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
    dependencies:
      safer-buffer ">= 2.1.2 < 3.0.0"
  
  ieee754@^1.1.4:
    version "1.2.1"
    resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
    integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
  
  ignore@^4.0.6:
    version "4.0.6"
    resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
    integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
  
  ignore@^5.1.4:
    version "5.1.8"
    resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
    integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
  
  image-size@1.0.0:
    version "1.0.0"
    resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.0.0.tgz#58b31fe4743b1cec0a0ac26f5c914d3c5b2f0750"
    integrity sha512-JLJ6OwBfO1KcA+TvJT+v8gbE6iWbj24LyDNFgFEN0lzegn6cC6a/p3NIDaepMsJjQjlUWqIC7wJv8lBFxPNjcw==
    dependencies:
      queue "6.0.2"
  
  import-fresh@^3.0.0, import-fresh@^3.2.1:
    version "3.3.0"
    resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
    integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
    dependencies:
      parent-module "^1.0.0"
      resolve-from "^4.0.0"
  
  imurmurhash@^0.1.4:
    version "0.1.4"
    resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
    integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
  
  inflight@^1.0.4:
    version "1.0.6"
    resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
    integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
    dependencies:
      once "^1.3.0"
      wrappy "1"
  
  inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4:
    version "2.0.4"
    resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
    integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
  
  inherits@2.0.1:
    version "2.0.1"
    resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
    integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=
  
  inherits@2.0.3:
    version "2.0.3"
    resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
    integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
  
  internal-slot@^1.0.3:
    version "1.0.3"
    resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
    integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==
    dependencies:
      get-intrinsic "^1.1.0"
      has "^1.0.3"
      side-channel "^1.0.4"
  
  is-arguments@^1.0.4:
    version "1.1.1"
    resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b"
    integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==
    dependencies:
      call-bind "^1.0.2"
      has-tostringtag "^1.0.0"
  
  is-arrayish@^0.2.1:
    version "0.2.1"
    resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
    integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
  
  is-bigint@^1.0.1:
    version "1.0.4"
    resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
    integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==
    dependencies:
      has-bigints "^1.0.1"
  
  is-binary-path@~2.1.0:
    version "2.1.0"
    resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
    integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
    dependencies:
      binary-extensions "^2.0.0"
  
  is-boolean-object@^1.1.0:
    version "1.1.2"
    resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719"
    integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==
    dependencies:
      call-bind "^1.0.2"
      has-tostringtag "^1.0.0"
  
  is-callable@^1.1.4, is-callable@^1.2.4:
    version "1.2.4"
    resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945"
    integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==
  
  is-core-module@^2.2.0, is-core-module@^2.6.0:
    version "2.6.0"
    resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.6.0.tgz#d7553b2526fe59b92ba3e40c8df757ec8a709e19"
    integrity sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==
    dependencies:
      has "^1.0.3"
  
  is-date-object@^1.0.1:
    version "1.0.5"
    resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
    integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
    dependencies:
      has-tostringtag "^1.0.0"
  
  is-extglob@^2.1.1:
    version "2.1.1"
    resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
    integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
  
  is-fullwidth-code-point@^3.0.0:
    version "3.0.0"
    resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
    integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
  
  is-generator-function@^1.0.7:
    version "1.0.10"
    resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72"
    integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==
    dependencies:
      has-tostringtag "^1.0.0"
  
  is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
    version "4.0.1"
    resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
    integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
    dependencies:
      is-extglob "^2.1.1"
  
  is-nan@^1.2.1:
    version "1.3.2"
    resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d"
    integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==
    dependencies:
      call-bind "^1.0.0"
      define-properties "^1.1.3"
  
  is-negative-zero@^2.0.1:
    version "2.0.1"
    resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24"
    integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==
  
  is-number-object@^1.0.4:
    version "1.0.6"
    resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0"
    integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==
    dependencies:
      has-tostringtag "^1.0.0"
  
  is-number@^7.0.0:
    version "7.0.0"
    resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
    integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
  
  is-regex@^1.1.4:
    version "1.1.4"
    resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
    integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
    dependencies:
      call-bind "^1.0.2"
      has-tostringtag "^1.0.0"
  
  is-string@^1.0.5, is-string@^1.0.7:
    version "1.0.7"
    resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd"
    integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==
    dependencies:
      has-tostringtag "^1.0.0"
  
  is-symbol@^1.0.2, is-symbol@^1.0.3:
    version "1.0.4"
    resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c"
    integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==
    dependencies:
      has-symbols "^1.0.2"
  
  is-typed-array@^1.1.3, is-typed-array@^1.1.7:
    version "1.1.8"
    resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.8.tgz#cbaa6585dc7db43318bc5b89523ea384a6f65e79"
    integrity sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==
    dependencies:
      available-typed-arrays "^1.0.5"
      call-bind "^1.0.2"
      es-abstract "^1.18.5"
      foreach "^2.0.5"
      has-tostringtag "^1.0.0"
  
  isarray@^1.0.0, isarray@~1.0.0:
    version "1.0.0"
    resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
    integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
  
  isexe@^2.0.0:
    version "2.0.0"
    resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
    integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
  
  jest-worker@27.0.0-next.5:
    version "27.0.0-next.5"
    resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.0.0-next.5.tgz#5985ee29b12a4e191f4aae4bb73b97971d86ec28"
    integrity sha512-mk0umAQ5lT+CaOJ+Qp01N6kz48sJG2kr2n1rX0koqKf6FIygQV0qLOdN9SCYID4IVeSigDOcPeGLozdMLYfb5g==
    dependencies:
      "@types/node" "*"
      merge-stream "^2.0.0"
      supports-color "^8.0.0"
  
  "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
    version "4.0.0"
    resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
    integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
  
  js-yaml@^3.13.1:
    version "3.14.1"
    resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
    integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
    dependencies:
      argparse "^1.0.7"
      esprima "^4.0.0"
  
  json-parse-better-errors@^1.0.1:
    version "1.0.2"
    resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
    integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
  
  json-schema-traverse@^0.4.1:
    version "0.4.1"
    resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
    integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
  
  json-schema-traverse@^1.0.0:
    version "1.0.0"
    resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
    integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
  
  json-stable-stringify-without-jsonify@^1.0.1:
    version "1.0.1"
    resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
    integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
  
  json5@^1.0.1:
    version "1.0.1"
    resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
    integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
    dependencies:
      minimist "^1.2.0"
  
  "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.1.0:
    version "3.2.1"
    resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b"
    integrity sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==
    dependencies:
      array-includes "^3.1.3"
      object.assign "^4.1.2"
  
  language-subtag-registry@~0.3.2:
    version "0.3.21"
    resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a"
    integrity sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==
  
  language-tags@^1.0.5:
    version "1.0.5"
    resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a"
    integrity sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=
    dependencies:
      language-subtag-registry "~0.3.2"
  
  levn@^0.4.1:
    version "0.4.1"
    resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
    integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
    dependencies:
      prelude-ls "^1.2.1"
      type-check "~0.4.0"
  
  load-json-file@^4.0.0:
    version "4.0.0"
    resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
    integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs=
    dependencies:
      graceful-fs "^4.1.2"
      parse-json "^4.0.0"
      pify "^3.0.0"
      strip-bom "^3.0.0"
  
  loader-utils@1.2.3:
    version "1.2.3"
    resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7"
    integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==
    dependencies:
      big.js "^5.2.2"
      emojis-list "^2.0.0"
      json5 "^1.0.1"
  
  locate-path@^2.0.0:
    version "2.0.0"
    resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
    integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
    dependencies:
      p-locate "^2.0.0"
      path-exists "^3.0.0"
  
  locate-path@^5.0.0:
    version "5.0.0"
    resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
    integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
    dependencies:
      p-locate "^4.1.0"
  
  lodash.clonedeep@^4.5.0:
    version "4.5.0"
    resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
    integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
  
  lodash.merge@^4.6.2:
    version "4.6.2"
    resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
    integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
  
  lodash.sortby@^4.7.0:
    version "4.7.0"
    resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
    integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
  
  lodash.truncate@^4.4.2:
    version "4.4.2"
    resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
    integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=
  
  loose-envify@^1.1.0, loose-envify@^1.4.0:
    version "1.4.0"
    resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
    integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
    dependencies:
      js-tokens "^3.0.0 || ^4.0.0"
  
  lru-cache@^6.0.0:
    version "6.0.0"
    resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
    integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
    dependencies:
      yallist "^4.0.0"
  
  make-dir@^3.0.2:
    version "3.1.0"
    resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
    integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
    dependencies:
      semver "^6.0.0"
  
  md5.js@^1.3.4:
    version "1.3.5"
    resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
    integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==
    dependencies:
      hash-base "^3.0.0"
      inherits "^2.0.1"
      safe-buffer "^5.1.2"
  
  merge-stream@^2.0.0:
    version "2.0.0"
    resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
    integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
  
  merge2@^1.3.0:
    version "1.4.1"
    resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
    integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
  
  micromatch@^4.0.4:
    version "4.0.4"
    resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9"
    integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==
    dependencies:
      braces "^3.0.1"
      picomatch "^2.2.3"
  
  miller-rabin@^4.0.0:
    version "4.0.1"
    resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
    integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==
    dependencies:
      bn.js "^4.0.0"
      brorand "^1.0.1"
  
  minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
    version "1.0.1"
    resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
    integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
  
  minimalistic-crypto-utils@^1.0.1:
    version "1.0.1"
    resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
    integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
  
  minimatch@^3.0.4:
    version "3.0.4"
    resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
    integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
    dependencies:
      brace-expansion "^1.1.7"
  
  minimist@^1.2.0:
    version "1.2.5"
    resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
    integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
  
  ms@2.0.0:
    version "2.0.0"
    resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
    integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
  
  ms@2.1.2:
    version "2.1.2"
    resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
    integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
  
  ms@^2.1.1:
    version "2.1.3"
    resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
    integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
  
  nanocolors@^0.1.0:
    version "0.1.12"
    resolved "https://registry.yarnpkg.com/nanocolors/-/nanocolors-0.1.12.tgz#8577482c58cbd7b5bb1681db4cf48f11a87fd5f6"
    integrity sha512-2nMHqg1x5PU+unxX7PGY7AuYxl2qDx7PSrTRjizr8sxdd3l/3hBuWWaki62qmtYm2U5i4Z5E7GbjlyDFhs9/EQ==
  
  nanoid@^3.1.23:
    version "3.1.25"
    resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152"
    integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==
  
  native-url@0.3.4:
    version "0.3.4"
    resolved "https://registry.yarnpkg.com/native-url/-/native-url-0.3.4.tgz#29c943172aed86c63cee62c8c04db7f5756661f8"
    integrity sha512-6iM8R99ze45ivyH8vybJ7X0yekIcPf5GgLV5K0ENCbmRcaRIDoj37BC8iLEmaaBfqqb8enuZ5p0uhY+lVAbAcA==
    dependencies:
      querystring "^0.2.0"
  
  natural-compare@^1.4.0:
    version "1.4.0"
    resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
    integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
  
  next@11.1.2:
    version "11.1.2"
    resolved "https://registry.yarnpkg.com/next/-/next-11.1.2.tgz#527475787a9a362f1bc916962b0c0655cc05bc91"
    integrity sha512-azEYL0L+wFjv8lstLru3bgvrzPvK0P7/bz6B/4EJ9sYkXeW8r5Bjh78D/Ol7VOg0EIPz0CXoe72hzAlSAXo9hw==
    dependencies:
      "@babel/runtime" "7.15.3"
      "@hapi/accept" "5.0.2"
      "@next/env" "11.1.2"
      "@next/polyfill-module" "11.1.2"
      "@next/react-dev-overlay" "11.1.2"
      "@next/react-refresh-utils" "11.1.2"
      "@node-rs/helper" "1.2.1"
      assert "2.0.0"
      ast-types "0.13.2"
      browserify-zlib "0.2.0"
      browserslist "4.16.6"
      buffer "5.6.0"
      caniuse-lite "^1.0.30001228"
      chalk "2.4.2"
      chokidar "3.5.1"
      constants-browserify "1.0.0"
      crypto-browserify "3.12.0"
      cssnano-simple "3.0.0"
      domain-browser "4.19.0"
      encoding "0.1.13"
      etag "1.8.1"
      find-cache-dir "3.3.1"
      get-orientation "1.1.2"
      https-browserify "1.0.0"
      image-size "1.0.0"
      jest-worker "27.0.0-next.5"
      native-url "0.3.4"
      node-fetch "2.6.1"
      node-html-parser "1.4.9"
      node-libs-browser "^2.2.1"
      os-browserify "0.3.0"
      p-limit "3.1.0"
      path-browserify "1.0.1"
      pnp-webpack-plugin "1.6.4"
      postcss "8.2.15"
      process "0.11.10"
      querystring-es3 "0.2.1"
      raw-body "2.4.1"
      react-is "17.0.2"
      react-refresh "0.8.3"
      stream-browserify "3.0.0"
      stream-http "3.1.1"
      string_decoder "1.3.0"
      styled-jsx "4.0.1"
      timers-browserify "2.0.12"
      tty-browserify "0.0.1"
      use-subscription "1.5.1"
      util "0.12.4"
      vm-browserify "1.1.2"
      watchpack "2.1.1"
    optionalDependencies:
      "@next/swc-darwin-arm64" "11.1.2"
      "@next/swc-darwin-x64" "11.1.2"
      "@next/swc-linux-x64-gnu" "11.1.2"
      "@next/swc-win32-x64-msvc" "11.1.2"
  
  node-fetch@2.6.1:
    version "2.6.1"
    resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
    integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
  
  node-html-parser@1.4.9:
    version "1.4.9"
    resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-1.4.9.tgz#3c8f6cac46479fae5800725edb532e9ae8fd816c"
    integrity sha512-UVcirFD1Bn0O+TSmloHeHqZZCxHjvtIeGdVdGMhyZ8/PWlEiZaZ5iJzR189yKZr8p0FXN58BUeC7RHRkf/KYGw==
    dependencies:
      he "1.2.0"
  
  node-libs-browser@^2.2.1:
    version "2.2.1"
    resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425"
    integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==
    dependencies:
      assert "^1.1.1"
      browserify-zlib "^0.2.0"
      buffer "^4.3.0"
      console-browserify "^1.1.0"
      constants-browserify "^1.0.0"
      crypto-browserify "^3.11.0"
      domain-browser "^1.1.1"
      events "^3.0.0"
      https-browserify "^1.0.0"
      os-browserify "^0.3.0"
      path-browserify "0.0.1"
      process "^0.11.10"
      punycode "^1.2.4"
      querystring-es3 "^0.2.0"
      readable-stream "^2.3.3"
      stream-browserify "^2.0.1"
      stream-http "^2.7.2"
      string_decoder "^1.0.0"
      timers-browserify "^2.0.4"
      tty-browserify "0.0.0"
      url "^0.11.0"
      util "^0.11.0"
      vm-browserify "^1.0.1"
  
  node-releases@^1.1.71:
    version "1.1.76"
    resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.76.tgz#df245b062b0cafbd5282ab6792f7dccc2d97f36e"
    integrity sha512-9/IECtNr8dXNmPWmFXepT0/7o5eolGesHUa3mtr0KlgnCvnZxwh2qensKL42JJY2vQKC3nIBXetFAqR+PW1CmA==
  
  normalize-package-data@^2.3.2:
    version "2.5.0"
    resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
    integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
    dependencies:
      hosted-git-info "^2.1.4"
      resolve "^1.10.0"
      semver "2 || 3 || 4 || 5"
      validate-npm-package-license "^3.0.1"
  
  normalize-path@^3.0.0, normalize-path@~3.0.0:
    version "3.0.0"
    resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
    integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
  
  object-assign@^4.1.1:
    version "4.1.1"
    resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
    integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
  
  object-inspect@^1.11.0, object-inspect@^1.9.0:
    version "1.11.0"
    resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1"
    integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==
  
  object-is@^1.0.1:
    version "1.1.5"
    resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac"
    integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==
    dependencies:
      call-bind "^1.0.2"
      define-properties "^1.1.3"
  
  object-keys@^1.0.12, object-keys@^1.1.1:
    version "1.1.1"
    resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
    integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
  
  object.assign@^4.1.2:
    version "4.1.2"
    resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
    integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==
    dependencies:
      call-bind "^1.0.0"
      define-properties "^1.1.3"
      has-symbols "^1.0.1"
      object-keys "^1.1.1"
  
  object.entries@^1.1.4:
    version "1.1.4"
    resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.4.tgz#43ccf9a50bc5fd5b649d45ab1a579f24e088cafd"
    integrity sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA==
    dependencies:
      call-bind "^1.0.2"
      define-properties "^1.1.3"
      es-abstract "^1.18.2"
  
  object.fromentries@^2.0.4:
    version "2.0.4"
    resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.4.tgz#26e1ba5c4571c5c6f0890cef4473066456a120b8"
    integrity sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ==
    dependencies:
      call-bind "^1.0.2"
      define-properties "^1.1.3"
      es-abstract "^1.18.0-next.2"
      has "^1.0.3"
  
  object.hasown@^1.0.0:
    version "1.0.0"
    resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.0.0.tgz#bdbade33cfacfb25d7f26ae2b6cb870bf99905c2"
    integrity sha512-qYMF2CLIjxxLGleeM0jrcB4kiv3loGVAjKQKvH8pSU/i2VcRRvUNmxbD+nEMmrXRfORhuVJuH8OtSYCZoue3zA==
    dependencies:
      define-properties "^1.1.3"
      es-abstract "^1.18.1"
  
  object.values@^1.1.4:
    version "1.1.4"
    resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.4.tgz#0d273762833e816b693a637d30073e7051535b30"
    integrity sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==
    dependencies:
      call-bind "^1.0.2"
      define-properties "^1.1.3"
      es-abstract "^1.18.2"
  
  once@^1.3.0:
    version "1.4.0"
    resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
    integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
    dependencies:
      wrappy "1"
  
  optionator@^0.9.1:
    version "0.9.1"
    resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
    integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
    dependencies:
      deep-is "^0.1.3"
      fast-levenshtein "^2.0.6"
      levn "^0.4.1"
      prelude-ls "^1.2.1"
      type-check "^0.4.0"
      word-wrap "^1.2.3"
  
  os-browserify@0.3.0, os-browserify@^0.3.0:
    version "0.3.0"
    resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
    integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=
  
  p-limit@3.1.0:
    version "3.1.0"
    resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
    integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
    dependencies:
      yocto-queue "^0.1.0"
  
  p-limit@^1.1.0:
    version "1.3.0"
    resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
    integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
    dependencies:
      p-try "^1.0.0"
  
  p-limit@^2.2.0:
    version "2.3.0"
    resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
    integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
    dependencies:
      p-try "^2.0.0"
  
  p-locate@^2.0.0:
    version "2.0.0"
    resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
    integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
    dependencies:
      p-limit "^1.1.0"
  
  p-locate@^4.1.0:
    version "4.1.0"
    resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
    integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy
Download .txt
gitextract_jnytts6o/

├── .eslintrc.json
├── .gitignore
├── .prettierrc.json
├── README.md
├── __mocks__/
│   └── fileMock.js
├── __tests__/
│   ├── api/
│   │   └── products.http
│   └── unit/
│       ├── cart.test.tsx
│       ├── productsDb.test.ts
│       └── shipping.test.tsx
├── components/
│   ├── Button.tsx
│   ├── Footer.tsx
│   ├── Layout.tsx
│   ├── MenuBar.tsx
│   ├── PageHeadline.tsx
│   ├── ProductCard.tsx
│   └── ProductCardCart.tsx
├── jest.config.js
├── jest.setup.js
├── lib/
│   ├── cart.tsx
│   ├── fetcher.tsx
│   ├── mapToObject.tsx
│   └── stripeHelpers.tsx
├── license.md
├── next-env.d.ts
├── next.config.js
├── package.json
├── pages/
│   ├── _app.tsx
│   ├── _document.tsx
│   ├── api/
│   │   ├── checkout_sessions/
│   │   │   ├── [id].ts
│   │   │   └── index.ts
│   │   └── products/
│   │       └── index.ts
│   ├── cart.tsx
│   ├── confirmation.tsx
│   ├── index.tsx
│   └── products/
│       ├── [slug].tsx
│       └── index.tsx
├── prisma/
│   ├── migrations/
│   │   ├── 20210923095130_init/
│   │   │   └── migration.sql
│   │   └── migration_lock.toml
│   ├── schema.prisma
│   └── seed.ts
├── stitches.config.ts
├── tsconfig.json
├── types.d.ts
└── yarn-error.log
Download .txt
SYMBOL INDEX (20 symbols across 10 files)

FILE: lib/cart.tsx
  type CartItem (line 9) | type CartItem = {
  type CartAction (line 15) | type CartAction =
  type Dispatch (line 19) | type Dispatch = (action: CartAction) => void;
  type CartState (line 21) | type CartState = CartItem[] | [];

FILE: lib/fetcher.tsx
  function fetchGetJSON (line 1) | async function fetchGetJSON(url: string) {
  function fetchPostJSON (line 11) | async function fetchPostJSON(url: string, data?: {}) {

FILE: pages/_app.tsx
  type NextPageWithLayout (line 8) | type NextPageWithLayout = NextPage & {
  type AppPropsWithLayout (line 12) | type AppPropsWithLayout = AppProps & {
  function MyApp (line 16) | function MyApp({ Component, pageProps }: AppPropsWithLayout) {

FILE: pages/_document.tsx
  class MyDocument (line 5) | class MyDocument extends Document {
    method render (line 6) | render() {

FILE: pages/api/checkout_sessions/[id].ts
  function handler (line 8) | async function handler(

FILE: pages/api/checkout_sessions/index.ts
  type ResponseData (line 5) | type ResponseData = {
  function handler (line 9) | async function handler(

FILE: pages/api/products/index.ts
  function handler (line 20) | async function handler(

FILE: prisma/migrations/20210923095130_init/migration.sql
  type "Product" (line 2) | CREATE TABLE "Product" (
  type "Brand" (line 17) | CREATE TABLE "Brand" (
  type "ShippingCode" (line 23) | CREATE TABLE "ShippingCode" (

FILE: prisma/seed.ts
  function main (line 4) | async function main() {

FILE: types.d.ts
  type Tmeta (line 1) | type Tmeta = {
Condensed preview — 44 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (256K chars).
[
  {
    "path": ".eslintrc.json",
    "chars": 62,
    "preview": "{\n  \"extends\": [\"next\", \"next/core-web-vitals\", \"prettier\"]\n}\n"
  },
  {
    "path": ".gitignore",
    "chars": 88,
    "preview": "node_modules\n# Keep environment variables out of version control\n.env\n.env.local\n\n.next\n"
  },
  {
    "path": ".prettierrc.json",
    "chars": 2,
    "preview": "{}"
  },
  {
    "path": "README.md",
    "chars": 7025,
    "preview": "# Teini\n\n> Teini (tiny, [ˈtīnē]) is an extremely small webshop leveraging awesome and free solutions like Github and Ver"
  },
  {
    "path": "__mocks__/fileMock.js",
    "chars": 35,
    "preview": "module.exports = \"test-file-stub\";\n"
  },
  {
    "path": "__tests__/api/products.http",
    "chars": 113,
    "preview": "GET http://localhost:3000/api/products HTTP/1.1\n\n###\n\nGET http://localhost:3000/api/products?page=1 HTTP/1.1\n\n###"
  },
  {
    "path": "__tests__/unit/cart.test.tsx",
    "chars": 4256,
    "preview": "/**\n * @jest-environment jsdom\n */\n\n/**\n * This test file should test the cart feature.\n * Currently, there are three sc"
  },
  {
    "path": "__tests__/unit/productsDb.test.ts",
    "chars": 554,
    "preview": "import { PrismaClient } from \"@prisma/client\";\nconst prisma = new PrismaClient();\n\nafterAll(async () => {\n  await prisma"
  },
  {
    "path": "__tests__/unit/shipping.test.tsx",
    "chars": 5232,
    "preview": "/**\n * @jest-environment jsdom\n */\n\n/**\n * This test file should test the shipping option feature.\n * Currently, there a"
  },
  {
    "path": "components/Button.tsx",
    "chars": 1421,
    "preview": "import { styled, keyframes } from \"../stitches.config\";\n\nconst Button = styled(\"button\", {\n  all: \"unset\",\n  background:"
  },
  {
    "path": "components/Footer.tsx",
    "chars": 339,
    "preview": "import { styled } from \"../stitches.config\";\nimport type { Tmeta } from \"../types\";\n\nconst Wrapper = styled(\"footer\", {\n"
  },
  {
    "path": "components/Layout.tsx",
    "chars": 850,
    "preview": "import { styled, Box } from \"../stitches.config\";\n\nconst LayoutWrapper = styled(\"div\", {\n  background: \"$mauve1\",\n\n  \"@s"
  },
  {
    "path": "components/MenuBar.tsx",
    "chars": 4820,
    "preview": "import Link from \"next/link\";\nimport { styled, keyframes, Box } from \"../stitches.config\";\nimport { useCart } from \"../l"
  },
  {
    "path": "components/PageHeadline.tsx",
    "chars": 601,
    "preview": "import { styled, Box } from \"../stitches.config\";\n\nconst Headline = styled(\"h1\", {\n  all: \"unset\",\n  color: \"$crimson12\""
  },
  {
    "path": "components/ProductCard.tsx",
    "chars": 2653,
    "preview": "import Link from \"next/link\";\nimport Image from \"next/image\";\nimport { styled, Box } from \"../stitches.config\";\nimport {"
  },
  {
    "path": "components/ProductCardCart.tsx",
    "chars": 4000,
    "preview": "import Link from \"next/link\";\nimport Image from \"next/image\";\nimport { styled, Box } from \"../stitches.config\";\nimport {"
  },
  {
    "path": "jest.config.js",
    "chars": 1098,
    "preview": "module.exports = {\n  collectCoverageFrom: [\n    \"**/*.{js,jsx,ts,tsx}\",\n    \"!**/*.d.ts\",\n    \"!**/node_modules/**\",\n  ]"
  },
  {
    "path": "jest.setup.js",
    "chars": 299,
    "preview": "import \"@testing-library/jest-dom/extend-expect\";\n\njest.mock(\"next/image\", () => ({\n  __esModule: true,\n  default: (prop"
  },
  {
    "path": "lib/cart.tsx",
    "chars": 2935,
    "preview": "import { Prisma } from \"@prisma/client\";\nimport {\n  createContext,\n  useReducer,\n  FunctionComponent,\n  useContext,\n} fr"
  },
  {
    "path": "lib/fetcher.tsx",
    "chars": 1120,
    "preview": "export async function fetchGetJSON(url: string) {\n  try {\n    const data = await fetch(url).then((res) => res.json());\n "
  },
  {
    "path": "lib/mapToObject.tsx",
    "chars": 445,
    "preview": "export const replacer = (key: any, value: any) => {\n  if (value instanceof Map) {\n    return {\n      dataType: \"Map\",\n  "
  },
  {
    "path": "lib/stripeHelpers.tsx",
    "chars": 1467,
    "preview": "import { Prisma } from \"@prisma/client\";\nimport type { CartItem } from \"./cart\";\n\nexport const cartItemToLineItem = ({\n "
  },
  {
    "path": "license.md",
    "chars": 1063,
    "preview": "MIT License\n\nCopyright (c) 2021 zeekrey\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof"
  },
  {
    "path": "next-env.d.ts",
    "chars": 245,
    "preview": "/// <reference types=\"next\" />\n/// <reference types=\"next/types/global\" />\n/// <reference types=\"next/image-types/global"
  },
  {
    "path": "next.config.js",
    "chars": 166,
    "preview": "/** @type {import('next').NextConfig} */\nmodule.exports = {\n  reactStrictMode: true,\n  serverRuntimeConfig: {\n    PROJEC"
  },
  {
    "path": "package.json",
    "chars": 1527,
    "preview": "{\n  \"name\": \"my-app\",\n  \"version\": \"0.2.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build\": \"next "
  },
  {
    "path": "pages/_app.tsx",
    "chars": 995,
    "preview": "import type { NextPage } from \"next\";\nimport type { AppProps } from \"next/app\";\nimport { globalStyles, darkTheme } from "
  },
  {
    "path": "pages/_document.tsx",
    "chars": 726,
    "preview": "// eslint-disable-next-line @next/next/no-document-import-in-page\nimport Document, { Html, Head, Main, NextScript } from"
  },
  {
    "path": "pages/api/checkout_sessions/[id].ts",
    "chars": 738,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport Stripe from \"stripe\";\n\nconst stripe = new Stripe(process."
  },
  {
    "path": "pages/api/checkout_sessions/index.ts",
    "chars": 1112,
    "preview": "import type { NextApiRequest, NextApiResponse } from \"next\";\n\nconst stripe = require(\"stripe\")(process.env.STRIPE_SECRET"
  },
  {
    "path": "pages/api/products/index.ts",
    "chars": 2335,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport { PrismaClient } from \"@prisma/client\";\nimport { getPlaic"
  },
  {
    "path": "pages/cart.tsx",
    "chars": 8586,
    "preview": "import Button, { Loading } from \"../components/Button\";\nimport { styled, Box } from \"../stitches.config\";\nimport { Prism"
  },
  {
    "path": "pages/confirmation.tsx",
    "chars": 3722,
    "preview": "import { styled, Box } from \"../stitches.config\";\nimport useSWR from \"swr\";\nimport { useRouter } from \"next/router\";\nimp"
  },
  {
    "path": "pages/index.tsx",
    "chars": 4789,
    "preview": "import { GetStaticProps } from \"next\";\nimport Link from \"next/link\";\nimport { PrismaClient, Prisma } from \"@prisma/clien"
  },
  {
    "path": "pages/products/[slug].tsx",
    "chars": 6917,
    "preview": "import { GetStaticPaths, GetStaticProps, NextPage } from \"next\";\nimport Image from \"next/image\";\nimport { promises as fs"
  },
  {
    "path": "pages/products/index.tsx",
    "chars": 5771,
    "preview": "import { GetStaticProps } from \"next\";\nimport { promises as fs } from \"fs\";\nimport React, { useState } from \"react\";\nimp"
  },
  {
    "path": "prisma/migrations/20210923095130_init/migration.sql",
    "chars": 935,
    "preview": "-- CreateTable\nCREATE TABLE \"Product\" (\n    \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n    \"createdAt\" DATETIME NO"
  },
  {
    "path": "prisma/migrations/migration_lock.toml",
    "chars": 122,
    "preview": "# Please do not edit this file manually\n# It should be added in your version-control system (i.e. Git)\nprovider = \"sqlit"
  },
  {
    "path": "prisma/schema.prisma",
    "chars": 791,
    "preview": "datasource db {\n  provider = \"sqlite\"\n  url      = \"file:../products.db\"\n}\n\ngenerator client {\n  provider = \"prisma-clie"
  },
  {
    "path": "prisma/seed.ts",
    "chars": 6321,
    "preview": "import { PrismaClient } from \"@prisma/client\";\nconst prisma = new PrismaClient();\n\nasync function main() {\n  const brand"
  },
  {
    "path": "stitches.config.ts",
    "chars": 1389,
    "preview": "import { createStitches } from \"@stitches/react\";\nimport { crimson, crimsonDark, mauve, mauveDark } from \"@radix-ui/colo"
  },
  {
    "path": "tsconfig.json",
    "chars": 609,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    "
  },
  {
    "path": "types.d.ts",
    "chars": 128,
    "preview": "export type Tmeta = {\n  headline: string;\n  subheadline: string;\n  contact: string;\n  name: string;\n  [key: string]: str"
  },
  {
    "path": "yarn-error.log",
    "chars": 153115,
    "preview": "Arguments: \n  C:\\Program Files\\nodejs\\node.exe C:\\Program Files (x86)\\Yarn\\bin\\yarn.js add -D prisma@3.1.1\n\nPATH: \n  C:\\"
  }
]

About this extraction

This page contains the full source code of the zeekrey/teini GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 44 files (235.9 KB), approximately 93.9k tokens, and a symbol index with 20 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!