? inferRaw : never;
25 | export declare type inferParsedPropertySchema
| Schema> = P extends Property ? Parsed : P extends Schema ? inferParsed : never;
26 | export declare type inferRawKey | Schema> = P extends Property ? Raw : ParsedKey;
27 |
--------------------------------------------------------------------------------
/backend/src/fern_fastapi_starter/api/generated/resources/imdb/service/service.py:
--------------------------------------------------------------------------------
1 | # This file was auto-generated by Fern from our API Definition.
2 |
3 | import abc
4 | import functools
5 | import inspect
6 | import logging
7 | import typing
8 |
9 | import fastapi
10 |
11 | from ....core.abstract_fern_service import AbstractFernService
12 | from ....core.exceptions.fern_http_exception import FernHTTPException
13 | from ....core.route_args import get_route_args
14 | from ..errors.movie_does_not_exist_error import MovieDoesNotExistError
15 | from ..types.movie import Movie
16 |
17 |
18 | class AbstractImdbService(AbstractFernService):
19 | """
20 | AbstractImdbService is an abstract class containing the methods that you should implement.
21 |
22 | Each method is associated with an API route, which will be registered
23 | with FastAPI when you register your implementation using Fern's register()
24 | function.
25 | """
26 |
27 | @abc.abstractmethod
28 | def get_movie(self, *, movie_id: str) -> Movie:
29 | ...
30 |
31 | """
32 | Below are internal methods used by Fern to register your implementation.
33 | You can ignore them.
34 | """
35 |
36 | @classmethod
37 | def _init_fern(cls, router: fastapi.APIRouter) -> None:
38 | cls.__init_get_movie(router=router)
39 |
40 | @classmethod
41 | def __init_get_movie(cls, router: fastapi.APIRouter) -> None:
42 | endpoint_function = inspect.signature(cls.get_movie)
43 | new_parameters: typing.List[inspect.Parameter] = []
44 | for index, (parameter_name, parameter) in enumerate(endpoint_function.parameters.items()):
45 | if index == 0:
46 | new_parameters.append(parameter.replace(default=fastapi.Depends(cls)))
47 | elif parameter_name == "movie_id":
48 | new_parameters.append(parameter.replace(default=fastapi.Path(...)))
49 | else:
50 | new_parameters.append(parameter)
51 | setattr(cls.get_movie, "__signature__", endpoint_function.replace(parameters=new_parameters))
52 |
53 | @functools.wraps(cls.get_movie)
54 | def wrapper(*args: typing.Any, **kwargs: typing.Any) -> Movie:
55 | try:
56 | return cls.get_movie(*args, **kwargs)
57 | except MovieDoesNotExistError as e:
58 | raise e
59 | except FernHTTPException as e:
60 | logging.getLogger(f"{cls.__module__}.{cls.__name__}").warn(
61 | f"Endpoint 'get_movie' unexpectedly threw {e.__class__.__name__}. "
62 | + f"If this was intentional, please add {e.__class__.__name__} to "
63 | + "the endpoint's errors list in your Fern Definition."
64 | )
65 | raise e
66 |
67 | # this is necessary for FastAPI to find forward-ref'ed type hints.
68 | # https://github.com/tiangolo/fastapi/pull/5077
69 | wrapper.__globals__.update(cls.get_movie.__globals__)
70 |
71 | router.get(
72 | path="/movies/{movie_id}",
73 | response_model=Movie,
74 | description=AbstractImdbService.get_movie.__doc__,
75 | **get_route_args(cls.get_movie, default_tag="imdb"),
76 | )(wrapper)
77 |
--------------------------------------------------------------------------------
/frontend/src/api/generated/core/schemas/builders/record/record.js:
--------------------------------------------------------------------------------
1 | import { SchemaType } from "../../Schema";
2 | import { entries } from "../../utils/entries";
3 | import { isPlainObject, NOT_AN_OBJECT_ERROR_MESSAGE } from "../../utils/isPlainObject";
4 | import { getSchemaUtils } from "../schema-utils";
5 | export function record(keySchema, valueSchema) {
6 | const baseSchema = {
7 | parse: async (raw, opts) => {
8 | return validateAndTransformRecord({
9 | value: raw,
10 | isKeyNumeric: (await keySchema.getType()) === SchemaType.NUMBER,
11 | transformKey: (key) => keySchema.parse(key, opts),
12 | transformValue: (value) => valueSchema.parse(value, opts),
13 | });
14 | },
15 | json: async (parsed, opts) => {
16 | return validateAndTransformRecord({
17 | value: parsed,
18 | isKeyNumeric: (await keySchema.getType()) === SchemaType.NUMBER,
19 | transformKey: (key) => keySchema.json(key, opts),
20 | transformValue: (value) => valueSchema.json(value, opts),
21 | });
22 | },
23 | getType: () => SchemaType.RECORD,
24 | };
25 | return {
26 | ...baseSchema,
27 | ...getSchemaUtils(baseSchema),
28 | };
29 | }
30 | async function validateAndTransformRecord({ value, isKeyNumeric, transformKey, transformValue, }) {
31 | if (!isPlainObject(value)) {
32 | return {
33 | ok: false,
34 | errors: [
35 | {
36 | path: [],
37 | message: NOT_AN_OBJECT_ERROR_MESSAGE,
38 | },
39 | ],
40 | };
41 | }
42 | return entries(value).reduce(async (accPromise, [stringKey, value]) => {
43 | // skip nullish keys
44 | if (value == null) {
45 | return accPromise;
46 | }
47 | const acc = await accPromise;
48 | let key = stringKey;
49 | if (isKeyNumeric) {
50 | const numberKey = stringKey.length > 0 ? Number(stringKey) : NaN;
51 | if (!isNaN(numberKey)) {
52 | key = numberKey;
53 | }
54 | }
55 | const transformedKey = await transformKey(key);
56 | const transformedValue = await transformValue(value);
57 | if (acc.ok && transformedKey.ok && transformedValue.ok) {
58 | return {
59 | ok: true,
60 | value: {
61 | ...acc.value,
62 | [transformedKey.value]: transformedValue.value,
63 | },
64 | };
65 | }
66 | const errors = [];
67 | if (!acc.ok) {
68 | errors.push(...acc.errors);
69 | }
70 | if (!transformedKey.ok) {
71 | errors.push(...transformedKey.errors.map((error) => ({
72 | path: [`${key} (key)`, ...error.path],
73 | message: error.message,
74 | })));
75 | }
76 | if (!transformedValue.ok) {
77 | errors.push(...transformedValue.errors.map((error) => ({
78 | path: [stringKey, ...error.path],
79 | message: error.message,
80 | })));
81 | }
82 | return {
83 | ok: false,
84 | errors,
85 | };
86 | }, Promise.resolve({ ok: true, value: {} }));
87 | }
88 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Starter repo for FastAPI + React, using [Fern](https://github.com/fern-api/fern)
2 |
3 | **Fern is an open source format for defining REST APIs.** Fern makes it easy to:
4 |
5 | 1. Define your API
6 | 1. Implement your API on the backend
7 | 1. Consume your API on the frontend
8 |
9 | ## Quick start
10 |
11 | ### Step 1: Fork this repo
12 |
13 | ### Step 2: Clone your fork
14 |
15 | ### Step 3: Generate code
16 |
17 | Most of the code for the backend and frontend is auto-generated by Fern!
18 |
19 | In a terminal, run:
20 |
21 | ```
22 | npm install -g fern-api
23 | fern generate
24 | ```
25 |
26 | ### Step 4: Run the backend
27 |
28 | _Prerequisite: Install [poetry](https://python-poetry.org/docs/)._
29 |
30 | Run:
31 |
32 | ```
33 | cd backend
34 | poetry install
35 | poetry run start
36 | ```
37 |
38 | ### Step 5: Run the frontend
39 |
40 | In a new terminal, run:
41 |
42 | ```
43 | cd frontend
44 | yarn install
45 | yarn start
46 | ```
47 |
48 | Open [http://localhost:5173](http://localhost:5173) to see the frontend!
49 |
50 | 
51 |
52 | ## Developing the backend
53 |
54 | The [FastAPI](https://fastapi.tiangolo.com/) backend lives in the
55 | [backend](backend/) directory.
56 |
57 | To get started, open a VSCode window for the root of this repo:
58 |
59 | ```
60 | code .
61 | ```
62 |
63 | Install the recommended MyPy extensions. This will give you type checking in the IDE.
64 |
65 | Install dependencies:
66 |
67 | ```
68 | cd backend
69 | poetry install
70 | ```
71 |
72 | Run the server:
73 |
74 | ```
75 | poetry run start
76 | ```
77 |
78 | You can edit the server code, and the server will automatically reload.
79 |
80 | ### Auto-generated server code
81 |
82 | Nearly all the FastAPI and Pydantic code is generated by Fern when you run `fern generate`.
83 | The generated code lives in [backend/src/fern_fastapi_starter/api/generated](backend/src/fern_fastapi_starter/api/generated).
84 |
85 | In addition to saving you time, the auto-generated code gives you compile-time safety
86 | that your API is implemented correctly. For example, if you forget to define the `getMovie`
87 | endpoint, you'll get a compile error:
88 |
89 | 
90 |
91 | ## Developing the frontend
92 |
93 | The frontend is generated using [React](https://reactjs.org/),
94 | [TypeScript](https://www.typescriptlang.org/) and [Vite](https://vitejs.dev/).
95 |
96 | To get started, open a new VSCode window for the `frontend/` directory:
97 |
98 | ```
99 | cd frontend
100 | code .
101 | ```
102 |
103 | Install dependencies:
104 |
105 | ```
106 | yarn install
107 | ```
108 |
109 | Run the frontend:
110 |
111 | ```
112 | yarn start
113 | ```
114 |
115 | Open [http://localhost:5173](http://localhost:5173) to see the frontend!
116 |
117 | You can edit the frontend code, and Vite will automatically reload your changes.
118 |
119 | ### Auto-generated API client
120 |
121 | The API client is automatically generated by Fern when you run `fern generate`.
122 | The generated client lives in [frontend/src/api/generated](frontend/src/api/generated). You can see it used
123 | in [frontend/src/App.tsx](frontend/src/App.tsx),
124 |
125 | In addition to saving you time, the auto-generated code gives you compile-time safety
126 | and autocomplete:
127 |
128 | 
129 |
130 | ## Changing the API
131 |
132 | The API is defined using [Fern](https://www.buildwithfern.com/). The definition
133 | lives in the [fern/](fern/api/definition) directory. You can edit these YAML files
134 | to update the API. Check out the [docs](https://docs.buildwithfern.com/definition) to read more about defining APIs.
135 |
136 | Most of the server and frontend code in this repo is **automatically generated
137 | by Fern.** You can regenerate the code using the Fern CLI:
138 |
139 | ```
140 | npm install -g fern
141 | fern generate
142 | ```
143 |
144 | This will output newly generated code:
145 |
146 | - Backend: [backend/src/fern_fastapi_starter/api/generated](backend/src/fern_fastapi_starter/api/generated)
147 | - Frontend: [frontend/src/api/generated](frontend/src/api/generated)
148 |
149 | When you change your API, you'll get compile errors on the backend if you're not
150 | implementing the API correctly.
151 |
152 | You can always use the command line to run mypy as well:
153 |
154 | ```
155 | poetry run mypy
156 | ```
157 |
158 | ## Issues & contributing
159 |
160 | If you run into any problems while using this ticket, plesae [file an
161 | issue](https://github.com/fern-api/fastapi-starter/issues). Of course, PRs are
162 | welcome and encouraged!
163 |
--------------------------------------------------------------------------------
/frontend/src/api/generated/core/schemas/builders/union/union.js:
--------------------------------------------------------------------------------
1 | import { SchemaType } from "../../Schema";
2 | import { isPlainObject, NOT_AN_OBJECT_ERROR_MESSAGE } from "../../utils/isPlainObject";
3 | import { keys } from "../../utils/keys";
4 | import { enum_ } from "../enum";
5 | import { getObjectLikeUtils } from "../object-like";
6 | import { getSchemaUtils } from "../schema-utils";
7 | export function union(discriminant, union) {
8 | const rawDiscriminant = typeof discriminant === "string" ? discriminant : discriminant.rawDiscriminant;
9 | const parsedDiscriminant = typeof discriminant === "string"
10 | ? discriminant
11 | : discriminant.parsedDiscriminant;
12 | const discriminantValueSchema = enum_(keys(union));
13 | const baseSchema = {
14 | parse: async (raw, opts) => {
15 | return transformAndValidateUnion({
16 | value: raw,
17 | discriminant: rawDiscriminant,
18 | transformedDiscriminant: parsedDiscriminant,
19 | transformDiscriminantValue: (discriminantValue) => discriminantValueSchema.parse(discriminantValue, {
20 | allowUnrecognizedEnumValues: opts?.allowUnrecognizedUnionMembers,
21 | }),
22 | getAdditionalPropertiesSchema: (discriminantValue) => union[discriminantValue],
23 | allowUnrecognizedUnionMembers: opts?.allowUnrecognizedUnionMembers,
24 | transformAdditionalProperties: (additionalProperties, additionalPropertiesSchema) => additionalPropertiesSchema.parse(additionalProperties, opts),
25 | });
26 | },
27 | json: async (parsed, opts) => {
28 | return transformAndValidateUnion({
29 | value: parsed,
30 | discriminant: parsedDiscriminant,
31 | transformedDiscriminant: rawDiscriminant,
32 | transformDiscriminantValue: (discriminantValue) => discriminantValueSchema.json(discriminantValue, {
33 | allowUnrecognizedEnumValues: opts?.allowUnrecognizedUnionMembers,
34 | }),
35 | getAdditionalPropertiesSchema: (discriminantValue) => union[discriminantValue],
36 | allowUnrecognizedUnionMembers: opts?.allowUnrecognizedUnionMembers,
37 | transformAdditionalProperties: (additionalProperties, additionalPropertiesSchema) => additionalPropertiesSchema.json(additionalProperties, opts),
38 | });
39 | },
40 | getType: () => SchemaType.UNION,
41 | };
42 | return {
43 | ...baseSchema,
44 | ...getSchemaUtils(baseSchema),
45 | ...getObjectLikeUtils(baseSchema),
46 | };
47 | }
48 | async function transformAndValidateUnion({ value, discriminant, transformedDiscriminant, transformDiscriminantValue, getAdditionalPropertiesSchema, allowUnrecognizedUnionMembers = false, transformAdditionalProperties, }) {
49 | if (!isPlainObject(value)) {
50 | return {
51 | ok: false,
52 | errors: [
53 | {
54 | path: [],
55 | message: NOT_AN_OBJECT_ERROR_MESSAGE,
56 | },
57 | ],
58 | };
59 | }
60 | const { [discriminant]: discriminantValue, ...additionalProperties } = value;
61 | if (discriminantValue == null) {
62 | return {
63 | ok: false,
64 | errors: [
65 | {
66 | path: [],
67 | message: `Missing discriminant ("${discriminant}")`,
68 | },
69 | ],
70 | };
71 | }
72 | const transformedDiscriminantValue = await transformDiscriminantValue(discriminantValue);
73 | if (!transformedDiscriminantValue.ok) {
74 | return {
75 | ok: false,
76 | errors: transformedDiscriminantValue.errors.map((error) => ({
77 | path: [discriminant, ...error.path],
78 | message: error.message,
79 | })),
80 | };
81 | }
82 | const additionalPropertiesSchema = getAdditionalPropertiesSchema(transformedDiscriminantValue.value);
83 | if (additionalPropertiesSchema == null) {
84 | if (allowUnrecognizedUnionMembers) {
85 | return {
86 | ok: true,
87 | value: {
88 | [transformedDiscriminant]: transformedDiscriminantValue.value,
89 | ...additionalProperties,
90 | },
91 | };
92 | }
93 | else {
94 | return {
95 | ok: false,
96 | errors: [
97 | {
98 | path: [discriminant],
99 | message: "Unrecognized discriminant value",
100 | },
101 | ],
102 | };
103 | }
104 | }
105 | const transformedAdditionalProperties = await transformAdditionalProperties(additionalProperties, additionalPropertiesSchema);
106 | if (!transformedAdditionalProperties.ok) {
107 | return transformedAdditionalProperties;
108 | }
109 | return {
110 | ok: true,
111 | value: {
112 | [transformedDiscriminant]: discriminantValue,
113 | ...transformedAdditionalProperties.value,
114 | },
115 | };
116 | }
117 |
--------------------------------------------------------------------------------
/frontend/src/api/generated/core/schemas/builders/object/object.js:
--------------------------------------------------------------------------------
1 | import { SchemaType } from "../../Schema";
2 | import { entries } from "../../utils/entries";
3 | import { filterObject } from "../../utils/filterObject";
4 | import { isPlainObject, NOT_AN_OBJECT_ERROR_MESSAGE } from "../../utils/isPlainObject";
5 | import { keys } from "../../utils/keys";
6 | import { partition } from "../../utils/partition";
7 | import { getObjectLikeUtils } from "../object-like";
8 | import { getSchemaUtils } from "../schema-utils";
9 | import { isProperty } from "./property";
10 | export function object(schemas) {
11 | const baseSchema = {
12 | _getRawProperties: () => Promise.resolve(Object.entries(schemas).map(([parsedKey, propertySchema]) => isProperty(propertySchema) ? propertySchema.rawKey : parsedKey)),
13 | _getParsedProperties: () => Promise.resolve(keys(schemas)),
14 | parse: async (raw, opts) => {
15 | const rawKeyToProperty = {};
16 | const requiredKeys = [];
17 | for (const [parsedKey, schemaOrObjectProperty] of entries(schemas)) {
18 | const rawKey = isProperty(schemaOrObjectProperty) ? schemaOrObjectProperty.rawKey : parsedKey;
19 | const valueSchema = isProperty(schemaOrObjectProperty)
20 | ? schemaOrObjectProperty.valueSchema
21 | : schemaOrObjectProperty;
22 | const property = {
23 | rawKey,
24 | parsedKey: parsedKey,
25 | valueSchema,
26 | };
27 | rawKeyToProperty[rawKey] = property;
28 | if (await isSchemaRequired(valueSchema)) {
29 | requiredKeys.push(rawKey);
30 | }
31 | }
32 | return validateAndTransformObject({
33 | value: raw,
34 | requiredKeys,
35 | getProperty: (rawKey) => {
36 | const property = rawKeyToProperty[rawKey];
37 | if (property == null) {
38 | return undefined;
39 | }
40 | return {
41 | transformedKey: property.parsedKey,
42 | transform: (propertyValue) => property.valueSchema.parse(propertyValue, opts),
43 | };
44 | },
45 | unrecognizedObjectKeys: opts?.unrecognizedObjectKeys,
46 | });
47 | },
48 | json: async (parsed, opts) => {
49 | const requiredKeys = [];
50 | for (const [parsedKey, schemaOrObjectProperty] of entries(schemas)) {
51 | const valueSchema = isProperty(schemaOrObjectProperty)
52 | ? schemaOrObjectProperty.valueSchema
53 | : schemaOrObjectProperty;
54 | if (await isSchemaRequired(valueSchema)) {
55 | requiredKeys.push(parsedKey);
56 | }
57 | }
58 | return validateAndTransformObject({
59 | value: parsed,
60 | requiredKeys,
61 | getProperty: (parsedKey) => {
62 | const property = schemas[parsedKey];
63 | // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
64 | if (property == null) {
65 | return undefined;
66 | }
67 | if (isProperty(property)) {
68 | return {
69 | transformedKey: property.rawKey,
70 | transform: (propertyValue) => property.valueSchema.json(propertyValue, opts),
71 | };
72 | }
73 | else {
74 | return {
75 | transformedKey: parsedKey,
76 | transform: (propertyValue) => property.json(propertyValue, opts),
77 | };
78 | }
79 | },
80 | unrecognizedObjectKeys: opts?.unrecognizedObjectKeys,
81 | });
82 | },
83 | getType: () => SchemaType.OBJECT,
84 | };
85 | return {
86 | ...baseSchema,
87 | ...getSchemaUtils(baseSchema),
88 | ...getObjectLikeUtils(baseSchema),
89 | ...getObjectUtils(baseSchema),
90 | };
91 | }
92 | async function validateAndTransformObject({ value, requiredKeys, getProperty, unrecognizedObjectKeys = "fail", }) {
93 | if (!isPlainObject(value)) {
94 | return {
95 | ok: false,
96 | errors: [
97 | {
98 | path: [],
99 | message: NOT_AN_OBJECT_ERROR_MESSAGE,
100 | },
101 | ],
102 | };
103 | }
104 | const missingRequiredKeys = new Set(requiredKeys);
105 | const errors = [];
106 | const transformed = {};
107 | for (const [preTransformedKey, preTransformedItemValue] of Object.entries(value)) {
108 | const property = getProperty(preTransformedKey);
109 | if (property != null) {
110 | missingRequiredKeys.delete(preTransformedKey);
111 | const value = await property.transform(preTransformedItemValue);
112 | if (value.ok) {
113 | transformed[property.transformedKey] = value.value;
114 | }
115 | else {
116 | errors.push(...value.errors.map((error) => ({
117 | path: [preTransformedKey, ...error.path],
118 | message: error.message,
119 | })));
120 | }
121 | }
122 | else {
123 | switch (unrecognizedObjectKeys) {
124 | case "fail":
125 | errors.push({
126 | path: [preTransformedKey],
127 | message: `Unrecognized key "${preTransformedKey}"`,
128 | });
129 | break;
130 | case "strip":
131 | break;
132 | case "passthrough":
133 | transformed[preTransformedKey] = preTransformedItemValue;
134 | break;
135 | }
136 | }
137 | }
138 | errors.push(...requiredKeys
139 | .filter((key) => missingRequiredKeys.has(key))
140 | .map((key) => ({
141 | path: [],
142 | message: `Missing required key "${key}"`,
143 | })));
144 | if (errors.length === 0) {
145 | return {
146 | ok: true,
147 | value: transformed,
148 | };
149 | }
150 | else {
151 | return {
152 | ok: false,
153 | errors,
154 | };
155 | }
156 | }
157 | export function getObjectUtils(schema) {
158 | return {
159 | extend: (extension) => {
160 | const baseSchema = {
161 | _getParsedProperties: async () => [
162 | ...(await schema._getParsedProperties()),
163 | ...(await extension._getParsedProperties()),
164 | ],
165 | _getRawProperties: async () => [
166 | ...(await schema._getRawProperties()),
167 | ...(await extension._getRawProperties()),
168 | ],
169 | parse: async (raw, opts) => {
170 | return validateAndTransformExtendedObject({
171 | extensionKeys: await extension._getRawProperties(),
172 | value: raw,
173 | transformBase: (rawBase) => schema.parse(rawBase, opts),
174 | transformExtension: (rawExtension) => extension.parse(rawExtension, opts),
175 | });
176 | },
177 | json: async (parsed, opts) => {
178 | return validateAndTransformExtendedObject({
179 | extensionKeys: await extension._getParsedProperties(),
180 | value: parsed,
181 | transformBase: (parsedBase) => schema.json(parsedBase, opts),
182 | transformExtension: (parsedExtension) => extension.json(parsedExtension, opts),
183 | });
184 | },
185 | getType: () => SchemaType.OBJECT,
186 | };
187 | return {
188 | ...baseSchema,
189 | ...getSchemaUtils(baseSchema),
190 | ...getObjectLikeUtils(baseSchema),
191 | ...getObjectUtils(baseSchema),
192 | };
193 | },
194 | };
195 | }
196 | async function validateAndTransformExtendedObject({ extensionKeys, value, transformBase, transformExtension, }) {
197 | const extensionPropertiesSet = new Set(extensionKeys);
198 | const [extensionProperties, baseProperties] = partition(keys(value), (key) => extensionPropertiesSet.has(key));
199 | const transformedBase = await transformBase(filterObject(value, baseProperties));
200 | const transformedExtension = await transformExtension(filterObject(value, extensionProperties));
201 | if (transformedBase.ok && transformedExtension.ok) {
202 | return {
203 | ok: true,
204 | value: {
205 | ...transformedBase.value,
206 | ...transformedExtension.value,
207 | },
208 | };
209 | }
210 | else {
211 | return {
212 | ok: false,
213 | errors: [
214 | ...(transformedBase.ok ? [] : transformedBase.errors),
215 | ...(transformedExtension.ok ? [] : transformedExtension.errors),
216 | ],
217 | };
218 | }
219 | }
220 | async function isSchemaRequired(schema) {
221 | return !(await isSchemaOptional(schema));
222 | }
223 | async function isSchemaOptional(schema) {
224 | switch (await schema.getType()) {
225 | case SchemaType.ANY:
226 | case SchemaType.UNKNOWN:
227 | case SchemaType.OPTIONAL:
228 | return true;
229 | default:
230 | return false;
231 | }
232 | }
233 |
--------------------------------------------------------------------------------
/backend/requirements.txt:
--------------------------------------------------------------------------------
1 | anyio==3.6.2 ; python_version >= "3.8" and python_version < "4.0" \
2 | --hash=sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421 \
3 | --hash=sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3
4 | cfgv==3.3.1 ; python_version >= "3.8" and python_version < "4.0" \
5 | --hash=sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426 \
6 | --hash=sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736
7 | click==8.1.3 ; python_version >= "3.8" and python_version < "4.0" \
8 | --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \
9 | --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48
10 | colorama==0.4.6 ; python_version >= "3.8" and python_version < "4.0" and platform_system == "Windows" \
11 | --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
12 | --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
13 | distlib==0.3.6 ; python_version >= "3.8" and python_version < "4.0" \
14 | --hash=sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46 \
15 | --hash=sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e
16 | fastapi-utils==0.2.1 ; python_version >= "3.8" and python_version < "4.0" \
17 | --hash=sha256:0e6c7fc1870b80e681494957abf65d4f4f42f4c7f70005918e9181b22f1bd759 \
18 | --hash=sha256:dd0be7dc7f03fa681b25487a206651d99f2330d5a567fb8ab6cb5f8a06a29360
19 | fastapi==0.79.1 ; python_version >= "3.8" and python_version < "4.0" \
20 | --hash=sha256:006862dec0f0f5683ac21fb0864af2ff12a931e7ba18920f28cc8eceed51896b \
21 | --hash=sha256:3c584179c64e265749e88221c860520fc512ea37e253282dab378cc503dfd7fd
22 | filelock==3.8.2 ; python_version >= "3.8" and python_version < "4.0" \
23 | --hash=sha256:7565f628ea56bfcd8e54e42bdc55da899c85c1abfe1b5bcfd147e9188cebb3b2 \
24 | --hash=sha256:8df285554452285f79c035efb0c861eb33a4bcfa5b7a137016e32e6a90f9792c
25 | greenlet==2.0.1 ; python_version >= "3.8" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version < "4.0" \
26 | --hash=sha256:0109af1138afbfb8ae647e31a2b1ab030f58b21dd8528c27beaeb0093b7938a9 \
27 | --hash=sha256:0459d94f73265744fee4c2d5ec44c6f34aa8a31017e6e9de770f7bcf29710be9 \
28 | --hash=sha256:04957dc96669be041e0c260964cfef4c77287f07c40452e61abe19d647505581 \
29 | --hash=sha256:0722c9be0797f544a3ed212569ca3fe3d9d1a1b13942d10dd6f0e8601e484d26 \
30 | --hash=sha256:097e3dae69321e9100202fc62977f687454cd0ea147d0fd5a766e57450c569fd \
31 | --hash=sha256:0b493db84d124805865adc587532ebad30efa68f79ad68f11b336e0a51ec86c2 \
32 | --hash=sha256:13ba6e8e326e2116c954074c994da14954982ba2795aebb881c07ac5d093a58a \
33 | --hash=sha256:13ebf93c343dd8bd010cd98e617cb4c1c1f352a0cf2524c82d3814154116aa82 \
34 | --hash=sha256:1407fe45246632d0ffb7a3f4a520ba4e6051fc2cbd61ba1f806900c27f47706a \
35 | --hash=sha256:1bf633a50cc93ed17e494015897361010fc08700d92676c87931d3ea464123ce \
36 | --hash=sha256:2d0bac0385d2b43a7bd1d651621a4e0f1380abc63d6fb1012213a401cbd5bf8f \
37 | --hash=sha256:3001d00eba6bbf084ae60ec7f4bb8ed375748f53aeaefaf2a37d9f0370558524 \
38 | --hash=sha256:356e4519d4dfa766d50ecc498544b44c0249b6de66426041d7f8b751de4d6b48 \
39 | --hash=sha256:38255a3f1e8942573b067510f9611fc9e38196077b0c8eb7a8c795e105f9ce77 \
40 | --hash=sha256:3d75b8d013086b08e801fbbb896f7d5c9e6ccd44f13a9241d2bf7c0df9eda928 \
41 | --hash=sha256:41b825d65f31e394b523c84db84f9383a2f7eefc13d987f308f4663794d2687e \
42 | --hash=sha256:42e602564460da0e8ee67cb6d7236363ee5e131aa15943b6670e44e5c2ed0f67 \
43 | --hash=sha256:4aeaebcd91d9fee9aa768c1b39cb12214b30bf36d2b7370505a9f2165fedd8d9 \
44 | --hash=sha256:4c8b1c43e75c42a6cafcc71defa9e01ead39ae80bd733a2608b297412beede68 \
45 | --hash=sha256:4d37990425b4687ade27810e3b1a1c37825d242ebc275066cfee8cb6b8829ccd \
46 | --hash=sha256:4f09b0010e55bec3239278f642a8a506b91034f03a4fb28289a7d448a67f1515 \
47 | --hash=sha256:505138d4fa69462447a562a7c2ef723c6025ba12ac04478bc1ce2fcc279a2db5 \
48 | --hash=sha256:5067920de254f1a2dee8d3d9d7e4e03718e8fd2d2d9db962c8c9fa781ae82a39 \
49 | --hash=sha256:56961cfca7da2fdd178f95ca407fa330c64f33289e1804b592a77d5593d9bd94 \
50 | --hash=sha256:5a8e05057fab2a365c81abc696cb753da7549d20266e8511eb6c9d9f72fe3e92 \
51 | --hash=sha256:659f167f419a4609bc0516fb18ea69ed39dbb25594934bd2dd4d0401660e8a1e \
52 | --hash=sha256:662e8f7cad915ba75d8017b3e601afc01ef20deeeabf281bd00369de196d7726 \
53 | --hash=sha256:6f61d71bbc9b4a3de768371b210d906726535d6ca43506737682caa754b956cd \
54 | --hash=sha256:72b00a8e7c25dcea5946692a2485b1a0c0661ed93ecfedfa9b6687bd89a24ef5 \
55 | --hash=sha256:811e1d37d60b47cb8126e0a929b58c046251f28117cb16fcd371eed61f66b764 \
56 | --hash=sha256:81b0ea3715bf6a848d6f7149d25bf018fd24554a4be01fcbbe3fdc78e890b955 \
57 | --hash=sha256:88c8d517e78acdf7df8a2134a3c4b964415b575d2840a2746ddb1cc6175f8608 \
58 | --hash=sha256:8dca09dedf1bd8684767bc736cc20c97c29bc0c04c413e3276e0962cd7aeb148 \
59 | --hash=sha256:974a39bdb8c90a85982cdb78a103a32e0b1be986d411303064b28a80611f6e51 \
60 | --hash=sha256:9e112e03d37987d7b90c1e98ba5e1b59e1645226d78d73282f45b326f7bddcb9 \
61 | --hash=sha256:9e9744c657d896c7b580455e739899e492a4a452e2dd4d2b3e459f6b244a638d \
62 | --hash=sha256:9ed358312e63bf683b9ef22c8e442ef6c5c02973f0c2a939ec1d7b50c974015c \
63 | --hash=sha256:9f2c221eecb7ead00b8e3ddb913c67f75cba078fd1d326053225a3f59d850d72 \
64 | --hash=sha256:a20d33124935d27b80e6fdacbd34205732660e0a1d35d8b10b3328179a2b51a1 \
65 | --hash=sha256:a4c0757db9bd08470ff8277791795e70d0bf035a011a528ee9a5ce9454b6cba2 \
66 | --hash=sha256:afe07421c969e259e9403c3bb658968702bc3b78ec0b6fde3ae1e73440529c23 \
67 | --hash=sha256:b1992ba9d4780d9af9726bbcef6a1db12d9ab1ccc35e5773685a24b7fb2758eb \
68 | --hash=sha256:b23d2a46d53210b498e5b701a1913697671988f4bf8e10f935433f6e7c332fb6 \
69 | --hash=sha256:b5e83e4de81dcc9425598d9469a624826a0b1211380ac444c7c791d4a2137c19 \
70 | --hash=sha256:be35822f35f99dcc48152c9839d0171a06186f2d71ef76dc57fa556cc9bf6b45 \
71 | --hash=sha256:be9e0fb2ada7e5124f5282d6381903183ecc73ea019568d6d63d33f25b2a9000 \
72 | --hash=sha256:c140e7eb5ce47249668056edf3b7e9900c6a2e22fb0eaf0513f18a1b2c14e1da \
73 | --hash=sha256:c6a08799e9e88052221adca55741bf106ec7ea0710bca635c208b751f0d5b617 \
74 | --hash=sha256:cb242fc2cda5a307a7698c93173d3627a2a90d00507bccf5bc228851e8304963 \
75 | --hash=sha256:cce1e90dd302f45716a7715517c6aa0468af0bf38e814ad4eab58e88fc09f7f7 \
76 | --hash=sha256:cd4ccc364cf75d1422e66e247e52a93da6a9b73cefa8cad696f3cbbb75af179d \
77 | --hash=sha256:d21681f09e297a5adaa73060737e3aa1279a13ecdcfcc6ef66c292cb25125b2d \
78 | --hash=sha256:d38ffd0e81ba8ef347d2be0772e899c289b59ff150ebbbbe05dc61b1246eb4e0 \
79 | --hash=sha256:d566b82e92ff2e09dd6342df7e0eb4ff6275a3f08db284888dcd98134dbd4243 \
80 | --hash=sha256:d5b0ff9878333823226d270417f24f4d06f235cb3e54d1103b71ea537a6a86ce \
81 | --hash=sha256:d6ee1aa7ab36475035eb48c01efae87d37936a8173fc4d7b10bb02c2d75dd8f6 \
82 | --hash=sha256:db38f80540083ea33bdab614a9d28bcec4b54daa5aff1668d7827a9fc769ae0a \
83 | --hash=sha256:ea688d11707d30e212e0110a1aac7f7f3f542a259235d396f88be68b649e47d1 \
84 | --hash=sha256:f6327b6907b4cb72f650a5b7b1be23a2aab395017aa6f1adb13069d66360eb3f \
85 | --hash=sha256:fb412b7db83fe56847df9c47b6fe3f13911b06339c2aa02dcc09dce8bbf582cd
86 | h11==0.14.0 ; python_version >= "3.8" and python_version < "4.0" \
87 | --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \
88 | --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761
89 | identify==2.5.11 ; python_version >= "3.8" and python_version < "4.0" \
90 | --hash=sha256:14b7076b29c99b1b0b8b08e96d448c7b877a9b07683cd8cfda2ea06af85ffa1c \
91 | --hash=sha256:e7db36b772b188099616aaf2accbee122949d1c6a1bac4f38196720d6f9f06db
92 | idna==3.4 ; python_version >= "3.8" and python_version < "4.0" \
93 | --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \
94 | --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2
95 | nodeenv==1.7.0 ; python_version >= "3.8" and python_version < "4.0" \
96 | --hash=sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e \
97 | --hash=sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b
98 | platformdirs==2.6.0 ; python_version >= "3.8" and python_version < "4.0" \
99 | --hash=sha256:1a89a12377800c81983db6be069ec068eee989748799b946cce2a6e80dcc54ca \
100 | --hash=sha256:b46ffafa316e6b83b47489d240ce17173f123a9b9c83282141c3daf26ad9ac2e
101 | pre-commit==2.20.0 ; python_version >= "3.8" and python_version < "4.0" \
102 | --hash=sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7 \
103 | --hash=sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959
104 | pydantic==1.10.2 ; python_version >= "3.8" and python_version < "4.0" \
105 | --hash=sha256:05e00dbebbe810b33c7a7362f231893183bcc4251f3f2ff991c31d5c08240c42 \
106 | --hash=sha256:06094d18dd5e6f2bbf93efa54991c3240964bb663b87729ac340eb5014310624 \
107 | --hash=sha256:0b959f4d8211fc964772b595ebb25f7652da3f22322c007b6fed26846a40685e \
108 | --hash=sha256:19b3b9ccf97af2b7519c42032441a891a5e05c68368f40865a90eb88833c2559 \
109 | --hash=sha256:1b6ee725bd6e83ec78b1aa32c5b1fa67a3a65badddde3976bca5fe4568f27709 \
110 | --hash=sha256:1ee433e274268a4b0c8fde7ad9d58ecba12b069a033ecc4645bb6303c062d2e9 \
111 | --hash=sha256:216f3bcbf19c726b1cc22b099dd409aa371f55c08800bcea4c44c8f74b73478d \
112 | --hash=sha256:2d0567e60eb01bccda3a4df01df677adf6b437958d35c12a3ac3e0f078b0ee52 \
113 | --hash=sha256:2e05aed07fa02231dbf03d0adb1be1d79cabb09025dd45aa094aa8b4e7b9dcda \
114 | --hash=sha256:352aedb1d71b8b0736c6d56ad2bd34c6982720644b0624462059ab29bd6e5912 \
115 | --hash=sha256:355639d9afc76bcb9b0c3000ddcd08472ae75318a6eb67a15866b87e2efa168c \
116 | --hash=sha256:37c90345ec7dd2f1bcef82ce49b6235b40f282b94d3eec47e801baf864d15525 \
117 | --hash=sha256:4b8795290deaae348c4eba0cebb196e1c6b98bdbe7f50b2d0d9a4a99716342fe \
118 | --hash=sha256:5760e164b807a48a8f25f8aa1a6d857e6ce62e7ec83ea5d5c5a802eac81bad41 \
119 | --hash=sha256:6eb843dcc411b6a2237a694f5e1d649fc66c6064d02b204a7e9d194dff81eb4b \
120 | --hash=sha256:7b5ba54d026c2bd2cb769d3468885f23f43710f651688e91f5fb1edcf0ee9283 \
121 | --hash=sha256:7c2abc4393dea97a4ccbb4ec7d8658d4e22c4765b7b9b9445588f16c71ad9965 \
122 | --hash=sha256:81a7b66c3f499108b448f3f004801fcd7d7165fb4200acb03f1c2402da73ce4c \
123 | --hash=sha256:91b8e218852ef6007c2b98cd861601c6a09f1aa32bbbb74fab5b1c33d4a1e410 \
124 | --hash=sha256:9300fcbebf85f6339a02c6994b2eb3ff1b9c8c14f502058b5bf349d42447dcf5 \
125 | --hash=sha256:9cabf4a7f05a776e7793e72793cd92cc865ea0e83a819f9ae4ecccb1b8aa6116 \
126 | --hash=sha256:a1f5a63a6dfe19d719b1b6e6106561869d2efaca6167f84f5ab9347887d78b98 \
127 | --hash=sha256:a4c805731c33a8db4b6ace45ce440c4ef5336e712508b4d9e1aafa617dc9907f \
128 | --hash=sha256:ae544c47bec47a86bc7d350f965d8b15540e27e5aa4f55170ac6a75e5f73b644 \
129 | --hash=sha256:b97890e56a694486f772d36efd2ba31612739bc6f3caeee50e9e7e3ebd2fdd13 \
130 | --hash=sha256:bb6ad4489af1bac6955d38ebcb95079a836af31e4c4f74aba1ca05bb9f6027bd \
131 | --hash=sha256:bedf309630209e78582ffacda64a21f96f3ed2e51fbf3962d4d488e503420254 \
132 | --hash=sha256:c1ba1afb396148bbc70e9eaa8c06c1716fdddabaf86e7027c5988bae2a829ab6 \
133 | --hash=sha256:c33602f93bfb67779f9c507e4d69451664524389546bacfe1bee13cae6dc7488 \
134 | --hash=sha256:c4aac8e7103bf598373208f6299fa9a5cfd1fc571f2d40bf1dd1955a63d6eeb5 \
135 | --hash=sha256:c6f981882aea41e021f72779ce2a4e87267458cc4d39ea990729e21ef18f0f8c \
136 | --hash=sha256:cc78cc83110d2f275ec1970e7a831f4e371ee92405332ebfe9860a715f8336e1 \
137 | --hash=sha256:d49f3db871575e0426b12e2f32fdb25e579dea16486a26e5a0474af87cb1ab0a \
138 | --hash=sha256:dd3f9a40c16daf323cf913593083698caee97df2804aa36c4b3175d5ac1b92a2 \
139 | --hash=sha256:e0bedafe4bc165ad0a56ac0bd7695df25c50f76961da29c050712596cf092d6d \
140 | --hash=sha256:e9069e1b01525a96e6ff49e25876d90d5a563bc31c658289a8772ae186552236
141 | pyyaml==6.0 ; python_version >= "3.8" and python_version < "4.0" \
142 | --hash=sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf \
143 | --hash=sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293 \
144 | --hash=sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b \
145 | --hash=sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57 \
146 | --hash=sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b \
147 | --hash=sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4 \
148 | --hash=sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07 \
149 | --hash=sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba \
150 | --hash=sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9 \
151 | --hash=sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287 \
152 | --hash=sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513 \
153 | --hash=sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0 \
154 | --hash=sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782 \
155 | --hash=sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0 \
156 | --hash=sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92 \
157 | --hash=sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f \
158 | --hash=sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2 \
159 | --hash=sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc \
160 | --hash=sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1 \
161 | --hash=sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c \
162 | --hash=sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86 \
163 | --hash=sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4 \
164 | --hash=sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c \
165 | --hash=sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34 \
166 | --hash=sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b \
167 | --hash=sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d \
168 | --hash=sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c \
169 | --hash=sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb \
170 | --hash=sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7 \
171 | --hash=sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737 \
172 | --hash=sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3 \
173 | --hash=sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d \
174 | --hash=sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358 \
175 | --hash=sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53 \
176 | --hash=sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78 \
177 | --hash=sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803 \
178 | --hash=sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a \
179 | --hash=sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f \
180 | --hash=sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174 \
181 | --hash=sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5
182 | setuptools==65.6.3 ; python_version >= "3.8" and python_version < "4.0" \
183 | --hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 \
184 | --hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75
185 | sniffio==1.3.0 ; python_version >= "3.8" and python_version < "4.0" \
186 | --hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \
187 | --hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384
188 | sqlalchemy==1.4.45 ; python_version >= "3.8" and python_version < "4.0" \
189 | --hash=sha256:01aa76f324c9bbc0dcb2bc3d9e2a9d7ede4808afa1c38d40d5e2007e3163b206 \
190 | --hash=sha256:06055476d38ed7915eeed22b78580556d446d175c3574a01b9eb04d91f3a8b2e \
191 | --hash=sha256:081e2a2d75466353c738ca2ee71c0cfb08229b4f9909b5fa085f75c48d021471 \
192 | --hash=sha256:099efef0de9fbda4c2d7cb129e4e7f812007901942259d4e6c6e19bd69de1088 \
193 | --hash=sha256:0e068b8414d60dd35d43c693555fc3d2e1d822cef07960bb8ca3f1ee6c4ff762 \
194 | --hash=sha256:13578d1cda69bc5e76c59fec9180d6db7ceb71c1360a4d7861c37d87ea6ca0b1 \
195 | --hash=sha256:16ad798fc121cad5ea019eb2297127b08c54e1aa95fe17b3fea9fdbc5c34fe62 \
196 | --hash=sha256:1a92685db3b0682776a5abcb5f9e9addb3d7d9a6d841a452a17ec2d8d457bea7 \
197 | --hash=sha256:26b8424b32eeefa4faad21decd7bdd4aade58640b39407bf43e7d0a7c1bc0453 \
198 | --hash=sha256:29a29d02c9e6f6b105580c5ed7afb722b97bc2e2fdb85e1d45d7ddd8440cfbca \
199 | --hash=sha256:2d1539fbc82d2206380a86d6d7d0453764fdca5d042d78161bbfb8dd047c80ec \
200 | --hash=sha256:2d6f178ff2923730da271c8aa317f70cf0df11a4d1812f1d7a704b1cf29c5fe3 \
201 | --hash=sha256:2db887dbf05bcc3151de1c4b506b14764c6240a42e844b4269132a7584de1e5f \
202 | --hash=sha256:416fe7d228937bd37990b5a429fd00ad0e49eabcea3455af7beed7955f192edd \
203 | --hash=sha256:445914dcadc0b623bd9851260ee54915ecf4e3041a62d57709b18a0eed19f33b \
204 | --hash=sha256:52b90c9487e4449ad954624d01dea34c90cd8c104bce46b322c83654f37a23c5 \
205 | --hash=sha256:55ddb5585129c5d964a537c9e32a8a68a8c6293b747f3fa164e1c034e1657a98 \
206 | --hash=sha256:561605cfc26273825ed2fb8484428faf36e853c13e4c90c61c58988aeccb34ed \
207 | --hash=sha256:5953e225be47d80410ae519f865b5c341f541d8e383fb6d11f67fb71a45bf890 \
208 | --hash=sha256:6a91b7883cb7855a27bc0637166eed622fdf1bb94a4d1630165e5dd88c7e64d3 \
209 | --hash=sha256:6cd53b4c756a6f9c6518a3dc9c05a38840f9ae442c91fe1abde50d73651b6922 \
210 | --hash=sha256:715f5859daa3bee6ecbad64501637fa4640ca6734e8cda6135e3898d5f8ccadd \
211 | --hash=sha256:7e32ce2584564d9e068bb7e0ccd1810cbb0a824c0687f8016fe67e97c345a637 \
212 | --hash=sha256:88f4ad3b081c0dbb738886f8d425a5d983328670ee83b38192687d78fc82bd1e \
213 | --hash=sha256:96821d806c0c90c68ce3f2ce6dd529c10e5d7587961f31dd5c30e3bfddc4545d \
214 | --hash=sha256:9a21c1fb71c69c8ec65430160cd3eee44bbcea15b5a4e556f29d03f246f425ec \
215 | --hash=sha256:9b7025d46aba946272f6b6b357a22f3787473ef27451f342df1a2a6de23743e3 \
216 | --hash=sha256:a3bcd5e2049ceb97e8c273e6a84ff4abcfa1dc47b6d8bbd36e07cce7176610d3 \
217 | --hash=sha256:a62ae2ea3b940ce9c9cbd675489c2047921ce0a79f971d3082978be91bd58117 \
218 | --hash=sha256:a87f8595390764db333a1705591d0934973d132af607f4fa8b792b366eacbb3c \
219 | --hash=sha256:c8051bff4ce48cbc98f11e95ac46bfd1e36272401070c010248a3230d099663f \
220 | --hash=sha256:ca152ffc7f0aa069c95fba46165030267ec5e4bb0107aba45e5e9e86fe4d9363 \
221 | --hash=sha256:cd95a3e6ab46da2c5b0703e797a772f3fab44d085b3919a4f27339aa3b1f51d3 \
222 | --hash=sha256:d458fd0566bc9e10b8be857f089e96b5ca1b1ef033226f24512f9ffdf485a8c0 \
223 | --hash=sha256:db3ccbce4a861bf4338b254f95916fc68dd8b7aa50eea838ecdaf3a52810e9c0 \
224 | --hash=sha256:dc10423b59d6d032d6dff0bb42aa06dc6a8824eb6029d70c7d1b6981a2e7f4d8 \
225 | --hash=sha256:e91a5e45a2ea083fe344b3503405978dff14d60ef3aa836432c9ca8cd47806b6 \
226 | --hash=sha256:f1d3fb02a4d0b07d1351a4a52f159e5e7b3045c903468b7e9349ebf0020ffdb9 \
227 | --hash=sha256:f61e54b8c2b389de1a8ad52394729c478c67712dbdcdadb52c2575e41dae94a5 \
228 | --hash=sha256:f7944b04e6fcf8d733964dd9ee36b6a587251a1a4049af3a9b846f6e64eb349a \
229 | --hash=sha256:fd69850860093a3f69fefe0ab56d041edfdfe18510b53d9a2eaecba2f15fa795
230 | starlette==0.19.1 ; python_version >= "3.8" and python_version < "4.0" \
231 | --hash=sha256:5a60c5c2d051f3a8eb546136aa0c9399773a689595e099e0877704d5888279bf \
232 | --hash=sha256:c6d21096774ecb9639acad41b86b7706e52ba3bf1dc13ea4ed9ad593d47e24c7
233 | toml==0.10.2 ; python_version >= "3.8" and python_version < "4.0" \
234 | --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \
235 | --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f
236 | typing-extensions==4.4.0 ; python_version >= "3.8" and python_version < "4.0" \
237 | --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \
238 | --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e
239 | uvicorn==0.18.3 ; python_version >= "3.8" and python_version < "4.0" \
240 | --hash=sha256:0abd429ebb41e604ed8d2be6c60530de3408f250e8d2d84967d85ba9e86fe3af \
241 | --hash=sha256:9a66e7c42a2a95222f76ec24a4b754c158261c4696e683b9dadc72b590e0311b
242 | virtualenv==20.17.1 ; python_version >= "3.8" and python_version < "4.0" \
243 | --hash=sha256:ce3b1684d6e1a20a3e5ed36795a97dfc6af29bc3970ca8dab93e11ac6094b3c4 \
244 | --hash=sha256:f8b927684efc6f1cc206c9db297a570ab9ad0e51c16fa9e45487d36d1905c058
245 |
--------------------------------------------------------------------------------