From 9c4c325e5a7a77842d2e5ffc7816cb19ab0d9a43 Mon Sep 17 00:00:00 2001 From: Michael Schramm Date: Sat, 2 Dec 2023 19:22:40 +0100 Subject: [PATCH] Switch to single branch (#221) * remove submodules * add api and ui files * update github actions * use sparse checkout * update node setup * update checkout * update docker * change permissions * update mariadb health check * update changelog --- .github/workflows/api-image.yml | 55 + .github/workflows/api-test.yml | 222 + .../{docker-image.yml => combined-image.yml} | 15 +- .github/workflows/ui-image.yml | 55 + .github/workflows/ui-test.yml | 50 + .gitmodules | 7 - CHANGELOG.md | 200 +- api | 1 - api/.dockerignore | 4 + api/.eslintrc.js | 72 + api/.gitignore | 43 + api/.prettierrc | 4 + api/Dockerfile | 49 + api/LICENSE.md | 661 ++ api/README.md | 40 + api/doc/cli.md | 14 + api/doc/development.md | 8 + api/doc/environment.md | 46 + api/doc/installation.metrics.md | 11 + api/doc/roles.md | 24 + api/docker-compose.yml | 65 + api/locales/en/mail/user/created.mjml | 22 + api/nest-cli.json | 7 + api/ormconfig_mariadb.json | 22 + api/ormconfig_postgres.json | 22 + api/ormconfig_sqlite.json | 16 + api/package.json | 126 + api/public/.gitkeep | 0 api/public/index.html | 5 + api/src/app.imports.ts | 168 + api/src/app.module.ts | 11 + api/src/app.providers.ts | 13 + api/src/cli.ts | 16 + api/src/command/index.ts | 3 + api/src/command/user.command.ts | 65 + api/src/config/fields.ts | 32 + api/src/config/languages.ts | 23 + api/src/config/roles.ts | 7 + api/src/controller/health.controller.ts | 9 + api/src/controller/index.ts | 3 + api/src/decorator/ip.address.decorator.ts | 19 + api/src/decorator/roles.decorator.ts | 4 + api/src/decorator/user.decorator.ts | 14 + api/src/dto/auth/auth.jwt.model.ts | 15 + api/src/dto/deleted.model.ts | 11 + api/src/dto/form/button.input.ts | 25 + api/src/dto/form/button.model.ts | 39 + api/src/dto/form/colors.input.ts | 22 + api/src/dto/form/colors.model.ts | 32 + api/src/dto/form/design.input.ts | 14 + api/src/dto/form/design.model.ts | 21 + api/src/dto/form/form.create.input.ts | 29 + api/src/dto/form/form.field.input.ts | 43 + api/src/dto/form/form.field.logic.input.ts | 33 + api/src/dto/form/form.field.logic.model.ts | 49 + api/src/dto/form/form.field.model.ts | 43 + api/src/dto/form/form.field.option.input.ts | 16 + api/src/dto/form/form.field.option.model.ts | 27 + api/src/dto/form/form.field.rating.input.ts | 11 + api/src/dto/form/form.field.rating.model.ts | 17 + api/src/dto/form/form.hook.input.ts | 16 + api/src/dto/form/form.hook.model.ts | 27 + api/src/dto/form/form.model.ts | 39 + api/src/dto/form/form.notification.input.ts | 28 + api/src/dto/form/form.notification.model.ts | 43 + api/src/dto/form/form.pager.model.ts | 25 + api/src/dto/form/form.statistic.model.ts | 6 + api/src/dto/form/form.update.input.ts | 45 + api/src/dto/form/page.input.ts | 23 + api/src/dto/form/page.model.ts | 37 + api/src/dto/profile/profile.model.ts | 15 + api/src/dto/profile/profile.update.input.ts | 25 + api/src/dto/setting/setting.model.ts | 24 + api/src/dto/setting/setting.pager.model.ts | 25 + api/src/dto/status.model.ts | 11 + api/src/dto/submission/device.input.ts | 13 + api/src/dto/submission/device.model.ts | 20 + api/src/dto/submission/geo.location.model.ts | 16 + .../dto/submission/submission.field.model.ts | 23 + api/src/dto/submission/submission.model.ts | 48 + .../submission.pager.filter.input.ts | 10 + .../dto/submission/submission.pager.model.ts | 25 + .../submission/submission.progress.model.ts | 33 + .../submission/submission.set.field.input.ts | 13 + .../dto/submission/submission.start.input.ts | 11 + .../submission/submission.statistic.model.ts | 6 + api/src/dto/user/user.create.input.ts | 28 + api/src/dto/user/user.model.ts | 57 + api/src/dto/user/user.pager.model.ts | 25 + api/src/dto/user/user.statistic.model.ts | 6 + api/src/dto/user/user.update.input.ts | 29 + api/src/entity/embedded/analytics.embedded.ts | 6 + api/src/entity/embedded/colors.embedded.ts | 21 + api/src/entity/embedded/design.embedded.ts | 13 + api/src/entity/embedded/device.embedded.ts | 12 + .../entity/embedded/geo.location.embedded.ts | 9 + api/src/entity/embedded/rating.embedded.ts | 9 + api/src/entity/form.entity.ts | 81 + api/src/entity/form.field.entity.ts | 47 + api/src/entity/form.field.logic.entity.ts | 37 + api/src/entity/form.field.option.entity.ts | 20 + api/src/entity/form.hook.entity.ts | 20 + api/src/entity/form.notification.entity.ts | 33 + api/src/entity/index.ts | 27 + api/src/entity/page.button.entity.ts | 29 + api/src/entity/page.entity.ts | 23 + api/src/entity/submission.entity.ts | 61 + api/src/entity/submission.field.entity.ts | 32 + api/src/entity/user.entity.ts | 56 + api/src/entity/visitor.entity.ts | 43 + api/src/guard/gql.auth.guard.ts | 29 + api/src/guard/index.ts | 16 + api/src/guard/local.auth.guard.ts | 10 + api/src/guard/roles.guard.ts | 27 + api/src/main.ts | 22 + .../mariadb/1619723437787-initial.ts | 74 + .../mariadb/1621078163528-layout.ts | 14 + .../mariadb/1641124349039-submission.ts | 17 + .../mariadb/1641132645227-confirm.ts | 13 + .../migrations/mariadb/1641151802308-idx.ts | 15 + .../mariadb/1641193946192-anonymous.ts | 13 + .../mariadb/1645952169100-defaultValue.ts | 13 + .../mariadb/1645956388810-defaultValue.ts | 14 + .../postgres/1619723437787-initial.ts | 59 + .../postgres/1621078163528-layout.ts | 14 + .../postgres/1641124349039-submission.ts | 17 + .../postgres/1641132645227-confirm.ts | 13 + .../migrations/postgres/1641151802308-idx.ts | 15 + .../postgres/1641193946192-anonymous.ts | 13 + .../postgres/1645952169100-defaultValue.ts | 13 + .../postgres/1645956388810-defaultValue.ts | 14 + api/src/migrations/sqlite.migration.ts | 47 + .../sqlite/1619723437787-initial.ts | 37 + .../migrations/sqlite/1621078163528-layout.ts | 20 + .../sqlite/1641124349039-submission.ts | 20 + .../sqlite/1641132645227-confirm.ts | 20 + .../migrations/sqlite/1641151802308-idx.ts | 28 + .../sqlite/1641193946192-anonymous.ts | 20 + .../sqlite/1645952169100-defaultValue.ts | 14 + .../sqlite/1645956388810-defaultValue.ts | 30 + api/src/pipe/form/form.by.id.pipe.ts | 19 + api/src/pipe/form/index.ts | 3 + api/src/pipe/index.ts | 9 + api/src/pipe/submission/index.ts | 3 + .../pipe/submission/submission.by.id.pipe.ts | 19 + api/src/pipe/user/index.ts | 3 + api/src/pipe/user/user.by.id.pipe.ts | 19 + api/src/resolver/auth/auth.login.mutation.ts | 26 + .../resolver/auth/auth.register.mutation.ts | 37 + api/src/resolver/auth/index.ts | 7 + api/src/resolver/context.cache.ts | 27 + api/src/resolver/form/form.create.mutation.ts | 34 + api/src/resolver/form/form.delete.mutation.ts | 36 + api/src/resolver/form/form.field.resolver.ts | 73 + api/src/resolver/form/form.list.query.ts | 45 + api/src/resolver/form/form.query.ts | 34 + api/src/resolver/form/form.resolver.ts | 179 + api/src/resolver/form/form.statistic.query.ts | 11 + .../resolver/form/form.statistic.resolver.ts | 18 + api/src/resolver/form/form.update.mutation.ts | 42 + api/src/resolver/form/index.ts | 23 + api/src/resolver/form/page.resolver.ts | 32 + api/src/resolver/index.ts | 17 + api/src/resolver/profile/index.ts | 7 + api/src/resolver/profile/profile.query.ts | 27 + .../profile/profile.update.mutation.ts | 47 + api/src/resolver/setting/index.ts | 7 + api/src/resolver/setting/setting.mutation.ts | 10 + api/src/resolver/setting/setting.query.ts | 40 + api/src/resolver/status.resolver.ts | 12 + api/src/resolver/submission/index.ts | 23 + .../submission/submission.field.resolver.ts | 43 + .../submission/submission.finish.mutation.ts | 32 + .../submission/submission.list.query.ts | 54 + .../submission.progress.resolver.ts | 7 + .../resolver/submission/submission.query.ts | 40 + .../submission/submission.resolver.ts | 33 + .../submission.set.field.mutation.ts | 40 + .../submission/submission.start.mutation.ts | 43 + .../submission/submission.statistic.query.ts | 11 + .../submission.statistic.resolver.ts | 19 + api/src/resolver/user/index.ts | 17 + api/src/resolver/user/user.delete.mutation.ts | 33 + api/src/resolver/user/user.list.query.ts | 37 + api/src/resolver/user/user.query.ts | 27 + api/src/resolver/user/user.resolver.ts | 41 + api/src/resolver/user/user.statistic.query.ts | 11 + .../resolver/user/user.statistic.resolver.ts | 18 + api/src/resolver/user/user.update.mutation.ts | 41 + api/src/service/auth/auth.service.ts | 55 + api/src/service/auth/index.ts | 11 + api/src/service/auth/jwt.strategy.ts | 30 + api/src/service/auth/local.strategy.ts | 19 + api/src/service/auth/password.service.ts | 29 + api/src/service/form/form.create.service.ts | 39 + api/src/service/form/form.delete.service.ts | 26 + api/src/service/form/form.field.service.ts | 25 + .../service/form/form.page.create.service.ts | 44 + .../service/form/form.page.update.service.ts | 73 + api/src/service/form/form.service.ts | 66 + .../service/form/form.statistic.service.ts | 15 + api/src/service/form/form.update.service.ts | 291 + api/src/service/form/index.ts | 19 + api/src/service/id.service.ts | 32 + api/src/service/index.ts | 49 + .../service/installation.metrics.service.ts | 45 + api/src/service/mail.service.ts | 91 + api/src/service/profile/index.ts | 3 + .../service/profile/profile.update.service.ts | 64 + api/src/service/setting.service.ts | 39 + api/src/service/submission/index.ts | 17 + .../submission/submission.hook.service.ts | 74 + .../submission.notification.service.ts | 92 + .../service/submission/submission.service.ts | 70 + .../submission.set.field.service.ts | 240 + .../submission/submission.start.service.ts | 47 + .../submission.statistic.service.ts | 15 + .../submission/submission.token.service.ts | 13 + api/src/service/user/boot.service.ts | 61 + api/src/service/user/index.ts | 17 + api/src/service/user/user.create.service.ts | 96 + api/src/service/user/user.delete.service.ts | 17 + api/src/service/user/user.service.ts | 74 + .../service/user/user.statistic.service.ts | 15 + api/src/service/user/user.token.service.ts | 13 + api/src/service/user/user.update.service.ts | 69 + api/tsconfig.build.json | 4 + api/tsconfig.json | 22 + api/yarn.lock | 9563 +++++++++++++++++ ui | 1 - ui/.dockerignore | 5 + ui/.eslintrc.js | 74 + ui/.gitignore | 33 + ui/.graphqlconfig | 15 + ui/.prettierrc.js | 8 + ui/Dockerfile | 39 + ui/LICENSE.md | 661 ++ ui/README.md | 17 + ui/assets/global.scss | 58 + ui/assets/images/logo_white.png | Bin 0 -> 60482 bytes ui/assets/images/logo_white_small.png | Bin 0 -> 33363 bytes ui/assets/images/marker-icon-2x.png | Bin 0 -> 2464 bytes ui/assets/images/marker-shadow.png | Bin 0 -> 618 bytes ui/assets/variables.scss | 3 + ui/components/auth/footer.module.scss | 18 + ui/components/auth/footer.tsx | 142 + ui/components/auth/layout.tsx | 25 + ui/components/clean.input.ts | 27 + ui/components/date.time.tsx | 22 + ui/components/error.page.tsx | 18 + ui/components/form/admin/base.data.tab.tsx | 69 + ui/components/form/admin/design.tab.tsx | 49 + ui/components/form/admin/end.page.tab.tsx | 130 + .../form/admin/export.submission.action.tsx | 125 + ui/components/form/admin/field.card.tsx | 244 + ui/components/form/admin/fields.tab.tsx | 124 + ui/components/form/admin/hooks.tab.tsx | 98 + ui/components/form/admin/is.live.tsx | 26 + ui/components/form/admin/logic.block.tsx | 233 + .../form/admin/notification.card.tsx | 247 + .../form/admin/notifications.tab.tsx | 93 + ui/components/form/admin/start.page.tab.tsx | 130 + .../form/admin/submission.values.tsx | 63 + ui/components/form/layouts/card/field.tsx | 67 + .../form/layouts/card/index.module.scss | 0 ui/components/form/layouts/card/index.tsx | 221 + ui/components/form/layouts/card/page.tsx | 65 + ui/components/form/layouts/layout.props.ts | 7 + ui/components/form/layouts/page.buttons.tsx | 34 + ui/components/form/layouts/slider/field.tsx | 119 + ui/components/form/layouts/slider/index.tsx | 122 + .../form/layouts/slider/page.module.scss | 20 + ui/components/form/layouts/slider/page.tsx | 69 + ui/components/form/types/abstract.type.tsx | 38 + .../form/types/checkbox/checkbox.admin.tsx | 77 + .../form/types/checkbox/checkbox.input.tsx | 61 + ui/components/form/types/checkbox/index.ts | 15 + ui/components/form/types/date/date.admin.tsx | 50 + ui/components/form/types/date/date.input.tsx | 78 + ui/components/form/types/date/index.ts | 24 + .../form/types/dropdown/dropdown.admin.tsx | 77 + .../form/types/dropdown/dropdown.input.tsx | 62 + ui/components/form/types/dropdown/index.ts | 15 + .../form/types/email/email.admin.tsx | 21 + .../form/types/email/email.input.tsx | 49 + ui/components/form/types/email/index.ts | 15 + ui/components/form/types/field.admin.props.ts | 7 + .../form/types/field.input.builder.type.ts | 6 + ui/components/form/types/field.input.props.ts | 11 + .../form/types/hidden/hidden.admin.tsx | 20 + ui/components/form/types/hidden/index.ts | 15 + .../form/types/image/image.admin.tsx | 2 + ui/components/form/types/image/image.type.tsx | 2 + ui/components/form/types/image/index.ts | 19 + ui/components/form/types/index.ts | 34 + ui/components/form/types/link/index.ts | 15 + ui/components/form/types/link/link.admin.tsx | 21 + ui/components/form/types/link/link.input.tsx | 49 + ui/components/form/types/location/index.ts | 34 + .../form/types/location/location.admin.tsx | 142 + .../form/types/location/location.input.tsx | 151 + ui/components/form/types/number/index.ts | 19 + .../form/types/number/number.admin.tsx | 20 + .../form/types/number/number.input.tsx | 49 + ui/components/form/types/radio/index.ts | 15 + .../form/types/radio/radio.admin.tsx | 77 + .../form/types/radio/radio.input.tsx | 55 + ui/components/form/types/rating/index.ts | 19 + .../form/types/rating/rating.admin.tsx | 21 + .../form/types/rating/rating.input.tsx | 43 + ui/components/form/types/slider/index.ts | 19 + .../form/types/slider/slider.admin.tsx | 88 + .../form/types/slider/slider.input.tsx | 92 + ui/components/form/types/textarea/index.ts | 15 + .../form/types/textarea/textarea.admin.tsx | 20 + .../form/types/textarea/textarea.input.tsx | 46 + ui/components/form/types/textfield/index.ts | 15 + .../form/types/textfield/textfield.admin.tsx | 18 + .../form/types/textfield/textfield.input.tsx | 52 + ui/components/form/types/yes_no/index.tsx | 36 + .../form/types/yes_no/yes_no.admin.tsx | 21 + .../form/types/yes_no/yes_no.input.tsx | 45 + ui/components/input/color.tsx | 38 + ui/components/loading.page.tsx | 23 + ui/components/map/draggable.marker.tsx | 36 + ui/components/omf.module.scss | 71 + ui/components/omf.tsx | 18 + ui/components/sidemenu.tsx | 57 + ui/components/structure.tsx | 328 + ui/components/styled/button.tsx | 28 + ui/components/styled/checkbox.tsx | 38 + ui/components/styled/date.input.tsx | 50 + ui/components/styled/h1.tsx | 17 + ui/components/styled/h2.tsx | 16 + ui/components/styled/input.tsx | 51 + ui/components/styled/markdown.tsx | 64 + ui/components/styled/number.input.tsx | 52 + ui/components/styled/p.tsx | 18 + ui/components/styled/radio.tsx | 38 + ui/components/styled/select.tsx | 50 + ui/components/styled/textarea.input.tsx | 49 + ui/components/time.ago.tsx | 25 + ui/components/use.imerative.query.ts | 16 + ui/components/use.math.ts | 34 + ui/components/use.router.ts | 21 + ui/components/use.submission.ts | 102 + ui/components/use.window.size.ts | 29 + ui/components/user/admin/base.data.tab.tsx | 113 + ui/components/user/role.tsx | 30 + ui/components/with.auth.tsx | 70 + ui/doc/development.md | 46 + ui/doc/environment.md | 8 + ui/graphql/client.ts | 46 + ui/graphql/fragment/admin.profile.fragment.ts | 26 + ui/graphql/fragment/admin.user.fragment.ts | 27 + ui/graphql/fragment/form.fragment.ts | 224 + ui/graphql/fragment/form.pager.fragment.ts | 31 + ui/graphql/fragment/form.public.fragment.ts | 177 + ui/graphql/fragment/submission.fragment.ts | 63 + ui/graphql/fragment/user.pager.fragment.ts | 19 + ui/graphql/mutation/form.create.mutation.ts | 45 + ui/graphql/mutation/form.delete.mutation.ts | 24 + ui/graphql/mutation/form.update.mutation.ts | 25 + ui/graphql/mutation/login.mutation.ts | 22 + .../mutation/profile.update.mutation.ts | 34 + ui/graphql/mutation/register.mutation.ts | 32 + .../mutation/submission.finish.mutation.ts | 21 + .../mutation/submission.set.field.mutation.ts | 26 + .../mutation/submission.start.mutation.ts | 28 + ui/graphql/mutation/user.delete.mutation.ts | 24 + ui/graphql/mutation/user.update.mutation.ts | 25 + ui/graphql/query/admin.profile.query.ts | 21 + ui/graphql/query/admin.statistic.query.ts | 29 + ui/graphql/query/admin.user.query.ts | 20 + ui/graphql/query/form.pager.query.ts | 37 + ui/graphql/query/form.public.query.ts | 25 + ui/graphql/query/form.query.ts | 25 + ui/graphql/query/me.query.ts | 23 + ui/graphql/query/settings.query.ts | 32 + ui/graphql/query/status.query.ts | 20 + ui/graphql/query/submission.pager.query.ts | 53 + ui/graphql/query/user.pager.query.ts | 37 + ui/i18n.ts | 20 + ui/locales/ar/admin.json | 1 + ui/locales/ar/common.json | 1 + ui/locales/ar/form.json | 1 + ui/locales/ar/index.ts | 27 + ui/locales/ar/language.json | 11 + ui/locales/ar/login.json | 1 + ui/locales/ar/profile.json | 1 + ui/locales/ar/register.json | 1 + ui/locales/ar/statistic.json | 1 + ui/locales/ar/submission.json | 1 + ui/locales/ar/type.json | 1 + ui/locales/ar/user.json | 1 + ui/locales/ar/validation.json | 1 + ui/locales/cn/admin.json | 9 + ui/locales/cn/common.json | 10 + ui/locales/cn/form.json | 114 + ui/locales/cn/index.ts | 27 + ui/locales/cn/language.json | 12 + ui/locales/cn/login.json | 8 + ui/locales/cn/profile.json | 12 + ui/locales/cn/register.json | 6 + ui/locales/cn/statistic.json | 5 + ui/locales/cn/submission.json | 17 + ui/locales/cn/type.json | 76 + ui/locales/cn/user.json | 18 + ui/locales/cn/validation.json | 20 + ui/locales/da/admin.json | 3 + ui/locales/da/common.json | 5 + ui/locales/da/form.json | 46 + ui/locales/da/index.ts | 27 + ui/locales/da/language.json | 1 + ui/locales/da/login.json | 5 + ui/locales/da/profile.json | 10 + ui/locales/da/register.json | 5 + ui/locales/da/statistic.json | 1 + ui/locales/da/submission.json | 11 + ui/locales/da/type.json | 15 + ui/locales/da/user.json | 15 + ui/locales/da/validation.json | 19 + ui/locales/de/admin.json | 9 + ui/locales/de/common.json | 10 + ui/locales/de/form.json | 114 + ui/locales/de/index.ts | 27 + ui/locales/de/language.json | 12 + ui/locales/de/login.json | 8 + ui/locales/de/profile.json | 12 + ui/locales/de/register.json | 6 + ui/locales/de/statistic.json | 5 + ui/locales/de/submission.json | 17 + ui/locales/de/type.json | 76 + ui/locales/de/user.json | 18 + ui/locales/de/validation.json | 20 + ui/locales/en/admin.json | 9 + ui/locales/en/common.json | 10 + ui/locales/en/form.json | 117 + ui/locales/en/index.ts | 27 + ui/locales/en/language.json | 11 + ui/locales/en/login.json | 8 + ui/locales/en/profile.json | 12 + ui/locales/en/register.json | 6 + ui/locales/en/statistic.json | 5 + ui/locales/en/submission.json | 17 + ui/locales/en/type.json | 87 + ui/locales/en/user.json | 17 + ui/locales/en/validation.json | 20 + ui/locales/es/admin.json | 9 + ui/locales/es/common.json | 9 + ui/locales/es/form.json | 100 + ui/locales/es/index.ts | 27 + ui/locales/es/language.json | 11 + ui/locales/es/login.json | 8 + ui/locales/es/profile.json | 10 + ui/locales/es/register.json | 6 + ui/locales/es/statistic.json | 5 + ui/locales/es/submission.json | 16 + ui/locales/es/type.json | 68 + ui/locales/es/user.json | 18 + ui/locales/es/validation.json | 18 + ui/locales/fr/admin.json | 9 + ui/locales/fr/common.json | 10 + ui/locales/fr/form.json | 114 + ui/locales/fr/index.ts | 27 + ui/locales/fr/language.json | 12 + ui/locales/fr/login.json | 8 + ui/locales/fr/profile.json | 12 + ui/locales/fr/register.json | 6 + ui/locales/fr/statistic.json | 5 + ui/locales/fr/submission.json | 17 + ui/locales/fr/type.json | 76 + ui/locales/fr/user.json | 18 + ui/locales/fr/validation.json | 20 + ui/locales/hi/admin.json | 9 + ui/locales/hi/common.json | 10 + ui/locales/hi/form.json | 7 + ui/locales/hi/index.ts | 27 + ui/locales/hi/language.json | 11 + ui/locales/hi/login.json | 8 + ui/locales/hi/profile.json | 12 + ui/locales/hi/register.json | 6 + ui/locales/hi/statistic.json | 5 + ui/locales/hi/submission.json | 17 + ui/locales/hi/type.json | 4 + ui/locales/hi/user.json | 5 + ui/locales/hi/validation.json | 12 + ui/locales/index.ts | 39 + ui/locales/it/admin.json | 8 + ui/locales/it/common.json | 10 + ui/locales/it/form.json | 90 + ui/locales/it/index.ts | 27 + ui/locales/it/language.json | 11 + ui/locales/it/login.json | 7 + ui/locales/it/profile.json | 10 + ui/locales/it/register.json | 6 + ui/locales/it/statistic.json | 5 + ui/locales/it/submission.json | 16 + ui/locales/it/type.json | 65 + ui/locales/it/user.json | 17 + ui/locales/it/validation.json | 15 + ui/locales/ja/admin.json | 9 + ui/locales/ja/common.json | 10 + ui/locales/ja/form.json | 120 + ui/locales/ja/index.ts | 27 + ui/locales/ja/language.json | 12 + ui/locales/ja/login.json | 8 + ui/locales/ja/profile.json | 12 + ui/locales/ja/register.json | 6 + ui/locales/ja/statistic.json | 5 + ui/locales/ja/submission.json | 17 + ui/locales/ja/type.json | 76 + ui/locales/ja/user.json | 18 + ui/locales/ja/validation.json | 20 + ui/locales/missing.ts | 78 + ui/locales/nl/admin.json | 8 + ui/locales/nl/common.json | 8 + ui/locales/nl/form.json | 25 + ui/locales/nl/index.ts | 27 + ui/locales/nl/language.json | 11 + ui/locales/nl/login.json | 6 + ui/locales/nl/profile.json | 10 + ui/locales/nl/register.json | 5 + ui/locales/nl/statistic.json | 5 + ui/locales/nl/submission.json | 13 + ui/locales/nl/type.json | 38 + ui/locales/nl/user.json | 15 + ui/locales/nl/validation.json | 18 + ui/locales/pl/admin.json | 9 + ui/locales/pl/common.json | 10 + ui/locales/pl/form.json | 111 + ui/locales/pl/index.ts | 27 + ui/locales/pl/language.json | 12 + ui/locales/pl/login.json | 8 + ui/locales/pl/profile.json | 12 + ui/locales/pl/register.json | 6 + ui/locales/pl/statistic.json | 5 + ui/locales/pl/submission.json | 17 + ui/locales/pl/type.json | 73 + ui/locales/pl/user.json | 18 + ui/locales/pl/validation.json | 18 + ui/locales/pt_BR/admin.json | 9 + ui/locales/pt_BR/common.json | 9 + ui/locales/pt_BR/form.json | 98 + ui/locales/pt_BR/index.ts | 27 + ui/locales/pt_BR/language.json | 11 + ui/locales/pt_BR/login.json | 8 + ui/locales/pt_BR/profile.json | 10 + ui/locales/pt_BR/register.json | 6 + ui/locales/pt_BR/statistic.json | 5 + ui/locales/pt_BR/submission.json | 17 + ui/locales/pt_BR/type.json | 67 + ui/locales/pt_BR/user.json | 17 + ui/locales/pt_BR/validation.json | 18 + ui/locales/pt_PT/admin.json | 9 + ui/locales/pt_PT/common.json | 9 + ui/locales/pt_PT/form.json | 98 + ui/locales/pt_PT/index.ts | 27 + ui/locales/pt_PT/language.json | 11 + ui/locales/pt_PT/login.json | 8 + ui/locales/pt_PT/profile.json | 10 + ui/locales/pt_PT/register.json | 6 + ui/locales/pt_PT/statistic.json | 5 + ui/locales/pt_PT/submission.json | 17 + ui/locales/pt_PT/type.json | 67 + ui/locales/pt_PT/user.json | 17 + ui/locales/pt_PT/validation.json | 18 + ui/locales/ru/admin.json | 9 + ui/locales/ru/common.json | 10 + ui/locales/ru/form.json | 98 + ui/locales/ru/index.ts | 27 + ui/locales/ru/language.json | 11 + ui/locales/ru/login.json | 8 + ui/locales/ru/profile.json | 10 + ui/locales/ru/register.json | 6 + ui/locales/ru/statistic.json | 5 + ui/locales/ru/submission.json | 17 + ui/locales/ru/type.json | 68 + ui/locales/ru/user.json | 17 + ui/locales/ru/validation.json | 18 + ui/locales/sort.ts | 52 + ui/locales/sv/admin.json | 9 + ui/locales/sv/common.json | 8 + ui/locales/sv/form.json | 37 + ui/locales/sv/index.ts | 27 + ui/locales/sv/language.json | 11 + ui/locales/sv/login.json | 7 + ui/locales/sv/profile.json | 9 + ui/locales/sv/register.json | 5 + ui/locales/sv/statistic.json | 5 + ui/locales/sv/submission.json | 16 + ui/locales/sv/type.json | 58 + ui/locales/sv/user.json | 13 + ui/locales/sv/validation.json | 11 + ui/locales/ta/admin.json | 3 + ui/locales/ta/common.json | 1 + ui/locales/ta/form.json | 25 + ui/locales/ta/index.ts | 27 + ui/locales/ta/language.json | 1 + ui/locales/ta/login.json | 3 + ui/locales/ta/profile.json | 10 + ui/locales/ta/register.json | 6 + ui/locales/ta/statistic.json | 5 + ui/locales/ta/submission.json | 16 + ui/locales/ta/type.json | 55 + ui/locales/ta/user.json | 14 + ui/locales/ta/validation.json | 18 + ui/locales/uk/admin.json | 9 + ui/locales/uk/common.json | 9 + ui/locales/uk/form.json | 101 + ui/locales/uk/index.ts | 27 + ui/locales/uk/language.json | 1 + ui/locales/uk/login.json | 8 + ui/locales/uk/profile.json | 10 + ui/locales/uk/register.json | 6 + ui/locales/uk/statistic.json | 5 + ui/locales/uk/submission.json | 17 + ui/locales/uk/type.json | 68 + ui/locales/uk/user.json | 18 + ui/locales/uk/validation.json | 18 + ui/next-env.d.ts | 4 + ui/next.config.js | 31 + ui/next.config.type.ts | 11 + ui/package.json | 77 + ui/pages/_app.tsx | 55 + ui/pages/admin/forms/[id]/index.tsx | 211 + ui/pages/admin/forms/[id]/submissions.tsx | 148 + ui/pages/admin/forms/create.tsx | 131 + ui/pages/admin/forms/index.tsx | 202 + ui/pages/admin/index.tsx | 42 + ui/pages/admin/profile.tsx | 202 + ui/pages/admin/users/[id]/index.tsx | 103 + ui/pages/admin/users/index.tsx | 132 + ui/pages/form/[id]/index.module.scss | 3 + ui/pages/form/[id]/index.tsx | 55 + ui/pages/form/index.tsx | 8 + ui/pages/index.tsx | 100 + ui/pages/login/confirm/[code].tsx | 28 + ui/pages/login/index.module.scss | 11 + ui/pages/login/index.tsx | 148 + ui/pages/login/recover.tsx | 28 + ui/pages/register.module.scss | 19 + ui/pages/register.tsx | 138 + ui/public/favicon.ico | Bin 0 -> 37898 bytes ui/store/auth/index.ts | 20 + ui/store/index.ts | 28 + ui/tsconfig.json | 33 + ui/yarn.lock | 6443 +++++++++++ 648 files changed, 39142 insertions(+), 118 deletions(-) create mode 100644 .github/workflows/api-image.yml create mode 100644 .github/workflows/api-test.yml rename .github/workflows/{docker-image.yml => combined-image.yml} (76%) create mode 100644 .github/workflows/ui-image.yml create mode 100644 .github/workflows/ui-test.yml delete mode 100644 .gitmodules delete mode 160000 api create mode 100644 api/.dockerignore create mode 100644 api/.eslintrc.js create mode 100644 api/.gitignore create mode 100644 api/.prettierrc create mode 100644 api/Dockerfile create mode 100644 api/LICENSE.md create mode 100644 api/README.md create mode 100644 api/doc/cli.md create mode 100644 api/doc/development.md create mode 100644 api/doc/environment.md create mode 100644 api/doc/installation.metrics.md create mode 100644 api/doc/roles.md create mode 100644 api/docker-compose.yml create mode 100644 api/locales/en/mail/user/created.mjml create mode 100644 api/nest-cli.json create mode 100644 api/ormconfig_mariadb.json create mode 100644 api/ormconfig_postgres.json create mode 100644 api/ormconfig_sqlite.json create mode 100644 api/package.json create mode 100644 api/public/.gitkeep create mode 100644 api/public/index.html create mode 100644 api/src/app.imports.ts create mode 100644 api/src/app.module.ts create mode 100644 api/src/app.providers.ts create mode 100644 api/src/cli.ts create mode 100644 api/src/command/index.ts create mode 100644 api/src/command/user.command.ts create mode 100644 api/src/config/fields.ts create mode 100644 api/src/config/languages.ts create mode 100644 api/src/config/roles.ts create mode 100644 api/src/controller/health.controller.ts create mode 100644 api/src/controller/index.ts create mode 100644 api/src/decorator/ip.address.decorator.ts create mode 100644 api/src/decorator/roles.decorator.ts create mode 100644 api/src/decorator/user.decorator.ts create mode 100644 api/src/dto/auth/auth.jwt.model.ts create mode 100644 api/src/dto/deleted.model.ts create mode 100644 api/src/dto/form/button.input.ts create mode 100644 api/src/dto/form/button.model.ts create mode 100644 api/src/dto/form/colors.input.ts create mode 100644 api/src/dto/form/colors.model.ts create mode 100644 api/src/dto/form/design.input.ts create mode 100644 api/src/dto/form/design.model.ts create mode 100644 api/src/dto/form/form.create.input.ts create mode 100644 api/src/dto/form/form.field.input.ts create mode 100644 api/src/dto/form/form.field.logic.input.ts create mode 100644 api/src/dto/form/form.field.logic.model.ts create mode 100644 api/src/dto/form/form.field.model.ts create mode 100644 api/src/dto/form/form.field.option.input.ts create mode 100644 api/src/dto/form/form.field.option.model.ts create mode 100644 api/src/dto/form/form.field.rating.input.ts create mode 100644 api/src/dto/form/form.field.rating.model.ts create mode 100644 api/src/dto/form/form.hook.input.ts create mode 100644 api/src/dto/form/form.hook.model.ts create mode 100644 api/src/dto/form/form.model.ts create mode 100644 api/src/dto/form/form.notification.input.ts create mode 100644 api/src/dto/form/form.notification.model.ts create mode 100644 api/src/dto/form/form.pager.model.ts create mode 100644 api/src/dto/form/form.statistic.model.ts create mode 100644 api/src/dto/form/form.update.input.ts create mode 100644 api/src/dto/form/page.input.ts create mode 100644 api/src/dto/form/page.model.ts create mode 100644 api/src/dto/profile/profile.model.ts create mode 100644 api/src/dto/profile/profile.update.input.ts create mode 100644 api/src/dto/setting/setting.model.ts create mode 100644 api/src/dto/setting/setting.pager.model.ts create mode 100644 api/src/dto/status.model.ts create mode 100644 api/src/dto/submission/device.input.ts create mode 100644 api/src/dto/submission/device.model.ts create mode 100644 api/src/dto/submission/geo.location.model.ts create mode 100644 api/src/dto/submission/submission.field.model.ts create mode 100644 api/src/dto/submission/submission.model.ts create mode 100644 api/src/dto/submission/submission.pager.filter.input.ts create mode 100644 api/src/dto/submission/submission.pager.model.ts create mode 100644 api/src/dto/submission/submission.progress.model.ts create mode 100644 api/src/dto/submission/submission.set.field.input.ts create mode 100644 api/src/dto/submission/submission.start.input.ts create mode 100644 api/src/dto/submission/submission.statistic.model.ts create mode 100644 api/src/dto/user/user.create.input.ts create mode 100644 api/src/dto/user/user.model.ts create mode 100644 api/src/dto/user/user.pager.model.ts create mode 100644 api/src/dto/user/user.statistic.model.ts create mode 100644 api/src/dto/user/user.update.input.ts create mode 100644 api/src/entity/embedded/analytics.embedded.ts create mode 100644 api/src/entity/embedded/colors.embedded.ts create mode 100644 api/src/entity/embedded/design.embedded.ts create mode 100644 api/src/entity/embedded/device.embedded.ts create mode 100644 api/src/entity/embedded/geo.location.embedded.ts create mode 100644 api/src/entity/embedded/rating.embedded.ts create mode 100644 api/src/entity/form.entity.ts create mode 100644 api/src/entity/form.field.entity.ts create mode 100644 api/src/entity/form.field.logic.entity.ts create mode 100644 api/src/entity/form.field.option.entity.ts create mode 100644 api/src/entity/form.hook.entity.ts create mode 100644 api/src/entity/form.notification.entity.ts create mode 100644 api/src/entity/index.ts create mode 100644 api/src/entity/page.button.entity.ts create mode 100644 api/src/entity/page.entity.ts create mode 100644 api/src/entity/submission.entity.ts create mode 100644 api/src/entity/submission.field.entity.ts create mode 100644 api/src/entity/user.entity.ts create mode 100644 api/src/entity/visitor.entity.ts create mode 100644 api/src/guard/gql.auth.guard.ts create mode 100644 api/src/guard/index.ts create mode 100644 api/src/guard/local.auth.guard.ts create mode 100644 api/src/guard/roles.guard.ts create mode 100644 api/src/main.ts create mode 100644 api/src/migrations/mariadb/1619723437787-initial.ts create mode 100644 api/src/migrations/mariadb/1621078163528-layout.ts create mode 100644 api/src/migrations/mariadb/1641124349039-submission.ts create mode 100644 api/src/migrations/mariadb/1641132645227-confirm.ts create mode 100644 api/src/migrations/mariadb/1641151802308-idx.ts create mode 100644 api/src/migrations/mariadb/1641193946192-anonymous.ts create mode 100644 api/src/migrations/mariadb/1645952169100-defaultValue.ts create mode 100644 api/src/migrations/mariadb/1645956388810-defaultValue.ts create mode 100644 api/src/migrations/postgres/1619723437787-initial.ts create mode 100644 api/src/migrations/postgres/1621078163528-layout.ts create mode 100644 api/src/migrations/postgres/1641124349039-submission.ts create mode 100644 api/src/migrations/postgres/1641132645227-confirm.ts create mode 100644 api/src/migrations/postgres/1641151802308-idx.ts create mode 100644 api/src/migrations/postgres/1641193946192-anonymous.ts create mode 100644 api/src/migrations/postgres/1645952169100-defaultValue.ts create mode 100644 api/src/migrations/postgres/1645956388810-defaultValue.ts create mode 100644 api/src/migrations/sqlite.migration.ts create mode 100644 api/src/migrations/sqlite/1619723437787-initial.ts create mode 100644 api/src/migrations/sqlite/1621078163528-layout.ts create mode 100644 api/src/migrations/sqlite/1641124349039-submission.ts create mode 100644 api/src/migrations/sqlite/1641132645227-confirm.ts create mode 100644 api/src/migrations/sqlite/1641151802308-idx.ts create mode 100644 api/src/migrations/sqlite/1641193946192-anonymous.ts create mode 100644 api/src/migrations/sqlite/1645952169100-defaultValue.ts create mode 100644 api/src/migrations/sqlite/1645956388810-defaultValue.ts create mode 100644 api/src/pipe/form/form.by.id.pipe.ts create mode 100644 api/src/pipe/form/index.ts create mode 100644 api/src/pipe/index.ts create mode 100644 api/src/pipe/submission/index.ts create mode 100644 api/src/pipe/submission/submission.by.id.pipe.ts create mode 100644 api/src/pipe/user/index.ts create mode 100644 api/src/pipe/user/user.by.id.pipe.ts create mode 100644 api/src/resolver/auth/auth.login.mutation.ts create mode 100644 api/src/resolver/auth/auth.register.mutation.ts create mode 100644 api/src/resolver/auth/index.ts create mode 100644 api/src/resolver/context.cache.ts create mode 100644 api/src/resolver/form/form.create.mutation.ts create mode 100644 api/src/resolver/form/form.delete.mutation.ts create mode 100644 api/src/resolver/form/form.field.resolver.ts create mode 100644 api/src/resolver/form/form.list.query.ts create mode 100644 api/src/resolver/form/form.query.ts create mode 100644 api/src/resolver/form/form.resolver.ts create mode 100644 api/src/resolver/form/form.statistic.query.ts create mode 100644 api/src/resolver/form/form.statistic.resolver.ts create mode 100644 api/src/resolver/form/form.update.mutation.ts create mode 100644 api/src/resolver/form/index.ts create mode 100644 api/src/resolver/form/page.resolver.ts create mode 100644 api/src/resolver/index.ts create mode 100644 api/src/resolver/profile/index.ts create mode 100644 api/src/resolver/profile/profile.query.ts create mode 100644 api/src/resolver/profile/profile.update.mutation.ts create mode 100644 api/src/resolver/setting/index.ts create mode 100644 api/src/resolver/setting/setting.mutation.ts create mode 100644 api/src/resolver/setting/setting.query.ts create mode 100644 api/src/resolver/status.resolver.ts create mode 100644 api/src/resolver/submission/index.ts create mode 100644 api/src/resolver/submission/submission.field.resolver.ts create mode 100644 api/src/resolver/submission/submission.finish.mutation.ts create mode 100644 api/src/resolver/submission/submission.list.query.ts create mode 100644 api/src/resolver/submission/submission.progress.resolver.ts create mode 100644 api/src/resolver/submission/submission.query.ts create mode 100644 api/src/resolver/submission/submission.resolver.ts create mode 100644 api/src/resolver/submission/submission.set.field.mutation.ts create mode 100644 api/src/resolver/submission/submission.start.mutation.ts create mode 100644 api/src/resolver/submission/submission.statistic.query.ts create mode 100644 api/src/resolver/submission/submission.statistic.resolver.ts create mode 100644 api/src/resolver/user/index.ts create mode 100644 api/src/resolver/user/user.delete.mutation.ts create mode 100644 api/src/resolver/user/user.list.query.ts create mode 100644 api/src/resolver/user/user.query.ts create mode 100644 api/src/resolver/user/user.resolver.ts create mode 100644 api/src/resolver/user/user.statistic.query.ts create mode 100644 api/src/resolver/user/user.statistic.resolver.ts create mode 100644 api/src/resolver/user/user.update.mutation.ts create mode 100644 api/src/service/auth/auth.service.ts create mode 100644 api/src/service/auth/index.ts create mode 100644 api/src/service/auth/jwt.strategy.ts create mode 100644 api/src/service/auth/local.strategy.ts create mode 100644 api/src/service/auth/password.service.ts create mode 100644 api/src/service/form/form.create.service.ts create mode 100644 api/src/service/form/form.delete.service.ts create mode 100644 api/src/service/form/form.field.service.ts create mode 100644 api/src/service/form/form.page.create.service.ts create mode 100644 api/src/service/form/form.page.update.service.ts create mode 100644 api/src/service/form/form.service.ts create mode 100644 api/src/service/form/form.statistic.service.ts create mode 100644 api/src/service/form/form.update.service.ts create mode 100644 api/src/service/form/index.ts create mode 100644 api/src/service/id.service.ts create mode 100644 api/src/service/index.ts create mode 100644 api/src/service/installation.metrics.service.ts create mode 100644 api/src/service/mail.service.ts create mode 100644 api/src/service/profile/index.ts create mode 100644 api/src/service/profile/profile.update.service.ts create mode 100644 api/src/service/setting.service.ts create mode 100644 api/src/service/submission/index.ts create mode 100644 api/src/service/submission/submission.hook.service.ts create mode 100644 api/src/service/submission/submission.notification.service.ts create mode 100644 api/src/service/submission/submission.service.ts create mode 100644 api/src/service/submission/submission.set.field.service.ts create mode 100644 api/src/service/submission/submission.start.service.ts create mode 100644 api/src/service/submission/submission.statistic.service.ts create mode 100644 api/src/service/submission/submission.token.service.ts create mode 100644 api/src/service/user/boot.service.ts create mode 100644 api/src/service/user/index.ts create mode 100644 api/src/service/user/user.create.service.ts create mode 100644 api/src/service/user/user.delete.service.ts create mode 100644 api/src/service/user/user.service.ts create mode 100644 api/src/service/user/user.statistic.service.ts create mode 100644 api/src/service/user/user.token.service.ts create mode 100644 api/src/service/user/user.update.service.ts create mode 100644 api/tsconfig.build.json create mode 100644 api/tsconfig.json create mode 100644 api/yarn.lock delete mode 160000 ui create mode 100644 ui/.dockerignore create mode 100644 ui/.eslintrc.js create mode 100644 ui/.gitignore create mode 100644 ui/.graphqlconfig create mode 100644 ui/.prettierrc.js create mode 100644 ui/Dockerfile create mode 100644 ui/LICENSE.md create mode 100644 ui/README.md create mode 100644 ui/assets/global.scss create mode 100644 ui/assets/images/logo_white.png create mode 100644 ui/assets/images/logo_white_small.png create mode 100644 ui/assets/images/marker-icon-2x.png create mode 100644 ui/assets/images/marker-shadow.png create mode 100644 ui/assets/variables.scss create mode 100644 ui/components/auth/footer.module.scss create mode 100644 ui/components/auth/footer.tsx create mode 100644 ui/components/auth/layout.tsx create mode 100644 ui/components/clean.input.ts create mode 100644 ui/components/date.time.tsx create mode 100644 ui/components/error.page.tsx create mode 100644 ui/components/form/admin/base.data.tab.tsx create mode 100644 ui/components/form/admin/design.tab.tsx create mode 100644 ui/components/form/admin/end.page.tab.tsx create mode 100644 ui/components/form/admin/export.submission.action.tsx create mode 100644 ui/components/form/admin/field.card.tsx create mode 100644 ui/components/form/admin/fields.tab.tsx create mode 100644 ui/components/form/admin/hooks.tab.tsx create mode 100644 ui/components/form/admin/is.live.tsx create mode 100644 ui/components/form/admin/logic.block.tsx create mode 100644 ui/components/form/admin/notification.card.tsx create mode 100644 ui/components/form/admin/notifications.tab.tsx create mode 100644 ui/components/form/admin/start.page.tab.tsx create mode 100644 ui/components/form/admin/submission.values.tsx create mode 100644 ui/components/form/layouts/card/field.tsx create mode 100644 ui/components/form/layouts/card/index.module.scss create mode 100644 ui/components/form/layouts/card/index.tsx create mode 100644 ui/components/form/layouts/card/page.tsx create mode 100644 ui/components/form/layouts/layout.props.ts create mode 100644 ui/components/form/layouts/page.buttons.tsx create mode 100644 ui/components/form/layouts/slider/field.tsx create mode 100644 ui/components/form/layouts/slider/index.tsx create mode 100644 ui/components/form/layouts/slider/page.module.scss create mode 100644 ui/components/form/layouts/slider/page.tsx create mode 100644 ui/components/form/types/abstract.type.tsx create mode 100644 ui/components/form/types/checkbox/checkbox.admin.tsx create mode 100644 ui/components/form/types/checkbox/checkbox.input.tsx create mode 100644 ui/components/form/types/checkbox/index.ts create mode 100644 ui/components/form/types/date/date.admin.tsx create mode 100644 ui/components/form/types/date/date.input.tsx create mode 100644 ui/components/form/types/date/index.ts create mode 100644 ui/components/form/types/dropdown/dropdown.admin.tsx create mode 100644 ui/components/form/types/dropdown/dropdown.input.tsx create mode 100644 ui/components/form/types/dropdown/index.ts create mode 100644 ui/components/form/types/email/email.admin.tsx create mode 100644 ui/components/form/types/email/email.input.tsx create mode 100644 ui/components/form/types/email/index.ts create mode 100644 ui/components/form/types/field.admin.props.ts create mode 100644 ui/components/form/types/field.input.builder.type.ts create mode 100644 ui/components/form/types/field.input.props.ts create mode 100644 ui/components/form/types/hidden/hidden.admin.tsx create mode 100644 ui/components/form/types/hidden/index.ts create mode 100644 ui/components/form/types/image/image.admin.tsx create mode 100644 ui/components/form/types/image/image.type.tsx create mode 100644 ui/components/form/types/image/index.ts create mode 100644 ui/components/form/types/index.ts create mode 100644 ui/components/form/types/link/index.ts create mode 100644 ui/components/form/types/link/link.admin.tsx create mode 100644 ui/components/form/types/link/link.input.tsx create mode 100644 ui/components/form/types/location/index.ts create mode 100644 ui/components/form/types/location/location.admin.tsx create mode 100644 ui/components/form/types/location/location.input.tsx create mode 100644 ui/components/form/types/number/index.ts create mode 100644 ui/components/form/types/number/number.admin.tsx create mode 100644 ui/components/form/types/number/number.input.tsx create mode 100644 ui/components/form/types/radio/index.ts create mode 100644 ui/components/form/types/radio/radio.admin.tsx create mode 100644 ui/components/form/types/radio/radio.input.tsx create mode 100644 ui/components/form/types/rating/index.ts create mode 100644 ui/components/form/types/rating/rating.admin.tsx create mode 100644 ui/components/form/types/rating/rating.input.tsx create mode 100644 ui/components/form/types/slider/index.ts create mode 100644 ui/components/form/types/slider/slider.admin.tsx create mode 100644 ui/components/form/types/slider/slider.input.tsx create mode 100644 ui/components/form/types/textarea/index.ts create mode 100644 ui/components/form/types/textarea/textarea.admin.tsx create mode 100644 ui/components/form/types/textarea/textarea.input.tsx create mode 100644 ui/components/form/types/textfield/index.ts create mode 100644 ui/components/form/types/textfield/textfield.admin.tsx create mode 100644 ui/components/form/types/textfield/textfield.input.tsx create mode 100644 ui/components/form/types/yes_no/index.tsx create mode 100644 ui/components/form/types/yes_no/yes_no.admin.tsx create mode 100644 ui/components/form/types/yes_no/yes_no.input.tsx create mode 100644 ui/components/input/color.tsx create mode 100644 ui/components/loading.page.tsx create mode 100644 ui/components/map/draggable.marker.tsx create mode 100644 ui/components/omf.module.scss create mode 100644 ui/components/omf.tsx create mode 100644 ui/components/sidemenu.tsx create mode 100644 ui/components/structure.tsx create mode 100644 ui/components/styled/button.tsx create mode 100644 ui/components/styled/checkbox.tsx create mode 100644 ui/components/styled/date.input.tsx create mode 100644 ui/components/styled/h1.tsx create mode 100644 ui/components/styled/h2.tsx create mode 100644 ui/components/styled/input.tsx create mode 100644 ui/components/styled/markdown.tsx create mode 100644 ui/components/styled/number.input.tsx create mode 100644 ui/components/styled/p.tsx create mode 100644 ui/components/styled/radio.tsx create mode 100644 ui/components/styled/select.tsx create mode 100644 ui/components/styled/textarea.input.tsx create mode 100644 ui/components/time.ago.tsx create mode 100644 ui/components/use.imerative.query.ts create mode 100644 ui/components/use.math.ts create mode 100644 ui/components/use.router.ts create mode 100644 ui/components/use.submission.ts create mode 100644 ui/components/use.window.size.ts create mode 100644 ui/components/user/admin/base.data.tab.tsx create mode 100644 ui/components/user/role.tsx create mode 100644 ui/components/with.auth.tsx create mode 100644 ui/doc/development.md create mode 100644 ui/doc/environment.md create mode 100644 ui/graphql/client.ts create mode 100644 ui/graphql/fragment/admin.profile.fragment.ts create mode 100644 ui/graphql/fragment/admin.user.fragment.ts create mode 100644 ui/graphql/fragment/form.fragment.ts create mode 100644 ui/graphql/fragment/form.pager.fragment.ts create mode 100644 ui/graphql/fragment/form.public.fragment.ts create mode 100644 ui/graphql/fragment/submission.fragment.ts create mode 100644 ui/graphql/fragment/user.pager.fragment.ts create mode 100644 ui/graphql/mutation/form.create.mutation.ts create mode 100644 ui/graphql/mutation/form.delete.mutation.ts create mode 100644 ui/graphql/mutation/form.update.mutation.ts create mode 100644 ui/graphql/mutation/login.mutation.ts create mode 100644 ui/graphql/mutation/profile.update.mutation.ts create mode 100644 ui/graphql/mutation/register.mutation.ts create mode 100644 ui/graphql/mutation/submission.finish.mutation.ts create mode 100644 ui/graphql/mutation/submission.set.field.mutation.ts create mode 100644 ui/graphql/mutation/submission.start.mutation.ts create mode 100644 ui/graphql/mutation/user.delete.mutation.ts create mode 100644 ui/graphql/mutation/user.update.mutation.ts create mode 100644 ui/graphql/query/admin.profile.query.ts create mode 100644 ui/graphql/query/admin.statistic.query.ts create mode 100644 ui/graphql/query/admin.user.query.ts create mode 100644 ui/graphql/query/form.pager.query.ts create mode 100644 ui/graphql/query/form.public.query.ts create mode 100644 ui/graphql/query/form.query.ts create mode 100644 ui/graphql/query/me.query.ts create mode 100644 ui/graphql/query/settings.query.ts create mode 100644 ui/graphql/query/status.query.ts create mode 100644 ui/graphql/query/submission.pager.query.ts create mode 100644 ui/graphql/query/user.pager.query.ts create mode 100644 ui/i18n.ts create mode 100644 ui/locales/ar/admin.json create mode 100644 ui/locales/ar/common.json create mode 100644 ui/locales/ar/form.json create mode 100644 ui/locales/ar/index.ts create mode 100644 ui/locales/ar/language.json create mode 100644 ui/locales/ar/login.json create mode 100644 ui/locales/ar/profile.json create mode 100644 ui/locales/ar/register.json create mode 100644 ui/locales/ar/statistic.json create mode 100644 ui/locales/ar/submission.json create mode 100644 ui/locales/ar/type.json create mode 100644 ui/locales/ar/user.json create mode 100644 ui/locales/ar/validation.json create mode 100644 ui/locales/cn/admin.json create mode 100644 ui/locales/cn/common.json create mode 100644 ui/locales/cn/form.json create mode 100644 ui/locales/cn/index.ts create mode 100644 ui/locales/cn/language.json create mode 100644 ui/locales/cn/login.json create mode 100644 ui/locales/cn/profile.json create mode 100644 ui/locales/cn/register.json create mode 100644 ui/locales/cn/statistic.json create mode 100644 ui/locales/cn/submission.json create mode 100644 ui/locales/cn/type.json create mode 100644 ui/locales/cn/user.json create mode 100644 ui/locales/cn/validation.json create mode 100644 ui/locales/da/admin.json create mode 100644 ui/locales/da/common.json create mode 100644 ui/locales/da/form.json create mode 100644 ui/locales/da/index.ts create mode 100644 ui/locales/da/language.json create mode 100644 ui/locales/da/login.json create mode 100644 ui/locales/da/profile.json create mode 100644 ui/locales/da/register.json create mode 100644 ui/locales/da/statistic.json create mode 100644 ui/locales/da/submission.json create mode 100644 ui/locales/da/type.json create mode 100644 ui/locales/da/user.json create mode 100644 ui/locales/da/validation.json create mode 100644 ui/locales/de/admin.json create mode 100644 ui/locales/de/common.json create mode 100644 ui/locales/de/form.json create mode 100644 ui/locales/de/index.ts create mode 100644 ui/locales/de/language.json create mode 100644 ui/locales/de/login.json create mode 100644 ui/locales/de/profile.json create mode 100644 ui/locales/de/register.json create mode 100644 ui/locales/de/statistic.json create mode 100644 ui/locales/de/submission.json create mode 100644 ui/locales/de/type.json create mode 100644 ui/locales/de/user.json create mode 100644 ui/locales/de/validation.json create mode 100644 ui/locales/en/admin.json create mode 100644 ui/locales/en/common.json create mode 100644 ui/locales/en/form.json create mode 100644 ui/locales/en/index.ts create mode 100644 ui/locales/en/language.json create mode 100644 ui/locales/en/login.json create mode 100644 ui/locales/en/profile.json create mode 100644 ui/locales/en/register.json create mode 100644 ui/locales/en/statistic.json create mode 100644 ui/locales/en/submission.json create mode 100644 ui/locales/en/type.json create mode 100644 ui/locales/en/user.json create mode 100644 ui/locales/en/validation.json create mode 100644 ui/locales/es/admin.json create mode 100644 ui/locales/es/common.json create mode 100644 ui/locales/es/form.json create mode 100644 ui/locales/es/index.ts create mode 100644 ui/locales/es/language.json create mode 100644 ui/locales/es/login.json create mode 100644 ui/locales/es/profile.json create mode 100644 ui/locales/es/register.json create mode 100644 ui/locales/es/statistic.json create mode 100644 ui/locales/es/submission.json create mode 100644 ui/locales/es/type.json create mode 100644 ui/locales/es/user.json create mode 100644 ui/locales/es/validation.json create mode 100644 ui/locales/fr/admin.json create mode 100644 ui/locales/fr/common.json create mode 100644 ui/locales/fr/form.json create mode 100644 ui/locales/fr/index.ts create mode 100644 ui/locales/fr/language.json create mode 100644 ui/locales/fr/login.json create mode 100644 ui/locales/fr/profile.json create mode 100644 ui/locales/fr/register.json create mode 100644 ui/locales/fr/statistic.json create mode 100644 ui/locales/fr/submission.json create mode 100644 ui/locales/fr/type.json create mode 100644 ui/locales/fr/user.json create mode 100644 ui/locales/fr/validation.json create mode 100644 ui/locales/hi/admin.json create mode 100644 ui/locales/hi/common.json create mode 100644 ui/locales/hi/form.json create mode 100644 ui/locales/hi/index.ts create mode 100644 ui/locales/hi/language.json create mode 100644 ui/locales/hi/login.json create mode 100644 ui/locales/hi/profile.json create mode 100644 ui/locales/hi/register.json create mode 100644 ui/locales/hi/statistic.json create mode 100644 ui/locales/hi/submission.json create mode 100644 ui/locales/hi/type.json create mode 100644 ui/locales/hi/user.json create mode 100644 ui/locales/hi/validation.json create mode 100644 ui/locales/index.ts create mode 100644 ui/locales/it/admin.json create mode 100644 ui/locales/it/common.json create mode 100644 ui/locales/it/form.json create mode 100644 ui/locales/it/index.ts create mode 100644 ui/locales/it/language.json create mode 100644 ui/locales/it/login.json create mode 100644 ui/locales/it/profile.json create mode 100644 ui/locales/it/register.json create mode 100644 ui/locales/it/statistic.json create mode 100644 ui/locales/it/submission.json create mode 100644 ui/locales/it/type.json create mode 100644 ui/locales/it/user.json create mode 100644 ui/locales/it/validation.json create mode 100644 ui/locales/ja/admin.json create mode 100644 ui/locales/ja/common.json create mode 100644 ui/locales/ja/form.json create mode 100644 ui/locales/ja/index.ts create mode 100644 ui/locales/ja/language.json create mode 100644 ui/locales/ja/login.json create mode 100644 ui/locales/ja/profile.json create mode 100644 ui/locales/ja/register.json create mode 100644 ui/locales/ja/statistic.json create mode 100644 ui/locales/ja/submission.json create mode 100644 ui/locales/ja/type.json create mode 100644 ui/locales/ja/user.json create mode 100644 ui/locales/ja/validation.json create mode 100644 ui/locales/missing.ts create mode 100644 ui/locales/nl/admin.json create mode 100644 ui/locales/nl/common.json create mode 100644 ui/locales/nl/form.json create mode 100644 ui/locales/nl/index.ts create mode 100644 ui/locales/nl/language.json create mode 100644 ui/locales/nl/login.json create mode 100644 ui/locales/nl/profile.json create mode 100644 ui/locales/nl/register.json create mode 100644 ui/locales/nl/statistic.json create mode 100644 ui/locales/nl/submission.json create mode 100644 ui/locales/nl/type.json create mode 100644 ui/locales/nl/user.json create mode 100644 ui/locales/nl/validation.json create mode 100644 ui/locales/pl/admin.json create mode 100644 ui/locales/pl/common.json create mode 100644 ui/locales/pl/form.json create mode 100644 ui/locales/pl/index.ts create mode 100644 ui/locales/pl/language.json create mode 100644 ui/locales/pl/login.json create mode 100644 ui/locales/pl/profile.json create mode 100644 ui/locales/pl/register.json create mode 100644 ui/locales/pl/statistic.json create mode 100644 ui/locales/pl/submission.json create mode 100644 ui/locales/pl/type.json create mode 100644 ui/locales/pl/user.json create mode 100644 ui/locales/pl/validation.json create mode 100644 ui/locales/pt_BR/admin.json create mode 100644 ui/locales/pt_BR/common.json create mode 100644 ui/locales/pt_BR/form.json create mode 100644 ui/locales/pt_BR/index.ts create mode 100644 ui/locales/pt_BR/language.json create mode 100644 ui/locales/pt_BR/login.json create mode 100644 ui/locales/pt_BR/profile.json create mode 100644 ui/locales/pt_BR/register.json create mode 100644 ui/locales/pt_BR/statistic.json create mode 100644 ui/locales/pt_BR/submission.json create mode 100644 ui/locales/pt_BR/type.json create mode 100644 ui/locales/pt_BR/user.json create mode 100644 ui/locales/pt_BR/validation.json create mode 100644 ui/locales/pt_PT/admin.json create mode 100644 ui/locales/pt_PT/common.json create mode 100644 ui/locales/pt_PT/form.json create mode 100644 ui/locales/pt_PT/index.ts create mode 100644 ui/locales/pt_PT/language.json create mode 100644 ui/locales/pt_PT/login.json create mode 100644 ui/locales/pt_PT/profile.json create mode 100644 ui/locales/pt_PT/register.json create mode 100644 ui/locales/pt_PT/statistic.json create mode 100644 ui/locales/pt_PT/submission.json create mode 100644 ui/locales/pt_PT/type.json create mode 100644 ui/locales/pt_PT/user.json create mode 100644 ui/locales/pt_PT/validation.json create mode 100644 ui/locales/ru/admin.json create mode 100644 ui/locales/ru/common.json create mode 100644 ui/locales/ru/form.json create mode 100644 ui/locales/ru/index.ts create mode 100644 ui/locales/ru/language.json create mode 100644 ui/locales/ru/login.json create mode 100644 ui/locales/ru/profile.json create mode 100644 ui/locales/ru/register.json create mode 100644 ui/locales/ru/statistic.json create mode 100644 ui/locales/ru/submission.json create mode 100644 ui/locales/ru/type.json create mode 100644 ui/locales/ru/user.json create mode 100644 ui/locales/ru/validation.json create mode 100644 ui/locales/sort.ts create mode 100644 ui/locales/sv/admin.json create mode 100644 ui/locales/sv/common.json create mode 100644 ui/locales/sv/form.json create mode 100644 ui/locales/sv/index.ts create mode 100644 ui/locales/sv/language.json create mode 100644 ui/locales/sv/login.json create mode 100644 ui/locales/sv/profile.json create mode 100644 ui/locales/sv/register.json create mode 100644 ui/locales/sv/statistic.json create mode 100644 ui/locales/sv/submission.json create mode 100644 ui/locales/sv/type.json create mode 100644 ui/locales/sv/user.json create mode 100644 ui/locales/sv/validation.json create mode 100644 ui/locales/ta/admin.json create mode 100644 ui/locales/ta/common.json create mode 100644 ui/locales/ta/form.json create mode 100644 ui/locales/ta/index.ts create mode 100644 ui/locales/ta/language.json create mode 100644 ui/locales/ta/login.json create mode 100644 ui/locales/ta/profile.json create mode 100644 ui/locales/ta/register.json create mode 100644 ui/locales/ta/statistic.json create mode 100644 ui/locales/ta/submission.json create mode 100644 ui/locales/ta/type.json create mode 100644 ui/locales/ta/user.json create mode 100644 ui/locales/ta/validation.json create mode 100644 ui/locales/uk/admin.json create mode 100644 ui/locales/uk/common.json create mode 100644 ui/locales/uk/form.json create mode 100644 ui/locales/uk/index.ts create mode 100644 ui/locales/uk/language.json create mode 100644 ui/locales/uk/login.json create mode 100644 ui/locales/uk/profile.json create mode 100644 ui/locales/uk/register.json create mode 100644 ui/locales/uk/statistic.json create mode 100644 ui/locales/uk/submission.json create mode 100644 ui/locales/uk/type.json create mode 100644 ui/locales/uk/user.json create mode 100644 ui/locales/uk/validation.json create mode 100644 ui/next-env.d.ts create mode 100644 ui/next.config.js create mode 100644 ui/next.config.type.ts create mode 100644 ui/package.json create mode 100644 ui/pages/_app.tsx create mode 100644 ui/pages/admin/forms/[id]/index.tsx create mode 100644 ui/pages/admin/forms/[id]/submissions.tsx create mode 100644 ui/pages/admin/forms/create.tsx create mode 100644 ui/pages/admin/forms/index.tsx create mode 100644 ui/pages/admin/index.tsx create mode 100644 ui/pages/admin/profile.tsx create mode 100644 ui/pages/admin/users/[id]/index.tsx create mode 100644 ui/pages/admin/users/index.tsx create mode 100644 ui/pages/form/[id]/index.module.scss create mode 100644 ui/pages/form/[id]/index.tsx create mode 100644 ui/pages/form/index.tsx create mode 100644 ui/pages/index.tsx create mode 100644 ui/pages/login/confirm/[code].tsx create mode 100644 ui/pages/login/index.module.scss create mode 100644 ui/pages/login/index.tsx create mode 100644 ui/pages/login/recover.tsx create mode 100644 ui/pages/register.module.scss create mode 100644 ui/pages/register.tsx create mode 100644 ui/public/favicon.ico create mode 100644 ui/store/auth/index.ts create mode 100644 ui/store/index.ts create mode 100644 ui/tsconfig.json create mode 100644 ui/yarn.lock diff --git a/.github/workflows/api-image.yml b/.github/workflows/api-image.yml new file mode 100644 index 00000000..0703dd6b --- /dev/null +++ b/.github/workflows/api-image.yml @@ -0,0 +1,55 @@ +name: Docker Image CI + +on: + push: + paths: + - 'api/**' + branches: + - master + release: + types: + - published + +jobs: + build: + name: push API docker image + runs-on: ubuntu-latest + + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + with: + sparse-checkout: 'api' + sparse-checkout-cone-mode: false + - name: Move API files to root + run: | + ls -lah + shopt -s dotglob + mv api/* . + rm -rf api + ls -lah + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ohmyform/api + tags: | + type=raw,value=latest + type=semver,pattern={{major}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{version}} + + - name: Build and push Docker image + uses: docker/login-action@v3 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/api-test.yml b/.github/workflows/api-test.yml new file mode 100644 index 00000000..06070ffc --- /dev/null +++ b/.github/workflows/api-test.yml @@ -0,0 +1,222 @@ +name: Lint + +on: + pull_request: + paths: + - 'api/**' + branches: + - master + +env: + CREATE_ADMIN: true + ADMIN_EMAIL: admin@localhost + ADMIN_USERNAME: admin + ADMIN_PASSWORD: admin + MAILER_URI: smtp://localhost:1025 + +jobs: + run-linters: + name: run API lint + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + with: + sparse-checkout: 'api' + sparse-checkout-cone-mode: false + - name: Move API files to root + run: | + ls -lah + shopt -s dotglob + mv api/* . + rm -rf api + ls -lah + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 16 + + # ESLint and Prettier must be in `package.json` + - name: Install Node.js dependencies + run: yarn install --frozen-lockfile --silent + + - run: ls -lah + + - name: Lint + uses: reviewdog/action-eslint@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-pr-review # Change reporter. + eslint_flags: '{src,test}/**/*.ts' + + - name: Typecheck + uses: andoshin11/typescript-error-reporter-action@v1.0.2 + + run-postgres: + name: run API postgres migrations + runs-on: ubuntu-latest + + services: + postgres: + image: postgres:10-alpine + env: + POSTGRES_USER: root + POSTGRES_PASSWORD: root + POSTGRES_DB: ohmyform + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + with: + sparse-checkout: 'api' + sparse-checkout-cone-mode: false + - name: Move API files to root + run: | + ls -lah + shopt -s dotglob + mv api/* . + rm -rf api + ls -lah + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 16 + + - name: Install Node.js dependencies + run: yarn install --frozen-lockfile --silent + + - name: PostgreSQL Migrations + run: yarn typeorm migration:run + env: + DATABASE_DRIVER: postgres + + TYPEORM_CONNECTION: postgres + TYPEORM_HOST: localhost + TYPEORM_PORT: 5432 + TYPEORM_USERNAME: root + TYPEORM_PASSWORD: root + TYPEORM_DATABASE: ohmyform + TYPEORM_AUTO_SCHEMA_SYNC: false + TYPEORM_ENTITIES: src/entity/**/*.ts + TYPEORM_SUBSCRIBERS: src/subscriber/**/*.ts + TYPEORM_MIGRATIONS: src/migrations/postgres/**/*.ts + TYPEORM_MIGRATIONS_TRANSACTION_MODE: 'each' + TYPEORM_ENTITIES_DIR: src/entity + TYPEORM_MIGRATIONS_DIR: src/migrations/postgres + TYPEORM_SUBSCRIBERS_DIR: src/subscriber + + run-mariadb: + name: run API mariadb migrations + runs-on: ubuntu-latest + + services: + mariadb: + image: mariadb + env: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: ohmyform + ports: + - 3306:3306 + options: >- + --health-cmd="healthcheck.sh --connect --innodb_initialized" + --health-interval=10s + --health-timeout=5s + --health-retries=3 + + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + with: + sparse-checkout: 'api' + sparse-checkout-cone-mode: false + - name: Move API files to root + run: | + ls -lah + shopt -s dotglob + mv api/* . + rm -rf api + ls -lah + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 16 + + - name: Install Node.js dependencies + run: yarn install --frozen-lockfile --silent + + - name: MariaDB Migrations + run: yarn typeorm migration:run + env: + DATABASE_DRIVER: mariadb + + TYPEORM_CONNECTION: mariadb + TYPEORM_HOST: localhost + TYPEORM_PORT: 3306 + TYPEORM_USERNAME: root + TYPEORM_PASSWORD: root + TYPEORM_DATABASE: ohmyform + TYPEORM_AUTO_SCHEMA_SYNC: false + TYPEORM_ENTITIES: src/entity/**/*.ts + TYPEORM_SUBSCRIBERS: src/subscriber/**/*.ts + TYPEORM_MIGRATIONS: src/migrations/mariadb/**/*.ts + TYPEORM_MIGRATIONS_TRANSACTION_MODE: 'each' + TYPEORM_ENTITIES_DIR: src/entity + TYPEORM_MIGRATIONS_DIR: src/migrations/mariadb + TYPEORM_SUBSCRIBERS_DIR: src/subscriber + + run-sqlite: + name: run API sqlite migrations + runs-on: ubuntu-latest + + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + with: + sparse-checkout: 'api' + sparse-checkout-cone-mode: false + - name: Move API files to root + run: | + ls -lah + shopt -s dotglob + mv api/* . + rm -rf api + ls -lah + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 16 + + - name: Install Node.js dependencies + run: yarn install --frozen-lockfile --silent + + - name: SQLite Migrations + run: yarn typeorm migration:run --transaction none + env: + DATABASE_DRIVER: sqlite + + TYPEORM_CONNECTION: sqlite + TYPEORM_USERNAME: root + TYPEORM_DATABASE: data.sqlite + TYPEORM_AUTO_SCHEMA_SYNC: false + TYPEORM_ENTITIES: src/entity/**/*.ts + TYPEORM_SUBSCRIBERS: src/subscriber/**/*.ts + TYPEORM_MIGRATIONS: src/migrations/sqlite/**/*.ts + TYPEORM_MIGRATIONS_TRANSACTION_MODE: 'none' + TYPEORM_ENTITIES_DIR: src/entity + TYPEORM_MIGRATIONS_DIR: src/migrations/sqlite + TYPEORM_SUBSCRIBERS_DIR: src/subscriber diff --git a/.github/workflows/docker-image.yml b/.github/workflows/combined-image.yml similarity index 76% rename from .github/workflows/docker-image.yml rename to .github/workflows/combined-image.yml index b14484e8..afd40bd0 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/combined-image.yml @@ -2,6 +2,13 @@ name: Docker Image CI on: push: + paths: + - 'ui/**' + - 'api/**' + - 'Dockerfile' + - 'supervisord.conf' + - 'nginx.conf' + - 'docker/**' branches: - master release: @@ -10,7 +17,7 @@ on: jobs: build: - name: Push Docker image to Docker Hub + name: push OHMYFORM docker image runs-on: ubuntu-latest steps: @@ -20,14 +27,14 @@ jobs: submodules: true - name: Log in to Docker Hub - uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + uses: docker/metadata-action@v5 with: images: ohmyform/ohmyform tags: | @@ -37,7 +44,7 @@ jobs: type=semver,pattern={{version}} - name: Build and push Docker image - uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + uses: docker/login-action@v3 with: context: . push: true diff --git a/.github/workflows/ui-image.yml b/.github/workflows/ui-image.yml new file mode 100644 index 00000000..61445fbb --- /dev/null +++ b/.github/workflows/ui-image.yml @@ -0,0 +1,55 @@ +name: Docker Image CI + +on: + push: + paths: + - 'ui/**' + branches: + - master + release: + types: + - published + +jobs: + build: + name: push UI docker image + runs-on: ubuntu-latest + + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + with: + sparse-checkout: 'ui' + sparse-checkout-cone-mode: false + - name: Move UI files to root + run: | + ls -lah + shopt -s dotglob + mv ui/* . + rm -rf ui + ls -lah + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ohmyform/ui + tags: | + type=raw,value=latest + type=semver,pattern={{major}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{version}} + + - name: Build and push Docker image + uses: docker/login-action@v3 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/ui-test.yml b/.github/workflows/ui-test.yml new file mode 100644 index 00000000..0440bd3f --- /dev/null +++ b/.github/workflows/ui-test.yml @@ -0,0 +1,50 @@ +name: Lint + +on: + pull_request: + paths: + - 'ui/**' + branches: + - master + +jobs: + run-linters: + name: run UI lint + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + with: + sparse-checkout: 'ui' + sparse-checkout-cone-mode: false + - name: Move UI files to root + run: | + ls -lah + shopt -s dotglob + mv ui/* . + rm -rf ui + ls -lah + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 16 + + # ESLint and Prettier must be in `package.json` + - name: Install Node.js dependencies + run: yarn install --frozen-lockfile --silent + + - name: Lint + uses: reviewdog/action-eslint@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-pr-review # Change reporter. + eslint_flags: 'pages/ store/ components/ graphql/' + + - name: Typecheck + uses: andoshin11/typescript-error-reporter-action@v1.0.2 + diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index b2ce7cc5..00000000 --- a/.gitmodules +++ /dev/null @@ -1,7 +0,0 @@ -[submodule "ui"] - path = ui - url = https://github.com/ohmyform/ui - -[submodule "api"] - path = api - url = https://github.com/ohmyform/api diff --git a/CHANGELOG.md b/CHANGELOG.md index 2aa10e62..f25b5a0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,71 +9,111 @@ and this project adheres to [Semantic Versioning](http://semver.org/). Template for next version ## [Unreleased] -### Added - -### Changed - -### Fixed - -### Security --> ## [Unreleased] -### Added - -### Changed - -### Fixed - -* Fixed typo https://github.com/ohmyform/ohmyform/pull/185 -* node prune location (https://github.com/ohmyform/ohmyform/issues/184) - -### Security +- [UI] node prune location (https://github.com/ohmyform/ohmyform/issues/184) +- [API] creation of new logic elements +- [API] node prune location (https://github.com/ohmyform/ohmyform/issues/184) +- Fixed typo https://github.com/ohmyform/ohmyform/pull/185 +- node prune location (https://github.com/ohmyform/ohmyform/issues/184) +- use monorepo (https://github.com/ohmyform/ohmyform/pull/221) ## [1.0.3] - 2022-03-27 -### Updates - -* https://github.com/ohmyform/api/releases/tag/1.0.3 -* https://github.com/ohmyform/ui/releases/tag/1.0.3 - -### Added - -* minimal configuration example for caddy server (https://github.com/ohmyform/ohmyform/pull/167) +- [UI] default form now has an end page +- [UI] sorting of fields in excel export +- [API] missing encode / decode for form fields within submissions (https://github.com/ohmyform/ui/commit/30ff2c96bca20c1641d9cbb96c34cce934e1afea#r68602651) +- [API] form field resolvers were missing +- [API] node-gyp update to enable build on osx 12.3 +- [API] creating of new fields +- [API] notifications / hooks / pages and buttons encode and decode their ids +- [API] add start and end page to form create call +- minimal configuration example for caddy server (https://github.com/ohmyform/ohmyform/pull/167) +- [API] form hooks should only be queryable for form admins ## [1.0.2] - 2022-03-13 -### Updates - -* https://github.com/ohmyform/api/releases/tag/1.0.2 -* https://github.com/ohmyform/ui/releases/tag/1.0.2 - -### Changed - +- [UI] field sort in excel submission export (https://github.com/ohmyform/ohmyform/issues/163) +- [API] error sending notification when field is not defined (https://github.com/ohmyform/ohmyform/issues/161) - docker restart policy (https://github.com/ohmyform/ohmyform/issues/164) ## [1.0.1] - 2022-03-01 -### Updates - -* https://github.com/ohmyform/api/releases/tag/1.0.1 -* https://github.com/ohmyform/ui/releases/tag/1.0.1 +- [UI] map field type +- [UI] update translations (https://github.com/ohmyform/ui/pull/70) +- [UI] show warning icon in form list if not public +- [UI] default form layout is now "card" +- [UI] creating of new fields combined in new field types +- [UI] locale scripts were missing dependency +- [UI] edit user shows now email in title +- [UI] focus is now passed also do slide layout fields +- [UI] empty fields are no longer submitted +- [UI] stuttery form because of logic rerenders +- [API] allow one field nested data to be submitted +- [API] only update user fields in update mutation if they changed +- [API] form delete +- [API] field submission without value field +- [API] start using hashids to prevent insights into form ids (https://hashids.org/javascript/) ## [1.0.0] - 2022-02-28 -### Updates - -* https://github.com/ohmyform/api/releases/tag/1.0.0 -* https://github.com/ohmyform/ui/releases/tag/1.0.0 - -### Changed - +- [UI] ability to change user passwords +- [UI] add default page background +- [UI] add environment list in [doc](doc/environment.md) +- [UI] show error message on homepage in case there is a problem with api connection +- [UI] new slider field type +- [UI] new card layout for forms +- [UI] field logic +- [UI] add environment config +- [UI] anonymous form submissions (fixes https://github.com/ohmyform/ohmyform/issues/108) +- [UI] checkbox field type (fixed https://github.com/ohmyform/ohmyform/issues/138) +- [UI] combined notificationts to become more versatile +- [UI] use exported hooks for graphql +- [UI] disable swipe gesture +- [UI] upgrade to nextjs 12 +- [UI] change default value from value to defaultValue +- [UI] handle options and values as json correctly +- [UI] exclude empty submissions per default (https://github.com/ohmyform/ohmyform/issues/153) +- [UI] links at the bottom for new users +- [UI] fixes for hide contrib setting +- [UI] fix problem with node-prune on production build +- [UI] translation for prev / continue during form submission +- [UI] reload form list after adding new one (https://github.com/ohmyform/ohmyform/issues/139) +- [UI] android screen size fix (https://github.com/ohmyform/ohmyform/issues/114) +- [UI] sending finish mutation (https://github.com/ohmyform/ui/pull/67) +- [UI] fix dev documentation (https://github.com/ohmyform/ui/issues/65) +- [UI] remove next/image as it does not work with static exports (https://github.com/ohmyform/ohmyform/issues/154) +- [UI] switch back to form.prefixName (https://github.com/ohmyform/ohmyform/issues/150) +- [UI] upgrade all packages to latest versions +- [UI] upgrad all packages +- [API] logic backend components +- [API] forms now have multiple notification +- [API] layout for forms +- [API] mariadb / mysql support (fixes https://github.com/ohmyform/ohmyform/issues/143) +- [API] user confirmation tokens +- [API] email verification +- [API] idx for fields and logic to have stable order +- [API] ability to load submission by id if token is present +- [API] anonymous form submissions (fixes https://github.com/ohmyform/ohmyform/issues/108) +- [API] ability to filter for partial / completed or empty submissions +- [API] migration tests for all commits +- [API] switched from mongoose to typeorm, with support right now for postgres and sqlite +- [API] colors object removed the "colors" postfix +- [API] if unsupported database engine is used error is thrown during startup +- [API] improved eslint checks +- [API] validate submission field data and store it json encoded +- [API] forms are no longer finished on 100% but instead on finish mutation +- [API] field default value renamed from value to defaultValue +- [API] env list in doc +- [API] version env variable for yarn +- [API] path argument error (https://github.com/ohmyform/ohmyform/issues/149) +- [API] webhook and form submission (https://github.com/ohmyform/api/pull/37) +- [API] sqlite migration fixes to allow changes to tables +- [API] upgraded all packages - switched to supervisord based combined container - upgrade to node 16 - -### Fixed - - heroku deployments - fix problem with node-prune on production build - variable names in examples (https://github.com/ohmyform/ohmyform/issues/134) @@ -82,45 +122,25 @@ Template for next version ## [0.9.9] - 2021-02-14 -### Added - -- Submission export -- Lokalize reference -- more languages - -### Changed - -- updated french translations by @Vercety87 -- upgrade to node 14 (https://github.com/ohmyform/ohmyform/issues/99) - -### Fixed - -- missing dependency to @apollo/client -- footer rendering during authentication check - -### Security - -- authentication check for profile page +- [UI] Submission export +- [UI] Lokalize reference +- [UI] updated french translations by @Vercety87 +- [UI] upgrade to node 14 (https://github.com/ohmyform/ohmyform/issues/99) +- [UI] missing dependency to @apollo/client +- [UI] footer rendering during authentication check +- [UI] authentication check for profile page +- [API] more languages +- [API] upgrade to node 14 (https://github.com/ohmyform/ohmyform/issues/99) ## [0.9.8] - 2020-09-02 -### Changed - - improved german translation (https://github.com/ohmyform/ui/pull/28) - -### Fixed - - colors for landing page buttons - menu selection type - -### Security - - upgraded dependencies ## [0.9.6] - 2020-07-17 -### Added - - slug for fields to be able to set value by url parameter - form submission hokks - default index.html for api without bundled ui @@ -141,27 +161,16 @@ Template for next version ] } ``` - -### Changed - - minify containers to reduce layer size - -### Fixed - - bug in settings resolver with nullable fields - bug if user was deleted and form still exists - do not show login note if it is not set - typo in dropdown options https://github.com/ohmyform/ohmyform/issues/96 - query parms are not parsed https://github.com/ohmyform/ui/pull/27 https://github.com/ohmyform/ohmyform/issues/100 - errors because of missing user reference (https://github.com/ohmyform/ohmyform/issues/102) - -### Security - - container now runs as non root user ## [0.9.5] - 2020-06-10 - -### Added - `DEFAULT_ROLE` -> `admin` | `superuser` | `user` - with `user` being the default, making it possible that new users can create their own forms after creating - `LOGIN_NOTE` -> markdown for Login Page, to show info text on login page @@ -172,13 +181,7 @@ Template for next version - login notes - username in admin toolbar - github stars in multiple places - -### Changed - - verified spanish translations https://github.com/ohmyform/ui/pull/23 - -### Fixed - - di on setting resolver, prevented signup settings to be visible in ui - return admin of form also for admins - yes / no field fixed on admin and user view @@ -191,8 +194,6 @@ Template for next version ## [0.9.4] - 2020-06-09 -### Added - - Fetch Server Settings to determine if signup is available - `SPA` env variable to have static page with loading spinner before redirect - `de`, `fr`, `es`, `it`, `cn` base folders for translations @@ -204,25 +205,14 @@ Template for next version - travis for tests - eslint with prettier - `SIGNUP_DISABLED=true` to prevent users from signing up - -### Changed - - `export` uses now spa mode for initial loading screen - -### Fixed - - [OMF#93](https://github.com/ohmyform/ohmyform/issues/93) dropdown options are not saved - redirect attempts on static export - startup error with invalid create admin config ## [0.9.3] - 2020-06-04 -### Added - - nginx example - load balanced example - minimal example - -### Fixed - - docker-compose mongo data dir to persist data diff --git a/api b/api deleted file mode 160000 index c2c421ba..00000000 --- a/api +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c2c421baa6f41e4e6fb812fa2978956aaf7aa0dd diff --git a/api/.dockerignore b/api/.dockerignore new file mode 100644 index 00000000..204f09af --- /dev/null +++ b/api/.dockerignore @@ -0,0 +1,4 @@ +/dist +/node_modules +/data +/.git diff --git a/api/.eslintrc.js b/api/.eslintrc.js new file mode 100644 index 00000000..9b9f3497 --- /dev/null +++ b/api/.eslintrc.js @@ -0,0 +1,72 @@ +module.exports = { + parser: '@typescript-eslint/parser', + parserOptions: { + project: 'tsconfig.json', + sourceType: 'module', + }, + 'plugins': [ + 'nestjs', + '@typescript-eslint/eslint-plugin', + '@typescript-eslint', + 'unused-imports' + ], + extends: [ + 'eslint:recommended', + 'plugin:nestjs/recommended', + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:@typescript-eslint/recommended-requiring-type-checking', + 'prettier', + ], + root: true, + env: { + node: true, + jest: true, + }, + rules: { + '@typescript-eslint/no-unsafe-return': 'warn', + '@typescript-eslint/no-unsafe-call': 'warn', + '@typescript-eslint/no-unsafe-argument': 'warn', + '@typescript-eslint/no-unsafe-assignment': 'warn', + '@typescript-eslint/no-unsafe-member-access': 'warn', + '@typescript-eslint/interface-name-prefix': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/no-explicit-any': 'off', + 'array-element-newline': ['error', { + 'ArrayExpression': 'consistent', + 'ArrayPattern': { + 'minItems': 3, + 'multiline': true, + } + }], + 'array-bracket-newline': ['error', { + 'minItems': 3, + 'multiline': true, + }], + 'indent': [ + 'error', + 2, + { + 'SwitchCase': 1 + } + ], + 'no-tabs': ['error'], + 'max-len': ['error', { + 'code': 100, + 'ignoreComments': true, + 'ignoreUrls': true, + 'ignoreTemplateLiterals': true, + 'ignoreTrailingComments': true, + 'ignoreStrings': true, + }], + 'quotes': ['error', 'single', { 'avoidEscape': true }], + 'comma-dangle': ['error', 'always-multiline'], + 'linebreak-style': [ + 'error', + 'unix' + ], + 'no-trailing-spaces': 'error', + 'eol-last': 'error', + 'unused-imports/no-unused-imports': 'error', + }, +}; diff --git a/api/.gitignore b/api/.gitignore new file mode 100644 index 00000000..36ca4782 --- /dev/null +++ b/api/.gitignore @@ -0,0 +1,43 @@ +# compiled output +/dist +/node_modules +/public + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# OS +.DS_Store + +# Tests +/coverage +/.nyc_output + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# local data +/data +/.env +/src/schema.gql +/data.sqlite +/maria_data +/pg_data diff --git a/api/.prettierrc b/api/.prettierrc new file mode 100644 index 00000000..dcb72794 --- /dev/null +++ b/api/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "trailingComma": "all" +} \ No newline at end of file diff --git a/api/Dockerfile b/api/Dockerfile new file mode 100644 index 00000000..fb033ec3 --- /dev/null +++ b/api/Dockerfile @@ -0,0 +1,49 @@ +FROM node:14-alpine AS builder +MAINTAINER OhMyForm + +WORKDIR /usr/src/app + +RUN apk update && apk add curl bash && rm -rf /var/cache/apk/* + +# install node-prune (https://github.com/tj/node-prune) +RUN curl -sf https://gobinaries.com/tj/node-prune | sh + +# just copy everhing +COPY . . + +RUN touch /usr/src/app/src/schema.gql && chown 9999:9999 /usr/src/app/src/schema.gql + +RUN yarn install --frozen-lockfile +RUN yarn build + +# remove development dependencies +RUN npm prune --production + +# run node prune +RUN /usr/local/bin/node-prune + +FROM node:14-alpine +MAINTAINER OhMyForm + +# Create a group and a user with name "ohmyform". +RUN addgroup --gid 9999 ohmyform && adduser -D --uid 9999 -G ohmyform ohmyform + +WORKDIR /usr/src/app + +COPY --from=builder /usr/src/app /usr/src/app + +ENV PORT=3000 \ + SECRET_KEY=ChangeMe \ + CREATE_ADMIN=FALSE \ + ADMIN_EMAIL=admin@ohmyform.com \ + ADMIN_USERNAME=root \ + ADMIN_PASSWORD=root \ + NODE_ENV=production + + +EXPOSE 3000 + +# Change to non-root privilege +USER ohmyform + +CMD [ "yarn", "start:prod" ] diff --git a/api/LICENSE.md b/api/LICENSE.md new file mode 100644 index 00000000..0ad25db4 --- /dev/null +++ b/api/LICENSE.md @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/api/README.md b/api/README.md new file mode 100644 index 00000000..ca7f14e2 --- /dev/null +++ b/api/README.md @@ -0,0 +1,40 @@ +# OhMyForm API + +[![Build Status](https://travis-ci.org/ohmyform/api.svg?branch=master)](https://travis-ci.org/ohmyform/api) +![Latest Release](https://badgen.net/github/tag/ohmyform/api) +[![Docker Pulls](https://badgen.net/docker/pulls/ohmyform/api)](https://hub.docker.com/r/ohmyform/api) +[![Lokalise](https://badgen.net/badge/Lokalise/EN/green?icon=libraries)](https://app.lokalise.com/public/379418475ede5d5c6937b0.31012044/) +![Last Commit](https://badgen.net/github/last-commit/ohmyform/api) + +[Demo](https://demo.ohmyform.com/login) + +> An *open source alternative to TypeForm* that can create stunning mobile-ready forms, surveys and questionnaires. + +[![Discord](https://img.shields.io/discord/595773457862492190.svg?label=Discord%20Chat)](https://discord.gg/MJqAuAZ) +[![Financial Contributors on Open Collective](https://opencollective.com/ohmyform-sustainability/all/badge.svg?label=financial+contributors)](https://opencollective.com/ohmyform-sustainability) + +## Description + +[OhMyForm](https://github.com/ohmyform) api backend + +All calls to the api are through GraphQL, with the endpoint +providing an introspectable schema at `GET /graphql` + +## Installation + +```bash +$ npm install +``` + +## Running the app + +```bash +# development +$ yarn run start + +# watch mode +$ yarn run start:dev + +# production mode +$ yarn run start:prod +``` diff --git a/api/doc/cli.md b/api/doc/cli.md new file mode 100644 index 00000000..d43ae940 --- /dev/null +++ b/api/doc/cli.md @@ -0,0 +1,14 @@ +# CLI + +Run `yarn cli` to get basic information of available commands + +## user commands + +### `yarn cli user create` + +create a new user + +### `yarn cli user activate ` + +activate the given user + diff --git a/api/doc/development.md b/api/doc/development.md new file mode 100644 index 00000000..781fd1c5 --- /dev/null +++ b/api/doc/development.md @@ -0,0 +1,8 @@ +# Development + +tip's and tricks to get you started + +## First Run + +install yarn on your system if not already present and then install all dependencies +by running `yarn install` diff --git a/api/doc/environment.md b/api/doc/environment.md new file mode 100644 index 00000000..43ac1228 --- /dev/null +++ b/api/doc/environment.md @@ -0,0 +1,46 @@ +# Environment Variables + +| Name | Default Value | Description | +|------------------------------|----------------------------|---------------------------------------------------------------------------------------| +| DISABLE_INSTALLATION_METRICS | *not set* | Per default installations are [publishing](./installation.metrics.md) their existence | +| SECRET_KEY | `changeMe` | JWT Secret for authentication | +| CLI | *automatically* | activates pretty print for log output | +| NODE_ENV | `production` | | +| HIDE_CONTRIB | `false` | decide if backlings to ohmyform should be added | +| SIGNUP_DISABLED | `false` | if users can sign up | +| LOGIN_NOTE | *not set* | Info box on top of login screen | +| LOCALES_PATH | *not set* | Path to translated elementes in backend like emails | +| LOCALE | `en` | Default Locale | +| BASE_URL | `http://localhost` | Url to Frontend root | +| USER_CONFIRM_PATH | `/confirm?token={{token}}` | Path to confirm user | + +## Default Account + +*username and email are unique on an instance* + +| Name | Default Value | Description | +|----------------|----------------------|-------------------------------------| +| CREATE_ADMIN | `false` | if `true` will create a super admin | +| ADMIN_USERNAME | `root` | username for the default admin user | +| ADMIN_EMAIL | `admin@ohmyform.com` | email to send notifications | +| ADMIN_PASSWORD | `root` | password for user | + +## Mailing + +| Name | Default Value | Description | +|-------------|---------------------------------|-----------------------------------------------------------------------------------| +| MAILER_URI | `smtp://localhost:1025` | [Mail Connection](https://nodemailer.com/smtp/) | +| MAILER_FROM | `OhMyForm ` | Default From path, make sure that your mail server supports the given from addres | + +## Database Variables + +| Name | Default Value | Description | +|-----------------------|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------| +| DATABASE_DRIVER | `sqlite` | database driver, either `sqlite` or `postgres` | +| DATABASE_URL | `sqlite://data.sqlite` | url in the format `TYPE://USER:PASS@HOST:PORT/NAME?EXTRA` ([read more](https://typeorm.io/#/connection-options/common-connection-options)) | +| DATABASE_TABLE_PREFIX | *empty* | prefix all tables if used within same database as other applications. | +| DATABASE_LOGGING | `false` | if `true` all db interactions will be logged to stdout | +| DATABASE_MIGRATE | `true` | can be used in load balanced environments to only allow one container to perform migrations / manually execute migrations | +| DATABASE_SSL | `false` | if `true` will require ssl database connection | +| REDIS_HOST | *not set* | required in multinode environments | +| REDIS_PORT | `6379` | port for redis | diff --git a/api/doc/installation.metrics.md b/api/doc/installation.metrics.md new file mode 100644 index 00000000..f4db6ee1 --- /dev/null +++ b/api/doc/installation.metrics.md @@ -0,0 +1,11 @@ +# Installation Metrics + +Attention: OhMyForm now collects completely anonymous +telemetry regarding usage. This information is used to +shape OhMyForm's roadmap and prioritize features. + +If you want to opt out you can disable this behavior by +setting the environment variable `DISABLE_INSTALLATION_METRICS=1` + +You can take a look [here](../src/service/installation.metrics.service.ts) to see how we trigger the metric +collection diff --git a/api/doc/roles.md b/api/doc/roles.md new file mode 100644 index 00000000..6011e81d --- /dev/null +++ b/api/doc/roles.md @@ -0,0 +1,24 @@ +# Roles + +## unauthenticated + +every request is unauthenticated unless an `Authorization` +header with a valid `JWT Bearer` token is provided. + +## user + +any new registration is a user per default, they can only see their +responses and do not have access to forms. + +## admin + +an admin can create forms and edit their own forms. They do not +have access to forms from other users. + +## superuser + +a superuser can create and edit any form on the platform as well as +modify any user + +they can also grant a user admin or superuser access, they cannot revoke +their own superuser role diff --git a/api/docker-compose.yml b/api/docker-compose.yml new file mode 100644 index 00000000..9db91fdc --- /dev/null +++ b/api/docker-compose.yml @@ -0,0 +1,65 @@ +version: "3" +services: + #mongo: + # image: mongo + # ports: + # - "27017:27017" + # volumes: + # - "./data/mongo:/data/db" + + maria: + image: mariadb + volumes: + - ./maria_data:/var/lib/mysql + environment: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: ohmyform + ports: + - "3306:3306" + + postgres: + image: postgres:10-alpine + volumes: + - ./pg_data:/var/lib/postgresql/data + environment: + POSTGRES_USER: root + POSTGRES_PASSWORD: root + POSTGRES_DB: ohmyform + ports: + - "5432:5432" + + redis: + image: redis + ports: + - "6003:6379" +# api: +# build: . +# volumes: +# - ".:/usr/src/app" +# environment: +# MONGODB_URI: mongodb://mongo/ohmyform +# MAILER_URI: smtp://mail:1025 +# PORT: 3000 + #command: yarn start:dev +# links: +# - mongo +# - mail +# ports: +# - "6100:3000" +# depends_on: +# - mongo + mail: + image: mailhog/mailhog + ports: + - "6001:8025" + - "6004:1025" + #mongoexpress: + # image: mongo-express + # environment: + # ME_CONFIG_MONGODB_SERVER: mongo + # ports: + # - "6002:8081" + # links: + # - mongo + # depends_on: + # - mongo diff --git a/api/locales/en/mail/user/created.mjml b/api/locales/en/mail/user/created.mjml new file mode 100644 index 00000000..ae057abf --- /dev/null +++ b/api/locales/en/mail/user/created.mjml @@ -0,0 +1,22 @@ + + + Welcome to OhMyForm + + + + + OhMyForm! + + + + + Your Username is {{username}} + + + + Click here to verify your Account + + + + + diff --git a/api/nest-cli.json b/api/nest-cli.json new file mode 100644 index 00000000..4a86fea4 --- /dev/null +++ b/api/nest-cli.json @@ -0,0 +1,7 @@ +{ + "collection": "@nestjs/schematics", + "sourceRoot": "src", + "compilerOptions": { + "plugins": ["@nestjs/graphql/plugin"] + } +} diff --git a/api/ormconfig_mariadb.json b/api/ormconfig_mariadb.json new file mode 100644 index 00000000..b504f535 --- /dev/null +++ b/api/ormconfig_mariadb.json @@ -0,0 +1,22 @@ +{ + "type": "mariadb", + "host": "localhost", + "username": "root", + "password": "root", + "database": "ohmyform", + "synchronize": false, + "logging": false, + "entities": [ + "src/entity/**/*.ts" + ], + "migrations": [ + "src/migrations/mariadb/**/*.ts" + ], + "migrationsTransactionMode": "each", + "subscribers": [ + "src/subscriber/**/*.ts" + ], + "cli": { + "migrationsDir": "src/migrations/mariadb" + } +} diff --git a/api/ormconfig_postgres.json b/api/ormconfig_postgres.json new file mode 100644 index 00000000..373c2549 --- /dev/null +++ b/api/ormconfig_postgres.json @@ -0,0 +1,22 @@ +{ + "type": "postgres", + "host": "localhost", + "username": "root", + "password": "root", + "database": "ohmyform", + "synchronize": false, + "logging": false, + "entities": [ + "src/entity/**/*.ts" + ], + "migrations": [ + "src/migrations/postgres/**/*.ts" + ], + "migrationsTransactionMode": "each", + "subscribers": [ + "src/subscriber/**/*.ts" + ], + "cli": { + "migrationsDir": "src/migrations/postgres" + } +} diff --git a/api/ormconfig_sqlite.json b/api/ormconfig_sqlite.json new file mode 100644 index 00000000..98dbe963 --- /dev/null +++ b/api/ormconfig_sqlite.json @@ -0,0 +1,16 @@ +{ + "type": "sqlite", + "database": "data.sqlite", + "synchronize": false, + "logging": false, + "entities": [ + "src/entity/**/*.ts" + ], + "migrations": [ + "src/migrations/sqlite/**/*.ts" + ], + "migrationsTransactionMode": "none", + "cli": { + "migrationsDir": "src/migrations/sqlite" + } +} diff --git a/api/package.json b/api/package.json new file mode 100644 index 00000000..0f326377 --- /dev/null +++ b/api/package.json @@ -0,0 +1,126 @@ +{ + "name": "ohmyform-api", + "version": "1.0.3", + "description": "", + "author": "", + "license": "AGPL-3.0-or-later", + "scripts": { + "prebuild": "rimraf dist", + "build": "nest build", + "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", + "cli:dev": "cross-env CLI=true TS_NODE_TRANSPILE_ONLY=true ts-node -r tsconfig-paths/register src/cli.ts", + "cli": "cross-env CLI=true node dist/console.js", + "start": "nest start", + "start:dev": "nest start --watch", + "start:debug": "nest start --debug --watch", + "start:prod": "cross-env NODE_ENV=production node dist/main", + "lint": "eslint \"{src,test}/**/*.ts\" --fix", + "test": "jest", + "test:watch": "jest --watch", + "test:cov": "jest --coverage", + "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", + "test:e2e": "jest --config ./test/jest-e2e.json", + "typeorm:sqlite": "cross-env TS_NODE_TRANSPILE_ONLY=true ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js -f ormconfig_sqlite.json", + "typeorm:postgres": "cross-env TS_NODE_TRANSPILE_ONLY=true ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js -f ormconfig_postgres.json", + "typeorm:mariadb": "cross-env TS_NODE_TRANSPILE_ONLY=true ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js -f ormconfig_mariadb.json", + "typeorm": "cross-env TS_NODE_TRANSPILE_ONLY=true ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js" + }, + "dependencies": { + "@ardatan/aggregate-error": "^0.0.6", + "@nestjs-modules/mailer": "^1.6.1", + "@nestjs/apollo": "^10.0.5", + "@nestjs/axios": "^0.0.6", + "@nestjs/common": "^8.3.1", + "@nestjs/config": "^1.2.0", + "@nestjs/core": "^8.3.1", + "@nestjs/graphql": "^10.0.5", + "@nestjs/jwt": "^8.0.0", + "@nestjs/passport": "^8.2.1", + "@nestjs/platform-express": "^8.3.1", + "@nestjs/serve-static": "^2.2.2", + "@nestjs/typeorm": "^8.0.3", + "apollo-server-express": "^3.6.3", + "bcrypt": "^5.0.1", + "class-transformer": "^0.5.1", + "class-validator": "^0.13.2", + "cors": "^2.8.5", + "cross-env": "^7.0.3", + "dayjs": "^1.10.7", + "graphql": "15.8.0", + "graphql-redis-subscriptions": "^2.4.2", + "graphql-subscriptions": "^2.0.0", + "graphql-tools": "^8.2.0", + "handlebars": "^4.7.7", + "hashids": "^2.2.10", + "html-to-text": "^8.1.0", + "inquirer": "^8.2.0", + "ioredis": "^4.28.5", + "ip-anonymize": "^0.1.0", + "matomo-tracker": "^2.2.4", + "mjml": "^4.12.0", + "mysql2": "^2.3.3", + "nestjs-console": "^7.0.1", + "nestjs-pino": "^2.5.0", + "nodemailer": "^6.7.2", + "passport": "^0.5.2", + "passport-jwt": "^4.0.0", + "passport-local": "^1.0.0", + "pg": "^8.7.3", + "pino-http": "^6.6.0", + "pino-pretty": "^7.5.1", + "reflect-metadata": "^0.1.13", + "request-ip": "^2.1.3", + "rimraf": "^3.0.2", + "rxjs": "^7.5.4", + "serialize-error": "^8.1.0", + "sqlite3": "^5.0.2", + "typeorm": "^0.2.44" + }, + "devDependencies": { + "@nestjs/cli": "^8.2.1", + "@nestjs/schematics": "^8.0.7", + "@nestjs/testing": "^8.3.1", + "@types/bcrypt": "^5.0.0", + "@types/express-serve-static-core": "^4.17.28", + "@types/handlebars": "^4.1.0", + "@types/html-to-text": "^8.0.1", + "@types/inquirer": "^8.2.0", + "@types/jest": "^27.4.1", + "@types/mjml": "^4.7.0", + "@types/node": "^17.0.21", + "@types/passport-jwt": "^3.0.6", + "@types/passport-local": "^1.0.34", + "@types/request-ip": "^0.0.37", + "@types/supertest": "^2.0.11", + "@typescript-eslint/eslint-plugin": "^5.12.1", + "@typescript-eslint/parser": "^5.12.1", + "eslint": "^8.10.0", + "eslint-config-prettier": "^8.4.0", + "eslint-plugin-import": "^2.25.4", + "eslint-plugin-nestjs": "^1.2.3", + "eslint-plugin-unused-imports": "^2.0.0", + "jest": "^27.5.1", + "node-gyp": "^9.0.0", + "prettier": "^2.5.1", + "supertest": "^6.2.2", + "ts-jest": "27.1.3", + "ts-loader": "^9.2.6", + "ts-node": "^10.5.0", + "tsconfig-paths": "^3.12.0", + "typescript": "^4.5.5" + }, + "jest": { + "moduleFileExtensions": [ + "js", + "json", + "ts" + ], + "rootDir": "src", + "testRegex": ".spec.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + }, + "coverageDirectory": "../coverage", + "testEnvironment": "node" + } +} diff --git a/api/public/.gitkeep b/api/public/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/api/public/index.html b/api/public/index.html new file mode 100644 index 00000000..db350e6b --- /dev/null +++ b/api/public/index.html @@ -0,0 +1,5 @@ +
+

OhMyForm API endpoint

+ +visit us at ohmyform.com +
diff --git a/api/src/app.imports.ts b/api/src/app.imports.ts new file mode 100644 index 00000000..71fca447 --- /dev/null +++ b/api/src/app.imports.ts @@ -0,0 +1,168 @@ +import { MailerModule } from '@nestjs-modules/mailer' +import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo' +import { HttpModule } from '@nestjs/axios' +import { RequestMethod } from '@nestjs/common' +import { ConfigModule, ConfigService } from '@nestjs/config' +import { GraphQLModule } from '@nestjs/graphql' +import { JwtModule, JwtModuleOptions } from '@nestjs/jwt' +import { ServeStaticModule } from '@nestjs/serve-static' +import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm' +import crypto from 'crypto' +import { Request } from 'express-serve-static-core' +import { IncomingHttpHeaders } from 'http' +import { ConsoleModule } from 'nestjs-console' +import { LoggerModule, Params as LoggerModuleParams } from 'nestjs-pino' +import { join } from 'path' +import { serializeError } from 'serialize-error' +import { entities } from './entity' + +export const LoggerConfig: LoggerModuleParams = { + pinoHttp: { + level: process.env.CLI ? 'warn' : process.env.NODE_ENV !== 'production' ? 'debug' : 'info', + serializers: { + error: serializeError, + }, + transport: process.env.NODE_ENV !== 'production' || process.env.CLI ? { + options: { + ignore: 'req,res,pid,hostname', + translateTime: true, + }, + target: 'pino-pretty', + } : undefined, + }, + exclude: [ + { + method: RequestMethod.ALL, + path: '_health', + }, + { + method: RequestMethod.ALL, + path: 'favicon.ico', + }, + ], +} + +export const imports = [ + ConsoleModule, + HttpModule.register({ + timeout: 5000, + maxRedirects: 10, + }), + ServeStaticModule.forRoot({ + rootPath: join(__dirname, '..', 'public'), + exclude: ['/graphql'], + }), + ConfigModule.forRoot({ + load: [ + () => { + return { + LOCALES_PATH: join(process.cwd(), 'locales'), + SECRET_KEY: process.env.SECRET_KEY || crypto.randomBytes(20).toString('hex'), + } + }, + ], + }), + JwtModule.registerAsync({ + imports: [ConfigModule], + inject: [ConfigService], + useFactory: (configService: ConfigService): JwtModuleOptions => ({ + secret: configService.get('SECRET_KEY'), + signOptions: { + expiresIn: '4h', + }, + }), + }), + LoggerModule.forRoot(LoggerConfig), + GraphQLModule.forRoot({ + debug: process.env.NODE_ENV !== 'production', + definitions: { + outputAs: 'class', + }, + driver: ApolloDriver, + sortSchema: true, + introspection: process.env.NODE_ENV !== 'production', + playground: process.env.NODE_ENV !== 'production', + installSubscriptionHandlers: true, + autoSchemaFile: join(process.cwd(), 'src/schema.gql'), + // to allow guards on resolver props https://github.com/nestjs/graphql/issues/295 + fieldResolverEnhancers: [ + 'guards', + 'interceptors', + ], + resolverValidationOptions: { + + }, + context: ({ req, connection }) => { + if (!req && connection) { + const headers: IncomingHttpHeaders = {} + + Object.keys(connection.context).forEach(key => { + headers[key.toLowerCase()] = connection.context[key] + }) + + return { + req: { + headers, + } as Request, + } + } + + return { req } + }, + }), + TypeOrmModule.forRootAsync({ + imports: [ConfigModule], + inject: [ConfigService], + useFactory: (configService: ConfigService): TypeOrmModuleOptions => { + const type: any = configService.get('DATABASE_DRIVER', 'sqlite') + let migrationFolder: string + let migrationsTransactionMode: 'each' | 'none' | 'all' = 'each' + + switch (type) { + case 'cockroachdb': + case 'postgres': + migrationFolder = 'postgres' + break + + case 'mysql': + case 'mariadb': + migrationFolder = 'mariadb' + break + + case 'sqlite': + migrationFolder = 'sqlite' + migrationsTransactionMode = 'none' + break + + default: + throw new Error('unsupported driver') + } + + return ({ + name: 'ohmyform', + synchronize: false, + type, + url: configService.get('DATABASE_URL'), + database: type === 'sqlite' ? configService.get('DATABASE_URL', 'data.sqlite').replace('sqlite://', '') : undefined, + ssl: configService.get('DATABASE_SSL', 'false') === 'true' ? { rejectUnauthorized: false } : false, + entityPrefix: configService.get('DATABASE_TABLE_PREFIX', ''), + logging: configService.get('DATABASE_LOGGING', 'false') === 'true', + entities, + migrations: [`${__dirname}/**/migrations/${migrationFolder}/**/*{.ts,.js}`], + migrationsRun: configService.get('DATABASE_MIGRATE', true), + migrationsTransactionMode, + }) + }, + }), + TypeOrmModule.forFeature(entities), + MailerModule.forRootAsync({ + imports: [ConfigModule], + inject: [ConfigService], + useFactory: (configService: ConfigService) => ({ + transport: configService.get('MAILER_URI', 'smtp://localhost:1025'), + defaults: { + from: configService.get('MAILER_FROM', 'OhMyForm '), + }, + }), + }), +] diff --git a/api/src/app.module.ts b/api/src/app.module.ts new file mode 100644 index 00000000..9943590c --- /dev/null +++ b/api/src/app.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common' +import { imports } from './app.imports' +import { providers } from './app.providers' +import { controllers } from './controller' + +@Module({ + imports, + controllers, + providers, +}) +export class AppModule {} diff --git a/api/src/app.providers.ts b/api/src/app.providers.ts new file mode 100644 index 00000000..1e8efde4 --- /dev/null +++ b/api/src/app.providers.ts @@ -0,0 +1,13 @@ +import { commands } from './command' +import { guards } from './guard' +import { pipes } from './pipe' +import { resolvers } from './resolver' +import { services } from './service' + +export const providers = [ + ...commands, + ...guards, + ...pipes, + ...resolvers, + ...services, +] diff --git a/api/src/cli.ts b/api/src/cli.ts new file mode 100644 index 00000000..9a9e2617 --- /dev/null +++ b/api/src/cli.ts @@ -0,0 +1,16 @@ +import { BootstrapConsole } from 'nestjs-console' +import { AppModule } from './app.module' + +const bootstrap = new BootstrapConsole({ + module: AppModule, + useDecorators: true, +}); +void bootstrap.init().then(async (app) => { + try { + await app.init(); + await bootstrap.boot(); + process.exit(0); + } catch (e) { + process.exit(1); + } +}); diff --git a/api/src/command/index.ts b/api/src/command/index.ts new file mode 100644 index 00000000..0adaa754 --- /dev/null +++ b/api/src/command/index.ts @@ -0,0 +1,3 @@ +import { UserCommand } from './user.command' + +export const commands = [UserCommand] diff --git a/api/src/command/user.command.ts b/api/src/command/user.command.ts new file mode 100644 index 00000000..ad2c3734 --- /dev/null +++ b/api/src/command/user.command.ts @@ -0,0 +1,65 @@ +import inquirer from 'inquirer' +import { Command, Console } from 'nestjs-console' +import { matchType, validatePassword } from '../config/fields' +import { UserCreateInput } from '../dto/user/user.create.input' +import { UserCreateService } from '../service/user/user.create.service' + +@Console({ + command: 'user', + description: 'handle instance users', +}) +export class UserCommand { + constructor( + private readonly createUser: UserCreateService + ) { + } + + @Command({ + command: 'create', + }) + async create(): Promise { + const answers = await inquirer.prompt([ + { + type: 'input', + name: 'username', + message: 'username for login', + }, + { + type: 'input', + name: 'email', + message: 'email to send notifications to', + validate(input: string): boolean | string { + if (!matchType.email.test(input)) { + return 'invalid email' + } + + return true + }, + }, + { + type: 'password', + name: 'password', + validate: validatePassword, + message: 'password to login', + }, + { + type: 'confirm', + name: 'create', + message: current => { + return `create user ${current.username} with email ${current.email}` + }, + }, + ]) + + await this.createUser.create(answers) + + console.info(`user ${answers.username} has been created`) + } + + @Command({ + command: 'activate ', + }) + activate(username: string): void { + console.log(`activate user ${username}`) + } +} diff --git a/api/src/config/fields.ts b/api/src/config/fields.ts new file mode 100644 index 00000000..2d18f508 --- /dev/null +++ b/api/src/config/fields.ts @@ -0,0 +1,32 @@ + +export const fieldTypes = [ + 'textfield', + 'date', + 'email', + // 'legal', + 'textarea', + 'link', + // 'statement', + 'dropdown', + 'rating', + 'radio', + 'hidden', + 'yes_no', + 'number', +] + +export const matchType = { + color: /^#([A-F0-9]{6}|[A-F0-9]{3})$/i, + // eslint-disable-next-line max-len + url: /((([A-Z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)/i, + email: /.+@.+\..+/, + slug: /^[a-z0-9_]+$/, +} + +export const validatePassword = (password: string): true | string => { + if (password.length < 4) { + return 'password is too short' + } + + return true +} diff --git a/api/src/config/languages.ts b/api/src/config/languages.ts new file mode 100644 index 00000000..fcda6fc7 --- /dev/null +++ b/api/src/config/languages.ts @@ -0,0 +1,23 @@ + +export const languages = [ + 'en', + 'ar', + 'cn', + 'da', + 'nl', + 'fr', + 'de', + 'hi', + 'it', + 'ja', + 'pl', + 'pt_BR', + 'pt_PT', + 'ru', + 'es', + 'sv', + 'ta', + 'uk', +] + +export const defaultLanguage = 'en' diff --git a/api/src/config/roles.ts b/api/src/config/roles.ts new file mode 100644 index 00000000..c6e2afcf --- /dev/null +++ b/api/src/config/roles.ts @@ -0,0 +1,7 @@ + +export type roleType = 'user' | 'admin' | 'superuser' +export type rolesType = roleType[] + +export const roles: rolesType = [ + 'user', 'admin', 'superuser', +] diff --git a/api/src/controller/health.controller.ts b/api/src/controller/health.controller.ts new file mode 100644 index 00000000..8fd6fee9 --- /dev/null +++ b/api/src/controller/health.controller.ts @@ -0,0 +1,9 @@ +import { Controller, Get } from '@nestjs/common' + +@Controller() +export class HealthController { + @Get('/_health') + getHello(): string { + return 'ok'; + } +} diff --git a/api/src/controller/index.ts b/api/src/controller/index.ts new file mode 100644 index 00000000..4fa4fdca --- /dev/null +++ b/api/src/controller/index.ts @@ -0,0 +1,3 @@ +import { HealthController } from './health.controller' + +export const controllers = [HealthController] diff --git a/api/src/decorator/ip.address.decorator.ts b/api/src/decorator/ip.address.decorator.ts new file mode 100644 index 00000000..91d0ac5a --- /dev/null +++ b/api/src/decorator/ip.address.decorator.ts @@ -0,0 +1,19 @@ +import { createParamDecorator, ExecutionContext } from '@nestjs/common' +import { GqlExecutionContext } from '@nestjs/graphql' +import { getClientIp } from 'request-ip' + +export const IpAddress = createParamDecorator((data: string, ctx: ExecutionContext) => { + let req + + if (ctx.getType() === 'graphql') { + req = GqlExecutionContext.create(ctx).getContext().req + } else { + req = ctx.switchToHttp().getRequest() + } + + if (req.clientIp) { + return req.clientIp + } + + return getClientIp(req) +}) diff --git a/api/src/decorator/roles.decorator.ts b/api/src/decorator/roles.decorator.ts new file mode 100644 index 00000000..5d38709b --- /dev/null +++ b/api/src/decorator/roles.decorator.ts @@ -0,0 +1,4 @@ +import { SetMetadata } from '@nestjs/common' +import { rolesType } from '../config/roles' + +export const Roles = (...roles: rolesType) => SetMetadata('roles', roles); diff --git a/api/src/decorator/user.decorator.ts b/api/src/decorator/user.decorator.ts new file mode 100644 index 00000000..c94a6fe6 --- /dev/null +++ b/api/src/decorator/user.decorator.ts @@ -0,0 +1,14 @@ +import { createParamDecorator, ExecutionContext } from '@nestjs/common' +import { GqlExecutionContext } from '@nestjs/graphql' + +export const User = createParamDecorator( + (data: unknown, ctx: ExecutionContext) => { + const user = GqlExecutionContext.create(ctx).getContext().req.user + + if (!user) { + return null + } + + return user + }, +); diff --git a/api/src/dto/auth/auth.jwt.model.ts b/api/src/dto/auth/auth.jwt.model.ts new file mode 100644 index 00000000..825f5634 --- /dev/null +++ b/api/src/dto/auth/auth.jwt.model.ts @@ -0,0 +1,15 @@ +import { Field, ObjectType } from '@nestjs/graphql' + +@ObjectType('AuthToken') +export class AuthJwtModel { + @Field() + readonly accessToken: string + + @Field() + readonly refreshToken: string + + constructor(partial: Partial) { + this.accessToken = partial.accessToken + this.refreshToken = partial.refreshToken + } +} diff --git a/api/src/dto/deleted.model.ts b/api/src/dto/deleted.model.ts new file mode 100644 index 00000000..4e1a4086 --- /dev/null +++ b/api/src/dto/deleted.model.ts @@ -0,0 +1,11 @@ +import { Field, ID, ObjectType } from '@nestjs/graphql' + +@ObjectType('Deleted') +export class DeletedModel { + @Field(() => ID) + id: string + + constructor(id: string) { + this.id = id + } +} diff --git a/api/src/dto/form/button.input.ts b/api/src/dto/form/button.input.ts new file mode 100644 index 00000000..230afe41 --- /dev/null +++ b/api/src/dto/form/button.input.ts @@ -0,0 +1,25 @@ +import { Field, ID, InputType } from '@nestjs/graphql' + +@InputType() +export class ButtonInput { + @Field(() => ID, { nullable: true }) + readonly id?: string + + @Field({ nullable: true }) + readonly url?: string + + @Field({ nullable: true }) + readonly action?: string + + @Field({ nullable: true }) + readonly text?: string + + @Field({ nullable: true }) + readonly bgColor?: string + + @Field({ nullable: true }) + readonly activeColor?: string + + @Field({ nullable: true }) + readonly color?: string +} diff --git a/api/src/dto/form/button.model.ts b/api/src/dto/form/button.model.ts new file mode 100644 index 00000000..d4a31044 --- /dev/null +++ b/api/src/dto/form/button.model.ts @@ -0,0 +1,39 @@ +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { PageButtonEntity } from '../../entity/page.button.entity' + +@ObjectType('Button') +export class ButtonModel { + readonly _id: number + + @Field(() => ID) + readonly id: string + + @Field({ nullable: true }) + readonly url?: string + + @Field({ nullable: true }) + readonly action?: string + + @Field({ nullable: true }) + readonly text?: string + + @Field({ nullable: true }) + readonly bgColor?: string + + @Field({ nullable: true }) + readonly activeColor?: string + + @Field({ nullable: true }) + readonly color?: string + + constructor(id: string, button: Partial) { + this._id = button.id + this.id = id + this.url = button.url + this.action = button.action + this.text = button.text + this.bgColor = button.bgColor + this.activeColor = button.activeColor + this.color = button.color + } +} diff --git a/api/src/dto/form/colors.input.ts b/api/src/dto/form/colors.input.ts new file mode 100644 index 00000000..9a7f1b98 --- /dev/null +++ b/api/src/dto/form/colors.input.ts @@ -0,0 +1,22 @@ +import { Field, InputType } from '@nestjs/graphql' + +@InputType() +export class ColorsInput { + @Field() + readonly background: string + + @Field() + readonly question: string + + @Field() + readonly answer: string + + @Field() + readonly button: string + + @Field() + readonly buttonActive: string + + @Field() + readonly buttonText: string +} diff --git a/api/src/dto/form/colors.model.ts b/api/src/dto/form/colors.model.ts new file mode 100644 index 00000000..b73afc88 --- /dev/null +++ b/api/src/dto/form/colors.model.ts @@ -0,0 +1,32 @@ +import { Field, ObjectType } from '@nestjs/graphql' +import { ColorsEmbedded } from '../../entity/embedded/colors.embedded' + +@ObjectType('Colors') +export class ColorsModel { + @Field() + readonly background: string + + @Field() + readonly question: string + + @Field() + readonly answer: string + + @Field() + readonly button: string + + @Field() + readonly buttonActive: string + + @Field() + readonly buttonText: string + + constructor(partial: Partial) { + this.background = partial.background ?? '#fff' + this.question = partial.question ?? '#333' + this.answer = partial.answer ?? '#333' + this.button = partial.button ?? '#fff' + this.buttonActive = partial.buttonActive ?? '#40a9ff' + this.buttonText = partial.buttonText ?? '#666' + } +} diff --git a/api/src/dto/form/design.input.ts b/api/src/dto/form/design.input.ts new file mode 100644 index 00000000..0bf89734 --- /dev/null +++ b/api/src/dto/form/design.input.ts @@ -0,0 +1,14 @@ +import { Field, InputType } from '@nestjs/graphql' +import { ColorsInput } from './colors.input' + +@InputType() +export class DesignInput { + @Field() + readonly colors: ColorsInput + + @Field({ nullable: true }) + readonly font?: string + + @Field({ nullable: true }) + readonly layout?: string +} diff --git a/api/src/dto/form/design.model.ts b/api/src/dto/form/design.model.ts new file mode 100644 index 00000000..39b25bda --- /dev/null +++ b/api/src/dto/form/design.model.ts @@ -0,0 +1,21 @@ +import { Field, ObjectType } from '@nestjs/graphql' +import { DesignEmbedded } from '../../entity/embedded/design.embedded' +import { ColorsModel } from './colors.model' + +@ObjectType('Design') +export class DesignModel { + @Field() + readonly colors: ColorsModel + + @Field({ nullable: true }) + readonly font?: string + + @Field({ nullable: true }) + readonly layout?: string + + constructor(partial: Partial) { + this.colors = new ColorsModel(partial.colors) + this.font = partial.font + this.layout = partial.layout + } +} diff --git a/api/src/dto/form/form.create.input.ts b/api/src/dto/form/form.create.input.ts new file mode 100644 index 00000000..3e6b4a65 --- /dev/null +++ b/api/src/dto/form/form.create.input.ts @@ -0,0 +1,29 @@ +import { Field, InputType } from '@nestjs/graphql' +import { PageInput } from './page.input' + +@InputType('FormCreateInput') +export class FormCreateInput { + @Field() + readonly title: string + + @Field() + readonly language: string + + @Field({ nullable: true }) + readonly showFooter: boolean + + @Field({ nullable: true }) + readonly anonymousSubmission: boolean + + @Field({ nullable: true }) + readonly isLive: boolean + + @Field({ nullable: true }) + readonly layout: string + + @Field({ nullable: true }) + readonly startPage: PageInput + + @Field({ nullable: true }) + readonly endPage: PageInput +} diff --git a/api/src/dto/form/form.field.input.ts b/api/src/dto/form/form.field.input.ts new file mode 100644 index 00000000..9dc75685 --- /dev/null +++ b/api/src/dto/form/form.field.input.ts @@ -0,0 +1,43 @@ +import { Field, ID, InputType } from '@nestjs/graphql' +import { FormFieldLogicInput } from './form.field.logic.input' +import { FormFieldOptionInput } from './form.field.option.input' +import { FormFieldRatingInput } from './form.field.rating.input' + +@InputType() +export class FormFieldInput { + @Field(() => ID) + readonly id: string + + @Field() + readonly title: string + + @Field() + readonly type: string + + @Field({ nullable: true }) + readonly slug?: string + + @Field({ nullable: true }) + readonly idx?: number + + @Field() + readonly description: string + + @Field() + readonly required: boolean + + @Field({ nullable: true }) + readonly defaultValue: string + + @Field({ nullable: true }) + readonly disabled?: boolean + + @Field(() => [FormFieldOptionInput], { nullable: true }) + readonly options: FormFieldOptionInput[] + + @Field(() => [FormFieldLogicInput], { nullable: true }) + readonly logic: FormFieldLogicInput[] + + @Field(() => FormFieldRatingInput, { nullable: true }) + readonly rating: FormFieldRatingInput +} diff --git a/api/src/dto/form/form.field.logic.input.ts b/api/src/dto/form/form.field.logic.input.ts new file mode 100644 index 00000000..cedf1601 --- /dev/null +++ b/api/src/dto/form/form.field.logic.input.ts @@ -0,0 +1,33 @@ +import { Field, ID, InputType } from '@nestjs/graphql' +import { FormFieldLogicAction } from '../../entity/form.field.logic.entity' + +@InputType() +export class FormFieldLogicInput { + @Field(() => ID, { nullable: true }) + readonly id?: string + + @Field({ nullable: true }) + readonly formula: string + + // TODO verify action value + @Field(() => String, { nullable: true }) + readonly action: FormFieldLogicAction + + @Field({ nullable: true }) + readonly idx?: number + + @Field(() => ID, { nullable: true }) + readonly jumpTo?: string + + @Field({ nullable: true }) + readonly visible?: boolean + + @Field({ nullable: true }) + readonly disable?: boolean + + @Field({ nullable: true }) + readonly require?: boolean + + @Field({ nullable: true }) + readonly enabled: boolean +} diff --git a/api/src/dto/form/form.field.logic.model.ts b/api/src/dto/form/form.field.logic.model.ts new file mode 100644 index 00000000..46a5b156 --- /dev/null +++ b/api/src/dto/form/form.field.logic.model.ts @@ -0,0 +1,49 @@ +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { FormFieldLogicEntity } from '../../entity/form.field.logic.entity' + +@ObjectType('FormFieldLogic') +export class FormFieldLogicModel { + readonly _id: number + + @Field(() => ID) + readonly id: string + + @Field({ nullable: true }) + readonly formula: string + + @Field() + readonly action: string + + @Field({ nullable: true }) + readonly idx?: number + + @Field(() => ID, { nullable: true }) + readonly jumpTo?: string + + @Field({ nullable: true }) + readonly visible?: boolean + + @Field({ nullable: true }) + readonly disable?: boolean + + @Field({ nullable: true }) + readonly require?: boolean + + @Field() + readonly enabled: boolean + + constructor(id: string, document: FormFieldLogicEntity) { + this._id = document.id + this.id = id + this.enabled = document.enabled + + this.formula = document.formula + this.jumpTo = document.jumpTo?.id.toString() + + this.idx = document.idx + this.action = document.action + this.visible = document.visible + this.disable = document.disable + this.require = document.require + } +} diff --git a/api/src/dto/form/form.field.model.ts b/api/src/dto/form/form.field.model.ts new file mode 100644 index 00000000..85060e36 --- /dev/null +++ b/api/src/dto/form/form.field.model.ts @@ -0,0 +1,43 @@ +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { FormFieldEntity } from '../../entity/form.field.entity' + +@ObjectType('FormField') +export class FormFieldModel { + readonly _id: number + + @Field(() => ID) + readonly id: string + + @Field() + readonly title: string + + @Field({ nullable: true }) + readonly slug?: string + + @Field({ nullable: true }) + readonly idx: number + + @Field() + readonly type: string + + @Field() + readonly description: string + + @Field() + readonly required: boolean + + @Field({ nullable: true }) + readonly defaultValue: string + + constructor(id: string, document: FormFieldEntity) { + this._id = document.id + this.id = id + this.idx = document.idx + this.title = document.title + this.slug = document.slug + this.type = document.type + this.description = document.description + this.required = document.required + this.defaultValue = document.defaultValue + } +} diff --git a/api/src/dto/form/form.field.option.input.ts b/api/src/dto/form/form.field.option.input.ts new file mode 100644 index 00000000..d730ad40 --- /dev/null +++ b/api/src/dto/form/form.field.option.input.ts @@ -0,0 +1,16 @@ +import { Field, ID, InputType } from '@nestjs/graphql' + +@InputType() +export class FormFieldOptionInput { + @Field(() => ID, { nullable: true }) + readonly id?: string + + @Field({ nullable: true }) + readonly key: string + + @Field({ nullable: true }) + readonly title: string + + @Field() + readonly value: string +} diff --git a/api/src/dto/form/form.field.option.model.ts b/api/src/dto/form/form.field.option.model.ts new file mode 100644 index 00000000..3f91fde7 --- /dev/null +++ b/api/src/dto/form/form.field.option.model.ts @@ -0,0 +1,27 @@ +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { FormFieldOptionEntity } from '../../entity/form.field.option.entity' + +@ObjectType('FormFieldOption') +export class FormFieldOptionModel { + readonly _id: number + + @Field(() => ID) + readonly id: string + + @Field({ nullable: true }) + readonly key: string + + @Field({ nullable: true }) + readonly title: string + + @Field() + readonly value: string + + constructor(id: string, option: FormFieldOptionEntity) { + this._id = option.id + this.id = id + this.key = option.key + this.title = option.title + this.value = option.value + } +} diff --git a/api/src/dto/form/form.field.rating.input.ts b/api/src/dto/form/form.field.rating.input.ts new file mode 100644 index 00000000..9663e92c --- /dev/null +++ b/api/src/dto/form/form.field.rating.input.ts @@ -0,0 +1,11 @@ +import { Field, InputType } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' + +@InputType() +export class FormFieldRatingInput { + @Field(() => GraphQLInt, { nullable: true }) + readonly steps: number + + @Field({ nullable: true }) + readonly shape: string +} diff --git a/api/src/dto/form/form.field.rating.model.ts b/api/src/dto/form/form.field.rating.model.ts new file mode 100644 index 00000000..0ea2e65d --- /dev/null +++ b/api/src/dto/form/form.field.rating.model.ts @@ -0,0 +1,17 @@ +import { Field, ObjectType } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { RatingEmbedded } from '../../entity/embedded/rating.embedded' + +@ObjectType('FormFieldRating') +export class FormFieldRatingModel { + @Field(() => GraphQLInt, { nullable: true }) + readonly steps: number + + @Field({ nullable: true }) + readonly shape: string + + constructor(option: RatingEmbedded) { + this.steps = option.steps + this.shape = option.shape + } +} diff --git a/api/src/dto/form/form.hook.input.ts b/api/src/dto/form/form.hook.input.ts new file mode 100644 index 00000000..68c8b74c --- /dev/null +++ b/api/src/dto/form/form.hook.input.ts @@ -0,0 +1,16 @@ +import { Field, ID, InputType } from '@nestjs/graphql' + +@InputType() +export class FormHookInput { + @Field(() => ID) + readonly id: string + + @Field() + readonly enabled: boolean + + @Field({ nullable: true }) + readonly url?: string + + @Field({ nullable: true }) + readonly format?: string +} diff --git a/api/src/dto/form/form.hook.model.ts b/api/src/dto/form/form.hook.model.ts new file mode 100644 index 00000000..8df37c3b --- /dev/null +++ b/api/src/dto/form/form.hook.model.ts @@ -0,0 +1,27 @@ +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { FormHookEntity } from '../../entity/form.hook.entity' + +@ObjectType('FormHook') +export class FormHookModel { + readonly _id: number + + @Field(() => ID) + readonly id: string + + @Field() + readonly enabled: boolean + + @Field({ nullable: true }) + readonly url?: string + + @Field({ nullable: true }) + readonly format?: string + + constructor(id, hook: FormHookEntity) { + this._id = hook.id + this.id = id + this.enabled = hook.enabled + this.url = hook.url + this.format = hook.format + } +} diff --git a/api/src/dto/form/form.model.ts b/api/src/dto/form/form.model.ts new file mode 100644 index 00000000..306f8fd4 --- /dev/null +++ b/api/src/dto/form/form.model.ts @@ -0,0 +1,39 @@ +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { FormEntity } from '../../entity/form.entity' + +@ObjectType('Form') +export class FormModel { + readonly _id: number + + @Field(() => ID) + readonly id: string + + @Field() + readonly title: string + + @Field() + readonly created: Date + + @Field({ nullable: true }) + readonly lastModified?: Date + + @Field() + readonly language: string + + @Field() + readonly showFooter: boolean + + @Field() + readonly anonymousSubmission: boolean + + constructor(id: string, form: FormEntity) { + this._id = form.id + this.id = id + this.title = form.title + this.created = form.created + this.lastModified = form.lastModified + this.language = form.language + this.showFooter = form.showFooter + this.anonymousSubmission = form.anonymousSubmission + } +} diff --git a/api/src/dto/form/form.notification.input.ts b/api/src/dto/form/form.notification.input.ts new file mode 100644 index 00000000..dc4b2512 --- /dev/null +++ b/api/src/dto/form/form.notification.input.ts @@ -0,0 +1,28 @@ +import { Field, ID, InputType } from '@nestjs/graphql' + +@InputType('FormNotificationInput') +export class FormNotificationInput { + @Field(() => ID, { nullable: true }) + readonly id?: string + + @Field({ nullable: true }) + readonly subject?: string + + @Field({ nullable: true }) + readonly htmlTemplate?: string + + @Field({ nullable: true }) + readonly toField?: string + + @Field({ nullable: true }) + readonly fromEmail?: string + + @Field({ nullable: true }) + readonly fromField?: string + + @Field({ nullable: true }) + readonly toEmail?: string + + @Field() + readonly enabled: boolean +} diff --git a/api/src/dto/form/form.notification.model.ts b/api/src/dto/form/form.notification.model.ts new file mode 100644 index 00000000..9d05c19f --- /dev/null +++ b/api/src/dto/form/form.notification.model.ts @@ -0,0 +1,43 @@ +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { FormNotificationEntity } from '../../entity/form.notification.entity' + +@ObjectType('FormNotification') +export class FormNotificationModel { + readonly _id: number + + @Field(() => ID) + readonly id: string + + @Field({ nullable: true }) + readonly subject?: string + + @Field({ nullable: true }) + readonly htmlTemplate?: string + + @Field({ nullable: true }) + readonly toField?: string + + @Field({ nullable: true }) + readonly fromEmail?: string + + @Field({ nullable: true }) + readonly fromField?: string + + @Field({ nullable: true }) + readonly toEmail?: string + + @Field() + readonly enabled: boolean + + constructor(id: string, partial: Partial) { + this._id = partial.id + this.id = id + this.subject = partial.subject + this.htmlTemplate = partial.htmlTemplate + this.enabled = partial.enabled + this.toField = partial.toField?.id.toString() + this.toEmail = partial.toEmail + this.fromField = partial.fromField?.id.toString() + this.fromEmail = partial.fromEmail + } +} diff --git a/api/src/dto/form/form.pager.model.ts b/api/src/dto/form/form.pager.model.ts new file mode 100644 index 00000000..866db2aa --- /dev/null +++ b/api/src/dto/form/form.pager.model.ts @@ -0,0 +1,25 @@ +import { Field, ObjectType } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { FormModel } from './form.model' + +@ObjectType('FormPager') +export class FormPagerModel { + @Field(() => [FormModel]) + entries: FormModel[] + + @Field(() => GraphQLInt) + total: number + + @Field(() => GraphQLInt) + limit: number + + @Field(() => GraphQLInt) + start: number + + constructor(entries: FormModel[], total: number, limit: number, start: number) { + this.entries = entries + this.total = total + this.limit = limit + this.start = start + } +} diff --git a/api/src/dto/form/form.statistic.model.ts b/api/src/dto/form/form.statistic.model.ts new file mode 100644 index 00000000..552446b0 --- /dev/null +++ b/api/src/dto/form/form.statistic.model.ts @@ -0,0 +1,6 @@ +import { ObjectType } from '@nestjs/graphql' + +@ObjectType('FormStatistic') +export class FormStatisticModel { + +} diff --git a/api/src/dto/form/form.update.input.ts b/api/src/dto/form/form.update.input.ts new file mode 100644 index 00000000..87675cd6 --- /dev/null +++ b/api/src/dto/form/form.update.input.ts @@ -0,0 +1,45 @@ +import { Field, ID, InputType } from '@nestjs/graphql' +import { DesignInput } from './design.input' +import { FormFieldInput } from './form.field.input' +import { FormHookInput } from './form.hook.input' +import { FormNotificationInput } from './form.notification.input' +import { PageInput } from './page.input' + +@InputType() +export class FormUpdateInput { + @Field(() => ID) + readonly id: string + + @Field({ nullable: true }) + readonly title: string + + @Field({ nullable: true }) + readonly language: string + + @Field({ nullable: true }) + readonly showFooter: boolean + + @Field({ nullable: true }) + readonly anonymousSubmission: boolean + + @Field({ nullable: true }) + readonly isLive: boolean + + @Field(() => [FormFieldInput], { nullable: true }) + readonly fields: FormFieldInput[] + + @Field(() => [FormHookInput], { nullable: true }) + readonly hooks: FormHookInput[] + + @Field({ nullable: true }) + readonly design: DesignInput + + @Field({ nullable: true }) + readonly startPage: PageInput + + @Field({ nullable: true }) + readonly endPage: PageInput + + @Field(() => [FormNotificationInput], { nullable: true }) + readonly notifications: FormNotificationInput[] +} diff --git a/api/src/dto/form/page.input.ts b/api/src/dto/form/page.input.ts new file mode 100644 index 00000000..2b4256ab --- /dev/null +++ b/api/src/dto/form/page.input.ts @@ -0,0 +1,23 @@ +import { Field, ID, InputType } from '@nestjs/graphql' +import { ButtonInput } from './button.input' + +@InputType() +export class PageInput { + @Field(() => ID, { nullable: true }) + readonly id?: string + + @Field() + readonly show: boolean + + @Field({ nullable: true }) + readonly title?: string + + @Field({ nullable: true }) + readonly paragraph?: string + + @Field({ nullable: true }) + readonly buttonText?: string + + @Field(() => [ButtonInput], { nullable: true }) + readonly buttons: ButtonInput[] +} diff --git a/api/src/dto/form/page.model.ts b/api/src/dto/form/page.model.ts new file mode 100644 index 00000000..c20c1835 --- /dev/null +++ b/api/src/dto/form/page.model.ts @@ -0,0 +1,37 @@ +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { PageEntity } from '../../entity/page.entity' + +@ObjectType('Page') +export class PageModel { + readonly _id: number + + @Field(() => ID) + readonly id: string + + @Field() + readonly show: boolean + + @Field({ nullable: true }) + readonly title?: string + + @Field({ nullable: true }) + readonly paragraph?: string + + @Field({ nullable: true }) + readonly buttonText?: string + + constructor(id: string, page?: Partial) { + if (!page) { + this.id = id + this.show = false + return + } + + this._id = page.id + this.id = id + this.show = page.show + this.title = page.title + this.paragraph = page.paragraph + this.buttonText = page.buttonText + } +} diff --git a/api/src/dto/profile/profile.model.ts b/api/src/dto/profile/profile.model.ts new file mode 100644 index 00000000..1b6ee0ad --- /dev/null +++ b/api/src/dto/profile/profile.model.ts @@ -0,0 +1,15 @@ +import { Field, ObjectType } from '@nestjs/graphql' +import { UserEntity } from '../../entity/user.entity' +import { UserModel } from '../user/user.model' + +@ObjectType('Profile') +export class ProfileModel extends UserModel { + @Field(() => [String]) + readonly roles: string[] + + constructor(id: string, user: UserEntity) { + super(id, user) + + this.roles = user.roles + } +} diff --git a/api/src/dto/profile/profile.update.input.ts b/api/src/dto/profile/profile.update.input.ts new file mode 100644 index 00000000..d09e98c2 --- /dev/null +++ b/api/src/dto/profile/profile.update.input.ts @@ -0,0 +1,25 @@ +import { Field, ID, InputType } from '@nestjs/graphql' + +@InputType() +export class ProfileUpdateInput { + @Field(() => ID) + readonly id: string + + @Field({ nullable: true }) + readonly username: string + + @Field({ nullable: true }) + readonly email: string + + @Field({ nullable: true }) + readonly firstName: string + + @Field({ nullable: true }) + readonly lastName: string + + @Field({ nullable: true }) + readonly password: string + + @Field({ nullable: true }) + readonly language: string +} diff --git a/api/src/dto/setting/setting.model.ts b/api/src/dto/setting/setting.model.ts new file mode 100644 index 00000000..b8ec678d --- /dev/null +++ b/api/src/dto/setting/setting.model.ts @@ -0,0 +1,24 @@ +import { Field, ID, ObjectType } from '@nestjs/graphql' + +@ObjectType('Setting') +export class SettingModel { + @Field(() => ID) + readonly key: string + + @Field({ nullable: true }) + readonly value?: string + + @Field() + readonly isTrue: boolean + + @Field() + readonly isFalse: boolean + + constructor(key: string, value: string) { + this.key = key + this.value = value + + this.isTrue = value ? (value.toLowerCase() === 'true' || value === '1') : false + this.isFalse = !this.isTrue + } +} diff --git a/api/src/dto/setting/setting.pager.model.ts b/api/src/dto/setting/setting.pager.model.ts new file mode 100644 index 00000000..9b8b5c37 --- /dev/null +++ b/api/src/dto/setting/setting.pager.model.ts @@ -0,0 +1,25 @@ +import { Field, ObjectType } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { SettingModel } from './setting.model' + +@ObjectType('SettingPager') +export class SettingPagerModel { + @Field(() => [SettingModel]) + entries: SettingModel[] + + @Field(() => GraphQLInt) + total: number + + @Field(() => GraphQLInt) + limit: number + + @Field(() => GraphQLInt) + start: number + + constructor(entries: SettingModel[], total: number, limit: number, start: number) { + this.entries = entries + this.total = total + this.limit = limit + this.start = start + } +} diff --git a/api/src/dto/status.model.ts b/api/src/dto/status.model.ts new file mode 100644 index 00000000..9aaf6171 --- /dev/null +++ b/api/src/dto/status.model.ts @@ -0,0 +1,11 @@ +import { Field, ObjectType } from '@nestjs/graphql' + +@ObjectType('Version') +export class StatusModel { + @Field() + readonly version: string + + constructor(partial: Partial) { + this.version = partial.version + } +} diff --git a/api/src/dto/submission/device.input.ts b/api/src/dto/submission/device.input.ts new file mode 100644 index 00000000..40caafbb --- /dev/null +++ b/api/src/dto/submission/device.input.ts @@ -0,0 +1,13 @@ +import { Field, InputType } from '@nestjs/graphql' + +@InputType() +export class DeviceInput { + @Field() + readonly type: string + + @Field() + readonly name: string + + @Field({ nullable: true }) + readonly language: string +} diff --git a/api/src/dto/submission/device.model.ts b/api/src/dto/submission/device.model.ts new file mode 100644 index 00000000..6080aa67 --- /dev/null +++ b/api/src/dto/submission/device.model.ts @@ -0,0 +1,20 @@ +import { Field, ObjectType } from '@nestjs/graphql' +import { DeviceEmbedded } from '../../entity/embedded/device.embedded' + +@ObjectType('Device') +export class DeviceModel { + @Field() + readonly type: string + + @Field() + readonly name: string + + @Field({ nullable: true }) + readonly language: string + + constructor(device: DeviceEmbedded) { + this.type = device.type + this.name = device.name + this.language = device.language + } +} diff --git a/api/src/dto/submission/geo.location.model.ts b/api/src/dto/submission/geo.location.model.ts new file mode 100644 index 00000000..3a0498de --- /dev/null +++ b/api/src/dto/submission/geo.location.model.ts @@ -0,0 +1,16 @@ +import { Field, ObjectType } from '@nestjs/graphql' +import { GeoLocationEmbedded } from '../../entity/embedded/geo.location.embedded' + +@ObjectType('GeoLocation') +export class GeoLocationModel { + @Field({ nullable: true }) + country?: string + + @Field({ nullable: true }) + city?: string + + constructor(geo: GeoLocationEmbedded) { + this.country = geo.country + this.city = geo.city + } +} diff --git a/api/src/dto/submission/submission.field.model.ts b/api/src/dto/submission/submission.field.model.ts new file mode 100644 index 00000000..d7e796dc --- /dev/null +++ b/api/src/dto/submission/submission.field.model.ts @@ -0,0 +1,23 @@ +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { SubmissionFieldEntity } from '../../entity/submission.field.entity' + +@ObjectType('SubmissionField') +export class SubmissionFieldModel { + readonly _id: number + + @Field(() => ID) + readonly id: string + + @Field() + readonly value: string + + @Field() + readonly type: string + + constructor(id: string, field: SubmissionFieldEntity) { + this._id = field.id + this.id = id + this.value = JSON.stringify(field.content) + this.type = field.type + } +} diff --git a/api/src/dto/submission/submission.model.ts b/api/src/dto/submission/submission.model.ts new file mode 100644 index 00000000..8885df21 --- /dev/null +++ b/api/src/dto/submission/submission.model.ts @@ -0,0 +1,48 @@ +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { SubmissionEntity } from '../../entity/submission.entity' +import { DeviceModel } from './device.model' +import { GeoLocationModel } from './geo.location.model' + +@ObjectType('Submission') +export class SubmissionModel { + readonly _id: number + + @Field(() => ID) + readonly id: string + + @Field() + readonly ipAddr: string + + @Field(() => GeoLocationModel) + readonly geoLocation: GeoLocationModel + + @Field(() => DeviceModel) + readonly device: DeviceModel + + @Field() + readonly timeElapsed: number + + @Field() + readonly percentageComplete: number + + @Field() + readonly created: Date + + @Field({ nullable: true }) + readonly lastModified?: Date + + constructor(id: string, submission: SubmissionEntity) { + this._id = submission.id + this.id = id + + this.ipAddr = submission.ipAddr + this.geoLocation = new GeoLocationModel(submission.geoLocation) + this.device = new DeviceModel(submission.device) + + this.timeElapsed = submission.timeElapsed + this.percentageComplete = submission.percentageComplete + + this.created = submission.created + this.lastModified = submission.lastModified + } +} diff --git a/api/src/dto/submission/submission.pager.filter.input.ts b/api/src/dto/submission/submission.pager.filter.input.ts new file mode 100644 index 00000000..08374279 --- /dev/null +++ b/api/src/dto/submission/submission.pager.filter.input.ts @@ -0,0 +1,10 @@ +import { Field, InputType } from '@nestjs/graphql' + +@InputType('SubmissionPagerFilterInput') +export class SubmissionPagerFilterInput { + @Field({ nullable: true } ) + finished?: boolean + + @Field({ nullable: true } ) + excludeEmpty?: boolean +} diff --git a/api/src/dto/submission/submission.pager.model.ts b/api/src/dto/submission/submission.pager.model.ts new file mode 100644 index 00000000..672f6aed --- /dev/null +++ b/api/src/dto/submission/submission.pager.model.ts @@ -0,0 +1,25 @@ +import { Field, ObjectType } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { SubmissionModel } from './submission.model' + +@ObjectType('SubmissionPager') +export class SubmissionPagerModel { + @Field(() => [SubmissionModel]) + entries: SubmissionModel[] + + @Field(() => GraphQLInt) + total: number + + @Field(() => GraphQLInt) + limit: number + + @Field(() => GraphQLInt) + start: number + + constructor(entries: SubmissionModel[], total: number, limit: number, start: number) { + this.entries = entries + this.total = total + this.limit = limit + this.start = start + } +} diff --git a/api/src/dto/submission/submission.progress.model.ts b/api/src/dto/submission/submission.progress.model.ts new file mode 100644 index 00000000..8a6ebb7a --- /dev/null +++ b/api/src/dto/submission/submission.progress.model.ts @@ -0,0 +1,33 @@ +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { SubmissionEntity } from '../../entity/submission.entity' + +@ObjectType('SubmissionProgress') +export class SubmissionProgressModel { + readonly _id: number + + @Field(() => ID) + readonly id: string + + @Field() + readonly timeElapsed: number + + @Field() + readonly percentageComplete: number + + @Field() + readonly created: Date + + @Field({ nullable: true }) + readonly lastModified?: Date + + constructor(id: string, submission: Partial) { + this._id = submission.id + this.id = id + + this.timeElapsed = submission.timeElapsed + this.percentageComplete = submission.percentageComplete + + this.created = submission.created + this.lastModified = submission.lastModified + } +} diff --git a/api/src/dto/submission/submission.set.field.input.ts b/api/src/dto/submission/submission.set.field.input.ts new file mode 100644 index 00000000..8c1bacb4 --- /dev/null +++ b/api/src/dto/submission/submission.set.field.input.ts @@ -0,0 +1,13 @@ +import { Field, ID, InputType } from '@nestjs/graphql' + +@InputType() +export class SubmissionSetFieldInput { + @Field() + readonly token: string + + @Field(() => ID) + readonly field: string + + @Field() + readonly data: string +} diff --git a/api/src/dto/submission/submission.start.input.ts b/api/src/dto/submission/submission.start.input.ts new file mode 100644 index 00000000..966d11f4 --- /dev/null +++ b/api/src/dto/submission/submission.start.input.ts @@ -0,0 +1,11 @@ +import { Field, InputType } from '@nestjs/graphql' +import { DeviceInput } from './device.input' + +@InputType() +export class SubmissionStartInput { + @Field() + readonly token: string + + @Field(() => DeviceInput) + readonly device: DeviceInput +} diff --git a/api/src/dto/submission/submission.statistic.model.ts b/api/src/dto/submission/submission.statistic.model.ts new file mode 100644 index 00000000..9c3623b5 --- /dev/null +++ b/api/src/dto/submission/submission.statistic.model.ts @@ -0,0 +1,6 @@ +import { ObjectType } from '@nestjs/graphql' + +@ObjectType('SubmissionStatistic') +export class SubmissionStatisticModel { + +} diff --git a/api/src/dto/user/user.create.input.ts b/api/src/dto/user/user.create.input.ts new file mode 100644 index 00000000..06a885bc --- /dev/null +++ b/api/src/dto/user/user.create.input.ts @@ -0,0 +1,28 @@ +import { Field, InputType } from '@nestjs/graphql' +import { IsEmail, IsNotEmpty, MaxLength, MinLength } from 'class-validator' + +@InputType() +export class UserCreateInput { + @Field() + @MinLength(2) + @MaxLength(50) + username: string + + @Field() + @IsEmail() + @IsNotEmpty() + email: string + + @Field() + @MinLength(5) + password: string + + @Field({ nullable: true }) + firstName?: string + + @Field({ nullable: true }) + lastName?: string + + @Field({ nullable: true }) + language?: string +} diff --git a/api/src/dto/user/user.model.ts b/api/src/dto/user/user.model.ts new file mode 100644 index 00000000..bae50070 --- /dev/null +++ b/api/src/dto/user/user.model.ts @@ -0,0 +1,57 @@ +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { UserEntity } from '../../entity/user.entity' + +@ObjectType('User') +export class UserModel { + readonly _id: number + + @Field(() => ID) + readonly id: string + + /** + * @deprecated use emailVerified instead + */ + @Field({ deprecationReason: 'use emailVerified instead' }) + readonly verifiedEmail: boolean + + @Field() + readonly emailVerified: boolean + + @Field() + readonly username: string + + @Field() + readonly email: string + + @Field() + readonly language: string + + @Field({ nullable: true }) + readonly firstName?: string + + @Field({ nullable: true }) + readonly lastName?: string + + @Field() + readonly created: Date + + @Field({ nullable: true }) + readonly lastModified: Date + + constructor(id: string, user: UserEntity) { + this._id = user.id + this.id = id + this.username = user.username + this.email = user.email + + this.language = user.language + this.firstName = user.firstName + this.lastName = user.lastName + + this.verifiedEmail = user.emailVerified + this.emailVerified = user.emailVerified + + this.created = user.created + this.lastModified = user.lastModified + } +} diff --git a/api/src/dto/user/user.pager.model.ts b/api/src/dto/user/user.pager.model.ts new file mode 100644 index 00000000..681ed652 --- /dev/null +++ b/api/src/dto/user/user.pager.model.ts @@ -0,0 +1,25 @@ +import { Field, ObjectType } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { UserModel } from './user.model' + +@ObjectType('UserPager') +export class UserPagerModel { + @Field(() => [UserModel]) + entries: UserModel[] + + @Field(() => GraphQLInt) + total: number + + @Field(() => GraphQLInt) + limit: number + + @Field(() => GraphQLInt) + start: number + + constructor(entries: UserModel[], total: number, limit: number, start: number) { + this.entries = entries + this.total = total + this.limit = limit + this.start = start + } +} diff --git a/api/src/dto/user/user.statistic.model.ts b/api/src/dto/user/user.statistic.model.ts new file mode 100644 index 00000000..203c99e6 --- /dev/null +++ b/api/src/dto/user/user.statistic.model.ts @@ -0,0 +1,6 @@ +import { ObjectType } from '@nestjs/graphql' + +@ObjectType('UserStatistic') +export class UserStatisticModel { + +} diff --git a/api/src/dto/user/user.update.input.ts b/api/src/dto/user/user.update.input.ts new file mode 100644 index 00000000..c5463263 --- /dev/null +++ b/api/src/dto/user/user.update.input.ts @@ -0,0 +1,29 @@ +import { Field, ID, InputType } from '@nestjs/graphql' + +@InputType() +export class UserUpdateInput { + @Field(() => ID) + readonly id: string + + @Field({ nullable: true }) + readonly username: string + + @Field({ nullable: true }) + readonly email: string + + @Field({ nullable: true }) + readonly firstName: string + + @Field({ nullable: true }) + readonly lastName: string + + @Field({ nullable: true }) + readonly password: string + + // TODO validate + @Field(() => [String], { nullable: true }) + readonly roles: string[] + + @Field({ nullable: true }) + readonly language: string +} diff --git a/api/src/entity/embedded/analytics.embedded.ts b/api/src/entity/embedded/analytics.embedded.ts new file mode 100644 index 00000000..11e71fe0 --- /dev/null +++ b/api/src/entity/embedded/analytics.embedded.ts @@ -0,0 +1,6 @@ +import { Column } from 'typeorm' + +export class AnalyticsEmbedded { + @Column({ nullable: true }) + readonly gaCode?: string +} diff --git a/api/src/entity/embedded/colors.embedded.ts b/api/src/entity/embedded/colors.embedded.ts new file mode 100644 index 00000000..9bb52d9b --- /dev/null +++ b/api/src/entity/embedded/colors.embedded.ts @@ -0,0 +1,21 @@ +import { Column } from 'typeorm' + +export class ColorsEmbedded { + @Column({ nullable: true }) + public background?: string + + @Column({ nullable: true }) + public question?: string + + @Column({ nullable: true }) + public answer?: string + + @Column({ nullable: true }) + public button?: string + + @Column({ nullable: true }) + public buttonActive?: string + + @Column({ nullable: true }) + public buttonText?: string +} diff --git a/api/src/entity/embedded/design.embedded.ts b/api/src/entity/embedded/design.embedded.ts new file mode 100644 index 00000000..0aa0ee8b --- /dev/null +++ b/api/src/entity/embedded/design.embedded.ts @@ -0,0 +1,13 @@ +import { Column } from 'typeorm' +import { ColorsEmbedded } from './colors.embedded' + +export class DesignEmbedded { + @Column(() => ColorsEmbedded) + colors: ColorsEmbedded = new ColorsEmbedded() + + @Column({ nullable: true }) + font?: string + + @Column({ nullable: true }) + layout?: string +} diff --git a/api/src/entity/embedded/device.embedded.ts b/api/src/entity/embedded/device.embedded.ts new file mode 100644 index 00000000..989dc2da --- /dev/null +++ b/api/src/entity/embedded/device.embedded.ts @@ -0,0 +1,12 @@ +import { Column } from 'typeorm' + +export class DeviceEmbedded { + @Column({ nullable: true }) + public language?: string + + @Column({ nullable: true }) + public type?: string + + @Column({ nullable: true }) + public name?: string +} diff --git a/api/src/entity/embedded/geo.location.embedded.ts b/api/src/entity/embedded/geo.location.embedded.ts new file mode 100644 index 00000000..91421338 --- /dev/null +++ b/api/src/entity/embedded/geo.location.embedded.ts @@ -0,0 +1,9 @@ +import { Column } from 'typeorm' + +export class GeoLocationEmbedded { + @Column({ nullable: true }) + readonly country?: string + + @Column({ nullable: true }) + readonly city?: string +} diff --git a/api/src/entity/embedded/rating.embedded.ts b/api/src/entity/embedded/rating.embedded.ts new file mode 100644 index 00000000..eb520c48 --- /dev/null +++ b/api/src/entity/embedded/rating.embedded.ts @@ -0,0 +1,9 @@ +import { Column } from 'typeorm' + +export class RatingEmbedded { + @Column({ nullable: true }) + readonly steps?: number + + @Column({ nullable: true }) + readonly shape?: string +} diff --git a/api/src/entity/form.entity.ts b/api/src/entity/form.entity.ts new file mode 100644 index 00000000..74c11037 --- /dev/null +++ b/api/src/entity/form.entity.ts @@ -0,0 +1,81 @@ +import { + Column, + CreateDateColumn, + Entity, + ManyToOne, + OneToMany, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from 'typeorm' +import { AnalyticsEmbedded } from './embedded/analytics.embedded' +import { DesignEmbedded } from './embedded/design.embedded' +import { FormFieldEntity } from './form.field.entity' +import { FormHookEntity } from './form.hook.entity' +import { FormNotificationEntity } from './form.notification.entity' +import { PageEntity } from './page.entity' +import { SubmissionEntity } from './submission.entity' +import { UserEntity } from './user.entity' +import { VisitorEntity } from './visitor.entity' + +@Entity({ name: 'form' }) +export class FormEntity { + @PrimaryGeneratedColumn() + public id: number + + @Column() + public title: string + + @Column({ length: 10 }) + public language: string + + @Column(() => AnalyticsEmbedded) + public analytics: AnalyticsEmbedded = new AnalyticsEmbedded() + + @OneToMany(() => VisitorEntity, visitor => visitor.form) + public visitors: VisitorEntity[] + + @OneToMany(() => SubmissionEntity, submission => submission.form) + public submissions: SubmissionEntity[] + + @OneToMany(() => FormFieldEntity, field => field.form, { eager: true, orphanedRowAction: 'delete', cascade: true }) + public fields: FormFieldEntity[] + + @OneToMany(() => FormHookEntity, field => field.form, { eager: true, orphanedRowAction: 'delete', cascade: true }) + public hooks: FormHookEntity[] + + @ManyToOne(() => UserEntity, { eager: true }) + public admin: UserEntity + + @ManyToOne(() => PageEntity, { eager: true, cascade: true }) + public startPage: PageEntity; + + @ManyToOne(() => PageEntity, { eager: true, cascade: true }) + public endPage: PageEntity; + + @OneToMany(() => FormNotificationEntity, notification => notification.form, { eager: true, orphanedRowAction: 'delete', cascade: true }) + public notifications: FormNotificationEntity[] + + @Column() + public showFooter: boolean; + + @Column() + public isLive: boolean; + + @Column({ default: false }) + public anonymousSubmission: boolean; + + @Column(() => DesignEmbedded) + public design: DesignEmbedded = new DesignEmbedded(); + + @CreateDateColumn() + public created: Date + + @UpdateDateColumn() + public lastModified: Date + + constructor(partial?: Partial) { + if (partial) { + Object.assign(this, partial) + } + } +} diff --git a/api/src/entity/form.field.entity.ts b/api/src/entity/form.field.entity.ts new file mode 100644 index 00000000..5f84af84 --- /dev/null +++ b/api/src/entity/form.field.entity.ts @@ -0,0 +1,47 @@ +import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from 'typeorm' +import { RatingEmbedded } from './embedded/rating.embedded' +import { FormEntity } from './form.entity' +import { FormFieldLogicEntity } from './form.field.logic.entity' +import { FormFieldOptionEntity } from './form.field.option.entity' + +@Entity({ name: 'form_field' }) +export class FormFieldEntity { + @PrimaryGeneratedColumn() + public id: number + + @ManyToOne(() => FormEntity, form => form.fields) + public form: FormEntity + + @Column() + public title: string + + @Column({ type: 'text' }) + public description: string + + @Column({ nullable: true }) + public slug?: string + + @Column({ nullable: true }) + public idx?: number + + @OneToMany(() => FormFieldLogicEntity, logic => logic.field, { eager: true, orphanedRowAction: 'delete', cascade: true }) + public logic: FormFieldLogicEntity[] + + @Column(() => RatingEmbedded) + public rating: RatingEmbedded = new RatingEmbedded() + + @OneToMany(() => FormFieldOptionEntity, option => option.field, { eager: true, orphanedRowAction: 'delete', cascade: true }) + public options?: FormFieldOptionEntity[] + + @Column() + public required: boolean + + @Column({ type: 'boolean' }) + public disabled = false + + @Column() + public type: string + + @Column({ nullable: true }) + public defaultValue: string +} diff --git a/api/src/entity/form.field.logic.entity.ts b/api/src/entity/form.field.logic.entity.ts new file mode 100644 index 00000000..7cdb0260 --- /dev/null +++ b/api/src/entity/form.field.logic.entity.ts @@ -0,0 +1,37 @@ +import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm' +import { FormFieldEntity } from './form.field.entity' + +export type FormFieldLogicAction = 'visible' | 'require' | 'disable' | 'jumpTo' + +@Entity({ name: 'form_field_logic' }) +export class FormFieldLogicEntity { + @PrimaryGeneratedColumn() + public id: number + + @ManyToOne(() => FormFieldEntity, field => field.options) + public field: FormFieldEntity + + @Column() + public formula: string + + @Column({ nullable: true }) + public idx?: number + + @Column({ type: 'varchar', length: 10 }) + public action: FormFieldLogicAction + + @Column({ nullable: true }) + public visible?: boolean + + @Column({ nullable: true }) + public require?: boolean + + @Column({ nullable: true }) + public disable?: boolean + + @ManyToOne(() => FormFieldEntity) + public jumpTo?: FormFieldEntity + + @Column() + public enabled: boolean +} diff --git a/api/src/entity/form.field.option.entity.ts b/api/src/entity/form.field.option.entity.ts new file mode 100644 index 00000000..1de91d80 --- /dev/null +++ b/api/src/entity/form.field.option.entity.ts @@ -0,0 +1,20 @@ +import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm' +import { FormFieldEntity } from './form.field.entity' + +@Entity({ name: 'form_field_option' }) +export class FormFieldOptionEntity { + @PrimaryGeneratedColumn() + public id: number + + @ManyToOne(() => FormFieldEntity, field => field.options) + public field: FormFieldEntity + + @Column({ nullable: true }) + public key?: string + + @Column({ nullable: true }) + public title?: string + + @Column() + public value: string +} diff --git a/api/src/entity/form.hook.entity.ts b/api/src/entity/form.hook.entity.ts new file mode 100644 index 00000000..877b9377 --- /dev/null +++ b/api/src/entity/form.hook.entity.ts @@ -0,0 +1,20 @@ +import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm' +import { FormEntity } from './form.entity' + +@Entity({ name: 'form_hook' }) +export class FormHookEntity { + @PrimaryGeneratedColumn() + public id: number + + @ManyToOne(() => FormEntity, form => form.hooks) + public form: FormEntity + + @Column() + public enabled: boolean + + @Column() + public url: string + + @Column({ nullable: true }) + public format?: string +} diff --git a/api/src/entity/form.notification.entity.ts b/api/src/entity/form.notification.entity.ts new file mode 100644 index 00000000..2d71e02e --- /dev/null +++ b/api/src/entity/form.notification.entity.ts @@ -0,0 +1,33 @@ +import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm' +import { FormEntity } from './form.entity' +import { FormFieldEntity } from './form.field.entity' + +@Entity({ name: 'form_notification' }) +export class FormNotificationEntity { + @PrimaryGeneratedColumn() + public id: number + + @ManyToOne(() => FormEntity, form => form.notifications) + public form: FormEntity + + @Column({ nullable: true }) + public subject?: string + + @Column({ nullable: true }) + public htmlTemplate?: string + + @Column() + public enabled: boolean + + @ManyToOne(() => FormFieldEntity) + public fromField?: FormFieldEntity + + @ManyToOne(() => FormFieldEntity) + public toField?: FormFieldEntity + + @Column({ nullable: true }) + public toEmail?: string + + @Column({ nullable: true }) + public fromEmail?: string +} diff --git a/api/src/entity/index.ts b/api/src/entity/index.ts new file mode 100644 index 00000000..53f3538f --- /dev/null +++ b/api/src/entity/index.ts @@ -0,0 +1,27 @@ +import { FormEntity } from './form.entity' +import { FormFieldEntity } from './form.field.entity' +import { FormFieldLogicEntity } from './form.field.logic.entity' +import { FormFieldOptionEntity } from './form.field.option.entity' +import { FormHookEntity } from './form.hook.entity' +import { FormNotificationEntity } from './form.notification.entity' +import { PageButtonEntity } from './page.button.entity' +import { PageEntity } from './page.entity' +import { SubmissionEntity } from './submission.entity' +import { SubmissionFieldEntity } from './submission.field.entity' +import { UserEntity } from './user.entity' +import { VisitorEntity } from './visitor.entity' + +export const entities = [ + FormEntity, + FormFieldEntity, + FormFieldLogicEntity, + FormFieldOptionEntity, + FormHookEntity, + FormNotificationEntity, + PageButtonEntity, + PageEntity, + SubmissionEntity, + SubmissionFieldEntity, + UserEntity, + VisitorEntity, +] diff --git a/api/src/entity/page.button.entity.ts b/api/src/entity/page.button.entity.ts new file mode 100644 index 00000000..399af1c7 --- /dev/null +++ b/api/src/entity/page.button.entity.ts @@ -0,0 +1,29 @@ +import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm' +import { PageEntity } from './page.entity' + +@Entity({ name: 'page_button' }) +export class PageButtonEntity { + @PrimaryGeneratedColumn() + public id: number + + @ManyToOne(() => PageEntity, page => page.buttons) + public page: PageEntity + + @Column({ nullable: true }) + public url?: string + + @Column({ nullable: true }) + public action?: string + + @Column() + public text: string + + @Column({ nullable: true }) + public bgColor?: string + + @Column({ nullable: true }) + public activeColor?: string + + @Column({ nullable: true }) + public color?: string +} diff --git a/api/src/entity/page.entity.ts b/api/src/entity/page.entity.ts new file mode 100644 index 00000000..25612a36 --- /dev/null +++ b/api/src/entity/page.entity.ts @@ -0,0 +1,23 @@ +import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm' +import { PageButtonEntity } from './page.button.entity' + +@Entity({ name: 'page' }) +export class PageEntity { + @PrimaryGeneratedColumn() + public id: number + + @Column() + public show: boolean + + @Column({ nullable: true }) + public title?: string + + @Column({ type: 'text', nullable: true }) + public paragraph?: string + + @Column({ nullable: true }) + public buttonText?: string + + @OneToMany(() => PageButtonEntity, button => button.page, { eager: true, orphanedRowAction: 'delete', cascade: true }) + public buttons: PageButtonEntity[] +} diff --git a/api/src/entity/submission.entity.ts b/api/src/entity/submission.entity.ts new file mode 100644 index 00000000..1a222fee --- /dev/null +++ b/api/src/entity/submission.entity.ts @@ -0,0 +1,61 @@ +import { + Column, + CreateDateColumn, + Entity, + ManyToOne, + OneToMany, + PrimaryGeneratedColumn, + RelationId, + UpdateDateColumn, +} from 'typeorm' +import { DeviceEmbedded } from './embedded/device.embedded' +import { GeoLocationEmbedded } from './embedded/geo.location.embedded' +import { FormEntity } from './form.entity' +import { SubmissionFieldEntity } from './submission.field.entity' +import { UserEntity } from './user.entity' +import { VisitorEntity } from './visitor.entity' + +@Entity({ name: 'submission' }) +export class SubmissionEntity { + @PrimaryGeneratedColumn() + public id: number + + @OneToMany(() => SubmissionFieldEntity, field => field.submission, { eager: true }) + public fields: SubmissionFieldEntity[] + + @ManyToOne(() => FormEntity, form => form.submissions, { eager: true }) + public form: FormEntity + + @RelationId('form') + readonly formId: number + + @ManyToOne(() => VisitorEntity, visitor => visitor.submissions, { eager: true }) + public visitor: VisitorEntity + + @Column() + public ipAddr: string + + @Column() + public tokenHash: string + + @Column(() => GeoLocationEmbedded) + public geoLocation: GeoLocationEmbedded = new GeoLocationEmbedded() + + @Column(() => DeviceEmbedded) + public device: DeviceEmbedded = new DeviceEmbedded() + + @Column({ type: 'numeric' }) + public timeElapsed: number + + @Column({ type: 'numeric' }) + public percentageComplete: number + + @ManyToOne(() => UserEntity, { eager: true }) + public user?: UserEntity + + @CreateDateColumn() + public created: Date + + @UpdateDateColumn() + public lastModified: Date +} diff --git a/api/src/entity/submission.field.entity.ts b/api/src/entity/submission.field.entity.ts new file mode 100644 index 00000000..c3866227 --- /dev/null +++ b/api/src/entity/submission.field.entity.ts @@ -0,0 +1,32 @@ +import { Column, Entity, ManyToOne, PrimaryGeneratedColumn, RelationId } from 'typeorm' +import { FormFieldEntity } from './form.field.entity' +import { SubmissionEntity } from './submission.entity' + +type Simple = string | number | boolean + +export type SubmissionFieldContent = Simple | Simple[] | { + [key: string]: Simple | Simple[] | { + [key: string]: Simple | Simple[] + } +} + +@Entity({ name: 'submission_field' }) +export class SubmissionFieldEntity { + @PrimaryGeneratedColumn() + public id: number + + @ManyToOne(() => SubmissionEntity, submission => submission.fields) + public submission: SubmissionEntity + + @ManyToOne(() => FormFieldEntity, { eager: true }) + public field: FormFieldEntity + + @RelationId('field') + readonly fieldId: number + + @Column() + public type: string + + @Column('simple-json') + public content: SubmissionFieldContent +} diff --git a/api/src/entity/user.entity.ts b/api/src/entity/user.entity.ts new file mode 100644 index 00000000..5cb58a48 --- /dev/null +++ b/api/src/entity/user.entity.ts @@ -0,0 +1,56 @@ +import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm' +import { rolesType } from '../config/roles' + +@Entity({ name: 'user' }) +export class UserEntity { + @PrimaryGeneratedColumn() + public id: number + + @Column({ nullable: true }) + public firstName?: string + + @Column({ nullable: true }) + public lastName?: string + + @Column({ length: 255, unique: true }) + public email: string + + @Column('boolean', { default: false }) + public emailVerified = false + + @Column({ length: 255, unique: true }) + public username: string + + @Column() + public passwordHash: string + + @Column({ nullable: true }) + public salt: string + + @Column() + public provider: string + + @Column({ type: 'simple-array' }) + public roles: rolesType + + @Column() + public language: string + + @Column({ nullable: true }) + public resetPasswordToken?: string + + @Column({ nullable: true }) + public resetPasswordExpires?: Date + + @Column({ nullable: true }) + public token?: string + + @Column({ nullable: true }) + public apiKey?: string + + @CreateDateColumn() + public created: Date + + @UpdateDateColumn() + public lastModified: Date +} diff --git a/api/src/entity/visitor.entity.ts b/api/src/entity/visitor.entity.ts new file mode 100644 index 00000000..0fa204c7 --- /dev/null +++ b/api/src/entity/visitor.entity.ts @@ -0,0 +1,43 @@ +import { + Column, + CreateDateColumn, + Entity, + ManyToOne, + OneToMany, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from 'typeorm' +import { DeviceEmbedded } from './embedded/device.embedded' +import { GeoLocationEmbedded } from './embedded/geo.location.embedded' +import { FormEntity } from './form.entity' +import { SubmissionEntity } from './submission.entity' + +@Entity({ name: 'form_visitor' }) +export class VisitorEntity { + @PrimaryGeneratedColumn() + public id: number + + @ManyToOne(() => FormEntity, form => form.visitors) + public form: FormEntity + + @OneToMany(() => SubmissionEntity, submission => submission.visitor) + public submissions: SubmissionEntity[] + + @Column({ nullable: true }) + readonly referrer?: string + + @Column() + readonly ipAddr: string + + @Column(() => GeoLocationEmbedded) + public geoLocation: GeoLocationEmbedded = new GeoLocationEmbedded() + + @Column(() => DeviceEmbedded) + public device: DeviceEmbedded = new DeviceEmbedded() + + @CreateDateColumn() + public created: Date + + @UpdateDateColumn() + public updated: Date +} diff --git a/api/src/guard/gql.auth.guard.ts b/api/src/guard/gql.auth.guard.ts new file mode 100644 index 00000000..18c181c0 --- /dev/null +++ b/api/src/guard/gql.auth.guard.ts @@ -0,0 +1,29 @@ +import { ExecutionContext, Injectable } from '@nestjs/common' +import { GqlExecutionContext } from '@nestjs/graphql' +import { AuthGuard } from '@nestjs/passport' +import { UserEntity } from '../entity/user.entity' +import { ContextCache } from '../resolver/context.cache' + +@Injectable() +export class GqlAuthGuard extends AuthGuard('jwt') { + getRequest(context: ExecutionContext) { + if (context.getType() === 'graphql') { + const ctx = GqlExecutionContext.create(context); + + if (!ctx.getContext().cache) { + ctx.getContext().cache = new ContextCache() + } + return ctx.getContext().req; + } + + return context.switchToHttp().getRequest() + } + + handleRequest(err, user: T): T { + if (err) { + throw new Error('invalid token') + } + + return user + } +} diff --git a/api/src/guard/index.ts b/api/src/guard/index.ts new file mode 100644 index 00000000..cab714b6 --- /dev/null +++ b/api/src/guard/index.ts @@ -0,0 +1,16 @@ +import { APP_GUARD } from '@nestjs/core' +import { GqlAuthGuard } from './gql.auth.guard' +import { LocalAuthGuard } from './local.auth.guard' +import { RolesGuard } from './roles.guard' + +export const guards = [ + { + provide: APP_GUARD, + useClass: GqlAuthGuard, + }, + { + provide: APP_GUARD, + useClass: RolesGuard, + }, + LocalAuthGuard, +] diff --git a/api/src/guard/local.auth.guard.ts b/api/src/guard/local.auth.guard.ts new file mode 100644 index 00000000..5062b31d --- /dev/null +++ b/api/src/guard/local.auth.guard.ts @@ -0,0 +1,10 @@ +import { ExecutionContext, Injectable } from '@nestjs/common' +import { GqlExecutionContext } from '@nestjs/graphql' +import { AuthGuard } from '@nestjs/passport' + +@Injectable() +export class LocalAuthGuard extends AuthGuard('local') { + getRequest(context: ExecutionContext) { + return GqlExecutionContext.create(context).getContext().req + } +} diff --git a/api/src/guard/roles.guard.ts b/api/src/guard/roles.guard.ts new file mode 100644 index 00000000..d07aab8e --- /dev/null +++ b/api/src/guard/roles.guard.ts @@ -0,0 +1,27 @@ +import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common' +import { Reflector } from '@nestjs/core' +import { GqlExecutionContext } from '@nestjs/graphql' + +@Injectable() +export class RolesGuard implements CanActivate { + constructor(private reflector: Reflector) {} + + canActivate(context: ExecutionContext): boolean { + const ctx = GqlExecutionContext.create(context); + + const roles = this.reflector.get('roles', ctx.getHandler()); + if (!roles) { + return true; + } + + const userRoles = ctx.getContext().req.user ? ctx.getContext().req.user.roles : [] + + for (const role of roles) { + if (!userRoles.includes(role)) { + return false; + } + } + + return true; + } +} diff --git a/api/src/main.ts b/api/src/main.ts new file mode 100644 index 00000000..45d6aea4 --- /dev/null +++ b/api/src/main.ts @@ -0,0 +1,22 @@ +import { NestApplicationOptions, ValidationPipe } from '@nestjs/common' +import { NestFactory } from '@nestjs/core' +import cors from 'cors' +import { Logger } from 'nestjs-pino' +import { AppModule } from './app.module' + +void (async () => { + const options: NestApplicationOptions = { + bufferLogs: true, + } + + const app = await NestFactory.create(AppModule, options) + app.useLogger(app.get(Logger)) + app.useGlobalPipes(new ValidationPipe({ + disableErrorMessages: false, + transform: true, + })) + app.enableCors({origin: '*'}) + app.getHttpAdapter().options('*', cors()) + + await app.listen(process.env.PORT || 4100); +})() diff --git a/api/src/migrations/mariadb/1619723437787-initial.ts b/api/src/migrations/mariadb/1619723437787-initial.ts new file mode 100644 index 00000000..08eae9a9 --- /dev/null +++ b/api/src/migrations/mariadb/1619723437787-initial.ts @@ -0,0 +1,74 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class initial1619723437787 implements MigrationInterface { + name = 'initial1619723437787' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('CREATE TABLE `form_field_logic` (`id` int NOT NULL AUTO_INCREMENT, `formula` varchar(255) NOT NULL, `action` varchar(10) NOT NULL, `visible` tinyint NULL, `require` tinyint NULL, `disable` tinyint NULL, `enabled` tinyint NOT NULL, `fieldId` int NULL, `jumpToId` int NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB'); + await queryRunner.query('CREATE TABLE `form_field_option` (`id` int NOT NULL AUTO_INCREMENT, `key` varchar(255) NULL, `title` varchar(255) NULL, `value` varchar(255) NOT NULL, `fieldId` int NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB'); + await queryRunner.query('CREATE TABLE `form_field` (`id` int NOT NULL AUTO_INCREMENT, `title` varchar(255) NOT NULL, `description` text NOT NULL, `slug` varchar(255) NULL, `required` tinyint NOT NULL, `disabled` tinyint NOT NULL, `type` varchar(255) NOT NULL, `value` varchar(255) NOT NULL, `formId` int NULL, `ratingSteps` int NULL, `ratingShape` varchar(255) NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB'); + await queryRunner.query('CREATE TABLE `form_hook` (`id` int NOT NULL AUTO_INCREMENT, `enabled` tinyint NOT NULL, `url` varchar(255) NOT NULL, `format` varchar(255) NULL, `formId` int NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB'); + await queryRunner.query('CREATE TABLE `form_notification` (`id` int NOT NULL AUTO_INCREMENT, `subject` varchar(255) NULL, `htmlTemplate` varchar(255) NULL, `enabled` tinyint NOT NULL, `toEmail` varchar(255) NULL, `fromEmail` varchar(255) NULL, `formId` int NULL, `fromFieldId` int NULL, `toFieldId` int NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB'); + await queryRunner.query('CREATE TABLE `page_button` (`id` int NOT NULL AUTO_INCREMENT, `url` varchar(255) NULL, `action` varchar(255) NULL, `text` varchar(255) NOT NULL, `bgColor` varchar(255) NULL, `activeColor` varchar(255) NULL, `color` varchar(255) NULL, `pageId` int NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB'); + await queryRunner.query('CREATE TABLE `page` (`id` int NOT NULL AUTO_INCREMENT, `show` tinyint NOT NULL, `title` varchar(255) NULL, `paragraph` text NULL, `buttonText` varchar(255) NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB'); + await queryRunner.query('CREATE TABLE `submission_field` (`id` int NOT NULL AUTO_INCREMENT, `fieldType` varchar(255) NOT NULL, `fieldValue` varchar(255) NOT NULL, `submissionId` int NULL, `fieldId` int NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB'); + await queryRunner.query('CREATE TABLE `user` (`id` int NOT NULL AUTO_INCREMENT, `firstName` varchar(255) NULL, `lastName` varchar(255) NULL, `email` varchar(255) NOT NULL, `username` varchar(255) NOT NULL, `passwordHash` varchar(255) NOT NULL, `salt` varchar(255) NULL, `provider` varchar(255) NOT NULL, `roles` text NOT NULL, `language` varchar(255) NOT NULL, `resetPasswordToken` varchar(255) NULL, `resetPasswordExpires` datetime NULL, `token` varchar(255) NULL, `apiKey` varchar(255) NULL, `created` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), `lastModified` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), UNIQUE INDEX `IDX_e12875dfb3b1d92d7d7c5377e2` (`email`), UNIQUE INDEX `IDX_78a916df40e02a9deb1c4b75ed` (`username`), PRIMARY KEY (`id`)) ENGINE=InnoDB'); + await queryRunner.query('CREATE TABLE `form_visitor` (`id` int NOT NULL AUTO_INCREMENT, `referrer` varchar(255) NULL, `ipAddr` varchar(255) NOT NULL, `created` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), `updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), `formId` int NULL, `geoLocationCountry` varchar(255) NULL, `geoLocationCity` varchar(255) NULL, `deviceLanguage` varchar(255) NULL, `deviceType` varchar(255) NULL, `deviceName` varchar(255) NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB'); + await queryRunner.query('CREATE TABLE `submission` (`id` int NOT NULL AUTO_INCREMENT, `ipAddr` varchar(255) NOT NULL, `tokenHash` varchar(255) NOT NULL, `timeElapsed` decimal NOT NULL, `percentageComplete` decimal NOT NULL, `created` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), `lastModified` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), `formId` int NULL, `visitorId` int NULL, `userId` int NULL, `geoLocationCountry` varchar(255) NULL, `geoLocationCity` varchar(255) NULL, `deviceLanguage` varchar(255) NULL, `deviceType` varchar(255) NULL, `deviceName` varchar(255) NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB'); + await queryRunner.query('CREATE TABLE `form` (`id` int NOT NULL AUTO_INCREMENT, `title` varchar(255) NOT NULL, `language` varchar(10) NOT NULL, `showFooter` tinyint NOT NULL, `isLive` tinyint NOT NULL, `created` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), `lastModified` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), `adminId` int NULL, `startPageId` int NULL, `endPageId` int NULL, `analyticsGacode` varchar(255) NULL, `designFont` varchar(255) NULL, `designColorsBackground` varchar(255) NULL, `designColorsQuestion` varchar(255) NULL, `designColorsAnswer` varchar(255) NULL, `designColorsButton` varchar(255) NULL, `designColorsButtonactive` varchar(255) NULL, `designColorsButtontext` varchar(255) NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB'); + await queryRunner.query('ALTER TABLE `form_field_logic` ADD CONSTRAINT `FK_6098b83f6759445d8cfdd03d545` FOREIGN KEY (`fieldId`) REFERENCES `form_field`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `form_field_logic` ADD CONSTRAINT `FK_4a8019f2b753cfb3216dc3001a6` FOREIGN KEY (`jumpToId`) REFERENCES `form_field`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `form_field_option` ADD CONSTRAINT `FK_c4484ad12c2c56db31dffdbfe97` FOREIGN KEY (`fieldId`) REFERENCES `form_field`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `form_field` ADD CONSTRAINT `FK_2d83d8a334dd66445db13f92b77` FOREIGN KEY (`formId`) REFERENCES `form`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `form_hook` ADD CONSTRAINT `FK_bbeb4d224d8857fd5a458538a30` FOREIGN KEY (`formId`) REFERENCES `form`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `form_notification` ADD CONSTRAINT `FK_a9ed55144108ded893b502d6321` FOREIGN KEY (`formId`) REFERENCES `form`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `form_notification` ADD CONSTRAINT `FK_0876741ce2acdaee4553d7a3bbd` FOREIGN KEY (`fromFieldId`) REFERENCES `form_field`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `form_notification` ADD CONSTRAINT `FK_4915ebae53e09b732322d0ff6ed` FOREIGN KEY (`toFieldId`) REFERENCES `form_field`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `page_button` ADD CONSTRAINT `FK_d9f099286b75fa0034dcd8cf7c2` FOREIGN KEY (`pageId`) REFERENCES `page`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `submission_field` ADD CONSTRAINT `FK_16fae661ce5b10f27abe2e524a0` FOREIGN KEY (`submissionId`) REFERENCES `submission`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `submission_field` ADD CONSTRAINT `FK_5befa92da2370b7eb1cab6ae30a` FOREIGN KEY (`fieldId`) REFERENCES `form_field`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `form_visitor` ADD CONSTRAINT `FK_72ade6c3a3e55d1fce94300f8b6` FOREIGN KEY (`formId`) REFERENCES `form`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `submission` ADD CONSTRAINT `FK_6090e1d5cbf3433ffd14e3b53e7` FOREIGN KEY (`formId`) REFERENCES `form`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `submission` ADD CONSTRAINT `FK_95b73c7faf2c199f005fda5e8c8` FOREIGN KEY (`visitorId`) REFERENCES `form_visitor`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `submission` ADD CONSTRAINT `FK_7bd626272858ef6464aa2579094` FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `form` ADD CONSTRAINT `FK_a7cb33580bca2b362e5e34fdfcd` FOREIGN KEY (`adminId`) REFERENCES `user`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `form` ADD CONSTRAINT `FK_023d9cf1d97e93facc96c86ca70` FOREIGN KEY (`startPageId`) REFERENCES `page`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE `form` ADD CONSTRAINT `FK_e5d158932e43cfbf9958931ee01` FOREIGN KEY (`endPageId`) REFERENCES `page`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `form` DROP FOREIGN KEY `FK_e5d158932e43cfbf9958931ee01`'); + await queryRunner.query('ALTER TABLE `form` DROP FOREIGN KEY `FK_023d9cf1d97e93facc96c86ca70`'); + await queryRunner.query('ALTER TABLE `form` DROP FOREIGN KEY `FK_a7cb33580bca2b362e5e34fdfcd`'); + await queryRunner.query('ALTER TABLE `submission` DROP FOREIGN KEY `FK_7bd626272858ef6464aa2579094`'); + await queryRunner.query('ALTER TABLE `submission` DROP FOREIGN KEY `FK_95b73c7faf2c199f005fda5e8c8`'); + await queryRunner.query('ALTER TABLE `submission` DROP FOREIGN KEY `FK_6090e1d5cbf3433ffd14e3b53e7`'); + await queryRunner.query('ALTER TABLE `form_visitor` DROP FOREIGN KEY `FK_72ade6c3a3e55d1fce94300f8b6`'); + await queryRunner.query('ALTER TABLE `submission_field` DROP FOREIGN KEY `FK_5befa92da2370b7eb1cab6ae30a`'); + await queryRunner.query('ALTER TABLE `submission_field` DROP FOREIGN KEY `FK_16fae661ce5b10f27abe2e524a0`'); + await queryRunner.query('ALTER TABLE `page_button` DROP FOREIGN KEY `FK_d9f099286b75fa0034dcd8cf7c2`'); + await queryRunner.query('ALTER TABLE `form_notification` DROP FOREIGN KEY `FK_4915ebae53e09b732322d0ff6ed`'); + await queryRunner.query('ALTER TABLE `form_notification` DROP FOREIGN KEY `FK_0876741ce2acdaee4553d7a3bbd`'); + await queryRunner.query('ALTER TABLE `form_notification` DROP FOREIGN KEY `FK_a9ed55144108ded893b502d6321`'); + await queryRunner.query('ALTER TABLE `form_hook` DROP FOREIGN KEY `FK_bbeb4d224d8857fd5a458538a30`'); + await queryRunner.query('ALTER TABLE `form_field` DROP FOREIGN KEY `FK_2d83d8a334dd66445db13f92b77`'); + await queryRunner.query('ALTER TABLE `form_field_option` DROP FOREIGN KEY `FK_c4484ad12c2c56db31dffdbfe97`'); + await queryRunner.query('ALTER TABLE `form_field_logic` DROP FOREIGN KEY `FK_4a8019f2b753cfb3216dc3001a6`'); + await queryRunner.query('ALTER TABLE `form_field_logic` DROP FOREIGN KEY `FK_6098b83f6759445d8cfdd03d545`'); + await queryRunner.query('DROP TABLE `form`'); + await queryRunner.query('DROP TABLE `submission`'); + await queryRunner.query('DROP TABLE `form_visitor`'); + await queryRunner.query('DROP INDEX `IDX_78a916df40e02a9deb1c4b75ed` ON `user`'); + await queryRunner.query('DROP INDEX `IDX_e12875dfb3b1d92d7d7c5377e2` ON `user`'); + await queryRunner.query('DROP TABLE `user`'); + await queryRunner.query('DROP TABLE `submission_field`'); + await queryRunner.query('DROP TABLE `page`'); + await queryRunner.query('DROP TABLE `page_button`'); + await queryRunner.query('DROP TABLE `form_notification`'); + await queryRunner.query('DROP TABLE `form_hook`'); + await queryRunner.query('DROP TABLE `form_field`'); + await queryRunner.query('DROP TABLE `form_field_option`'); + await queryRunner.query('DROP TABLE `form_field_logic`'); + } + +} diff --git a/api/src/migrations/mariadb/1621078163528-layout.ts b/api/src/migrations/mariadb/1621078163528-layout.ts new file mode 100644 index 00000000..d9b87874 --- /dev/null +++ b/api/src/migrations/mariadb/1621078163528-layout.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class layout1621078163528 implements MigrationInterface { + name = 'layout1621078163528' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `form` ADD `designLayout` varchar(255) NULL'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `form` DROP COLUMN `designLayout`'); + } + +} diff --git a/api/src/migrations/mariadb/1641124349039-submission.ts b/api/src/migrations/mariadb/1641124349039-submission.ts new file mode 100644 index 00000000..41cb15e7 --- /dev/null +++ b/api/src/migrations/mariadb/1641124349039-submission.ts @@ -0,0 +1,17 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class submission1641124349039 implements MigrationInterface { + name = 'submission1641124349039' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `submission_field` RENAME COLUMN `fieldType` TO `type`'); + await queryRunner.query('ALTER TABLE `submission_field` RENAME COLUMN `fieldValue` TO `content`'); + await queryRunner.query('ALTER TABLE `submission_field` MODIFY COLUMN `content` text NOT NULL'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `submission_field` MODIFY COLUMN `content` varchar(255) NOT NULL'); + await queryRunner.query('ALTER TABLE `submission_field` RENAME COLUMN `content` TO `fieldValue`'); + await queryRunner.query('ALTER TABLE `submission_field` RENAME COLUMN `type` TO `fieldType`'); + } +} diff --git a/api/src/migrations/mariadb/1641132645227-confirm.ts b/api/src/migrations/mariadb/1641132645227-confirm.ts new file mode 100644 index 00000000..ec0215d0 --- /dev/null +++ b/api/src/migrations/mariadb/1641132645227-confirm.ts @@ -0,0 +1,13 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class confirm1641132645227 implements MigrationInterface { + name = 'confirm1641132645227' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `user` ADD `emailVerified` tinyint NOT NULL DEFAULT 0'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `user` DROP COLUMN `emailVerified`'); + } +} diff --git a/api/src/migrations/mariadb/1641151802308-idx.ts b/api/src/migrations/mariadb/1641151802308-idx.ts new file mode 100644 index 00000000..42ff91ef --- /dev/null +++ b/api/src/migrations/mariadb/1641151802308-idx.ts @@ -0,0 +1,15 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class idx1641151802308 implements MigrationInterface { + name = 'idx1641151802308' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `form_field_logic` ADD `idx` int NULL'); + await queryRunner.query('ALTER TABLE `form_field` ADD `idx` int NULL'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `form_field` DROP COLUMN `idx`'); + await queryRunner.query('ALTER TABLE `form_field_logic` DROP COLUMN `idx`'); + } +} diff --git a/api/src/migrations/mariadb/1641193946192-anonymous.ts b/api/src/migrations/mariadb/1641193946192-anonymous.ts new file mode 100644 index 00000000..5f86bfc0 --- /dev/null +++ b/api/src/migrations/mariadb/1641193946192-anonymous.ts @@ -0,0 +1,13 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class anonymous1641193946192 implements MigrationInterface { + name = 'anonymous1641193946192' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `form` ADD `anonymousSubmission` tinyint NOT NULL DEFAULT 0'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `form` DROP COLUMN `anonymousSubmission`'); + } +} diff --git a/api/src/migrations/mariadb/1645952169100-defaultValue.ts b/api/src/migrations/mariadb/1645952169100-defaultValue.ts new file mode 100644 index 00000000..36e6547e --- /dev/null +++ b/api/src/migrations/mariadb/1645952169100-defaultValue.ts @@ -0,0 +1,13 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class defaultValue1645952169100 implements MigrationInterface { + name = 'defaultValue1645952169100' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `form_field` RENAME COLUMN `value` TO `defaultValue`'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `form_field` RENAME COLUMN `defaultValue` TO `value`'); + } +} diff --git a/api/src/migrations/mariadb/1645956388810-defaultValue.ts b/api/src/migrations/mariadb/1645956388810-defaultValue.ts new file mode 100644 index 00000000..aa66c9af --- /dev/null +++ b/api/src/migrations/mariadb/1645956388810-defaultValue.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class defaultValue1645956388810 implements MigrationInterface { + name = 'defaultValue1645956388810' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `form_field` MODIFY COLUMN `defaultValue` varchar(255)'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('UPDATE `form_field` SET `defaultValue` = "" WHERE `defaultValue` IS NULL'); + await queryRunner.query('ALTER TABLE `form_field` MODIFY COLUMN `defaultValue` varchar(255) NOT NULL'); + } +} diff --git a/api/src/migrations/postgres/1619723437787-initial.ts b/api/src/migrations/postgres/1619723437787-initial.ts new file mode 100644 index 00000000..9c5ac677 --- /dev/null +++ b/api/src/migrations/postgres/1619723437787-initial.ts @@ -0,0 +1,59 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class initial1619723437787 implements MigrationInterface { + name = 'initial1619723437787' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('CREATE TABLE "form_field_logic" ("id" SERIAL NOT NULL, "formula" character varying NOT NULL, "action" character varying(10) NOT NULL, "visible" boolean, "require" boolean, "disable" boolean, "enabled" boolean NOT NULL, "fieldId" integer, "jumpToId" integer, CONSTRAINT "PK_c40e7f583854ff1b60900d8cf1b" PRIMARY KEY ("id"))'); + await queryRunner.query('CREATE TABLE "form_field_option" ("id" SERIAL NOT NULL, "key" character varying, "title" character varying, "value" character varying NOT NULL, "fieldId" integer, CONSTRAINT "PK_812955356e516819e37b64bf39b" PRIMARY KEY ("id"))'); + await queryRunner.query('CREATE TABLE "form_field" ("id" SERIAL NOT NULL, "title" character varying NOT NULL, "description" text NOT NULL, "slug" character varying, "required" boolean NOT NULL, "disabled" boolean NOT NULL, "type" character varying NOT NULL, "value" character varying NOT NULL, "formId" integer, "ratingSteps" integer, "ratingShape" character varying, CONSTRAINT "PK_135904ddb60085b07254ea4f485" PRIMARY KEY ("id"))'); + await queryRunner.query('CREATE TABLE "form_hook" ("id" SERIAL NOT NULL, "enabled" boolean NOT NULL, "url" character varying NOT NULL, "format" character varying, "formId" integer, CONSTRAINT "PK_4b63bd9ff09f7b3e5c4a41fcbec" PRIMARY KEY ("id"))'); + await queryRunner.query('CREATE TABLE "form_notification" ("id" SERIAL NOT NULL, "subject" character varying, "htmlTemplate" character varying, "enabled" boolean NOT NULL, "toEmail" character varying, "fromEmail" character varying, "formId" integer, "fromFieldId" integer, "toFieldId" integer, CONSTRAINT "PK_935306529aed07c9f6628f6e24f" PRIMARY KEY ("id"))'); + await queryRunner.query('CREATE TABLE "page_button" ("id" SERIAL NOT NULL, "url" character varying, "action" character varying, "text" character varying NOT NULL, "bgColor" character varying, "activeColor" character varying, "color" character varying, "pageId" integer, CONSTRAINT "PK_6609a75a7d82775aac8af1a591c" PRIMARY KEY ("id"))'); + await queryRunner.query('CREATE TABLE "page" ("id" SERIAL NOT NULL, "show" boolean NOT NULL, "title" character varying, "paragraph" text, "buttonText" character varying, CONSTRAINT "PK_742f4117e065c5b6ad21b37ba1f" PRIMARY KEY ("id"))'); + await queryRunner.query('CREATE TABLE "submission_field" ("id" SERIAL NOT NULL, "fieldType" character varying NOT NULL, "fieldValue" character varying NOT NULL, "submissionId" integer, "fieldId" integer, CONSTRAINT "PK_5443f5f769fce3107982c16e0b5" PRIMARY KEY ("id"))'); + await queryRunner.query('CREATE TABLE "user" ("id" SERIAL NOT NULL, "firstName" character varying, "lastName" character varying, "email" character varying(255) NOT NULL, "username" character varying(255) NOT NULL, "passwordHash" character varying NOT NULL, "salt" character varying, "provider" character varying NOT NULL, "roles" text NOT NULL, "language" character varying NOT NULL, "resetPasswordToken" character varying, "resetPasswordExpires" TIMESTAMP, "token" character varying, "apiKey" character varying, "created" TIMESTAMP NOT NULL DEFAULT now(), "lastModified" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"), CONSTRAINT "UQ_78a916df40e02a9deb1c4b75edb" UNIQUE ("username"), CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY ("id"))'); + await queryRunner.query('CREATE TABLE "form_visitor" ("id" SERIAL NOT NULL, "referrer" character varying, "ipAddr" character varying NOT NULL, "created" TIMESTAMP NOT NULL DEFAULT now(), "updated" TIMESTAMP NOT NULL DEFAULT now(), "formId" integer, "geoLocationCountry" character varying, "geoLocationCity" character varying, "deviceLanguage" character varying, "deviceType" character varying, "deviceName" character varying, CONSTRAINT "PK_74224dc63e13cf5cb5f0420e65b" PRIMARY KEY ("id"))'); + await queryRunner.query('CREATE TABLE "submission" ("id" SERIAL NOT NULL, "ipAddr" character varying NOT NULL, "tokenHash" character varying NOT NULL, "timeElapsed" numeric NOT NULL, "percentageComplete" numeric NOT NULL, "created" TIMESTAMP NOT NULL DEFAULT now(), "lastModified" TIMESTAMP NOT NULL DEFAULT now(), "formId" integer, "visitorId" integer, "userId" integer, "geoLocationCountry" character varying, "geoLocationCity" character varying, "deviceLanguage" character varying, "deviceType" character varying, "deviceName" character varying, CONSTRAINT "PK_7faa571d0e4a7076e85890c9bd0" PRIMARY KEY ("id"))'); + await queryRunner.query('CREATE TABLE "form" ("id" SERIAL NOT NULL, "title" character varying NOT NULL, "language" character varying(10) NOT NULL, "showFooter" boolean NOT NULL, "isLive" boolean NOT NULL, "created" TIMESTAMP NOT NULL DEFAULT now(), "lastModified" TIMESTAMP NOT NULL DEFAULT now(), "adminId" integer, "startPageId" integer, "endPageId" integer, "analyticsGacode" character varying, "designFont" character varying, "designColorsBackground" character varying, "designColorsQuestion" character varying, "designColorsAnswer" character varying, "designColorsButton" character varying, "designColorsButtonactive" character varying, "designColorsButtontext" character varying, CONSTRAINT "PK_8f72b95aa2f8ba82cf95dc7579e" PRIMARY KEY ("id"))'); + await queryRunner.query('ALTER TABLE "form_field_logic" ADD CONSTRAINT "FK_6098b83f6759445d8cfdd03d545" FOREIGN KEY ("fieldId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "form_field_logic" ADD CONSTRAINT "FK_4a8019f2b753cfb3216dc3001a6" FOREIGN KEY ("jumpToId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "form_field_option" ADD CONSTRAINT "FK_c4484ad12c2c56db31dffdbfe97" FOREIGN KEY ("fieldId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "form_field" ADD CONSTRAINT "FK_2d83d8a334dd66445db13f92b77" FOREIGN KEY ("formId") REFERENCES "form"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "form_hook" ADD CONSTRAINT "FK_bbeb4d224d8857fd5a458538a30" FOREIGN KEY ("formId") REFERENCES "form"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "form_notification" ADD CONSTRAINT "FK_a9ed55144108ded893b502d6321" FOREIGN KEY ("formId") REFERENCES "form"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "form_notification" ADD CONSTRAINT "FK_0876741ce2acdaee4553d7a3bbd" FOREIGN KEY ("fromFieldId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "form_notification" ADD CONSTRAINT "FK_4915ebae53e09b732322d0ff6ed" FOREIGN KEY ("toFieldId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "page_button" ADD CONSTRAINT "FK_d9f099286b75fa0034dcd8cf7c2" FOREIGN KEY ("pageId") REFERENCES "page"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "submission_field" ADD CONSTRAINT "FK_16fae661ce5b10f27abe2e524a0" FOREIGN KEY ("submissionId") REFERENCES "submission"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "submission_field" ADD CONSTRAINT "FK_5befa92da2370b7eb1cab6ae30a" FOREIGN KEY ("fieldId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "form_visitor" ADD CONSTRAINT "FK_72ade6c3a3e55d1fce94300f8b6" FOREIGN KEY ("formId") REFERENCES "form"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "submission" ADD CONSTRAINT "FK_6090e1d5cbf3433ffd14e3b53e7" FOREIGN KEY ("formId") REFERENCES "form"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "submission" ADD CONSTRAINT "FK_95b73c7faf2c199f005fda5e8c8" FOREIGN KEY ("visitorId") REFERENCES "form_visitor"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "submission" ADD CONSTRAINT "FK_7bd626272858ef6464aa2579094" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "form" ADD CONSTRAINT "FK_a7cb33580bca2b362e5e34fdfcd" FOREIGN KEY ("adminId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "form" ADD CONSTRAINT "FK_023d9cf1d97e93facc96c86ca70" FOREIGN KEY ("startPageId") REFERENCES "page"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + await queryRunner.query('ALTER TABLE "form" ADD CONSTRAINT "FK_e5d158932e43cfbf9958931ee01" FOREIGN KEY ("endPageId") REFERENCES "page"("id") ON DELETE NO ACTION ON UPDATE NO ACTION'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form" DROP CONSTRAINT "FK_e5d158932e43cfbf9958931ee01"'); + await queryRunner.query('ALTER TABLE "form" DROP CONSTRAINT "FK_023d9cf1d97e93facc96c86ca70"'); + await queryRunner.query('ALTER TABLE "form" DROP CONSTRAINT "FK_a7cb33580bca2b362e5e34fdfcd"'); + await queryRunner.query('ALTER TABLE "submission" DROP CONSTRAINT "FK_7bd626272858ef6464aa2579094"'); + await queryRunner.query('ALTER TABLE "submission" DROP CONSTRAINT "FK_95b73c7faf2c199f005fda5e8c8"'); + await queryRunner.query('ALTER TABLE "submission" DROP CONSTRAINT "FK_6090e1d5cbf3433ffd14e3b53e7"'); + await queryRunner.query('ALTER TABLE "form_visitor" DROP CONSTRAINT "FK_72ade6c3a3e55d1fce94300f8b6"'); + await queryRunner.query('ALTER TABLE "submission_field" DROP CONSTRAINT "FK_5befa92da2370b7eb1cab6ae30a"'); + await queryRunner.query('ALTER TABLE "submission_field" DROP CONSTRAINT "FK_16fae661ce5b10f27abe2e524a0"'); + await queryRunner.query('ALTER TABLE "page_button" DROP CONSTRAINT "FK_d9f099286b75fa0034dcd8cf7c2"'); + await queryRunner.query('ALTER TABLE "form_notification" DROP CONSTRAINT "FK_4915ebae53e09b732322d0ff6ed"'); + await queryRunner.query('ALTER TABLE "form_notification" DROP CONSTRAINT "FK_0876741ce2acdaee4553d7a3bbd"'); + await queryRunner.query('ALTER TABLE "form_notification" DROP CONSTRAINT "FK_a9ed55144108ded893b502d6321"'); + await queryRunner.query('ALTER TABLE "form_hook" DROP CONSTRAINT "FK_bbeb4d224d8857fd5a458538a30"'); + await queryRunner.query('ALTER TABLE "form_field" DROP CONSTRAINT "FK_2d83d8a334dd66445db13f92b77"'); + await queryRunner.query('ALTER TABLE "form_field_option" DROP CONSTRAINT "FK_c4484ad12c2c56db31dffdbfe97"'); + await queryRunner.query('ALTER TABLE "form_field_logic" DROP CONSTRAINT "FK_4a8019f2b753cfb3216dc3001a6"'); + await queryRunner.query('ALTER TABLE "form_field_logic" DROP CONSTRAINT "FK_6098b83f6759445d8cfdd03d545"'); + } +} diff --git a/api/src/migrations/postgres/1621078163528-layout.ts b/api/src/migrations/postgres/1621078163528-layout.ts new file mode 100644 index 00000000..85bb84ce --- /dev/null +++ b/api/src/migrations/postgres/1621078163528-layout.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class layout1621078163528 implements MigrationInterface { + name = 'layout1621078163528' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form" ADD "designLayout" character varying'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form" DROP COLUMN "designLayout"'); + } + +} diff --git a/api/src/migrations/postgres/1641124349039-submission.ts b/api/src/migrations/postgres/1641124349039-submission.ts new file mode 100644 index 00000000..29297657 --- /dev/null +++ b/api/src/migrations/postgres/1641124349039-submission.ts @@ -0,0 +1,17 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class submission1641124349039 implements MigrationInterface { + name = 'submission1641124349039' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "submission_field" RENAME COLUMN "fieldType" TO "type"'); + await queryRunner.query('ALTER TABLE "submission_field" RENAME COLUMN "fieldValue" TO "content"'); + await queryRunner.query('ALTER TABLE "submission_field" ALTER COLUMN "content" type text'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "submission_field" ALTER COLUMN "content" type character varying'); + await queryRunner.query('ALTER TABLE "submission_field" RENAME COLUMN "content" TO "fieldValue"'); + await queryRunner.query('ALTER TABLE "submission_field" RENAME COLUMN "type" TO "fieldType"'); + } +} diff --git a/api/src/migrations/postgres/1641132645227-confirm.ts b/api/src/migrations/postgres/1641132645227-confirm.ts new file mode 100644 index 00000000..f13f0f3c --- /dev/null +++ b/api/src/migrations/postgres/1641132645227-confirm.ts @@ -0,0 +1,13 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class confirm1641132645227 implements MigrationInterface { + name = 'confirm1641132645227' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "user" ADD "emailVerified" boolean NOT NULL DEFAULT false'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "user" DROP COLUMN "emailVerified"'); + } +} diff --git a/api/src/migrations/postgres/1641151802308-idx.ts b/api/src/migrations/postgres/1641151802308-idx.ts new file mode 100644 index 00000000..8e7d61aa --- /dev/null +++ b/api/src/migrations/postgres/1641151802308-idx.ts @@ -0,0 +1,15 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class idx1641151802308 implements MigrationInterface { + name = 'idx1641151802308' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form_field_logic" ADD "idx" integer'); + await queryRunner.query('ALTER TABLE "form_field" ADD "idx" integer'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form_field" DROP COLUMN "idx"'); + await queryRunner.query('ALTER TABLE "form_field_logic" DROP COLUMN "idx"'); + } +} diff --git a/api/src/migrations/postgres/1641193946192-anonymous.ts b/api/src/migrations/postgres/1641193946192-anonymous.ts new file mode 100644 index 00000000..e9a29044 --- /dev/null +++ b/api/src/migrations/postgres/1641193946192-anonymous.ts @@ -0,0 +1,13 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class anonymous1641193946192 implements MigrationInterface { + name = 'anonymous1641193946192' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form" ADD "anonymousSubmission" boolean NOT NULL DEFAULT false'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form" DROP COLUMN "anonymousSubmission"'); + } +} diff --git a/api/src/migrations/postgres/1645952169100-defaultValue.ts b/api/src/migrations/postgres/1645952169100-defaultValue.ts new file mode 100644 index 00000000..b9615482 --- /dev/null +++ b/api/src/migrations/postgres/1645952169100-defaultValue.ts @@ -0,0 +1,13 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class defaultValue1645952169100 implements MigrationInterface { + name = 'defaultValue1645952169100' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form_field" RENAME COLUMN "value" TO "defaultValue"'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form_field" RENAME COLUMN "defaultValue" TO "value"'); + } +} diff --git a/api/src/migrations/postgres/1645956388810-defaultValue.ts b/api/src/migrations/postgres/1645956388810-defaultValue.ts new file mode 100644 index 00000000..bd4bf49d --- /dev/null +++ b/api/src/migrations/postgres/1645956388810-defaultValue.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class defaultValue1645956388810 implements MigrationInterface { + name = 'defaultValue1645956388810' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form_field" ALTER COLUMN "defaultValue" DROP NOT NULL'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('UPDATE "form_field" SET "defaultValue" = \'\' WHERE "defaultValue" IS NULL'); + await queryRunner.query('ALTER TABLE "form_field" ALTER COLUMN "defaultValue" SET NOT NULL'); + } +} diff --git a/api/src/migrations/sqlite.migration.ts b/api/src/migrations/sqlite.migration.ts new file mode 100644 index 00000000..c86e6eca --- /dev/null +++ b/api/src/migrations/sqlite.migration.ts @@ -0,0 +1,47 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +function final(target: object, key: string | symbol, descriptor: PropertyDescriptor) { + descriptor.writable = false; +} + + +export abstract class SqliteMigration implements MigrationInterface { + abstract realUp(queryRunner: QueryRunner): Promise + abstract realDown(queryRunner: QueryRunner): Promise + + @final + async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('PRAGMA foreign_keys=off') + await queryRunner.query('BEGIN TRANSACTION') + + try { + await this.realUp(queryRunner) + + await queryRunner.query('COMMIT') + } catch (e) { + await queryRunner.query('ROLLBACK') + + throw e + } finally { + await queryRunner.query('PRAGMA foreign_keys=on') + } + } + + @final + async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('PRAGMA foreign_keys=off') + await queryRunner.query('BEGIN TRANSACTION') + + try { + await this.realDown(queryRunner) + + await queryRunner.query('COMMIT') + } catch (e) { + await queryRunner.query('ROLLBACK') + + throw e + } finally { + await queryRunner.query('PRAGMA foreign_keys=on') + } + } +} diff --git a/api/src/migrations/sqlite/1619723437787-initial.ts b/api/src/migrations/sqlite/1619723437787-initial.ts new file mode 100644 index 00000000..23483153 --- /dev/null +++ b/api/src/migrations/sqlite/1619723437787-initial.ts @@ -0,0 +1,37 @@ +import { QueryRunner } from 'typeorm' +import { SqliteMigration } from '../sqlite.migration' + +export class initial1619723437787 extends SqliteMigration { + name = 'initial1619723437787' + + public async realUp(queryRunner: QueryRunner): Promise { + await queryRunner.query('CREATE TABLE "page" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "show" boolean NOT NULL, "title" varchar, "paragraph" text, "buttonText" varchar)'); + await queryRunner.query('CREATE TABLE "user" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "firstName" varchar, "lastName" varchar, "email" varchar(255) NOT NULL, "username" varchar(255) NOT NULL, "passwordHash" varchar NOT NULL, "salt" varchar, "provider" varchar NOT NULL, "roles" text NOT NULL, "language" varchar NOT NULL, "resetPasswordToken" varchar, "resetPasswordExpires" datetime, "token" varchar, "apiKey" varchar, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "lastModified" datetime NOT NULL DEFAULT (datetime(\'now\')), CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"), CONSTRAINT "UQ_78a916df40e02a9deb1c4b75edb" UNIQUE ("username"))'); + await queryRunner.query('CREATE TABLE "form_field_logic" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "formula" varchar NOT NULL, "action" varchar(10) NOT NULL, "visible" boolean, "require" boolean, "disable" boolean, "enabled" boolean NOT NULL, "fieldId" integer, "jumpToId" integer, CONSTRAINT "FK_6098b83f6759445d8cfdd03d545" FOREIGN KEY ("fieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_4a8019f2b753cfb3216dc3001a6" FOREIGN KEY ("jumpToId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('CREATE TABLE "form_field_option" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "key" varchar, "title" varchar, "value" varchar NOT NULL, "fieldId" integer, CONSTRAINT "FK_c4484ad12c2c56db31dffdbfe97" FOREIGN KEY ("fieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('CREATE TABLE "form_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "description" text NOT NULL, "slug" varchar, "required" boolean NOT NULL, "disabled" boolean NOT NULL, "type" varchar NOT NULL, "value" varchar NOT NULL, "formId" integer, "ratingSteps" integer, "ratingShape" varchar, CONSTRAINT "FK_2d83d8a334dd66445db13f92b77" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('CREATE TABLE "form_hook" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "enabled" boolean NOT NULL, "url" varchar NOT NULL, "format" varchar, "formId" integer, CONSTRAINT "FK_bbeb4d224d8857fd5a458538a30" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('CREATE TABLE "form_notification" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "subject" varchar, "htmlTemplate" varchar, "enabled" boolean NOT NULL, "toEmail" varchar, "fromEmail" varchar, "formId" integer, "fromFieldId" integer, "toFieldId" integer, CONSTRAINT "FK_a9ed55144108ded893b502d6321" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_0876741ce2acdaee4553d7a3bbd" FOREIGN KEY ("fromFieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_4915ebae53e09b732322d0ff6ed" FOREIGN KEY ("toFieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('CREATE TABLE "page_button" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "url" varchar, "action" varchar, "text" varchar NOT NULL, "bgColor" varchar, "activeColor" varchar, "color" varchar, "pageId" integer, CONSTRAINT "FK_d9f099286b75fa0034dcd8cf7c2" FOREIGN KEY ("pageId") REFERENCES "page" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('CREATE TABLE "submission_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "fieldType" varchar NOT NULL, "fieldValue" varchar NOT NULL, "submissionId" integer, "fieldId" integer, CONSTRAINT "FK_16fae661ce5b10f27abe2e524a0" FOREIGN KEY ("submissionId") REFERENCES "submission" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_5befa92da2370b7eb1cab6ae30a" FOREIGN KEY ("fieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('CREATE TABLE "form_visitor" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "referrer" varchar, "ipAddr" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "formId" integer, "geoLocationCountry" varchar, "geoLocationCity" varchar, "deviceLanguage" varchar, "deviceType" varchar, "deviceName" varchar, CONSTRAINT "FK_72ade6c3a3e55d1fce94300f8b6" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('CREATE TABLE "submission" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "ipAddr" varchar NOT NULL, "tokenHash" varchar NOT NULL, "timeElapsed" numeric NOT NULL, "percentageComplete" numeric NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "lastModified" datetime NOT NULL DEFAULT (datetime(\'now\')), "formId" integer, "visitorId" integer, "userId" integer, "geoLocationCountry" varchar, "geoLocationCity" varchar, "deviceLanguage" varchar, "deviceType" varchar, "deviceName" varchar, CONSTRAINT "FK_6090e1d5cbf3433ffd14e3b53e7" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_95b73c7faf2c199f005fda5e8c8" FOREIGN KEY ("visitorId") REFERENCES "form_visitor" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_7bd626272858ef6464aa2579094" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + + await queryRunner.query('CREATE TABLE "form" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "language" varchar(10) NOT NULL, "showFooter" boolean NOT NULL, "isLive" boolean NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "lastModified" datetime NOT NULL DEFAULT (datetime(\'now\')), "adminId" integer, "startPageId" integer, "endPageId" integer, "analyticsGacode" varchar, "designFont" varchar, "designColorsBackground" varchar, "designColorsQuestion" varchar, "designColorsAnswer" varchar, "designColorsButton" varchar, "designColorsButtonactive" varchar, "designColorsButtontext" varchar, CONSTRAINT "FK_a7cb33580bca2b362e5e34fdfcd" FOREIGN KEY ("adminId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_023d9cf1d97e93facc96c86ca70" FOREIGN KEY ("startPageId") REFERENCES "page" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_e5d158932e43cfbf9958931ee01" FOREIGN KEY ("endPageId") REFERENCES "page" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + } + + public async realDown(queryRunner: QueryRunner): Promise { + await queryRunner.query('DROP TABLE "form"'); + await queryRunner.query('DROP TABLE "submission"'); + await queryRunner.query('DROP TABLE "form_visitor"'); + await queryRunner.query('DROP TABLE "user"'); + await queryRunner.query('DROP TABLE "submission_field"'); + await queryRunner.query('DROP TABLE "page"'); + await queryRunner.query('DROP TABLE "page_button"'); + await queryRunner.query('DROP TABLE "form_notification"'); + await queryRunner.query('DROP TABLE "form_hook"'); + await queryRunner.query('DROP TABLE "form_field"'); + await queryRunner.query('DROP TABLE "form_field_option"'); + await queryRunner.query('DROP TABLE "form_field_logic"'); + } +} diff --git a/api/src/migrations/sqlite/1621078163528-layout.ts b/api/src/migrations/sqlite/1621078163528-layout.ts new file mode 100644 index 00000000..8faf88bd --- /dev/null +++ b/api/src/migrations/sqlite/1621078163528-layout.ts @@ -0,0 +1,20 @@ +import { QueryRunner } from 'typeorm' +import { SqliteMigration } from '../sqlite.migration' + +export class layout1621078163528 extends SqliteMigration { + name = 'layout1621078163528' + + public async realUp(queryRunner: QueryRunner): Promise { + await queryRunner.query('CREATE TABLE "temporary_form" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "language" varchar(10) NOT NULL, "showFooter" boolean NOT NULL, "isLive" boolean NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "lastModified" datetime NOT NULL DEFAULT (datetime(\'now\')), "adminId" integer, "startPageId" integer, "endPageId" integer, "analyticsGacode" varchar, "designFont" varchar, "designColorsBackground" varchar, "designColorsQuestion" varchar, "designColorsAnswer" varchar, "designColorsButton" varchar, "designColorsButtonactive" varchar, "designColorsButtontext" varchar, "designLayout" varchar, CONSTRAINT "FK_e5d158932e43cfbf9958931ee01" FOREIGN KEY ("endPageId") REFERENCES "page" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_023d9cf1d97e93facc96c86ca70" FOREIGN KEY ("startPageId") REFERENCES "page" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_a7cb33580bca2b362e5e34fdfcd" FOREIGN KEY ("adminId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "temporary_form"("id", "title", "language", "showFooter", "isLive", "created", "lastModified", "adminId", "startPageId", "endPageId", "analyticsGacode", "designFont", "designColorsBackground", "designColorsQuestion", "designColorsAnswer", "designColorsButton", "designColorsButtonactive", "designColorsButtontext") SELECT "id", "title", "language", "showFooter", "isLive", "created", "lastModified", "adminId", "startPageId", "endPageId", "analyticsGacode", "designFont", "designColorsBackground", "designColorsQuestion", "designColorsAnswer", "designColorsButton", "designColorsButtonactive", "designColorsButtontext" FROM "form"'); + await queryRunner.query('DROP TABLE "form"'); + await queryRunner.query('ALTER TABLE "temporary_form" RENAME TO "form"'); + } + + public async realDown(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form" RENAME TO "temporary_form"'); + await queryRunner.query('CREATE TABLE "form" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "language" varchar(10) NOT NULL, "showFooter" boolean NOT NULL, "isLive" boolean NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "lastModified" datetime NOT NULL DEFAULT (datetime(\'now\')), "adminId" integer, "startPageId" integer, "endPageId" integer, "analyticsGacode" varchar, "designFont" varchar, "designColorsBackground" varchar, "designColorsQuestion" varchar, "designColorsAnswer" varchar, "designColorsButton" varchar, "designColorsButtonactive" varchar, "designColorsButtontext" varchar, CONSTRAINT "FK_e5d158932e43cfbf9958931ee01" FOREIGN KEY ("endPageId") REFERENCES "page" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_023d9cf1d97e93facc96c86ca70" FOREIGN KEY ("startPageId") REFERENCES "page" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_a7cb33580bca2b362e5e34fdfcd" FOREIGN KEY ("adminId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "form"("id", "title", "language", "showFooter", "isLive", "created", "lastModified", "adminId", "startPageId", "endPageId", "analyticsGacode", "designFont", "designColorsBackground", "designColorsQuestion", "designColorsAnswer", "designColorsButton", "designColorsButtonactive", "designColorsButtontext") SELECT "id", "title", "language", "showFooter", "isLive", "created", "lastModified", "adminId", "startPageId", "endPageId", "analyticsGacode", "designFont", "designColorsBackground", "designColorsQuestion", "designColorsAnswer", "designColorsButton", "designColorsButtonactive", "designColorsButtontext" FROM "temporary_form"'); + await queryRunner.query('DROP TABLE "temporary_form"'); + } +} diff --git a/api/src/migrations/sqlite/1641124349039-submission.ts b/api/src/migrations/sqlite/1641124349039-submission.ts new file mode 100644 index 00000000..032f03ba --- /dev/null +++ b/api/src/migrations/sqlite/1641124349039-submission.ts @@ -0,0 +1,20 @@ +import { QueryRunner } from 'typeorm' +import { SqliteMigration } from '../sqlite.migration' + +export class submission1641124349039 extends SqliteMigration { + name = 'submission1641124349039' + + public async realUp(queryRunner: QueryRunner): Promise { + await queryRunner.query('CREATE TABLE "temporary_submission_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "submissionId" integer, "fieldId" integer, "type" varchar NOT NULL, "content" text NOT NULL, CONSTRAINT "FK_5befa92da2370b7eb1cab6ae30a" FOREIGN KEY ("fieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_16fae661ce5b10f27abe2e524a0" FOREIGN KEY ("submissionId") REFERENCES "submission" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "temporary_submission_field"("id", "submissionId", "type", "content", "fieldId") SELECT "id", "submissionId", "fieldType", "fieldValue", "fieldId" FROM "submission_field"'); + await queryRunner.query('DROP TABLE "submission_field"'); + await queryRunner.query('ALTER TABLE "temporary_submission_field" RENAME TO "submission_field"'); + } + + public async realDown(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "submission_field" RENAME TO "temporary_submission_field"'); + await queryRunner.query('CREATE TABLE "submission_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "fieldType" varchar NOT NULL, "fieldValue" varchar NOT NULL, "submissionId" integer, "fieldId" integer, CONSTRAINT "FK_5befa92da2370b7eb1cab6ae30a" FOREIGN KEY ("fieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_16fae661ce5b10f27abe2e524a0" FOREIGN KEY ("submissionId") REFERENCES "submission" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "submission_field"("id", "submissionId", "fieldType", "fieldValue", "fieldId") SELECT "id", "submissionId", "type", "content", "fieldId" FROM "temporary_submission_field"'); + await queryRunner.query('DROP TABLE "temporary_submission_field"'); + } +} diff --git a/api/src/migrations/sqlite/1641132645227-confirm.ts b/api/src/migrations/sqlite/1641132645227-confirm.ts new file mode 100644 index 00000000..0bfbd44a --- /dev/null +++ b/api/src/migrations/sqlite/1641132645227-confirm.ts @@ -0,0 +1,20 @@ +import { QueryRunner } from 'typeorm' +import { SqliteMigration } from '../sqlite.migration' + +export class confirm1641132645227 extends SqliteMigration { + name = 'confirm1641132645227' + + public async realUp(queryRunner: QueryRunner): Promise { + await queryRunner.query('CREATE TABLE "temporary_user" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "firstName" varchar, "lastName" varchar, "email" varchar(255) NOT NULL, "username" varchar(255) NOT NULL, "passwordHash" varchar NOT NULL, "salt" varchar, "provider" varchar NOT NULL, "roles" text NOT NULL, "language" varchar NOT NULL, "resetPasswordToken" varchar, "resetPasswordExpires" datetime, "token" varchar, "apiKey" varchar, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "lastModified" datetime NOT NULL DEFAULT (datetime(\'now\')), "emailVerified" boolean NOT NULL DEFAULT (0), CONSTRAINT "UQ_78a916df40e02a9deb1c4b75edb" UNIQUE ("username"), CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"))'); + await queryRunner.query('INSERT INTO "temporary_user"("id", "firstName", "lastName", "email", "username", "passwordHash", "salt", "provider", "roles", "language", "resetPasswordToken", "resetPasswordExpires", "token", "apiKey", "created", "lastModified") SELECT "id", "firstName", "lastName", "email", "username", "passwordHash", "salt", "provider", "roles", "language", "resetPasswordToken", "resetPasswordExpires", "token", "apiKey", "created", "lastModified" FROM "user"'); + await queryRunner.query('DROP TABLE "user"'); + await queryRunner.query('ALTER TABLE "temporary_user" RENAME TO "user"'); + } + + public async realDown(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "user" RENAME TO "temporary_user"'); + await queryRunner.query('CREATE TABLE "user" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "firstName" varchar, "lastName" varchar, "email" varchar(255) NOT NULL, "username" varchar(255) NOT NULL, "passwordHash" varchar NOT NULL, "salt" varchar, "provider" varchar NOT NULL, "roles" text NOT NULL, "language" varchar NOT NULL, "resetPasswordToken" varchar, "resetPasswordExpires" datetime, "token" varchar, "apiKey" varchar, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "lastModified" datetime NOT NULL DEFAULT (datetime(\'now\')), CONSTRAINT "UQ_78a916df40e02a9deb1c4b75edb" UNIQUE ("username"), CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"))'); + await queryRunner.query('INSERT INTO "user"("id", "firstName", "lastName", "email", "username", "passwordHash", "salt", "provider", "roles", "language", "resetPasswordToken", "resetPasswordExpires", "token", "apiKey", "created", "lastModified") SELECT "id", "firstName", "lastName", "email", "username", "passwordHash", "salt", "provider", "roles", "language", "resetPasswordToken", "resetPasswordExpires", "token", "apiKey", "created", "lastModified" FROM "temporary_user"'); + await queryRunner.query('DROP TABLE "temporary_user"'); + } +} diff --git a/api/src/migrations/sqlite/1641151802308-idx.ts b/api/src/migrations/sqlite/1641151802308-idx.ts new file mode 100644 index 00000000..18d9d6f9 --- /dev/null +++ b/api/src/migrations/sqlite/1641151802308-idx.ts @@ -0,0 +1,28 @@ +import { QueryRunner } from 'typeorm' +import { SqliteMigration } from '../sqlite.migration' + +export class idx1641151802308 extends SqliteMigration { + name = 'idx1641151802308' + + public async realUp(queryRunner: QueryRunner): Promise { + await queryRunner.query('CREATE TABLE "temporary_form_field_logic" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "formula" varchar NOT NULL, "action" varchar(10) NOT NULL, "visible" boolean, "require" boolean, "disable" boolean, "enabled" boolean NOT NULL, "fieldId" integer, "jumpToId" integer, "idx" integer, CONSTRAINT "FK_4a8019f2b753cfb3216dc3001a6" FOREIGN KEY ("jumpToId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_6098b83f6759445d8cfdd03d545" FOREIGN KEY ("fieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "temporary_form_field_logic"("id", "formula", "action", "visible", "require", "disable", "enabled", "fieldId", "jumpToId") SELECT "id", "formula", "action", "visible", "require", "disable", "enabled", "fieldId", "jumpToId" FROM "form_field_logic"'); + await queryRunner.query('DROP TABLE "form_field_logic"'); + await queryRunner.query('ALTER TABLE "temporary_form_field_logic" RENAME TO "form_field_logic"'); + await queryRunner.query('CREATE TABLE "temporary_form_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "description" text NOT NULL, "slug" varchar, "required" boolean NOT NULL, "disabled" boolean NOT NULL, "type" varchar NOT NULL, "value" varchar NOT NULL, "formId" integer, "ratingSteps" integer, "ratingShape" varchar, "idx" integer, CONSTRAINT "FK_2d83d8a334dd66445db13f92b77" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "temporary_form_field"("id", "title", "description", "slug", "required", "disabled", "type", "value", "formId", "ratingSteps", "ratingShape") SELECT "id", "title", "description", "slug", "required", "disabled", "type", "value", "formId", "ratingSteps", "ratingShape" FROM "form_field"'); + await queryRunner.query('DROP TABLE "form_field"'); + await queryRunner.query('ALTER TABLE "temporary_form_field" RENAME TO "form_field"'); + } + + public async realDown(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form_field" RENAME TO "temporary_form_field"'); + await queryRunner.query('CREATE TABLE "form_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "description" text NOT NULL, "slug" varchar, "required" boolean NOT NULL, "disabled" boolean NOT NULL, "type" varchar NOT NULL, "value" varchar NOT NULL, "formId" integer, "ratingSteps" integer, "ratingShape" varchar, CONSTRAINT "FK_2d83d8a334dd66445db13f92b77" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "form_field"("id", "title", "description", "slug", "required", "disabled", "type", "value", "formId", "ratingSteps", "ratingShape") SELECT "id", "title", "description", "slug", "required", "disabled", "type", "value", "formId", "ratingSteps", "ratingShape" FROM "temporary_form_field"'); + await queryRunner.query('DROP TABLE "temporary_form_field"'); + await queryRunner.query('ALTER TABLE "form_field_logic" RENAME TO "temporary_form_field_logic"'); + await queryRunner.query('CREATE TABLE "form_field_logic" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "formula" varchar NOT NULL, "action" varchar(10) NOT NULL, "visible" boolean, "require" boolean, "disable" boolean, "enabled" boolean NOT NULL, "fieldId" integer, "jumpToId" integer, CONSTRAINT "FK_4a8019f2b753cfb3216dc3001a6" FOREIGN KEY ("jumpToId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_6098b83f6759445d8cfdd03d545" FOREIGN KEY ("fieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "form_field_logic"("id", "formula", "action", "visible", "require", "disable", "enabled", "fieldId", "jumpToId") SELECT "id", "formula", "action", "visible", "require", "disable", "enabled", "fieldId", "jumpToId" FROM "temporary_form_field_logic"'); + await queryRunner.query('DROP TABLE "temporary_form_field_logic"'); + } +} diff --git a/api/src/migrations/sqlite/1641193946192-anonymous.ts b/api/src/migrations/sqlite/1641193946192-anonymous.ts new file mode 100644 index 00000000..838595c4 --- /dev/null +++ b/api/src/migrations/sqlite/1641193946192-anonymous.ts @@ -0,0 +1,20 @@ +import { QueryRunner } from 'typeorm' +import { SqliteMigration } from '../sqlite.migration' + +export class anonymous1641193946192 extends SqliteMigration { + name = 'anonymous1641193946192' + + public async realUp(queryRunner: QueryRunner): Promise { + await queryRunner.query('CREATE TABLE "temporary_form" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "language" varchar(10) NOT NULL, "showFooter" boolean NOT NULL, "isLive" boolean NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "lastModified" datetime NOT NULL DEFAULT (datetime(\'now\')), "adminId" integer, "startPageId" integer, "endPageId" integer, "analyticsGacode" varchar, "designFont" varchar, "designColorsBackground" varchar, "designColorsQuestion" varchar, "designColorsAnswer" varchar, "designColorsButton" varchar, "designColorsButtonactive" varchar, "designColorsButtontext" varchar, "designLayout" varchar, "anonymousSubmission" boolean NOT NULL DEFAULT (0), CONSTRAINT "FK_a7cb33580bca2b362e5e34fdfcd" FOREIGN KEY ("adminId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_023d9cf1d97e93facc96c86ca70" FOREIGN KEY ("startPageId") REFERENCES "page" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_e5d158932e43cfbf9958931ee01" FOREIGN KEY ("endPageId") REFERENCES "page" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "temporary_form"("id", "title", "language", "showFooter", "isLive", "created", "lastModified", "adminId", "startPageId", "endPageId", "analyticsGacode", "designFont", "designColorsBackground", "designColorsQuestion", "designColorsAnswer", "designColorsButton", "designColorsButtonactive", "designColorsButtontext", "designLayout") SELECT "id", "title", "language", "showFooter", "isLive", "created", "lastModified", "adminId", "startPageId", "endPageId", "analyticsGacode", "designFont", "designColorsBackground", "designColorsQuestion", "designColorsAnswer", "designColorsButton", "designColorsButtonactive", "designColorsButtontext", "designLayout" FROM "form"'); + await queryRunner.query('DROP TABLE "form"'); + await queryRunner.query('ALTER TABLE "temporary_form" RENAME TO "form"'); + } + + public async realDown(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form" RENAME TO "temporary_form"'); + await queryRunner.query('CREATE TABLE "form" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "language" varchar(10) NOT NULL, "showFooter" boolean NOT NULL, "isLive" boolean NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "lastModified" datetime NOT NULL DEFAULT (datetime(\'now\')), "adminId" integer, "startPageId" integer, "endPageId" integer, "analyticsGacode" varchar, "designFont" varchar, "designColorsBackground" varchar, "designColorsQuestion" varchar, "designColorsAnswer" varchar, "designColorsButton" varchar, "designColorsButtonactive" varchar, "designColorsButtontext" varchar, "designLayout" varchar, CONSTRAINT "FK_a7cb33580bca2b362e5e34fdfcd" FOREIGN KEY ("adminId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_023d9cf1d97e93facc96c86ca70" FOREIGN KEY ("startPageId") REFERENCES "page" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_e5d158932e43cfbf9958931ee01" FOREIGN KEY ("endPageId") REFERENCES "page" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "form"("id", "title", "language", "showFooter", "isLive", "created", "lastModified", "adminId", "startPageId", "endPageId", "analyticsGacode", "designFont", "designColorsBackground", "designColorsQuestion", "designColorsAnswer", "designColorsButton", "designColorsButtonactive", "designColorsButtontext", "designLayout") SELECT "id", "title", "language", "showFooter", "isLive", "created", "lastModified", "adminId", "startPageId", "endPageId", "analyticsGacode", "designFont", "designColorsBackground", "designColorsQuestion", "designColorsAnswer", "designColorsButton", "designColorsButtonactive", "designColorsButtontext", "designLayout" FROM "temporary_form"'); + await queryRunner.query('DROP TABLE "temporary_form"'); + } +} diff --git a/api/src/migrations/sqlite/1645952169100-defaultValue.ts b/api/src/migrations/sqlite/1645952169100-defaultValue.ts new file mode 100644 index 00000000..bea5979d --- /dev/null +++ b/api/src/migrations/sqlite/1645952169100-defaultValue.ts @@ -0,0 +1,14 @@ +import { QueryRunner } from 'typeorm' +import { SqliteMigration } from '../sqlite.migration' + +export class defaultValue1645952169100 extends SqliteMigration { + name = 'defaultValue1645952169100' + + public async realUp(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form_field" RENAME COLUMN "value" TO "defaultValue"'); + } + + public async realDown(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form_field" RENAME COLUMN "defaultValue" TO "value"'); + } +} diff --git a/api/src/migrations/sqlite/1645956388810-defaultValue.ts b/api/src/migrations/sqlite/1645956388810-defaultValue.ts new file mode 100644 index 00000000..4bfdd614 --- /dev/null +++ b/api/src/migrations/sqlite/1645956388810-defaultValue.ts @@ -0,0 +1,30 @@ +import { QueryRunner } from 'typeorm' +import { SqliteMigration } from '../sqlite.migration' + +export class defaultValue1645956388810 extends SqliteMigration { + name = 'defaultValue1645956388810' + + public async realUp(queryRunner: QueryRunner): Promise { + await queryRunner.query('CREATE TABLE "temporary_form_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "description" text NOT NULL, "slug" varchar, "required" boolean NOT NULL, "disabled" boolean NOT NULL, "type" varchar NOT NULL, "defaultValue" varchar NOT NULL, "formId" integer, "ratingSteps" integer, "ratingShape" varchar, "idx" integer, CONSTRAINT "FK_2d83d8a334dd66445db13f92b77" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "temporary_form_field"("id", "title", "description", "slug", "required", "disabled", "type", "defaultValue", "formId", "ratingSteps", "ratingShape", "idx") SELECT "id", "title", "description", "slug", "required", "disabled", "type", "defaultValue", "formId", "ratingSteps", "ratingShape", "idx" FROM "form_field"'); + await queryRunner.query('DROP TABLE "form_field"'); + await queryRunner.query('ALTER TABLE "temporary_form_field" RENAME TO "form_field"'); + await queryRunner.query('CREATE TABLE "temporary_form_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "description" text NOT NULL, "slug" varchar, "required" boolean NOT NULL, "disabled" boolean NOT NULL, "type" varchar NOT NULL, "defaultValue" varchar, "formId" integer, "ratingSteps" integer, "ratingShape" varchar, "idx" integer, CONSTRAINT "FK_2d83d8a334dd66445db13f92b77" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "temporary_form_field"("id", "title", "description", "slug", "required", "disabled", "type", "defaultValue", "formId", "ratingSteps", "ratingShape", "idx") SELECT "id", "title", "description", "slug", "required", "disabled", "type", "defaultValue", "formId", "ratingSteps", "ratingShape", "idx" FROM "form_field"'); + await queryRunner.query('DROP TABLE "form_field"'); + await queryRunner.query('ALTER TABLE "temporary_form_field" RENAME TO "form_field"'); + } + + public async realDown(queryRunner: QueryRunner): Promise { + await queryRunner.query('UPDATE "form_field" SET "defaultValue" = \'\' WHERE "defaultValue" IS NULL'); + + await queryRunner.query('ALTER TABLE "form_field" RENAME TO "temporary_form_field"'); + await queryRunner.query('CREATE TABLE "form_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "description" text NOT NULL, "slug" varchar, "required" boolean NOT NULL, "disabled" boolean NOT NULL, "type" varchar NOT NULL, "defaultValue" varchar NOT NULL, "formId" integer, "ratingSteps" integer, "ratingShape" varchar, "idx" integer, CONSTRAINT "FK_2d83d8a334dd66445db13f92b77" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "form_field"("id", "title", "description", "slug", "required", "disabled", "type", "defaultValue", "formId", "ratingSteps", "ratingShape", "idx") SELECT "id", "title", "description", "slug", "required", "disabled", "type", "defaultValue", "formId", "ratingSteps", "ratingShape", "idx" FROM "temporary_form_field"'); + await queryRunner.query('DROP TABLE "temporary_form_field"'); + await queryRunner.query('ALTER TABLE "form_field" RENAME TO "temporary_form_field"'); + await queryRunner.query('CREATE TABLE "form_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "description" text NOT NULL, "slug" varchar, "required" boolean NOT NULL, "disabled" boolean NOT NULL, "type" varchar NOT NULL, "defaultValue" varchar NOT NULL, "formId" integer, "ratingSteps" integer, "ratingShape" varchar, "idx" integer, CONSTRAINT "FK_2d83d8a334dd66445db13f92b77" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "form_field"("id", "title", "description", "slug", "required", "disabled", "type", "defaultValue", "formId", "ratingSteps", "ratingShape", "idx") SELECT "id", "title", "description", "slug", "required", "disabled", "type", "defaultValue", "formId", "ratingSteps", "ratingShape", "idx" FROM "temporary_form_field"'); + await queryRunner.query('DROP TABLE "temporary_form_field"'); + } +} diff --git a/api/src/pipe/form/form.by.id.pipe.ts b/api/src/pipe/form/form.by.id.pipe.ts new file mode 100644 index 00000000..e7304273 --- /dev/null +++ b/api/src/pipe/form/form.by.id.pipe.ts @@ -0,0 +1,19 @@ +import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common' +import { FormEntity } from '../../entity/form.entity' +import { FormService } from '../../service/form/form.service' +import { IdService } from '../../service/id.service' + +@Injectable() +export class FormByIdPipe implements PipeTransform> { + constructor( + private readonly formService: FormService, + private readonly idService: IdService, + ) { + } + + async transform(value: string, metadata: ArgumentMetadata): Promise { + const id = this.idService.decode(value) + + return await this.formService.findById(id) + } +} diff --git a/api/src/pipe/form/index.ts b/api/src/pipe/form/index.ts new file mode 100644 index 00000000..2d90edb5 --- /dev/null +++ b/api/src/pipe/form/index.ts @@ -0,0 +1,3 @@ +import { FormByIdPipe } from './form.by.id.pipe' + +export const formPipes = [FormByIdPipe] diff --git a/api/src/pipe/index.ts b/api/src/pipe/index.ts new file mode 100644 index 00000000..ceeb99a5 --- /dev/null +++ b/api/src/pipe/index.ts @@ -0,0 +1,9 @@ +import { formPipes } from './form' +import { submissionPipes } from './submission' +import { userPipes } from './user' + +export const pipes = [ + ...formPipes, + ...submissionPipes, + ...userPipes, +] diff --git a/api/src/pipe/submission/index.ts b/api/src/pipe/submission/index.ts new file mode 100644 index 00000000..71f93507 --- /dev/null +++ b/api/src/pipe/submission/index.ts @@ -0,0 +1,3 @@ +import { SubmissionByIdPipe } from './submission.by.id.pipe' + +export const submissionPipes = [SubmissionByIdPipe] diff --git a/api/src/pipe/submission/submission.by.id.pipe.ts b/api/src/pipe/submission/submission.by.id.pipe.ts new file mode 100644 index 00000000..db6a7dfd --- /dev/null +++ b/api/src/pipe/submission/submission.by.id.pipe.ts @@ -0,0 +1,19 @@ +import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common' +import { SubmissionEntity } from '../../entity/submission.entity' +import { IdService } from '../../service/id.service' +import { SubmissionService } from '../../service/submission/submission.service' + +@Injectable() +export class SubmissionByIdPipe implements PipeTransform> { + constructor( + private readonly submissionService: SubmissionService, + private readonly idService: IdService, + ) { + } + + async transform(value: string, metadata: ArgumentMetadata): Promise { + const id = this.idService.decode(value) + + return await this.submissionService.findById(id) + } +} diff --git a/api/src/pipe/user/index.ts b/api/src/pipe/user/index.ts new file mode 100644 index 00000000..425d7b25 --- /dev/null +++ b/api/src/pipe/user/index.ts @@ -0,0 +1,3 @@ +import { UserByIdPipe } from './user.by.id.pipe' + +export const userPipes = [UserByIdPipe] diff --git a/api/src/pipe/user/user.by.id.pipe.ts b/api/src/pipe/user/user.by.id.pipe.ts new file mode 100644 index 00000000..ef3d6244 --- /dev/null +++ b/api/src/pipe/user/user.by.id.pipe.ts @@ -0,0 +1,19 @@ +import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common' +import { UserEntity } from '../../entity/user.entity' +import { IdService } from '../../service/id.service' +import { UserService } from '../../service/user/user.service' + +@Injectable() +export class UserByIdPipe implements PipeTransform> { + constructor( + private readonly userService: UserService, + private readonly idService: IdService, + ) { + } + + async transform(value: string, metadata: ArgumentMetadata): Promise { + const id = this.idService.decode(value) + + return await this.userService.findById(id) + } +} diff --git a/api/src/resolver/auth/auth.login.mutation.ts b/api/src/resolver/auth/auth.login.mutation.ts new file mode 100644 index 00000000..46108b43 --- /dev/null +++ b/api/src/resolver/auth/auth.login.mutation.ts @@ -0,0 +1,26 @@ +import { Injectable } from '@nestjs/common' +import { Args, Mutation } from '@nestjs/graphql' +import { AuthJwtModel } from '../../dto/auth/auth.jwt.model' +import { AuthService } from '../../service/auth/auth.service' + +@Injectable() +export class AuthLoginMutation { + constructor( + private readonly auth: AuthService + ) { + } + + @Mutation(() => AuthJwtModel) + async authLogin( + @Args({ name: 'username', type: () => String }) username: string, + @Args({ name: 'password', type: () => String }) password: string, + ): Promise { + const user = await this.auth.validateUser(username, password) + + if (!user) { + throw new Error('invalid user / password') + } + + return this.auth.login(user) + } +} diff --git a/api/src/resolver/auth/auth.register.mutation.ts b/api/src/resolver/auth/auth.register.mutation.ts new file mode 100644 index 00000000..dcbf59df --- /dev/null +++ b/api/src/resolver/auth/auth.register.mutation.ts @@ -0,0 +1,37 @@ +import { Injectable } from '@nestjs/common' +import { Args, Mutation } from '@nestjs/graphql' +import { PinoLogger } from 'nestjs-pino' +import { AuthJwtModel } from '../../dto/auth/auth.jwt.model' +import { UserCreateInput } from '../../dto/user/user.create.input' +import { AuthService } from '../../service/auth/auth.service' +import { SettingService } from '../../service/setting.service' +import { UserCreateService } from '../../service/user/user.create.service' + +@Injectable() +export class AuthRegisterMutation { + constructor( + private readonly createUser: UserCreateService, + private readonly settingService: SettingService, + private readonly auth: AuthService, + private readonly logger: PinoLogger, + ) { + logger.setContext(this.constructor.name) + } + + @Mutation(() => AuthJwtModel) + async authRegister( + @Args({ name: 'user' }) data: UserCreateInput, + ): Promise { + if (this.settingService.isTrue('SIGNUP_DISABLED')) { + throw new Error('signup disabled') + } + + this.logger.info({ + email: data.email, + username: data.username, + }, 'try to register new user') + const user = await this.createUser.create(data) + + return this.auth.login(user) + } +} diff --git a/api/src/resolver/auth/index.ts b/api/src/resolver/auth/index.ts new file mode 100644 index 00000000..0d83ae9f --- /dev/null +++ b/api/src/resolver/auth/index.ts @@ -0,0 +1,7 @@ +import { AuthLoginMutation } from './auth.login.mutation' +import { AuthRegisterMutation } from './auth.register.mutation' + +export const authServices = [ + AuthRegisterMutation, + AuthLoginMutation, +] diff --git a/api/src/resolver/context.cache.ts b/api/src/resolver/context.cache.ts new file mode 100644 index 00000000..2a05b99d --- /dev/null +++ b/api/src/resolver/context.cache.ts @@ -0,0 +1,27 @@ + +export class ContextCache { + private cache: { + [key: string]: any + } = {} + + public getCacheKey(type: string, id: number): string { + return `${type}:${id}` + } + + public add(key: string, element: B): void { + this.cache[key] = element + } + + public get(key: string, init?: () => Promise): B | Promise { + if (!this.cache[key] && init) { + const result = init() + void result.then(r => { + this.cache[key] = r + }) + + return result + } + + return this.cache[key] + } +} diff --git a/api/src/resolver/form/form.create.mutation.ts b/api/src/resolver/form/form.create.mutation.ts new file mode 100644 index 00000000..791bd43c --- /dev/null +++ b/api/src/resolver/form/form.create.mutation.ts @@ -0,0 +1,34 @@ +import { Injectable } from '@nestjs/common' +import { Args, Context, Mutation } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { FormCreateInput } from '../../dto/form/form.create.input' +import { FormModel } from '../../dto/form/form.model' +import { FormEntity } from '../../entity/form.entity' +import { UserEntity } from '../../entity/user.entity' +import { FormCreateService } from '../../service/form/form.create.service' +import { IdService } from '../../service/id.service' +import { ContextCache } from '../context.cache' + +@Injectable() +export class FormCreateMutation { + constructor( + private readonly createService: FormCreateService, + private readonly idService: IdService, + ) { + } + + @Mutation(() => FormModel) + @Roles('admin') + async createForm( + @User() user: UserEntity, + @Args({ name: 'form', type: () => FormCreateInput }) input: FormCreateInput, + @Context('cache') cache: ContextCache, + ): Promise { + const form = await this.createService.create(user, input) + + cache.add(cache.getCacheKey(FormEntity.name, form.id), form) + + return new FormModel(this.idService.encode(form.id), form) + } +} diff --git a/api/src/resolver/form/form.delete.mutation.ts b/api/src/resolver/form/form.delete.mutation.ts new file mode 100644 index 00000000..223436cc --- /dev/null +++ b/api/src/resolver/form/form.delete.mutation.ts @@ -0,0 +1,36 @@ +import { Injectable } from '@nestjs/common' +import { Args, ID, Mutation } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { DeletedModel } from '../../dto/deleted.model' +import { FormEntity } from '../../entity/form.entity' +import { UserEntity } from '../../entity/user.entity' +import { FormByIdPipe } from '../../pipe/form/form.by.id.pipe' +import { FormDeleteService } from '../../service/form/form.delete.service' +import { FormService } from '../../service/form/form.service' +import { IdService } from '../../service/id.service' + +@Injectable() +export class FormDeleteMutation { + constructor( + private readonly deleteService: FormDeleteService, + private readonly formService: FormService, + private readonly idService: IdService, + ) { + } + + @Mutation(() => DeletedModel) + @Roles('admin') + async deleteForm( + @User() user: UserEntity, + @Args('id', {type: () => ID}, FormByIdPipe) form: FormEntity, + ): Promise { + if (!form.isLive && !this.formService.isAdmin(form, user)) { + throw new Error('invalid form') + } + + await this.deleteService.delete(form.id) + + return new DeletedModel(this.idService.encode(form.id)) + } +} diff --git a/api/src/resolver/form/form.field.resolver.ts b/api/src/resolver/form/form.field.resolver.ts new file mode 100644 index 00000000..369d6fc4 --- /dev/null +++ b/api/src/resolver/form/form.field.resolver.ts @@ -0,0 +1,73 @@ +import { Context, Parent, ResolveField, Resolver } from '@nestjs/graphql' +import { FormFieldLogicModel } from '../../dto/form/form.field.logic.model' +import { FormFieldModel } from '../../dto/form/form.field.model' +import { FormFieldOptionModel } from '../../dto/form/form.field.option.model' +import { FormFieldRatingModel } from '../../dto/form/form.field.rating.model' +import { FormFieldEntity } from '../../entity/form.field.entity' +import { IdService } from '../../service/id.service' +import { ContextCache } from '../context.cache' + +@Resolver(FormFieldModel) +export class FormFieldResolver { + constructor( + private readonly idService: IdService, + ) { + } + + @ResolveField(() => [FormFieldOptionModel]) + async options( + @Parent() parent: FormFieldModel, + @Context('cache') cache: ContextCache, + ): Promise { + const field = await cache.get(cache.getCacheKey( + FormFieldEntity.name, + parent._id + )) + + if (!field.options) { + return [] + } + + return field.options.map(option => new FormFieldOptionModel( + this.idService.encode(option.id), + option, + )) + } + + @ResolveField(() => [FormFieldLogicModel]) + async logic( + @Parent() parent: FormFieldModel, + @Context('cache') cache: ContextCache, + ): Promise { + const field = await cache.get(cache.getCacheKey( + FormFieldEntity.name, + parent._id + )) + + if (!field.logic) { + return [] + } + + return field.logic.map(logic => new FormFieldLogicModel( + this.idService.encode(logic.id), + logic, + )) + } + + @ResolveField(() => FormFieldRatingModel, { nullable: true }) + async rating( + @Parent() parent: FormFieldModel, + @Context('cache') cache: ContextCache, + ): Promise { + const field = await cache.get(cache.getCacheKey( + FormFieldEntity.name, + parent._id + )) + + if (!field.rating) { + return null + } + + return new FormFieldRatingModel(field.rating) + } +} diff --git a/api/src/resolver/form/form.list.query.ts b/api/src/resolver/form/form.list.query.ts new file mode 100644 index 00000000..47ac096a --- /dev/null +++ b/api/src/resolver/form/form.list.query.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common' +import { Args, Context, Int, Query } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { FormModel } from '../../dto/form/form.model' +import { FormPagerModel } from '../../dto/form/form.pager.model' +import { FormEntity } from '../../entity/form.entity' +import { UserEntity } from '../../entity/user.entity' +import { FormService } from '../../service/form/form.service' +import { IdService } from '../../service/id.service' +import { ContextCache } from '../context.cache' + +@Injectable() +export class FormListQuery { + constructor( + private readonly formService: FormService, + private readonly idService: IdService, + ) { + } + + @Query(() => FormPagerModel) + @Roles('user') + async listForms( + @User() user: UserEntity, + @Args('start', {type: () => Int, defaultValue: 0, nullable: true}) start: number, + @Args('limit', {type: () => Int, defaultValue: 50, nullable: true}) limit: number, + @Context('cache') cache: ContextCache, + ): Promise { + const [forms, total] = await this.formService.find( + start, + limit, + {}, + user.roles.includes('superuser') ? null : user, + ) + + forms.forEach(form => cache.add(cache.getCacheKey(FormEntity.name, form.id), form)) + + return new FormPagerModel( + forms.map(form => new FormModel(this.idService.encode(form.id), form)), + total, + limit, + start, + ) + } +} diff --git a/api/src/resolver/form/form.query.ts b/api/src/resolver/form/form.query.ts new file mode 100644 index 00000000..bb4a48dd --- /dev/null +++ b/api/src/resolver/form/form.query.ts @@ -0,0 +1,34 @@ +import { Injectable } from '@nestjs/common' +import { Args, Context, ID, Query } from '@nestjs/graphql' +import { User } from '../../decorator/user.decorator' +import { FormModel } from '../../dto/form/form.model' +import { FormEntity } from '../../entity/form.entity' +import { UserEntity } from '../../entity/user.entity' +import { FormByIdPipe } from '../../pipe/form/form.by.id.pipe' +import { FormService } from '../../service/form/form.service' +import { IdService } from '../../service/id.service' +import { ContextCache } from '../context.cache' + +@Injectable() +export class FormQuery { + constructor( + private readonly formService: FormService, + private readonly idService: IdService, + ) { + } + + @Query(() => FormModel) + getFormById( + @User() user: UserEntity, + @Args('id', {type: () => ID}, FormByIdPipe) form: FormEntity, + @Context('cache') cache: ContextCache, + ): FormModel { + if (!form.isLive && !this.formService.isAdmin(form, user)) { + throw new Error('invalid form') + } + + cache.add(cache.getCacheKey(FormEntity.name, form.id), form) + + return new FormModel(this.idService.encode(form.id), form) + } +} diff --git a/api/src/resolver/form/form.resolver.ts b/api/src/resolver/form/form.resolver.ts new file mode 100644 index 00000000..76b27861 --- /dev/null +++ b/api/src/resolver/form/form.resolver.ts @@ -0,0 +1,179 @@ +import { Context, Parent, ResolveField, Resolver } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { DesignModel } from '../../dto/form/design.model' +import { FormFieldModel } from '../../dto/form/form.field.model' +import { FormHookModel } from '../../dto/form/form.hook.model' +import { FormModel } from '../../dto/form/form.model' +import { FormNotificationModel } from '../../dto/form/form.notification.model' +import { PageModel } from '../../dto/form/page.model' +import { UserModel } from '../../dto/user/user.model' +import { FormEntity } from '../../entity/form.entity' +import { FormFieldEntity } from '../../entity/form.field.entity' +import { PageEntity } from '../../entity/page.entity' +import { UserEntity } from '../../entity/user.entity' +import { FormService } from '../../service/form/form.service' +import { IdService } from '../../service/id.service' +import { ContextCache } from '../context.cache' + +@Resolver(() => FormModel) +export class FormResolver { + constructor( + private readonly formService: FormService, + private readonly idService: IdService, + ) { + } + + @ResolveField(() => [FormFieldModel]) + async fields( + @User() user: UserEntity, + @Parent() parent: FormModel, + @Context('cache') cache: ContextCache, + ): Promise { + const form = await cache.get(cache.getCacheKey(FormEntity.name, parent._id)) + + if (!form.fields) { + return [] + } + + return form.fields + .sort((a,b) => a.idx - b.idx) + .map(field => { + cache.add(cache.getCacheKey(FormFieldEntity.name, field.id), field) + + return new FormFieldModel( + this.idService.encode(field.id), + field, + ) + }) + } + + @ResolveField(() => [FormHookModel]) + @Roles('admin') + async hooks( + @User() user: UserEntity, + @Parent() parent: FormModel, + @Context('cache') cache: ContextCache, + ): Promise { + const form = await cache.get(cache.getCacheKey(FormEntity.name, parent._id)) + + if (!this.formService.isAdmin(form, user)) { + throw new Error('no access to field') + } + + if (!form.hooks) { + return [] + } + + return form.hooks.map(hook => new FormHookModel( + this.idService.encode(hook.id), + hook + )) + } + + @ResolveField(() => Boolean) + @Roles('admin') + async isLive( + @User() user: UserEntity, + @Parent() parent: FormModel, + @Context('cache') cache: ContextCache, + ): Promise { + const form = await cache.get(cache.getCacheKey(FormEntity.name, parent._id)) + + if (!this.formService.isAdmin(form, user)) { + throw new Error('no access to field') + } + + return form.isLive + } + + @ResolveField(() => [FormNotificationModel]) + @Roles('admin') + async notifications( + @User() user: UserEntity, + @Parent() parent: FormModel, + @Context('cache') cache: ContextCache, + ): Promise { + const form = await cache.get(cache.getCacheKey(FormEntity.name, parent._id)) + + if (!this.formService.isAdmin(form, user)) { + throw new Error('no access to field') + } + + if (!form.notifications) { + return [] + } + + return form.notifications.map(notification => new FormNotificationModel( + this.idService.encode(notification.id), + notification + )) + } + + @ResolveField(() => DesignModel) + async design( + @User() user: UserEntity, + @Parent() parent: FormModel, + @Context('cache') cache: ContextCache, + ): Promise { + const form = await cache.get(cache.getCacheKey(FormEntity.name, parent._id)) + + return new DesignModel(form.design) + } + + @ResolveField(() => PageModel) + async startPage( + @Parent() parent: FormModel, + @Context('cache') cache: ContextCache, + ): Promise { + const { startPage } = await cache.get(cache.getCacheKey( + FormEntity.name, + parent._id + )) + + if (startPage) { + cache.add(cache.getCacheKey(PageEntity.name, startPage.id), startPage) + + return new PageModel( + this.idService.encode(startPage.id), + startPage + ) + } + + return new PageModel(Math.random().toString()) + } + + @ResolveField(() => PageModel) + async endPage( + @Parent() parent: FormModel, + @Context('cache') cache: ContextCache, + ): Promise { + const { endPage } = await cache.get(cache.getCacheKey(FormEntity.name, parent._id)) + + if (endPage) { + cache.add(cache.getCacheKey(PageEntity.name, endPage.id), endPage) + + return new PageModel( + this.idService.encode(endPage.id), + endPage + ) + } + + return new PageModel(Math.random().toString()) + } + + @ResolveField(() => UserModel, { nullable: true }) + @Roles('admin') + async admin( + @Parent() parent: FormModel, + @Context('cache') cache: ContextCache, + ): Promise { + const form = await cache.get(cache.getCacheKey(FormEntity.name, parent._id)) + + if (!form.admin) { + return null + } + + return new UserModel(this.idService.encode(form.admin.id), form.admin) + } +} diff --git a/api/src/resolver/form/form.statistic.query.ts b/api/src/resolver/form/form.statistic.query.ts new file mode 100644 index 00000000..1cdc9433 --- /dev/null +++ b/api/src/resolver/form/form.statistic.query.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common' +import { Query } from '@nestjs/graphql' +import { FormStatisticModel } from '../../dto/form/form.statistic.model' + +@Injectable() +export class FormStatisticQuery { + @Query(() => FormStatisticModel) + getFormStatistic(): FormStatisticModel { + return new FormStatisticModel() + } +} diff --git a/api/src/resolver/form/form.statistic.resolver.ts b/api/src/resolver/form/form.statistic.resolver.ts new file mode 100644 index 00000000..021a947d --- /dev/null +++ b/api/src/resolver/form/form.statistic.resolver.ts @@ -0,0 +1,18 @@ +import { Int, ResolveField, Resolver } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { FormStatisticModel } from '../../dto/form/form.statistic.model' +import { FormStatisticService } from '../../service/form/form.statistic.service' + +@Resolver(() => FormStatisticModel) +export class FormStatisticResolver { + constructor( + private readonly statisticService: FormStatisticService, + ) { + } + + @ResolveField(() => Int) + @Roles('admin') + total(): Promise { + return this.statisticService.getTotal() + } +} diff --git a/api/src/resolver/form/form.update.mutation.ts b/api/src/resolver/form/form.update.mutation.ts new file mode 100644 index 00000000..62485ed3 --- /dev/null +++ b/api/src/resolver/form/form.update.mutation.ts @@ -0,0 +1,42 @@ +import { Injectable } from '@nestjs/common' +import { Args, Context, Mutation } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { FormModel } from '../../dto/form/form.model' +import { FormUpdateInput } from '../../dto/form/form.update.input' +import { FormEntity } from '../../entity/form.entity' +import { UserEntity } from '../../entity/user.entity' +import { FormService } from '../../service/form/form.service' +import { FormUpdateService } from '../../service/form/form.update.service' +import { IdService } from '../../service/id.service' +import { ContextCache } from '../context.cache' + +@Injectable() +export class FormUpdateMutation { + constructor( + private readonly updateService: FormUpdateService, + private readonly formService: FormService, + private readonly idService: IdService, + ) { + } + + @Mutation(() => FormModel) + @Roles('admin') + async updateForm( + @User() user: UserEntity, + @Args({ name: 'form', type: () => FormUpdateInput }) input: FormUpdateInput, + @Context('cache') cache: ContextCache, + ): Promise { + const form = await this.formService.findById(this.idService.decode(input.id)) + + if (!form.isLive && !this.formService.isAdmin(form, user)) { + throw new Error('invalid form') + } + + await this.updateService.update(form, input) + + cache.add(cache.getCacheKey(FormEntity.name, form.id), form) + + return new FormModel(this.idService.encode(form.id), form) + } +} diff --git a/api/src/resolver/form/index.ts b/api/src/resolver/form/index.ts new file mode 100644 index 00000000..f8412928 --- /dev/null +++ b/api/src/resolver/form/index.ts @@ -0,0 +1,23 @@ +import { FormCreateMutation } from './form.create.mutation' +import { FormDeleteMutation } from './form.delete.mutation' +import { FormFieldResolver } from './form.field.resolver' +import { FormListQuery } from './form.list.query' +import { FormQuery } from './form.query' +import { FormResolver } from './form.resolver' +import { FormStatisticQuery } from './form.statistic.query' +import { FormStatisticResolver } from './form.statistic.resolver' +import { FormUpdateMutation } from './form.update.mutation' +import { PageResolver } from './page.resolver' + +export const formResolvers = [ + FormCreateMutation, + FormDeleteMutation, + FormFieldResolver, + FormQuery, + FormResolver, + FormListQuery, + FormStatisticQuery, + FormStatisticResolver, + FormUpdateMutation, + PageResolver, +] diff --git a/api/src/resolver/form/page.resolver.ts b/api/src/resolver/form/page.resolver.ts new file mode 100644 index 00000000..e1573288 --- /dev/null +++ b/api/src/resolver/form/page.resolver.ts @@ -0,0 +1,32 @@ +import { Context, Parent, ResolveField, Resolver } from '@nestjs/graphql' +import { ButtonModel } from '../../dto/form/button.model' +import { FormModel } from '../../dto/form/form.model' +import { PageModel } from '../../dto/form/page.model' +import { PageEntity } from '../../entity/page.entity' +import { IdService } from '../../service/id.service' +import { ContextCache } from '../context.cache' + +@Resolver(() => PageModel) +export class PageResolver { + constructor( + private readonly idService: IdService, + ) { + } + + @ResolveField(() => [ButtonModel]) + async buttons( + @Parent() parent: FormModel, + @Context('cache') cache: ContextCache, + ): Promise { + if (!parent._id) { + return [] + } + + const page = await cache.get(cache.getCacheKey(PageEntity.name, parent._id)) + + return page.buttons.map(button => new ButtonModel( + this.idService.encode(button.id), + button + )) + } +} diff --git a/api/src/resolver/index.ts b/api/src/resolver/index.ts new file mode 100644 index 00000000..e4c87b7a --- /dev/null +++ b/api/src/resolver/index.ts @@ -0,0 +1,17 @@ +import { authServices } from './auth' +import { formResolvers } from './form' +import { profileResolvers } from './profile' +import { settingsResolvers } from './setting' +import { StatusResolver } from './status.resolver' +import { submissionResolvers } from './submission' +import { userResolvers } from './user' + +export const resolvers = [ + StatusResolver, + ...userResolvers, + ...authServices, + ...profileResolvers, + ...formResolvers, + ...submissionResolvers, + ...settingsResolvers, +] diff --git a/api/src/resolver/profile/index.ts b/api/src/resolver/profile/index.ts new file mode 100644 index 00000000..409c6502 --- /dev/null +++ b/api/src/resolver/profile/index.ts @@ -0,0 +1,7 @@ +import { ProfileQuery } from './profile.query' +import { ProfileUpdateMutation } from './profile.update.mutation' + +export const profileResolvers = [ + ProfileQuery, + ProfileUpdateMutation, +] diff --git a/api/src/resolver/profile/profile.query.ts b/api/src/resolver/profile/profile.query.ts new file mode 100644 index 00000000..ce821255 --- /dev/null +++ b/api/src/resolver/profile/profile.query.ts @@ -0,0 +1,27 @@ +import { Injectable } from '@nestjs/common' +import { Context, Query } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { ProfileModel } from '../../dto/profile/profile.model' +import { UserEntity } from '../../entity/user.entity' +import { IdService } from '../../service/id.service' +import { ContextCache } from '../context.cache' + +@Injectable() +export class ProfileQuery { + constructor( + private readonly idService: IdService, + ) { + } + + @Query(() => ProfileModel) + @Roles('user') + public me( + @User() user: UserEntity, + @Context('cache') cache: ContextCache, + ): ProfileModel { + cache.add(cache.getCacheKey(UserEntity.name, user.id), user) + + return new ProfileModel(this.idService.encode(user.id), user) + } +} diff --git a/api/src/resolver/profile/profile.update.mutation.ts b/api/src/resolver/profile/profile.update.mutation.ts new file mode 100644 index 00000000..1fbce675 --- /dev/null +++ b/api/src/resolver/profile/profile.update.mutation.ts @@ -0,0 +1,47 @@ +import { Injectable } from '@nestjs/common' +import { Args, Context, Mutation } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { ProfileModel } from '../../dto/profile/profile.model' +import { ProfileUpdateInput } from '../../dto/profile/profile.update.input' +import { UserEntity } from '../../entity/user.entity' +import { IdService } from '../../service/id.service' +import { ProfileUpdateService } from '../../service/profile/profile.update.service' +import { ContextCache } from '../context.cache' + +@Injectable() +export class ProfileUpdateMutation { + constructor( + private readonly updateService: ProfileUpdateService, + private readonly idService: IdService, + ) { + } + + @Mutation(() => ProfileModel) + @Roles('user') + async updateProfile( + @User() user: UserEntity, + @Args({ name: 'user', type: () => ProfileUpdateInput }) input: ProfileUpdateInput, + @Context('cache') cache: ContextCache, + ): Promise { + await this.updateService.update(user, input) + + cache.add(cache.getCacheKey(UserEntity.name, user.id), user) + + return new ProfileModel(this.idService.encode(user.id), user) + } + + @Mutation(() => ProfileModel) + @Roles('user') + async verifyEmail( + @User() user: UserEntity, + @Args({ name: 'token' }) token: string, + @Context('cache') cache: ContextCache, + ): Promise { + await this.updateService.verifyEmail(user, token) + + cache.add(cache.getCacheKey(UserEntity.name, user.id), user) + + return new ProfileModel(this.idService.encode(user.id), user) + } +} diff --git a/api/src/resolver/setting/index.ts b/api/src/resolver/setting/index.ts new file mode 100644 index 00000000..e4fbe626 --- /dev/null +++ b/api/src/resolver/setting/index.ts @@ -0,0 +1,7 @@ +import { SettingMutation } from './setting.mutation' +import { SettingQuery } from './setting.query' + +export const settingsResolvers = [ + SettingQuery, + SettingMutation, +] diff --git a/api/src/resolver/setting/setting.mutation.ts b/api/src/resolver/setting/setting.mutation.ts new file mode 100644 index 00000000..4f78a628 --- /dev/null +++ b/api/src/resolver/setting/setting.mutation.ts @@ -0,0 +1,10 @@ +import { Injectable } from '@nestjs/common' +import { Roles } from '../../decorator/roles.decorator' + +@Injectable() +export class SettingMutation { + @Roles('superuser') + setSetting(key: string, value: string) { + // TODO https://github.com/ohmyform/api/issues/3 + } +} diff --git a/api/src/resolver/setting/setting.query.ts b/api/src/resolver/setting/setting.query.ts new file mode 100644 index 00000000..d8964416 --- /dev/null +++ b/api/src/resolver/setting/setting.query.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@nestjs/common' +import { Args, ID, Query } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { SettingModel } from '../../dto/setting/setting.model' +import { SettingPagerModel } from '../../dto/setting/setting.pager.model' +import { UserEntity } from '../../entity/user.entity' +import { SettingService } from '../../service/setting.service' + +@Injectable() +export class SettingQuery { + constructor( + private readonly settingService: SettingService, + ) { + } + + @Query(() => SettingPagerModel) + @Roles('superuser') + getSettings(): SettingPagerModel { + // TODO https://github.com/ohmyform/api/issues/3 + return new SettingPagerModel( + [], + 0, + 0, + 0, + ) + } + + @Query(() => SettingModel) + getSetting( + @Args('key', {type: () => ID}) key: string, + @User() user: UserEntity, + ): SettingModel { + if (!this.settingService.isPublicKey(key) && !user.roles.includes('superuser')) { + throw new Error(`no access to key ${key}`) + } + + return this.settingService.getByKey(key) + } +} diff --git a/api/src/resolver/status.resolver.ts b/api/src/resolver/status.resolver.ts new file mode 100644 index 00000000..3c332cbd --- /dev/null +++ b/api/src/resolver/status.resolver.ts @@ -0,0 +1,12 @@ +import { Query, Resolver } from '@nestjs/graphql' +import { StatusModel } from '../dto/status.model' + +@Resolver(() => StatusModel) +export class StatusResolver { + @Query(() => StatusModel) + status(): StatusModel { + return new StatusModel({ + version: process.env.version || 'dev', + }) + } +} diff --git a/api/src/resolver/submission/index.ts b/api/src/resolver/submission/index.ts new file mode 100644 index 00000000..483fe0d3 --- /dev/null +++ b/api/src/resolver/submission/index.ts @@ -0,0 +1,23 @@ +import { SubmissionFieldResolver } from './submission.field.resolver' +import { SubmissionListQuery } from './submission.list.query' +import { SubmissionProgressResolver } from './submission.progress.resolver' +import { SubmissionQuery } from './submission.query' +import { SubmissionResolver } from './submission.resolver' +import { SubmissionSetFieldMutation } from './submission.set.field.mutation' +import { SubmissionStartMutation } from './submission.start.mutation' +import { SubmissionStatisticQuery } from './submission.statistic.query' +import { SubmissionStatisticResolver } from './submission.statistic.resolver' +import { SubmissionFinishMutation } from './submission.finish.mutation' + +export const submissionResolvers = [ + SubmissionFieldResolver, + SubmissionListQuery, + SubmissionProgressResolver, + SubmissionQuery, + SubmissionResolver, + SubmissionSetFieldMutation, + SubmissionFinishMutation, + SubmissionStartMutation, + SubmissionStatisticQuery, + SubmissionStatisticResolver, +] diff --git a/api/src/resolver/submission/submission.field.resolver.ts b/api/src/resolver/submission/submission.field.resolver.ts new file mode 100644 index 00000000..a4283bf2 --- /dev/null +++ b/api/src/resolver/submission/submission.field.resolver.ts @@ -0,0 +1,43 @@ +import { Context, Parent, ResolveField, Resolver } from '@nestjs/graphql' +import { FormFieldModel } from '../../dto/form/form.field.model' +import { SubmissionFieldModel } from '../../dto/submission/submission.field.model' +import { FormFieldEntity } from '../../entity/form.field.entity' +import { SubmissionFieldEntity } from '../../entity/submission.field.entity' +import { FormFieldService } from '../../service/form/form.field.service' +import { IdService } from '../../service/id.service' +import { ContextCache } from '../context.cache' + +@Resolver(() => SubmissionFieldModel) +export class SubmissionFieldResolver { + constructor( + private readonly formFieldService: FormFieldService, + private readonly idService: IdService, + ) { + } + + @ResolveField(() => FormFieldModel, { nullable: true }) + async field( + @Parent() parent: SubmissionFieldModel, + @Context('cache') cache: ContextCache, + ): Promise { + const submissionField = await cache.get( + cache.getCacheKey(SubmissionFieldEntity.name, parent._id) + ) + + const field = await cache.get( + cache.getCacheKey( + FormFieldEntity.name, + submissionField.fieldId), + () => this.formFieldService.findById(submissionField.fieldId, submissionField.field) + ) + + if (!field) { + return null + } + + return new FormFieldModel( + this.idService.encode(field.id), + field, + ) + } +} diff --git a/api/src/resolver/submission/submission.finish.mutation.ts b/api/src/resolver/submission/submission.finish.mutation.ts new file mode 100644 index 00000000..8bddbaba --- /dev/null +++ b/api/src/resolver/submission/submission.finish.mutation.ts @@ -0,0 +1,32 @@ +import { Injectable } from '@nestjs/common' +import { Args, Context, ID, Mutation } from '@nestjs/graphql' +import { User } from '../../decorator/user.decorator' +import { SubmissionProgressModel } from '../../dto/submission/submission.progress.model' +import { SubmissionEntity } from '../../entity/submission.entity' +import { UserEntity } from '../../entity/user.entity' +import { SubmissionByIdPipe } from '../../pipe/submission/submission.by.id.pipe' +import { IdService } from '../../service/id.service' +import { SubmissionSetFieldService } from '../../service/submission/submission.set.field.service' +import { ContextCache } from '../context.cache' + +@Injectable() +export class SubmissionFinishMutation { + constructor( + private readonly setFieldService: SubmissionSetFieldService, + private readonly idService: IdService, + ) { + } + + @Mutation(() => SubmissionProgressModel) + async submissionFinish( + @User() user: UserEntity, + @Args({ name: 'submission', type: () => ID }, SubmissionByIdPipe) submission: SubmissionEntity, + @Context('cache') cache: ContextCache, + ): Promise { + await this.setFieldService.finishSubmission(submission) + + cache.add(cache.getCacheKey(SubmissionEntity.name, submission.id), submission) + + return new SubmissionProgressModel(this.idService.encode(submission.id), submission) + } +} diff --git a/api/src/resolver/submission/submission.list.query.ts b/api/src/resolver/submission/submission.list.query.ts new file mode 100644 index 00000000..cda96bb1 --- /dev/null +++ b/api/src/resolver/submission/submission.list.query.ts @@ -0,0 +1,54 @@ +import { Injectable } from '@nestjs/common' +import { Args, Context, ID, Int, Query } from '@nestjs/graphql' +import { User } from '../../decorator/user.decorator' +import { SubmissionModel } from '../../dto/submission/submission.model' +import { SubmissionPagerFilterInput } from '../../dto/submission/submission.pager.filter.input' +import { SubmissionPagerModel } from '../../dto/submission/submission.pager.model' +import { FormEntity } from '../../entity/form.entity' +import { SubmissionEntity } from '../../entity/submission.entity' +import { UserEntity } from '../../entity/user.entity' +import { FormByIdPipe } from '../../pipe/form/form.by.id.pipe' +import { IdService } from '../../service/id.service' +import { SubmissionService } from '../../service/submission/submission.service' +import { ContextCache } from '../context.cache' + +@Injectable() +export class SubmissionListQuery { + constructor( + private readonly submissionService: SubmissionService, + private readonly idService: IdService, + ) { + } + + @Query(() => SubmissionPagerModel) + async listSubmissions( + @User() user: UserEntity, + @Args('form', {type: () => ID}, FormByIdPipe) form: FormEntity, + @Args('start', {type: () => Int, defaultValue: 0, nullable: true}) start: number, + @Args('limit', {type: () => Int, defaultValue: 50, nullable: true}) limit: number, + @Args('filter', {type: () => SubmissionPagerFilterInput, defaultValue: new SubmissionPagerFilterInput()}) filter: SubmissionPagerFilterInput, + @Context('cache') cache: ContextCache, + ): Promise { + const [submissions, total] = await this.submissionService.find( + form, + start, + limit, + {}, + filter, + ) + + submissions.forEach(submission => { + cache.add(cache.getCacheKey(SubmissionEntity.name, submission.id), submission) + }) + + return new SubmissionPagerModel( + submissions.map(submission => new SubmissionModel( + this.idService.encode(submission.id), + submission + )), + total, + limit, + start, + ) + } +} diff --git a/api/src/resolver/submission/submission.progress.resolver.ts b/api/src/resolver/submission/submission.progress.resolver.ts new file mode 100644 index 00000000..93201f31 --- /dev/null +++ b/api/src/resolver/submission/submission.progress.resolver.ts @@ -0,0 +1,7 @@ +import { Resolver } from '@nestjs/graphql' +import { SubmissionProgressModel } from '../../dto/submission/submission.progress.model' + +@Resolver(() => SubmissionProgressModel) +export class SubmissionProgressResolver { + +} diff --git a/api/src/resolver/submission/submission.query.ts b/api/src/resolver/submission/submission.query.ts new file mode 100644 index 00000000..eedd71ae --- /dev/null +++ b/api/src/resolver/submission/submission.query.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@nestjs/common' +import { Args, Context, ID, Query } from '@nestjs/graphql' +import { User } from '../../decorator/user.decorator' +import { SubmissionModel } from '../../dto/submission/submission.model' +import { SubmissionEntity } from '../../entity/submission.entity' +import { UserEntity } from '../../entity/user.entity' +import { SubmissionByIdPipe } from '../../pipe/submission/submission.by.id.pipe' +import { FormService } from '../../service/form/form.service' +import { IdService } from '../../service/id.service' +import { SubmissionTokenService } from '../../service/submission/submission.token.service' +import { ContextCache } from '../context.cache' + +@Injectable() +export class SubmissionQuery { + constructor( + private readonly formService: FormService, + private readonly tokenService: SubmissionTokenService, + private readonly idService: IdService, + ) { + } + + @Query(() => SubmissionModel) + async getSubmissionById( + @User() user: UserEntity, + @Args('id', {type: () => ID}, SubmissionByIdPipe) submission: SubmissionEntity, + @Args('token', {nullable: true}) token: string, + @Context('cache') cache: ContextCache, + ): Promise { + if ( + !await this.tokenService.verify(token, submission.tokenHash) + && !this.formService.isAdmin(submission.form, user) + ) { + throw new Error('invalid form') + } + + cache.add(cache.getCacheKey(SubmissionEntity.name, submission.id), submission) + + return new SubmissionModel(this.idService.encode(submission.id), submission) + } +} diff --git a/api/src/resolver/submission/submission.resolver.ts b/api/src/resolver/submission/submission.resolver.ts new file mode 100644 index 00000000..1025244b --- /dev/null +++ b/api/src/resolver/submission/submission.resolver.ts @@ -0,0 +1,33 @@ +import { Context, Parent, ResolveField, Resolver } from '@nestjs/graphql' +import { User } from '../../decorator/user.decorator' +import { SubmissionFieldModel } from '../../dto/submission/submission.field.model' +import { SubmissionModel } from '../../dto/submission/submission.model' +import { SubmissionEntity } from '../../entity/submission.entity' +import { SubmissionFieldEntity } from '../../entity/submission.field.entity' +import { UserEntity } from '../../entity/user.entity' +import { IdService } from '../../service/id.service' +import { ContextCache } from '../context.cache' + +@Resolver(() => SubmissionModel) +export class SubmissionResolver { + constructor( + private readonly idService: IdService, + ) { + } + + @ResolveField(() => [SubmissionFieldModel]) + async fields( + @User() user: UserEntity, + @Parent() parent: SubmissionModel, + @Context('cache') cache: ContextCache, + ): Promise { + const submission = await cache.get( + cache.getCacheKey(SubmissionEntity.name, parent._id) + ) + + return submission.fields.map(field => { + cache.add(cache.getCacheKey(SubmissionFieldEntity.name, field.id), field) + return new SubmissionFieldModel(this.idService.encode(field.id), field) + }) + } +} diff --git a/api/src/resolver/submission/submission.set.field.mutation.ts b/api/src/resolver/submission/submission.set.field.mutation.ts new file mode 100644 index 00000000..c9be89e4 --- /dev/null +++ b/api/src/resolver/submission/submission.set.field.mutation.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@nestjs/common' +import { Args, Context, ID, Mutation } from '@nestjs/graphql' +import { User } from '../../decorator/user.decorator' +import { SubmissionProgressModel } from '../../dto/submission/submission.progress.model' +import { SubmissionSetFieldInput } from '../../dto/submission/submission.set.field.input' +import { SubmissionEntity } from '../../entity/submission.entity' +import { UserEntity } from '../../entity/user.entity' +import { SubmissionByIdPipe } from '../../pipe/submission/submission.by.id.pipe' +import { IdService } from '../../service/id.service' +import { SubmissionService } from '../../service/submission/submission.service' +import { SubmissionSetFieldService } from '../../service/submission/submission.set.field.service' +import { ContextCache } from '../context.cache' + +@Injectable() +export class SubmissionSetFieldMutation { + constructor( + private readonly submissionService: SubmissionService, + private readonly setFieldService: SubmissionSetFieldService, + private readonly idService: IdService, + ) { + } + + @Mutation(() => SubmissionProgressModel) + async submissionSetField( + @User() user: UserEntity, + @Args({ name: 'submission', type: () => ID }, SubmissionByIdPipe) submission: SubmissionEntity, + @Args({ name: 'field', type: () => SubmissionSetFieldInput }) input: SubmissionSetFieldInput, + @Context('cache') cache: ContextCache, + ): Promise { + if (!await this.submissionService.isOwner(submission, input.token)) { + throw new Error('no access to submission') + } + + await this.setFieldService.saveField(submission, input) + + cache.add(cache.getCacheKey(SubmissionEntity.name, submission.id), submission) + + return new SubmissionProgressModel(this.idService.encode(submission.id), submission) + } +} diff --git a/api/src/resolver/submission/submission.start.mutation.ts b/api/src/resolver/submission/submission.start.mutation.ts new file mode 100644 index 00000000..23f12679 --- /dev/null +++ b/api/src/resolver/submission/submission.start.mutation.ts @@ -0,0 +1,43 @@ +import { Injectable } from '@nestjs/common' +import { Args, Context, ID, Mutation } from '@nestjs/graphql' +import { IpAddress } from '../../decorator/ip.address.decorator' +import { User } from '../../decorator/user.decorator' +import { SubmissionProgressModel } from '../../dto/submission/submission.progress.model' +import { SubmissionStartInput } from '../../dto/submission/submission.start.input' +import { FormEntity } from '../../entity/form.entity' +import { SubmissionEntity } from '../../entity/submission.entity' +import { UserEntity } from '../../entity/user.entity' +import { FormByIdPipe } from '../../pipe/form/form.by.id.pipe' +import { FormService } from '../../service/form/form.service' +import { IdService } from '../../service/id.service' +import { SubmissionStartService } from '../../service/submission/submission.start.service' +import { ContextCache } from '../context.cache' + +@Injectable() +export class SubmissionStartMutation { + constructor( + private readonly startService: SubmissionStartService, + private readonly formService: FormService, + private readonly idService: IdService, + ) { + } + + @Mutation(() => SubmissionProgressModel) + async submissionStart( + @User() user: UserEntity, + @Args({ name: 'form', type: () => ID }, FormByIdPipe) form: FormEntity, + @Args({ name: 'submission', type: () => SubmissionStartInput }) input: SubmissionStartInput, + @IpAddress() ipAddr: string, + @Context('cache') cache: ContextCache, + ): Promise { + if (!form.isLive && !this.formService.isAdmin(form, user)) { + throw new Error('invalid form') + } + + const submission = await this.startService.start(form, input, user, ipAddr) + + cache.add(cache.getCacheKey(SubmissionEntity.name, submission.id), submission) + + return new SubmissionProgressModel(this.idService.encode(submission.id), submission) + } +} diff --git a/api/src/resolver/submission/submission.statistic.query.ts b/api/src/resolver/submission/submission.statistic.query.ts new file mode 100644 index 00000000..5c7714fd --- /dev/null +++ b/api/src/resolver/submission/submission.statistic.query.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common' +import { Query } from '@nestjs/graphql' +import { SubmissionStatisticModel } from '../../dto/submission/submission.statistic.model' + +@Injectable() +export class SubmissionStatisticQuery { + @Query(() => SubmissionStatisticModel) + getSubmissionStatistic(): SubmissionStatisticModel { + return new SubmissionStatisticModel() + } +} diff --git a/api/src/resolver/submission/submission.statistic.resolver.ts b/api/src/resolver/submission/submission.statistic.resolver.ts new file mode 100644 index 00000000..2f77169b --- /dev/null +++ b/api/src/resolver/submission/submission.statistic.resolver.ts @@ -0,0 +1,19 @@ +import { ResolveField, Resolver } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { Roles } from '../../decorator/roles.decorator' +import { SubmissionStatisticModel } from '../../dto/submission/submission.statistic.model' +import { SubmissionStatisticService } from '../../service/submission/submission.statistic.service' + +@Resolver(() => SubmissionStatisticModel) +export class SubmissionStatisticResolver { + constructor( + private readonly statisticService: SubmissionStatisticService, + ) { + } + + @ResolveField(() => GraphQLInt) + @Roles('admin') + total(): Promise { + return this.statisticService.getTotal() + } +} diff --git a/api/src/resolver/user/index.ts b/api/src/resolver/user/index.ts new file mode 100644 index 00000000..9e9e2541 --- /dev/null +++ b/api/src/resolver/user/index.ts @@ -0,0 +1,17 @@ +import { UserDeleteMutation } from './user.delete.mutation' +import { UserListQuery } from './user.list.query' +import { UserQuery } from './user.query' +import { UserResolver } from './user.resolver' +import { UserStatisticQuery } from './user.statistic.query' +import { UserStatisticResolver } from './user.statistic.resolver' +import { UserUpdateMutation } from './user.update.mutation' + +export const userResolvers = [ + UserDeleteMutation, + UserListQuery, + UserQuery, + UserResolver, + UserStatisticQuery, + UserStatisticResolver, + UserUpdateMutation, +] diff --git a/api/src/resolver/user/user.delete.mutation.ts b/api/src/resolver/user/user.delete.mutation.ts new file mode 100644 index 00000000..aebedde3 --- /dev/null +++ b/api/src/resolver/user/user.delete.mutation.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@nestjs/common' +import { Args, ID, Mutation } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { DeletedModel } from '../../dto/deleted.model' +import { UserEntity } from '../../entity/user.entity' +import { UserByIdPipe } from '../../pipe/user/user.by.id.pipe' +import { IdService } from '../../service/id.service' +import { UserDeleteService } from '../../service/user/user.delete.service' + +@Injectable() +export class UserDeleteMutation { + constructor( + private readonly deleteService: UserDeleteService, + private readonly idService: IdService, + ) { + } + + @Mutation(() => DeletedModel) + @Roles('admin') + async deleteUser( + @User() auth: UserEntity, + @Args({ name: 'id', type: () => ID}, UserByIdPipe) user: UserEntity, + ): Promise { + if (auth.id === user.id) { + throw new Error('cannot delete your own user') + } + + await this.deleteService.delete(user.id) + + return new DeletedModel(this.idService.encode(user.id)) + } +} diff --git a/api/src/resolver/user/user.list.query.ts b/api/src/resolver/user/user.list.query.ts new file mode 100644 index 00000000..b7631b72 --- /dev/null +++ b/api/src/resolver/user/user.list.query.ts @@ -0,0 +1,37 @@ +import { Args, Context, Int, Query, Resolver } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { UserModel } from '../../dto/user/user.model' +import { UserPagerModel } from '../../dto/user/user.pager.model' +import { UserEntity } from '../../entity/user.entity' +import { IdService } from '../../service/id.service' +import { UserService } from '../../service/user/user.service' +import { ContextCache } from '../context.cache' + +@Resolver(() => UserPagerModel) +export class UserListQuery { + constructor( + private readonly userService: UserService, + private readonly idService: IdService, + ) { + } + + @Query(() => UserPagerModel) + @Roles('superuser') + async listUsers( + @Args('start', {type: () => Int, defaultValue: 0, nullable: true}) start: number, + @Args('limit', {type: () => Int, defaultValue: 50, nullable: true}) limit: number, + @Context('cache') cache: ContextCache, + ): Promise { + const [entities, total] = await this.userService.find(start, limit) + + return new UserPagerModel( + entities.map(entity => { + cache.add(cache.getCacheKey(UserEntity.name, entity.id), entity) + return new UserModel(this.idService.encode(entity.id), entity) + }), + total, + limit, + start, + ) + } +} diff --git a/api/src/resolver/user/user.query.ts b/api/src/resolver/user/user.query.ts new file mode 100644 index 00000000..8d6785dd --- /dev/null +++ b/api/src/resolver/user/user.query.ts @@ -0,0 +1,27 @@ +import { Injectable } from '@nestjs/common' +import { Args, Context, ID, Query } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { UserModel } from '../../dto/user/user.model' +import { UserEntity } from '../../entity/user.entity' +import { UserByIdPipe } from '../../pipe/user/user.by.id.pipe' +import { IdService } from '../../service/id.service' +import { ContextCache } from '../context.cache' + +@Injectable() +export class UserQuery { + constructor( + private readonly idService: IdService, + ) { + } + + @Query(() => UserModel) + @Roles('admin') + public getUserById( + @Args('id', {type: () => ID}, UserByIdPipe) user: UserEntity, + @Context('cache') cache: ContextCache, + ): UserModel { + cache.add(cache.getCacheKey(UserEntity.name, user.id), user) + + return new UserModel(this.idService.encode(user.id), user) + } +} diff --git a/api/src/resolver/user/user.resolver.ts b/api/src/resolver/user/user.resolver.ts new file mode 100644 index 00000000..1d47b1f0 --- /dev/null +++ b/api/src/resolver/user/user.resolver.ts @@ -0,0 +1,41 @@ +import { Context, Parent, ResolveField, Resolver } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { UserModel } from '../../dto/user/user.model' +import { UserEntity } from '../../entity/user.entity' +import { UserService } from '../../service/user/user.service' +import { ContextCache } from '../context.cache' + +@Resolver(() => UserModel) +export class UserResolver { + constructor( + private readonly userService: UserService, + ) { + } + + @ResolveField(() => [String]) + @Roles('user') + async roles( + @User() user: UserEntity, + @Parent() parent: UserModel, + @Context('cache') cache: ContextCache, + ): Promise { + return this.returnFieldForSuperuser( + await cache.get(cache.getCacheKey(UserEntity.name, parent._id)), + user, + c => c.roles + ) + } + + private returnFieldForSuperuser( + parent: UserEntity, + user: UserEntity, + callback: (user: UserEntity) => T + ): T { + if (user.id !== parent.id && !this.userService.isSuperuser(user)) { + throw new Error('No access to roles') + } + + return callback(parent) + } +} diff --git a/api/src/resolver/user/user.statistic.query.ts b/api/src/resolver/user/user.statistic.query.ts new file mode 100644 index 00000000..f023a598 --- /dev/null +++ b/api/src/resolver/user/user.statistic.query.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common' +import { Query } from '@nestjs/graphql' +import { UserStatisticModel } from '../../dto/user/user.statistic.model' + +@Injectable() +export class UserStatisticQuery { + @Query(() => UserStatisticModel) + getUserStatistic(): UserStatisticModel { + return new UserStatisticModel() + } +} diff --git a/api/src/resolver/user/user.statistic.resolver.ts b/api/src/resolver/user/user.statistic.resolver.ts new file mode 100644 index 00000000..7c779d3f --- /dev/null +++ b/api/src/resolver/user/user.statistic.resolver.ts @@ -0,0 +1,18 @@ +import { Int, ResolveField, Resolver } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { UserStatisticModel } from '../../dto/user/user.statistic.model' +import { UserStatisticService } from '../../service/user/user.statistic.service' + +@Resolver(() => UserStatisticModel) +export class UserStatisticResolver { + constructor( + private readonly statisticService: UserStatisticService, + ) { + } + + @ResolveField(() => Int) + @Roles('admin') + total(): Promise { + return this.statisticService.getTotal() + } +} diff --git a/api/src/resolver/user/user.update.mutation.ts b/api/src/resolver/user/user.update.mutation.ts new file mode 100644 index 00000000..b401594e --- /dev/null +++ b/api/src/resolver/user/user.update.mutation.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@nestjs/common' +import { Args, Context, Mutation } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { UserModel } from '../../dto/user/user.model' +import { UserUpdateInput } from '../../dto/user/user.update.input' +import { UserEntity } from '../../entity/user.entity' +import { IdService } from '../../service/id.service' +import { UserService } from '../../service/user/user.service' +import { UserUpdateService } from '../../service/user/user.update.service' +import { ContextCache } from '../context.cache' + +@Injectable() +export class UserUpdateMutation { + constructor( + private readonly updateService: UserUpdateService, + private readonly userService: UserService, + private readonly idService: IdService, + ) { + } + + @Mutation(() => UserModel) + @Roles('superuser') + async updateUser( + @User() auth: UserEntity, + @Args({ name: 'user', type: () => UserUpdateInput }) input: UserUpdateInput, + @Context('cache') cache: ContextCache, + ): Promise { + if (auth.id.toString() === input.id) { + throw new Error('cannot update your own user') + } + + const user = await this.userService.findById(this.idService.decode(input.id)) + + await this.updateService.update(user, input) + + cache.add(cache.getCacheKey(UserEntity.name, user.id), user) + + return new UserModel(this.idService.encode(user.id), user) + } +} diff --git a/api/src/service/auth/auth.service.ts b/api/src/service/auth/auth.service.ts new file mode 100644 index 00000000..138e0e05 --- /dev/null +++ b/api/src/service/auth/auth.service.ts @@ -0,0 +1,55 @@ +import { Injectable } from '@nestjs/common' +import { JwtService } from '@nestjs/jwt' +import { PinoLogger } from 'nestjs-pino' +import { serializeError } from 'serialize-error' +import { AuthJwtModel } from '../../dto/auth/auth.jwt.model' +import { UserEntity } from '../../entity/user.entity' +import { UserService } from '../user/user.service' +import { PasswordService } from './password.service' + +@Injectable() +export class AuthService { + constructor( + private userService: UserService, + private jwtService: JwtService, + private passwordService: PasswordService, + private logger: PinoLogger, + ) { + logger.setContext(this.constructor.name) + } + + async validateUser(username: string, password: string): Promise { + // TODO only allow login for verified users! + + try { + const user = await this.userService.findByUsername(username); + if (user && await this.passwordService.verify(password, user.passwordHash, user.salt)) { + return user; + } + } catch (e) { + this.logger.error({ + error: serializeError(e), + username, + },'failed to verify user') + } + + return null; + } + + public login(user: UserEntity): AuthJwtModel { + return new AuthJwtModel({ + accessToken: this.jwtService.sign({ + username: user.username, + roles: user.roles, + sub: user.id, + }, { + expiresIn: '4h', + }), + refreshToken: this.jwtService.sign({ + sub: user.id, + }, { + expiresIn: '30d', + }), + }); + } +} diff --git a/api/src/service/auth/index.ts b/api/src/service/auth/index.ts new file mode 100644 index 00000000..840bbfc6 --- /dev/null +++ b/api/src/service/auth/index.ts @@ -0,0 +1,11 @@ +import { AuthService } from './auth.service' +import { JwtStrategy } from './jwt.strategy' +import { LocalStrategy } from './local.strategy' +import { PasswordService } from './password.service' + +export const authServices = [ + AuthService, + LocalStrategy, + PasswordService, + JwtStrategy, +] diff --git a/api/src/service/auth/jwt.strategy.ts b/api/src/service/auth/jwt.strategy.ts new file mode 100644 index 00000000..88593e36 --- /dev/null +++ b/api/src/service/auth/jwt.strategy.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@nestjs/common' +import { ConfigService } from '@nestjs/config' +import { PassportStrategy } from '@nestjs/passport' +import { ExtractJwt, Strategy } from 'passport-jwt' +import { UserEntity } from '../../entity/user.entity' +import { UserService } from '../user/user.service' + +@Injectable() +export class JwtStrategy extends PassportStrategy(Strategy) { + constructor( + configService: ConfigService, + private readonly userService: UserService, + ) { + super({ + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + ignoreExpiration: false, + secretOrKey: configService.get('SECRET_KEY'), + }); + } + + async validate(payload: any): Promise { + try { + return await this.userService.findById(payload.sub) + } catch (e) { + // log error + } + + return null + } +} diff --git a/api/src/service/auth/local.strategy.ts b/api/src/service/auth/local.strategy.ts new file mode 100644 index 00000000..cd8cfbe5 --- /dev/null +++ b/api/src/service/auth/local.strategy.ts @@ -0,0 +1,19 @@ +import { Injectable, UnauthorizedException } from '@nestjs/common' +import { PassportStrategy } from '@nestjs/passport' +import { Strategy } from 'passport-local' +import { AuthService } from './auth.service' + +@Injectable() +export class LocalStrategy extends PassportStrategy(Strategy) { + constructor(private authService: AuthService) { + super(); + } + + async validate(username: string, password: string): Promise { + const user = await this.authService.validateUser(username, password); + if (!user) { + throw new UnauthorizedException(); + } + return user; + } +} diff --git a/api/src/service/auth/password.service.ts b/api/src/service/auth/password.service.ts new file mode 100644 index 00000000..e9fe5388 --- /dev/null +++ b/api/src/service/auth/password.service.ts @@ -0,0 +1,29 @@ +import { Injectable } from '@nestjs/common' +import * as bcrypt from 'bcrypt' +import * as crypto from 'crypto' + +@Injectable() +export class PasswordService { + async verify(password: string, hash: string, salt?: string): Promise { + if (hash[0] === '$') { + return await bcrypt.compare(password, hash) + } + + //Generate salt if it doesn't exist yet + if(!salt){ + salt = crypto.randomBytes(64).toString('base64'); + } + + return hash === crypto.pbkdf2Sync( + password, + new Buffer(salt, 'base64'), + 10000, + 128, + 'SHA1' + ).toString('base64'); + } + + public hash(password: string): Promise { + return bcrypt.hash(password, 4) + } +} diff --git a/api/src/service/form/form.create.service.ts b/api/src/service/form/form.create.service.ts new file mode 100644 index 00000000..1c0bcdf5 --- /dev/null +++ b/api/src/service/form/form.create.service.ts @@ -0,0 +1,39 @@ +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { FormCreateInput } from '../../dto/form/form.create.input' +import { FormEntity } from '../../entity/form.entity' +import { PageEntity } from '../../entity/page.entity' +import { UserEntity } from '../../entity/user.entity' +import { FormPageCreateService } from './form.page.create.service' + +@Injectable() +export class FormCreateService { + constructor( + @InjectRepository(FormEntity) + private readonly formRepository: Repository, + private readonly formPageCreateService: FormPageCreateService, + ) { + } + + async create(admin: UserEntity, input: FormCreateInput): Promise { + const form = new FormEntity() + + form.title = input.title + form.isLive = Boolean(input.isLive) + form.showFooter = Boolean(input.showFooter) + form.anonymousSubmission = Boolean(input.anonymousSubmission) + form.language = input.language || 'en' + form.design.layout = input.layout + + + form.endPage = this.formPageCreateService.create(input.endPage) + form.startPage = this.formPageCreateService.create(input.startPage) + + form.admin = admin + + return await this.formRepository.save(form) + } + +} + diff --git a/api/src/service/form/form.delete.service.ts b/api/src/service/form/form.delete.service.ts new file mode 100644 index 00000000..93e3785b --- /dev/null +++ b/api/src/service/form/form.delete.service.ts @@ -0,0 +1,26 @@ +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { FormEntity } from '../../entity/form.entity' +import { SubmissionEntity } from '../../entity/submission.entity' + +@Injectable() +export class FormDeleteService { + constructor( + @InjectRepository(FormEntity) + private readonly formRepository: Repository, + @InjectRepository(SubmissionEntity) + private readonly submissionRepository: Repository, + ) { + } + + async delete(id: number): Promise { + await this.submissionRepository.delete({ + form: new FormEntity({ id }), + }) + + await this.formRepository.delete({ + id, + }) + } +} diff --git a/api/src/service/form/form.field.service.ts b/api/src/service/form/form.field.service.ts new file mode 100644 index 00000000..d90c672a --- /dev/null +++ b/api/src/service/form/form.field.service.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { FormFieldEntity } from '../../entity/form.field.entity' + +@Injectable() +export class FormFieldService { + constructor( + @InjectRepository(FormFieldEntity) + private readonly formFieldRepository: Repository, + ) { + } + + async findById(id: number | string, existing?: FormFieldEntity): Promise { + if (existing) return existing + + const entity = await this.formFieldRepository.findOne(id); + + if (!entity) { + throw new Error('no form field found') + } + + return entity + } +} diff --git a/api/src/service/form/form.page.create.service.ts b/api/src/service/form/form.page.create.service.ts new file mode 100644 index 00000000..27871514 --- /dev/null +++ b/api/src/service/form/form.page.create.service.ts @@ -0,0 +1,44 @@ +import { Injectable } from '@nestjs/common' +import { PageInput } from '../../dto/form/page.input' +import { PageButtonEntity } from '../../entity/page.button.entity' +import { PageEntity } from '../../entity/page.entity' +import { IdService } from '../id.service' + +@Injectable() +export class FormPageCreateService { + constructor( + private readonly idService: IdService, + ) { + } + + public create(input: PageInput): PageEntity { + const page = new PageEntity() + page.show = Boolean(input?.show) + page.buttons = [] + + if (!input) { + return page + } + + page.title = input.title + page.buttonText = input.buttonText + page.paragraph = input.paragraph + + if (input.buttons !== undefined) { + page.buttons = input.buttons.map(buttonInput => { + const button = new PageButtonEntity() + button.page = page + button.url = buttonInput.url + button.action = buttonInput.action + button.text = buttonInput.text + button.color = buttonInput.color + button.bgColor = buttonInput.bgColor + button.activeColor = buttonInput.activeColor + + return button + }) + } + + return page + } +} \ No newline at end of file diff --git a/api/src/service/form/form.page.update.service.ts b/api/src/service/form/form.page.update.service.ts new file mode 100644 index 00000000..28446fd9 --- /dev/null +++ b/api/src/service/form/form.page.update.service.ts @@ -0,0 +1,73 @@ +import { Injectable } from '@nestjs/common' +import { PageInput } from '../../dto/form/page.input' +import { PageButtonEntity } from '../../entity/page.button.entity' +import { PageEntity } from '../../entity/page.entity' +import { IdService } from '../id.service' + +@Injectable() +export class FormPageUpdateService { + constructor( + private readonly idService: IdService, + ) { + } + + public update(page: PageEntity, input: PageInput): PageEntity { + if (!page) { + page = new PageEntity() + page.show = false + } + + if (input.show !== undefined) { + page.show = input.show + } + + if (input.title !== undefined) { + page.title = input.title + } + + if (input.paragraph !== undefined) { + page.paragraph = input.paragraph + } + + if (input.buttonText !== undefined) { + page.buttonText = input.buttonText + } + + if (input.buttons !== undefined) { + page.buttons = input.buttons.map(buttonInput => { + const entity = this.findByIdInList( + page?.buttons, + buttonInput.id, + new PageButtonEntity() + ) + + entity.page = page + entity.url = buttonInput.url + entity.action = buttonInput.action + entity.text = buttonInput.text + entity.color = buttonInput.color + entity.bgColor = buttonInput.bgColor + entity.activeColor = buttonInput.activeColor + + return entity + }) + } + + return page + } + + + private findByIdInList(list: T[], id: string, fallback: T): T { + if (!list || /^NEW-/.test(id)) { + return fallback + } + + const found = list.find((value) => value.id === this.idService.decode(id)) + + if (found) { + return found + } + + return fallback + } +} \ No newline at end of file diff --git a/api/src/service/form/form.service.ts b/api/src/service/form/form.service.ts new file mode 100644 index 00000000..afc30561 --- /dev/null +++ b/api/src/service/form/form.service.ts @@ -0,0 +1,66 @@ +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { PinoLogger } from 'nestjs-pino' +import { Repository } from 'typeorm' +import { FormEntity } from '../../entity/form.entity' +import { UserEntity } from '../../entity/user.entity' + +@Injectable() +export class FormService { + constructor( + @InjectRepository(FormEntity) + private readonly formRepository: Repository, + private readonly logger: PinoLogger, + ) { + logger.setContext(this.constructor.name) + } + + isAdmin(form: FormEntity, user: UserEntity): boolean { + if (!user) { + return false + } + + if (user.roles.includes('superuser')) { + return true + } + + return form.admin.id === user.id + } + + async find( + start: number, + limit: number, + sort: any = {}, + user?: UserEntity + ): Promise<[FormEntity[], number]> { + const qb = this.formRepository.createQueryBuilder('f') + + qb.leftJoinAndSelect('f.admin', 'a') + + if (user) { + qb.where('f.admin = :user', { user: user.id }) + } + + // TODO readd sort + this.logger.debug({ + sort, + }, 'ignored sorting for submissions') + + qb.skip(start) + qb.take(limit) + + return await qb.getManyAndCount() + } + + async findById(id: number | string, existing?: FormEntity): Promise { + if (existing) return existing + + const form = await this.formRepository.findOne(id); + + if (!form) { + throw new Error('no form found') + } + + return form + } +} diff --git a/api/src/service/form/form.statistic.service.ts b/api/src/service/form/form.statistic.service.ts new file mode 100644 index 00000000..278df262 --- /dev/null +++ b/api/src/service/form/form.statistic.service.ts @@ -0,0 +1,15 @@ +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { FormEntity } from '../../entity/form.entity' + +export class FormStatisticService { + constructor( + @InjectRepository(FormEntity) + private readonly formRepository: Repository + ) { + } + + async getTotal(): Promise { + return await this.formRepository.count(); + } +} diff --git a/api/src/service/form/form.update.service.ts b/api/src/service/form/form.update.service.ts new file mode 100644 index 00000000..122eeed6 --- /dev/null +++ b/api/src/service/form/form.update.service.ts @@ -0,0 +1,291 @@ +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { FormUpdateInput } from '../../dto/form/form.update.input' +import { FormEntity } from '../../entity/form.entity' +import { FormFieldEntity } from '../../entity/form.field.entity' +import { FormFieldLogicEntity } from '../../entity/form.field.logic.entity' +import { FormFieldOptionEntity } from '../../entity/form.field.option.entity' +import { FormHookEntity } from '../../entity/form.hook.entity' +import { FormNotificationEntity } from '../../entity/form.notification.entity' +import { PageButtonEntity } from '../../entity/page.button.entity' +import { PageEntity } from '../../entity/page.entity' +import { IdService } from '../id.service' +import { FormPageUpdateService } from './form.page.update.service' + +@Injectable() +export class FormUpdateService { + constructor( + @InjectRepository(FormEntity) + private readonly formRepository: Repository, + @InjectRepository(FormFieldEntity) + private readonly formFieldRepository: Repository, + @InjectRepository(FormHookEntity) + private readonly formHookRepository: Repository, + private readonly idService: IdService, + private readonly pageService: FormPageUpdateService, + ) { + } + + async update(form: FormEntity, input: FormUpdateInput): Promise { + if (input.language !== undefined) { + form.language = input.language + } + + if (input.title !== undefined) { + form.title = input.title + } + + if (input.showFooter !== undefined) { + form.showFooter = input.showFooter + } + + if (input.anonymousSubmission !== undefined) { + form.anonymousSubmission = input.anonymousSubmission + } + + if (input.isLive !== undefined) { + form.isLive = input.isLive + } + + if (input.fields !== undefined) { + form.fields = input.fields.map((nextField) => { + let field = this.findByIdInList( + form.fields, + nextField.id, + null + ) + + if (!field) { + field = new FormFieldEntity() + field.type = nextField.type + } + + if (nextField.title !== undefined) { + field.title = nextField.title + } + + if (nextField.description !== undefined) { + field.description = nextField.description + } + + if (nextField.idx !== undefined) { + field.idx = nextField.idx + } + + if (nextField.disabled !== undefined) { + field.disabled = nextField.disabled + } + + if (nextField.required !== undefined) { + field.required = nextField.required + } + + if (nextField.defaultValue !== undefined) { + field.defaultValue = nextField.defaultValue + } + + if (nextField.slug !== undefined) { + field.slug = nextField.slug + } + + if (nextField.logic !== undefined) { + field.logic = nextField.logic.map(nextLogic => { + const logic = this.findByIdInList( + field.logic, + nextLogic.id, + new FormFieldLogicEntity() + ) + + logic.field = field + + if (nextLogic.formula !== undefined) { + logic.formula = nextLogic.formula + } + if (nextLogic.idx !== undefined) { + logic.idx = nextLogic.idx + } + if (nextLogic.action !== undefined) { + logic.action = nextLogic.action + } + if (nextLogic.visible !== undefined) { + logic.visible = nextLogic.visible + } + if (nextLogic.require !== undefined) { + logic.require = nextLogic.require + } + if (nextLogic.disable !== undefined) { + logic.disable = nextLogic.disable + } + if (nextLogic.jumpTo !== undefined) { + logic.jumpTo = this.findByIdInList( + form.fields, + nextLogic.jumpTo, + null + ) + } + if (nextLogic.enabled !== undefined) { + logic.enabled = nextLogic.enabled + } + + return logic + }) + } + + if (nextField.options !== undefined) { + field.options = nextField.options.map(nextOption => { + const option = this.findByIdInList( + field.options, + nextOption.id, + new FormFieldOptionEntity() + ) + + option.field = field + + option.title = nextOption.title + option.value = nextOption.value + option.key = nextOption.key + + return option + }) + } + + if (nextField.rating !== undefined) { + field.rating = nextField.rating + } + + return field + }) + } + + if (input.hooks !== undefined) { + form.hooks = input.hooks.map((nextHook) => { + const hook = this.findByIdInList( + form.hooks, + nextHook.id, + new FormHookEntity() + ) + + // ability for other fields to apply mapping + hook.url = nextHook.url + hook.enabled = nextHook.enabled + + if (nextHook.format !== undefined) { + hook.format = nextHook.format + } + + return hook + }) + + } + + if (input.design !== undefined) { + if (input.design.font !== undefined) { + form.design.font = input.design.font + } + + if (input.design.layout !== undefined) { + form.design.layout = input.design.layout + } + + if (input.design.colors !== undefined) { + if (input.design.colors.answer !== undefined) { + form.design.colors.answer = input.design.colors.answer + } + if (input.design.colors.buttonText !== undefined) { + form.design.colors.buttonText = input.design.colors.buttonText + } + if (input.design.colors.background !== undefined) { + form.design.colors.background = input.design.colors.background + } + if (input.design.colors.button !== undefined) { + form.design.colors.button = input.design.colors.button + } + if (input.design.colors.buttonActive !== undefined) { + form.design.colors.buttonActive = input.design.colors.buttonActive + } + if (input.design.colors.question !== undefined) { + form.design.colors.question = input.design.colors.question + } + } + } + + + if (input.notifications !== undefined) { + form.notifications = input.notifications.map(notificationInput => { + const notification = this.findByIdInList( + form.notifications, + notificationInput.id, + new FormNotificationEntity() + ) + + notification.form = form + notification.enabled = notificationInput.enabled + + if (notificationInput.fromEmail !== undefined) { + notification.fromEmail = notificationInput.fromEmail + } + if (notificationInput.fromField !== undefined) { + notification.fromField = this.findByIdInList( + form.fields, + notificationInput.fromField, + null + ) + } + if (notificationInput.subject !== undefined) { + notification.subject = notificationInput.subject + } + if (notificationInput.htmlTemplate !== undefined) { + notification.htmlTemplate = notificationInput.htmlTemplate + } + if (notificationInput.toEmail !== undefined) { + notification.toEmail = notificationInput.toEmail + } + if (notificationInput.toField !== undefined) { + notification.toField = this.findByIdInList( + form.fields, + notificationInput.toField, + null + ) + } + + return notification + }) + } + + /* + if (input.respondentNotifications !== undefined) { + form.set('respondentNotifications', { + ...input.respondentNotifications, + toField: extractField(input.respondentNotifications.toField) + }) + } + */ + + if (input.startPage !== undefined) { + form.startPage = this.pageService.update(form.startPage, input.startPage) + } + + if (input.endPage !== undefined) { + form.endPage = this.pageService.update(form.endPage, input.endPage) + } + + await this.formRepository.save(form) + + return form + } + + private findByIdInList(list: T[], id: string, fallback: T): T { + if (!list || /^NEW-/.test(id) || !id) { + return fallback + } + + const found = list.find((value) => value.id === this.idService.decode(id)) + + if (found) { + return found + } + + return fallback + } +} diff --git a/api/src/service/form/index.ts b/api/src/service/form/index.ts new file mode 100644 index 00000000..1add17ee --- /dev/null +++ b/api/src/service/form/index.ts @@ -0,0 +1,19 @@ +import { FormCreateService } from './form.create.service' +import { FormDeleteService } from './form.delete.service' +import { FormFieldService } from './form.field.service' +import { FormPageCreateService } from './form.page.create.service' +import { FormPageUpdateService } from './form.page.update.service' +import { FormService } from './form.service' +import { FormStatisticService } from './form.statistic.service' +import { FormUpdateService } from './form.update.service' + +export const formServices = [ + FormCreateService, + FormDeleteService, + FormFieldService, + FormPageCreateService, + FormPageUpdateService, + FormService, + FormStatisticService, + FormUpdateService, +] diff --git a/api/src/service/id.service.ts b/api/src/service/id.service.ts new file mode 100644 index 00000000..a6b87ef1 --- /dev/null +++ b/api/src/service/id.service.ts @@ -0,0 +1,32 @@ +import { Injectable } from '@nestjs/common' +import { ConfigService } from '@nestjs/config' +import Hashids from 'hashids' + +@Injectable() +export class IdService { + private readonly hashids: Hashids + + constructor( + readonly config: ConfigService + ) { + this.hashids = new Hashids(config.get('SECRET_KEY'), 6) + } + + public encode(id: number): string { + return this.hashids.encode([ id ]) + } + + public decode(raw: string): number { + if (!this.hashids.isValidId(raw)) { + throw new Error('invalid id passed') + } + + const results: number[] = this.hashids.decode(raw) as number[] + + if (results[0] === undefined) { + throw new Error('invalid id passed') + } + + return results[0] + } +} diff --git a/api/src/service/index.ts b/api/src/service/index.ts new file mode 100644 index 00000000..b05082f6 --- /dev/null +++ b/api/src/service/index.ts @@ -0,0 +1,49 @@ +import { ConfigService } from '@nestjs/config' +import { RedisPubSub } from 'graphql-redis-subscriptions' +import { PubSub, PubSubEngine } from 'graphql-subscriptions' +import Redis from 'ioredis' +import { PinoLogger } from 'nestjs-pino' +import { authServices } from './auth' +import { formServices } from './form' +import { IdService } from './id.service' +import { InstallationMetricsService } from './installation.metrics.service' +import { MailService } from './mail.service' +import { profileServices } from './profile' +import { SettingService } from './setting.service' +import { submissionServices } from './submission' +import { userServices } from './user' + +export const services = [ + ...userServices, + ...profileServices, + ...formServices, + ...authServices, + ...submissionServices, + SettingService, + MailService, + InstallationMetricsService, + { + provide: 'PUB_SUB', + inject: [ConfigService, PinoLogger], + useFactory: (configService: ConfigService, logger: PinoLogger): PubSubEngine => { + const host = configService.get('REDIS_HOST', null) + const port = configService.get('REDIS_PORT', 6379) + + if (host === null) { + logger.warn('without redis graphql subscriptions will be unreliable in load balanced environments') + return new PubSub() + } + + const options = { + host, + port, + } + + return new RedisPubSub({ + publisher: new Redis(options), + subscriber: new Redis(options), + }) + }, + }, + IdService, +] diff --git a/api/src/service/installation.metrics.service.ts b/api/src/service/installation.metrics.service.ts new file mode 100644 index 00000000..4b62577a --- /dev/null +++ b/api/src/service/installation.metrics.service.ts @@ -0,0 +1,45 @@ +import { Injectable, OnApplicationBootstrap } from '@nestjs/common' +import { ConfigService } from '@nestjs/config' +import MatomoTracker from 'matomo-tracker' +import { PinoLogger } from 'nestjs-pino' + +@Injectable() +export class InstallationMetricsService implements OnApplicationBootstrap { + private host = 'https://metrics.ohmyform.com/matomo.php' + + constructor( + private readonly logger: PinoLogger, + private readonly configService: ConfigService, + ) { + logger.setContext(this.constructor.name) + } + + onApplicationBootstrap(): void { + if (this.configService.get('DISABLE_INSTALLATION_METRICS')) { + this.logger.info('installation metrics are disabled') + return + } + + const tracker = new MatomoTracker(2, this.host) + + tracker.on('error', () => { + this.logger.error('failed to add installation metrics') + }) + + this.logger.info('try to add startup metric') + tracker.track({ + url: `http://localhost/version/${process.env.version}`, + action_name: 'startup', + ua: process.arch, + }) + + setInterval(() => { + this.logger.info('try to add running metric') + tracker.track({ + url: `http://localhost/version/${process.env.version}`, + action_name: 'running', + ua: process.arch, + }) + }, 24 * 60 * 60 * 1000) + } +} diff --git a/api/src/service/mail.service.ts b/api/src/service/mail.service.ts new file mode 100644 index 00000000..56dece10 --- /dev/null +++ b/api/src/service/mail.service.ts @@ -0,0 +1,91 @@ +import { MailerService } from '@nestjs-modules/mailer' +import { Injectable } from '@nestjs/common' +import { ConfigService } from '@nestjs/config' +import fs from 'fs' +import handlebars from 'handlebars' +import htmlToText from 'html-to-text' +import mjml2html from 'mjml' +import { PinoLogger } from 'nestjs-pino' +import { join } from 'path' +import { serializeError } from 'serialize-error' +import { defaultLanguage } from '../config/languages' + +@Injectable() +export class MailService { + constructor( + private readonly nestMailer: MailerService, + private readonly configService: ConfigService, + private readonly logger: PinoLogger, + ) { + logger.setContext(this.constructor.name) + } + + async send( + to: string, + template: string, + context: { [key: string]: any }, + forceLanguage?: string + ): Promise { + const language = forceLanguage || this.configService.get('LOCALE', defaultLanguage) + + this.logger.debug({ + email: to, + template, + }, 'try to send email') + + try { + const path = this.getTemplatePath(template, language) + + const html = mjml2html( + handlebars.compile( + fs.readFileSync(path).toString('utf-8') + )(context), + { + minify: true, + } + ).html + + const text = htmlToText.htmlToText(html) + + const subject = this.extractSubject(html, template) + + await this.nestMailer.sendMail({ to, subject, html, text }) + this.logger.info({ + email: to, + template, + language, + }, 'sent email') + } catch (error) { + this.logger.error({ + error: serializeError(error), + email: to, + template, + }, 'failed to send email') + return false + } + + return true + } + + private extractSubject(html: string, template: string): string { + if (/(.*?)<\/title>/gi.test(html)) { + return /<title>(.*?)<\/title>/gi.exec(html)[1] + } + + return template + } + + private getTemplatePath(template: string, language: string): string { + let templatePath = join(this.configService.get<string>('LOCALES_PATH'), language, 'mail', `${template}.mjml`) + + if (!fs.existsSync(templatePath)) { + templatePath = join(this.configService.get<string>('LOCALES_PATH'), 'en', 'mail', `${template}.mjml`) + } + + if (!fs.existsSync(templatePath)) { + throw new Error('invalid template') + } + + return templatePath + } +} diff --git a/api/src/service/profile/index.ts b/api/src/service/profile/index.ts new file mode 100644 index 00000000..5c86d10a --- /dev/null +++ b/api/src/service/profile/index.ts @@ -0,0 +1,3 @@ +import { ProfileUpdateService } from './profile.update.service' + +export const profileServices = [ProfileUpdateService] diff --git a/api/src/service/profile/profile.update.service.ts b/api/src/service/profile/profile.update.service.ts new file mode 100644 index 00000000..bb68a8be --- /dev/null +++ b/api/src/service/profile/profile.update.service.ts @@ -0,0 +1,64 @@ +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { ProfileUpdateInput } from '../../dto/profile/profile.update.input' +import { UserEntity } from '../../entity/user.entity' +import { PasswordService } from '../auth/password.service' +import { UserTokenService } from '../user/user.token.service' + +@Injectable() +export class ProfileUpdateService { + constructor( + @InjectRepository(UserEntity) + private readonly userRepository: Repository<UserEntity>, + private readonly passwordService: PasswordService, + private readonly userTokenService: UserTokenService, + ) { + } + + async verifyEmail(user: UserEntity, token: string): Promise<UserEntity> { + if (!await this.userTokenService.verify(token, user.token)) { + throw new Error('invalid token') + } + + return await this.userRepository.save(user) + } + + async update(user: UserEntity, input: ProfileUpdateInput): Promise<UserEntity> { + if (input.firstName !== undefined) { + user.firstName = input.firstName + } + + if (input.lastName !== undefined) { + user.lastName = input.lastName + } + + if (input.email !== undefined && user.email !== input.email) { + user.email = input.email + user.emailVerified = false + // TODO request email verification + + if (undefined !== await this.userRepository.findOne({ email: input.email })) { + throw new Error('email already in use') + } + } + + if (input.username !== undefined && user.username !== input.username) { + user.username = input.username + + if (undefined !== await this.userRepository.findOne({ username: input.username })) { + throw new Error('username already in use') + } + } + + if (input.language !== undefined) { + user.language = input.language + } + + if (input.password !== undefined) { + user.passwordHash = await this.passwordService.hash(input.password) + } + + return await this.userRepository.save(user) + } +} diff --git a/api/src/service/setting.service.ts b/api/src/service/setting.service.ts new file mode 100644 index 00000000..e9e41e2f --- /dev/null +++ b/api/src/service/setting.service.ts @@ -0,0 +1,39 @@ +import { Injectable } from '@nestjs/common' +import { ConfigService } from '@nestjs/config' +import { SettingModel } from '../dto/setting/setting.model' + +@Injectable() +export class SettingService { + constructor( + private readonly configService: ConfigService, + ) { + } + + isPublicKey(key: string): boolean { + return [ + 'SIGNUP_DISABLED', + 'LOGIN_NOTE', + 'HIDE_CONTRIB', + ].includes(key) + } + + getByKey(key: string): SettingModel { + switch (key) { + case 'SIGNUP_DISABLED': + case 'LOGIN_NOTE': + case 'DEFAULT_ROLE': + case 'HIDE_CONTRIB': + return new SettingModel(key, this.configService.get(key)) + } + + throw new Error(`no config stored for key ${key}`) + } + + isTrue(key: string): boolean { + return this.getByKey(key).isTrue + } + + isFalse(key: string): boolean { + return this.getByKey(key).isFalse + } +} diff --git a/api/src/service/submission/index.ts b/api/src/service/submission/index.ts new file mode 100644 index 00000000..ca460216 --- /dev/null +++ b/api/src/service/submission/index.ts @@ -0,0 +1,17 @@ +import { SubmissionHookService } from './submission.hook.service' +import { SubmissionNotificationService } from './submission.notification.service' +import { SubmissionService } from './submission.service' +import { SubmissionSetFieldService } from './submission.set.field.service' +import { SubmissionStartService } from './submission.start.service' +import { SubmissionStatisticService } from './submission.statistic.service' +import { SubmissionTokenService } from './submission.token.service' + +export const submissionServices = [ + SubmissionHookService, + SubmissionNotificationService, + SubmissionService, + SubmissionSetFieldService, + SubmissionStartService, + SubmissionStatisticService, + SubmissionTokenService, +] diff --git a/api/src/service/submission/submission.hook.service.ts b/api/src/service/submission/submission.hook.service.ts new file mode 100644 index 00000000..6c6b2a39 --- /dev/null +++ b/api/src/service/submission/submission.hook.service.ts @@ -0,0 +1,74 @@ +import { HttpService } from '@nestjs/axios' +import { Injectable } from '@nestjs/common' +import handlebars from 'handlebars' +import { PinoLogger } from 'nestjs-pino' +import { lastValueFrom } from 'rxjs' +import { serializeError } from 'serialize-error' +import { SubmissionEntity } from '../../entity/submission.entity' + +@Injectable() +export class SubmissionHookService { + constructor( + private httpService: HttpService, + private readonly logger: PinoLogger, + ) { + logger.setContext(this.constructor.name) + } + + public async process(submission: SubmissionEntity): Promise<void> { + await Promise.all(submission.form.hooks.map(async (hook) => { + if (!hook.enabled) { + return + } + + try { + const response = await lastValueFrom(this.httpService.post( + hook.url, + this.format(submission, hook.format) + )) + + this.logger.info({ + submission: submission.id, + form: submission.formId, + webhook: hook.url, + }, 'sent hook') + } catch (e) { + this.logger.error({ + submission: submission.id, + form: submission.formId, + webhook: hook.url, + error: serializeError(e), + }, 'failed to post webhook') + throw e + } + })) + } + + private format(submission: SubmissionEntity, format?: string): any { + const fields = {} + submission.form.fields.forEach((field) => { + fields[field.id] = field + }) + + const data = { + form: submission.form.id, + submission: submission.id, + created: submission.created, + lastModified: submission.lastModified, + fields: submission.fields.map((submissionField) => { + return { + field: submissionField.field.id, + slug: submissionField.field.slug || null, + default_value: submissionField.field.defaultValue, + content: submissionField.content, + } + }), + } + + if (!format) { + return data + } + + return JSON.parse(handlebars.compile(format)(data)) + } +} diff --git a/api/src/service/submission/submission.notification.service.ts b/api/src/service/submission/submission.notification.service.ts new file mode 100644 index 00000000..4202b657 --- /dev/null +++ b/api/src/service/submission/submission.notification.service.ts @@ -0,0 +1,92 @@ +import { MailerService } from '@nestjs-modules/mailer' +import { Injectable } from '@nestjs/common' +import handlebars from 'handlebars' +import htmlToText from 'html-to-text' +import mjml2html from 'mjml' +import { PinoLogger } from 'nestjs-pino' +import { serializeError } from 'serialize-error' +import { SubmissionEntity } from '../../entity/submission.entity' + +@Injectable() +export class SubmissionNotificationService { + constructor( + private readonly nestMailer: MailerService, + private readonly logger: PinoLogger, + ) { + logger.setContext(this.constructor.name) + } + + public async process(submission: SubmissionEntity): Promise<void> { + await Promise.all(submission.form.notifications.map(async (notification) => { + if (!notification.enabled) { + return + } + + try { + const to = this.getEmail( + submission, + notification.toField?.id, + notification.toEmail + ) + const from = this.getEmail( + submission, + notification.fromField?.id, + notification.fromEmail + ) + + const template = handlebars.compile( + notification.htmlTemplate + ) + + const html: string = mjml2html( + template({ + // TODO add variables + }) , + { + minify: true, + } + ).html + + await this.nestMailer.sendMail({ + to, + replyTo: from, + subject: notification.subject, + html, + text: htmlToText.htmlToText(html), + }) + + this.logger.info({ + form: submission.formId, + submission: submission.id, + notification: notification.id, + }, 'sent notification') + } catch (e) { + this.logger.error({ + form: submission.formId, + submission: submission.id, + notification: notification.id, + error: serializeError(e), + }, 'failed to process notification') + throw e + } + })) + } + + private getEmail(submission: SubmissionEntity, fieldId: number, fallback: string): string { + if (!fieldId) { + return fallback + } + + const data = submission.fields.find(field => field.fieldId === fieldId)?.content + + if (!data) { + return fallback + } + + if (typeof data === 'string') { + return data + } + + return fallback + } +} diff --git a/api/src/service/submission/submission.service.ts b/api/src/service/submission/submission.service.ts new file mode 100644 index 00000000..51fe25cc --- /dev/null +++ b/api/src/service/submission/submission.service.ts @@ -0,0 +1,70 @@ +import { InjectRepository } from '@nestjs/typeorm' +import { PinoLogger } from 'nestjs-pino' +import { Repository } from 'typeorm' +import { FormEntity } from '../../entity/form.entity' +import { SubmissionEntity } from '../../entity/submission.entity' +import { SubmissionTokenService } from './submission.token.service' + +export class SubmissionService { + constructor( + @InjectRepository(SubmissionEntity) + private readonly submissionRepository: Repository<SubmissionEntity>, + private readonly tokenService: SubmissionTokenService, + private readonly logger: PinoLogger, + ) { + this.logger.setContext(this.constructor.name) + } + + async isOwner(submission: SubmissionEntity, token: string): Promise<boolean> { + return this.tokenService.verify(token, submission.tokenHash) + } + + async find( + form: FormEntity, + start: number, + limit: number, + sort: any = {}, + filter: { + finished?: boolean, + excludeEmpty?: boolean + } = {} + ): Promise<[SubmissionEntity[], number]> { + const qb = this.submissionRepository.createQueryBuilder('s') + + qb.leftJoinAndSelect('s.fields', 'fields') + + qb.where('s.form = :form', { form: form.id }) + + if (filter.finished === true) { + qb.andWhere('s.percentageComplete = 1') + } + + if (filter.finished === false) { + qb.andWhere('s.percentageComplete < 1') + } + + if (filter.excludeEmpty === true) { + qb.andWhere('s.percentageComplete > 0') + } + + // TODO readd sort + this.logger.debug({ + sort, + }, 'ignored sorting for submissions') + + qb.skip(start) + qb.take(limit) + + return await qb.getManyAndCount() + } + + async findById(id: number): Promise<SubmissionEntity> { + const submission = await this.submissionRepository.findOne(id); + + if (!submission) { + throw new Error('no form found') + } + + return submission + } +} diff --git a/api/src/service/submission/submission.set.field.service.ts b/api/src/service/submission/submission.set.field.service.ts new file mode 100644 index 00000000..0ab66a89 --- /dev/null +++ b/api/src/service/submission/submission.set.field.service.ts @@ -0,0 +1,240 @@ +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import dayjs from 'dayjs' +import { PinoLogger } from 'nestjs-pino' +import { serializeError } from 'serialize-error' +import { Repository } from 'typeorm' +import { SubmissionSetFieldInput } from '../../dto/submission/submission.set.field.input' +import { SubmissionEntity } from '../../entity/submission.entity' +import { SubmissionFieldContent, SubmissionFieldEntity } from '../../entity/submission.field.entity' +import { IdService } from '../id.service' +import { SubmissionHookService } from './submission.hook.service' +import { SubmissionNotificationService } from './submission.notification.service' + +@Injectable() +export class SubmissionSetFieldService { + constructor( + @InjectRepository(SubmissionEntity) + private readonly submissionRepository: Repository<SubmissionEntity>, + @InjectRepository(SubmissionFieldEntity) + private readonly submissionFieldRepository: Repository<SubmissionFieldEntity>, + private readonly webHook: SubmissionHookService, + private readonly notifications: SubmissionNotificationService, + private readonly idService: IdService, + private readonly logger: PinoLogger, + ) { + logger.setContext(this.constructor.name) + } + + async saveField(submission: SubmissionEntity, input: SubmissionSetFieldInput): Promise<void> { + const formFieldId = this.idService.decode(input.field) + + let field = submission.fields.find(field => field.field.id === formFieldId) + + submission.timeElapsed = dayjs().diff(dayjs(submission.created), 'second') + + if (field) { + field.content = this.parseData(field, input.data) + + await this.submissionRepository.save(submission) + await this.submissionFieldRepository.save(field) + } else { + field = new SubmissionFieldEntity() + + field.submission = submission + field.field = submission.form.fields.find(field => field.id === formFieldId) + field.type = field.field.type + field.content = this.parseData(field, input.data) + + submission.fields.push(field) + submission.percentageComplete = (submission.fields.length) / submission.form.fields.length + + // figure out why this cannot be after field save... + await this.submissionRepository.save(submission) + await this.submissionFieldRepository.save(field) + } + + if (submission.percentageComplete === 1) { + await this.finishSubmission(submission) + } + } + + async finishSubmission(submission: SubmissionEntity): Promise<void> { + submission.percentageComplete = 1 + await this.submissionRepository.update({ + id: submission.id, + }, { + percentageComplete: 1, + }) + + this.webHook.process(submission).catch(e => { + this.logger.error({ + submission: submission.id, + form: submission.formId, + error: serializeError(e), + }, 'failed to send webhooks') + }) + + this.notifications.process(submission).catch(e => { + this.logger.error({ + submission: submission.id, + form: submission.formId, + error: serializeError(e), + }, 'failed to send notifications') + }) + } + + private parseData( + field: SubmissionFieldEntity, + data: string + ): SubmissionFieldContent { + let raw: SubmissionFieldContent + + const context = { + field: field.fieldId, + type: field.type, + } + + try { + raw = JSON.parse(data) as SubmissionFieldContent + } catch (e) { + this.logger.warn(context, 'received invalid data for field') + return { value: null } + } + + if (Array.isArray(raw)) { + return raw.map((row: unknown, index) => { + switch (typeof row) { + case 'number': + case 'string': + case 'boolean': + case 'undefined': + return row + } + + if (row === null) { + return row + } + + this.logger.warn({ + ...context, + path: `${index}`, + }, 'invalid data in array') + valid = false + + return null + }) + } + + if ( + [ + 'number', + 'string', + 'boolean', + 'undefined', + ].includes(typeof raw) + ) { + return raw + } + + // now ensure data structure + const result = {} + + let valid = true + + Object.keys(raw).forEach((key) => { + const value = raw[String(key)] + + switch (typeof value) { + case 'number': + case 'string': + case 'boolean': + result[String(key)] = value + return + } + + if (Array.isArray(value)) { + result[String(key)] = value.map((row: unknown, index) => { + switch (typeof row) { + case 'number': + case 'string': + case 'boolean': + case 'undefined': + return row + } + + if (row === null) { + return row + } + + this.logger.warn({ + ...context, + path: `${key}/${index}`, + }, 'invalid data in array') + valid = false + + return null + }) + + return + } + + if (typeof value === 'object') { + result[String(key)] = {} + + for (const subKey of Object.keys(value)) { + const subValue = raw[String(key)][String(subKey)] + + switch (typeof subValue) { + case 'number': + case 'string': + case 'boolean': + result[String(key)][String(subKey)] = subValue + return + } + + if (Array.isArray(subValue)) { + result[String(key)][String(subKey)] = subValue.map((row: unknown, index) => { + switch (typeof row) { + case 'number': + case 'string': + case 'boolean': + case 'undefined': + return row + } + + if (row === null) { + return row + } + + this.logger.warn({ + ...context, + path: `${key}/${subKey}/${index}`, + }, 'invalid data in array') + valid = false + + return null + }) + + return + } + } + } + + this.logger.warn({ + ...context, + path: String(key), + + }, 'invalid data in entry') + + valid = false + }) + + if (!valid) { + this.logger.warn(context, 'invalid data in object entries') + return { value: null } + } + + return result + } +} diff --git a/api/src/service/submission/submission.start.service.ts b/api/src/service/submission/submission.start.service.ts new file mode 100644 index 00000000..6d4492ca --- /dev/null +++ b/api/src/service/submission/submission.start.service.ts @@ -0,0 +1,47 @@ +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import anonymize from 'ip-anonymize' +import { Repository } from 'typeorm' +import { SubmissionStartInput } from '../../dto/submission/submission.start.input' +import { FormEntity } from '../../entity/form.entity' +import { SubmissionEntity } from '../../entity/submission.entity' +import { UserEntity } from '../../entity/user.entity' +import { SubmissionTokenService } from './submission.token.service' + +@Injectable() +export class SubmissionStartService { + constructor( + @InjectRepository(SubmissionEntity) + private readonly submissionRepository: Repository<SubmissionEntity>, + private readonly tokenService: SubmissionTokenService + ) { + } + + async start( + form: FormEntity, + input: SubmissionStartInput, + user?: UserEntity, + ipAddr?: string, + ): Promise<SubmissionEntity> { + const submission = new SubmissionEntity() + + if (!form.anonymousSubmission) { + submission.user = user + } + + submission.form = form + submission.ipAddr = anonymize(ipAddr, 16, 16) || '?' + submission.timeElapsed = 0 + submission.percentageComplete = 0 + + // TODO set country! + + submission.device.language = input.device.language + submission.device.name = input.device.name + submission.device.type = input.device.type + + submission.tokenHash = await this.tokenService.hash(input.token) + + return await this.submissionRepository.save(submission) + } +} diff --git a/api/src/service/submission/submission.statistic.service.ts b/api/src/service/submission/submission.statistic.service.ts new file mode 100644 index 00000000..4388d633 --- /dev/null +++ b/api/src/service/submission/submission.statistic.service.ts @@ -0,0 +1,15 @@ +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { SubmissionEntity } from '../../entity/submission.entity' + +export class SubmissionStatisticService { + constructor( + @InjectRepository(SubmissionEntity) + private readonly submissionRepository: Repository<SubmissionEntity>, + ) { + } + + async getTotal(): Promise<number> { + return await this.submissionRepository.count(); + } +} diff --git a/api/src/service/submission/submission.token.service.ts b/api/src/service/submission/submission.token.service.ts new file mode 100644 index 00000000..1490a483 --- /dev/null +++ b/api/src/service/submission/submission.token.service.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@nestjs/common' +import * as bcrypt from 'bcrypt' + +@Injectable() +export class SubmissionTokenService { + async hash(token: string): Promise<string> { + return bcrypt.hash(token, 4) + } + + async verify(token: string, hash: string): Promise<boolean> { + return await bcrypt.compare(token, hash) + } +} diff --git a/api/src/service/user/boot.service.ts b/api/src/service/user/boot.service.ts new file mode 100644 index 00000000..83f25e17 --- /dev/null +++ b/api/src/service/user/boot.service.ts @@ -0,0 +1,61 @@ +import { Injectable, OnApplicationBootstrap } from '@nestjs/common' +import { ConfigService } from '@nestjs/config' +import { PinoLogger } from 'nestjs-pino' +import { serializeError } from 'serialize-error' +import { UserCreateService } from './user.create.service' +import { UserService } from './user.service' + +@Injectable() +export class BootService implements OnApplicationBootstrap { + constructor( + private readonly createService: UserCreateService, + private readonly userService: UserService, + private readonly configService: ConfigService, + private readonly logger: PinoLogger, + ) { + logger.setContext(this.constructor.name) + } + + async onApplicationBootstrap(): Promise<void> { + const create = this.configService.get<string>('CREATE_ADMIN', 'false') + + if (!create || [ + 'false', '0', 'no', '', + ].includes(create.toLowerCase())) { + return + } + + this.logger.warn('admin user check is still enabled! once your use has been created this should be disabled') + + const username = this.configService.get<string>('ADMIN_USERNAME', 'root') + const email = this.configService.get<string>('ADMIN_EMAIL', 'admin@ohmyform.com') + const password = this.configService.get<string>('ADMIN_PASSWORD', 'root') + + if (await this.userService.usernameInUse(username)) { + this.logger.info('username already exists, skip creating') + return + } + + if (await this.userService.emailInUse(email)) { + this.logger.info('email already exists, skip creating') + return + } + + try { + await this.createService.create({ + username, + email, + password, + }, [ + 'user', 'admin', 'superuser', + ]) + } catch (e) { + this.logger.error({ + error: serializeError(e), + }, 'could not create admin user') + return + } + + this.logger.info('new root user created') + } +} diff --git a/api/src/service/user/index.ts b/api/src/service/user/index.ts new file mode 100644 index 00000000..3ad6c279 --- /dev/null +++ b/api/src/service/user/index.ts @@ -0,0 +1,17 @@ +import { BootService } from './boot.service' +import { UserCreateService } from './user.create.service' +import { UserDeleteService } from './user.delete.service' +import { UserService } from './user.service' +import { UserStatisticService } from './user.statistic.service' +import { UserTokenService } from './user.token.service' +import { UserUpdateService } from './user.update.service' + +export const userServices = [ + BootService, + UserCreateService, + UserDeleteService, + UserService, + UserStatisticService, + UserTokenService, + UserUpdateService, +] diff --git a/api/src/service/user/user.create.service.ts b/api/src/service/user/user.create.service.ts new file mode 100644 index 00000000..fc2a587b --- /dev/null +++ b/api/src/service/user/user.create.service.ts @@ -0,0 +1,96 @@ +import { Injectable } from '@nestjs/common' +import { ConfigService } from '@nestjs/config' +import { InjectRepository } from '@nestjs/typeorm' +import crypto from 'crypto' +import { PinoLogger } from 'nestjs-pino' +import { Repository } from 'typeorm' +import { rolesType } from '../../config/roles' +import { UserCreateInput } from '../../dto/user/user.create.input' +import { UserEntity } from '../../entity/user.entity' +import { PasswordService } from '../auth/password.service' +import { MailService } from '../mail.service' +import { SettingService } from '../setting.service' +import { UserTokenService } from './user.token.service' + +@Injectable() +export class UserCreateService { + constructor( + @InjectRepository(UserEntity) + private readonly userRepository: Repository<UserEntity>, + private readonly mailerService: MailService, + private readonly logger: PinoLogger, + private readonly passwordService: PasswordService, + private readonly settingService: SettingService, + private readonly configService: ConfigService, + private readonly userTokenService: UserTokenService, + ) { + logger.setContext(this.constructor.name) + } + + private getDefaultRoles(): rolesType { + const roleSetting = this.settingService.getByKey('DEFAULT_ROLE') + + switch (roleSetting.value) { + case 'superuser': + return [ + 'superuser', + 'admin', + 'user', + ] + + case 'admin': + return ['admin', 'user'] + } + + return ['user'] + } + + async create(input: UserCreateInput, roles?: rolesType): Promise<UserEntity> { + if (undefined !== await this.userRepository.findOne({ username: input.username })) { + throw new Error('username already in use') + } + + if (undefined !== await this.userRepository.findOne({ email: input.email })) { + throw new Error('email already in use') + } + + const confirmToken = crypto.randomBytes(30).toString('base64') + + let user = new UserEntity() + + user.provider = 'local' + user.username = input.username + user.email = input.email + user.firstName = input.firstName + user.lastName = input.lastName + user.language = input.language ?? 'en' + user.roles = roles ? roles : this.getDefaultRoles() + user.passwordHash = await this.passwordService.hash(input.password) + user.token = await this.userTokenService.hash(confirmToken) + + user = await this.userRepository.save(user) + + const confirmUrl = [ + this.configService.get('BASE_URL', 'http://localhost'), + this.configService.get('USER_CONFIRM_PATH', '/confirm?token={{token}}'), + ] + .join('') + .replace('{{token}}', confirmToken) + + const sent = await this.mailerService.send( + user.email, + 'user/created', + { + username: user.username, + confirm: confirmUrl, + } + ) + + // so send email + if (!sent) { + this.logger.warn('failed to send email for user creation') + } + + return user + } +} diff --git a/api/src/service/user/user.delete.service.ts b/api/src/service/user/user.delete.service.ts new file mode 100644 index 00000000..96c23586 --- /dev/null +++ b/api/src/service/user/user.delete.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { UserEntity } from '../../entity/user.entity' + +@Injectable() +export class UserDeleteService { + constructor( + @InjectRepository(UserEntity) + private readonly userRepository: Repository<UserEntity>, + ) { + } + + async delete(id: number): Promise<void> { + await this.userRepository.delete(id) + } +} diff --git a/api/src/service/user/user.service.ts b/api/src/service/user/user.service.ts new file mode 100644 index 00000000..303adabf --- /dev/null +++ b/api/src/service/user/user.service.ts @@ -0,0 +1,74 @@ +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { UserEntity } from '../../entity/user.entity' + +@Injectable() +export class UserService { + constructor( + @InjectRepository(UserEntity) + private readonly userRepository: Repository<UserEntity>, + ) { + } + + isSuperuser(user: UserEntity): boolean { + return user.roles.includes('superuser') + } + + async find(start: number, limit: number, sort: any = {}): Promise<[UserEntity[], number]> { + const qb = this.userRepository.createQueryBuilder('u') + + // TODO readd sort + + qb.skip(start) + qb.take(limit) + + return await qb.getManyAndCount() + } + + async findById(id: number): Promise<UserEntity> { + const user = await this.userRepository.findOne(id); + + if (!user) { + throw new Error('no user found') + } + + return user + } + + async findByUsername(username: string): Promise<UserEntity> { + const user = await this.userRepository.findOne({ + username, + }) + + if (!user) { + throw new Error('no user found') + } + + return user + } + + async findByEmail(email: string): Promise<UserEntity> { + const user = await this.userRepository.findOne({ + email, + }) + + if (!user) { + throw new Error('no user found') + } + + return user + } + + async usernameInUse(username: string): Promise<boolean> { + return 0 !== await this.userRepository.count({ + username, + }) + } + + async emailInUse(email: string): Promise<boolean> { + return 0 !== await this.userRepository.count({ + email, + }) + } +} diff --git a/api/src/service/user/user.statistic.service.ts b/api/src/service/user/user.statistic.service.ts new file mode 100644 index 00000000..b7444a4b --- /dev/null +++ b/api/src/service/user/user.statistic.service.ts @@ -0,0 +1,15 @@ +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { UserEntity } from '../../entity/user.entity' + +export class UserStatisticService { + constructor( + @InjectRepository(UserEntity) + private readonly userRepository: Repository<UserEntity>, + ) { + } + + async getTotal(): Promise<number> { + return await this.userRepository.count(); + } +} diff --git a/api/src/service/user/user.token.service.ts b/api/src/service/user/user.token.service.ts new file mode 100644 index 00000000..0e6d431d --- /dev/null +++ b/api/src/service/user/user.token.service.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@nestjs/common' +import * as bcrypt from 'bcrypt' + +@Injectable() +export class UserTokenService { + async hash(token: string): Promise<string> { + return bcrypt.hash(token, 4) + } + + async verify(token: string, hash: string): Promise<boolean> { + return await bcrypt.compare(token, hash) + } +} diff --git a/api/src/service/user/user.update.service.ts b/api/src/service/user/user.update.service.ts new file mode 100644 index 00000000..f2d2ecce --- /dev/null +++ b/api/src/service/user/user.update.service.ts @@ -0,0 +1,69 @@ +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { rolesType } from '../../config/roles' +import { UserUpdateInput } from '../../dto/user/user.update.input' +import { UserEntity } from '../../entity/user.entity' +import { PasswordService } from '../auth/password.service' + +@Injectable() +export class UserUpdateService { + constructor( + @InjectRepository(UserEntity) + private readonly userRepository: Repository<UserEntity>, + private readonly passwordService: PasswordService, + ) { + } + + async update(user: UserEntity, input: UserUpdateInput): Promise<UserEntity> { + if (this.shouldUpdate(input, user, 'firstName')) { + user.firstName = input.firstName + } + + if (this.shouldUpdate(input, user, 'lastName')) { + user.lastName = input.lastName + } + + if (this.shouldUpdate(input, user, 'email')) { + user.email = input.email + user.emailVerified = false + // TODO request email verification + + if (undefined !== await this.userRepository.findOne({ email: input.email })) { + throw new Error('email already in use') + } + } + + if (this.shouldUpdate(input, user, 'username')) { + user.username = input.username + } + + if (this.shouldUpdate(input, user, 'roles')) { + user.roles = input.roles as rolesType + } + + if (this.shouldUpdate(input, user, 'language')) { + user.language = input.language + } + + if (input.password !== undefined) { + user.passwordHash = await this.passwordService.hash(input.password) + } + + await this.userRepository.save(user) + + return user + } + + private shouldUpdate( + input: UserUpdateInput, + user: UserEntity, + property: keyof UserUpdateInput + ): boolean { + if (input[property] === undefined) { + return false + } + + return input[property] == user[property] + } +} diff --git a/api/tsconfig.build.json b/api/tsconfig.build.json new file mode 100644 index 00000000..64f86c6b --- /dev/null +++ b/api/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] +} diff --git a/api/tsconfig.json b/api/tsconfig.json new file mode 100644 index 00000000..8568927d --- /dev/null +++ b/api/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "esModuleInterop": true, + "experimentalDecorators": true, + "target": "es2017", + "skipLibCheck": true, + "sourceMap": true, + "outDir": "./dist", + "baseUrl": "./", + "incremental": true, + "allowSyntheticDefaultImports": true + }, + "include": ["src/**/*"], + "exclude": [ + "node_modules", + "dist" + ] +} diff --git a/api/yarn.lock b/api/yarn.lock new file mode 100644 index 00000000..7afcfc7f --- /dev/null +++ b/api/yarn.lock @@ -0,0 +1,9563 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.1.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34" + integrity sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg== + dependencies: + "@jridgewell/trace-mapping" "^0.3.0" + +"@angular-devkit/core@13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-13.0.2.tgz#1ef92388464ca86d22b21c6ebcb9fc3b6a16c374" + integrity sha512-I4co4GH+iu0tns+UXfMtjJISO+cLpaUuiEH6kf0wF5cqjaIeluA9UjIRnxuNbdTW8iE2xVj/UWhQfHe/Ncp76w== + dependencies: + ajv "8.6.3" + ajv-formats "2.1.1" + fast-json-stable-stringify "2.1.0" + magic-string "0.25.7" + rxjs "6.6.7" + source-map "0.7.3" + +"@angular-devkit/core@13.2.3": + version "13.2.3" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-13.2.3.tgz#a5770c7a5e50d1b09e5a41ccb7cf0af140a9e168" + integrity sha512-/47RA8qmWzeS60xSdaprIn1MiSv0Iw83t0M9/ENH7irFS5vMAq62NCcwiWXH59pZmvvLbF+7xy/RgYUZLr4nHQ== + dependencies: + ajv "8.9.0" + ajv-formats "2.1.1" + fast-json-stable-stringify "2.1.0" + magic-string "0.25.7" + rxjs "6.6.7" + source-map "0.7.3" + +"@angular-devkit/core@13.2.4": + version "13.2.4" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-13.2.4.tgz#3de82f14434db168093d8d6b4df84a10594612b8" + integrity sha512-hSw1JWA/6dDAF/xleQRXGtzHphfU49TMUhvAoAmsmmz3NAn03xLy1dtqdIXIf+TkFXVvZDaAB2mW8KfRV67GFg== + dependencies: + ajv "8.9.0" + ajv-formats "2.1.1" + fast-json-stable-stringify "2.1.0" + magic-string "0.25.7" + rxjs "6.6.7" + source-map "0.7.3" + +"@angular-devkit/schematics-cli@13.2.3": + version "13.2.3" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics-cli/-/schematics-cli-13.2.3.tgz#95d834b7f08eac05a318dad9a4865500e2e2acf0" + integrity sha512-huCAno7u2K3Td3oiB41ax5AtoMyij6NmJsUxhpYQkZxnNsio9CKeSJnOuzml8SAILExc7sHFNW5A+9BeLluE4A== + dependencies: + "@angular-devkit/core" "13.2.3" + "@angular-devkit/schematics" "13.2.3" + ansi-colors "4.1.1" + inquirer "8.2.0" + minimist "1.2.5" + symbol-observable "4.0.0" + +"@angular-devkit/schematics@13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-13.0.2.tgz#975e5e1494261d5efac2848f42e83c7cc25a32ed" + integrity sha512-qrTe1teQptgP8gmVy6QX0T4dNfnNipEv+cM2cr7JXOmkPpwF+6oBDrTRIJ55t6rziqrXHJ3rxjKm1aHAxFrIEQ== + dependencies: + "@angular-devkit/core" "13.0.2" + jsonc-parser "3.0.0" + magic-string "0.25.7" + ora "5.4.1" + rxjs "6.6.7" + +"@angular-devkit/schematics@13.2.3": + version "13.2.3" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-13.2.3.tgz#c2acb68ba798f4ab115bee73f078d98f5b20d21c" + integrity sha512-+dyC4iKV0huvpjiuz4uyjLNK3FsCIp/Ghv5lXvhG6yok/dCAubsJItJOxi6G16aVCzG/E9zbsDfm9fNMyVOkgQ== + dependencies: + "@angular-devkit/core" "13.2.3" + jsonc-parser "3.0.0" + magic-string "0.25.7" + ora "5.4.1" + rxjs "6.6.7" + +"@angular-devkit/schematics@13.2.4": + version "13.2.4" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-13.2.4.tgz#dc22c94f52e1123cad8e03a09a5e80663cda6c9d" + integrity sha512-VMhYa4cDu5yE31OvHncAd15Rmlchih/Sr6sxFsIwkg4xzRNIIZCtwqxVXgf0TiTN9zrvlvzK7nhPqTGNqqYb2A== + dependencies: + "@angular-devkit/core" "13.2.4" + jsonc-parser "3.0.0" + magic-string "0.25.7" + ora "5.4.1" + rxjs "6.6.7" + +"@apollo/client@~3.2.5 || ~3.3.0 || ~3.4.0": + version "3.4.17" + resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.4.17.tgz#4972e19a49809e16d17c5adc67f45623a6dac135" + integrity sha512-MDt2rwMX1GqodiVEKJqmDmAz8xr0qJmq5PdWeIt0yDaT4GOkKYWZiWkyfhfv3raTk8PyJvbsNG9q2CqmUrlGfg== + dependencies: + "@graphql-typed-document-node/core" "^3.0.0" + "@wry/context" "^0.6.0" + "@wry/equality" "^0.5.0" + "@wry/trie" "^0.3.0" + graphql-tag "^2.12.3" + hoist-non-react-statics "^3.3.2" + optimism "^0.16.1" + prop-types "^15.7.2" + symbol-observable "^4.0.0" + ts-invariant "^0.9.0" + tslib "^2.3.0" + zen-observable-ts "~1.1.0" + +"@apollo/protobufjs@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@apollo/protobufjs/-/protobufjs-1.2.2.tgz#4bd92cd7701ccaef6d517cdb75af2755f049f87c" + integrity sha512-vF+zxhPiLtkwxONs6YanSt1EpwpGilThpneExUN5K3tCymuxNnVq2yojTvnpRjv2QfsEIt/n7ozPIIzBLwGIDQ== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.0" + "@types/node" "^10.1.0" + long "^4.0.0" + +"@apollographql/apollo-tools@^0.5.1": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@apollographql/apollo-tools/-/apollo-tools-0.5.2.tgz#01750a655731a198c3634ee819c463254a7c7767" + integrity sha512-KxZiw0Us3k1d0YkJDhOpVH5rJ+mBfjXcgoRoCcslbgirjgLotKMzOcx4PZ7YTEvvEROmvG7X3Aon41GvMmyGsw== + +"@apollographql/graphql-playground-html@1.6.29": + version "1.6.29" + resolved "https://registry.yarnpkg.com/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.29.tgz#a7a646614a255f62e10dcf64a7f68ead41dec453" + integrity sha512-xCcXpoz52rI4ksJSdOCxeOCn2DLocxwHf9dVT/Q90Pte1LX+LY+91SFtJF3KXVHH8kEin+g1KKCQPKBjZJfWNA== + dependencies: + xss "^1.0.8" + +"@ardatan/aggregate-error@^0.0.6": + version "0.0.6" + resolved "https://registry.yarnpkg.com/@ardatan/aggregate-error/-/aggregate-error-0.0.6.tgz#fe6924771ea40fc98dc7a7045c2e872dc8527609" + integrity sha512-vyrkEHG1jrukmzTPtyWB4NLPauUw5bQeg4uhn8f+1SSynmrOcyvlb1GKQjjgoBzElLdfXCRYX8UnBlhklOHYRQ== + dependencies: + tslib "~2.0.1" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.8.3": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + +"@babel/compat-data@^7.16.4": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e" + integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q== + +"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.2": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.7.tgz#db990f931f6d40cb9b87a0dc7d2adc749f1dcbcf" + integrity sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.7" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helpers" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + +"@babel/core@^7.8.0": + version "7.17.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.5.tgz#6cd2e836058c28f06a4ca8ee7ed955bbf37c8225" + integrity sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.3" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helpers" "^7.17.2" + "@babel/parser" "^7.17.3" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + +"@babel/generator@^7.16.7", "@babel/generator@^7.7.2": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.7.tgz#b42bf46a3079fa65e1544135f32e7958f048adbb" + integrity sha512-/ST3Sg8MLGY5HVYmrjOgL60ENux/HfO/CsUh7y4MalThufhE/Ff/6EibFDHi4jiDCaWfJKoqbE6oTh21c5hrRg== + dependencies: + "@babel/types" "^7.16.7" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/generator@^7.17.3": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.3.tgz#a2c30b0c4f89858cb87050c3ffdfd36bdf443200" + integrity sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg== + dependencies: + "@babel/types" "^7.17.0" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-compilation-targets@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b" + integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA== + dependencies: + "@babel/compat-data" "^7.16.4" + "@babel/helper-validator-option" "^7.16.7" + browserslist "^4.17.5" + semver "^6.3.0" + +"@babel/helper-environment-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" + integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== + dependencies: + "@babel/helper-get-function-arity" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helper-get-function-arity@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" + integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-hoist-variables@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-imports@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-transforms@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz#7665faeb721a01ca5327ddc6bba15a5cb34b6a41" + integrity sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" + integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== + +"@babel/helper-simple-access@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7" + integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + +"@babel/helper-validator-option@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" + integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== + +"@babel/helpers@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.7.tgz#7e3504d708d50344112767c3542fc5e357fffefc" + integrity sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw== + dependencies: + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helpers@^7.17.2": + version "7.17.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.2.tgz#23f0a0746c8e287773ccd27c14be428891f63417" + integrity sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ== + dependencies: + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.0" + "@babel/types" "^7.17.0" + +"@babel/highlight@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.7.tgz#81a01d7d675046f0d96f82450d9d9578bdfd6b0b" + integrity sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.6.0", "@babel/parser@^7.9.6": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.7.tgz#d372dda9c89fcec340a82630a9f533f2fe15877e" + integrity sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA== + +"@babel/parser@^7.17.3": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.3.tgz#b07702b982990bf6fdc1da5049a23fece4c5c3d0" + integrity sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz#39c9b55ee153151990fb038651d58d3fd03f98f8" + integrity sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/runtime@^7.14.6": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa" + integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.16.7", "@babel/template@^7.3.3": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/traverse@^7.16.7", "@babel/traverse@^7.7.2": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.7.tgz#dac01236a72c2560073658dd1a285fe4e0865d76" + integrity sha512-8KWJPIb8c2VvY8AJrydh6+fVRo2ODx1wYBU2398xJVq0JomuLBZmVQzLPBblJgHIGYG4znCpUZUZ0Pt2vdmVYQ== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/traverse@^7.17.0", "@babel/traverse@^7.17.3": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" + integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.3" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.17.3" + "@babel/types" "^7.17.0" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.16.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.6.1", "@babel/types@^7.9.6": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.7.tgz#4ed19d51f840ed4bd5645be6ce40775fecf03159" + integrity sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + +"@babel/types@^7.17.0": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" + integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@cspotcode/source-map-consumer@0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" + integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== + +"@cspotcode/source-map-support@0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" + integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== + dependencies: + "@cspotcode/source-map-consumer" "0.8.0" + +"@eslint/eslintrc@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.0.tgz#7ce1547a5c46dfe56e1e45c3c9ed18038c721c6a" + integrity sha512-igm9SjJHNEJRiUnecP/1R5T3wKLEJ7pL6e2P+GUSfCd0dGjPYYZve08uzw8L2J8foVHFz+NGu12JxRcU2gGo6w== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.3.1" + globals "^13.9.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@gar/promisify@^1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" + integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== + +"@graphql-tools/merge@8.2.2": + version "8.2.2" + resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.2.2.tgz#433566c662a33f5a9c3cc5f3ce3753fb0019477a" + integrity sha512-2DyqhIOMUMKbCPqo8p6xSdll2OBcBxGdOrxlJJlFQvinsSaYqp/ct3dhAxNtzaIcvSVgXvttQqfD7O2ziFtE7Q== + dependencies: + "@graphql-tools/utils" "^8.5.1" + tslib "~2.3.0" + +"@graphql-tools/merge@^8.2.1": + version "8.2.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.2.1.tgz#bf83aa06a0cfc6a839e52a58057a84498d0d51ff" + integrity sha512-Q240kcUszhXiAYudjuJgNuLgy9CryDP3wp83NOZQezfA6h3ByYKU7xI6DiKrdjyVaGpYN3ppUmdj0uf5GaXzMA== + dependencies: + "@graphql-tools/utils" "^8.5.1" + tslib "~2.3.0" + +"@graphql-tools/merge@^8.2.3": + version "8.2.3" + resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.2.3.tgz#a2861fec230ee7be9dc42d72fed2ac075c31669f" + integrity sha512-XCSmL6/Xg8259OTWNp69B57CPWiVL69kB7pposFrufG/zaAlI9BS68dgzrxmmSqZV5ZHU4r/6Tbf6fwnEJGiSw== + dependencies: + "@graphql-tools/utils" "^8.6.2" + tslib "~2.3.0" + +"@graphql-tools/mock@^8.1.2": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/mock/-/mock-8.5.0.tgz#7e7b8ce579413f1c8113f55a45a60af01b384c73" + integrity sha512-J4HZFPT78RbVFpm/yqY/1UeDVkvXQW6RMxZbOlV9xpC4ufFw/AzUlBnaXKhWgkRgIPf7RZZidahoz1W+dt/Juw== + dependencies: + "@graphql-tools/schema" "^8.3.1" + "@graphql-tools/utils" "^8.5.1" + fast-json-stable-stringify "^2.1.0" + tslib "~2.3.0" + +"@graphql-tools/schema@8.3.1", "@graphql-tools/schema@^8.0.0", "@graphql-tools/schema@^8.3.1": + version "8.3.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.3.1.tgz#1ee9da494d2da457643b3c93502b94c3c4b68c74" + integrity sha512-3R0AJFe715p4GwF067G5i0KCr/XIdvSfDLvTLEiTDQ8V/hwbOHEKHKWlEBHGRQwkG5lwFQlW1aOn7VnlPERnWQ== + dependencies: + "@graphql-tools/merge" "^8.2.1" + "@graphql-tools/utils" "^8.5.1" + tslib "~2.3.0" + value-or-promise "1.0.11" + +"@graphql-tools/schema@^8.2.0": + version "8.3.2" + resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.3.2.tgz#5b949d7a2cc3936f73507d91cc609996f1266d11" + integrity sha512-77feSmIuHdoxMXRbRyxE8rEziKesd/AcqKV6fmxe7Zt+PgIQITxNDew2XJJg7qFTMNM43W77Ia6njUSBxNOkwg== + dependencies: + "@graphql-tools/merge" "^8.2.3" + "@graphql-tools/utils" "^8.6.2" + tslib "~2.3.0" + value-or-promise "1.0.11" + +"@graphql-tools/utils@8.6.1": + version "8.6.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.6.1.tgz#52c7eb108f2ca2fd01bdba8eef85077ead1bf882" + integrity sha512-uxcfHCocp4ENoIiovPxUWZEHOnbXqj3ekWc0rm7fUhW93a1xheARNHcNKhwMTR+UKXVJbTFQdGI1Rl5XdyvDBg== + dependencies: + tslib "~2.3.0" + +"@graphql-tools/utils@^8.5.1": + version "8.5.5" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.5.5.tgz#019ddb99719feb19602afdb537c06e463df674a9" + integrity sha512-y7zRXWIUI73X+9/rf/0KzrNFMlpRKFfzLiwdbIeWwgLs+NV9vfUOoVkX8luXX6LwQxhSypHATMiwZGM2ro/wJA== + dependencies: + tslib "~2.3.0" + +"@graphql-tools/utils@^8.6.2": + version "8.6.2" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.6.2.tgz#095408135f091aac68fe18a0a21b708e685500da" + integrity sha512-x1DG0cJgpJtImUlNE780B/dfp8pxvVxOD6UeykFH5rHes26S4kGokbgU8F1IgrJ1vAPm/OVBHtd2kicTsPfwdA== + dependencies: + tslib "~2.3.0" + +"@graphql-typed-document-node/core@^3.0.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.1.tgz#076d78ce99822258cf813ecc1e7fa460fa74d052" + integrity sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg== + +"@humanwhocodes/config-array@^0.9.2": + version "0.9.2" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914" + integrity sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.5.1.tgz#260fe7239602fe5130a94f1aa386eff54b014bba" + integrity sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^27.5.1" + jest-util "^27.5.1" + slash "^3.0.0" + +"@jest/core@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.5.1.tgz#267ac5f704e09dc52de2922cbf3af9edcd64b626" + integrity sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ== + dependencies: + "@jest/console" "^27.5.1" + "@jest/reporters" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^27.5.1" + jest-config "^27.5.1" + jest-haste-map "^27.5.1" + jest-message-util "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-resolve-dependencies "^27.5.1" + jest-runner "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + jest-watcher "^27.5.1" + micromatch "^4.0.4" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74" + integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA== + dependencies: + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + +"@jest/fake-timers@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74" + integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ== + dependencies: + "@jest/types" "^27.5.1" + "@sinonjs/fake-timers" "^8.0.1" + "@types/node" "*" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-util "^27.5.1" + +"@jest/globals@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.5.1.tgz#7ac06ce57ab966566c7963431cef458434601b2b" + integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/types" "^27.5.1" + expect "^27.5.1" + +"@jest/reporters@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.5.1.tgz#ceda7be96170b03c923c37987b64015812ffec04" + integrity sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-haste-map "^27.5.1" + jest-resolve "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^8.1.0" + +"@jest/source-map@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf" + integrity sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.9" + source-map "^0.6.0" + +"@jest/test-result@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.5.1.tgz#56a6585fa80f7cdab72b8c5fc2e871d03832f5bb" + integrity sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag== + dependencies: + "@jest/console" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz#4057e0e9cea4439e544c6353c6affe58d095745b" + integrity sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ== + dependencies: + "@jest/test-result" "^27.5.1" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-runtime "^27.5.1" + +"@jest/transform@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409" + integrity sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^27.5.1" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-regex-util "^27.5.1" + jest-util "^27.5.1" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + +"@jest/types@^27.4.2": + version "27.4.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.4.2.tgz#96536ebd34da6392c2b7c7737d693885b5dd44a5" + integrity sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + +"@jest/types@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" + integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + +"@jonkemp/package-utils@^1.0.6": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@jonkemp/package-utils/-/package-utils-1.0.7.tgz#6550ea56c9bd61bb4161c99e7ca38b972ad3a25d" + integrity sha512-OoK+K1RmhtS8SlORrlH7sW0CNdrnm0BxKNcv4pQIk6y6VORsHiX91gV3dh6XD2eS7J+iCXROcu5sGuH0tjmNEQ== + +"@josephg/resolvable@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@josephg/resolvable/-/resolvable-1.0.1.tgz#69bc4db754d79e1a2f17a650d3466e038d94a5eb" + integrity sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg== + +"@jridgewell/resolve-uri@^3.0.3": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" + integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.11" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" + integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== + +"@jridgewell/trace-mapping@^0.3.0": + version "0.3.4" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz#f6a0832dffd5b8a6aaa633b7d9f8e8e94c83a0c3" + integrity sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@mapbox/node-pre-gyp@^1.0.0": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz#32abc8a5c624bc4e46c43d84dfb8b26d33a96f58" + integrity sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg== + dependencies: + detect-libc "^1.0.3" + https-proxy-agent "^5.0.0" + make-dir "^3.1.0" + node-fetch "^2.6.5" + nopt "^5.0.0" + npmlog "^5.0.1" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.11" + +"@nestjs-modules/mailer@^1.6.1": + version "1.6.1" + resolved "https://registry.yarnpkg.com/@nestjs-modules/mailer/-/mailer-1.6.1.tgz#741a095e7450a19ec1925b733ce9b98bba0f51fb" + integrity sha512-ZfJFB3sIQyYr52g7HRUr3VOyZZSPBI+89hcm3hvLvP3flTJs/g98QbZxWR/mH2BzQVHdCAzlP98Qw/KQULPM4w== + dependencies: + glob "7.1.7" + inline-css "3.0.0" + preview-email "3.0.4" + optionalDependencies: + "@types/ejs" "^3.0.3" + "@types/pug" "2.0.5" + ejs "^3.1.2" + handlebars "^4.7.6" + pug "^3.0.1" + +"@nestjs/apollo@^10.0.5": + version "10.0.5" + resolved "https://registry.yarnpkg.com/@nestjs/apollo/-/apollo-10.0.5.tgz#58d767ef013ae4f48760d4958629d5862ef75fb4" + integrity sha512-HGM/nnYjS4t4W+lvvv4lo1ZKQvClDZvW/6l8aWEKtmbogeR0jOEcUQGLQs9S5J9TgcqcoPCIkBLn4VkEdS/K5A== + dependencies: + iterall "1.3.0" + lodash.omit "4.5.0" + +"@nestjs/axios@^0.0.6": + version "0.0.6" + resolved "https://registry.yarnpkg.com/@nestjs/axios/-/axios-0.0.6.tgz#1d641822bfe1d5fe72f6dcc77a43c3007fd916b3" + integrity sha512-RgtKUziiEPRtWS3KJNDqq0Epw9ffFdIKAtcj6cXnWeJvgHLwnDkw2rUsmHpDYrhszG+8bc4H8sDygRKwNPPAQA== + dependencies: + axios "0.26.0" + +"@nestjs/cli@^8.2.1": + version "8.2.1" + resolved "https://registry.yarnpkg.com/@nestjs/cli/-/cli-8.2.1.tgz#3d107e99058735d7511b774a26bc253e8589aa8b" + integrity sha512-GnwpORSIkGl6N6yWPONq1wwZ8+zltr3vF1M/2qzupDnXOAvSSCh1otDQRAmeOf3uIIeCiCsJEEx79kRnT7Zdrw== + dependencies: + "@angular-devkit/core" "13.2.3" + "@angular-devkit/schematics" "13.2.3" + "@angular-devkit/schematics-cli" "13.2.3" + "@nestjs/schematics" "^8.0.3" + chalk "3.0.0" + chokidar "3.5.3" + cli-table3 "0.6.1" + commander "4.1.1" + fork-ts-checker-webpack-plugin "6.5.0" + inquirer "7.3.3" + node-emoji "1.11.0" + ora "5.4.1" + os-name "4.0.1" + rimraf "3.0.2" + shelljs "0.8.5" + source-map-support "0.5.21" + tree-kill "1.2.2" + tsconfig-paths "3.12.0" + tsconfig-paths-webpack-plugin "3.5.2" + typescript "4.5.5" + webpack "5.66.0" + webpack-node-externals "3.0.0" + +"@nestjs/common@^8.3.1": + version "8.3.1" + resolved "https://registry.yarnpkg.com/@nestjs/common/-/common-8.3.1.tgz#4d5fcc879865acf012733cc5c0f804a46de89fe3" + integrity sha512-3kKeaRXn1c2jf0ihVu6bvQ9Ok+7CkqkU0Ggi5NjWXA2oVRs3vPzr2d5DEvqUqY9JZpT5qGvzRDyKzaPlekxD2A== + dependencies: + axios "0.26.0" + iterare "1.2.1" + tslib "2.3.1" + uuid "8.3.2" + +"@nestjs/config@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@nestjs/config/-/config-1.2.0.tgz#a4eb58390dd8145b761ee0c8e98e78c8471cabb1" + integrity sha512-GGZOj2g6EMZ23orsQqeD2Vs5E2ZrmAiB0qCGvERv+5nQmZjY4nKkisG4awQsym1uotmmzgtsd9lOiKqTIFONhA== + dependencies: + dotenv "16.0.0" + dotenv-expand "8.0.1" + lodash "4.17.21" + uuid "8.3.2" + +"@nestjs/core@^8.3.1": + version "8.3.1" + resolved "https://registry.yarnpkg.com/@nestjs/core/-/core-8.3.1.tgz#737c2aef5529da7946de82414e7065ab01c27bad" + integrity sha512-tdZkhqopd5xSVjogezpP4tPZWntyUNzwOGrVJCQ3RMVH12oxyDMpaMtDnCNvV7cSyoSyHzepMh5nCgLsZ/c88w== + dependencies: + "@nuxtjs/opencollective" "0.3.2" + fast-safe-stringify "2.1.1" + iterare "1.2.1" + object-hash "2.2.0" + path-to-regexp "3.2.0" + tslib "2.3.1" + uuid "8.3.2" + +"@nestjs/graphql@^10.0.5": + version "10.0.5" + resolved "https://registry.yarnpkg.com/@nestjs/graphql/-/graphql-10.0.5.tgz#8afd8b2869b34035d16e56a4a3beacc00df16b43" + integrity sha512-ok7dXJOIw3hqoler3IP/ehm2S9FBQLgmjKguuPB4OMe/pk4TbcDXzQO7SPzwkgVMB/H/fhol9+kHoCXrCMHf7w== + dependencies: + "@graphql-tools/merge" "8.2.2" + "@graphql-tools/schema" "8.3.1" + "@graphql-tools/utils" "8.6.1" + "@nestjs/mapped-types" "1.0.1" + chokidar "3.5.3" + fast-glob "3.2.11" + graphql-tag "2.12.6" + graphql-ws "5.5.5" + lodash "4.17.21" + normalize-path "3.0.0" + subscriptions-transport-ws "0.11.0" + tslib "2.3.1" + uuid "8.3.2" + ws "8.5.0" + +"@nestjs/jwt@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@nestjs/jwt/-/jwt-8.0.0.tgz#6c811c17634252dd1dcd5dabf409dbd692b812da" + integrity sha512-fz2LQgYY2zmuD8S+8UE215anwKyXlnB/1FwJQLVR47clNfMeFMK8WCxmn6xdPhF5JKuV1crO6FVabb1qWzDxqQ== + dependencies: + "@types/jsonwebtoken" "8.5.4" + jsonwebtoken "8.5.1" + +"@nestjs/mapped-types@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@nestjs/mapped-types/-/mapped-types-1.0.1.tgz#78b62041c7a407db4a90eb140567321602bed18e" + integrity sha512-NFvofzSinp00j5rzUd4tf+xi9od6383iY0JP7o0Bnu1fuItAUkWBgc4EKuIQ3D+c2QI3i9pG1kDWAeY27EMGtg== + +"@nestjs/passport@^8.2.1": + version "8.2.1" + resolved "https://registry.yarnpkg.com/@nestjs/passport/-/passport-8.2.1.tgz#a2abff9f51b3857b3423f5380a00f475aa298fe7" + integrity sha512-HXEKMLX1x865+lsJB4srwKHBciDNAhWY1Ha+xbxYRbk7J5leGDoHJAmeqe+Wb3NDn5nkboggLV87t0q2mbYc8w== + +"@nestjs/platform-express@^8.3.1": + version "8.3.1" + resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-8.3.1.tgz#fbf129cbdc56f2fbb17758df4971162de79e2265" + integrity sha512-mdmcokcs2Krd4lXYfSHOhx88Zs+MZRpddGtww/jvZuB0rhtnRpTb9SBhLlgVZmFbboEAgxyrKP+rF9Y9Y7F/Qg== + dependencies: + body-parser "1.19.1" + cors "2.8.5" + express "4.17.2" + multer "1.4.4" + tslib "2.3.1" + +"@nestjs/schematics@^8.0.3": + version "8.0.5" + resolved "https://registry.yarnpkg.com/@nestjs/schematics/-/schematics-8.0.5.tgz#7154be7d85a135ea75bb275db042c2a663677a48" + integrity sha512-nK1hWQeLNbdhsiJDX/XJXLqq7nC6/xxC8CN+seFTQmly+H3gG2xaFnl6JPHURumuQaYJX8JEpC8m0+4tz+wvOg== + dependencies: + "@angular-devkit/core" "13.0.2" + "@angular-devkit/schematics" "13.0.2" + fs-extra "10.0.0" + jsonc-parser "3.0.0" + pluralize "8.0.0" + +"@nestjs/schematics@^8.0.7": + version "8.0.7" + resolved "https://registry.yarnpkg.com/@nestjs/schematics/-/schematics-8.0.7.tgz#bd721f678e8eb975b0ee72b8ee0b4a48196e955d" + integrity sha512-7k+eMMBUwvXFp6vwZ5byiLBEQKzjMyIJwO46ginoFugt2AXrOt0iUhR3BKFuWDBZaYQ1l4az86UGw5ohgH3wow== + dependencies: + "@angular-devkit/core" "13.2.4" + "@angular-devkit/schematics" "13.2.4" + fs-extra "10.0.1" + jsonc-parser "3.0.0" + pluralize "8.0.0" + +"@nestjs/serve-static@^2.2.2": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@nestjs/serve-static/-/serve-static-2.2.2.tgz#8e9dc2fc6c042ddac5133b957d6bc25d9f8fa225" + integrity sha512-3Mr+Q/npS3N7iGoF3Wd6Lj9QcjMGxbNrSqupi5cviM0IKrZ1BHl5qekW95rWYNATAVqoTmjGROAq+nKKpuUagQ== + dependencies: + path-to-regexp "0.1.7" + +"@nestjs/testing@^8.3.1": + version "8.3.1" + resolved "https://registry.yarnpkg.com/@nestjs/testing/-/testing-8.3.1.tgz#8af5b6127d1250405fe65a857be98658e04a386a" + integrity sha512-QZ7WwXYpUpfuyLddFwPSkJOWbpTUCtxvY2P9DjxcEsafmxaCeEURBM0DjaKcSwsTvyg9WIew803zViJO5NklPA== + dependencies: + optional "0.1.4" + tslib "2.3.1" + +"@nestjs/typeorm@^8.0.3": + version "8.0.3" + resolved "https://registry.yarnpkg.com/@nestjs/typeorm/-/typeorm-8.0.3.tgz#e62feb1f3ec7fa0d1353f774f3f6915594c34a4e" + integrity sha512-tf9rTXP6LeFInkwd+tktQhtLRsKp4RRYImprqT8gcHcJDx+xMP1IygnXELOKwF5vo2/mnhrGtBlRQ/iiS6170g== + dependencies: + uuid "8.3.2" + +"@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" + +"@npmcli/fs@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-2.1.0.tgz#f2a21c28386e299d1a9fae8051d35ad180e33109" + integrity sha512-DmfBvNXGaetMxj9LTp8NAN9vEidXURrf5ZTslQzEAi/6GbW+4yjaLFQc6Tue5cpZ9Frlk4OBo/Snf1Bh/S7qTQ== + dependencies: + "@gar/promisify" "^1.1.3" + semver "^7.3.5" + +"@npmcli/move-file@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" + integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== + dependencies: + mkdirp "^1.0.4" + rimraf "^3.0.2" + +"@nuxtjs/opencollective@0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz#620ce1044f7ac77185e825e1936115bb38e2681c" + integrity sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA== + dependencies: + chalk "^4.1.0" + consola "^2.15.0" + node-fetch "^2.6.1" + +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78= + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A= + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU= + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E= + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik= + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0= + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q= + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= + +"@selderee/plugin-htmlparser2@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.6.0.tgz#27e994afd1c2cb647ceb5406a185a5574188069d" + integrity sha512-J3jpy002TyBjd4N/p6s+s90eX42H2eRhK3SbsZuvTDv977/E8p2U3zikdiehyJja66do7FlxLomZLPlvl2/xaA== + dependencies: + domhandler "^4.2.0" + selderee "^0.6.0" + +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^8.0.1": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" + integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@sqltools/formatter@^1.2.2": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.3.tgz#1185726610acc37317ddab11c3c7f9066966bd20" + integrity sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg== + +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + +"@tootallnate/once@2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" + integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== + +"@tsconfig/node10@^1.0.7": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" + integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== + +"@tsconfig/node12@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" + integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== + +"@tsconfig/node14@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" + integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== + +"@tsconfig/node16@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" + integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== + +"@types/accepts@^1.3.5": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/accepts/-/accepts-1.3.5.tgz#c34bec115cfc746e04fe5a059df4ce7e7b391575" + integrity sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ== + dependencies: + "@types/node" "*" + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": + version "7.1.18" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.18.tgz#1a29abcc411a9c05e2094c98f9a1b7da6cdf49f8" + integrity sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" + integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== + dependencies: + "@babel/types" "^7.3.0" + +"@types/bcrypt@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/bcrypt/-/bcrypt-5.0.0.tgz#a835afa2882d165aff5690893db314eaa98b9f20" + integrity sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw== + dependencies: + "@types/node" "*" + +"@types/body-parser@*", "@types/body-parser@1.19.2": + version "1.19.2" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" + integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + +"@types/cookiejar@*": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.2.tgz#66ad9331f63fe8a3d3d9d8c6e3906dd10f6446e8" + integrity sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog== + +"@types/cors@2.8.12": + version "2.8.12" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" + integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== + +"@types/ejs@^3.0.3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/ejs/-/ejs-3.1.0.tgz#ab8109208106b5e764e5a6c92b2ba1c625b73020" + integrity sha512-DCg+Ka+uDQ31lJ/UtEXVlaeV3d6t81gifaVWKJy4MYVVgvJttyX/viREy+If7fz+tK/gVxTGMtyrFPnm4gjrVA== + +"@types/eslint-scope@^3.7.0": + version "3.7.2" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.2.tgz#11e96a868c67acf65bf6f11d10bb89ea71d5e473" + integrity sha512-TzgYCWoPiTeRg6RQYgtuW7iODtVoKu3RVL72k3WohqhjfaOLK5Mg2T4Tg1o2bSfu0vPkoI48wdQFv5b/Xe04wQ== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.2.1" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.2.1.tgz#13f3d69bac93c2ae008019c28783868d0a1d6605" + integrity sha512-UP9rzNn/XyGwb5RQ2fok+DzcIRIYwc16qTXse5+Smsy8MOIccCChT15KAwnsgQx4PzJkaMq4myFyZ4CL5TjhIQ== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^0.0.50": + version "0.0.50" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" + integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== + +"@types/express-serve-static-core@4.17.28", "@types/express-serve-static-core@^4.17.28": + version "4.17.28" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz#c47def9f34ec81dc6328d0b1b5303d1ec98d86b8" + integrity sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + +"@types/express-serve-static-core@^4.17.18": + version "4.17.27" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.27.tgz#7a776191e47295d2a05962ecbb3a4ce97e38b401" + integrity sha512-e/sVallzUTPdyOTiqi8O8pMdBBphscvI6E4JYaKlja4Lm+zh7UFSSdW5VMkRbhDtmrONqOUHOXRguPsDckzxNA== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + +"@types/express@*", "@types/express@4.17.13": + version "4.17.13" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" + integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.18" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/graceful-fs@^4.1.2": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + dependencies: + "@types/node" "*" + +"@types/handlebars@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@types/handlebars/-/handlebars-4.1.0.tgz#3fcce9bf88f85fe73dc932240ab3fb682c624850" + integrity sha512-gq9YweFKNNB1uFK71eRqsd4niVkXrxHugqWFQkeLRJvGjnxsLr16bYtcsG4tOFwmYi0Bax+wCkbf1reUfdl4kA== + dependencies: + handlebars "*" + +"@types/html-to-text@^8.0.1": + version "8.0.1" + resolved "https://registry.yarnpkg.com/@types/html-to-text/-/html-to-text-8.0.1.tgz#e449513df2283b1adedc85bdc2f6b7187f32972a" + integrity sha512-0B/OifmJYmk5r9z9+KJtGWOF0LEjbTN4D2QeCh+mAw81JkJwC83NvNWUZFEqRT5PpnjX7vX0ab1SMGcwCs3Lag== + +"@types/inquirer@^8.2.0": + version "8.2.0" + resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-8.2.0.tgz#b9566d048f5ff65159f2ed97aff45fe0f00b35ec" + integrity sha512-BNoMetRf3gmkpAlV5we+kxyZTle7YibdOntIZbU5pyIfMdcwy784KfeZDAcuyMznkh5OLa17RVXZOGA5LTlkgQ== + dependencies: + "@types/through" "*" + rxjs "^7.2.0" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^27.4.1": + version "27.4.1" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.4.1.tgz#185cbe2926eaaf9662d340cc02e548ce9e11ab6d" + integrity sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw== + dependencies: + jest-matcher-utils "^27.0.0" + pretty-format "^27.0.0" + +"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + +"@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/jsonwebtoken@*": + version "8.5.6" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-8.5.6.tgz#1913e5a61e70a192c5a444623da4901a7b1a9d42" + integrity sha512-+P3O/xC7nzVizIi5VbF34YtqSonFsdnbXBnWUCYRiKOi1f9gA4sEFvXkrGr/QVV23IbMYvcoerI7nnhDUiWXRQ== + dependencies: + "@types/node" "*" + +"@types/jsonwebtoken@8.5.4": + version "8.5.4" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-8.5.4.tgz#50ccaf0aa6f5d7b9956e70fe323b76e582991913" + integrity sha512-4L8msWK31oXwdtC81RmRBAULd0ShnAHjBuKT9MRQpjP0piNrZdXyTRcKY9/UIfhGeKIT4PvF5amOOUbbT/9Wpg== + dependencies: + "@types/node" "*" + +"@types/long@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" + integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w== + +"@types/mime@^1": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" + integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== + +"@types/mjml-core@*": + version "4.7.1" + resolved "https://registry.yarnpkg.com/@types/mjml-core/-/mjml-core-4.7.1.tgz#c2627499045b54eccfca38e2b532566fb0689189" + integrity sha512-k5IRafi93tyZBGF+0BTrcBDvG47OueI+Q7TC4V4UjGQn0AMVvL3Y+S26QF/UHMmMJW5r1hxLyv3StX2/+FatFg== + +"@types/mjml@^4.7.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@types/mjml/-/mjml-4.7.0.tgz#ea31b58008f54119efda9e673af674757d35981b" + integrity sha512-aWWu8Lxq2SexXGs+lBPRUpN3kFf0sDRo3Y4jz7BQ15cQvMfyZOadgFJsNlHmDqI6D2Qjx0PIK+1f9IMXgq9vTA== + dependencies: + "@types/mjml-core" "*" + +"@types/node@*": + version "17.0.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.6.tgz#cc1589c9ee853b389e67e8fb4384e0f250a139b9" + integrity sha512-+XBAjfZmmivILUzO0HwBJoYkAyyySSLg5KCGBDFLomJo0sV6szvVLAf4ANZZ0pfWzgEds5KmGLG9D5hfEqOhaA== + +"@types/node@^10.1.0": + version "10.17.60" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" + integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== + +"@types/node@^17.0.21": + version "17.0.21" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" + integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/passport-jwt@^3.0.6": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/passport-jwt/-/passport-jwt-3.0.6.tgz#41cc8b5803d5f5f06eb33e19c453b42716def4f1" + integrity sha512-cmAAMIRTaEwpqxlrZyiEY9kdibk94gP5KTF8AT1Ra4rWNZYHNMreqhKUEeC5WJtuN5SJZjPQmV+XO2P5PlnvNQ== + dependencies: + "@types/express" "*" + "@types/jsonwebtoken" "*" + "@types/passport-strategy" "*" + +"@types/passport-local@^1.0.34": + version "1.0.34" + resolved "https://registry.yarnpkg.com/@types/passport-local/-/passport-local-1.0.34.tgz#84d3b35b2fd4d36295039ded17fe5f3eaa62f4f6" + integrity sha512-PSc07UdYx+jhadySxxIYWuv6sAnY5e+gesn/5lkPKfBeGuIYn9OPR+AAEDq73VRUh6NBTpvE/iPE62rzZUslog== + dependencies: + "@types/express" "*" + "@types/passport" "*" + "@types/passport-strategy" "*" + +"@types/passport-strategy@*": + version "0.2.35" + resolved "https://registry.yarnpkg.com/@types/passport-strategy/-/passport-strategy-0.2.35.tgz#e52f5212279ea73f02d9b06af67efe9cefce2d0c" + integrity sha512-o5D19Jy2XPFoX2rKApykY15et3Apgax00RRLf0RUotPDUsYrQa7x4howLYr9El2mlUApHmCMv5CZ1IXqKFQ2+g== + dependencies: + "@types/express" "*" + "@types/passport" "*" + +"@types/passport@*": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@types/passport/-/passport-1.0.7.tgz#85892f14932168158c86aecafd06b12f5439467a" + integrity sha512-JtswU8N3kxBYgo+n9of7C97YQBT+AYPP2aBfNGTzABqPAZnK/WOAaKfh3XesUYMZRrXFuoPc2Hv0/G/nQFveHw== + dependencies: + "@types/express" "*" + +"@types/prettier@^2.1.5": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.2.tgz#4c62fae93eb479660c3bd93f9d24d561597a8281" + integrity sha512-ekoj4qOQYp7CvjX8ZDBgN86w3MqQhLE1hczEJbEIjgFEumDy+na/4AJAbLXfgEWFNB2pKadM5rPFtuSGMWK7xA== + +"@types/pug@2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@types/pug/-/pug-2.0.5.tgz#69bc700934dd473c7ab97270bd2dbacefe562231" + integrity sha512-LOnASQoeNZMkzexRuyqcBBDZ6rS+rQxUMkmj5A0PkhhiSZivLIuz6Hxyr1mkGoEZEkk66faROmpMi4fFkrKsBA== + +"@types/qs@*": + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/range-parser@*": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + +"@types/request-ip@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@types/request-ip/-/request-ip-0.0.37.tgz#06decdcdeeaa834edf2b0a7dea0c1aefd5a04375" + integrity sha512-uw6/i3rQnpznxD7LtLaeuZytLhKZK6bRoTS6XVJlwxIOoOpEBU7bgKoVXDNtOg4Xl6riUKHa9bjMVrL6ESqYlQ== + dependencies: + "@types/node" "*" + +"@types/serve-static@*": + version "1.13.10" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" + integrity sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/superagent@*": + version "4.1.14" + resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.14.tgz#ca2eed4fad671e704d3d0f33aaf099edb4a5b857" + integrity sha512-iiXaOL2wSbnSY4qg0mFPWJHL9iwyEsoNYwaHF2w58/fsVAQJlj+KUfFAFZu+nzbz+b7dUprJEAc+O9vhHHhQTA== + dependencies: + "@types/cookiejar" "*" + "@types/node" "*" + +"@types/supertest@^2.0.11": + version "2.0.11" + resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.11.tgz#2e70f69f220bc77b4f660d72c2e1a4231f44a77d" + integrity sha512-uci4Esokrw9qGb9bvhhSVEjd6rkny/dk5PK/Qz4yxKiyppEI+dOPlNrZBahE3i+PoKFYyDxChVXZ/ysS/nrm1Q== + dependencies: + "@types/superagent" "*" + +"@types/through@*": + version "0.0.30" + resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895" + integrity sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg== + dependencies: + "@types/node" "*" + +"@types/yargs-parser@*": + version "20.2.1" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" + integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw== + +"@types/yargs@^16.0.0": + version "16.0.4" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" + integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== + dependencies: + "@types/yargs-parser" "*" + +"@types/zen-observable@0.8.3": + version "0.8.3" + resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3" + integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== + +"@typescript-eslint/eslint-plugin@^5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.12.1.tgz#b2cd3e288f250ce8332d5035a2ff65aba3374ac4" + integrity sha512-M499lqa8rnNK7mUv74lSFFttuUsubIRdAbHcVaP93oFcKkEmHmLqy2n7jM9C8DVmFMYK61ExrZU6dLYhQZmUpw== + dependencies: + "@typescript-eslint/scope-manager" "5.12.1" + "@typescript-eslint/type-utils" "5.12.1" + "@typescript-eslint/utils" "5.12.1" + debug "^4.3.2" + functional-red-black-tree "^1.0.1" + ignore "^5.1.8" + regexpp "^3.2.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.12.1.tgz#b090289b553b8aa0899740d799d0f96e6f49771b" + integrity sha512-6LuVUbe7oSdHxUWoX/m40Ni8gsZMKCi31rlawBHt7VtW15iHzjbpj2WLiToG2758KjtCCiLRKZqfrOdl3cNKuw== + dependencies: + "@typescript-eslint/scope-manager" "5.12.1" + "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/typescript-estree" "5.12.1" + debug "^4.3.2" + +"@typescript-eslint/scope-manager@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.12.1.tgz#58734fd45d2d1dec49641aacc075fba5f0968817" + integrity sha512-J0Wrh5xS6XNkd4TkOosxdpObzlYfXjAFIm9QxYLCPOcHVv1FyyFCPom66uIh8uBr0sZCrtS+n19tzufhwab8ZQ== + dependencies: + "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/visitor-keys" "5.12.1" + +"@typescript-eslint/type-utils@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.12.1.tgz#8d58c6a0bb176b5e9a91581cda1a7f91a114d3f0" + integrity sha512-Gh8feEhsNLeCz6aYqynh61Vsdy+tiNNkQtc+bN3IvQvRqHkXGUhYkUi+ePKzP0Mb42se7FDb+y2SypTbpbR/Sg== + dependencies: + "@typescript-eslint/utils" "5.12.1" + debug "^4.3.2" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.12.1.tgz#46a36a28ff4d946821b58fe5a73c81dc2e12aa89" + integrity sha512-hfcbq4qVOHV1YRdhkDldhV9NpmmAu2vp6wuFODL71Y0Ixak+FLeEU4rnPxgmZMnGreGEghlEucs9UZn5KOfHJA== + +"@typescript-eslint/typescript-estree@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.12.1.tgz#6a9425b9c305bcbc38e2d1d9a24c08e15e02b722" + integrity sha512-ahOdkIY9Mgbza7L9sIi205Pe1inCkZWAHE1TV1bpxlU4RZNPtXaDZfiiFWcL9jdxvW1hDYZJXrFm+vlMkXRbBw== + dependencies: + "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/visitor-keys" "5.12.1" + debug "^4.3.2" + globby "^11.0.4" + is-glob "^4.0.3" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.12.1.tgz#447c24a05d9c33f9c6c64cb48f251f2371eef920" + integrity sha512-Qq9FIuU0EVEsi8fS6pG+uurbhNTtoYr4fq8tKjBupsK5Bgbk2I32UGm0Sh+WOyjOPgo/5URbxxSNV6HYsxV4MQ== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.12.1" + "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/typescript-estree" "5.12.1" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/visitor-keys@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.12.1.tgz#f722da106c8f9695ae5640574225e45af3e52ec3" + integrity sha512-l1KSLfupuwrXx6wc0AuOmC7Ko5g14ZOQ86wJJqRbdLbXLK02pK/DPiDDqCc7BqqiiA04/eAA6ayL0bgOrAkH7A== + dependencies: + "@typescript-eslint/types" "5.12.1" + eslint-visitor-keys "^3.0.0" + +"@webassemblyjs/ast@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" + integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + +"@webassemblyjs/floating-point-hex-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" + integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== + +"@webassemblyjs/helper-api-error@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" + integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== + +"@webassemblyjs/helper-buffer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" + integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== + +"@webassemblyjs/helper-numbers@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" + integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" + integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== + +"@webassemblyjs/helper-wasm-section@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" + integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + +"@webassemblyjs/ieee754@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" + integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" + integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" + integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== + +"@webassemblyjs/wasm-edit@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" + integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/helper-wasm-section" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-opt" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + "@webassemblyjs/wast-printer" "1.11.1" + +"@webassemblyjs/wasm-gen@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" + integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + +"@webassemblyjs/wasm-opt@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" + integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + +"@webassemblyjs/wasm-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" + integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + +"@webassemblyjs/wast-printer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" + integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@xtuc/long" "4.2.2" + +"@wry/context@^0.6.0": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.6.1.tgz#c3c29c0ad622adb00f6a53303c4f965ee06ebeb2" + integrity sha512-LOmVnY1iTU2D8tv4Xf6MVMZZ+juIJ87Kt/plMijjN20NMAXGmH4u8bS1t0uT74cZ5gwpocYueV58YwyI8y+GKw== + dependencies: + tslib "^2.3.0" + +"@wry/equality@^0.5.0": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.5.2.tgz#72c8a7a7d884dff30b612f4f8464eba26c080e73" + integrity sha512-oVMxbUXL48EV/C0/M7gLVsoK6qRHPS85x8zECofEZOVvxGmIPLA9o5Z27cc2PoAyZz1S2VoM2A7FLAnpfGlneA== + dependencies: + tslib "^2.3.0" + +"@wry/trie@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.3.1.tgz#2279b790f15032f8bcea7fc944d27988e5b3b139" + integrity sha512-WwB53ikYudh9pIorgxrkHKrQZcCqNM/Q/bDzZBffEaGUKGuHrRb3zZUT9Sh2qw9yogC7SsdRmQ1ER0pqvd3bfw== + dependencies: + tslib "^2.3.0" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abab@^2.0.3, abab@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" + integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@^1.3.5, accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + +acorn-import-assertions@^1.7.6: + version "1.8.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" + integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== + +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-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^7.1.1: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.2.4, acorn@^8.4.1, acorn@^8.7.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" + integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== + +agent-base@6, agent-base@^6.0.0, agent-base@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +agentkeepalive@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.2.1.tgz#a7975cbb9f83b367f06c90cc51ff28fe7d499717" + integrity sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA== + dependencies: + debug "^4.1.0" + depd "^1.1.2" + humanize-ms "^1.2.1" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv-formats@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv@8.6.3: + 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" + +ajv@8.9.0: + version "8.9.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.9.0.tgz#738019146638824dea25edcf299dcba1b0e7eb18" + integrity sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: + 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.0: + version "8.8.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb" + integrity sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ansi-colors@4.1.1, 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-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^5.0.1: + 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" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + +anymatch@^3.0.3, anymatch@~3.1.2: + 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" + +apollo-datasource@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/apollo-datasource/-/apollo-datasource-3.3.1.tgz#a1168dd68371930de3ed4245ad12fa8600efe2cc" + integrity sha512-Z3a8rEUXVPIZ1p8xrFL8bcNhWmhOmovgDArvwIwmJOBnh093ZpRfO+ESJEDAN4KswmyzCLDAwjsW4zQOONdRUw== + dependencies: + apollo-server-caching "^3.3.0" + apollo-server-env "^4.2.1" + +apollo-reporting-protobuf@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/apollo-reporting-protobuf/-/apollo-reporting-protobuf-3.3.0.tgz#2fc0f7508e488851eda8a6e7c8cc3b5a156ab44b" + integrity sha512-51Jwrg0NvHJfKz7TIGU8+Os3rUAqWtXeKRsRtKYtTeMSBPNhzz8UoGjAB3XyVmUXRE3IRmLtDPDRFL7qbxMI/w== + dependencies: + "@apollo/protobufjs" "1.2.2" + +apollo-server-caching@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/apollo-server-caching/-/apollo-server-caching-3.3.0.tgz#f501cbeb820a4201d98c2b768c085f22848d9dc5" + integrity sha512-Wgcb0ArjZ5DjQ7ID+tvxUcZ7Yxdbk5l1MxZL8D8gkyjooOkhPNzjRVQ7ubPoXqO54PrOMOTm1ejVhsF+AfIirQ== + dependencies: + lru-cache "^6.0.0" + +apollo-server-core@^3.6.3: + version "3.6.3" + resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-3.6.3.tgz#6b12ffa1af8bc8799930f72360090834915033d1" + integrity sha512-TFJmAlI6vPp1MHOSXqYkE6leAyMekWv/D/3ma11uETkcd3EPjERGmxtTXPJElMVEkOK9BEElYKthCrH7bjYLuw== + dependencies: + "@apollographql/apollo-tools" "^0.5.1" + "@apollographql/graphql-playground-html" "1.6.29" + "@graphql-tools/mock" "^8.1.2" + "@graphql-tools/schema" "^8.0.0" + "@josephg/resolvable" "^1.0.0" + apollo-datasource "^3.3.1" + apollo-reporting-protobuf "^3.3.0" + apollo-server-caching "^3.3.0" + apollo-server-env "^4.2.1" + apollo-server-errors "^3.3.1" + apollo-server-plugin-base "^3.5.1" + apollo-server-types "^3.5.1" + async-retry "^1.2.1" + fast-json-stable-stringify "^2.1.0" + graphql-tag "^2.11.0" + lodash.sortby "^4.7.0" + loglevel "^1.6.8" + lru-cache "^6.0.0" + sha.js "^2.4.11" + uuid "^8.0.0" + +apollo-server-env@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/apollo-server-env/-/apollo-server-env-4.2.1.tgz#ea5b1944accdbdba311f179e4dfaeca482c20185" + integrity sha512-vm/7c7ld+zFMxibzqZ7SSa5tBENc4B0uye9LTfjJwGoQFY5xsUPH5FpO5j0bMUDZ8YYNbrF9SNtzc5Cngcr90g== + dependencies: + node-fetch "^2.6.7" + +apollo-server-errors@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/apollo-server-errors/-/apollo-server-errors-3.3.1.tgz#ba5c00cdaa33d4cbd09779f8cb6f47475d1cd655" + integrity sha512-xnZJ5QWs6FixHICXHxUfm+ZWqqxrNuPlQ+kj5m6RtEgIpekOPssH/SD9gf2B4HuWV0QozorrygwZnux8POvyPA== + +apollo-server-express@^3.6.3: + version "3.6.3" + resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-3.6.3.tgz#5daf58bf0bdf0107ded7cd52c7e6ce6cd32c8b44" + integrity sha512-3CjahZ+n+1T7pHH1qW1B6Ns0BzwOMeupAp2u0+M8ruOmE/e7VKn0OSOQQckZ8Z2AcWxWeno9K89fIv3PoSYgYA== + dependencies: + "@types/accepts" "^1.3.5" + "@types/body-parser" "1.19.2" + "@types/cors" "2.8.12" + "@types/express" "4.17.13" + "@types/express-serve-static-core" "4.17.28" + accepts "^1.3.5" + apollo-server-core "^3.6.3" + apollo-server-types "^3.5.1" + body-parser "^1.19.0" + cors "^2.8.5" + parseurl "^1.3.3" + +apollo-server-plugin-base@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/apollo-server-plugin-base/-/apollo-server-plugin-base-3.5.1.tgz#73fc1591522e36e32eff3d033975333e30cf1a7c" + integrity sha512-wgDHz3lLrCqpecDky3z6AOQ0vik0qs0Cya/Ti6n3ESYXJ9MdK3jE/QunATIrOYYJaa+NKl9V7YwU+/bojNfFuQ== + dependencies: + apollo-server-types "^3.5.1" + +apollo-server-types@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/apollo-server-types/-/apollo-server-types-3.5.1.tgz#73fc8aa82b3175fde3906fa3d6786ee4d3e8c982" + integrity sha512-zG7xLl4mmHuZMAYOfjWKHY/IC/GgIkJ3HnYuR7FRrnPpRA9Yt5Kf1M1rjm1Esuqzpb/dt8pM7cX40QaIQObCYQ== + dependencies: + apollo-reporting-protobuf "^3.3.0" + apollo-server-caching "^3.3.0" + apollo-server-env "^4.2.1" + +app-root-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" + integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw== + +append-field@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" + integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY= + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +"aproba@^1.0.3 || ^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + +are-we-there-yet@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz#ba20bd6b553e31d62fc8c31bd23d22b95734390d" + integrity sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + +are-we-there-yet@~1.1.2: + version "1.1.7" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" + integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +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" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +args@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/args/-/args-5.0.1.tgz#4bf298df90a4799a09521362c579278cc2fdd761" + integrity sha512-1kqmFCFsPffavQFGt8OxJdIcETti99kySRUPMpOhaGjL6mRJn8HFU1OxKY5bMqfZKUwTQc1mZkAjmGYaVOHFtQ== + dependencies: + camelcase "5.0.0" + chalk "2.4.2" + leven "2.1.0" + mri "1.1.4" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-includes@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" + integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + is-string "^1.0.7" + +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.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" + integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + +asap@^2.0.0, asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + +asn1@~0.2.3: + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + +assert-never@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/assert-never/-/assert-never-1.2.1.tgz#11f0e363bf146205fb08193b5c7b90f4d1cf44fe" + integrity sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw== + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +ast-types@^0.13.2: + version "0.13.4" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" + integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w== + dependencies: + tslib "^2.0.1" + +async-retry@^1.2.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" + integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== + dependencies: + retry "0.13.1" + +async@0.9.x: + version "0.9.2" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + +atomic-sleep@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" + integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== + +axios@0.26.0: + version "0.26.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.0.tgz#9a318f1c69ec108f8cd5f3c3d390366635e13928" + integrity sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og== + dependencies: + follow-redirects "^1.14.8" + +babel-jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444" + integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg== + dependencies: + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^27.5.1" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz#9be98ecf28c331eb9f5df9c72d6f89deb8181c2e" + integrity sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81" + integrity sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag== + dependencies: + babel-plugin-jest-hoist "^27.5.1" + babel-preset-current-node-syntax "^1.0.0" + +babel-walk@3.0.0-canary-5: + version "3.0.0-canary-5" + resolved "https://registry.yarnpkg.com/babel-walk/-/babel-walk-3.0.0-canary-5.tgz#f66ecd7298357aee44955f235a6ef54219104b11" + integrity sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw== + dependencies: + "@babel/types" "^7.9.6" + +backo2@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= + +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.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +batch@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +bcrypt@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-5.0.1.tgz#f1a2c20f208e2ccdceea4433df0c8b2c54ecdf71" + integrity sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw== + dependencies: + "@mapbox/node-pre-gyp" "^1.0.0" + node-addon-api "^3.1.0" + +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== + +bl@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= + dependencies: + inherits "~2.0.0" + +body-parser@1.19.1, body-parser@^1.19.0: + version "1.19.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.1.tgz#1499abbaa9274af3ecc9f6f10396c995943e31d4" + integrity sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA== + dependencies: + bytes "3.1.1" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.8.1" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.9.6" + raw-body "2.4.2" + type-is "~1.6.18" + +boolbase@^1.0.0, boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + +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" + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browserslist@^4.14.5, browserslist@^4.17.5: + version "4.19.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3" + integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A== + dependencies: + caniuse-lite "^1.0.30001286" + electron-to-chromium "^1.4.17" + escalade "^3.1.1" + node-releases "^2.0.1" + picocolors "^1.0.0" + +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-writer@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" + integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== + +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +busboy@^0.2.11: + version "0.2.14" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453" + integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM= + dependencies: + dicer "0.2.5" + readable-stream "1.1.x" + +bytes@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.1.tgz#3f018291cb4cbad9accb6e6970bca9c8889e879a" + integrity sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg== + +cacache@^16.0.2: + version "16.0.3" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-16.0.3.tgz#0b6314bde969bd4098b03a5f90a351e8a1483f48" + integrity sha512-eC7wYodNCVb97kuHGk5P+xZsvUJHkhSEOyNwkenqQPAsOtrTjvWOE5vSPNBpz9d8X3acIf6w2Ub5s4rvOCTs4g== + dependencies: + "@npmcli/fs" "^2.1.0" + "@npmcli/move-file" "^1.1.2" + chownr "^2.0.0" + fs-minipass "^2.1.0" + glob "^7.2.0" + infer-owner "^1.0.4" + lru-cache "^7.7.1" + minipass "^3.1.6" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + mkdirp "^1.0.4" + p-map "^4.0.0" + promise-inflight "^1.0.1" + rimraf "^3.0.2" + ssri "^8.0.1" + tar "^6.1.11" + unique-filename "^1.1.1" + +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== + +camel-case@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" + integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M= + dependencies: + no-case "^2.2.0" + upper-case "^1.1.1" + +camelcase@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" + integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001286: + version "1.0.30001295" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001295.tgz#68a60f8f0664f342b2835c5d8898b4faea7b3d51" + integrity sha512-lSP16vcyC0FEy0R4ECc9duSPoKoZy+YkpGkue9G4D81OfPnliopaZrU10+qtPdT8PbGXad/PNx43TIQrOmJZSQ== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chalk@2.4.2, chalk@^2.0.0, chalk@^2.4.2: + 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@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: + 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" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +character-parser@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/character-parser/-/character-parser-2.2.0.tgz#c7ce28f36d4bcd9744e5ffc2c5fcde1c73261fc0" + integrity sha1-x84o821LzZdE5f/CxfzeHHMmH8A= + dependencies: + is-regex "^1.0.3" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +cheerio-select@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-1.5.0.tgz#faf3daeb31b17c5e1a9dabcee288aaf8aafa5823" + integrity sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg== + dependencies: + css-select "^4.1.3" + css-what "^5.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + domutils "^2.7.0" + +cheerio@1.0.0-rc.10, cheerio@^1.0.0-rc.3: + version "1.0.0-rc.10" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.10.tgz#2ba3dcdfcc26e7956fc1f440e61d51c643379f3e" + integrity sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw== + dependencies: + cheerio-select "^1.5.0" + dom-serializer "^1.3.2" + domhandler "^4.2.0" + htmlparser2 "^6.1.0" + parse5 "^6.0.1" + parse5-htmlparser2-tree-adapter "^6.0.1" + tslib "^2.2.0" + +cheerio@^0.22.0: + version "0.22.0" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" + integrity sha1-qbqoYKP5tZWmuBsahocxIe06Jp4= + dependencies: + css-select "~1.2.0" + dom-serializer "~0.1.0" + entities "~1.1.1" + htmlparser2 "^3.9.1" + lodash.assignin "^4.0.9" + lodash.bind "^4.1.4" + lodash.defaults "^4.0.1" + lodash.filter "^4.4.0" + lodash.flatten "^4.2.0" + lodash.foreach "^4.3.0" + lodash.map "^4.4.0" + lodash.merge "^4.4.0" + lodash.pick "^4.2.1" + lodash.reduce "^4.4.0" + lodash.reject "^4.4.0" + lodash.some "^4.4.0" + +chokidar@3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chokidar@^3.0.0, chokidar@^3.4.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chownr@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +ci-info@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" + integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== + +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + +class-transformer@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" + integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw== + +class-validator@^0.13.2: + version "0.13.2" + resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.13.2.tgz#64b031e9f3f81a1e1dcd04a5d604734608b24143" + integrity sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw== + dependencies: + libphonenumber-js "^1.9.43" + validator "^13.7.0" + +clean-css@^4.2.1: + version "4.2.4" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.4.tgz#733bf46eba4e607c6891ea57c24a989356831178" + integrity sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A== + dependencies: + source-map "~0.6.0" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-highlight@^2.1.11: + version "2.1.11" + resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" + integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== + dependencies: + chalk "^4.0.0" + highlight.js "^10.7.1" + mz "^2.4.0" + parse5 "^5.1.1" + parse5-htmlparser2-tree-adapter "^6.0.0" + yargs "^16.0.0" + +cli-spinners@^2.5.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" + integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== + +cli-table3@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.1.tgz#36ce9b7af4847f288d3cdd081fbd09bf7bd237b8" + integrity sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA== + dependencies: + string-width "^4.2.0" + optionalDependencies: + colors "1.4.0" + +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + +cluster-key-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" + integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + +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== + +color-support@^1.1.2, color-support@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + +colorette@^2.0.7: + version "2.0.16" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" + integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== + +colors@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +commander@^2.19.0, commander@^2.20.0, commander@^2.20.3: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" + integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== + +commander@^8.1.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + +component-emitter@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +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= + +concat-stream@^1.5.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +config-chain@^1.1.12: + version "1.1.13" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" + integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + +consola@^2.15.0: + version "2.15.3" + resolved "https://registry.yarnpkg.com/consola/-/consola-2.15.3.tgz#2e11f98d6a4be71ff72e0bdf07bd23e12cb61550" + integrity sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw== + +console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +constantinople@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/constantinople/-/constantinople-4.0.1.tgz#0def113fa0e4dc8de83331a5cf79c8b325213151" + integrity sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw== + dependencies: + "@babel/parser" "^7.6.0" + "@babel/types" "^7.6.1" + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" + integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== + +cookiejar@^2.1.2, cookiejar@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.3.tgz#fc7a6216e408e74414b90230050842dacda75acc" + integrity sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ== + +core-util-is@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +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== + +cors@2.8.5, cors@^2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.7.2" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-env@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" + integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== + dependencies: + cross-spawn "^7.0.1" + +cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: + 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" + +css-rules@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/css-rules/-/css-rules-1.0.9.tgz#614c2c76dda9d9d574336cbc550d16d9cfb78ab5" + integrity sha512-HU0mZu0RFIjRRWn4QIAO8MaE1W7q+JSCIiiKE9g2s3b0xgDEAYXG/F9n35xAkaU9NpvUbxBTMJWx1quRRPXbjg== + dependencies: + cssom "^0.4.4" + +css-select@^4.1.3: + version "4.2.1" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.2.1.tgz#9e665d6ae4c7f9d65dbe69d0316e3221fb274cdd" + integrity sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ== + dependencies: + boolbase "^1.0.0" + css-what "^5.1.0" + domhandler "^4.3.0" + domutils "^2.8.0" + nth-check "^2.0.1" + +css-select@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-what@2.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" + integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== + +css-what@^5.0.1, css-what@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" + integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw== + +cssfilter@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae" + integrity sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4= + +cssom@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +data-uri-to-buffer@3: + 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== + +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + +dateformat@^4.6.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" + integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== + +dayjs@^1.10.4, dayjs@^1.10.7: + version "1.10.7" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.7.tgz#2cf5f91add28116748440866a0a1d26f3a6ce468" + integrity sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig== + +debug@2.6.9, 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@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + +debug@^3.1.0, debug@^3.2.6, 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" + +decimal.js@^10.2.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@^0.1.3, 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== + +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + +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" + +degenerator@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-2.2.0.tgz#49e98c11fa0293c5b26edfbb52f15729afcdb254" + integrity sha512-aiQcQowF01RxFI4ZLFMpzyotbQonhNpBao6dkI8JPk5a+hmSjR5ErHp2CQySmQe8os3VBqLCIh87nDBgZXvsmg== + dependencies: + ast-types "^0.13.2" + escodegen "^1.8.1" + esprima "^4.0.0" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +denque@^1.1.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" + integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== + +denque@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-2.0.1.tgz#bcef4c1b80dc32efe97515744f21a4229ab8934a" + integrity sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ== + +depd@^1.1.2, depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-libc@^1.0.2, detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +detect-node@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" + integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== + +dezalgo@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= + dependencies: + asap "^2.0.0" + wrappy "1" + +dicer@0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f" + integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8= + dependencies: + readable-stream "1.1.x" + streamsearch "0.1.2" + +diff-sequences@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" + integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +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" + +discontinuous-range@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a" + integrity sha1-44Mx8IRLukm5qctxx3FYWqsbxlo= + +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" + +doctypes@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/doctypes/-/doctypes-1.1.0.tgz#ea80b106a87538774e8a3a4a5afe293de489e0a9" + integrity sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk= + +dom-serializer@0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +dom-serializer@^1.0.1, dom-serializer@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" + integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + +dom-serializer@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" + integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== + dependencies: + domelementtype "^1.3.0" + entities "^1.1.1" + +domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1, domelementtype@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" + integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== + +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== + dependencies: + domelementtype "1" + +domhandler@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-3.3.0.tgz#6db7ea46e4617eb15cf875df68b2b8524ce0037a" + integrity sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA== + dependencies: + domelementtype "^2.0.1" + +domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.0.tgz#16c658c626cf966967e306f966b431f77d4a5626" + integrity sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g== + dependencies: + domelementtype "^2.2.0" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^1.5.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^2.0.0, domutils@^2.5.2, domutils@^2.7.0, domutils@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +dotenv-expand@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-8.0.1.tgz#332aa17c14b12e28e2e230f8d183eecc1c014fdc" + integrity sha512-j/Ih7bIERDR5PzI89Zu8ayd3tXZ6E3dbY0ljQ9Db0K87qBO8zdLsi2dIvDHMWtjC3Yxb8XixOTHAtia0fDHRpg== + +dotenv@16.0.0: + version "16.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.0.tgz#c619001253be89ebb638d027b609c75c26e47411" + integrity sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q== + +dotenv@^8.2.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" + integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== + +duplexify@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.2.tgz#18b4f8d28289132fa0b9573c898d9f903f81c7b0" + integrity sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw== + dependencies: + end-of-stream "^1.4.1" + inherits "^2.0.3" + readable-stream "^3.1.1" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + +editorconfig@^0.15.3: + version "0.15.3" + resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.3.tgz#bef84c4e75fb8dcb0ce5cee8efd51c15999befc5" + integrity sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g== + dependencies: + commander "^2.19.0" + lru-cache "^4.1.5" + semver "^5.6.0" + sigmund "^1.0.1" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +ejs@^3.1.2: + version "3.1.6" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.6.tgz#5bfd0a0689743bb5268b3550cceeebbc1702822a" + integrity sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw== + dependencies: + jake "^10.6.1" + +electron-to-chromium@^1.4.17: + version "1.4.31" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.31.tgz#8d5ccc3f8253cd142b07afaa84f200fd33a7f2a6" + integrity sha512-t3XVQtk+Frkv6aTD4RRk0OqosU+VLe1dQFW83MDer78ZD6a52frgXuYOIsLYTQiH2Lm+JB2OKYcn7zrX+YGAiQ== + +emittery@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" + integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== + +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== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +encoding-japanese@1.0.30: + version "1.0.30" + resolved "https://registry.yarnpkg.com/encoding-japanese/-/encoding-japanese-1.0.30.tgz#537c4d62881767925d601acb4c79fb14db81703a" + integrity sha512-bd/DFLAoJetvv7ar/KIpE3CNO8wEuyrt9Xuw6nSMiZ+Vrz/Q21BPsMHvARL2Wz6IKHKXgb+DWZqtRg1vql9cBg== + +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" + +end-of-stream@^1.1.0, end-of-stream@^1.4.1: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enhanced-resolve@^5.0.0, enhanced-resolve@^5.7.0, enhanced-resolve@^5.8.3: + version "5.8.3" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0" + integrity sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +entities@^1.1.1, entities@~1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +env-paths@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +err-code@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== + +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.19.0, es-abstract@^1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" + integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== + 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-shared-array-buffer "^1.0.1" + is-string "^1.0.7" + is-weakref "^1.0.1" + 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-module-lexer@^0.9.0: + version "0.9.3" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" + integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== + +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" + +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-goat@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-3.0.0.tgz#e8b5fb658553fe8a3c4959c316c6ebb8c842b19c" + integrity sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +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@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +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== + +escodegen@^1.8.1: + version "1.14.3" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" + integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== + dependencies: + esprima "^4.0.1" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +escodegen@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-config-prettier@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.4.0.tgz#8e6d17c7436649e98c4c2189868562921ef563de" + integrity sha512-CFotdUcMY18nGRo5KGsnNxpznzhkopOcOo0InID+sgQssPrzjvsyKZPvOgymTFeHrFuC3Tzdf2YndhXtULK9Iw== + +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-module-utils@^2.7.2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" + integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== + dependencies: + debug "^3.2.7" + find-up "^2.1.0" + +eslint-plugin-import@^2.25.4: + version "2.25.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1" + integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA== + dependencies: + array-includes "^3.1.4" + array.prototype.flat "^1.2.5" + debug "^2.6.9" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.6" + eslint-module-utils "^2.7.2" + has "^1.0.3" + is-core-module "^2.8.0" + is-glob "^4.0.3" + minimatch "^3.0.4" + object.values "^1.1.5" + resolve "^1.20.0" + tsconfig-paths "^3.12.0" + +eslint-plugin-nestjs@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-nestjs/-/eslint-plugin-nestjs-1.2.3.tgz#d59deefd0404c5d62889a84a95317dabfa87a587" + integrity sha512-CYS2l+oO9sZ8QN1B0/Xgz+2CERfiWCiHDmDslX30yrJrNlBNKFypeCac/7g/NE+LDuox5MH13uvd4qd52Tlt5w== + dependencies: + tslib "^1.8.1" + +eslint-plugin-unused-imports@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-2.0.0.tgz#d8db8c4d0cfa0637a8b51ce3fd7d1b6bc3f08520" + integrity sha512-3APeS/tQlTrFa167ThtP0Zm0vctjr4M44HMpeg1P4bK6wItarumq0Ma82xorMKdFsWpphQBlRPzw/pxiVELX1A== + dependencies: + eslint-rule-composer "^0.3.0" + +eslint-rule-composer@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" + integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== + +eslint-scope@5.1.1, 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-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +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-visitor-keys@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz#eee4acea891814cda67a7d8812d9647dd0179af2" + integrity sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA== + +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@^8.10.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.10.0.tgz#931be395eb60f900c01658b278e05b6dae47199d" + integrity sha512-tcI1D9lfVec+R4LE1mNDnzoJ/f71Kl/9Cv4nG47jOueCMBrCCKYXr4AUVS7go6mWYGFD4+EoN6+eXSrEbRzXVw== + dependencies: + "@eslint/eslintrc" "^1.2.0" + "@humanwhocodes/config-array" "^0.9.2" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.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 "^6.0.1" + globals "^13.6.0" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^4.1.0" + 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" + regexpp "^3.2.0" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^9.3.1: + version "9.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd" + integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ== + dependencies: + acorn "^8.7.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^3.3.0" + +esprima@^4.0.0, esprima@^4.0.1: + 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, estraverse@^4.2.0: + 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.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +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= + +eventemitter3@^3.1.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" + integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +execa@^4.0.2: + version "4.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expect@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74" + integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw== + dependencies: + "@jest/types" "^27.5.1" + jest-get-type "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + +express@4.17.2: + version "4.17.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.2.tgz#c18369f265297319beed4e5558753cc8c1364cb3" + integrity sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.1" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.4.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.9.6" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.17.2" + serve-static "1.14.2" + setprototypeof "1.2.0" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +extract-css@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/extract-css/-/extract-css-2.0.0.tgz#d31fb1dc3d97be940a3762736837211b6a1b55a9" + integrity sha512-tu9Yd6UOdeuSNAcNqrAvEBILxqGVir6A5yRVwfm4t/xYFJc81v/qobn7AExZpdFn7bfxOcA7lTZe4E/GSBohYA== + dependencies: + batch "^0.6.1" + href-content "^2.0.0" + list-stylesheets "^1.2.9" + style-data "^1.4.7" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== + +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.2.11: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + 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-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.1.0, fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.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, 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= + +fast-redact@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.0.2.tgz#c940ba7162dde3aeeefc522926ae8c5231412904" + integrity sha512-YN+CYfCVRVMUZOUPeinHNKgytM1wPI/C/UCLEi56EsY2dwwvI00kIJHJoI7pMVqGoMew8SMZ2SSfHKHULHXDsg== + +fast-safe-stringify@2.1.1, fast-safe-stringify@^2.0.7, fast-safe-stringify@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" + integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== + +fast-url-parser@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" + integrity sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0= + dependencies: + punycode "^1.3.2" + +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" + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +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" + +file-uri-to-path@2: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz#7b415aeba227d575851e0a5b0c640d7656403fba" + integrity sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg== + +filelist@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.2.tgz#80202f21462d4d1c2e214119b1807c1bc0380e5b" + integrity sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ== + dependencies: + minimatch "^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" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.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, find-up@^4.1.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" + +flat-util@^1.1.6: + version "1.1.8" + resolved "https://registry.yarnpkg.com/flat-util/-/flat-util-1.1.8.tgz#09d85e8d0132eb26a2005fee985569d9313890f6" + integrity sha512-//APN9ZHXUESb3JJv11KNpmMvZrvQXPamTsYZB9zDwxu1qiZEs0k8uWIC6su53P5s8jVyEfsGjaJJqitoZ5mJA== + +flatted@^3.1.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2" + integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw== + +follow-redirects@^1.14.8: + version "1.14.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" + integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +fork-ts-checker-webpack-plugin@6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.0.tgz#0282b335fa495a97e167f69018f566ea7d2a2b5e" + integrity sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw== + dependencies: + "@babel/code-frame" "^7.8.3" + "@types/json-schema" "^7.0.5" + chalk "^4.1.0" + chokidar "^3.4.2" + cosmiconfig "^6.0.0" + deepmerge "^4.2.2" + fs-extra "^9.0.0" + glob "^7.1.6" + memfs "^3.1.2" + minimatch "^3.0.4" + schema-utils "2.7.0" + semver "^7.3.2" + tapable "^1.0.0" + +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +formidable@^1.2.2: + version "1.2.6" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.6.tgz#d2a51d60162bbc9b4a055d8457a7c75315d1a168" + integrity sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ== + +formidable@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-2.0.1.tgz#4310bc7965d185536f9565184dee74fbb75557ff" + integrity sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ== + dependencies: + dezalgo "1.0.3" + hexoid "1.0.0" + once "1.4.0" + qs "6.9.3" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +fs-extra@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" + integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-extra@10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.1.tgz#27de43b4320e833f6867cc044bfce29fdf0ef3b8" + integrity sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^9.0.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-minipass@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== + dependencies: + minipass "^2.6.0" + +fs-minipass@^2.0.0, fs-minipass@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + +fs-monkey@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" + integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== + +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.2, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +fstream@^1.0.0, fstream@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" + integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +ftp@^0.3.10: + version "0.3.10" + resolved "https://registry.yarnpkg.com/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d" + integrity sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0= + dependencies: + readable-stream "1.1.x" + xregexp "2.0.0" + +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= + +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" + signal-exit "^3.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" + +gauge@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.3.tgz#286cf105c1962c659f0963058fb05116c1b82d3f" + integrity sha512-ICw1DhAwMtb22rYFwEHgJcx1JCwJGv3x6G0OQUq56Nge+H4Q8JEwr8iveS0XFlsUNSI67F5ffMGK25bK4Pmskw== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.3" + console-control-strings "^1.1.0" + has-unicode "^2.0.1" + signal-exit "^3.0.7" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.5" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +generate-function@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" + integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== + dependencies: + is-property "^1.0.2" + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +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-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +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" + +get-uri@3: + version "3.0.2" + resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c" + integrity sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg== + dependencies: + "@tootallnate/once" "1" + data-uri-to-buffer "3" + debug "4" + file-uri-to-path "2" + fs-extra "^8.1.0" + ftp "^0.3.10" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + 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-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +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.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0: + 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@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.6.0, globals@^13.9.0: + version "13.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" + integrity sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg== + dependencies: + type-fest "^0.20.2" + +globby@^11.0.4: + 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, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: + version "4.2.8" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== + +graceful-fs@^4.2.6, graceful-fs@^4.2.9: + version "4.2.9" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" + integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== + +graphql-redis-subscriptions@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/graphql-redis-subscriptions/-/graphql-redis-subscriptions-2.4.2.tgz#338e77bd180cc5bfc810699ff5f0f5fdc380f90d" + integrity sha512-zMd1G6uZcEvqHZ6PsQ63BfRtw5Bg4cccql1pfkEQsj1vXVWe4p+o8DqNfd9DDUFXIqhHpqkSeN/49BlIwud4Ag== + dependencies: + iterall "^1.3.0" + optionalDependencies: + ioredis "^4.17.3" + +graphql-subscriptions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/graphql-subscriptions/-/graphql-subscriptions-2.0.0.tgz#11ec181d475852d8aec879183e8e1eb94f2eb79a" + integrity sha512-s6k2b8mmt9gF9pEfkxsaO1lTxaySfKoEJzEfmwguBbQ//Oq23hIXCfR1hm4kdh5hnR20RdwB+s3BCb+0duHSZA== + dependencies: + iterall "^1.3.0" + +graphql-tag@2.12.6, graphql-tag@^2.11.0, graphql-tag@^2.12.3: + version "2.12.6" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" + integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== + dependencies: + tslib "^2.1.0" + +graphql-tools@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-8.2.0.tgz#493edc2760469f39d8334c6f20aa75ae91a7ab86" + integrity sha512-9axT/0exEzVCk+vMPykOPannlrA4VQNo6nuWgh25IJ5arPf92OKxvjSHAbm7dQIFmcWxE0hVvyD2rWHjDqZCgQ== + dependencies: + "@graphql-tools/schema" "^8.2.0" + tslib "~2.3.0" + optionalDependencies: + "@apollo/client" "~3.2.5 || ~3.3.0 || ~3.4.0" + +graphql-ws@5.5.5: + version "5.5.5" + resolved "https://registry.yarnpkg.com/graphql-ws/-/graphql-ws-5.5.5.tgz#f375486d3f196e2a2527b503644693ae3a8670a9" + integrity sha512-hvyIS71vs4Tu/yUYHPvGXsTgo0t3arU820+lT5VjZS2go0ewp2LqyCgxEN56CzOG7Iys52eRhHBiD1gGRdiQtw== + +graphql@15.8.0: + version "15.8.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38" + integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw== + +handlebars@*, handlebars@^4.7.6, handlebars@^4.7.7: + version "4.7.7" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" + integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.0" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + +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-unicode@^2.0.0, has-unicode@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +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" + +hashids@^2.2.10: + version "2.2.10" + resolved "https://registry.yarnpkg.com/hashids/-/hashids-2.2.10.tgz#82f45538cf03ce73e31b78d1abe78d287cf760c4" + integrity sha512-nXnYums7F8B5Y+GSThutLPlKMaamW1yjWNZVt0WModiJfdjaDZHnhYTWblS+h1OoBx3yjwiBwxldPP3nIbFSSA== + +he@1.2.0, 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== + +hexoid@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18" + integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g== + +highlight.js@^10.7.1: + version "10.7.3" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" + integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== + +hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +href-content@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/href-content/-/href-content-2.0.0.tgz#f1cd87c4da90b0886760dd9f7c4357a6e42eec2b" + integrity sha512-1BGExrs0CfRm+VAfFH99UshhZO8ZGyXHtW6HsroQRwiN1cNAIYVgCt6IYXB+nEEjFb7Efd+RZMcs11C6s4WoZQ== + dependencies: + remote-content "^2.0.0" + +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +html-minifier@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-4.0.0.tgz#cca9aad8bce1175e02e17a8c33e46d8988889f56" + integrity sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig== + dependencies: + camel-case "^3.0.0" + clean-css "^4.2.1" + commander "^2.19.0" + he "^1.2.0" + param-case "^2.1.1" + relateurl "^0.2.7" + uglify-js "^3.5.1" + +html-to-text@8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/html-to-text/-/html-to-text-8.0.0.tgz#5848681a5a38d657a7bb58cf5006d1c29fe64ce3" + integrity sha512-fEtul1OerF2aMEV+Wpy+Ue20tug134jOY1GIudtdqZi7D0uTudB2tVJBKfVhTL03dtqeJoF8gk8EPX9SyMEvLg== + dependencies: + "@selderee/plugin-htmlparser2" "^0.6.0" + deepmerge "^4.2.2" + he "^1.2.0" + htmlparser2 "^6.1.0" + minimist "^1.2.5" + selderee "^0.6.0" + +html-to-text@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/html-to-text/-/html-to-text-8.1.0.tgz#0c35fc452e6eccb275669adb8bcc61d93ec43ed5" + integrity sha512-Z9iYAqYK2c18GswSbnxJSeMs7lyJgwR2oIkDOyOHGBbYsPsG4HvT379jj3Lcbfko8A5ceyyMHAfkmp/BiXA9/Q== + dependencies: + "@selderee/plugin-htmlparser2" "^0.6.0" + deepmerge "^4.2.2" + he "^1.2.0" + htmlparser2 "^6.1.0" + minimist "^1.2.5" + selderee "^0.6.0" + +htmlparser2@^3.9.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" + integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== + dependencies: + domelementtype "^1.3.1" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^3.1.1" + +htmlparser2@^4.0.0, htmlparser2@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-4.1.0.tgz#9a4ef161f2e4625ebf7dfbe6c0a2f52d18a59e78" + integrity sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q== + dependencies: + domelementtype "^2.0.1" + domhandler "^3.0.0" + domutils "^2.0.0" + entities "^2.0.0" + +htmlparser2@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" + integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.5.2" + entities "^2.0.0" + +http-cache-semantics@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" + integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== + +http-errors@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" + integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.1" + +http-proxy-agent@^4.0.0, http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + +http-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" + integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== + dependencies: + "@tootallnate/once" "2" + agent-base "6" + debug "4" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-proxy-agent@5, https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" + +human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= + dependencies: + ms "^2.0.0" + +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: + 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.2" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.2.tgz#ce13d1875b0c3a674bd6a04b7f76b01b1b6ded01" + integrity sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +iconv-lite@0.6.3, iconv-lite@^0.6.2, iconv-lite@^0.6.3: + 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.13, ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore-walk@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" + integrity sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ== + dependencies: + minimatch "^3.0.4" + +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, ignore@^5.1.8, ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +import-fresh@^3.0.0, import-fresh@^3.1.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" + +import-local@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.3.tgz#4d51c2c495ca9393da259ec66b62e022920211e0" + integrity sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.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= + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +infer-owner@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== + +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.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@^1.3.4, ini@~1.3.0: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +inline-css@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/inline-css/-/inline-css-3.0.0.tgz#f8ddcffab5693ab15c7dd10b05d35aebda90f8c4" + integrity sha512-a+IE7oLaQqeVr3hMviekDDk94LA0+oZX8JEfJuXOm20diZAkOFrq/f/QZCEXpMK6qIbYr0nQNpsuioXQN1ZgXA== + dependencies: + cheerio "^0.22.0" + css-rules "^1.0.9" + extract-css "^2.0.0" + flat-util "^1.1.6" + pick-util "^1.1.3" + slick "^1.12.2" + specificity "^0.4.1" + +inquirer@7.3.3: + version "7.3.3" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" + integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.19" + mute-stream "0.0.8" + run-async "^2.4.0" + rxjs "^6.6.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +inquirer@8.2.0, inquirer@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.0.tgz#f44f008dd344bbfc4b30031f45d984e034a3ac3a" + integrity sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.1" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.21" + mute-stream "0.0.8" + ora "^5.4.1" + run-async "^2.4.0" + rxjs "^7.2.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +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" + +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + +ioredis@^4.17.3: + version "4.28.2" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.2.tgz#493ccd5d869fd0ec86c96498192718171f6c9203" + integrity sha512-kQ+Iv7+c6HsDdPP2XUHaMv8DhnSeAeKEwMbaoqsXYbO+03dItXt7+5jGQDRyjdRUV2rFJbzg7P4Qt1iX2tqkOg== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.3.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + lodash.isarguments "^3.1.0" + p-map "^2.1.0" + redis-commands "1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + +ioredis@^4.28.5: + version "4.28.5" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.5.tgz#5c149e6a8d76a7f8fa8a504ffc85b7d5b6797f9f" + integrity sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.3.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + lodash.isarguments "^3.1.0" + p-map "^2.1.0" + redis-commands "1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + +ip-anonymize@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ip-anonymize/-/ip-anonymize-0.1.0.tgz#5ead504d01871c5c28189a25382f852036b57f7e" + integrity sha512-cZJu+N5JKKFGMK0eEQWNaQMn2EhCysciVM6eotCJwfqotj16BTfVchKsJCH6mQAT9N0GC7oWRcsZ6Lb8dDiwTA== + +ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +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.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" + integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== + 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-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-expression@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-expression/-/is-expression-4.0.0.tgz#c33155962abf21d0afd2552514d67d2ec16fd2ab" + integrity sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A== + dependencies: + acorn "^7.1.1" + object-assign "^4.1.1" + +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@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +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-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-interactive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" + integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== + +is-lambda@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" + integrity sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU= + +is-negative-zero@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +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-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + +is-promise@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" + integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== + +is-property@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + integrity sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ= + +is-regex@^1.0.3, 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-shared-array-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" + integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +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-typedarray@^1.0.0, is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-weakref@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-wsl@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +is_js@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/is_js/-/is_js-0.9.0.tgz#0ab94540502ba7afa24c856aa985561669e9c52d" + integrity sha1-CrlFQFArp6+iTIVqqYVWFmnpxS0= + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +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= + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" + integrity sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.4" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.4.tgz#1b6f068ecbc6c331040aab5741991273e609e40c" + integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +iterall@1.3.0, iterall@^1.2.1, iterall@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" + integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== + +iterare@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/iterare/-/iterare-1.2.1.tgz#139c400ff7363690e33abffa33cbba8920f00042" + integrity sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q== + +jake@^10.6.1: + version "10.8.2" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.2.tgz#ebc9de8558160a66d82d0eadc6a2e58fbc500a7b" + integrity sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A== + dependencies: + async "0.9.x" + chalk "^2.4.2" + filelist "^1.0.1" + minimatch "^3.0.4" + +jest-changed-files@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" + integrity sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw== + dependencies: + "@jest/types" "^27.5.1" + execa "^5.0.0" + throat "^6.0.1" + +jest-circus@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.5.1.tgz#37a5a4459b7bf4406e53d637b49d22c65d125ecc" + integrity sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + expect "^27.5.1" + is-generator-fn "^2.0.0" + jest-each "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + slash "^3.0.0" + stack-utils "^2.0.3" + throat "^6.0.1" + +jest-cli@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.5.1.tgz#278794a6e6458ea8029547e6c6cbf673bd30b145" + integrity sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw== + dependencies: + "@jest/core" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + prompts "^2.0.1" + yargs "^16.2.0" + +jest-config@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.5.1.tgz#5c387de33dca3f99ad6357ddeccd91bf3a0e4a41" + integrity sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA== + dependencies: + "@babel/core" "^7.8.0" + "@jest/test-sequencer" "^27.5.1" + "@jest/types" "^27.5.1" + babel-jest "^27.5.1" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.9" + jest-circus "^27.5.1" + jest-environment-jsdom "^27.5.1" + jest-environment-node "^27.5.1" + jest-get-type "^27.5.1" + jest-jasmine2 "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-runner "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^27.5.1" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def" + integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-docblock@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0" + integrity sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ== + dependencies: + detect-newline "^3.0.0" + +jest-each@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.5.1.tgz#5bc87016f45ed9507fed6e4702a5b468a5b2c44e" + integrity sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ== + dependencies: + "@jest/types" "^27.5.1" + chalk "^4.0.0" + jest-get-type "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + +jest-environment-jsdom@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz#ea9ccd1fc610209655a77898f86b2b559516a546" + integrity sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + jest-util "^27.5.1" + jsdom "^16.6.0" + +jest-environment-node@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.5.1.tgz#dedc2cfe52fab6b8f5714b4808aefa85357a365e" + integrity sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + jest-util "^27.5.1" + +jest-get-type@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" + integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== + +jest-haste-map@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" + integrity sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng== + dependencies: + "@jest/types" "^27.5.1" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^27.5.1" + jest-serializer "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + micromatch "^4.0.4" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.3.2" + +jest-jasmine2@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz#a037b0034ef49a9f3d71c4375a796f3b230d1ac4" + integrity sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/source-map" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^27.5.1" + is-generator-fn "^2.0.0" + jest-each "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + throat "^6.0.1" + +jest-leak-detector@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz#6ec9d54c3579dd6e3e66d70e3498adf80fde3fb8" + integrity sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ== + dependencies: + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-matcher-utils@^27.0.0, jest-matcher-utils@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" + integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== + dependencies: + chalk "^4.0.0" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-message-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" + integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^27.5.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^27.5.1" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" + integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + +jest-regex-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" + integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== + +jest-resolve-dependencies@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz#d811ecc8305e731cc86dd79741ee98fed06f1da8" + integrity sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg== + dependencies: + "@jest/types" "^27.5.1" + jest-regex-util "^27.5.1" + jest-snapshot "^27.5.1" + +jest-resolve@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.5.1.tgz#a2f1c5a0796ec18fe9eb1536ac3814c23617b384" + integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== + dependencies: + "@jest/types" "^27.5.1" + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-pnp-resolver "^1.2.2" + jest-util "^27.5.1" + jest-validate "^27.5.1" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + +jest-runner@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.5.1.tgz#071b27c1fa30d90540805c5645a0ec167c7b62e5" + integrity sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ== + dependencies: + "@jest/console" "^27.5.1" + "@jest/environment" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.8.1" + graceful-fs "^4.2.9" + jest-docblock "^27.5.1" + jest-environment-jsdom "^27.5.1" + jest-environment-node "^27.5.1" + jest-haste-map "^27.5.1" + jest-leak-detector "^27.5.1" + jest-message-util "^27.5.1" + jest-resolve "^27.5.1" + jest-runtime "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + source-map-support "^0.5.6" + throat "^6.0.1" + +jest-runtime@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.5.1.tgz#4896003d7a334f7e8e4a53ba93fb9bcd3db0a1af" + integrity sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/globals" "^27.5.1" + "@jest/source-map" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-serializer@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" + integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.9" + +jest-snapshot@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.5.1.tgz#b668d50d23d38054a51b42c4039cab59ae6eb6a1" + integrity sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA== + dependencies: + "@babel/core" "^7.7.2" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.0.0" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^27.5.1" + graceful-fs "^4.2.9" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + jest-haste-map "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-util "^27.5.1" + natural-compare "^1.4.0" + pretty-format "^27.5.1" + semver "^7.3.2" + +jest-util@^27.0.0: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.4.2.tgz#ed95b05b1adfd761e2cda47e0144c6a58e05a621" + integrity sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA== + dependencies: + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.4" + picomatch "^2.2.3" + +jest-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" + integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067" + integrity sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ== + dependencies: + "@jest/types" "^27.5.1" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^27.5.1" + leven "^3.1.0" + pretty-format "^27.5.1" + +jest-watcher@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.5.1.tgz#71bd85fb9bde3a2c2ec4dc353437971c43c642a2" + integrity sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw== + dependencies: + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^27.5.1" + string-length "^4.0.1" + +jest-worker@^27.4.1: + version "27.4.5" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.5.tgz#d696e3e46ae0f24cff3fa7195ffba22889262242" + integrity sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest-worker@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest/-/jest-27.5.1.tgz#dadf33ba70a779be7a6fc33015843b51494f63fc" + integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ== + dependencies: + "@jest/core" "^27.5.1" + import-local "^3.0.2" + jest-cli "^27.5.1" + +joycon@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" + integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== + +js-beautify@^1.6.14: + version "1.14.0" + resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.14.0.tgz#2ce790c555d53ce1e3d7363227acf5dc69024c2d" + integrity sha512-yuck9KirNSCAwyNJbqW+BxJqJ0NLJ4PwBUzQQACl5O3qHMBXVkXb/rD0ilh/Lat/tn88zSZ+CAHOlk0DsY7GuQ== + dependencies: + config-chain "^1.1.12" + editorconfig "^0.15.3" + glob "^7.1.3" + nopt "^5.0.0" + +js-stringify@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/js-stringify/-/js-stringify-1.0.2.tgz#1736fddfd9724f28a3682adc6230ae7e4e9679db" + integrity sha1-Fzb939lyTyijaCrcYjCufk6Weds= + +"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" + +js-yaml@^4.0.0, js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsdom@^16.6.0: + version "16.7.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.6" + xml-name-validator "^3.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-parse-better-errors@^1.0.2: + 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-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +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-schema@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + +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= + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json5@2.x, json5@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== + dependencies: + minimist "^1.2.5" + +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" + +jsonc-parser@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.0.0.tgz#abdd785701c7e7eaca8a9ec8cf070ca51a745a22" + integrity sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA== + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonwebtoken@8.5.1, jsonwebtoken@^8.2.0: + version "8.5.1" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" + integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^5.6.0" + +jsprim@^1.2.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" + integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.4.0" + verror "1.10.0" + +jstransformer@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/jstransformer/-/jstransformer-1.0.0.tgz#ed8bf0921e2f3f1ed4d5c1a44f68709ed24722c3" + integrity sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM= + dependencies: + is-promise "^2.0.0" + promise "^7.0.1" + +juice@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/juice/-/juice-7.0.0.tgz#509bed6adbb6e4bbaa7fbfadac4e2e83e8c89ba3" + integrity sha512-AjKQX31KKN+uJs+zaf+GW8mBO/f/0NqSh2moTMyvwBY+4/lXIYTU8D8I2h6BAV3Xnz6GGsbalUyFqbYMe+Vh+Q== + dependencies: + cheerio "^1.0.0-rc.3" + commander "^5.1.0" + mensch "^0.3.4" + slick "^1.12.2" + web-resource-inliner "^5.0.0" + +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +leven@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" + integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA= + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +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" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +libbase64@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/libbase64/-/libbase64-1.2.1.tgz#fb93bf4cb6d730f29b92155b6408d1bd2176a8c8" + integrity sha512-l+nePcPbIG1fNlqMzrh68MLkX/gTxk/+vdvAb388Ssi7UuUN31MI44w4Yf33mM3Cm4xDfw48mdf3rkdHszLNew== + +libmime@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/libmime/-/libmime-5.0.0.tgz#4759c76eb219985c5d4057b3a9359922194d9ff7" + integrity sha512-2Bm96d5ktnE217Ib1FldvUaPAaOst6GtZrsxJCwnJgi9lnsoAKIHyU0sae8rNx6DNYbjdqqh8lv5/b9poD8qOg== + dependencies: + encoding-japanese "1.0.30" + iconv-lite "0.6.2" + libbase64 "1.2.1" + libqp "1.1.0" + +libphonenumber-js@^1.9.43: + version "1.9.44" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.9.44.tgz#d036364fe4c1e27205d1d283c7bf8fc25625200b" + integrity sha512-zhw8nUMJuQf7jG1dZfEOKKOS6M3QYIv3HnvB/vGohNd0QfxIQcObH3a6Y6s350H+9xgBeOXClOJkS0hJ0yvS3g== + +libqp@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/libqp/-/libqp-1.1.0.tgz#f5e6e06ad74b794fb5b5b66988bf728ef1dedbe8" + integrity sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g= + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +linkify-it@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.3.tgz#a98baf44ce45a550efb4d49c769d07524cc2fa2e" + integrity sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ== + dependencies: + uc.micro "^1.0.1" + +list-stylesheets@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/list-stylesheets/-/list-stylesheets-1.2.9.tgz#5f4c8603ed7fc96f703fce481c31cf635b64ab73" + integrity sha512-d0Mlv8tlsstnwW8yIJLPRBoXczmQj4uh66lp8pWn1/aiyVXb3tBS8flUuYsgvKfJdKJBiHJ5m8PLDcx5EikDOg== + dependencies: + cheerio "^0.22.0" + pick-util "^1.1.3" + +loader-runner@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" + integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== + +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.assignin@^4.0.9: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + integrity sha1-uo31+4QesKPoBEIysOJjqNxqKKI= + +lodash.bind@^4.1.4: + version "4.2.1" + resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35" + integrity sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU= + +lodash.defaults@^4.0.1, lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.filter@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" + integrity sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4= + +lodash.flatten@^4.2.0, lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + +lodash.foreach@^4.3.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" + integrity sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM= + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= + +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= + +lodash.map@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" + integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM= + +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + +lodash.merge@^4.4.0, 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.omit@4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" + integrity sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA= + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= + +lodash.pick@^4.2.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= + +lodash.reduce@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" + integrity sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs= + +lodash.reject@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" + integrity sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU= + +lodash.some@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" + integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0= + +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@4.17.21, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.7.0: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +loglevel@^1.6.8: + version "1.8.0" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.0.tgz#e7ec73a57e1e7b419cb6c6ac06bf050b67356114" + integrity sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA== + +long@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== + +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" + +lower-case@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" + integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= + +lru-cache@^4.1.3, lru-cache@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +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" + +lru-cache@^7.7.1: + version "7.7.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.7.1.tgz#03d2846b1ad2dcc7931a9340b8711d9798fcb0c6" + integrity sha512-cRffBiTW8s73eH4aTXqBcTLU0xQnwGV3/imttRHGWCrbergmnK4D6JXQd8qin5z43HnDwRI+o7mVW0LEB+tpAw== + +macos-release@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.5.0.tgz#067c2c88b5f3fb3c56a375b2ec93826220fa1ff2" + integrity sha512-EIgv+QZ9r+814gjJj0Bt5vSLJLzswGmSUbUpbi9AIr/fsN2IWFBl2NucV9PAiek+U1STK468tEkxmVYUtuAN3g== + +magic-string@0.25.7: + version "0.25.7" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" + integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== + dependencies: + sourcemap-codec "^1.4.4" + +mailparser@^3.1.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/mailparser/-/mailparser-3.4.0.tgz#249869bc5a41af9e0eabbf005197789442fbac9e" + integrity sha512-u2pfpLg+xr7m2FKDl+ohQhy2gMok1QZ+S9E5umS9ez5DSJWttrqSmBGswyj9F68pZMVTwbhLpBt7Kd04q/W4Vw== + dependencies: + encoding-japanese "1.0.30" + he "1.2.0" + html-to-text "8.0.0" + iconv-lite "0.6.3" + libmime "5.0.0" + linkify-it "3.0.3" + mailsplit "5.3.1" + nodemailer "6.7.0" + tlds "1.224.0" + +mailsplit@5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/mailsplit/-/mailsplit-5.3.1.tgz#dd6d5c20a7b8a767fe9c9649dfcb26ee04f84c36" + integrity sha512-o6R6HCzqWYmI2/IYlB+v2IMPgYqC2EynmagZQICAhR7zAq0CO6fPcsO6CrYmVuYT+SSwvLAEZR5WniohBELcAA== + dependencies: + libbase64 "1.2.1" + libmime "5.0.0" + libqp "1.1.0" + +make-dir@^3.0.0, make-dir@^3.1.0: + 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" + +make-error@1.x, make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +make-fetch-happen@^10.0.3: + version "10.1.0" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-10.1.0.tgz#7232ef7002a635c04d4deac325df144f21871408" + integrity sha512-HeP4QlkadP/Op+hE+Une1070kcyN85FshQObku3/rmzRh4zDcKXA19d2L3AQR6UoaX3uZmhSOpTLH15b1vOFvQ== + dependencies: + agentkeepalive "^4.2.1" + cacache "^16.0.2" + http-cache-semantics "^4.1.0" + http-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.0" + is-lambda "^1.0.1" + lru-cache "^7.7.1" + minipass "^3.1.6" + minipass-collect "^1.0.2" + minipass-fetch "^2.0.3" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + negotiator "^0.6.3" + promise-retry "^2.0.1" + socks-proxy-agent "^6.1.1" + ssri "^8.0.1" + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +matomo-tracker@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/matomo-tracker/-/matomo-tracker-2.2.4.tgz#ee397d915d7b2e7964996ca28a0a03f4f0692453" + integrity sha512-7fDy4wRhDQ1dnSxVqmnVqmmos9ACKag0fCBtBD3/Qeoqks7MFqXcO35nfS6S8xU/IXNf7534q/4Gx8fuWKYW6A== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +mediaquery-text@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/mediaquery-text/-/mediaquery-text-1.1.5.tgz#6ced6675205ba9d5497bf34ebd0f42f23cfb0684" + integrity sha512-T27sUGebV4BhxKpvBThwlZHnMR5elqw4hDSXs0ohHBRGh7k79LaR3lmJHJlIjrNa+LHTl35OWUW56dSGtMNzXQ== + dependencies: + cssom "^0.4.4" + +memfs@^3.1.2: + version "3.4.1" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.1.tgz#b78092f466a0dce054d63d39275b24c71d3f1305" + integrity sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw== + dependencies: + fs-monkey "1.0.3" + +mensch@^0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/mensch/-/mensch-0.3.4.tgz#770f91b46cb16ea5b204ee735768c3f0c491fecd" + integrity sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g== + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +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== + +methods@^1.1.2, methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +micromatch@^4.0.0, 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" + +mime-db@1.51.0: + version "1.51.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" + integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== + +mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.19, mime-types@~2.1.24: + version "2.1.34" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" + integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== + dependencies: + mime-db "1.51.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.4.6, mime@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +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.5, minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +minipass-collect@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" + integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== + dependencies: + minipass "^3.0.0" + +minipass-fetch@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-2.1.0.tgz#ca1754a5f857a3be99a9271277246ac0b44c3ff8" + integrity sha512-H9U4UVBGXEyyWJnqYDCLp1PwD8XIkJ4akNHp1aGVI+2Ym7wQMlxDKi4IB4JbmyU+pl9pEs/cVrK6cOuvmbK4Sg== + dependencies: + minipass "^3.1.6" + minipass-sized "^1.0.3" + minizlib "^2.1.2" + optionalDependencies: + encoding "^0.1.13" + +minipass-flush@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" + integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== + dependencies: + minipass "^3.0.0" + +minipass-pipeline@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" + integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== + dependencies: + minipass "^3.0.0" + +minipass-sized@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" + integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== + dependencies: + minipass "^3.0.0" + +minipass@^2.6.0, minipass@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minipass@^3.0.0, minipass@^3.1.1, minipass@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.6.tgz#3b8150aa688a711a1521af5e8779c1d3bb4f45ee" + integrity sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ== + dependencies: + yallist "^4.0.0" + +minizlib@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== + dependencies: + minipass "^2.9.0" + +minizlib@^2.1.1, minizlib@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + +mjml-accordion@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-accordion/-/mjml-accordion-4.12.0.tgz#8fa8a6777fc12caeac9aa8f21b77ac6a3e9b9261" + integrity sha512-vqBk4NhXN+w6F3c5vnLxkvgneREpkwTzZpbxtMzpNqkUW2yei0oSQ26j/wLgXYTaX+4Czp+oVr0cnNxjyCZHjA== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-body@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-body/-/mjml-body-4.12.0.tgz#97feb40e556ceb6444c6af3d79db3d96e9bc9549" + integrity sha512-IQBAHhdRKsNUXat+oxvRTjVJ1qzTRkNjFe/mtD/Pbn9olUnQmV+RKxnkqRZf7QtiTxVIOGC4kU9VLPjNymsFXQ== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-button@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-button/-/mjml-button-4.12.0.tgz#c89103f702181f0722787ab9905affe98f326c73" + integrity sha512-XJfLP+mHvCr6Ky16ooYz5+8ODkf10+ATyvENCKyrof+rietr5WxN2FxWCZA9Orq20OE74/hvaOeZZdkxwtsXig== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-carousel@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-carousel/-/mjml-carousel-4.12.0.tgz#0fdd9954c53108aa8c35cf9f6c2a3af9626566f8" + integrity sha512-vQ5Aqvix9mbAE0GspxIDpKK4dVMRuKFO3qV6N/CkrIAOe4+2CKV4AMn2fWUvQEx6hA6CGxayeLkI7E0hNOWcZA== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-cli@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-cli/-/mjml-cli-4.12.0.tgz#1911b8fa9925ae59e760714ba1c3a404c2c23393" + integrity sha512-//Y4XsN6aFgpZtDbQZRu4qe+CQzGWV3i5K3rC1dwPcdtpDMsXBPKiwIZFrQxpRVBwxs0hU4ZBQOMtvYZkoicdQ== + dependencies: + "@babel/runtime" "^7.14.6" + chokidar "^3.0.0" + glob "^7.1.1" + html-minifier "^4.0.0" + js-beautify "^1.6.14" + lodash "^4.17.21" + mjml-core "4.12.0" + mjml-migrate "4.12.0" + mjml-parser-xml "4.12.0" + mjml-validator "4.12.0" + yargs "^16.1.0" + +mjml-column@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-column/-/mjml-column-4.12.0.tgz#8b88423478c5499f845b04701a961195eb88a69b" + integrity sha512-Ub/7ov2B1T2jfSpxvF61o3UCU4gGDFUqIelr7ghuazLc2KvTwdHYeR8mWt8l8RBM6zZiWjkYEFMP22ty7WXztg== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-core@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-core/-/mjml-core-4.12.0.tgz#acb6268cd9cd31f7bdfcf54a6dcb10708f976b48" + integrity sha512-B3gUkV3kFN1IlzIV3GnpWBmE21XHH5ARyydMxacR75iC53PvJ9c50hr6DWLGdrrDCC6Fdud8jTmgD9dnWPmJhQ== + dependencies: + "@babel/runtime" "^7.14.6" + cheerio "1.0.0-rc.10" + detect-node "2.0.4" + html-minifier "^4.0.0" + js-beautify "^1.6.14" + juice "^7.0.0" + lodash "^4.17.21" + mjml-migrate "4.12.0" + mjml-parser-xml "4.12.0" + mjml-validator "4.12.0" + +mjml-divider@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-divider/-/mjml-divider-4.12.0.tgz#04baa6096a8da4460aa53a7c930e72a4a792937e" + integrity sha512-L87iqrhVS+PnUInYbXK4lcTQcHfWMTL7ZqDL9XEMBywzX8cCfviLNMbqmLCO2HD8nMPVMRbcE32H04T6LyZ2qw== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-group@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-group/-/mjml-group-4.12.0.tgz#ccef836fd7d16166f8f73128d0707fdad3139614" + integrity sha512-Rl7Iydd7M2SnbH1ItIi07hYY+FrEai5c6kYMKbcFWAuNupCuvUThuhx1AphMPCZFMLbbPSKNWMarBkWhepS7cw== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-head-attributes@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-head-attributes/-/mjml-head-attributes-4.12.0.tgz#21a31fe824f451d95a8750c12f5b7f8dcdaca164" + integrity sha512-tRwKUzIrtcw1FGy8Xpy4vrFo0u2daZgqx3X0cM5WWrGFcKe7ZdjNEAkU/3w+WsFjeMcb0fHdKvd+sxBjPJ6fpA== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-head-breakpoint@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-head-breakpoint/-/mjml-head-breakpoint-4.12.0.tgz#f71f4ddd8ca0b97c5de864b83aee879345d962cb" + integrity sha512-BVVbvAIcIu49P1EJkEPPIY8Gu4GleyzpkdddqD3ihAPn3Pz07SEsFlHvI35eCszuaJeeMbSSxLrsF4m+aQQlvw== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-head-font@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-head-font/-/mjml-head-font-4.12.0.tgz#698af765ef785d353a42d127296e742df15a68f5" + integrity sha512-ja5sWbGOIr1gF/7IIPzrgOlWYiKk57BC8JWYRANV7CxNKa635sd6aBJHbzXv1A6Ph+zH5KtE0MSQCK8n49BIsw== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-head-html-attributes@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-head-html-attributes/-/mjml-head-html-attributes-4.12.0.tgz#3c6a6e927ee314a0afd29a08bd103f68ac53a2e1" + integrity sha512-XJesJuW9uzlNN5w/S7t5ZquSVDay7BehOKmIZKMwKn1y0SJBXiakcwt9M9hhF0HB189Bew0gpGt3m7QYvTez8g== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-head-preview@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-head-preview/-/mjml-head-preview-4.12.0.tgz#34b8f7797a2170de6f2be4c42b170aa9351340f2" + integrity sha512-pr02ZkxwU6/LWhrL3xP/hLrUXx27I1FnfgaYjgvMjh6pMURuy7W+W8BrNJKeyXZo685b2A5lNFDJV7rCJ6HrEQ== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-head-style@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-head-style/-/mjml-head-style-4.12.0.tgz#d86dd9553dd3f9a057f70c193dd15ef0cf934bd3" + integrity sha512-64IVdJ2Xl000SrwLt4cebl+MiZcino/ywMkuLQ/c48XeR6pkvbjXYAInWsdlMG1y041n1bOZICNnQQc4xhNJrw== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-head-title@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-head-title/-/mjml-head-title-4.12.0.tgz#d21ee32b2b929bac36140f92ea5b447e039d03af" + integrity sha512-c7thJUmNLIdVy1ftLbYUjchHwrIfAb9SHdbuVQHdtQz45a3Ni2nie4AWxF/srn90k8q/uEKtQq1taOa4f71Zug== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-head@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-head/-/mjml-head-4.12.0.tgz#fe0167cd4d8a16edc0ba1be0e9f73b78ca7be79e" + integrity sha512-LcI4ykOB6nMV5W//tF9S1unlXxexfNZUnnyZ2OOzP1V7J5poLXdKXqB8XATN2YGGTsDZ5Q/5V1KO+NnjpW7zSw== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-hero@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-hero/-/mjml-hero-4.12.0.tgz#a1a9e10a0c8693d504d26866c862b17ef554d639" + integrity sha512-j87DgSAyLzMMuNtVqR1okkI/orKnvZoR7i+RsA1yueNql9dZtnw3Ezy8cas8MJaAoGOmqIy9AqGRJIr82w4mxQ== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-image@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-image/-/mjml-image-4.12.0.tgz#3ac0fd5917aa51c55b3619fa16e460489b0c11c8" + integrity sha512-P77M+PLLNn7QvGhL8sx+6yzkQbEMxIQO3yxqUC+x8Ie8kXS8phSNGcqx8qfhdN7p7sQ3CZdOIZSXkG7RRAF94w== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-migrate@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-migrate/-/mjml-migrate-4.12.0.tgz#b0b2ff7f7b799f4255f13946d8ec6c63a84b2bfd" + integrity sha512-KDdPkuOzL9CAekY0CslM0Yqiomk4TubNMszw6UFfylp5xRA3CfBo0HdGcnewHBkZ8+isjPlzDWf3n+NkU11OiA== + dependencies: + "@babel/runtime" "^7.14.6" + js-beautify "^1.6.14" + lodash "^4.17.21" + mjml-core "4.12.0" + mjml-parser-xml "4.12.0" + yargs "^16.1.0" + +mjml-navbar@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-navbar/-/mjml-navbar-4.12.0.tgz#2b5c965c83fae83a38c5e4534f325450faf5bc86" + integrity sha512-TWKV5lFgwUvRbG+FNz6Uo7mGPJRU/BK1v0BeQr1e5Ykft4052iYIuv2XNwRkeoORmLT+7AN8FbkP+TVBpflbWw== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-parser-xml@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-parser-xml/-/mjml-parser-xml-4.12.0.tgz#5db2285ca4625c443ce369c8de576687db3453aa" + integrity sha512-cmCcvoiirH0kuCglGAjwBVfDrlnqS3e83uBwPN6wDN6IfxSgsPT6IV0vRfcJERsr2ThpFjvoSq4GmYi9oCUSMw== + dependencies: + "@babel/runtime" "^7.14.6" + detect-node "2.0.4" + htmlparser2 "^4.1.0" + lodash "^4.17.15" + +mjml-preset-core@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-preset-core/-/mjml-preset-core-4.12.0.tgz#93af147b2f37817e74ef889fc45748b2077ae52c" + integrity sha512-zoiCKcl/bK43ltr2J8dY9Qg5fcB3TbhaWcTG84oGYWdii5WEkKTXj5hpP1ss1XqdOGMNLij/HVwmli+xQCo6FQ== + dependencies: + "@babel/runtime" "^7.14.6" + mjml-accordion "4.12.0" + mjml-body "4.12.0" + mjml-button "4.12.0" + mjml-carousel "4.12.0" + mjml-column "4.12.0" + mjml-divider "4.12.0" + mjml-group "4.12.0" + mjml-head "4.12.0" + mjml-head-attributes "4.12.0" + mjml-head-breakpoint "4.12.0" + mjml-head-font "4.12.0" + mjml-head-html-attributes "4.12.0" + mjml-head-preview "4.12.0" + mjml-head-style "4.12.0" + mjml-head-title "4.12.0" + mjml-hero "4.12.0" + mjml-image "4.12.0" + mjml-navbar "4.12.0" + mjml-raw "4.12.0" + mjml-section "4.12.0" + mjml-social "4.12.0" + mjml-spacer "4.12.0" + mjml-table "4.12.0" + mjml-text "4.12.0" + mjml-wrapper "4.12.0" + +mjml-raw@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-raw/-/mjml-raw-4.12.0.tgz#3fb7525d630911e2e25eb5dcf7f4904f0e0bec0d" + integrity sha512-vQUmrEZEgu0DCca7tiPdQ/vf8GM5QyeaabbLd1rX3XCt5Mid47LCdszmVcrk1WxqNuExIw1fNyEGCCDeP2qCJg== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-section@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-section/-/mjml-section-4.12.0.tgz#9d67bd52bb8418a76765d556f60467a506ed79b9" + integrity sha512-5BdHrAghS/XJ40t3qtLHpY3rIVuBnJXv8dGm8U+oMVAzw3L4ySk5WI+FulRkchdPFCKpeXQZjXZaX0C7pmNaIw== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-social@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-social/-/mjml-social-4.12.0.tgz#7423acc02a180c91b186806ba7e522861dcbc8bf" + integrity sha512-eTsqJoKP65Imawh+WEX2dv4N34ItUmvIbsCeSQPhC/NG6klxDjzg5oDA1F2tZk+CPIuXVmJiauQ5/vPHLzUiVw== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-spacer@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-spacer/-/mjml-spacer-4.12.0.tgz#129662cfc02ef777973517eadd99cfdf6c3ab215" + integrity sha512-YB+VCixcuWXDzICrGLFw7PJDkL166e4OG8IUUB2yhvd5VHtFFBc0iRksaEAumOL1r6MnXVCRq4Wcmxlzj7zOfQ== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-table@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-table/-/mjml-table-4.12.0.tgz#e8682786a43a144e96d43c2891affab8facc3dde" + integrity sha512-IuLvyiJOsM6RgobuIfZuM36fJcoH8pK/A4awCLTEme0HCxEkkjzDkl4RBMK/KX53Cpor0U6oR6RlQfZcducpLg== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-text@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-text/-/mjml-text-4.12.0.tgz#615af59c8932433b82dd8c7f5d132ec7625f397f" + integrity sha512-AFcXiQBC48ZfKKgAdU0NRS2nqftc8zLGxBtPwHNgFkuh5Lf2rWgPK6JRubNi7qhb8Sd7M8stU+LIRA5sxM1nRQ== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + +mjml-validator@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-validator/-/mjml-validator-4.12.0.tgz#f359f89f8ca6bfe955af2bf351a48055d59db903" + integrity sha512-EmOScfcJJ4LdIyHnE+K4FdkryQ+c6QRV7qp+zlunAHE5AUPaBS0OrHPHuNo1sOu7g1tc+bVl7eHR4FIb0Wkzwg== + dependencies: + "@babel/runtime" "^7.14.6" + +mjml-wrapper@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml-wrapper/-/mjml-wrapper-4.12.0.tgz#8f2b6ee108ed5cc49dd7fbe75c09a77351221d03" + integrity sha512-u0pq+A9QBLwpeF/hdv2uWZIv3Qp4wwf+CMaHZsUpb3YfOJD/6YKwLvkeA7ngE+YxwwzgtgjmIEs4eDae1evlgQ== + dependencies: + "@babel/runtime" "^7.14.6" + lodash "^4.17.21" + mjml-core "4.12.0" + mjml-section "4.12.0" + +mjml@^4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mjml/-/mjml-4.12.0.tgz#bcf5c508075c5b05d84f611180234f4a2b3e13b0" + integrity sha512-uWDu1pPQVyoX4iKIrM02J6qOBN6PC1rSMP64DKi2qGU4dpOztVgvTBh6JttIbINV4ZiALtpeGu+jeEUqp2ROXA== + dependencies: + "@babel/runtime" "^7.14.6" + mjml-cli "4.12.0" + mjml-core "4.12.0" + mjml-migrate "4.12.0" + mjml-preset-core "4.12.0" + mjml-validator "4.12.0" + +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.4, mkdirp@^0.5.5: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +mkdirp@^1.0.3, mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +moo@^0.5.0, moo@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.1.tgz#7aae7f384b9b09f620b6abf6f74ebbcd1b65dbc4" + integrity sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w== + +mri@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" + integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w== + +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.3, ms@^2.0.0, 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== + +multer@1.4.4: + version "1.4.4" + resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.4.tgz#e2bc6cac0df57a8832b858d7418ccaa8ebaf7d8c" + integrity sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw== + dependencies: + append-field "^1.0.0" + busboy "^0.2.11" + concat-stream "^1.5.2" + mkdirp "^0.5.4" + object-assign "^4.1.1" + on-finished "^2.3.0" + type-is "^1.6.4" + xtend "^4.0.0" + +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + +mysql2@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/mysql2/-/mysql2-2.3.3.tgz#944f3deca4b16629052ff8614fbf89d5552545a0" + integrity sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA== + dependencies: + denque "^2.0.1" + generate-function "^2.3.1" + iconv-lite "^0.6.3" + long "^4.0.0" + lru-cache "^6.0.0" + named-placeholders "^1.1.2" + seq-queue "^0.0.5" + sqlstring "^2.3.2" + +mz@^2.4.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +named-placeholders@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/named-placeholders/-/named-placeholders-1.1.2.tgz#ceb1fbff50b6b33492b5cf214ccf5e39cef3d0e8" + integrity sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA== + dependencies: + lru-cache "^4.1.3" + +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= + +nearley@^2.20.1: + version "2.20.1" + resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.20.1.tgz#246cd33eff0d012faf197ff6774d7ac78acdd474" + integrity sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ== + dependencies: + commander "^2.19.0" + moo "^0.5.0" + railroad-diagrams "^1.0.0" + randexp "0.4.6" + +needle@^2.2.1: + version "2.9.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.9.1.tgz#22d1dffbe3490c2b83e301f7709b6736cd8f2684" + integrity sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +negotiator@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +neo-async@^2.6.0, neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +nestjs-console@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/nestjs-console/-/nestjs-console-7.0.1.tgz#4d23dcb2ec8e2b99b51fcb449e2c0c1f6842c636" + integrity sha512-V99VFWBJ69EdMJj5TrciauBPwI3BmaBDepOKJW3NlmGJlJaD+nKZKENWv7+zcHJEk31b8eL1CFuMnHVFp0X9Fg== + dependencies: + commander "^8.1.0" + ora "5.4.1" + +nestjs-pino@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/nestjs-pino/-/nestjs-pino-2.5.0.tgz#3390237c8ec6d9a789a9480c045e4b5d39e3281d" + integrity sha512-Nb0fsGNQ0Qg/v3lUvxah8IzxKRjRd5fo1/+V2ZBbzciDzi4xjI6YqhwvF0rHQy2IMTAZmmrQNpzMgZk7lNeR4Q== + +netmask@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" + integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== + +no-case@^2.2.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" + integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== + dependencies: + lower-case "^1.1.1" + +node-addon-api@^3.0.0, node-addon-api@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + +node-emoji@1.11.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.11.0.tgz#69a0150e6946e2f115e9d7ea4df7971e2628301c" + integrity sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A== + dependencies: + lodash "^4.17.21" + +node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.5: + version "2.6.6" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89" + integrity sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA== + dependencies: + whatwg-url "^5.0.0" + +node-fetch@^2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + +node-gyp@3.x: + version "3.8.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" + integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA== + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request "^2.87.0" + rimraf "2" + semver "~5.3.0" + tar "^2.0.0" + which "1" + +node-gyp@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-9.0.0.tgz#e1da2067427f3eb5bb56820cb62bc6b1e4bd2089" + integrity sha512-Ma6p4s+XCTPxCuAMrOA/IJRmVy16R8Sdhtwl4PrCr7IBlj4cPawF0vg/l7nOT1jPbuNS7lIRJpBSvVsXwEZuzw== + dependencies: + env-paths "^2.2.0" + glob "^7.1.4" + graceful-fs "^4.2.6" + make-fetch-happen "^10.0.3" + nopt "^5.0.0" + npmlog "^6.0.0" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.2" + which "^2.0.2" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + +node-pre-gyp@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054" + integrity sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +node-releases@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" + integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== + +nodemailer@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.0.tgz#86614722c4e0c33d1b5b02aecb90d6d629932b0d" + integrity sha512-AtiTVUFHLiiDnMQ43zi0YgkzHOEWUkhDgPlBXrsDzJiJvB29Alo4OKxHQ0ugF3gRqRQIneCLtZU3yiUo7pItZw== + +nodemailer@^6.5.0, nodemailer@^6.7.2: + version "6.7.2" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.2.tgz#44b2ad5f7ed71b7067f7a21c4fedabaec62b85e0" + integrity sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q== + +"nopt@2 || 3": + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= + dependencies: + abbrev "1" + +nopt@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" + integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== + dependencies: + abbrev "1" + osenv "^0.1.4" + +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + +normalize-path@3.0.0, 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== + +npm-bundled@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" + integrity sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ== + dependencies: + npm-normalize-package-bin "^1.0.1" + +npm-normalize-package-bin@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" + integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== + +npm-packlist@^1.1.6: + version "1.4.8" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" + integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + npm-normalize-package-bin "^1.0.1" + +npm-run-path@^4.0.0, npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== + dependencies: + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + set-blocking "^2.0.0" + +npmlog@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.1.tgz#06f1344a174c06e8de9c6c70834cfba2964bba17" + integrity sha512-BTHDvY6nrRHuRfyjt1MAufLxYdVXZfd099H4+i1f0lPywNQyI4foeNXJRObB/uy+TYqUW0vAD9gbdSOXPst7Eg== + dependencies: + are-we-there-yet "^3.0.0" + console-control-strings "^1.1.0" + gauge "^4.0.0" + set-blocking "^2.0.0" + +nth-check@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" + integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== + dependencies: + boolbase "^1.0.0" + +nth-check@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +nwsapi@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, 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-hash@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" + integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== + +object-inspect@^1.11.0, object-inspect@^1.9.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" + integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== + +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.values@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" + integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +on-exit-leak-free@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz#b39c9e3bf7690d890f4861558b0d7b90a442d209" + integrity sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg== + +on-finished@^2.3.0, on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +once@1.4.0, once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^5.1.0, onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +open@7: + version "7.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + +optimism@^0.16.1: + version "0.16.1" + resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.16.1.tgz#7c8efc1f3179f18307b887e18c15c5b7133f6e7d" + integrity sha512-64i+Uw3otrndfq5kaoGNoY7pvOhSsjFEN4bdEFh80MWVk/dbgJfMv7VFDeCT8LxNAlEVhQmdVEbfE7X2nWNIIg== + dependencies: + "@wry/context" "^0.6.0" + "@wry/trie" "^0.3.0" + +optional@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/optional/-/optional-0.1.4.tgz#cdb1a9bedc737d2025f690ceeb50e049444fd5b3" + integrity sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw== + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +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" + +ora@5.4.1, ora@^5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" + integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== + dependencies: + bl "^4.1.0" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + is-unicode-supported "^0.1.0" + log-symbols "^4.1.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-name@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/os-name/-/os-name-4.0.1.tgz#32cee7823de85a8897647ba4d76db46bf845e555" + integrity sha512-xl9MAoU97MH1Xt5K9ERft2YfCAoaO6msy1OBA0ozxEC0x0TmIoE6K3QvgJMMZA9yKGLmHXNY/YZoDbiGDj4zYw== + dependencies: + macos-release "^2.5.0" + windows-release "^4.0.0" + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@0, osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.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/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-map@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +pac-proxy-agent@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-4.1.0.tgz#66883eeabadc915fc5e95457324cb0f0ac78defb" + integrity sha512-ejNgYm2HTXSIYX9eFlkvqFp8hyJ374uDf0Zq5YUAifiSh1D6fo+iBivQZirGvVv8dCYUsLhmLBRhlAYvBKI5+Q== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + get-uri "3" + http-proxy-agent "^4.0.1" + https-proxy-agent "5" + pac-resolver "^4.1.0" + raw-body "^2.2.0" + socks-proxy-agent "5" + +pac-resolver@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-4.2.0.tgz#b82bcb9992d48166920bc83c7542abb454bd9bdd" + integrity sha512-rPACZdUyuxT5Io/gFKUeeZFfE5T7ve7cAkE5TUZRRfuKP0u5Hocwe48X7ZEm6mYB+bTB0Qf+xlVlA/RM/i6RCQ== + dependencies: + degenerator "^2.2.0" + ip "^1.1.5" + netmask "^2.0.1" + +packet-reader@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" + integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== + +param-case@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" + integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc= + dependencies: + no-case "^2.2.0" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.0.0, parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse5-htmlparser2-tree-adapter@^6.0.0, parse5-htmlparser2-tree-adapter@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" + integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== + dependencies: + parse5 "^6.0.1" + +parse5@6.0.1, parse5@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + +parse5@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" + integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== + +parseley@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/parseley/-/parseley-0.7.0.tgz#9949e3a0ed05c5072adb04f013c2810cf49171a8" + integrity sha512-xyOytsdDu077M3/46Am+2cGXEKM9U9QclBDv7fimY7e+BBlxh2JcBp2mgNsmkyA9uvgyTjVzDi7cP1v4hcFxbw== + dependencies: + moo "^0.5.1" + nearley "^2.20.1" + +parseurl@^1.3.3, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +passport-jwt@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/passport-jwt/-/passport-jwt-4.0.0.tgz#7f0be7ba942e28b9f5d22c2ebbb8ce96ef7cf065" + integrity sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg== + dependencies: + jsonwebtoken "^8.2.0" + passport-strategy "^1.0.0" + +passport-local@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee" + integrity sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4= + dependencies: + passport-strategy "1.x.x" + +passport-strategy@1.x.x, passport-strategy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" + integrity sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ= + +passport@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/passport/-/passport-0.5.2.tgz#0cb38dd8a71552c8390dfa6a9a6f7f3909954bcf" + integrity sha512-w9n/Ot5I7orGD4y+7V3EFJCQEznE5RxHamUxcqLT2QoJY0f2JdN8GyHonYFvN0Vz+L6lUJfVhrk2aZz2LbuREw== + dependencies: + passport-strategy "1.x.x" + pause "0.0.1" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-to-regexp@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-3.2.0.tgz#fa7877ecbc495c601907562222453c43cc204a5f" + integrity sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pause@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" + integrity sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10= + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +pg-connection-string@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34" + integrity sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ== + +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-pool@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.5.1.tgz#f499ce76f9bf5097488b3b83b19861f28e4ed905" + integrity sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ== + +pg-protocol@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0" + integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ== + +pg-types@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + +pg@^8.7.3: + version "8.7.3" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.7.3.tgz#8a5bdd664ca4fda4db7997ec634c6e5455b27c44" + integrity sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw== + dependencies: + buffer-writer "2.0.0" + packet-reader "1.0.0" + pg-connection-string "^2.5.0" + pg-pool "^3.5.1" + pg-protocol "^1.5.0" + pg-types "^2.1.0" + pgpass "1.x" + +pgpass@1.x: + version "1.0.5" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d" + integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== + dependencies: + split2 "^4.1.0" + +pick-util@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/pick-util/-/pick-util-1.1.3.tgz#69d9b0ebcb75f828318b1d1f1f1fe49a0bf9abe2" + integrity sha512-nQnaPOPjkXCCXBiUELsJrM795/mOQAHH4TyCdiS8mXL6ihj7sfyen/2rPfT8veWnnUnyFdWZawIiKMy7CD7wBQ== + dependencies: + "@jonkemp/package-utils" "^1.0.6" + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== + +pino-abstract-transport@^0.5.0, pino-abstract-transport@v0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-0.5.0.tgz#4b54348d8f73713bfd14e3dc44228739aa13d9c0" + integrity sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ== + dependencies: + duplexify "^4.1.2" + split2 "^4.0.0" + +pino-http@^6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/pino-http/-/pino-http-6.6.0.tgz#d0a1deacada8c93327fdaa48f5bdc94bc43d3407" + integrity sha512-PlItaK2MLpoIMLEcClhfb1VQk/o6fKppINl5s6sPE/4rvufkdO3kCSs/92EwrBsB1yssRCQqDV+w1xpYuPVnjg== + dependencies: + fast-url-parser "^1.1.3" + get-caller-file "^2.0.5" + pino "^7.5.0" + pino-std-serializers "^5.0.0" + +pino-pretty@^7.5.1: + version "7.5.1" + resolved "https://registry.yarnpkg.com/pino-pretty/-/pino-pretty-7.5.1.tgz#4614b8c1077b718428c5a630749c905247951693" + integrity sha512-xEOUJiokdBGcZ9d0v7OY6SqEp+rrVH2drE3bHOUsK8elw44eh9V83InZqeL1dFwgD1IDnd6crUoec3hIXxfdBQ== + dependencies: + args "^5.0.1" + colorette "^2.0.7" + dateformat "^4.6.3" + fast-safe-stringify "^2.0.7" + joycon "^3.1.1" + pino-abstract-transport "^0.5.0" + pump "^3.0.0" + readable-stream "^3.6.0" + rfdc "^1.3.0" + secure-json-parse "^2.4.0" + sonic-boom "^2.2.0" + strip-json-comments "^3.1.1" + +pino-std-serializers@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz#1791ccd2539c091ae49ce9993205e2cd5dbba1e2" + integrity sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q== + +pino-std-serializers@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-5.0.0.tgz#ad2a5b9b332efba2cedb4d16d0c2f31ea792107e" + integrity sha512-YC5Lv+nNxY51oicb/t8VX/sA3dnecCXeQ7heir+H+c4fbg3LD65NFdrfP3Y2ufR0Y/EYbEs5UDxHIB9NwCmYyQ== + +pino@^7.5.0: + version "7.6.2" + resolved "https://registry.yarnpkg.com/pino/-/pino-7.6.2.tgz#73d09dcf13079fd0a2fa7e8648f715d5082e63d8" + integrity sha512-GTzW+HHOzUTaPIyvK6tasky2jMXF1o3iw7Oc2ik7qFjcaexXfyn6ej72XwX4O+wuRyFCbp3oKpv00htrPddv5A== + dependencies: + fast-redact "^3.0.0" + on-exit-leak-free "^0.2.0" + pino-abstract-transport v0.5.0 + pino-std-serializers "^4.0.0" + process-warning "^1.0.0" + quick-format-unescaped "^4.0.3" + real-require "^0.1.0" + safe-stable-stringify "^2.1.0" + sonic-boom "^2.2.1" + thread-stream "^0.13.0" + +pirates@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" + integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pluralize@8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" + integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== + +postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= + +postgres-date@~1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" + integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +prettier@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" + integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== + +pretty-format@^27.0.0, pretty-format@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + +preview-email@3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/preview-email/-/preview-email-3.0.4.tgz#3405c014dcd6890e1618f18d1b2973db71e7e60f" + integrity sha512-g9jbnFHI8QfQAcKeCsZpSzMJT/CeGuJoV311R/NLS6PTsalJkMKkUeirSJJgMJBUYOGJLrhM7MsNVWgk1b13BA== + dependencies: + dayjs "^1.10.4" + debug "^4.3.1" + mailparser "^3.1.0" + nodemailer "^6.5.0" + open "7" + pug "^3.0.2" + uuid "^8.3.2" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process-warning@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-1.0.0.tgz#980a0b25dc38cd6034181be4b7726d89066b4616" + integrity sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q== + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +promise-retry@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== + dependencies: + err-code "^2.0.2" + retry "^0.12.0" + +promise@^7.0.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +prop-types@^15.7.2: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +proxy-agent@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-4.0.1.tgz#326c3250776c7044cd19655ccbfadf2e065a045c" + integrity sha512-ODnQnW2jc/FUVwHHuaZEfN5otg/fMbvMxz9nMSUQfJ9JU7q2SZvSULSsjLloVgJOiv9yhc8GlNMKc4GkFmcVEA== + dependencies: + agent-base "^6.0.0" + debug "4" + http-proxy-agent "^4.0.0" + https-proxy-agent "^5.0.0" + lru-cache "^5.1.1" + pac-proxy-agent "^4.1.0" + proxy-from-env "^1.0.0" + socks-proxy-agent "^5.0.0" + +proxy-from-env@^1.0.0, proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +psl@^1.1.28, psl@^1.1.33: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + +pug-attrs@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pug-attrs/-/pug-attrs-3.0.0.tgz#b10451e0348165e31fad1cc23ebddd9dc7347c41" + integrity sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA== + dependencies: + constantinople "^4.0.1" + js-stringify "^1.0.2" + pug-runtime "^3.0.0" + +pug-code-gen@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/pug-code-gen/-/pug-code-gen-3.0.2.tgz#ad190f4943133bf186b60b80de483100e132e2ce" + integrity sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg== + dependencies: + constantinople "^4.0.1" + doctypes "^1.1.0" + js-stringify "^1.0.2" + pug-attrs "^3.0.0" + pug-error "^2.0.0" + pug-runtime "^3.0.0" + void-elements "^3.1.0" + with "^7.0.0" + +pug-error@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pug-error/-/pug-error-2.0.0.tgz#5c62173cb09c34de2a2ce04f17b8adfec74d8ca5" + integrity sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ== + +pug-filters@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pug-filters/-/pug-filters-4.0.0.tgz#d3e49af5ba8472e9b7a66d980e707ce9d2cc9b5e" + integrity sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A== + dependencies: + constantinople "^4.0.1" + jstransformer "1.0.0" + pug-error "^2.0.0" + pug-walk "^2.0.0" + resolve "^1.15.1" + +pug-lexer@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/pug-lexer/-/pug-lexer-5.0.1.tgz#ae44628c5bef9b190b665683b288ca9024b8b0d5" + integrity sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w== + dependencies: + character-parser "^2.2.0" + is-expression "^4.0.0" + pug-error "^2.0.0" + +pug-linker@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pug-linker/-/pug-linker-4.0.0.tgz#12cbc0594fc5a3e06b9fc59e6f93c146962a7708" + integrity sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw== + dependencies: + pug-error "^2.0.0" + pug-walk "^2.0.0" + +pug-load@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pug-load/-/pug-load-3.0.0.tgz#9fd9cda52202b08adb11d25681fb9f34bd41b662" + integrity sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ== + dependencies: + object-assign "^4.1.1" + pug-walk "^2.0.0" + +pug-parser@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/pug-parser/-/pug-parser-6.0.0.tgz#a8fdc035863a95b2c1dc5ebf4ecf80b4e76a1260" + integrity sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw== + dependencies: + pug-error "^2.0.0" + token-stream "1.0.0" + +pug-runtime@^3.0.0, pug-runtime@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/pug-runtime/-/pug-runtime-3.0.1.tgz#f636976204723f35a8c5f6fad6acda2a191b83d7" + integrity sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg== + +pug-strip-comments@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz#f94b07fd6b495523330f490a7f554b4ff876303e" + integrity sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ== + dependencies: + pug-error "^2.0.0" + +pug-walk@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pug-walk/-/pug-walk-2.0.0.tgz#417aabc29232bb4499b5b5069a2b2d2a24d5f5fe" + integrity sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ== + +pug@^3.0.1, pug@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/pug/-/pug-3.0.2.tgz#f35c7107343454e43bc27ae0ff76c731b78ea535" + integrity sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw== + dependencies: + pug-code-gen "^3.0.2" + pug-filters "^4.0.0" + pug-lexer "^5.0.1" + pug-linker "^4.0.0" + pug-load "^3.0.0" + pug-parser "^6.0.0" + pug-runtime "^3.0.1" + pug-strip-comments "^2.0.0" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@^1.3.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qs@6.9.3: + version "6.9.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.3.tgz#bfadcd296c2d549f1dffa560619132c977f5008e" + integrity sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw== + +qs@6.9.6: + version "6.9.6" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee" + integrity sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ== + +qs@^6.10.1: + version "6.10.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" + integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== + dependencies: + side-channel "^1.0.4" + +qs@^6.9.4: + version "6.10.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.2.tgz#c1431bea37fc5b24c5bdbafa20f16bdf2a4b9ffe" + integrity sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw== + dependencies: + side-channel "^1.0.4" + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +quick-format-unescaped@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" + integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== + +railroad-diagrams@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" + integrity sha1-635iZ1SN3t+4mcG5Dlc3RVnN234= + +randexp@0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3" + integrity sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ== + dependencies: + discontinuous-range "1.0.0" + ret "~0.1.10" + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.2, raw-body@^2.2.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.2.tgz#baf3e9c21eebced59dd6533ac872b71f7b61cb32" + integrity sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ== + dependencies: + bytes "3.1.1" + http-errors "1.8.1" + iconv-lite "0.4.24" + unpipe "1.0.0" + +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +react-is@^16.13.1, react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +readable-stream@1.1.x: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.0.6, readable-stream@^2.2.2: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +real-require@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.1.0.tgz#736ac214caa20632847b7ca8c1056a0767df9381" + integrity sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg== + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + dependencies: + resolve "^1.1.6" + +redis-commands@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" + integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== + +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= + dependencies: + redis-errors "^1.0.0" + +reflect-metadata@^0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +relateurl@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= + +remote-content@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/remote-content/-/remote-content-2.0.0.tgz#795ac977e144657db2d0b34cd383911ab6e8dc33" + integrity sha512-rDCmYAaHRi8SseKY2BFvrPnE6AqTYgKzHdh+az17L+SYBWKjxadiizR/x8B4BUzpanfXnbTgCWxJM1o4u18MNg== + dependencies: + proxy-from-env "^1.1.0" + superagent "^6.1.0" + superagent-proxy "^2.1.0" + +request-ip@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/request-ip/-/request-ip-2.1.3.tgz#99ab2bafdeaf2002626e28083cb10597511d9e14" + integrity sha512-J3qdE/IhVM3BXkwMIVO4yFrvhJlU3H7JH16+6yHucadT4fePnR8dyh+vEs6FIx0S2x5TCt2ptiPfHcn0sqhbYQ== + dependencies: + is_js "^0.9.0" + +request@^2.87.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" + integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== + +resolve@^1.1.6, resolve@^1.15.1, resolve@^1.20.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +retry@0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +rimraf@2, rimraf@^2.6.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@6.6.7, rxjs@^6.6.0: + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + +rxjs@^7.2.0: + version "7.5.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.1.tgz#af73df343cbcab37628197f43ea0c8256f54b157" + integrity sha512-KExVEeZWxMZnZhUZtsJcFwz8IvPvgu4G2Z2QyqjZQzUGr32KDYuSxrEYO4w3tFFNbfLozcrKUTvTPi+E9ywJkQ== + dependencies: + tslib "^2.1.0" + +rxjs@^7.5.4: + version "7.5.4" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.4.tgz#3d6bd407e6b7ce9a123e76b1e770dc5761aa368d" + integrity sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ== + dependencies: + tslib "^2.1.0" + +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-stable-stringify@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz#ab67cbe1fe7d40603ca641c5e765cb942d04fc73" + integrity sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg== + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sax@>=0.6.0, sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + +schema-utils@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" + integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A== + dependencies: + "@types/json-schema" "^7.0.4" + ajv "^6.12.2" + ajv-keywords "^3.4.1" + +schema-utils@^3.1.0, schema-utils@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +secure-json-parse@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.4.0.tgz#5aaeaaef85c7a417f76271a4f5b0cc3315ddca85" + integrity sha512-Q5Z/97nbON5t/L/sH6mY2EacfjVGwrCcSi5D3btRO2GZ8pf1K1UN7Z9H5J57hjVU2Qzxr1xO+FmBhOvEkzCMmg== + +selderee@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/selderee/-/selderee-0.6.0.tgz#f3bee66cfebcb6f33df98e4a1df77388b42a96f7" + integrity sha512-ibqWGV5aChDvfVdqNYuaJP/HnVBhlRGSRrlbttmlMpHcLuTqqbMH36QkSs9GEgj5M88JDYLI8eyP94JaQ8xRlg== + dependencies: + parseley "^0.7.0" + +semver@7.x, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +semver@^5.3.0, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= + +send@0.17.2: + version "0.17.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820" + integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "1.8.1" + mime "1.6.0" + ms "2.1.3" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +seq-queue@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" + integrity sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4= + +serialize-error@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-8.1.0.tgz#3a069970c712f78634942ddd50fbbc0eaebe2f67" + integrity sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ== + dependencies: + type-fest "^0.20.2" + +serialize-javascript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +serve-static@1.14.2: + version "1.14.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa" + integrity sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.2" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +sha.js@^2.4.11: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shelljs@0.8.5: + version "0.8.5" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" + integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +sigmund@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= + +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: + version "3.0.6" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" + integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== + +signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slick@^1.12.2: + version "1.12.2" + resolved "https://registry.yarnpkg.com/slick/-/slick-1.12.2.tgz#bd048ddb74de7d1ca6915faa4a57570b3550c2d7" + integrity sha1-vQSN23TefRymkV+qSldXCzVQwtc= + +smart-buffer@^4.1.0, smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +socks-proxy-agent@5, socks-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz#032fb583048a29ebffec2e6a73fca0761f48177e" + integrity sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ== + dependencies: + agent-base "^6.0.2" + debug "4" + socks "^2.3.3" + +socks-proxy-agent@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz#e664e8f1aaf4e1fb3df945f09e3d94f911137f87" + integrity sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew== + dependencies: + agent-base "^6.0.2" + debug "^4.3.1" + socks "^2.6.1" + +socks@^2.3.3: + version "2.6.1" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e" + integrity sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA== + dependencies: + ip "^1.1.5" + smart-buffer "^4.1.0" + +socks@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.2.tgz#ec042d7960073d40d94268ff3bb727dc685f111a" + integrity sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA== + dependencies: + ip "^1.1.5" + smart-buffer "^4.2.0" + +sonic-boom@^2.2.0, sonic-boom@^2.2.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-2.4.2.tgz#34c0965b1a498abedaaca794c752d190f74b5e8f" + integrity sha512-zlOmAKFLJzTI+MbvmkWhnOOJ++NYo0Iy7F93ARNPmvZvpWG2l8Ff3uwM3CkpHqRw8v3pcRROScM5E+vbeTeOKw== + dependencies: + atomic-sleep "^1.0.0" + +source-map-support@0.5.21, source-map-support@^0.5.6, source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@0.7.3, source-map@^0.7.3, source-map@~0.7.2: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sourcemap-codec@^1.4.4: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + +specificity@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/specificity/-/specificity-0.4.1.tgz#aab5e645012db08ba182e151165738d00887b019" + integrity sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg== + +split2@^4.0.0, split2@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.1.0.tgz#101907a24370f85bb782f08adaabe4e281ecf809" + integrity sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +sqlite3@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.0.2.tgz#00924adcc001c17686e0a6643b6cbbc2d3965083" + integrity sha512-1SdTNo+BVU211Xj1csWa8lV6KM0CtucDwRyA0VHl91wEH1Mgh7RxUpI4rVvG7OhHrzCSGaVyW5g8vKvlrk9DJA== + dependencies: + node-addon-api "^3.0.0" + node-pre-gyp "^0.11.0" + optionalDependencies: + node-gyp "3.x" + +sqlstring@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.2.tgz#cdae7169389a1375b18e885f2e60b3e460809514" + integrity sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg== + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +ssri@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" + integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== + dependencies: + minipass "^3.1.1" + +stack-utils@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + dependencies: + escape-string-regexp "^2.0.0" + +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +stream-shift@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" + integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== + +streamsearch@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" + integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +style-data@^1.4.7: + version "1.4.7" + resolved "https://registry.yarnpkg.com/style-data/-/style-data-1.4.7.tgz#371d5b6400244c865fa03452c9b1c5bf6b8d8de7" + integrity sha512-JUm9y0IOnyaoQprqIEP7H3DtDOX8I7wfbkHPSdq2kRCXommqzvP+f+HNkM6F7gweOBRdFRcp/uoBPif02P/N/A== + dependencies: + cheerio "^0.22.0" + mediaquery-text "^1.1.5" + pick-util "^1.1.3" + +subscriptions-transport-ws@0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.11.0.tgz#baf88f050cba51d52afe781de5e81b3c31f89883" + integrity sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ== + dependencies: + backo2 "^1.0.2" + eventemitter3 "^3.1.0" + iterall "^1.2.1" + symbol-observable "^1.0.4" + ws "^5.2.0 || ^6.0.0 || ^7.0.0" + +superagent-proxy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/superagent-proxy/-/superagent-proxy-2.1.0.tgz#34e91f9024fbace95f0a35c50c69edf2a0d331e2" + integrity sha512-DnarpKN6Xn8e3pYlFV4Yvsj9yxLY4q5FIsUe5JvN7vjzP+YCfzXv03dTkZSD2yzrSadsNYHf0IgOUJwKjX457A== + dependencies: + debug "^3.1.0" + proxy-agent "^4.0.0" + +superagent@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-6.1.0.tgz#09f08807bc41108ef164cfb4be293cebd480f4a6" + integrity sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg== + dependencies: + component-emitter "^1.3.0" + cookiejar "^2.1.2" + debug "^4.1.1" + fast-safe-stringify "^2.0.7" + form-data "^3.0.0" + formidable "^1.2.2" + methods "^1.1.2" + mime "^2.4.6" + qs "^6.9.4" + readable-stream "^3.6.0" + semver "^7.3.2" + +superagent@^7.1.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-7.1.1.tgz#2ab187d38c3078c31c3771c0b751f10163a27136" + integrity sha512-CQ2weSS6M+doIwwYFoMatklhRbx6sVNdB99OEJ5czcP3cng76Ljqus694knFWgOj3RkrtxZqIgpe6vhe0J7QWQ== + dependencies: + component-emitter "^1.3.0" + cookiejar "^2.1.3" + debug "^4.3.3" + fast-safe-stringify "^2.1.1" + form-data "^4.0.0" + formidable "^2.0.1" + methods "^1.1.2" + mime "^2.5.0" + qs "^6.10.1" + readable-stream "^3.6.0" + semver "^7.3.5" + +supertest@^6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/supertest/-/supertest-6.2.2.tgz#04a5998fd3efaff187cb69f07a169755d655b001" + integrity sha512-wCw9WhAtKJsBvh07RaS+/By91NNE0Wh0DN19/hWPlBOU8tAfOtbZoVSV4xXeoKoxgPx0rx2y+y+8660XtE7jzg== + dependencies: + methods "^1.1.2" + superagent "^7.1.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +symbol-observable@4.0.0, symbol-observable@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" + integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== + +symbol-observable@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +tapable@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +tar@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40" + integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA== + dependencies: + block-stream "*" + fstream "^1.0.12" + inherits "2" + +tar@^4: + version "4.4.19" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" + integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== + dependencies: + chownr "^1.1.4" + fs-minipass "^1.2.7" + minipass "^2.9.0" + minizlib "^1.3.3" + mkdirp "^0.5.5" + safe-buffer "^5.2.1" + yallist "^3.1.1" + +tar@^6.1.11, tar@^6.1.2: + version "6.1.11" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +terser-webpack-plugin@^5.1.3: + version "5.3.0" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz#21641326486ecf91d8054161c816e464435bae9f" + integrity sha512-LPIisi3Ol4chwAaPP8toUJ3L4qCM1G0wao7L3qNv57Drezxj6+VEyySpPw4B1HSO2Eg/hDY/MNF5XihCAoqnsQ== + dependencies: + jest-worker "^27.4.1" + schema-utils "^3.1.1" + serialize-javascript "^6.0.0" + source-map "^0.6.1" + terser "^5.7.2" + +terser@^5.7.2: + version "5.10.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" + integrity sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA== + dependencies: + commander "^2.20.0" + source-map "~0.7.2" + source-map-support "~0.5.20" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + +thread-stream@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-0.13.0.tgz#c68054bdea250c5d8d400caa3233a150d5461cca" + integrity sha512-kTMZeX4Dzlb1zZ00/01aerGaTw2i8NE4sWF0TvF1uXewRhCiUjCvatQkvxIvFqauWG2ADFS2Wpd3qBeYL9i3dg== + dependencies: + real-require "^0.1.0" + +throat@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" + integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +tlds@1.224.0: + version "1.224.0" + resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.224.0.tgz#dc9a5b0bda0708af0302114f6e24458770c5af01" + integrity sha512-Jgdc8SEijbDFUsmCn6Wk/f7E6jBLFZOG3U1xK0amGSfEH55Xx97ItUS/d2NngsuApjn11UeWCWj8Um3VRhseZQ== + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +token-stream@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/token-stream/-/token-stream-1.0.0.tgz#cc200eab2613f4166d27ff9afc7ca56d49df6eb4" + integrity sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ= + +tough-cookie@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.1.2" + +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== + dependencies: + punycode "^2.1.1" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + +tree-kill@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + +ts-invariant@^0.9.0: + version "0.9.4" + resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.9.4.tgz#42ac6c791aade267dd9dc65276549df5c5d71cac" + integrity sha512-63jtX/ZSwnUNi/WhXjnK8kz4cHHpYS60AnmA6ixz17l7E12a5puCWFlNpkne5Rl0J8TBPVHpGjsj4fxs8ObVLQ== + dependencies: + tslib "^2.1.0" + +ts-jest@27.1.3: + version "27.1.3" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.3.tgz#1f723e7e74027c4da92c0ffbd73287e8af2b2957" + integrity sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^27.0.0" + json5 "2.x" + lodash.memoize "4.x" + make-error "1.x" + semver "7.x" + yargs-parser "20.x" + +ts-loader@^9.2.6: + version "9.2.6" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.2.6.tgz#9937c4dd0a1e3dbbb5e433f8102a6601c6615d74" + integrity sha512-QMTC4UFzHmu9wU2VHZEmWWE9cUajjfcdcws+Gh7FhiO+Dy0RnR1bNz0YCHqhI0yRowCE9arVnNxYHqELOy9Hjw== + dependencies: + chalk "^4.1.0" + enhanced-resolve "^5.0.0" + micromatch "^4.0.0" + semver "^7.3.4" + +ts-node@^10.5.0: + version "10.5.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.5.0.tgz#618bef5854c1fbbedf5e31465cbb224a1d524ef9" + integrity sha512-6kEJKwVxAJ35W4akuiysfKwKmjkbYxwQMTBaAxo9KKAx/Yd26mPUyhGz3ji+EsJoAgrLqVsYHNuuYwQe22lbtw== + dependencies: + "@cspotcode/source-map-support" "0.7.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.0" + yn "3.1.1" + +tsconfig-paths-webpack-plugin@3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.5.2.tgz#01aafff59130c04a8c4ebc96a3045c43c376449a" + integrity sha512-EhnfjHbzm5IYI9YPNVIxx1moxMI4bpHD2e0zTXeDNQcwjjRaGepP7IhTHJkyDBG0CAOoxRfe7jCG630Ou+C6Pw== + dependencies: + chalk "^4.1.0" + enhanced-resolve "^5.7.0" + tsconfig-paths "^3.9.0" + +tsconfig-paths@3.12.0, tsconfig-paths@^3.12.0, tsconfig-paths@^3.9.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b" + integrity sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.0" + strip-bom "^3.0.0" + +tslib@2.3.1, tslib@^2.0.1, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@~2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + +tslib@^1.8.1, tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@~2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c" + integrity sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-is@^1.6.4, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +typeorm@^0.2.44: + version "0.2.44" + resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.44.tgz#4cc07eb1eb7a0e7f3ec9e65ded9eb3c3aedbb3e1" + integrity sha512-yFyb9Ts73vGaS/O06TvLpzvT5U/ngO31GeciNc0eoH7P1QcG8kVZdOy9FHJqkTeDmIljMRgWjbYUoMw53ZY7Xw== + dependencies: + "@sqltools/formatter" "^1.2.2" + app-root-path "^3.0.0" + buffer "^6.0.3" + chalk "^4.1.0" + cli-highlight "^2.1.11" + debug "^4.3.1" + dotenv "^8.2.0" + glob "^7.1.6" + js-yaml "^4.0.0" + mkdirp "^1.0.4" + reflect-metadata "^0.1.13" + sha.js "^2.4.11" + tslib "^2.1.0" + uuid "^8.3.2" + xml2js "^0.4.23" + yargs "^17.0.1" + zen-observable-ts "^1.0.0" + +typescript@4.5.5, typescript@^4.5.5: + version "4.5.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3" + integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== + +uc.micro@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" + integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== + +uglify-js@^3.1.4, uglify-js@^3.5.1: + version "3.14.5" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.14.5.tgz#cdabb7d4954231d80cb4a927654c4655e51f4859" + integrity sha512-qZukoSxOG0urUTvjc2ERMTcAy+BiFh3weWAkeurLwjrCba73poHmG3E36XEjd/JGukMzwTL7uCxZiAexj8ppvQ== + +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + +universalify@^0.1.0, universalify@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +upper-case@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" + integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg= + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@8.3.2, uuid@^8.0.0, uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +v8-compile-cache-lib@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz#0582bcb1c74f3a2ee46487ceecf372e46bce53e8" + integrity sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA== + +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +v8-to-istanbul@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz#0aeb763894f1a0a1676adf8a8b7612a38902446c" + integrity sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + +valid-data-url@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/valid-data-url/-/valid-data-url-3.0.1.tgz#826c1744e71b5632e847dd15dbd45b9fb38aa34f" + integrity sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA== + +validator@^13.7.0: + version "13.7.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.7.0.tgz#4f9658ba13ba8f3d82ee881d3516489ea85c0857" + integrity sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw== + +value-or-promise@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.11.tgz#3e90299af31dd014fe843fe309cefa7c1d94b140" + integrity sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg== + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +void-elements@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" + integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk= + +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + +walker@^1.0.7: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +watchpack@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.1.tgz#4200d9447b401156eeca7767ee610f8809bc9d25" + integrity sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + dependencies: + defaults "^1.0.3" + +web-resource-inliner@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/web-resource-inliner/-/web-resource-inliner-5.0.0.tgz#ac30db8096931f20a7c1b3ade54ff444e2e20f7b" + integrity sha512-AIihwH+ZmdHfkJm7BjSXiEClVt4zUFqX4YlFAzjL13wLtDuUneSaFvDBTbdYRecs35SiU7iNKbMnN+++wVfb6A== + dependencies: + ansi-colors "^4.1.1" + escape-goat "^3.0.0" + htmlparser2 "^4.0.0" + mime "^2.4.6" + node-fetch "^2.6.0" + valid-data-url "^3.0.0" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + +webpack-node-externals@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz#1a3407c158d547a9feb4229a9e3385b7b60c9917" + integrity sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ== + +webpack-sources@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.2.tgz#d88e3741833efec57c4c789b6010db9977545260" + integrity sha512-cp5qdmHnu5T8wRg2G3vZZHoJPN14aqQ89SyQ11NpGH5zEMDCclt49rzo+MaRazk7/UeILhAI+/sEtcM+7Fr0nw== + +webpack@5.66.0: + version "5.66.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.66.0.tgz#789bf36287f407fc92b3e2d6f978ddff1bfc2dbb" + integrity sha512-NJNtGT7IKpGzdW7Iwpn/09OXz9inIkeIQ/ibY6B+MdV1x6+uReqz/5z1L89ezWnpPDWpXF0TY5PCYKQdWVn8Vg== + dependencies: + "@types/eslint-scope" "^3.7.0" + "@types/estree" "^0.0.50" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/wasm-edit" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + acorn "^8.4.1" + acorn-import-assertions "^1.7.6" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.8.3" + es-module-lexer "^0.9.0" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.9" + json-parse-better-errors "^1.0.2" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.1.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.1.3" + watchpack "^2.3.1" + webpack-sources "^3.2.2" + +whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which@1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1, which@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0, wide-align@^1.1.2, wide-align@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + +windows-release@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-4.0.0.tgz#4725ec70217d1bf6e02c7772413b29cdde9ec377" + integrity sha512-OxmV4wzDKB1x7AZaZgXMVsdJ1qER1ed83ZrTYd5Bwq2HfJVg3DJS8nqlAG4sMoJ7mu8cuRmLEYyU13BKwctRAg== + dependencies: + execa "^4.0.2" + +with@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/with/-/with-7.0.2.tgz#ccee3ad542d25538a7a7a80aad212b9828495bac" + integrity sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w== + dependencies: + "@babel/parser" "^7.9.6" + "@babel/types" "^7.9.6" + assert-never "^1.2.1" + babel-walk "3.0.0-canary-5" + +word-wrap@^1.2.3, word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + +"ws@^5.2.0 || ^6.0.0 || ^7.0.0", ws@^7.4.6: + version "7.5.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" + integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + +xml2js@^0.4.23: + version "0.4.23" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" + integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +xregexp@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" + integrity sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM= + +xss@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.10.tgz#5cd63a9b147a755a14cb0455c7db8866120eb4d2" + integrity sha512-qmoqrRksmzqSKvgqzN0055UFWY7OKx1/9JWeRswwEVX9fCG5jcYRxa/A2DHcmZX6VJvjzHRQ2STeeVcQkrmLSw== + dependencies: + commander "^2.20.3" + cssfilter "0.0.10" + +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.0, yallist@^3.0.2, yallist@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yaml@^1.7.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yargs-parser@20.x, yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-parser@^21.0.0: + version "21.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.0.tgz#a485d3966be4317426dd56bdb6a30131b281dc55" + integrity sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA== + +yargs@^16.0.0, yargs@^16.1.0, yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yargs@^17.0.1: + version "17.3.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9" + integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.0.0" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +zen-observable-ts@^1.0.0, zen-observable-ts@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz#2d1aa9d79b87058e9b75698b92791c1838551f83" + integrity sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA== + dependencies: + "@types/zen-observable" "0.8.3" + zen-observable "0.8.15" + +zen-observable@0.8.15: + version "0.8.15" + resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" + integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== diff --git a/ui b/ui deleted file mode 160000 index 011a6bae..00000000 --- a/ui +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 011a6baef416bb9265f5172707bc21e7823c8086 diff --git a/ui/.dockerignore b/ui/.dockerignore new file mode 100644 index 00000000..96884d0b --- /dev/null +++ b/ui/.dockerignore @@ -0,0 +1,5 @@ +/out +/node_modules +/.git +/.next +/doc diff --git a/ui/.eslintrc.js b/ui/.eslintrc.js new file mode 100644 index 00000000..e222e143 --- /dev/null +++ b/ui/.eslintrc.js @@ -0,0 +1,74 @@ +module.exports = { + root: true, + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaFeatures: { jsx: true }, + tsconfigRootDir: __dirname, + project: ['./tsconfig.json'], + }, + plugins: [ + '@typescript-eslint/eslint-plugin', + '@typescript-eslint', + 'unused-imports' + ], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:@typescript-eslint/recommended-requiring-type-checking', + 'plugin:react/recommended', + 'plugin:jsx-a11y/recommended', + 'plugin:@typescript-eslint/recommended-requiring-type-checking', + 'prettier', + ], + rules: { + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-explicit-any': 'off', + 'react/prop-types': 'off', + '@typescript-eslint/no-empty-interface': 'off', + 'jsx-a11y/no-autofocus': 'off', + 'array-element-newline': ['error', { + 'ArrayExpression': 'consistent', + 'ArrayPattern': { + 'minItems': 3, + 'multiline': true, + } + }], + 'array-bracket-newline': ['error', { + 'minItems': 3, + 'multiline': true, + }], + 'indent': [ + 'error', + 2, + { + 'SwitchCase': 1 + } + ], + 'no-tabs': ['error'], + 'max-len': ['error', { + 'code': 100, + 'ignoreComments': true, + 'ignoreUrls': true, + 'ignoreTemplateLiterals': true, + 'ignoreTrailingComments': true, + 'ignoreStrings': true, + }], + 'quotes': ['error', 'single', { 'avoidEscape': true }], + 'comma-dangle': ['error', 'always-multiline'], + 'linebreak-style': [ + 'error', + 'unix' + ], + 'no-trailing-spaces': 'error', + 'eol-last': 'error', + 'unused-imports/no-unused-imports': 'error', + }, + settings: { + react: { + version: 'detect', + }, + }, +} diff --git a/ui/.gitignore b/ui/.gitignore new file mode 100644 index 00000000..11fc3f03 --- /dev/null +++ b/ui/.gitignore @@ -0,0 +1,33 @@ +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local +.env + +# development environments +/.idea +schema.graphql diff --git a/ui/.graphqlconfig b/ui/.graphqlconfig new file mode 100644 index 00000000..37cb9301 --- /dev/null +++ b/ui/.graphqlconfig @@ -0,0 +1,15 @@ +{ + "name": "OhMyForm API GraphQL Schema", + "schemaPath": "./schema.graphql", + "extensions": { + "endpoints": { + "OhMyForm API GraphQL Endpoint1": { + "url": "http://localhost:4100/graphql", + "headers": { + "user-agent": "JS GraphQL" + }, + "introspect": true + } + } + } +} diff --git a/ui/.prettierrc.js b/ui/.prettierrc.js new file mode 100644 index 00000000..c63bada3 --- /dev/null +++ b/ui/.prettierrc.js @@ -0,0 +1,8 @@ +module.exports = { + semi: false, + trailingComma: 'es5', + singleQuote: true, + printWidth: 100, + tabWidth: 2, + useTabs: false, +} diff --git a/ui/Dockerfile b/ui/Dockerfile new file mode 100644 index 00000000..4bed4709 --- /dev/null +++ b/ui/Dockerfile @@ -0,0 +1,39 @@ +FROM node:14-alpine AS builder +MAINTAINER OhMyForm <admin@ohmyform.com> + +WORKDIR /usr/src/app + +RUN apk --update --no-cache add curl bash g++ make libpng-dev + +# install node-prune (https://github.com/tj/node-prune) +RUN curl -sf https://gobinaries.com/tj/node-prune | sh + +COPY . ./ + +RUN yarn install --frozen-lock-file +RUN yarn build + +# remove development dependencies +RUN npm prune --production + +# run node prune +# there is some problem running node prune that then prevents the frontend to load (just start with /form/1 and it will crash) +#RUN /usr/local/bin/node-prune + +FROM node:14-alpine +MAINTAINER OhMyForm <admin@ohmyform.com> + +# Create a group and a user with name "ohmyform". +RUN addgroup --gid 9999 ohmyform && adduser -D --uid 9999 -G ohmyform ohmyform + +WORKDIR /usr/src/app + +COPY --from=builder /usr/src/app /usr/src/app + +ENV PORT=4000 \ + NODE_ENV=production + +# Change to non-root privilege +USER ohmyform + +CMD [ "yarn", "start" ] diff --git a/ui/LICENSE.md b/ui/LICENSE.md new file mode 100644 index 00000000..0ad25db4 --- /dev/null +++ b/ui/LICENSE.md @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +<https://www.gnu.org/licenses/>. diff --git a/ui/README.md b/ui/README.md new file mode 100644 index 00000000..7db361a2 --- /dev/null +++ b/ui/README.md @@ -0,0 +1,17 @@ +# OhMyForm UI + +[![Build Status](https://travis-ci.org/ohmyform/ui.svg?branch=master)](https://travis-ci.org/ohmyform/ui) +![Latest Release](https://badgen.net/github/tag/ohmyform/ui) +[![Docker Pulls](https://badgen.net/docker/pulls/ohmyform/ui)](https://hub.docker.com/r/ohmyform/ui) +[![Lokalise](https://badgen.net/badge/Lokalise/EN/green?icon=libraries)](https://app.lokalise.com/public/379418475ede5d5c6937b0.31012044/) +![Last Commit](https://badgen.net/github/last-commit/ohmyform/ui) + +[Demo](https://demo.ohmyform.com/login) + +> An *open source alternative to TypeForm* that can create stunning mobile-ready forms, surveys and questionnaires. + +[![Discord](https://img.shields.io/discord/595773457862492190.svg?label=Discord%20Chat)](https://discord.gg/MJqAuAZ) +[![Financial Contributors on Open Collective](https://opencollective.com/ohmyform-sustainability/all/badge.svg?label=financial+contributors)](https://opencollective.com/ohmyform-sustainability) + + + diff --git a/ui/assets/global.scss b/ui/assets/global.scss new file mode 100644 index 00000000..a975db5e --- /dev/null +++ b/ui/assets/global.scss @@ -0,0 +1,58 @@ +@import "variables"; +@import "node_modules/swiper/swiper.scss"; +@import "../node_modules/react-github-button/assets/style.css"; +@import "../node_modules/leaflet/dist/leaflet.css"; + +:root { + --backgroundColor: #{$background-color}; + --primaryColor: #{$primary-color}; + --textColorSecondary: #{$text-color-secondary}; + + --amplify-primary-color: #{$primary-color}; + --amplify-primary-tint: #{lighten($primary-color, 0.1)}; + --amplify-primary-shade: #{$primary-color}; +} + +.sidebar-toggle { + font-size: 18px; + line-height: 64px; + padding: 0 24px; + cursor: pointer; + transition: color 0.3s; + color: #FFF; + + &:hover { + color: #1890ff; + } +} + +.full-height { + height: 100vh; + height: calc(var(--vh, 1vh) * 100); +} + +.ant-spin-nested-loading > div > .ant-spin { + max-height: unset; +} + +.swiper-container { + height: 100vh; + height: calc(var(--vh, 1vh) * 100); + + .swiper-wrapper { + position: fixed + } +} + +.admin { + .sidemenu { + .ant-layout-sider-children { + display: flex; + flex-direction: column; + + .language-selector { + padding-left: 12px !important; + } + } + } +} diff --git a/ui/assets/images/logo_white.png b/ui/assets/images/logo_white.png new file mode 100644 index 0000000000000000000000000000000000000000..cc9bb06b7db162bebd869a5ddf3c3e6e8320d404 GIT binary patch literal 60482 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 literal 0 HcmV?d00001 diff --git a/ui/assets/images/logo_white_small.png b/ui/assets/images/logo_white_small.png new file mode 100644 index 0000000000000000000000000000000000000000..99c79d8a5f936ca58bfc69627fff889d5e303b9a GIT binary patch literal 33363 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 UH=se$5C-~DkX4bXmNE(bKg^)GC;$Ke literal 0 HcmV?d00001 diff --git a/ui/assets/images/marker-icon-2x.png b/ui/assets/images/marker-icon-2x.png new file mode 100644 index 0000000000000000000000000000000000000000..88f9e501888c9c6cb29ad340d9a888627dd1b6d8 GIT binary patch literal 2464 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 literal 0 HcmV?d00001 diff --git a/ui/assets/images/marker-shadow.png b/ui/assets/images/marker-shadow.png new file mode 100644 index 0000000000000000000000000000000000000000..9fd2979532a19a15b824ce763c76e04a8dafadfb GIT binary patch literal 618 zcmV-w0+s!VP)<h;3K|Lk000e1NJLTq001cf001cn1ONa40%^#70006pNkl<ZcmeIw zg^uGu5CqT)GyVU69WyhA4Rfv1l&qHB$KsvZaQsx;oqodqP9OjM+>ke9$Lam@{1K@O ze*LXqlKQHiv=gx+V^Cbb2?z@ISBQ*3amF;9UJ3SBg(N|710TLamQmYZ&Qjn2LuO<* zCZlB4n%@pc&7NNnY1}x+NWpHlq`OJEo|`aYN9<`RBUB+79g;>dgb6YlfN#kGL?lO_ z!6~M^7s<Gunku4}oCz-(lbU68)PP!;P_>OnbsUkKk<@Ysie&`G>ruxH&Mgy&8;i=A zB9OO!xR{AyODw>DS-q5YM<tr&0OJhK)KQ42rl<PpbdcQi3@gi=Q)DY%>{0ExFEAzt zm>RdS+ssW(-8|?xr0(?$vBVB*%(xDLtq3Hf0I5yFm<_g=W2`QWAax{1rWVH=I!VrP zs(rTFX@W#t$hXNvbgX`gK&^w_YD;CQ!B@e0QbLIWaKAXQe2-kkloo;{iF#6}z!4=W zi$giRj1{<MQYafm<N;SepyTR{T`X5iA(Wqm8yCrb?x#{3bi&bc!kMT@fkDfJv!SI> zt;2w`VSCF#WE&*ev7jpsC=6175@(~nTE2;7M-L((0bH@yG}-TB$R~WXd?tA$s3|%y zA`9$sA(>F%J3ioz<-LJl*^o1|w84l>HBR`>3l9c8$5Xr@xCiIQ7{x$fMCzOk_-M=% z+{a_Q#;42`#KfUte@$NT77uaTz?b-fBe)1s5XE$yA79fm?KqM^VgLXD07*qoM6N<$ Ef<_J(9smFU literal 0 HcmV?d00001 diff --git a/ui/assets/variables.scss b/ui/assets/variables.scss new file mode 100644 index 00000000..0535181e --- /dev/null +++ b/ui/assets/variables.scss @@ -0,0 +1,3 @@ +$background-color: #f7f7f7; +$primary-color: #4182e4; +$text-color-secondary: rgba(0, 0, 0, 0.45); diff --git a/ui/components/auth/footer.module.scss b/ui/components/auth/footer.module.scss new file mode 100644 index 00000000..8709e0e6 --- /dev/null +++ b/ui/components/auth/footer.module.scss @@ -0,0 +1,18 @@ +.footer { + position: absolute; + padding-left: 16px; + margin-bottom: 4px; + bottom: 0; + left: 0; + right: 0; + display: flex; + flex-direction: row; + align-items: center; + + @media (max-width: 600px) { + position: relative; + margin-bottom: 16px; + flex-direction: column; + text-align: center; + } +} diff --git a/ui/components/auth/footer.tsx b/ui/components/auth/footer.tsx new file mode 100644 index 00000000..bb4f76d4 --- /dev/null +++ b/ui/components/auth/footer.tsx @@ -0,0 +1,142 @@ +import { Button, Select } from 'antd' +import Link from 'next/link' +import { useRouter } from 'next/router' +import React from 'react' +import GitHubButton from 'react-github-button' +import { useTranslation } from 'react-i18next' +import { useSettingsQuery } from '../../graphql/query/settings.query' +import { languages } from '../../i18n' +import { clearAuth, withAuth } from '../with.auth' +import scss from './footer.module.scss' + +interface Props { + me?: { + id: string + username: string + roles: string[] + } +} + +const AuthFooterInner: React.FC<Props> = (props) => { + const { t, i18n } = useTranslation() + const router = useRouter() + const { data, loading } = useSettingsQuery() + + const logout = () => { + clearAuth() + router.reload() + } + + return ( + <footer className={scss.footer}> + {props.me + ? [ + <span style={{ color: '#FFF' }} key={'user'}> + Hi, {props.me.username} + </span>, + props.me.roles.includes('admin') && ( + <Link key={'admin'} href={'/admin'}> + <Button + type={'link'} + style={{ + color: '#FFF', + }} + > + {t('admin')} + </Button> + </Link> + ), + <Link key={'profile'} href={'/admin/profile'}> + <Button + type={'link'} + style={{ + color: '#FFF', + }} + > + {t('profile')} + </Button> + </Link>, + <Button + key={'logout'} + type={'link'} + onClick={logout} + style={{ + color: '#FFF', + }} + > + {t('logout')} + </Button>, + ] + : [ + <Link href={'/login'} key={'login'}> + <Button + type={'link'} + style={{ + color: '#FFF', + }} + > + {t('login')} + </Button> + </Link>, + !loading && !data?.disabledSignUp.value && ( + <Link href={'/register'} key={'register'}> + <Button + type={'link'} + style={{ + color: '#FFF', + }} + > + {t('register')} + </Button> + </Link> + ), + ]} + <div style={{ flex: 1 }} /> + <Select + bordered={false} + value={i18n.language.replace(/-.*/, '')} + onChange={(next) => i18n.changeLanguage(next)} + style={{ + color: '#FFF', + paddingLeft: 18, + }} + suffixIcon={false} + > + {languages.map((language) => ( + <Select.Option value={language} key={language}> + {t(`language:${language}`)} + </Select.Option> + ))} + </Select> + {!loading && !data?.hideContrib.value && ( + <> + <GitHubButton type="stargazers" namespace="ohmyform" repo="ohmyform" /> + <Button + type={'link'} + target={'_blank'} + rel={'noreferrer'} + href={'https://www.ohmyform.com'} + style={{ + color: '#FFF', + }} + > + OhMyForm + </Button> + <Button + type={'link'} + target={'_blank'} + rel={'noreferrer'} + href={'https://lokalise.com/'} + style={{ + color: '#FFF', + }} + > + translated with Lokalize + </Button> + </> + )} + </footer> + ) +} + +export const AuthFooter = withAuth(AuthFooterInner, [], true) diff --git a/ui/components/auth/layout.tsx b/ui/components/auth/layout.tsx new file mode 100644 index 00000000..f86eb723 --- /dev/null +++ b/ui/components/auth/layout.tsx @@ -0,0 +1,25 @@ +import { Layout, Spin } from 'antd' +import getConfig from 'next/config' +import React from 'react' +import { NextConfigType } from '../../next.config.type' + +const { publicRuntimeConfig } = getConfig() as NextConfigType + +interface Props { + loading?: boolean +} + +export const AuthLayout: React.FC<Props> = (props) => { + return ( + <Spin spinning={props.loading || false}> + <Layout + style={{ + height: '100vh', + background: publicRuntimeConfig.mainBackground, + }} + > + {props.children} + </Layout> + </Spin> + ) +} diff --git a/ui/components/clean.input.ts b/ui/components/clean.input.ts new file mode 100644 index 00000000..7771a15c --- /dev/null +++ b/ui/components/clean.input.ts @@ -0,0 +1,27 @@ +/* eslint-disable */ +const omitDeepArrayWalk = (arr, key) => { + return arr.map((val) => { + if (Array.isArray(val)) return omitDeepArrayWalk(val, key) + else if (typeof val === 'object') return omitDeep(val, key) + return val + }) +} + +const omitDeep = (obj: any, key: string | number): any => { + const keys: Array<any> = Object.keys(obj) + const newObj: any = {} + keys.forEach((i: any) => { + if (i !== key) { + const val: any = obj[i] + if (val instanceof Date) newObj[i] = val + else if (Array.isArray(val)) newObj[i] = omitDeepArrayWalk(val, key) + else if (typeof val === 'object' && val !== null) newObj[i] = omitDeep(val, key) + else newObj[i] = val + } + }) + return newObj +} + +export const cleanInput = <T>(obj: T): T => { + return omitDeep(obj, '__typename') +} diff --git a/ui/components/date.time.tsx b/ui/components/date.time.tsx new file mode 100644 index 00000000..7467de50 --- /dev/null +++ b/ui/components/date.time.tsx @@ -0,0 +1,22 @@ +import dayjs from 'dayjs' +import React from 'react' + +interface Props { + date: string + + hideTime?: boolean +} + +export const DateTime: React.FC<Props> = (props) => { + const format = props.hideTime ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm' + + return ( + <div + style={{ + display: 'inline-block', + }} + > + {dayjs(props.date).format(format)} + </div> + ) +} diff --git a/ui/components/error.page.tsx b/ui/components/error.page.tsx new file mode 100644 index 00000000..09d369e7 --- /dev/null +++ b/ui/components/error.page.tsx @@ -0,0 +1,18 @@ +import React from 'react' + +export const ErrorPage: React.FC = () => { + return ( + <div + style={{ + height: '100vh', + justifyContent: 'center', + alignItems: 'center', + display: 'flex', + flexDirection: 'column', + }} + > + <h1>ERROR</h1> + <p>there was an error with your request</p> + </div> + ) +} diff --git a/ui/components/form/admin/base.data.tab.tsx b/ui/components/form/admin/base.data.tab.tsx new file mode 100644 index 00000000..67b609a1 --- /dev/null +++ b/ui/components/form/admin/base.data.tab.tsx @@ -0,0 +1,69 @@ +import { Form, Input, Select, Switch, Tabs } from 'antd' +import { TabPaneProps } from 'antd/lib/tabs' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { languages } from '../../../i18n' + +export const BaseDataTab: React.FC<TabPaneProps> = (props) => { + const { t } = useTranslation() + + return ( + <Tabs.TabPane {...props}> + <Form.Item + label={t('form:baseData.isLive')} + name={['form', 'isLive']} + valuePropName={'checked'} + > + <Switch /> + </Form.Item> + + <Form.Item + label={t('form:baseData.title')} + name={['form', 'title']} + rules={[ + { + required: true, + message: t('validation:titleRequired'), + }, + ]} + > + <Input /> + </Form.Item> + + <Form.Item + label={t('form:baseData.language')} + name={['form', 'language']} + rules={[ + { + required: true, + message: t('validation:languageRequired'), + }, + ]} + > + <Select> + {languages.map((language) => ( + <Select.Option value={language} key={language}> + {t(`language:${language}`)} + </Select.Option> + ))} + </Select> + </Form.Item> + + <Form.Item + label={t('form:baseData.showFooter')} + name={['form', 'showFooter']} + valuePropName={'checked'} + > + <Switch /> + </Form.Item> + + <Form.Item + label={t('form:baseData.anonymousSubmission')} + name={['form', 'anonymousSubmission']} + valuePropName={'checked'} + > + <Switch /> + </Form.Item> + </Tabs.TabPane> + ) +} diff --git a/ui/components/form/admin/design.tab.tsx b/ui/components/form/admin/design.tab.tsx new file mode 100644 index 00000000..ce2a3c1a --- /dev/null +++ b/ui/components/form/admin/design.tab.tsx @@ -0,0 +1,49 @@ +import { Form, Input, Select, Tabs } from 'antd' +import { TabPaneProps } from 'antd/lib/tabs' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { InputColor } from '../../input/color' + +export const DesignTab: React.FC<TabPaneProps> = (props) => { + const { t } = useTranslation() + + return ( + <Tabs.TabPane {...props}> + <Form.Item label={t('form:design.font')} name={[ + 'form', 'design', 'font', + ]}> + <Input /> + </Form.Item> + <Form.Item label={t('form:design.layouts')} name={[ + 'form', 'design', 'layout', + ]}> + <Select + options={[ + { + value: null, + label: t('form:design.layout.slider'), + }, + { + value: 'card', + label: t('form:design.layout.card'), + }, + ]} + /> + </Form.Item> + + {[ + 'background', 'question', 'answer', 'button', 'buttonActive', 'buttonText', + ].map((name) => ( + <Form.Item + key={name} + label={t(`form:design.color.${name}`)} + name={[ + 'form', 'design', 'colors', name, + ]} + > + <InputColor /> + </Form.Item> + ))} + </Tabs.TabPane> + ) +} diff --git a/ui/components/form/admin/end.page.tab.tsx b/ui/components/form/admin/end.page.tab.tsx new file mode 100644 index 00000000..49f7cb21 --- /dev/null +++ b/ui/components/form/admin/end.page.tab.tsx @@ -0,0 +1,130 @@ +import { DeleteOutlined, PlusOutlined } from '@ant-design/icons/lib' +import { Button, Card, Form, Input, Switch, Tabs } from 'antd' +import { TabPaneProps } from 'antd/lib/tabs' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { InputColor } from '../../input/color' + +export const EndPageTab: React.FC<TabPaneProps> = (props) => { + const { t } = useTranslation() + + return ( + <Tabs.TabPane {...props}> + <Form.Item + label={t('form:endPage.show')} + name={[ + 'form', 'endPage', 'show', + ]} + valuePropName={'checked'} + > + <Switch /> + </Form.Item> + + <Form.Item label={t('form:endPage.title')} name={[ + 'form', 'endPage', 'title', + ]}> + <Input /> + </Form.Item> + + <Form.Item + label={t('form:endPage.paragraph')} + name={[ + 'form', 'endPage', 'paragraph', + ]} + extra={t('type:descriptionInfo')} + > + <Input.TextArea autoSize /> + </Form.Item> + + <Form.Item + label={t('form:endPage.continueButtonText')} + name={[ + 'form', 'endPage', 'buttonText', + ]} + > + <Input /> + </Form.Item> + + <Form.List name={[ + 'form', 'endPage', 'buttons', + ]}> + {(fields, { add, remove }) => { + return ( + <div> + {fields.map((field, index) => ( + <Form.Item + wrapperCol={{ + sm: { offset: index === 0 ? 0 : 6 }, + }} + label={index === 0 ? t('form:endPage.buttons') : ''} + key={field.key} + > + <Card actions={[<DeleteOutlined key={'delete'} onClick={() => remove(index)} />]}> + <Form.Item + label={t('form:endPage.url')} + name={[field.key, 'url']} + rules={[{ type: 'url', message: t('validation:invalidUrl') }]} + labelCol={{ span: 6 }} + > + <Input /> + </Form.Item> + <Form.Item + label={t('form:endPage.action')} + name={[field.key, 'action']} + labelCol={{ span: 6 }} + > + <Input /> + </Form.Item> + <Form.Item + label={t('form:endPage.text')} + name={[field.key, 'text']} + labelCol={{ span: 6 }} + > + <Input /> + </Form.Item> + <Form.Item + label={t('form:endPage.bgColor')} + name={[field.key, 'bgColor']} + labelCol={{ span: 6 }} + > + <InputColor /> + </Form.Item> + <Form.Item + label={t('form:endPage.activeColor')} + name={[field.key, 'activeColor']} + labelCol={{ span: 6 }} + > + <InputColor /> + </Form.Item> + <Form.Item + label={t('form:endPage.color')} + name={[field.key, 'color']} + labelCol={{ span: 6 }} + > + <InputColor /> + </Form.Item> + </Card> + </Form.Item> + ))} + <Form.Item + wrapperCol={{ + sm: { offset: 6 }, + }} + > + <Button + type="dashed" + onClick={() => { + add() + }} + style={{ width: '60%' }} + > + <PlusOutlined /> {t('form:endPage.addButton')} + </Button> + </Form.Item> + </div> + ) + }} + </Form.List> + </Tabs.TabPane> + ) +} diff --git a/ui/components/form/admin/export.submission.action.tsx b/ui/components/form/admin/export.submission.action.tsx new file mode 100644 index 00000000..3d722097 --- /dev/null +++ b/ui/components/form/admin/export.submission.action.tsx @@ -0,0 +1,125 @@ +import { message } from 'antd' +import ExcelJS, { CellValue } from 'exceljs' +import { useCallback, useState } from 'react' +import { SubmissionFragment } from '../../../graphql/fragment/submission.fragment' +import { useFormQuery } from '../../../graphql/query/form.query' +import { useSubmissionPagerImperativeQuery } from '../../../graphql/query/submission.pager.query' +import { fieldTypes } from '../types' + +interface Props { + form: string + trigger: (open: () => any, loading: boolean) => JSX.Element +} + +export const ExportSubmissionAction: React.FC<Props> = (props) => { + const [loading, setLoading] = useState(false) + + const form = useFormQuery({ + variables: { + id: props.form, + }, + }) + + const getSubmissions = useSubmissionPagerImperativeQuery() + + const exportSubmissions = useCallback(async () => { + if (loading) { + return + } + + setLoading(true) + + try { + const workbook = new ExcelJS.Workbook() + workbook.creator = 'OhMyForm' + workbook.lastModifiedBy = 'OhMyForm' + workbook.created = new Date() + workbook.modified = new Date() + + const orderedFields = form.data.form.fields + .map(field => field) + .sort((a, b) => (a.idx ?? 0) - (b.idx ?? 0)) + + // TODO should go through deleted fields as well to have a complete overview! + + const sheet = workbook.addWorksheet('Submissions') + sheet.getRow(1).values = [ + 'Submission ID', + 'Created', + 'Last Change', + 'Country', + 'City', + 'User Agent', + 'Device', + ...orderedFields.map((field) => `${field.title} (${field.type})`), + ] + + const firstPage = await getSubmissions({ + form: props.form, + limit: 50, + start: 0, + }) + + const buildRow = (data: SubmissionFragment): CellValue[] => { + const row: CellValue[] = [ + data.id, + data.created, + data.lastModified, + data.geoLocation.country, + data.geoLocation.city, + data.device.type, + data.device.name, + ] + + orderedFields.forEach((formField) => { + const field = data.fields.find(submission => submission.field?.id === formField.id) + + try { + fieldTypes[field.type]?.stringifyValue(field.value) + + row.push(fieldTypes[field.type]?.stringifyValue(field.value)) + } catch (e) { + row.push('') + } + }) + + return row + } + + firstPage.data.pager.entries.forEach((row, index) => { + sheet.getRow(index + 2).values = buildRow(row) + }) + + const pages = Math.ceil(firstPage.data.pager.total / 50) + for (let page = 1; page < pages; page++) { + // now process each page! + const next = await getSubmissions({ + form: props.form, + limit: 50, + start: page * 50, + }) + + next.data.pager.entries.forEach((row, index) => { + sheet.getRow(index + 2 + page * 50).values = buildRow(row) + }) + } + + const buffer = await workbook.xlsx.writeBuffer() + + const link = document.createElement('a') + link.href = window.URL.createObjectURL(new Blob([buffer], { type: 'application/xlsx' })) + link.download = 'submissions.xlsx' + link.click() + } catch (e) { + console.log('error', e) + void message.error({ + content: 'Failed to generate export', + }) + } + setLoading(false) + }, [ + form, getSubmissions, props.form, setLoading, loading, + ]) + + return props.trigger(() => exportSubmissions(), loading) +} diff --git a/ui/components/form/admin/field.card.tsx b/ui/components/form/admin/field.card.tsx new file mode 100644 index 00000000..788f0e80 --- /dev/null +++ b/ui/components/form/admin/field.card.tsx @@ -0,0 +1,244 @@ +import { VerticalAlignBottomOutlined, VerticalAlignTopOutlined } from '@ant-design/icons' +import { DeleteOutlined, PlusOutlined } from '@ant-design/icons/lib' +import { Button, Card, Checkbox, Form, Input, Popconfirm, Popover, Space, Tag, Tooltip } from 'antd' +import { FormInstance } from 'antd/lib/form' +import { FieldData } from 'rc-field-form/lib/interface' +import React, { useCallback, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { FormFieldFragment, FormFieldLogicFragment } from '../../../graphql/fragment/form.fragment' +import { fieldTypes } from '../types' +import { LogicBlock } from './logic.block' + +interface Props { + form: FormInstance + fields: FormFieldFragment[] + onChangeFields: (fields: FormFieldFragment[]) => void + field: FieldData + remove: (index: number) => void + move: (from: number, to: number) => void + index: number +} + +export const FieldCard: React.FC<Props> = ({ + form, + field, + fields, + onChangeFields, + remove, + move, + index, +}) => { + const { t } = useTranslation() + + const type = form.getFieldValue([ + 'form', 'fields', field.name as string, 'type', + ]) as string + const TypeComponent = (fieldTypes[type] || fieldTypes['textfield']).adminFormField() + + const [shouldUpdate, setShouldUpdate] = useState(false) + const [nextTitle, setNextTitle] = useState<string>( + form.getFieldValue([ + 'form', 'fields', field.name as string, 'title', + ]) + ) + + useEffect(() => { + if (!shouldUpdate) { + return + } + + const id = setTimeout(() => { + setShouldUpdate(false) + onChangeFields( + fields.map((field, i) => { + if (i === index) { + return { + ...field, + title: nextTitle, + } + } else { + return field + } + }) + ) + }, 500) + + return () => clearTimeout(id) + }, [ + nextTitle, shouldUpdate, fields, + ]) + + const addLogic = useCallback((add: (defaults: unknown) => void, index: number) => { + return ( + <Form.Item wrapperCol={{ span: 24 }}> + <Space + style={{ + width: '100%', + justifyContent: 'flex-end', + }} + > + <Button + type="dashed" + onClick={() => { + const defaults: FormFieldLogicFragment = { + id: `NEW-${Date.now()}`, + formula: null, + action: null, + jumpTo: null, + visible: null, + disable: null, + require: null, + enabled: false, + } + + add(defaults) + }} + > + <PlusOutlined /> {t('form:logic.add')} + </Button> + </Space> + </Form.Item> + ) + }, []) + + return ( + <Card + title={nextTitle} + type={'inner'} + extra={ + <Space> + <Tooltip title={t('form:field.move.up')}> + <Button + type={'text'} + disabled={index === 0} + onClick={() => move(index, index - 1)} + icon={<VerticalAlignTopOutlined />} + /> + </Tooltip> + <Tooltip title={t('form:field.move.down')}> + <Button + type={'text'} + disabled={index + 1 >= form.getFieldValue(['form', 'fields']).length} + onClick={() => move(index, index + 1)} + icon={<VerticalAlignBottomOutlined />} + /> + </Tooltip> + <Form.Item noStyle shouldUpdate> + {() => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const slug = form.getFieldValue([ + 'form', 'fields', field.name as string, 'slug', + ]) + + if (!slug) { + return null + } + + return <Tag color={'warning'}>Slug: {slug}</Tag> + }} + </Form.Item> + <Popover + placement={'left'} + content={ + <Form.Item + name={[field.name as string, 'slug']} + label={false} + rules={[ + { + pattern: /^[a-z0-9_]+$/, + message: t('validation:invalidSlug'), + }, + ]} + help={t('type:slugInfo')} + > + <Input /> + </Form.Item> + } + title={t('type:slug')} + > + <Tag color={'blue'}>{t(`type:${type}.name`)}</Tag> + </Popover> + <Popconfirm + placement={'left'} + title={t('type:confirmDelete')} + okText={t('type:deleteNow')} + okButtonProps={{ danger: true }} + onConfirm={() => { + remove(index) + onChangeFields(fields.filter((e, i) => i !== index)) + }} + > + <Button danger> + <DeleteOutlined /> + </Button> + </Popconfirm> + </Space> + } + > + <Form.Item name={[field.name as string, 'type']} noStyle> + <Input type={'hidden'} /> + </Form.Item> + <Form.Item + label={t('type:title')} + name={[field.name as string, 'title']} + rules={[{ required: true, message: 'Title is required' }]} + labelCol={{ span: 6 }} + > + <Input + onChange={(e) => { + setNextTitle(e.target.value) + setShouldUpdate(true) + }} + /> + </Form.Item> + <Form.Item + label={t('type:description')} + name={[field.name as string, 'description']} + labelCol={{ span: 6 }} + extra={t('type:descriptionInfo')} + > + <Input.TextArea autoSize /> + </Form.Item> + <Form.Item + label={t('type:required')} + name={[field.name as string, 'required']} + labelCol={{ span: 6 }} + valuePropName={'checked'} + extra={type === 'hidden' && t('type:requiredInfo')} + > + <Checkbox /> + </Form.Item> + + <TypeComponent field={field} form={form} /> + + <Form.List name={[field.name as string, 'logic']}> + {(logic, { add, remove, move }) => { + const addAndMove = (index: number) => (defaults) => { + add(defaults) + move(fields.length, index) + } + + return ( + <div> + {addLogic(addAndMove(0), 0)} + {logic.map((field, index) => ( + <div key={field.key}> + <Form.Item wrapperCol={{ span: 24 }} noStyle> + <LogicBlock + field={field} + form={form} + fields={fields} + index={index} + remove={remove} + /> + </Form.Item> + {addLogic(addAndMove(index + 1), index + 1)} + </div> + ))} + </div> + ) + }} + </Form.List> + </Card> + ) +} diff --git a/ui/components/form/admin/fields.tab.tsx b/ui/components/form/admin/fields.tab.tsx new file mode 100644 index 00000000..b9d2593d --- /dev/null +++ b/ui/components/form/admin/fields.tab.tsx @@ -0,0 +1,124 @@ +import { PlusOutlined } from '@ant-design/icons/lib' +import { Button, Form, Select, Space, Tabs } from 'antd' +import { FormInstance } from 'antd/lib/form' +import { TabPaneProps } from 'antd/lib/tabs' +import debug from 'debug' +import { FieldData } from 'rc-field-form/lib/interface' +import React, { useCallback, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { FormFieldFragment } from '../../../graphql/fragment/form.fragment' +import { fieldTypes } from '../types' +import { FieldCard } from './field.card' + +const logger = debug('FieldsTab') + +interface Props extends TabPaneProps { + form: FormInstance + fields: FormFieldFragment[] + onChangeFields: (fields: FormFieldFragment[]) => void +} + +export const FieldsTab: React.FC<Props> = (props) => { + const { t } = useTranslation() + const [nextType, setNextType] = useState('textfield') + + const renderType = useCallback( + ( + field: FieldData, + index: number, + remove: (index: number) => void, + move: (from: number, to: number) => void + ) => { + return ( + <FieldCard + form={props.form} + field={field} + index={index} + remove={(index: number) => { + logger('remove %d', index) + remove(index) + }} + move={(from: number, to: number) => { + logger('move %d TO %d', from, to) + move(from, to) + }} + fields={props.fields} + onChangeFields={props.onChangeFields} + /> + ) + }, + [props.fields] + ) + + const addField = useCallback( + (add: (defaults: unknown) => void, index: number) => { + return ( + <Form.Item wrapperCol={{ span: 24 }}> + <Space + style={{ + width: '100%', + justifyContent: 'flex-end', + }} + > + <Select value={nextType} onChange={(e) => setNextType(e)} style={{ minWidth: 200 }}> + {Object.keys(fieldTypes).map((type) => ( + <Select.Option value={type} key={type}> + {t(`type:${type}.name`)} + </Select.Option> + ))} + </Select> + <Button + type="dashed" + onClick={() => { + const defaults: FormFieldFragment = { + logic: [], + options: [], + id: `NEW-${Date.now()}`, + type: nextType, + title: '', + description: '', + required: false, + } + + add(defaults) + const next = [...props.fields] + next.splice(index, 0, defaults) + props.onChangeFields(next) + }} + > + <PlusOutlined /> {t('type:add')} + </Button> + </Space> + </Form.Item> + ) + }, + [props.fields, nextType] + ) + + return ( + <Tabs.TabPane {...props}> + <Form.List name={['form', 'fields']}> + {(fields, { add, remove, move }) => { + const addAndMove = (index: number) => (defaults) => { + add(defaults) + move(fields.length, index) + } + + return ( + <div> + {addField(addAndMove(0), 0)} + {fields.map((field, index) => ( + <div key={field.key}> + <Form.Item wrapperCol={{ span: 24 }}> + {renderType(field, index, remove, move)} + </Form.Item> + {addField(addAndMove(index + 1), index + 1)} + </div> + ))} + </div> + ) + }} + </Form.List> + </Tabs.TabPane> + ) +} diff --git a/ui/components/form/admin/hooks.tab.tsx b/ui/components/form/admin/hooks.tab.tsx new file mode 100644 index 00000000..04765018 --- /dev/null +++ b/ui/components/form/admin/hooks.tab.tsx @@ -0,0 +1,98 @@ +import { DeleteOutlined, PlusOutlined } from '@ant-design/icons/lib' +import { Button, Card, Checkbox, Form, Input, Popconfirm, Space, Tabs } from 'antd' +import { TabPaneProps } from 'antd/lib/tabs' +import React from 'react' +import { useTranslation } from 'react-i18next' + +interface Props extends TabPaneProps {} + +export const HooksTab: React.FC<Props> = (props) => { + const { t } = useTranslation() + + return ( + <Tabs.TabPane {...props}> + <Form.List name={['form', 'hooks']}> + {(hooks, { add, remove }) => { + return ( + <div> + <Form.Item wrapperCol={{ span: 24 }}> + <Space + style={{ + width: '100%', + justifyContent: 'flex-end', + }} + > + <Button + type="dashed" + onClick={() => { + const defaults = { + id: `NEW-${Date.now()}`, + enabled: false, + url: '', + } + + add(defaults) + }} + > + <PlusOutlined /> {t('form:hooks.add')} + </Button> + </Space> + </Form.Item> + {hooks.map((hook, index) => ( + <div key={hook.key}> + <Form.Item wrapperCol={{ span: 24 }}> + <Card + title={ + <div> + <Form.Item + name={[hook.name, 'enabled']} + valuePropName={'checked'} + noStyle + > + <Checkbox /> + </Form.Item> +  {t('form:hooks.enabled')} + </div> + } + type={'inner'} + extra={ + <div> + <Popconfirm + placement={'left'} + title={t('form:hooks.confirmDelete')} + okText={t('form:hooks.deleteNow')} + okButtonProps={{ danger: true }} + onConfirm={() => { + remove(index) + }} + > + <Button danger> + <DeleteOutlined /> + </Button> + </Popconfirm> + </div> + } + actions={[<DeleteOutlined key={'delete'} onClick={() => remove(index)} />]} + > + <Form.Item + label={t('form:hooks.url')} + name={[hook.name, 'url']} + rules={[ + { required: true, message: t('validation:urlRequired') }, + { type: 'url', message: t('validation:invalidUrl') }, + ]} + labelCol={{ span: 6 }} + > + <Input /> + </Form.Item> + </Card> + </Form.Item> + </div> + ))} + </div> + ) + }} + </Form.List> + </Tabs.TabPane> + ) +} diff --git a/ui/components/form/admin/is.live.tsx b/ui/components/form/admin/is.live.tsx new file mode 100644 index 00000000..863b4b72 --- /dev/null +++ b/ui/components/form/admin/is.live.tsx @@ -0,0 +1,26 @@ +import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons/lib' +import React from 'react' + +interface Props { + isLive: boolean +} + +export const FormIsLive: React.FC<Props> = (props) => { + if (props.isLive) { + return ( + <CheckCircleOutlined + style={{ + color: 'green', + }} + /> + ) + } + + return ( + <CloseCircleOutlined + style={{ + color: 'red', + }} + /> + ) +} diff --git a/ui/components/form/admin/logic.block.tsx b/ui/components/form/admin/logic.block.tsx new file mode 100644 index 00000000..7f806e5d --- /dev/null +++ b/ui/components/form/admin/logic.block.tsx @@ -0,0 +1,233 @@ +import { DeleteOutlined } from '@ant-design/icons' +import { Alert, Button, Checkbox, Form, Mentions, Popconfirm, Select } from 'antd' +import { FormInstance } from 'antd/lib/form' +import { FieldData } from 'rc-field-form/lib/interface' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FormFieldFragment } from '../../../graphql/fragment/form.fragment' +import { useMath } from '../../use.math' + +interface Props { + form: FormInstance + fields: FormFieldFragment[] + field: FieldData + remove: (index: number) => void + index: number +} + +export const LogicBlock: React.FC<Props> = ({ + form, + field, + fields, + remove, + index, +}) => { + const { t } = useTranslation() + const evaluator = useMath() + + return ( + <div + style={{ + borderRight: '5px solid #DDD', + paddingRight: 10, + }} + > + <Form.Item + name={[field.name as string, 'formula']} + labelCol={{ span: 6 }} + label={'Formula'} + rules={[{ required: true, message: 'combine other fields' }]} + extra={'Save form to get new @IDs and $slugs. (example: $slug < 21 or @id = 42)'} + > + <Mentions rows={1}> + {fields.map((field) => ( + <Mentions.Option key={field.id} value={field.id}> + {field.title} + </Mentions.Option> + ))} + </Mentions> + </Form.Item> + + <Form.Item noStyle shouldUpdate> + {(form: FormInstance & { prefixName: string[] }) => { + try { + const defaults = {} + + fields.forEach((field) => { + defaults[`@${field.id}`] = field.defaultValue + + if (field.slug) { + defaults[`$${field.slug}`] = field.defaultValue + } + }) + + const result = evaluator( + form.getFieldValue([ + ...form.prefixName, + field.name as string, + 'formula', + ]), + defaults + ) + + return ( + <Alert + type={result ? 'success' : 'warning'} + message={ + result + ? 'would trigger action with current default values' + : 'would NOT trigger action with current default values' + } + style={{ marginBottom: 24 }} + /> + ) + } catch (e) { + return ( + <Alert + message={(e as Error).message || 'Failed to process formula'} + type={'error'} + style={{ marginBottom: 24 }} + /> + ) + } + }} + </Form.Item> + <Form.Item name={[field.name as string, 'action']} labelCol={{ span: 6 }} label={'Action'}> + <Select + options={[ + { + value: 'jumpTo', + label: t('form:logic.action.jumpTo'), + }, + { + value: 'visible', + label: t('form:logic.action.visible'), + }, + { + value: 'disable', + label: t('form:logic.action.disable'), + }, + { + value: 'require', + label: t('form:logic.action.require'), + }, + ]} + /> + </Form.Item> + <Form.Item noStyle shouldUpdate> + {(form: FormInstance & { prefixName: string[] }) => { + return ( + <Form.Item + hidden={ + form.getFieldValue([ + ...form.prefixName, field.name as string, 'action', + ]) !== + 'jumpTo' + } + labelCol={{ span: 6 }} + label={t('form:logic.action.jumpTo')} + rules={[{ required: true, message: 'Jump target is required' }]} + extra={'after selecting field (works best with clickable values)'} + > + <Select + options={fields + .filter((field) => !/NEW/i.test(field.id)) + .map((field) => ({ + value: field.id, + label: field.title, + }))} + /> + </Form.Item> + ) + }} + </Form.Item> + + <Form.Item noStyle shouldUpdate> + {(form: FormInstance & { prefixName: string[] }) => { + return ( + <Form.Item + hidden={ + form.getFieldValue([ + ...form.prefixName, field.name as string, 'action', + ]) !== + 'visible' + } + initialValue={true} + labelCol={{ span: 6 }} + label={t('form:logic.action.visible')} + valuePropName={'checked'} + getValueFromEvent={(checked: boolean) => (checked ? '1' : '')} + getValueProps={(e: string) => ({ checked: !!e })} + > + <Checkbox /> + </Form.Item> + ) + }} + </Form.Item> + + <Form.Item noStyle shouldUpdate> + {(form: FormInstance & { prefixName: string[] }) => { + return ( + <Form.Item + hidden={ + form.getFieldValue([ + ...form.prefixName, field.name as string, 'action', + ]) !== + 'disable' + } + initialValue={false} + labelCol={{ span: 6 }} + label={t('form:logic.action.disable')} + valuePropName={'checked'} + getValueFromEvent={(checked: boolean) => (checked ? '1' : '')} + getValueProps={(e: string) => ({ checked: !!e })} + > + <Checkbox /> + </Form.Item> + ) + }} + </Form.Item> + + <Form.Item noStyle shouldUpdate> + {(form: FormInstance & { prefixName: string[] }) => { + return ( + <Form.Item + hidden={ + form.getFieldValue([ + ...form.prefixName, field.name as string, 'action', + ]) !== + 'require' + } + initialValue={true} + labelCol={{ span: 6 }} + label={t('form:logic.action.require')} + valuePropName={'checked'} + getValueFromEvent={(checked: boolean) => (checked ? '1' : '')} + getValueProps={(e: string) => ({ checked: !!e })} + > + <Checkbox /> + </Form.Item> + ) + }} + </Form.Item> + + <Form.Item> + <div style={{ textAlign: 'right' }}> + <Popconfirm + placement={'right'} + title={t('type:confirmDelete')} + okText={t('type:deleteNow')} + okButtonProps={{ danger: true }} + onConfirm={() => { + remove(index) + }} + > + <Button danger> + <DeleteOutlined /> + </Button> + </Popconfirm> + </div> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/admin/notification.card.tsx b/ui/components/form/admin/notification.card.tsx new file mode 100644 index 00000000..50004f96 --- /dev/null +++ b/ui/components/form/admin/notification.card.tsx @@ -0,0 +1,247 @@ +import { DeleteOutlined, InfoCircleOutlined } from '@ant-design/icons/lib' +import { Button, Card, Form, Input, Popconfirm, Select, Switch } from 'antd' +import { FormInstance } from 'antd/lib/form' +import { FieldData } from 'rc-field-form/lib/interface' +import React, { useState } from 'react' +import { Trans, useTranslation } from 'react-i18next' +import { FormFieldFragment } from '../../../graphql/fragment/form.fragment' + +interface Props { + form: FormInstance + field: FieldData + groups: { + [key: string]: FormFieldFragment[] + } + remove: (index: number) => void + index: number +} + +export const NotificationCard: React.FC<Props> = (props) => { + const { t } = useTranslation() + const { form, field, remove, index, groups } = props + + const [enabled, setEnabled] = useState<boolean>() + + return ( + <Card + title={'Notification'} + type={'inner'} + extra={ + <div> + <Popconfirm + placement={'left'} + title={t('type:confirmDelete')} + okText={t('type:deleteNow')} + okButtonProps={{ danger: true }} + onConfirm={() => { + remove(index) + }} + > + <Button danger> + <DeleteOutlined /> + </Button> + </Popconfirm> + </div> + } + actions={[<DeleteOutlined key={'delete'} onClick={() => remove(index)} />]} + > + <Form.Item + label={t('form:notifications.enabled')} + name={[field.name as string, 'enabled']} + valuePropName={'checked'} + labelCol={{ span: 6 }} + > + <Switch onChange={(e) => setEnabled(e.valueOf())} /> + </Form.Item> + + <Form.Item shouldUpdate noStyle> + {() => ( + <Form.Item + label={t('form:notifications.subject')} + name={[field.name as string, 'subject']} + rules={[ + { + required: Boolean( + form.getFieldValue([ + 'form', 'notifications', field.name as string, 'enabled', + ]) + ), + message: t('validation:subjectRequired'), + }, + ]} + labelCol={{ span: 6 }} + > + <Input /> + </Form.Item> + )} + </Form.Item> + + <Form.Item shouldUpdate noStyle> + {() => ( + <Form.Item + label={t('form:notifications.htmlTemplate')} + name={[field.name as string, 'htmlTemplate']} + rules={[ + { + required: Boolean( + form.getFieldValue([ + 'form', 'notifications', field.name as string, 'enabled', + ]) + ), + message: t('validation:templateRequired'), + }, + ]} + extra={ + <div> + <Trans>form:notifications.htmlTemplateInfo</Trans> + <a + href={'https://mjml.io/try-it-live'} + target={'_blank'} + rel={'noreferrer'} + style={{ + marginLeft: 16, + }} + > + <InfoCircleOutlined /> + </a> + </div> + } + labelCol={{ span: 6 }} + > + <Input.TextArea autoSize /> + </Form.Item> + )} + </Form.Item> + + <Form.Item shouldUpdate noStyle> + {() => ( + <Form.Item + label={t('form:notifications.fromField')} + name={[field.name as string, 'fromField']} + extra={t('form:notifications.fromFieldInfo')} + labelCol={{ span: 6 }} + rules={[ + { + required: Boolean( + form.getFieldValue([ + 'form', 'notifications', field.name as string, 'enabled', + ]) && + !form.getFieldValue([ + 'form', + 'notifications', + field.name as string, + 'fromEmail', + ]) + ), + message: t('validation:emailFieldRequired'), + }, + ]} + > + <Select> + {Object.keys(groups).map((key) => ( + <Select.OptGroup label={key.toUpperCase()} key={key}> + {groups[key].map((element) => ( + <Select.Option value={element.id} key={element.id}> + {element.title} + </Select.Option> + ))} + </Select.OptGroup> + ))} + </Select> + </Form.Item> + )} + </Form.Item> + + <Form.Item shouldUpdate noStyle> + {() => ( + <Form.Item + label={t('form:notifications.fromEmail')} + name={[field.name as string, 'fromEmail']} + extra={t('form:notifications.fromEmailInfo')} + labelCol={{ span: 6 }} + rules={[ + { + required: Boolean( + form.getFieldValue([ + 'form', 'notifications', field.name as string, 'enabled', + ]) && + !form.getFieldValue([ + 'form', + 'notifications', + field.name as string, + 'fromField', + ]) + ), + message: t('validation:emailFieldRequired'), + }, + ]} + > + <Input /> + </Form.Item> + )} + </Form.Item> + + <Form.Item shouldUpdate noStyle> + {() => ( + <Form.Item + label={t('form:notifications.toField')} + name={[field.name as string, 'toField']} + extra={t('form:notifications.toFieldInfo')} + rules={[ + { + required: Boolean( + form.getFieldValue([ + 'form', 'notifications', field.name as string, 'enabled', + ]) && + !form.getFieldValue([ + 'form', 'notifications', field.name as string, 'toEmail', + ]) + ), + message: t('validation:emailFieldRequired'), + }, + ]} + labelCol={{ span: 6 }} + > + <Select> + {Object.keys(groups).map((key) => ( + <Select.OptGroup label={key.toUpperCase()} key={key}> + {groups[key].map((field) => ( + <Select.Option value={field.id} key={field.id}> + {field.title} + </Select.Option> + ))} + </Select.OptGroup> + ))} + </Select> + </Form.Item> + )} + </Form.Item> + + <Form.Item shouldUpdate noStyle> + {() => ( + <Form.Item + label={t('form:notifications.toEmail')} + name={[field.name as string, 'toEmail']} + extra={t('form:notifications.toEmailInfo')} + labelCol={{ span: 6 }} + rules={[ + { + required: Boolean( + form.getFieldValue([ + 'form', 'notifications', field.name as string, 'enabled', + ]) && + !form.getFieldValue([ + 'form', 'notifications', field.name as string, 'toField', + ]) + ), + message: t('validation:emailFieldRequired'), + }, + ]} + > + <Input /> + </Form.Item> + )} + </Form.Item> + </Card> + ) +} diff --git a/ui/components/form/admin/notifications.tab.tsx b/ui/components/form/admin/notifications.tab.tsx new file mode 100644 index 00000000..b7af187e --- /dev/null +++ b/ui/components/form/admin/notifications.tab.tsx @@ -0,0 +1,93 @@ +import { PlusOutlined } from '@ant-design/icons/lib' +import { Button, Form, Space, Tabs } from 'antd' +import { FormInstance } from 'antd/lib/form' +import { TabPaneProps } from 'antd/lib/tabs' +import React, { useCallback } from 'react' +import { useTranslation } from 'react-i18next' +import { + FormFieldFragment, + FormNotificationFragment, +} from '../../../graphql/fragment/form.fragment' +import { NotificationCard } from './notification.card' + +interface Props extends TabPaneProps { + form: FormInstance + fields: FormFieldFragment[] +} + +export const NotificationsTab: React.FC<Props> = (props) => { + const { t } = useTranslation() + + const groups: { + [key: string]: FormFieldFragment[] + } = {} + props.fields.forEach((field) => { + if (!groups[field.type]) { + groups[field.type] = [] + } + groups[field.type].push(field) + }) + + const addField = useCallback( + (add: (defaults: unknown) => void, index: number) => { + return ( + <Form.Item wrapperCol={{ span: 24 }}> + <Space + style={{ + width: '100%', + justifyContent: 'flex-end', + }} + > + <Button + type="dashed" + onClick={() => { + const defaults: FormNotificationFragment = { + id: Math.random().toString(), + enabled: false, + } + + add(defaults) + }} + > + <PlusOutlined /> {t('form:notifications.add')} + </Button> + </Space> + </Form.Item> + ) + }, + [props.fields] + ) + + return ( + <Tabs.TabPane {...props}> + <Form.List name={['form', 'notifications']}> + {(fields, { add, remove, move }) => { + const addAndMove = (index: number) => (defaults) => { + add(defaults) + move(fields.length, index) + } + + return ( + <div> + {addField(addAndMove(0), 0)} + {fields.map((field, index) => ( + <div key={field.key}> + <Form.Item wrapperCol={{ span: 24 }}> + <NotificationCard + form={props.form} + field={field} + index={index} + remove={remove} + groups={groups} + /> + </Form.Item> + {addField(addAndMove(index + 1), index + 1)} + </div> + ))} + </div> + ) + }} + </Form.List> + </Tabs.TabPane> + ) +} diff --git a/ui/components/form/admin/start.page.tab.tsx b/ui/components/form/admin/start.page.tab.tsx new file mode 100644 index 00000000..7bc480bb --- /dev/null +++ b/ui/components/form/admin/start.page.tab.tsx @@ -0,0 +1,130 @@ +import { DeleteOutlined, PlusOutlined } from '@ant-design/icons/lib' +import { Button, Card, Form, Input, Switch, Tabs } from 'antd' +import { TabPaneProps } from 'antd/lib/tabs' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { InputColor } from '../../input/color' + +export const StartPageTab: React.FC<TabPaneProps> = (props) => { + const { t } = useTranslation() + + return ( + <Tabs.TabPane {...props}> + <Form.Item + label={t('form:startPage.show')} + name={[ + 'form', 'startPage', 'show', + ]} + valuePropName={'checked'} + > + <Switch /> + </Form.Item> + + <Form.Item label={t('form:startPage.title')} name={[ + 'form', 'startPage', 'title', + ]}> + <Input /> + </Form.Item> + + <Form.Item + label={t('form:startPage.paragraph')} + name={[ + 'form', 'startPage', 'paragraph', + ]} + extra={t('form:startPage.paragraphInfo')} + > + <Input.TextArea autoSize /> + </Form.Item> + + <Form.Item + label={t('form:startPage.continueButtonText')} + name={[ + 'form', 'startPage', 'buttonText', + ]} + > + <Input /> + </Form.Item> + + <Form.List name={[ + 'form', 'startPage', 'buttons', + ]}> + {(fields, { add, remove }) => { + return ( + <div> + {fields.map((field, index) => ( + <Form.Item + wrapperCol={{ + sm: { offset: index === 0 ? 0 : 6 }, + }} + label={index === 0 ? t('form:startPage.buttons') : ''} + key={field.key} + > + <Card actions={[<DeleteOutlined key={'delete'} onClick={() => remove(index)} />]}> + <Form.Item + label={t('form:startPage.url')} + name={[field.key, 'url']} + rules={[{ type: 'url', message: t('validation:invalidUrl') }]} + labelCol={{ span: 6 }} + > + <Input /> + </Form.Item> + <Form.Item + label={t('form:startPage.action')} + name={[field.key, 'action']} + labelCol={{ span: 6 }} + > + <Input /> + </Form.Item> + <Form.Item + label={t('form:startPage.text')} + name={[field.key, 'text']} + labelCol={{ span: 6 }} + > + <Input /> + </Form.Item> + <Form.Item + label={t('form:startPage.bgColor')} + name={[field.key, 'bgColor']} + labelCol={{ span: 6 }} + > + <InputColor /> + </Form.Item> + <Form.Item + label={t('form:startPage.activeColor')} + name={[field.key, 'activeColor']} + labelCol={{ span: 6 }} + > + <InputColor /> + </Form.Item> + <Form.Item + label={t('form:startPage.color')} + name={[field.key, 'color']} + labelCol={{ span: 6 }} + > + <InputColor /> + </Form.Item> + </Card> + </Form.Item> + ))} + <Form.Item + wrapperCol={{ + sm: { offset: 6 }, + }} + > + <Button + type="dashed" + onClick={() => { + add() + }} + style={{ width: '60%' }} + > + <PlusOutlined /> {t('form:startPage.addButton')} + </Button> + </Form.Item> + </div> + ) + }} + </Form.List> + </Tabs.TabPane> + ) +} diff --git a/ui/components/form/admin/submission.values.tsx b/ui/components/form/admin/submission.values.tsx new file mode 100644 index 00000000..b7b2d4e0 --- /dev/null +++ b/ui/components/form/admin/submission.values.tsx @@ -0,0 +1,63 @@ +import { Descriptions, Table } from 'antd' +import { ColumnsType } from 'antd/lib/table/interface' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FormPagerFragment } from '../../../graphql/fragment/form.pager.fragment' +import { + SubmissionFieldFragment, + SubmissionFragment, +} from '../../../graphql/fragment/submission.fragment' +import { fieldTypes } from '../types' + +interface Props { + form: FormPagerFragment + submission: SubmissionFragment +} + +export const SubmissionValues: React.FC<Props> = (props) => { + const { t } = useTranslation() + + const columns: ColumnsType<SubmissionFieldFragment> = [ + { + title: t('submission:field'), + render(_, row) { + if (row.field) { + return `${row.field.title}${row.field.required ? '*' : ''}` + } + + return `${row.id}` + }, + }, + { + title: t('submission:value'), + render(_, row) { + try { + return fieldTypes[row.type]?.displayValue(row.value) + } catch (e) { + return row.value + } + }, + }, + ] + + return ( + <div> + <Descriptions title={t('submission:submission')}> + <Descriptions.Item label={t('submission:country')}> + {props.submission.geoLocation.country} + </Descriptions.Item> + <Descriptions.Item label={t('submission:city')}> + {props.submission.geoLocation.city} + </Descriptions.Item> + <Descriptions.Item label={t('submission:device.type')}> + {props.submission.device.type} + </Descriptions.Item> + <Descriptions.Item label={t('submission:device.name')}> + {props.submission.device.name} + </Descriptions.Item> + </Descriptions> + + <Table columns={columns} dataSource={props.submission.fields} rowKey={'id'} /> + </div> + ) +} diff --git a/ui/components/form/layouts/card/field.tsx b/ui/components/form/layouts/card/field.tsx new file mode 100644 index 00000000..6eabaf10 --- /dev/null +++ b/ui/components/form/layouts/card/field.tsx @@ -0,0 +1,67 @@ +import React from 'react' +import { + FormPublicDesignFragment, + FormPublicFieldFragment, +} from '../../../../graphql/fragment/form.public.fragment' +import { StyledH1 } from '../../../styled/h1' +import { StyledMarkdown } from '../../../styled/markdown' +import { useRouter } from '../../../use.router' +import { fieldTypes } from '../../types' + +interface Props { + focus?: boolean + field: FormPublicFieldFragment + design: FormPublicDesignFragment +} + +export const Field: React.FC<Props> = ({ field, design, focus, ...props }) => { + const router = useRouter() + + const FieldInput = (fieldTypes[field.type] || fieldTypes['text']).inputFormField() + + const getUrlDefault = (): string => { + if (router.query[field.id]) { + return router.query[field.id] as string + } + + if (router.query[field.slug]) { + return router.query[field.slug] as string + } + + return undefined + } + + return ( + <div + {...props} + style={{ + display: 'flex', + flexDirection: 'column', + }} + > + <div + style={{ + flex: 1, + display: 'flex', + flexDirection: 'column', + padding: 32, + justifyContent: 'flex-end', + }} + > + <StyledH1 design={design} type={'question'}> + {field.title} + </StyledH1> + {field.description && ( + <StyledMarkdown design={design} type={'question'} >{field.description}</StyledMarkdown> + )} + + <FieldInput + design={design} + field={field} + urlValue={getUrlDefault()} + focus={focus} + /> + </div> + </div> + ) +} diff --git a/ui/components/form/layouts/card/index.module.scss b/ui/components/form/layouts/card/index.module.scss new file mode 100644 index 00000000..e69de29b diff --git a/ui/components/form/layouts/card/index.tsx b/ui/components/form/layouts/card/index.tsx new file mode 100644 index 00000000..76d108f8 --- /dev/null +++ b/ui/components/form/layouts/card/index.tsx @@ -0,0 +1,221 @@ +import { Card, Form, message, Modal, Spin } from 'antd' +import debug from 'debug' +import { darken, lighten } from 'polished' +import React, { useCallback, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' +import styled from 'styled-components' +import { Omf } from '../../../omf' +import { StyledButton } from '../../../styled/button' +import { useMath } from '../../../use.math' +import { fieldTypes } from '../../types' +import { LayoutProps } from '../layout.props' +import { Field } from './field' +import { Page } from './page' + +type Step = 'start' | 'form' | 'end' + +const logger = debug('layout/card') + +const MyCard = styled.div<{ background: string }>` + background: ${(props) => darken(0.1, props.background)}; + height: 100%; + min-height: 100vh; + min-height: calc(var(--vh, 1vh) * 100); + + padding: 32px; + + .ant-card { + background: ${(props) => props.background}; + border-color: ${(props) => lighten(0.4, props.background)}; + width: 800px; + margin: auto; + max-width: 90%; + } +` + +export const CardLayout: React.FC<LayoutProps> = (props) => { + const { t } = useTranslation() + const [form] = Form.useForm() + const [loading, setLoading] = useState(false) + const [step, setStep] = useState<Step>(props.form.startPage.show ? 'start' : 'form') + const evaluator = useMath() + const [visiblity, setVisibility] = useState({}) + + const { design, startPage, endPage, fields } = props.form + const { setField } = props.submission + + const updateValues = useCallback(() => { + const defaults = {} + + fields.forEach(field => { + const defaultValue = field.defaultValue + ? fieldTypes[field.type].parseValue(field.defaultValue) + : null + + defaults[`@${field.id}`] = form.getFieldValue([field.id, 'value']) ?? defaultValue + + if (field.slug) { + defaults[`$${field.slug}`] = form.getFieldValue([field.id, 'value']) ?? defaultValue + } + }) + + // now calculate visibility + const nextVisibility = {} + fields.forEach(field => { + if (!field.logic) return + + const logic = field.logic + .filter(logic => logic.action === 'visible') + + if (logic.length === 0) { + return + } + + nextVisibility[field.id] = logic + .map(logic => { + try { + const r = evaluator( + logic.formula, + defaults + ) + + return Boolean(r) + } catch { + return true + } + }) + .reduce<boolean>((previous, current) => previous && current, true) + }) + + // TODO improve logic of how we calculate new logic checks + if (Object.values(nextVisibility).join(',') == Object.values(visiblity).join(',')) { + return + } + + setVisibility(nextVisibility) + }, [ + fields, form, visiblity, + ]) + + useEffect(() => { + updateValues() + }, [updateValues]) + + const finish = async (data: { [key: number]: unknown }) => { + logger('finish form %O', data) + setLoading(true) + + try { + // save fields + await Promise.all(Object.keys(data).map((fieldId) => setField(fieldId, data[fieldId]))) + + await props.submission.finish() + + if (endPage.show) { + setStep('end') + } else { + Modal.success({ + content: t('form:submitted'), + okText: t('from:restart'), + onOk: () => { + window.location.reload() + }, + }) + } + } catch (e) { + logger('failed to finish form %O', e) + void message.error({ + content: 'Error saving Input', + }) + } + + setLoading(false) + } + + console.log('render') + + const render = () => { + switch (step) { + case 'start': + return <Page page={startPage} design={design} next={() => setStep('form')} /> + + case 'form': + return ( + <Card> + <Form + form={form} + onFinish={finish} + onValuesChange={updateValues} + > + {fields.map((field, i) => { + if (field.type === 'hidden') { + return null + } + + if (visiblity[field.id] === false) { + return null + } + + return ( + <Field + key={field.id} + field={field} + design={design} + focus={i === 0} + /> + ) + })} + <div + style={{ + padding: 32, + display: 'flex', + }} + > + {startPage.show && ( + <StyledButton + background={design.colors.button} + color={design.colors.buttonText} + highlight={design.colors.buttonActive} + onClick={() => setStep('start')} + > + {t('form:previous')} + </StyledButton> + )} + + <div style={{ flex: 1 }} /> + + <StyledButton + background={design.colors.button} + color={design.colors.buttonText} + highlight={design.colors.buttonActive} + size={'large'} + onClick={form.submit} + > + {t('form:next')} + </StyledButton> + </div> + </Form> + </Card> + ) + + case 'end': + return ( + <Page + page={endPage} + design={design} + next={() => { + window.location.reload() + }} + /> + ) + } + } + + return ( + <MyCard background={design.colors.background}> + <Omf /> + + <Spin spinning={loading}>{render()}</Spin> + </MyCard> + ) +} diff --git a/ui/components/form/layouts/card/page.tsx b/ui/components/form/layouts/card/page.tsx new file mode 100644 index 00000000..5514a21c --- /dev/null +++ b/ui/components/form/layouts/card/page.tsx @@ -0,0 +1,65 @@ +import { Card } from 'antd' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { + FormPublicDesignFragment, + FormPublicPageFragment, +} from '../../../../graphql/fragment/form.public.fragment' +import { StyledButton } from '../../../styled/button' +import { StyledH1 } from '../../../styled/h1' +import { StyledMarkdown } from '../../../styled/markdown' +import { PageButtons } from '../page.buttons' + +interface Props { + page: FormPublicPageFragment + design: FormPublicDesignFragment + + next?: () => void + prev?: () => void +} + +export const Page: React.FC<Props> = ({ design, page, next, prev }) => { + const { t } = useTranslation() + + return ( + <Card> + <StyledH1 design={design} type={'question'}> + {page.title} + </StyledH1> + <StyledMarkdown design={design} type={'question'}>{page.paragraph}</StyledMarkdown> + + <div + style={{ + padding: 32, + display: 'flex', + }} + > + {prev && ( + <StyledButton + background={design.colors.button} + color={design.colors.buttonText} + highlight={design.colors.buttonActive} + onClick={prev} + > + {t('form:restart')} + </StyledButton> + )} + <PageButtons buttons={page.buttons} /> + + <div style={{ flex: 1 }} /> + + {next && ( + <StyledButton + background={design.colors.button} + color={design.colors.buttonText} + highlight={design.colors.buttonActive} + size={'large'} + onClick={next} + > + {page.buttonText || t('form:continue')} + </StyledButton> + )} + </div> + </Card> + ) +} diff --git a/ui/components/form/layouts/layout.props.ts b/ui/components/form/layouts/layout.props.ts new file mode 100644 index 00000000..2e35c183 --- /dev/null +++ b/ui/components/form/layouts/layout.props.ts @@ -0,0 +1,7 @@ +import { FormPublicFragment } from '../../../graphql/fragment/form.public.fragment' +import { Submission } from '../../use.submission' + +export interface LayoutProps { + form: FormPublicFragment + submission: Submission +} diff --git a/ui/components/form/layouts/page.buttons.tsx b/ui/components/form/layouts/page.buttons.tsx new file mode 100644 index 00000000..beac63a6 --- /dev/null +++ b/ui/components/form/layouts/page.buttons.tsx @@ -0,0 +1,34 @@ +import { Space } from 'antd' +import React from 'react' +import { FormPublicPageButtonFragment } from '../../../graphql/fragment/form.public.fragment' +import { StyledButton } from '../../styled/button' + +interface Props { + buttons: FormPublicPageButtonFragment[] +} + +export const PageButtons: React.FC<Props> = ({ buttons }) => { + if (buttons.length === 0) { + return null + } + + return ( + <Space> + {buttons.map((button, key) => { + return ( + <StyledButton + background={button.bgColor} + color={button.color} + highlight={button.activeColor} + key={key} + href={button.url} + target={'_blank'} + rel={'noreferrer'} + > + {button.text} + </StyledButton> + ) + })} + </Space> + ) +} diff --git a/ui/components/form/layouts/slider/field.tsx b/ui/components/form/layouts/slider/field.tsx new file mode 100644 index 00000000..06eb8119 --- /dev/null +++ b/ui/components/form/layouts/slider/field.tsx @@ -0,0 +1,119 @@ +import { Form, message } from 'antd' +import { useForm } from 'antd/lib/form/Form' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { + FormPublicDesignFragment, + FormPublicFieldFragment, +} from '../../../../graphql/fragment/form.public.fragment' +import { StyledButton } from '../../../styled/button' +import { StyledH1 } from '../../../styled/h1' +import { StyledMarkdown } from '../../../styled/markdown' +import { useRouter } from '../../../use.router' +import { fieldTypes } from '../../types' + +interface Props { + focus: boolean + field: FormPublicFieldFragment + design: FormPublicDesignFragment + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + save: (data: any) => void + next: () => void + prev: () => void +} + +export const Field: React.FC<Props> = ({ field, save, design, next, prev, ...props }) => { + const [form] = useForm() + const router = useRouter() + const { t } = useTranslation() + + const FieldInput = (fieldTypes[field.type] || fieldTypes[field.type]).inputFormField() + + const finish = (data) => { + console.log('received field data', data) + save(data) + next() + } + + const error = async () => { + await message.error('Check inputs!') + } + + const getUrlDefault = (): string => { + if (router.query[field.id]) { + return router.query[field.id] as string + } + + if (router.query[field.slug]) { + return router.query[field.slug] as string + } + + return undefined + } + + return ( + <Form + form={form} + onFinish={finish} + onFinishFailed={error} + {...props} + style={{ + display: 'flex', + flexDirection: 'column', + height: '100%', + }} + > + <div + style={{ + flex: 1, + display: 'flex', + flexDirection: 'column', + padding: 32, + justifyContent: 'flex-end', + }} + > + <StyledH1 design={design} type={'question'}> + {field.title} + </StyledH1> + {field.description && ( + <StyledMarkdown design={design} type={'question'}>{field.description}</StyledMarkdown> + )} + + <FieldInput + design={design} + field={field} + focus={props.focus} + urlValue={getUrlDefault()} + /> + </div> + <div + style={{ + padding: 32, + display: 'flex', + }} + > + <StyledButton + background={design.colors.button} + color={design.colors.buttonText} + highlight={design.colors.buttonActive} + onClick={prev} + > + {t('form:previous')} + </StyledButton> + + <div style={{ flex: 1 }} /> + + <StyledButton + background={design.colors.button} + color={design.colors.buttonText} + highlight={design.colors.buttonActive} + size={'large'} + onClick={form.submit} + > + {t('form:next')} + </StyledButton> + </div> + </Form> + ) +} diff --git a/ui/components/form/layouts/slider/index.tsx b/ui/components/form/layouts/slider/index.tsx new file mode 100644 index 00000000..2e43b7f4 --- /dev/null +++ b/ui/components/form/layouts/slider/index.tsx @@ -0,0 +1,122 @@ +import { Modal } from 'antd' +import debug from 'debug' +import React, { useState } from 'react' +import { useTranslation } from 'react-i18next' +import SwiperClass from 'swiper' +import { Swiper, SwiperProps, SwiperSlide } from 'swiper/react' +import { Omf } from '../../../omf' +import { useWindowSize } from '../../../use.window.size' +import { LayoutProps } from '../layout.props' +import { Field } from './field' +import { FormPage } from './page' + +const logger = debug('layout/slider') + +export const SliderLayout: React.FC<LayoutProps> = (props) => { + const { t } = useTranslation() + const [swiper, setSwiper] = useState<SwiperClass>(null) + const { height } = useWindowSize() + const { design, startPage, endPage, fields } = props.form + const { finish, setField } = props.submission + + const goNext = () => { + if (!swiper) return + + logger('goNext') + swiper.allowSlideNext = true + swiper.slideNext() + swiper.allowSlideNext = false + } + const goPrev = () => { + if (!swiper) { + return + } + + logger('goPrevious') + swiper.slidePrev() + } + + const swiperConfig: SwiperProps = { + direction: 'vertical', + allowSlideNext: false, + allowSlidePrev: true, + noSwiping: true, + updateOnWindowResize: true, + } + + return ( + <div + className={'swiper-container'} + style={{ + background: design.colors.background, + }} + > + <Omf /> + {/* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */} + <Swiper + height={height} + {...swiperConfig} + onSwiper={next => { + logger('setSwiper') + setSwiper(next) + }} + > + {[ + startPage.show ? ( + <SwiperSlide key={'start'}> + <FormPage page={startPage} design={design} next={goNext} prev={goPrev} /> + </SwiperSlide> + ) : undefined, + ...fields + .map((field, i) => { + if (field.type === 'hidden') { + return null + } + + return ( + <SwiperSlide key={field.id}> + <Field + field={field} + focus={swiper?.activeIndex === (startPage.show ? 1 : 0) + i} + design={design} + save={async (values: { [key: string]: unknown }) => { + await setField(field.id, values[field.id]) + + if (fields.length === i + 1) { + await finish() + } + }} + next={() => { + if (fields.length === i + 1) { + // prevent going back! + swiper.allowSlidePrev = true + + if (!endPage.show) { + Modal.success({ + content: t('form:submitted'), + okText: t('from:restart'), + onOk: () => { + window.location.reload() + }, + }) + } + } + + goNext() + }} + prev={goPrev} + /> + </SwiperSlide> + ) + }) + .filter((e) => e !== null), + endPage.show ? ( + <SwiperSlide key={'end'}> + <FormPage page={endPage} design={design} next={finish} prev={goPrev} /> + </SwiperSlide> + ) : undefined, + ].filter((e) => !!e)} + </Swiper> + </div> + ) +} diff --git a/ui/components/form/layouts/slider/page.module.scss b/ui/components/form/layouts/slider/page.module.scss new file mode 100644 index 00000000..48f665ca --- /dev/null +++ b/ui/components/form/layouts/slider/page.module.scss @@ -0,0 +1,20 @@ +.main { + display: flex; + flex-direction: column; + height: 100%; + + .content { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + overflow: auto; + padding: 16px; + + @media (max-width: 600px) { + display: block; + } + } +} + diff --git a/ui/components/form/layouts/slider/page.tsx b/ui/components/form/layouts/slider/page.tsx new file mode 100644 index 00000000..3a65e93c --- /dev/null +++ b/ui/components/form/layouts/slider/page.tsx @@ -0,0 +1,69 @@ +import React from 'react' +import { useTranslation } from 'react-i18next' +import { + FormPublicDesignFragment, + FormPublicPageFragment, +} from '../../../../graphql/fragment/form.public.fragment' +import { StyledButton } from '../../../styled/button' +import { StyledH1 } from '../../../styled/h1' +import { StyledMarkdown } from '../../../styled/markdown' +import { PageButtons } from '../page.buttons' +import scss from './page.module.scss' + +interface Props { + page: FormPublicPageFragment + design: FormPublicDesignFragment + className?: string + + next: () => void + prev: () => void +} + +export const FormPage: React.FC<Props> = ({ page, design, next, prev, className, ...props }) => { + const { t } = useTranslation() + + if (!page.show) { + return null + } + + return ( + <div className={[scss.main, className].filter((c) => !!c).join(' ')} {...props}> + <div className={scss.content}> + <StyledH1 design={design} type={'question'}> + {page.title} + </StyledH1> + <StyledMarkdown design={design} type={'question'}>{page.paragraph}</StyledMarkdown> + </div> + <div + style={{ + padding: 32, + display: 'flex', + }} + > + {prev && ( + <StyledButton + background={design.colors.button} + color={design.colors.buttonText} + highlight={design.colors.buttonActive} + onClick={prev} + > + {t('form:previous')} + </StyledButton> + )} + <PageButtons buttons={page.buttons} /> + + <div style={{ flex: 1 }} /> + + <StyledButton + background={design.colors.button} + color={design.colors.buttonText} + highlight={design.colors.buttonActive} + size={'large'} + onClick={next} + > + {page.buttonText || t('form:continue')} + </StyledButton> + </div> + </div> + ) +} diff --git a/ui/components/form/types/abstract.type.tsx b/ui/components/form/types/abstract.type.tsx new file mode 100644 index 00000000..f1f0e698 --- /dev/null +++ b/ui/components/form/types/abstract.type.tsx @@ -0,0 +1,38 @@ +import React, { ComponentType } from 'react' +import { FieldAdminProps } from './field.admin.props' +import { FieldInputProps } from './field.input.props' + +export abstract class AbstractType<A = any> { + public parseValue(raw: string): A { + return JSON.parse(raw) as A + } + + public parseUrlValue(raw: string): A { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return raw as any + } + + public stringifyValue(raw: string): string { + return raw + } + + public displayValue(raw: string): JSX.Element { + const data = this.parseValue(raw) + + if (Array.isArray(data)) { + return ( + <ul> + {data.map(r => ( + <li key={r}>{JSON.stringify(r)}</li> + ))} + </ul> + ) + } + + return <div>{this.stringifyValue(raw)}</div> + } + + public abstract adminFormField(): ComponentType<FieldAdminProps> + + public abstract inputFormField(): ComponentType<FieldInputProps> +} diff --git a/ui/components/form/types/checkbox/checkbox.admin.tsx b/ui/components/form/types/checkbox/checkbox.admin.tsx new file mode 100644 index 00000000..f7a0836f --- /dev/null +++ b/ui/components/form/types/checkbox/checkbox.admin.tsx @@ -0,0 +1,77 @@ +import { Button, Col, Form, Input, Row } from 'antd' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FieldAdminProps } from '../field.admin.props' + +export const CheckboxAdmin: React.FC<FieldAdminProps> = (props) => { + const { t } = useTranslation() + + return ( + <div> + <Form.Item + label={t('type:checkbox:default')} + name={[props.field.name as string, 'defaultValue']} + labelCol={{ span: 6 }} + > + <Input /> + </Form.Item> + + <Form.List name={[props.field.name as string, 'options']}> + {(fields, { add, remove }) => { + return ( + <div> + {fields.map((field, index) => ( + <Form.Item + wrapperCol={{ + sm: { offset: index === 0 ? 0 : 6 }, + }} + labelCol={{ span: 6 }} + label={index === 0 ? t('type:checkbox:options') : ''} + key={field.key} + > + <Row gutter={16}> + <Col span={12}> + <Form.Item + wrapperCol={{ span: 24 }} + name={[field.name, 'title']} + style={{ marginBottom: 0 }} + > + <Input placeholder={t('type:checkbox:titlePlaceholder')} /> + </Form.Item> + </Col> + <Col span={8}> + <Form.Item + wrapperCol={{ span: 24 }} + name={[field.name, 'value']} + style={{ marginBottom: 0 }} + rules={[{ required: true, message: t('validation:valueRequired') }]} + > + <Input placeholder={t('type:checkbox:valuePlaceholder')} /> + </Form.Item> + </Col> + <Col span={4}> + <Button danger onClick={() => remove(index)}> + {t('type:checkbox:removeOption')} + </Button> + </Col> + </Row> + </Form.Item> + ))} + + <Form.Item + wrapperCol={{ + sm: { offset: 6 }, + }} + labelCol={{ span: 6 }} + > + <Button type={'dashed'} onClick={() => add()}> + {t('type:checkbox:addOption')} + </Button> + </Form.Item> + </div> + ) + }} + </Form.List> + </div> + ) +} diff --git a/ui/components/form/types/checkbox/checkbox.input.tsx b/ui/components/form/types/checkbox/checkbox.input.tsx new file mode 100644 index 00000000..71383cb1 --- /dev/null +++ b/ui/components/form/types/checkbox/checkbox.input.tsx @@ -0,0 +1,61 @@ +import { Checkbox, Form } from 'antd' +import debug from 'debug' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { StyledCheckbox } from '../../../styled/checkbox' +import { FieldInputBuilderType } from '../field.input.builder.type' + +const logger = debug('checkbox.input') + +export const builder: FieldInputBuilderType = ({ + parseUrlValue, + parseValue, +}) => function CheckboxInput ({ + field, + design, + urlValue, + focus, +}) { + const { t } = useTranslation() + + let initialValue: string = undefined + + if (field.defaultValue) { + try { + initialValue = parseValue(field.defaultValue) + } catch (e) { + logger('invalid default value %O', e) + } + } + + if (urlValue) { + initialValue = parseUrlValue(urlValue) + } + + return ( + <div> + <Form.Item + name={[field.id]} + rules={[{ required: field.required, message: t('validation:valueRequired') }]} + initialValue={field.options + .map((option) => option.value) + .find((value) => value === initialValue)} + > + <Checkbox.Group> + {field.options + .filter((option) => option.key === null) + .map((option, i) => ( + <StyledCheckbox + design={design} + value={option.value} + key={option.value} + autoFocus={i === 0 && focus} + > + {option.title || option.value} + </StyledCheckbox> + ))} + </Checkbox.Group> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/checkbox/index.ts b/ui/components/form/types/checkbox/index.ts new file mode 100644 index 00000000..1fcdb253 --- /dev/null +++ b/ui/components/form/types/checkbox/index.ts @@ -0,0 +1,15 @@ +import dynamic from 'next/dynamic' +import { ComponentType } from 'react' +import { AbstractType } from '../abstract.type' +import { FieldAdminProps } from '../field.admin.props' +import { FieldInputProps } from '../field.input.props' + +export class CheckboxType extends AbstractType<string> { + adminFormField(): ComponentType<FieldAdminProps> { + return dynamic(() => import('./checkbox.admin').then(c => c.CheckboxAdmin)); + } + + inputFormField(): ComponentType<FieldInputProps> { + return dynamic(() => import('./checkbox.input').then(c => c.builder(this))); + } +} diff --git a/ui/components/form/types/date/date.admin.tsx b/ui/components/form/types/date/date.admin.tsx new file mode 100644 index 00000000..5f19ae51 --- /dev/null +++ b/ui/components/form/types/date/date.admin.tsx @@ -0,0 +1,50 @@ +import { DatePicker, Form } from 'antd' +import moment, { Moment } from 'moment' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FieldAdminProps } from '../field.admin.props' + +export const DateAdmin: React.FC<FieldAdminProps> = ({ field }) => { + const { t } = useTranslation() + + return ( + <div> + <Form.Item + label={t('type:date.default')} + name={[field.name as string, 'defaultValue']} + labelCol={{ span: 6 }} + getValueFromEvent={(e: Moment) => (e ? e.format('YYYY-MM-DD') : undefined)} + getValueProps={(e: string) => ({ value: e ? moment(e) : undefined })} + > + <DatePicker format={'YYYY-MM-DD'} /> + </Form.Item> + <Form.Item + label={t('type:date.min')} + name={[ + field.name as string, + 'optionKeys', + 'min', + ]} + labelCol={{ span: 6 }} + getValueFromEvent={(e: Moment) => e.format('YYYY-MM-DD')} + getValueProps={(e: string) => ({ value: e ? moment(e) : undefined })} + > + <DatePicker /> + </Form.Item> + + <Form.Item + label={t('type:date.max')} + name={[ + field.name as string, + 'optionKeys', + 'max', + ]} + labelCol={{ span: 6 }} + getValueFromEvent={(e: Moment) => e.format('YYYY-MM-DD')} + getValueProps={(e: string) => ({ value: e ? moment(e) : undefined })} + > + <DatePicker /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/date/date.input.tsx b/ui/components/form/types/date/date.input.tsx new file mode 100644 index 00000000..0bf6cee8 --- /dev/null +++ b/ui/components/form/types/date/date.input.tsx @@ -0,0 +1,78 @@ +import { Form } from 'antd' +import dayjs, { Dayjs } from 'dayjs' +import debug from 'debug' +import moment, { Moment } from 'moment' +import React, { useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { StyledDateInput } from '../../../styled/date.input' +import { FieldInputBuilderType } from '../field.input.builder.type' + +const logger = debug('date.input') + +export const builder: FieldInputBuilderType = ({ + parseUrlValue, + parseValue, +}) => function DateInput ({ + field, + design, + urlValue, + focus, +}) { + const [min, setMin] = useState<Dayjs>() + const [max, setMax] = useState<Dayjs>() + const { t } = useTranslation() + + useEffect(() => { + field.options.forEach((option) => { + if (option.key === 'min') { + setMin(dayjs(option.value)) + } + if (option.key === 'max') { + setMax(dayjs(option.value)) + } + }) + }, [field]) + + let initialValue: Moment = undefined + + if (field.defaultValue) { + try { + initialValue = parseValue(field.defaultValue) + } catch (e) { + logger('invalid default value %O', e) + } + } + + if (urlValue) { + initialValue = parseUrlValue(urlValue) + } + + return ( + <div> + <Form.Item + name={[field.id]} + rules={[{ required: field.required, message: t('validation:valueRequired') }]} + getValueFromEvent={(e: Moment) => e.format('YYYY-MM-DD')} + getValueProps={(e: string) => ({ value: e ? moment(e) : undefined })} + initialValue={initialValue} + > + <StyledDateInput + autoFocus={focus} + size={'large'} + design={design} + disabledDate={(d: Moment) => { + if (min && min.isAfter(d.toDate())) { + return true + } + + if (max && max.isBefore(d.toDate())) { + return true + } + + return false + }} + /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/date/index.ts b/ui/components/form/types/date/index.ts new file mode 100644 index 00000000..8244f90e --- /dev/null +++ b/ui/components/form/types/date/index.ts @@ -0,0 +1,24 @@ +import moment, { Moment } from 'moment' +import dynamic from 'next/dynamic' +import { ComponentType } from 'react' +import { AbstractType } from '../abstract.type' +import { FieldAdminProps } from '../field.admin.props' +import { FieldInputProps } from '../field.input.props' + +export class DateType extends AbstractType<Moment> { + parseValue(raw: string): Moment { + return moment(JSON.parse(raw)) + } + + parseUrlValue(raw: string): Moment { + return moment(raw) + } + + adminFormField(): ComponentType<FieldAdminProps> { + return dynamic(() => import('./date.admin').then(c => c.DateAdmin)); + } + + inputFormField(): ComponentType<FieldInputProps> { + return dynamic(() => import('./date.input').then(c => c.builder(this))); + } +} diff --git a/ui/components/form/types/dropdown/dropdown.admin.tsx b/ui/components/form/types/dropdown/dropdown.admin.tsx new file mode 100644 index 00000000..0d6ca19f --- /dev/null +++ b/ui/components/form/types/dropdown/dropdown.admin.tsx @@ -0,0 +1,77 @@ +import { Button, Col, Form, Input, Row } from 'antd' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FieldAdminProps } from '../field.admin.props' + +export const DropdownAdmin: React.FC<FieldAdminProps> = (props) => { + const { t } = useTranslation() + + return ( + <div> + <Form.Item + label={t('type:dropdown.default')} + name={[props.field.name as string, 'defaultValue']} + labelCol={{ span: 6 }} + > + <Input /> + </Form.Item> + + <Form.List name={[props.field.name as string, 'options']}> + {(fields, { add, remove }) => { + return ( + <div> + {fields.map((field, index) => ( + <Form.Item + wrapperCol={{ + sm: { offset: index === 0 ? 0 : 6 }, + }} + labelCol={{ span: 6 }} + label={index === 0 ? t('type:dropdown.options') : ''} + key={field.key} + > + <Row gutter={16}> + <Col span={12}> + <Form.Item + wrapperCol={{ span: 24 }} + name={[field.name, 'title']} + style={{ marginBottom: 0 }} + > + <Input placeholder={t('type:dropdown.titlePlaceholder')} /> + </Form.Item> + </Col> + <Col span={8}> + <Form.Item + wrapperCol={{ span: 24 }} + name={[field.name, 'value']} + style={{ marginBottom: 0 }} + rules={[{ required: true, message: t('validation:valueRequired') }]} + > + <Input placeholder={t('type:dropdown.valuePlaceholder')} /> + </Form.Item> + </Col> + <Col span={4}> + <Button danger onClick={() => remove(index)}> + {t('type:dropdown.removeOption')} + </Button> + </Col> + </Row> + </Form.Item> + ))} + + <Form.Item + wrapperCol={{ + sm: { offset: 6 }, + }} + labelCol={{ span: 6 }} + > + <Button type={'dashed'} onClick={() => add()}> + {t('type:dropdown.addOption')} + </Button> + </Form.Item> + </div> + ) + }} + </Form.List> + </div> + ) +} diff --git a/ui/components/form/types/dropdown/dropdown.input.tsx b/ui/components/form/types/dropdown/dropdown.input.tsx new file mode 100644 index 00000000..25961576 --- /dev/null +++ b/ui/components/form/types/dropdown/dropdown.input.tsx @@ -0,0 +1,62 @@ +import { Form, Select } from 'antd' +import debug from 'debug' +import React, { useState } from 'react' +import { useTranslation } from 'react-i18next' +import { StyledSelect } from '../../../styled/select' +import { FieldInputBuilderType } from '../field.input.builder.type' + +const logger = debug('field/dropdown') + +export const builder: FieldInputBuilderType = ({ + parseUrlValue, + parseValue, +}) => function DateInput ({ + field, + design, + urlValue, + focus, +}) { + const [open, setOpen] = useState(false) + const { t } = useTranslation() + + let initialValue = null + + if (field.defaultValue) { + try { + initialValue = parseValue(field.defaultValue) + } catch (e) { + logger('invalid default value %O', e) + } + } + + if (urlValue) { + initialValue = parseUrlValue(urlValue) + } + + return ( + <div> + <Form.Item + name={[field.id]} + rules={[{ required: field.required, message: t('validation:valueRequired') }]} + initialValue={initialValue} + > + <StyledSelect + autoFocus={focus} + design={design} + open={open} + onBlur={() => setOpen(false)} + onFocus={() => setOpen(true)} + onSelect={() => setOpen(false)} + > + {field.options + .filter((option) => option.key === null) + .map((option) => ( + <Select.Option value={option.value} key={option.value}> + {option.title || option.value} + </Select.Option> + ))} + </StyledSelect> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/dropdown/index.ts b/ui/components/form/types/dropdown/index.ts new file mode 100644 index 00000000..bf9c351a --- /dev/null +++ b/ui/components/form/types/dropdown/index.ts @@ -0,0 +1,15 @@ +import dynamic from 'next/dynamic' +import { ComponentType } from 'react' +import { AbstractType } from '../abstract.type' +import { FieldAdminProps } from '../field.admin.props' +import { FieldInputProps } from '../field.input.props' + +export class DropdownType extends AbstractType<string> { + adminFormField(): ComponentType<FieldAdminProps> { + return dynamic(() => import('./dropdown.admin').then(c => c.DropdownAdmin)); + } + + inputFormField(): ComponentType<FieldInputProps> { + return dynamic(() => import('./dropdown.input').then(c => c.builder(this))); + } +} diff --git a/ui/components/form/types/email/email.admin.tsx b/ui/components/form/types/email/email.admin.tsx new file mode 100644 index 00000000..e015943e --- /dev/null +++ b/ui/components/form/types/email/email.admin.tsx @@ -0,0 +1,21 @@ +import { Form, Input } from 'antd' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FieldAdminProps } from '../field.admin.props' + +export const EmailAdmin: React.FC<FieldAdminProps> = (props) => { + const { t } = useTranslation() + + return ( + <div> + <Form.Item + label={t('type:email.default')} + name={[props.field.name as string, 'defaultValue']} + rules={[{ type: 'email', message: t('validation:emailRequired') }]} + labelCol={{ span: 6 }} + > + <Input type={'email'} /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/email/email.input.tsx b/ui/components/form/types/email/email.input.tsx new file mode 100644 index 00000000..9151db4b --- /dev/null +++ b/ui/components/form/types/email/email.input.tsx @@ -0,0 +1,49 @@ +import { Form } from 'antd' +import debug from 'debug' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { StyledInput } from '../../../styled/input' +import { FieldInputBuilderType } from '../field.input.builder.type' + +const logger = debug('email.input') + +export const builder: FieldInputBuilderType = ({ + parseUrlValue, + parseValue, +}) => function EmailInput ({ + field, + design, + urlValue, + focus, +}) { + const { t } = useTranslation() + + let initialValue = null + + if (field.defaultValue) { + try { + initialValue = parseValue(field.defaultValue) + } catch (e) { + logger('invalid default value %O', e) + } + } + + if (urlValue) { + initialValue = parseUrlValue(urlValue) + } + + return ( + <div> + <Form.Item + name={[field.id]} + rules={[ + { required: field.required, message: t('validation:valueRequired') }, + { type: 'email', message: t('validation:invalidEmail') }, + ]} + initialValue={initialValue} + > + <StyledInput autoFocus={focus} design={design} allowClear size={'large'} /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/email/index.ts b/ui/components/form/types/email/index.ts new file mode 100644 index 00000000..97389264 --- /dev/null +++ b/ui/components/form/types/email/index.ts @@ -0,0 +1,15 @@ +import dynamic from 'next/dynamic' +import { ComponentType } from 'react' +import { AbstractType } from '../abstract.type' +import { FieldAdminProps } from '../field.admin.props' +import { FieldInputProps } from '../field.input.props' + +export class EmailType extends AbstractType<string> { + adminFormField(): ComponentType<FieldAdminProps> { + return dynamic(() => import('./email.admin').then(c => c.EmailAdmin)); + } + + inputFormField(): ComponentType<FieldInputProps> { + return dynamic(() => import('./email.input').then(c => c.builder(this))); + } +} diff --git a/ui/components/form/types/field.admin.props.ts b/ui/components/form/types/field.admin.props.ts new file mode 100644 index 00000000..26f9cdc1 --- /dev/null +++ b/ui/components/form/types/field.admin.props.ts @@ -0,0 +1,7 @@ +import { FormInstance } from 'antd/lib/form' +import { FieldData } from 'rc-field-form/lib/interface' + +export interface FieldAdminProps { + form: FormInstance + field: FieldData +} diff --git a/ui/components/form/types/field.input.builder.type.ts b/ui/components/form/types/field.input.builder.type.ts new file mode 100644 index 00000000..6e652b38 --- /dev/null +++ b/ui/components/form/types/field.input.builder.type.ts @@ -0,0 +1,6 @@ +import { ComponentType } from 'react' + +import { AbstractType } from './abstract.type' +import { FieldInputProps } from './field.input.props' + +export type FieldInputBuilderType<A = AbstractType> = (type: A) => ComponentType<FieldInputProps> diff --git a/ui/components/form/types/field.input.props.ts b/ui/components/form/types/field.input.props.ts new file mode 100644 index 00000000..92b414ec --- /dev/null +++ b/ui/components/form/types/field.input.props.ts @@ -0,0 +1,11 @@ +import { + FormPublicDesignFragment, + FormPublicFieldFragment, +} from '../../../graphql/fragment/form.public.fragment' + +export interface FieldInputProps { + field: FormPublicFieldFragment + design: FormPublicDesignFragment + focus?: boolean + urlValue?: string +} diff --git a/ui/components/form/types/hidden/hidden.admin.tsx b/ui/components/form/types/hidden/hidden.admin.tsx new file mode 100644 index 00000000..95523bd9 --- /dev/null +++ b/ui/components/form/types/hidden/hidden.admin.tsx @@ -0,0 +1,20 @@ +import { Form, Input } from 'antd' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FieldAdminProps } from '../field.admin.props' + +export const HiddenAdmin: React.FC<FieldAdminProps> = (props) => { + const { t } = useTranslation() + + return ( + <div> + <Form.Item + label={t('type:hidden.default')} + name={[props.field.name as string, 'defaultValue']} + labelCol={{ span: 6 }} + > + <Input /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/hidden/index.ts b/ui/components/form/types/hidden/index.ts new file mode 100644 index 00000000..da223412 --- /dev/null +++ b/ui/components/form/types/hidden/index.ts @@ -0,0 +1,15 @@ +import dynamic from 'next/dynamic' +import { ComponentType } from 'react' +import { AbstractType } from '../abstract.type' +import { FieldAdminProps } from '../field.admin.props' +import { FieldInputProps } from '../field.input.props' + +export class HiddenType extends AbstractType<string> { + adminFormField(): ComponentType<FieldAdminProps> { + return dynamic(() => import('./hidden.admin').then(c => c.HiddenAdmin)); + } + + inputFormField(): ComponentType<FieldInputProps> { + return null; + } +} diff --git a/ui/components/form/types/image/image.admin.tsx b/ui/components/form/types/image/image.admin.tsx new file mode 100644 index 00000000..59ad568a --- /dev/null +++ b/ui/components/form/types/image/image.admin.tsx @@ -0,0 +1,2 @@ + +export {} diff --git a/ui/components/form/types/image/image.type.tsx b/ui/components/form/types/image/image.type.tsx new file mode 100644 index 00000000..59ad568a --- /dev/null +++ b/ui/components/form/types/image/image.type.tsx @@ -0,0 +1,2 @@ + +export {} diff --git a/ui/components/form/types/image/index.ts b/ui/components/form/types/image/index.ts new file mode 100644 index 00000000..1174d485 --- /dev/null +++ b/ui/components/form/types/image/index.ts @@ -0,0 +1,19 @@ +/* +TODO +import dynamic from 'next/dynamic' +import { ComponentType } from 'react' +import { AbstractType } from '../abstract.type' +import { FieldAdminProps } from '../field.admin.props' +import { FieldInputProps } from '../field.input.props' + +export class ImageType extends AbstractType<string> { + adminFormField(): ComponentType<FieldAdminProps> { + return dynamic(() => import('./dropdown.admin').then(c => c.DropdownAdmin)); + } + + inputFormField(): ComponentType<FieldInputProps> { + return dynamic(() => import('./dropdown.input').then(c => c.builder(this))); + } +} +*/ +export {} diff --git a/ui/components/form/types/index.ts b/ui/components/form/types/index.ts new file mode 100644 index 00000000..6bfadcbe --- /dev/null +++ b/ui/components/form/types/index.ts @@ -0,0 +1,34 @@ +import { AbstractType } from './abstract.type' +import { CheckboxType } from './checkbox' +import { DateType } from './date' +import { DropdownType } from './dropdown' +import { EmailType } from './email' +import { HiddenType } from './hidden' +import { LinkType } from './link' +import { LocationType } from './location' +import { NumberType } from './number' +import { RadioType } from './radio' +import { RatingType } from './rating' +import { SliderType } from './slider' +import { TextareaType } from './textarea' +import { TextfieldType } from './textfield' +import { YesNoType } from './yes_no' + +export const fieldTypes: { + [key: string]: AbstractType +} = { + checkbox: new CheckboxType(), + date: new DateType(), + dropdown: new DropdownType(), + email: new EmailType(), + hidden: new HiddenType(), + link: new LinkType(), + location: new LocationType(), + number: new NumberType(), + radio: new RadioType(), + rating: new RatingType(), + slider: new SliderType(), + textarea: new TextareaType(), + textfield: new TextfieldType(), + yes_no: new YesNoType(), +} diff --git a/ui/components/form/types/link/index.ts b/ui/components/form/types/link/index.ts new file mode 100644 index 00000000..1630c890 --- /dev/null +++ b/ui/components/form/types/link/index.ts @@ -0,0 +1,15 @@ +import dynamic from 'next/dynamic' +import { ComponentType } from 'react' +import { AbstractType } from '../abstract.type' +import { FieldAdminProps } from '../field.admin.props' +import { FieldInputProps } from '../field.input.props' + +export class LinkType extends AbstractType<string> { + adminFormField(): ComponentType<FieldAdminProps> { + return dynamic(() => import('./link.admin').then(c => c.LinkAdmin)); + } + + inputFormField(): ComponentType<FieldInputProps> { + return dynamic(() => import('./link.input').then(c => c.builder(this))); + } +} diff --git a/ui/components/form/types/link/link.admin.tsx b/ui/components/form/types/link/link.admin.tsx new file mode 100644 index 00000000..3b026495 --- /dev/null +++ b/ui/components/form/types/link/link.admin.tsx @@ -0,0 +1,21 @@ +import { Form, Input } from 'antd' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FieldAdminProps } from '../field.admin.props' + +export const LinkAdmin: React.FC<FieldAdminProps> = (props) => { + const { t } = useTranslation() + + return ( + <div> + <Form.Item + label={t('type:link.default')} + name={[props.field.name as string, 'defaultValue']} + rules={[{ type: 'url', message: t('validation:invalidUrl') }]} + labelCol={{ span: 6 }} + > + <Input type={'url'} /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/link/link.input.tsx b/ui/components/form/types/link/link.input.tsx new file mode 100644 index 00000000..9766815d --- /dev/null +++ b/ui/components/form/types/link/link.input.tsx @@ -0,0 +1,49 @@ +import { Form } from 'antd' +import debug from 'debug' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { StyledInput } from '../../../styled/input' +import { FieldInputBuilderType } from '../field.input.builder.type' + +const logger = debug('link.input') + +export const builder: FieldInputBuilderType = ({ + parseUrlValue, + parseValue, +}) => function LinkInput ({ + field, + design, + urlValue, + focus, +}) { + const { t } = useTranslation() + + let initialValue = null + + if (field.defaultValue) { + try { + initialValue = parseValue(field.defaultValue) + } catch (e) { + logger('invalid default value %O', e) + } + } + + if (urlValue) { + initialValue = parseUrlValue(urlValue) + } + + return ( + <div> + <Form.Item + name={[field.id]} + rules={[ + { required: field.required, message: t('validation:valueRequired') }, + { type: 'url', message: t('validation:invalidUrl') }, + ]} + initialValue={initialValue} + > + <StyledInput autoFocus={focus} design={design} allowClear size={'large'} /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/location/index.ts b/ui/components/form/types/location/index.ts new file mode 100644 index 00000000..dda717f6 --- /dev/null +++ b/ui/components/form/types/location/index.ts @@ -0,0 +1,34 @@ +import dynamic from 'next/dynamic' +import { ComponentType } from 'react' +import { AbstractType } from '../abstract.type' +import { FieldAdminProps } from '../field.admin.props' +import { FieldInputProps } from '../field.input.props' + +export class LocationType extends AbstractType<{ lat: number, lng: number }> { + parseUrlValue(raw: string): { lat: number; lng: number } { + if (raw.includes(',')) { + const [lat, lng] = raw.split(',') + + return { + lat: parseFloat(lat), + lng: parseFloat(lng), + } + } + + throw new Error('no separator found') + } + + adminFormField(): ComponentType<FieldAdminProps> { + return dynamic(() => import('./location.admin').then(c => c.LocationAdmin), { ssr: false }); + } + + inputFormField(): ComponentType<FieldInputProps> { + return dynamic(() => import('./location.input').then(c => c.builder(this)), { ssr: false }); + } + + stringifyValue(raw: string): string { + const data = this.parseValue(raw) + + return `${data.lat}, ${data.lng}` + } +} diff --git a/ui/components/form/types/location/location.admin.tsx b/ui/components/form/types/location/location.admin.tsx new file mode 100644 index 00000000..44b86654 --- /dev/null +++ b/ui/components/form/types/location/location.admin.tsx @@ -0,0 +1,142 @@ +import { Alert, Form, Input, InputNumber, Space } from 'antd' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { MapContainer, TileLayer } from 'react-leaflet' +import { DraggableMarker } from '../../../map/draggable.marker' +import { FieldAdminProps } from '../field.admin.props' + +export const LocationAdmin: React.FC<FieldAdminProps> = (props) => { + const { t } = useTranslation() + + return ( + <div> + <Form.Item + label={t('type:location:default')} + labelCol={{ span: 6 }} + > + <Space> + <Form.Item + name={[ + props.field.name as string, + 'defaultValue', + 'lat', + ]} + noStyle + > + <InputNumber addonAfter={'LAT'} precision={7} step={0.00001} max={90} min={-90} /> + </Form.Item> + + <Form.Item + name={[ + props.field.name as string, + 'defaultValue', + 'lng', + ]} + noStyle + > + <InputNumber addonAfter={'LNG'} precision={7} step={0.00001} max={180} min={-180} /> + </Form.Item> + </Space> + </Form.Item> + + <Form.Item + label={t('type:location.initialZoom')} + name={[ + props.field.name as string, + 'optionKeys', + 'initialZoom', + ]} + labelCol={{ span: 6 }} + initialValue={1} + > + <InputNumber precision={0} min={1} max={18} /> + </Form.Item> + + <Form.Item + label={t('type:location.tiles')} + name={[ + props.field.name as string, + 'optionKeys', + 'tiles', + ]} + labelCol={{ span: 6 }} + initialValue={'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'} + > + <Input placeholder={'https://tile.openstreetmap.org/{z}/{x}/{y}.png'} /> + </Form.Item> + + <Form.Item shouldUpdate> + {(form) => { + //const prefix = React.useContext(FormItemContext).prefixName + const prefix = (form as any).prefixName + + const zoom = form.getFieldValue([ + ...prefix, + props.field.name as string, + 'optionKeys', + 'initialZoom', + ]) + + const center = form.getFieldValue([ + ...prefix, + props.field.name as string, + 'defaultValue', + ]) + + const tiles = form.getFieldValue([ + ...prefix, + props.field.name as string, + 'optionKeys', + 'tiles', + ]) + + if (!tiles) { + return <Alert message={'Tiles missing!'} /> + } + + return ( + <div> + <MapContainer + center={center} + zoom={zoom} + style={{ height: 300, width: '100%' }} + > + <TileLayer + attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' + url={tiles} + /> + {center?.lat && center?.lng && ( + <DraggableMarker + value={center} + onChange={next => { + form.setFields([ + { + name: [ + ...prefix, + props.field.name as string, + 'defaultValue', + 'lng', + ], + value: next.lng, + }, + { + name: [ + ...prefix, + props.field.name as string, + 'defaultValue', + 'lat', + ], + value: next.lat, + }, + ]) + }} + /> + )} + </MapContainer> + </div> + ) + }} + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/location/location.input.tsx b/ui/components/form/types/location/location.input.tsx new file mode 100644 index 00000000..77920f3c --- /dev/null +++ b/ui/components/form/types/location/location.input.tsx @@ -0,0 +1,151 @@ +import { Alert, Form, InputNumber, Space, Spin } from 'antd' +import debug from 'debug' +import React, { useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { MapContainer, TileLayer } from 'react-leaflet' +import { DraggableMarker } from '../../../map/draggable.marker' +import { FieldInputBuilderType } from '../field.input.builder.type' + +const logger = debug('location.number') + +export const builder: FieldInputBuilderType = ({ + parseUrlValue, + parseValue, +}) => function LocationInput ({ + field, + urlValue, +}) { + const [initialZoom, setInitialZoom] = useState<number>(13) + const [tiles, setTiles] = useState<string>() + const [loading, setLoading] = useState(true) + + const { t } = useTranslation() + + + useEffect(() => { + field.options.forEach((option) => { + if (option.key === 'initialZoom') { + try { + setInitialZoom(JSON.parse(option.value)) + } catch (e) { + logger('invalid initialZoom value %O', e) + } + } + + if (option.key === 'tiles') { + try { + setTiles(JSON.parse(option.value)) + } catch (e) { + logger('invalid tiles value %O', e) + } + } + }) + + setLoading(false) + }, [field]) + + let initialValue: { lat: number, lng: number } = undefined + + if (field.defaultValue) { + try { + initialValue = parseValue(field.defaultValue) + } catch (e) { + logger('invalid default value %O', e) + } + } + + if (urlValue) { + try { + initialValue = parseUrlValue(urlValue) + } catch (e) { + logger('invalid url value %O', e) + } + } + + if (loading) { + return ( + <div> + <Spin /> + </div> + ) + } + + if (!tiles) { + return <Alert message={'Tiles missing!'} /> + } + + return ( + <div> + <Form.Item> + <Space> + <Form.Item + rules={[{ required: field.required, message: t('validation:valueRequired') }]} + name={[ + field.id, + 'lat', + ]} + initialValue={initialValue?.lat} + noStyle + > + <InputNumber addonAfter={'LAT'} precision={7} step={0.00001} max={90} min={-90} /> + </Form.Item> + + <Form.Item + rules={[{ required: field.required, message: t('validation:valueRequired') }]} + name={[ + field.id, + 'lng', + ]} + initialValue={initialValue?.lng} + noStyle + > + <InputNumber addonAfter={'LNG'} precision={7} step={0.00001} max={180} min={-180} /> + </Form.Item> + </Space> + </Form.Item> + <Form.Item dependencies={[[field.id, 'lat'], [field.id, 'lng']]}> + {(form) => { + const center = form.getFieldValue([field.id]) + + return ( + <div> + <MapContainer + center={initialValue} + zoom={initialZoom} + style={{ height: 300, width: '100%' }} + > + <TileLayer + attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' + url={tiles} + /> + {center.lat && center.lng && ( + <DraggableMarker + value={center} + onChange={next => { + form.setFields([ + { + name: [ + field.id, + 'lng', + ], + value: next.lng, + }, + { + name: [ + field.id, + 'lat', + ], + value: next.lat, + }, + ]) + }} + /> + )} + </MapContainer> + </div> + ) + }} + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/number/index.ts b/ui/components/form/types/number/index.ts new file mode 100644 index 00000000..a8411f70 --- /dev/null +++ b/ui/components/form/types/number/index.ts @@ -0,0 +1,19 @@ +import dynamic from 'next/dynamic' +import { ComponentType } from 'react' +import { AbstractType } from '../abstract.type' +import { FieldAdminProps } from '../field.admin.props' +import { FieldInputProps } from '../field.input.props' + +export class NumberType extends AbstractType<number> { + parseUrlValue(raw: string): number { + return parseFloat(raw) + } + + adminFormField(): ComponentType<FieldAdminProps> { + return dynamic(() => import('./number.admin').then(c => c.NumberAdmin)); + } + + inputFormField(): ComponentType<FieldInputProps> { + return dynamic(() => import('./number.input').then(c => c.builder(this))); + } +} diff --git a/ui/components/form/types/number/number.admin.tsx b/ui/components/form/types/number/number.admin.tsx new file mode 100644 index 00000000..09c8553b --- /dev/null +++ b/ui/components/form/types/number/number.admin.tsx @@ -0,0 +1,20 @@ +import { Form, InputNumber } from 'antd' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FieldAdminProps } from '../field.admin.props' + +export const NumberAdmin: React.FC<FieldAdminProps> = (props) => { + const { t } = useTranslation() + + return ( + <div> + <Form.Item + label={t('type:number:default')} + name={[props.field.name as string, 'defaultValue']} + labelCol={{ span: 6 }} + > + <InputNumber precision={2} /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/number/number.input.tsx b/ui/components/form/types/number/number.input.tsx new file mode 100644 index 00000000..95b35467 --- /dev/null +++ b/ui/components/form/types/number/number.input.tsx @@ -0,0 +1,49 @@ +import { Form } from 'antd' +import debug from 'debug' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { StyledNumberInput } from '../../../styled/number.input' +import { FieldInputBuilderType } from '../field.input.builder.type' + +const logger = debug('number.input') + +export const builder: FieldInputBuilderType = ({ + parseUrlValue, + parseValue, +}) => function NumberInput ({ + field, + design, + urlValue, + focus, +}) { + const { t } = useTranslation() + + let initialValue: number = undefined + + if (field.defaultValue) { + try { + initialValue = parseValue(field.defaultValue) + } catch (e) { + logger('invalid default value %O', e) + } + } + + if (urlValue) { + initialValue = parseUrlValue(urlValue) + } + + return ( + <div> + <Form.Item + name={[field.id]} + rules={[ + { type: 'number', message: t('validation:invalidNumber') }, + { required: field.required, message: t('validation:valueRequired') }, + ]} + initialValue={initialValue} + > + <StyledNumberInput autoFocus={focus} design={design} size={'large'} /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/radio/index.ts b/ui/components/form/types/radio/index.ts new file mode 100644 index 00000000..419ec777 --- /dev/null +++ b/ui/components/form/types/radio/index.ts @@ -0,0 +1,15 @@ +import dynamic from 'next/dynamic' +import { ComponentType } from 'react' +import { AbstractType } from '../abstract.type' +import { FieldAdminProps } from '../field.admin.props' +import { FieldInputProps } from '../field.input.props' + +export class RadioType extends AbstractType<string> { + adminFormField(): ComponentType<FieldAdminProps> { + return dynamic(() => import('./radio.admin').then(c => c.RadioAdmin)); + } + + inputFormField(): ComponentType<FieldInputProps> { + return dynamic(() => import('./radio.input').then(c => c.builder(this))); + } +} diff --git a/ui/components/form/types/radio/radio.admin.tsx b/ui/components/form/types/radio/radio.admin.tsx new file mode 100644 index 00000000..192bacaf --- /dev/null +++ b/ui/components/form/types/radio/radio.admin.tsx @@ -0,0 +1,77 @@ +import { Button, Col, Form, Input, Row } from 'antd' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FieldAdminProps } from '../field.admin.props' + +export const RadioAdmin: React.FC<FieldAdminProps> = (props) => { + const { t } = useTranslation() + + return ( + <div> + <Form.Item + label={t('type:radio:default')} + name={[props.field.name as string, 'defaultValue']} + labelCol={{ span: 6 }} + > + <Input /> + </Form.Item> + + <Form.List name={[props.field.name as string, 'options']}> + {(fields, { add, remove }) => { + return ( + <div> + {fields.map((field, index) => ( + <Form.Item + wrapperCol={{ + sm: { offset: index === 0 ? 0 : 6 }, + }} + labelCol={{ span: 6 }} + label={index === 0 ? t('type:radio:options') : ''} + key={field.key} + > + <Row gutter={16}> + <Col span={12}> + <Form.Item + wrapperCol={{ span: 24 }} + name={[field.name, 'title']} + style={{ marginBottom: 0 }} + > + <Input placeholder={t('type:radio:titlePlaceholder')} /> + </Form.Item> + </Col> + <Col span={8}> + <Form.Item + wrapperCol={{ span: 24 }} + name={[field.name, 'value']} + style={{ marginBottom: 0 }} + rules={[{ required: true, message: t('validation:valueRequired') }]} + > + <Input placeholder={t('type:radio:valuePlaceholder')} /> + </Form.Item> + </Col> + <Col span={4}> + <Button danger onClick={() => remove(index)}> + {t('type:radio:removeOption')} + </Button> + </Col> + </Row> + </Form.Item> + ))} + + <Form.Item + wrapperCol={{ + sm: { offset: 6 }, + }} + labelCol={{ span: 6 }} + > + <Button type={'dashed'} onClick={() => add()}> + {t('type:radio:addOption')} + </Button> + </Form.Item> + </div> + ) + }} + </Form.List> + </div> + ) +} diff --git a/ui/components/form/types/radio/radio.input.tsx b/ui/components/form/types/radio/radio.input.tsx new file mode 100644 index 00000000..cb65f733 --- /dev/null +++ b/ui/components/form/types/radio/radio.input.tsx @@ -0,0 +1,55 @@ +import { Form, Radio } from 'antd' +import debug from 'debug' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { StyledRadio } from '../../../styled/radio' +import { FieldInputBuilderType } from '../field.input.builder.type' + +const logger = debug('radio.input') + +export const builder: FieldInputBuilderType = ({ + parseUrlValue, + parseValue, +}) => function RadioInput ({ + field, + design, + urlValue, +}) { + const { t } = useTranslation() + + let initialValue: string = undefined + + if (field.defaultValue) { + try { + initialValue = parseValue(field.defaultValue) + } catch (e) { + logger('invalid default value %O', e) + } + } + + if (urlValue) { + initialValue = parseUrlValue(urlValue) + } + + return ( + <div> + <Form.Item + name={[field.id]} + rules={[{ required: field.required, message: t('validation:valueRequired') }]} + initialValue={field.options + .map((option) => option.value) + .find((value) => value === initialValue)} + > + <Radio.Group> + {field.options + .filter((option) => option.key === null) + .map((option) => ( + <StyledRadio design={design} value={option.value} key={option.value}> + {option.title || option.value} + </StyledRadio> + ))} + </Radio.Group> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/rating/index.ts b/ui/components/form/types/rating/index.ts new file mode 100644 index 00000000..9f4f213b --- /dev/null +++ b/ui/components/form/types/rating/index.ts @@ -0,0 +1,19 @@ +import dynamic from 'next/dynamic' +import { ComponentType } from 'react' +import { AbstractType } from '../abstract.type' +import { FieldAdminProps } from '../field.admin.props' +import { FieldInputProps } from '../field.input.props' + +export class RatingType extends AbstractType<number> { + parseUrlValue(raw: string): number { + return parseFloat(raw) + } + + adminFormField(): ComponentType<FieldAdminProps> { + return dynamic(() => import('./rating.admin').then(c => c.RatingAdmin)); + } + + inputFormField(): ComponentType<FieldInputProps> { + return dynamic(() => import('./rating.input').then(c => c.builder(this))); + } +} diff --git a/ui/components/form/types/rating/rating.admin.tsx b/ui/components/form/types/rating/rating.admin.tsx new file mode 100644 index 00000000..2c54ab20 --- /dev/null +++ b/ui/components/form/types/rating/rating.admin.tsx @@ -0,0 +1,21 @@ +import { Form, Rate } from 'antd' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FieldAdminProps } from '../field.admin.props' + +export const RatingAdmin: React.FC<FieldAdminProps> = (props) => { + const { t } = useTranslation() + + return ( + <div> + <Form.Item + label={t('type:rating:default')} + name={[props.field.name as string, 'defaultValue']} + labelCol={{ span: 6 }} + extra={t('type:rating.clearNote')} + > + <Rate allowHalf allowClear /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/rating/rating.input.tsx b/ui/components/form/types/rating/rating.input.tsx new file mode 100644 index 00000000..c325e4d3 --- /dev/null +++ b/ui/components/form/types/rating/rating.input.tsx @@ -0,0 +1,43 @@ +import { Form, Rate } from 'antd' +import debug from 'debug' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FieldInputBuilderType } from '../field.input.builder.type' + +const logger = debug('rating.input') + +export const builder: FieldInputBuilderType = ({ + parseUrlValue, + parseValue, +}) => function RatingInput ({ + field, + urlValue, +}) { + const { t } = useTranslation() + + let initialValue: number = undefined + + if (field.defaultValue) { + try { + initialValue = parseValue(field.defaultValue) + } catch (e) { + logger('invalid default value %O', e) + } + } + + if (urlValue) { + initialValue = parseUrlValue(urlValue) + } + + return ( + <div> + <Form.Item + name={[field.id]} + rules={[{ required: field.required, message: t('validation:valueRequired') }]} + initialValue={initialValue} + > + <Rate allowHalf /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/slider/index.ts b/ui/components/form/types/slider/index.ts new file mode 100644 index 00000000..99ce0bc7 --- /dev/null +++ b/ui/components/form/types/slider/index.ts @@ -0,0 +1,19 @@ +import dynamic from 'next/dynamic' +import { ComponentType } from 'react' +import { AbstractType } from '../abstract.type' +import { FieldAdminProps } from '../field.admin.props' +import { FieldInputProps } from '../field.input.props' + +export class SliderType extends AbstractType<number> { + parseUrlValue(raw: string): number { + return parseFloat(raw) + } + + adminFormField(): ComponentType<FieldAdminProps> { + return dynamic(() => import('./slider.admin').then(c => c.SliderAdmin)); + } + + inputFormField(): ComponentType<FieldInputProps> { + return dynamic(() => import('./slider.input').then(c => c.builder(this))); + } +} diff --git a/ui/components/form/types/slider/slider.admin.tsx b/ui/components/form/types/slider/slider.admin.tsx new file mode 100644 index 00000000..db7504a5 --- /dev/null +++ b/ui/components/form/types/slider/slider.admin.tsx @@ -0,0 +1,88 @@ +import { Form, InputNumber, Slider } from 'antd' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FieldAdminProps } from '../field.admin.props' + +export const SliderAdmin: React.FC<FieldAdminProps> = (props) => { + const { t } = useTranslation() + + return ( + <div> + <Form.Item shouldUpdate noStyle> + {(form) => { + //const prefix = React.useContext(FormItemContext).prefixName + const prefix = (form as any).prefixName + + const getValue = (name, defaultValue: number): number => { + const current: unknown = form.getFieldValue([ + ...prefix, + props.field.name as string, + 'optionKeys', + name, + ]) + + if (!current) { + return defaultValue + } + + return parseFloat(current as string) + } + + const max = getValue('max', 100) + const min = getValue('min', 0) + const step = getValue('step', 1) + + return ( + <Form.Item + label={t('type:slider.default')} + name={[props.field.name as string, 'defaultValue']} + labelCol={{ span: 6 }} + getValueProps={(value: string) => ({ value: value ? parseFloat(value) : undefined })} + > + <Slider min={min} max={max} step={step} dots={(max - min) / step <= 10} /> + </Form.Item> + ) + }} + </Form.Item> + + <Form.Item + label={t('type:slider.min')} + name={[ + props.field.name as string, + 'optionKeys', + 'min', + ]} + labelCol={{ span: 6 }} + initialValue={0} + > + <InputNumber /> + </Form.Item> + + <Form.Item + label={t('type:slider.max')} + name={[ + props.field.name as string, + 'optionKeys', + 'max', + ]} + labelCol={{ span: 6 }} + initialValue={100} + > + <InputNumber /> + </Form.Item> + + <Form.Item + label={t('type:slider.step')} + name={[ + props.field.name as string, + 'optionKeys', + 'step', + ]} + labelCol={{ span: 6 }} + initialValue={1} + > + <InputNumber /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/slider/slider.input.tsx b/ui/components/form/types/slider/slider.input.tsx new file mode 100644 index 00000000..779db871 --- /dev/null +++ b/ui/components/form/types/slider/slider.input.tsx @@ -0,0 +1,92 @@ +import { Form, Slider, Spin } from 'antd' +import debug from 'debug' +import React, { useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { FieldInputBuilderType } from '../field.input.builder.type' + +const logger = debug('slider.input') + +export const builder: FieldInputBuilderType = ({ + parseUrlValue, + parseValue, +}) => function SliderInput ({ + field, + urlValue, + focus, +}) { + const [min, setMin] = useState<number>() + const [max, setMax] = useState<number>() + const [step, setStep] = useState<number>() + const [loading, setLoading] = useState(true) + + const { t } = useTranslation() + + useEffect(() => { + field.options.forEach((option) => { + if (option.key === 'min') { + try { + setMin(JSON.parse(option.value)) + } catch (e) { + logger('invalid min value %O', e) + } + } + if (option.key === 'max') { + try { + setMax(JSON.parse(option.value)) + } catch (e) { + logger('invalid max value %O', e) + } + } + if (option.key === 'step') { + try { + setStep(JSON.parse(option.value)) + } catch (e) { + logger('invalid step value %O', e) + } + } + }) + + setLoading(false) + }, [field]) + + let initialValue: number = undefined + + if (field.defaultValue) { + try { + initialValue = parseValue(field.defaultValue) + } catch (e) { + logger('invalid default value %O', e) + } + } + + if (urlValue) { + initialValue = parseUrlValue(urlValue) + } + + if (loading) { + return ( + <div> + <Spin /> + </div> + ) + } + + return ( + <div> + <Form.Item + name={[field.id]} + rules={[{ required: field.required, message: t('validation:valueRequired') }]} + initialValue={initialValue} + > + <Slider + autoFocus={focus} + min={min} + max={max} + step={step} + tooltipVisible={true} + dots={(max - min) / step <= 10} + /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/textarea/index.ts b/ui/components/form/types/textarea/index.ts new file mode 100644 index 00000000..eedb92d9 --- /dev/null +++ b/ui/components/form/types/textarea/index.ts @@ -0,0 +1,15 @@ +import dynamic from 'next/dynamic' +import { ComponentType } from 'react' +import { AbstractType } from '../abstract.type' +import { FieldAdminProps } from '../field.admin.props' +import { FieldInputProps } from '../field.input.props' + +export class TextareaType extends AbstractType<string> { + adminFormField(): ComponentType<FieldAdminProps> { + return dynamic(() => import('./textarea.admin').then(c => c.TextareaAdmin)); + } + + inputFormField(): ComponentType<FieldInputProps> { + return dynamic(() => import('./textarea.input').then(c => c.builder(this))); + } +} diff --git a/ui/components/form/types/textarea/textarea.admin.tsx b/ui/components/form/types/textarea/textarea.admin.tsx new file mode 100644 index 00000000..0e12aad5 --- /dev/null +++ b/ui/components/form/types/textarea/textarea.admin.tsx @@ -0,0 +1,20 @@ +import { Form, Input } from 'antd' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FieldAdminProps } from '../field.admin.props' + +export const TextareaAdmin: React.FC<FieldAdminProps> = (props) => { + const { t } = useTranslation() + + return ( + <div> + <Form.Item + label={t('type:textarea:default')} + name={[props.field.name as string, 'defaultValue']} + labelCol={{ span: 6 }} + > + <Input.TextArea autoSize /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/textarea/textarea.input.tsx b/ui/components/form/types/textarea/textarea.input.tsx new file mode 100644 index 00000000..e47ee667 --- /dev/null +++ b/ui/components/form/types/textarea/textarea.input.tsx @@ -0,0 +1,46 @@ +import { Form } from 'antd' +import debug from 'debug' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { StyledTextareaInput } from '../../../styled/textarea.input' +import { FieldInputBuilderType } from '../field.input.builder.type' + +const logger = debug('textarea.input') + +export const builder: FieldInputBuilderType = ({ + parseUrlValue, + parseValue, +}) => function TextareaInput ({ + field, + design, + urlValue, + focus, +}) { + const { t } = useTranslation() + + let initialValue = undefined + + if (field.defaultValue) { + try { + initialValue = parseValue(field.defaultValue) + } catch (e) { + logger('invalid default value %O', e) + } + } + + if (urlValue) { + initialValue = parseUrlValue(urlValue) + } + + return ( + <div> + <Form.Item + name={[field.id]} + rules={[{ required: field.required, message: t('validation:valueRequired') }]} + initialValue={initialValue} + > + <StyledTextareaInput autoFocus={focus} design={design} allowClear autoSize /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/textfield/index.ts b/ui/components/form/types/textfield/index.ts new file mode 100644 index 00000000..ae616e83 --- /dev/null +++ b/ui/components/form/types/textfield/index.ts @@ -0,0 +1,15 @@ +import dynamic from 'next/dynamic' +import { ComponentType } from 'react' +import { AbstractType } from '../abstract.type' +import { FieldAdminProps } from '../field.admin.props' +import { FieldInputProps } from '../field.input.props' + +export class TextfieldType extends AbstractType<string> { + adminFormField(): ComponentType<FieldAdminProps> { + return dynamic(() => import('./textfield.admin').then(c => c.TextfieldAdmin)); + } + + inputFormField(): ComponentType<FieldInputProps> { + return dynamic(() => import('./textfield.input').then(c => c.builder(this))); + } +} diff --git a/ui/components/form/types/textfield/textfield.admin.tsx b/ui/components/form/types/textfield/textfield.admin.tsx new file mode 100644 index 00000000..d2320734 --- /dev/null +++ b/ui/components/form/types/textfield/textfield.admin.tsx @@ -0,0 +1,18 @@ +import { Form, Input } from 'antd' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FieldAdminProps } from '../field.admin.props' + +export const TextfieldAdmin: React.FC<FieldAdminProps> = (props) => { + const { t } = useTranslation() + + return ( + <Form.Item + label={t('type:textfield:default')} + name={[props.field.name as string, 'defaultValue']} + labelCol={{ span: 6 }} + > + <Input /> + </Form.Item> + ) +} diff --git a/ui/components/form/types/textfield/textfield.input.tsx b/ui/components/form/types/textfield/textfield.input.tsx new file mode 100644 index 00000000..f6e40a9f --- /dev/null +++ b/ui/components/form/types/textfield/textfield.input.tsx @@ -0,0 +1,52 @@ +import { Form } from 'antd' +import debug from 'debug' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { StyledInput } from '../../../styled/input' +import { FieldInputBuilderType } from '../field.input.builder.type' + +const logger = debug('textfield.input') + +export const builder: FieldInputBuilderType = ({ + parseUrlValue, + parseValue, +}) => function TextfieldInput ({ + field, + design, + urlValue, + focus, +}) { + const { t } = useTranslation() + // TODO focus when becomes visible + + let initialValue = undefined + + if (field.defaultValue) { + try { + initialValue = parseValue(field.defaultValue) + } catch (e) { + logger('invalid default value %O', e) + } + } + + if (urlValue) { + initialValue = parseUrlValue(urlValue) + } + + return ( + <div> + <Form.Item + name={[field.id]} + rules={[{ required: field.required, message: t('validation:valueRequired') }]} + initialValue={initialValue} + > + <StyledInput + autoFocus={focus} + design={design} + allowClear + size={'large'} + /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/yes_no/index.tsx b/ui/components/form/types/yes_no/index.tsx new file mode 100644 index 00000000..3d853f86 --- /dev/null +++ b/ui/components/form/types/yes_no/index.tsx @@ -0,0 +1,36 @@ +import { Tag } from 'antd' +import dynamic from 'next/dynamic' +import React, { ComponentType } from 'react' +import { AbstractType } from '../abstract.type' +import { FieldAdminProps } from '../field.admin.props' +import { FieldInputProps } from '../field.input.props' + +export class YesNoType extends AbstractType<boolean> { + parseUrlValue(raw: string): boolean { + return !!raw + } + + adminFormField(): ComponentType<FieldAdminProps> { + return dynamic(() => import('./yes_no.admin').then(c => c.YesNoAdmin)); + } + + inputFormField(): ComponentType<FieldInputProps> { + return dynamic(() => import('./yes_no.input').then(c => c.builder(this))); + } + + stringifyValue(raw: string): string { + if (this.parseValue(raw)) { + return 'YES' + } else { + return 'NO' + } + } + + displayValue(raw: string): JSX.Element { + if (this.parseValue(raw)) { + return <Tag color={'green'}>YES</Tag> + } else { + return <Tag color={'red'}>NO</Tag> + } + } +} diff --git a/ui/components/form/types/yes_no/yes_no.admin.tsx b/ui/components/form/types/yes_no/yes_no.admin.tsx new file mode 100644 index 00000000..a3a65249 --- /dev/null +++ b/ui/components/form/types/yes_no/yes_no.admin.tsx @@ -0,0 +1,21 @@ +import { Form, Switch } from 'antd' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FieldAdminProps } from '../field.admin.props' + +export const YesNoAdmin: React.FC<FieldAdminProps> = (props) => { + const { t } = useTranslation() + + return ( + <div> + <Form.Item + label={t('type:yes_no:default')} + name={[props.field.name as string, 'defaultValue']} + labelCol={{ span: 6 }} + valuePropName={'checked'} + > + <Switch /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/form/types/yes_no/yes_no.input.tsx b/ui/components/form/types/yes_no/yes_no.input.tsx new file mode 100644 index 00000000..d41cdfdb --- /dev/null +++ b/ui/components/form/types/yes_no/yes_no.input.tsx @@ -0,0 +1,45 @@ +import { Form, Switch } from 'antd' +import debug from 'debug' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { FieldInputBuilderType } from '../field.input.builder.type' + +const logger = debug('yes_no.input') + +export const builder: FieldInputBuilderType = ({ + parseUrlValue, + parseValue, +}) => function YesNoInput ({ + field, + urlValue, +}) { + const { t } = useTranslation() + + + let initialValue: boolean = undefined + + if (field.defaultValue) { + try { + initialValue = parseValue(field.defaultValue) + } catch (e) { + logger('invalid default value %O', e) + } + } + + if (urlValue !== undefined) { + initialValue = parseUrlValue(urlValue) + } + + return ( + <div> + <Form.Item + name={[field.id]} + rules={[{ required: field.required, message: t('validation:valueRequired') }]} + initialValue={initialValue} + valuePropName={'checked'} + > + <Switch /> + </Form.Item> + </div> + ) +} diff --git a/ui/components/input/color.tsx b/ui/components/input/color.tsx new file mode 100644 index 00000000..4b77bd80 --- /dev/null +++ b/ui/components/input/color.tsx @@ -0,0 +1,38 @@ +import React, { useEffect } from 'react' +import { BlockPicker } from 'react-color' + +interface Props { + value?: string + onChange?: (value: string) => void +} + +export const InputColor: React.FC<Props> = (props) => { + useEffect(() => { + if (!props.value) { + props.onChange('#FFF') + } + }, [props.value]) + + return ( + <BlockPicker + triangle={'hide'} + width={'100%'} + color={props.value} + onChange={(e: { hex: string }) => props.onChange(e.hex)} + styles={{ + default: { + card: { + flexDirection: 'row', + display: 'flex', + boxShadow: 'none', + }, + head: { + flex: 1, + borderRadius: 6, + height: 'auto', + }, + }, + }} + /> + ) +} diff --git a/ui/components/loading.page.tsx b/ui/components/loading.page.tsx new file mode 100644 index 00000000..fb056455 --- /dev/null +++ b/ui/components/loading.page.tsx @@ -0,0 +1,23 @@ +import { Spin } from 'antd' +import React from 'react' + +interface Props { + message?: string +} + +export const LoadingPage: React.FC<Props> = (props) => { + return ( + <div + style={{ + height: '100vh', + justifyContent: 'center', + alignItems: 'center', + display: 'flex', + flexDirection: 'column', + }} + > + <Spin size="large" /> + {props.message} + </div> + ) +} diff --git a/ui/components/map/draggable.marker.tsx b/ui/components/map/draggable.marker.tsx new file mode 100644 index 00000000..37887792 --- /dev/null +++ b/ui/components/map/draggable.marker.tsx @@ -0,0 +1,36 @@ +import L from 'leaflet' +import React, { FC, useMemo, useRef } from 'react' +import { Marker } from 'react-leaflet' + +interface Props { + value: { lat: number, lng: number } + onChange: (value: { lat: number, lng: number }) => void +} + +export const DraggableMarker: FC<Props> = (props) => { + const markerRef = useRef<L.Marker>(null) + const eventHandlers = useMemo( + () => ({ + dragend() { + const marker = markerRef.current + if (marker != null) { + props.onChange(marker.getLatLng()) + } + }, + }), + [], + ) + return ( + <Marker + draggable={true} + eventHandlers={eventHandlers} + position={props.value} + ref={markerRef} + icon={L.icon({ + iconUrl: require('assets/images/marker-icon-2x.png'), + iconSize: [50/2, 82/2], + iconAnchor: [50 / 4, 82/2], + })} + /> + ) +} diff --git a/ui/components/omf.module.scss b/ui/components/omf.module.scss new file mode 100644 index 00000000..d3afd723 --- /dev/null +++ b/ui/components/omf.module.scss @@ -0,0 +1,71 @@ +$omf: #000; +$omfText: #FFF; +$support: #000; + +.badge { + left: -65px; + height: 30px; + top: 40px; + position: absolute; + text-decoration: none; + width: 250px; + transform: rotate(-45deg); + z-index: 100; + font-weight: bold; + letter-spacing: 0.05em; + + span { + background: transparentize($omf, 0.3); + color: $omfText; + font-size: 14px; + left: 0; + padding: 5px 0; + position: absolute; + text-align: center; + width: 250px; + box-shadow: rgba($omf, 0.2) 1px 1px 10px; + transition: opacity 1s; + &:last-child { + background: transparentize($support, 0.3); + opacity: 0; + } + } + + :hover span { + &:first-child { + opacity: 0; + } + &:last-child { + opacity: 1; + } + } + + span { + opacity: 1 !important; + backface-visibility: hidden; + transition: transform 1s; + &:last-child { + transform: rotateX(180deg); + } + } + + &:hover span { + &:first-child { + transform: rotateX(180deg); + } + &:last-child { + transform: rotateX(360deg); + } + } + + @media (max-width: 500px) { + left: -85px; + height: 30px; + top: 20px; + width: 250px; + + span { + font-size: 11px; + } + } +} diff --git a/ui/components/omf.tsx b/ui/components/omf.tsx new file mode 100644 index 00000000..319ea3da --- /dev/null +++ b/ui/components/omf.tsx @@ -0,0 +1,18 @@ +import React from 'react' +import { useSettingsQuery } from '../graphql/query/settings.query' +import scss from './omf.module.scss' + +export const Omf: React.FC = () => { + const { data, loading } = useSettingsQuery() + + if (loading || (data && data.hideContrib.value)) { + return null + } + + return ( + <a className={scss.badge} href="https://ohmyform.com" target={'_blank'} rel={'noreferrer'}> + <span>OhMyForm</span> + <span>Fork & Support!</span> + </a> + ) +} diff --git a/ui/components/sidemenu.tsx b/ui/components/sidemenu.tsx new file mode 100644 index 00000000..c9a5b68a --- /dev/null +++ b/ui/components/sidemenu.tsx @@ -0,0 +1,57 @@ +import { HomeOutlined, MessageOutlined, TeamOutlined } from '@ant-design/icons' +import { UserOutlined } from '@ant-design/icons/lib' +import React from 'react' + +export interface SideMenuElement { + items?: SideMenuElement[] + + key: string + name: string + group?: boolean + href?: string + icon?: JSX.Element + role?: 'superuser' | 'admin' +} + +export const sideMenu: SideMenuElement[] = [ + { + key: 'home', + name: 'admin:home', + href: '/admin', + icon: <HomeOutlined />, + }, + { + key: 'profile', + name: 'admin:profile', + href: '/admin/profile', + icon: <UserOutlined />, + }, + { + key: 'public', + name: 'admin:forms', + group: true, + role: 'admin', + items: [ + { + key: 'forms', + name: 'admin:forms', + href: '/admin/forms', + icon: <MessageOutlined />, + }, + ], + }, + { + key: 'administration', + name: 'admin:administration', + group: true, + role: 'superuser', + items: [ + { + key: 'users', + name: 'admin:users', + href: '/admin/users', + icon: <TeamOutlined />, + }, + ], + }, +] diff --git a/ui/components/structure.tsx b/ui/components/structure.tsx new file mode 100644 index 00000000..df8fc5d2 --- /dev/null +++ b/ui/components/structure.tsx @@ -0,0 +1,328 @@ +import { CaretDownOutlined, UserOutlined } from '@ant-design/icons' +import { MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons/lib' +import { Alert, Dropdown, Layout, Menu, PageHeader, Select, Space, Spin, Tag } from 'antd' +import Link from 'next/link' +import { useRouter } from 'next/router' +import React, { CSSProperties, FunctionComponent } from 'react' +import GitHubButton from 'react-github-button' +import { useTranslation } from 'react-i18next' +import { useMeQuery } from '../graphql/query/me.query' +import { languages } from '../i18n' +import { sideMenu, SideMenuElement } from './sidemenu' +import { useWindowSize } from './use.window.size' +import { clearAuth } from './with.auth' + +const { SubMenu, ItemGroup } = Menu +const { Header, Content, Sider } = Layout + +interface BreadcrumbEntry { + name: string + href?: string + as?: string +} + +interface Props { + loading?: boolean + padded?: boolean + style?: CSSProperties + + selected?: string + + breadcrumbs?: BreadcrumbEntry[] + title?: string + subTitle?: string + extra?: JSX.Element[] + error?: string +} + +export const Structure: FunctionComponent<Props> = (props) => { + const { t, i18n } = useTranslation() + const size = useWindowSize() + const [userMenu, setUserMenu] = React.useState(false) + const [open, setOpen] = React.useState<string[]>() + const [selected, setSelected] = React.useState<string[]>() + const [sidebar, setSidebar] = React.useState(size.width < 700) + const router = useRouter() + const user = useMeQuery() + + React.useEffect(() => { + if (sidebar !== size.width < 700) { + setSidebar(size.width < 700) + } + }, [size.width]) + + React.useEffect(() => { + if (props.selected) { + const parts = props.selected.split('.') + + const last = parts.pop() + + if (parts.length > 0) { + setOpen(parts) + } + + setSelected([last]) + } + }, [props.selected]) + + const buildMenu = (data: SideMenuElement[]): JSX.Element[] => { + return data + .filter((element) => { + if (!element.role) { + return true + } + + if (user.loading) { + return false + } + + return user.data?.me.roles.includes(element.role) + }) + .map( + (element): JSX.Element => { + if (element.items && element.items.length > 0) { + if (element.group) { + return ( + <ItemGroup + key={element.key} + title={ + <Space + style={{ + textTransform: 'uppercase', + paddingTop: 16, + fontWeight: 'bold', + color: '#444', + }} + > + {element.icon} + <div> + {t(element.name)} + </div> + </Space> + } + > + {buildMenu(element.items)} + </ItemGroup> + ) + } + + return ( + <SubMenu + key={element.key} + title={ + <Space> + {element.icon} + <div> + {t(element.name)} + </div> + </Space> + } + > + {buildMenu(element.items)} + </SubMenu> + ) + } + + return ( + <Menu.Item + onClick={async () => { + if (element.href) { + await router.push(element.href) + } + }} + key={element.key} + > + <Space> + {element.icon} + <div> + {t(element.name)} + </div> + </Space> + </Menu.Item> + ) + } + ) + } + + const signOut = (): void => { + clearAuth() + router.reload() + } + + return ( + <Layout style={{ height: '100vh' }} className={'admin'}> + <Header + style={{ + paddingLeft: 0, + }} + > + <Space + style={{ + float: 'left', + color: '#FFF', + fontSize: 14, + marginRight: 26, + fontWeight: 'bold', + }} + > + {React.createElement(sidebar ? MenuUnfoldOutlined : MenuFoldOutlined, { + className: 'sidebar-toggle', + onClick: () => setSidebar(!sidebar), + })} + + <div style={{ + display: 'flex', + alignItems: 'center', + }}> + <img + height={40} + src={require('../assets/images/logo_white.png?resize&size=256')} + alt={'OhMyForm'} + /> + </div> + </Space> + <div style={{ float: 'right', display: 'flex', height: '100%' }}> + <Dropdown + overlay={ + <Menu> + <Menu.Item key={'profile'} onClick={() => router.push('/admin/profile')}>Profile</Menu.Item> + <Menu.Divider key={'d1'} /> + <Menu.Item key={'logout'} onClick={signOut}>Logout</Menu.Item> + </Menu> + } + onVisibleChange={setUserMenu} + visible={userMenu} + > + <Space + style={{ + color: '#FFF', + alignItems: 'center', + display: 'inline-flex', + }} + > + <div>Hi {user.data && user.data.me.username},</div> + <UserOutlined style={{ fontSize: 24 }} /> + <CaretDownOutlined /> + </Space> + </Dropdown> + </div> + </Header> + <Layout + style={{ + height: '100%', + }} + > + <Sider + collapsed={sidebar} + trigger={null} + collapsedWidth={0} + breakpoint={'xs'} + width={200} + style={{ + background: '#fff', + maxHeight: '100%', + overflow: 'auto', + }} + className={'sidemenu'} + > + <Menu + mode="inline" + style={{ flex: 1 }} + defaultSelectedKeys={['1']} + selectedKeys={selected} + onSelect={(s): void => setSelected(s.keyPath )} + openKeys={open} + onOpenChange={(open): void => setOpen(open )} + > + {buildMenu(sideMenu)} + </Menu> + <Menu mode="inline" selectable={false}> + <Menu.Item className={'language-selector'} key={'language-selector'}> + <Select + bordered={false} + value={i18n.language.replace(/-.*/, '')} + onChange={(next) => i18n.changeLanguage(next)} + style={{ + width: '100%', + }} + > + {languages.map((language) => ( + <Select.Option value={language} key={language}> + {t(`language:${language}`)} + </Select.Option> + ))} + </Select> + </Menu.Item> + <Menu.Item style={{ display: 'flex', alignItems: 'center' }} key={'github'}> + <GitHubButton type="stargazers" namespace="ohmyform" repo="ohmyform" /> + </Menu.Item> + <Menu.Item key={'version'}> + Version: <Tag color="gold">{process.env.version}</Tag> + </Menu.Item> + </Menu> + </Sider> + <Layout + style={{ padding: '0 24px 24px', minHeight: 500, height: '100%', overflow: 'auto' }} + > + {props.title && ( + <PageHeader + title={props.title} + subTitle={props.subTitle} + extra={props.extra} + breadcrumb={{ + routes: [ + ...(props.breadcrumbs || []).map((b) => ({ + breadcrumbName: b.name, + path: '', + })), + { + breadcrumbName: props.title, + path: '', + }, + ], + params: props.breadcrumbs, + itemRender(route, params: BreadcrumbEntry[], routes) { + if (routes.indexOf(route) === routes.length - 1) { + return <span>{route.breadcrumbName}</span> + } + + const entry = params[routes.indexOf(route)] + + return ( + <Link href={entry.href} as={entry.as || entry.href}> + {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} + <a>{entry.name}</a> + </Link> + ) + }, + }} + /> + )} + + {props.error && ( + <Alert message={props.error} type={'error'} style={{ marginBottom: 24 }} /> + )} + + <Spin spinning={!!props.loading}> + <Content + style={{ + background: props.padded ? '#fff' : null, + padding: props.padded ? 24 : 0, + ...props.style, + }} + > + {props.children} + </Content> + </Spin> + </Layout> + </Layout> + </Layout> + ) +} + +Structure.defaultProps = { + padded: true, + style: {}, +} + +export default Structure diff --git a/ui/components/styled/button.tsx b/ui/components/styled/button.tsx new file mode 100644 index 00000000..780d59bc --- /dev/null +++ b/ui/components/styled/button.tsx @@ -0,0 +1,28 @@ +import { Button } from 'antd' +import { ButtonProps } from 'antd/lib/button/button' +import { darken, lighten } from 'polished' +import React from 'react' +import styled from 'styled-components' + +interface Props extends ButtonProps { + background: string + highlight: string + color: string +} + +// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment +const Styled = styled(Button)` + background: ${(props: Props) => props.background}; + color: ${(props: Props) => props.color}; + border-color: ${(props: Props) => darken(0.1, props.background)}; + + :hover { + color: ${(props: Props) => props.highlight}; + background-color: ${(props: Props) => lighten(0.1, props.background)}; + border-color: ${(props: Props) => darken(0.1, props.highlight)}; + } +` + +export const StyledButton: React.FC<Props> = ({ children, ...props }) => { + return <Styled {...props}>{children}</Styled> +} diff --git a/ui/components/styled/checkbox.tsx b/ui/components/styled/checkbox.tsx new file mode 100644 index 00000000..a313be0c --- /dev/null +++ b/ui/components/styled/checkbox.tsx @@ -0,0 +1,38 @@ +import { Checkbox } from 'antd' +import { RadioProps } from 'antd/lib/radio/interface' +import React from 'react' +import styled from 'styled-components' +import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment' + +interface Props extends RadioProps { + design: FormPublicDesignFragment +} + +// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment +const Field = styled(Checkbox)` + color: ${(props: Props) => props.design.colors.answer}; + border-color: ${(props: Props) => props.design.colors.answer}; + background: none; + + .ant-radio { + .ant-radio-inner { + border-color: ${(props: Props) => props.design.colors.answer}; + + &::after { + background: ${(props: Props) => props.design.colors.answer}; + } + } + + &::after { + border-color: ${(props: Props) => props.design.colors.answer}; + } + } + + .anticon { + color: ${(props: Props) => props.design.colors.answer}; + } +` + +export const StyledCheckbox: React.FC<Props> = ({ children, ...props }) => { + return <Field {...props}>{children}</Field> +} diff --git a/ui/components/styled/date.input.tsx b/ui/components/styled/date.input.tsx new file mode 100644 index 00000000..4728adee --- /dev/null +++ b/ui/components/styled/date.input.tsx @@ -0,0 +1,50 @@ +import { DatePicker } from 'antd' +import { PickerProps } from 'antd/lib/date-picker/generatePicker' +import { Moment } from 'moment' +import { transparentize } from 'polished' +import React from 'react' +import styled from 'styled-components' +import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment' + +type Props = { design: FormPublicDesignFragment } & PickerProps<Moment> + +// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment +const Field = styled(DatePicker)` + color: ${(props: Props) => props.design.colors.answer}; + border-color: ${(props: Props) => props.design.colors.answer}; + background: none !important; + border-right: none; + border-top: none; + border-left: none; + border-radius: 0; + width: 100%; + + :hover, + :active { + border-color: ${(props: Props) => props.design.colors.answer}; + } + + &.ant-picker { + box-shadow: none; + } + + .ant-picker-clear { + background: none; + } + + input { + color: ${(props: Props) => props.design.colors.answer}; + + ::placeholder { + color: ${(props: Props) => transparentize(0.6, props.design.colors.answer)}; + } + } + + .anticon { + color: ${(props: Props) => props.design.colors.answer}; + } +` + +export const StyledDateInput: React.FC<Props> = ({ children, ...props }) => { + return <Field {...props}>{children}</Field> +} diff --git a/ui/components/styled/h1.tsx b/ui/components/styled/h1.tsx new file mode 100644 index 00000000..2aa4bef2 --- /dev/null +++ b/ui/components/styled/h1.tsx @@ -0,0 +1,17 @@ +import React from 'react' +import styled from 'styled-components' +import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment' + +interface Props { + type: 'question' | 'answer' + design: FormPublicDesignFragment +} + +const Header = styled.h1` + color: ${(props: Props) => + props.type === 'question' ? props.design.colors.question : props.design.colors.answer}; +` + +export const StyledH1: React.FC<Props> = ({ children, ...props }) => { + return <Header {...props}>{children}</Header> +} diff --git a/ui/components/styled/h2.tsx b/ui/components/styled/h2.tsx new file mode 100644 index 00000000..f717b955 --- /dev/null +++ b/ui/components/styled/h2.tsx @@ -0,0 +1,16 @@ +import React from 'react' +import styled from 'styled-components' +import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment' + +interface Props { + type: 'question' | 'answer' + design: FormPublicDesignFragment +} +const Header = styled.h2` + color: ${(props: Props) => + props.type === 'question' ? props.design.colors.question : props.design.colors.answer}; +` + +export const StyledH2: React.FC<Props> = ({ children, ...props }) => { + return <Header {...props}>{children}</Header> +} diff --git a/ui/components/styled/input.tsx b/ui/components/styled/input.tsx new file mode 100644 index 00000000..78113af2 --- /dev/null +++ b/ui/components/styled/input.tsx @@ -0,0 +1,51 @@ +import { Input } from 'antd' +import { InputProps } from 'antd/lib/input/Input' +import { transparentize } from 'polished' +import React from 'react' +import styled from 'styled-components' +import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment' + +interface Props extends InputProps { + design: FormPublicDesignFragment +} + +// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment +const Field = styled(Input)` + color: ${(props: Props) => props.design.colors.answer}; + border-color: ${(props: Props) => props.design.colors.answer}; + background: none !important; + border-right: none; + border-top: none; + border-left: none; + border-radius: 0; + + :focus { + outline: ${(props: Props) => props.design.colors.answer} auto 5px; + } + + :hover, + :active { + border-color: ${(props: Props) => props.design.colors.answer}; + } + + &.ant-input-affix-wrapper { + box-shadow: none; + } + + input { + background: none !important; + color: ${(props: Props) => props.design.colors.answer}; + + ::placeholder { + color: ${(props: Props) => transparentize(0.6, props.design.colors.answer)}; + } + } + + .anticon { + color: ${(props: Props) => props.design.colors.answer}; + } +` + +export const StyledInput: React.FC<Props> = ({ children, ...props }) => { + return <Field {...props}>{children}</Field> +} diff --git a/ui/components/styled/markdown.tsx b/ui/components/styled/markdown.tsx new file mode 100644 index 00000000..8b849219 --- /dev/null +++ b/ui/components/styled/markdown.tsx @@ -0,0 +1,64 @@ +import { lighten } from 'polished' +import React from 'react' +import ReactMarkdown from 'react-markdown' +import { ReactMarkdownOptions } from 'react-markdown/lib/react-markdown' +import styled from 'styled-components' +import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment' + +interface Props extends ReactMarkdownOptions { + type: 'question' | 'answer' + design: FormPublicDesignFragment +} + +const getColor = (props: Props) => + props.type === 'question' ? props.design.colors.question : props.design.colors.answer + +// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment +const Markdown = styled(ReactMarkdown)` + color: ${getColor}; + + h1, + h2, + h3, + h4, + h5, + h6, + p, + span, + div { + color: ${getColor}; + } + + blockquote { + color: ${(props: Props) => lighten(0.5, getColor(props))}; + padding-left: 20px; + border-left: 10px rgba(0, 0, 0, 0.05) solid; + } + + table { + border-collapse: collapse; + border-spacing: 0; + + tr { + border-top: 1px solid ${getColor}; + + th, + td { + padding: 6px 13px; + border: 1px solid ${getColor}; + } + } + + tr:nth-child(2n) { + background: rgba(0, 0, 0, 0.05); + } + } +` + +export const StyledMarkdown: React.FC<Props> = ({ children, ...props }) => { + return ( + <Markdown {...props}> + {children} + </Markdown> + ) +} diff --git a/ui/components/styled/number.input.tsx b/ui/components/styled/number.input.tsx new file mode 100644 index 00000000..6207d7d9 --- /dev/null +++ b/ui/components/styled/number.input.tsx @@ -0,0 +1,52 @@ +import { InputNumber } from 'antd' +import { InputNumberProps } from 'antd/lib/input-number' +import { transparentize } from 'polished' +import React from 'react' +import styled from 'styled-components' +import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment' + +interface Props extends InputNumberProps { + design: FormPublicDesignFragment +} + +// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment +const Field = styled(InputNumber)` + color: ${(props: Props) => props.design.colors.answer}; + border-color: ${(props: Props) => props.design.colors.answer}; + background: none !important; + border-right: none; + border-top: none; + border-left: none; + border-radius: 0; + width: 100%; + + :focus { + outline: ${(props: Props) => props.design.colors.answer} auto 5px; + } + + :hover, + :active { + border-color: ${(props: Props) => props.design.colors.answer}; + } + + &.ant-input-number { + box-shadow: none; + } + + input { + background: none !important; + color: ${(props: Props) => props.design.colors.answer}; + + ::placeholder { + color: ${(props: Props) => transparentize(0.6, props.design.colors.answer)}; + } + } + + .anticon { + color: ${(props: Props) => props.design.colors.answer}; + } +` + +export const StyledNumberInput: React.FC<Props> = ({ children, ...props }) => { + return <Field {...props}>{children}</Field> +} diff --git a/ui/components/styled/p.tsx b/ui/components/styled/p.tsx new file mode 100644 index 00000000..e8d0f76e --- /dev/null +++ b/ui/components/styled/p.tsx @@ -0,0 +1,18 @@ +import React from 'react' +import styled from 'styled-components' +import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment' + +interface Props { + type: 'question' | 'answer' + design: FormPublicDesignFragment +} + +// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment +const Paragraph = styled.p` + color: ${(props: Props) => + props.type === 'question' ? props.design.colors.question : props.design.colors.answer}; +` + +export const StyledP: React.FC<Props> = ({ children, ...props }) => { + return <Paragraph {...props}>{children}</Paragraph> +} diff --git a/ui/components/styled/radio.tsx b/ui/components/styled/radio.tsx new file mode 100644 index 00000000..58d22df4 --- /dev/null +++ b/ui/components/styled/radio.tsx @@ -0,0 +1,38 @@ +import { Radio } from 'antd' +import { RadioProps } from 'antd/lib/radio/interface' +import React from 'react' +import styled from 'styled-components' +import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment' + +interface Props extends RadioProps { + design: FormPublicDesignFragment +} + +// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment +const Field = styled(Radio)` + color: ${(props: Props) => props.design.colors.answer}; + border-color: ${(props: Props) => props.design.colors.answer}; + background: none; + + .ant-radio { + .ant-radio-inner { + border-color: ${(props: Props) => props.design.colors.answer}; + + &::after { + background: ${(props: Props) => props.design.colors.answer}; + } + } + + &::after { + border-color: ${(props: Props) => props.design.colors.answer}; + } + } + + .anticon { + color: ${(props: Props) => props.design.colors.answer}; + } +` + +export const StyledRadio: React.FC<Props> = ({ children, ...props }) => { + return <Field {...props}>{children}</Field> +} diff --git a/ui/components/styled/select.tsx b/ui/components/styled/select.tsx new file mode 100644 index 00000000..17512688 --- /dev/null +++ b/ui/components/styled/select.tsx @@ -0,0 +1,50 @@ +import { Select } from 'antd' +import { SelectProps } from 'antd/lib/select' +import { transparentize } from 'polished' +import React from 'react' +import styled from 'styled-components' +import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment' + +interface Props extends SelectProps<string> { + design: FormPublicDesignFragment +} + +// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment +const Field = styled(Select)` + .ant-select-selector { + color: ${(props: Props) => props.design.colors.answer}; + border-color: ${(props: Props) => props.design.colors.answer} !important; + background: none !important; + border-right: none !important; + border-top: none !important; + border-left: none !important; + border-radius: 0 !important; + box-shadow: none !important; + } + + :focus { + outline: ${(props: Props) => props.design.colors.answer} auto 5px; + } + + :hover, + :active { + border-color: ${(props: Props) => props.design.colors.answer}; + } + + input { + background: none !important; + color: ${(props: Props) => props.design.colors.answer}; + + ::placeholder { + color: ${(props: Props) => transparentize(0.6, props.design.colors.answer)}; + } + } + + .anticon { + color: ${(props: Props) => props.design.colors.answer}; + } +` + +export const StyledSelect: React.FC<Props> = ({ children, ...props }) => { + return <Field {...props}>{children}</Field> +} diff --git a/ui/components/styled/textarea.input.tsx b/ui/components/styled/textarea.input.tsx new file mode 100644 index 00000000..9c3b0c2f --- /dev/null +++ b/ui/components/styled/textarea.input.tsx @@ -0,0 +1,49 @@ +import { Input } from 'antd' +import { TextAreaProps } from 'antd/lib/input/TextArea' +import { transparentize } from 'polished' +import React from 'react' +import styled from 'styled-components' +import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment' + +interface Props extends TextAreaProps { + design: FormPublicDesignFragment +} + +// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment +const Field = styled(Input.TextArea)` + color: ${(props: Props) => props.design.colors.answer}; + border-color: ${(props: Props) => props.design.colors.answer}; + background: none !important; + border-right: none; + border-top: none; + border-left: none; + border-radius: 0; + + :focus { + outline: none; + box-shadow: none; + border-color: ${(props: Props) => props.design.colors.answer}; + } + + :hover, + :active { + border-color: ${(props: Props) => props.design.colors.answer}; + } + + input { + background: none !important; + color: ${(props: Props) => props.design.colors.answer}; + + ::placeholder { + color: ${(props: Props) => transparentize(0.6, props.design.colors.answer)}; + } + } + + .anticon { + color: ${(props: Props) => props.design.colors.answer}; + } +` + +export const StyledTextareaInput: React.FC<Props> = ({ children, ...props }) => { + return <Field {...props}>{children}</Field> +} diff --git a/ui/components/time.ago.tsx b/ui/components/time.ago.tsx new file mode 100644 index 00000000..4c29d1c4 --- /dev/null +++ b/ui/components/time.ago.tsx @@ -0,0 +1,25 @@ +import { Tooltip } from 'antd' +import dayjs from 'dayjs' +import relativeTime from 'dayjs/plugin/relativeTime' +import React from 'react' + +dayjs.extend(relativeTime) + +interface Props { + date: string +} + +export const TimeAgo: React.FC<Props> = (props) => { + const date = dayjs(props.date) + return ( + <Tooltip title={date.format('YYYY-MM-DD HH:mm:ss')}> + <div + style={{ + display: 'inline-block', + }} + > + {date.fromNow()} + </div> + </Tooltip> + ) +} diff --git a/ui/components/use.imerative.query.ts b/ui/components/use.imerative.query.ts new file mode 100644 index 00000000..3abe4343 --- /dev/null +++ b/ui/components/use.imerative.query.ts @@ -0,0 +1,16 @@ +import { ApolloQueryResult, useQuery } from '@apollo/client' +import { DocumentNode } from 'graphql' +import { useCallback } from 'react' + +export const useImperativeQuery: <TData, TVariables>( + query: DocumentNode +) => (variables: TVariables) => Promise<ApolloQueryResult<TData>> = (query) => { + const { refetch } = useQuery(query, { skip: true }) + + return useCallback( + (variables) => { + return refetch(variables) + }, + [refetch] + ) +} diff --git a/ui/components/use.math.ts b/ui/components/use.math.ts new file mode 100644 index 00000000..0af9c993 --- /dev/null +++ b/ui/components/use.math.ts @@ -0,0 +1,34 @@ +import debug from 'debug' +import { formula, init } from 'expressionparser' + +const logger = debug('useMath') + +export const useMath = (): (( + expression: string, + values?: { [id: string]: string | number } +) => boolean) => { + return (expression, values) => { + const parser = init(formula, (term: string) => { + if (Object.prototype.hasOwnProperty.call(values, term)) { + return values[term] + } + + throw new Error(`Invalid term: ${term}`); + }) + + try { + return Boolean(parser.expressionToValue(expression)) + } catch (e) { + logger( + 'failed to calculate %O: %s', + { + expression, + values, + }, + e.message + ) + + throw e + } + } +} diff --git a/ui/components/use.router.ts b/ui/components/use.router.ts new file mode 100644 index 00000000..d242e056 --- /dev/null +++ b/ui/components/use.router.ts @@ -0,0 +1,21 @@ +import { NextRouter, useRouter as useNextRouter } from 'next/router' + +type parseQueryResponse = { [key: string]: string } + +const parseQuery = (path: string): parseQueryResponse => { + const query = {} + const regex = /[?&]([^&$=]+)(=([^&$]+))?/g + let param: RegExpExecArray + + while ((param = regex.exec(path)) !== null) { + query[decodeURIComponent(param[1])] = decodeURIComponent(param[3]) + } + + return query +} + +export const useRouter = (): NextRouter => { + const router = useNextRouter() + router.query = { ...router.query, ...parseQuery(router.asPath) } + return router +} diff --git a/ui/components/use.submission.ts b/ui/components/use.submission.ts new file mode 100644 index 00000000..0342832a --- /dev/null +++ b/ui/components/use.submission.ts @@ -0,0 +1,102 @@ +import { useMutation } from '@apollo/client' +import debug from 'debug' +import { useCallback, useEffect, useState } from 'react' +import { + SUBMISSION_FINISH_MUTATION, + SubmissionFinishMutationData, + SubmissionFinishMutationVariables, +} from '../graphql/mutation/submission.finish.mutation' +import { + SUBMISSION_SET_FIELD_MUTATION, + SubmissionSetFieldMutationData, + SubmissionSetFieldMutationVariables, +} from '../graphql/mutation/submission.set.field.mutation' +import { + SUBMISSION_START_MUTATION, + SubmissionStartMutationData, + SubmissionStartMutationVariables, +} from '../graphql/mutation/submission.start.mutation' + +const logger = debug('useSubmission') + +export interface Submission { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + setField: (fieldId: string, data: unknown) => Promise<void> + finish: () => Promise<void> +} + +export const useSubmission = (formId: string): Submission => { + const [submission, setSubmission] = useState<{ id: string; token: string }>() + + const [start] = useMutation<SubmissionStartMutationData, SubmissionStartMutationVariables>( + SUBMISSION_START_MUTATION + ) + const [save] = useMutation<SubmissionSetFieldMutationData, SubmissionSetFieldMutationVariables>( + SUBMISSION_SET_FIELD_MUTATION + ) + const [submit] = useMutation<SubmissionFinishMutationData, SubmissionFinishMutationVariables>( + SUBMISSION_FINISH_MUTATION + ) + + useEffect(() => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const token = [...Array(40)].map(() => Math.random().toString(36)[2]).join('') + + start({ + variables: { + form: formId, + submission: { + token, + device: { + name: /Mobi/i.test(window.navigator.userAgent) ? 'mobile' : 'desktop', + type: window.navigator.userAgent, + }, + }, + }, + }) + .then(({ data }) => { + logger('submission id = %O', data.submission.id) + setSubmission({ + id: data.submission.id, + token, + }) + }) + .catch((e: Error) => logger('failed to start submission %J', e)) + }, [formId]) + + const setField = useCallback( + async (fieldId: string, data: unknown) => { + if (data === undefined || data === null) { + logger('skip save field id=%O %O', fieldId, data) + return + } + + logger('save field id=%O %O', fieldId, data) + await save({ + variables: { + submission: submission.id, + field: { + token: submission.token, + field: fieldId, + data: JSON.stringify(data), + }, + }, + }) + }, + [submission] + ) + + const finish = useCallback(async () => { + logger('finish submission!!', formId) + await submit({ + variables: { + submission: submission.id, + }, + }) + }, [submission]) + + return { + setField, + finish, + } +} diff --git a/ui/components/use.window.size.ts b/ui/components/use.window.size.ts new file mode 100644 index 00000000..536575e9 --- /dev/null +++ b/ui/components/use.window.size.ts @@ -0,0 +1,29 @@ +import { useEffect, useState } from 'react' + +export const useWindowSize = (): { width?: number; height?: number } => { + const isClient = typeof window === 'object' + + function getSize() { + return { + width: isClient ? window.innerWidth : undefined, + height: isClient ? window.innerHeight : undefined, + } + } + + const [windowSize, setWindowSize] = useState(getSize) + + useEffect(() => { + if (!isClient) { + return + } + + function handleResize() { + setWindowSize(getSize()) + } + + window.addEventListener('resize', handleResize) + return () => window.removeEventListener('resize', handleResize) + }, []) // Empty array ensures that effect is only run on mount and unmount + + return windowSize +} diff --git a/ui/components/user/admin/base.data.tab.tsx b/ui/components/user/admin/base.data.tab.tsx new file mode 100644 index 00000000..8fe8dbed --- /dev/null +++ b/ui/components/user/admin/base.data.tab.tsx @@ -0,0 +1,113 @@ +import { Form, Input, Select, Tabs } from 'antd' +import { TabPaneProps } from 'antd/lib/tabs' +import React from 'react' +import { languages } from '../../../i18n' + +export const BaseDataTab: React.FC<TabPaneProps> = (props) => { + return ( + <Tabs.TabPane {...props}> + <Form.Item + label="Username" + name={['user', 'username']} + rules={[ + { + required: true, + message: 'Please provide a Username', + }, + ]} + > + <Input /> + </Form.Item> + + <Form.Item + label="Email" + name={['user', 'email']} + rules={[ + { + required: true, + message: 'Please provide an email', + }, + { + type: 'email', + message: 'Must be a valid email', + }, + ]} + > + <Input type={'email'} /> + </Form.Item> + + <Form.Item + label="Role" + name={['user', 'roles']} + rules={[ + { + required: true, + message: 'Please select a role', + }, + ]} + getValueFromEvent={(e) => { + switch (e) { + case 'superuser': + return [ + 'user', 'admin', 'superuser', + ] + case 'admin': + return ['user', 'admin'] + default: + return ['user'] + } + }} + getValueProps={(v: string[]) => { + let role = 'user' + + if (v && v.includes('superuser')) { + role = 'superuser' + } else if (v && v.includes('admin')) { + role = 'admin' + } + + return { + value: role, + } + }} + > + <Select> + {[ + 'user', 'admin', 'superuser', + ].map((role) => ( + <Select.Option value={role} key={role}> + {role.toUpperCase()} + </Select.Option> + ))} + </Select> + </Form.Item> + + <Form.Item + label="Language" + name={['user', 'language']} + rules={[ + { + required: true, + message: 'Please select a Language', + }, + ]} + > + <Select> + {languages.map((language) => ( + <Select.Option value={language} key={language}> + {language.toUpperCase()} + </Select.Option> + ))} + </Select> + </Form.Item> + + <Form.Item label="First Name" name={['user', 'firstName']}> + <Input /> + </Form.Item> + + <Form.Item label="Last Name" name={['user', 'lastName']}> + <Input /> + </Form.Item> + </Tabs.TabPane> + ) +} diff --git a/ui/components/user/role.tsx b/ui/components/user/role.tsx new file mode 100644 index 00000000..73483204 --- /dev/null +++ b/ui/components/user/role.tsx @@ -0,0 +1,30 @@ +import { Tag } from 'antd' +import React, { CSSProperties } from 'react' + +interface Props { + roles: string[] +} + +export const UserRole: React.FC<Props> = (props) => { + let color: string + let level = 'unknown' + const css: CSSProperties = {} + + if (props.roles.includes('superuser')) { + color = 'red' + level = 'superuser' + } else if (props.roles.includes('admin')) { + color = 'orange' + level = 'admin' + } else if (props.roles.includes('user')) { + color = '#F0F0F0' + css.color = '#AAA' + level = 'user' + } + + return ( + <Tag color={color} style={css}> + {level.toUpperCase()} + </Tag> + ) +} diff --git a/ui/components/with.auth.tsx b/ui/components/with.auth.tsx new file mode 100644 index 00000000..0a9179cc --- /dev/null +++ b/ui/components/with.auth.tsx @@ -0,0 +1,70 @@ +import { useRouter } from 'next/router' +import React, { useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { useMeQuery } from '../graphql/query/me.query' +import { LoadingPage } from './loading.page' + +export const clearAuth = (): void => { + localStorage.removeItem('access') + localStorage.removeItem('refresh') +} + +export const setAuth = (access: string, refresh: string): void => { + localStorage.setItem('access', access) + localStorage.setItem('refresh', refresh) +} + +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types,@typescript-eslint/no-explicit-any +export const withAuth = (Component: any, roles: string[] = [], optional?: boolean): React.FC => { + // eslint-disable-next-line react/display-name + return (props) => { + const { t } = useTranslation() + const router = useRouter() + const [access, setAccess] = useState(false) + const { loading, data, error } = useMeQuery() + + useEffect(() => { + if (roles.length === 0) { + setAccess(true) + return + } + setAccess(false) + if (!error) { + return + } + + localStorage.clear() + const path = router.asPath || router.pathname + localStorage.setItem('redirect', path) + + router.push('/login').catch((e: Error) => console.error('failed to redirect to login', e)) + }, [error]) + + useEffect(() => { + if (!data || roles.length === 0) { + setAccess(true) + return + } + + const next = roles.map((role) => data.me.roles.includes(role)).filter((p) => p).length > 0 + + setAccess(next) + + if (!next) { + router.push('/').catch((e: Error) => console.error('failed to redirect to /', e)) + } + }, [data]) + + if (!optional) { + if (loading) { + return <LoadingPage message={t('loadingCredentials')} /> + } + + if (!access) { + return <LoadingPage message={t('checkingCredentials')} /> + } + } + + return <Component me={data && data.me} {...props} /> + } +} diff --git a/ui/doc/development.md b/ui/doc/development.md new file mode 100644 index 00000000..76886d2a --- /dev/null +++ b/ui/doc/development.md @@ -0,0 +1,46 @@ +# Development + +tip's and tricks to get you started + +## First Run + +install yarn on your system if not already present and then install all dependencies +by running `yarn install` + +## Development Run + +to run with hot code reloading call `yarn start:dev` + +## Production Run + +there are 2 options for a production build, one with SSR enabled and one for static exports. + +### Static Export + +To create a static export call `yarn export`, this will create the folder `/out` that can +be copied to any static hosting site. + +### SSR + +first build the current codebase by `yarn build` and then execute `PORT=4000 yarn start`, any request +coming into the system will then be rendered on the server. (great for SEO) + +## Configuration Options + +### GraphQL Path + +Per default the graphql endpoint is expected at `/graphql` on the same host as the frontend. +To modify this pass the environment variable ENDPOINT with the parameter you need. + +With a local backend you could start ie the dev server with +`ENDPOINT=http://localhost:4100/graphql yarn start:dev` + + +## Used Tools / Libraries + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Ant Design](https://ant.design/components/overview/) - UI Framework used +- [SwiperJS](https://swiperjs.com/) - Form Slides +- [Apollo Client](https://www.apollographql.com/docs/react/) - GraphQL Client +- [Styled Components](https://styled-components.com/) - Component Styling + diff --git a/ui/doc/environment.md b/ui/doc/environment.md new file mode 100644 index 00000000..1a4df094 --- /dev/null +++ b/ui/doc/environment.md @@ -0,0 +1,8 @@ +# Environment Variables + +| Name | Default Value | Description | +| ---- | ------------- | ----------- | +| ENDPOINT | `/graphql` | Path to graphql api endpoint | +| SERVER_ENDPOINT | *ENDPOINT* | if endpoint is relative it should point to a resolvable url of graphql api endpoint | +| MAIN_BACKGROUND | *not set* | background color of home page | +| SPA | `false` | dependent on the build mode this must be set to true to have working routing diff --git a/ui/graphql/client.ts b/ui/graphql/client.ts new file mode 100644 index 00000000..3eb2f8f9 --- /dev/null +++ b/ui/graphql/client.ts @@ -0,0 +1,46 @@ +import { ApolloClient, from, HttpLink, InMemoryCache } from '@apollo/client' +import { NormalizedCacheObject } from '@apollo/client/cache/inmemory/types' +import { setContext } from '@apollo/client/link/context' +import 'isomorphic-fetch' +import getConfig from 'next/config' +import { NextConfigType } from '../next.config.type' + +let client: ApolloClient<NormalizedCacheObject> + +const getClient = (): ApolloClient<NormalizedCacheObject> => { + if (!client) { + const config = getConfig() as NextConfigType + + if (!config) return client + + const { publicRuntimeConfig, serverRuntimeConfig } = config + + client = new ApolloClient<NormalizedCacheObject>({ + cache: new InMemoryCache(), + link: from([ + setContext((request, context) => { + const headers: { [key: string]: string } = {} + + if (process.browser) { + const access = localStorage.getItem('access') + + if (access) { + headers.authorization = `Bearer ${access}` + } + } + + return { + headers, + } + }), + new HttpLink({ + uri: serverRuntimeConfig.endpoint || publicRuntimeConfig.endpoint, + }), + ]), + }) + } + + return client +} + +export default getClient diff --git a/ui/graphql/fragment/admin.profile.fragment.ts b/ui/graphql/fragment/admin.profile.fragment.ts new file mode 100644 index 00000000..5cf940af --- /dev/null +++ b/ui/graphql/fragment/admin.profile.fragment.ts @@ -0,0 +1,26 @@ +import { gql } from '@apollo/client/core' + +export interface AdminProfileFragment { + id: string + email: string + username: string + language: string + firstName: string + lastName: string + created: string + lastModified?: string +} + +export const ADMIN_PROFILE_FRAGMENT = gql` + fragment AdminProfile on Profile { + id + email + username + language + firstName + lastName + roles + created + lastModified + } +` diff --git a/ui/graphql/fragment/admin.user.fragment.ts b/ui/graphql/fragment/admin.user.fragment.ts new file mode 100644 index 00000000..202f5a3d --- /dev/null +++ b/ui/graphql/fragment/admin.user.fragment.ts @@ -0,0 +1,27 @@ +import { gql } from '@apollo/client/core' + +export interface AdminUserFragment { + id: string + email: string + username: string + language: string + firstName: string + lastName: string + roles: string[] + created: string + lastModified?: string +} + +export const ADMIN_USER_FRAGMENT = gql` + fragment AdminUser on User { + id + email + username + language + firstName + lastName + roles + created + lastModified + } +` diff --git a/ui/graphql/fragment/form.fragment.ts b/ui/graphql/fragment/form.fragment.ts new file mode 100644 index 00000000..16db8572 --- /dev/null +++ b/ui/graphql/fragment/form.fragment.ts @@ -0,0 +1,224 @@ +import { gql } from '@apollo/client/core' + +export interface FormPageFragment { + id: string + show: boolean + title?: string + paragraph?: string + buttonText?: string + buttons: { + id: string + url?: string + action?: string + text?: string + bgColor?: string + color?: string + }[] +} + +export interface FormFieldOptionFragment { + id: string + key?: string + title?: string + value: string +} + +export interface FormFieldOptionKeysFragment { + [key: string]: string +} + +export interface FormFieldLogicFragment { + id: string + action: string + formula: string + enabled: boolean + jumpTo?: string + require?: boolean + visible?: boolean + disable?: boolean +} + +export interface FormFieldFragment { + id: string + idx?: number + title: string + slug?: string + type: string + description: string + required: boolean + defaultValue?: string + + options: FormFieldOptionFragment[] + optionKeys?: FormFieldOptionKeysFragment + + logic: FormFieldLogicFragment[] + + rating?: { + steps?: number + shape?: string + } +} + +export interface FormHookFragment { + id: string + enabled: boolean + url?: string + format?: string +} + +export interface FormNotificationFragment { + id: string + enabled: boolean + subject?: string + htmlTemplate?: string + toField?: string + toEmail?: string + fromField?: string + fromEmail?: string +} + +export interface FormFragment { + id?: string + title: string + created: string + lastModified?: string + language: string + showFooter: boolean + anonymousSubmission: boolean + isLive: boolean + fields: FormFieldFragment[] + hooks: FormHookFragment[] + notifications: FormNotificationFragment[] + design: { + colors: { + background: string + question: string + answer: string + button: string + buttonText: string + } + font?: string + layout?: string + } + startPage: FormPageFragment + endPage: FormPageFragment + admin: { + id: string + username: string + email: string + } +} + +export const FORM_FRAGMENT = gql` + fragment Form on Form { + id + title + created + lastModified + language + showFooter + anonymousSubmission + isLive + + hooks { + id + enabled + format + url + } + + fields { + id + idx + title + slug + type + description + required + defaultValue + + options { + id + key + title + value + } + + logic { + id + action + formula + enabled + jumpTo + require + visible + disable + } + rating { + steps + shape + } + } + + notifications { + id + enabled + subject + htmlTemplate + fromField + fromEmail + toField + toEmail + } + + design { + colors { + background + question + answer + button + buttonActive + buttonText + } + font + layout + } + startPage { + id + show + title + paragraph + buttonText + buttons { + id + url + action + text + bgColor + activeColor + color + } + } + endPage { + id + show + title + paragraph + buttonText + buttons { + id + url + action + text + bgColor + activeColor + color + } + } + admin { + id + username + email + } + } +` diff --git a/ui/graphql/fragment/form.pager.fragment.ts b/ui/graphql/fragment/form.pager.fragment.ts new file mode 100644 index 00000000..399b5b8a --- /dev/null +++ b/ui/graphql/fragment/form.pager.fragment.ts @@ -0,0 +1,31 @@ +import { gql } from '@apollo/client/core' + +export interface FormPagerFragment { + id: string + created: string + lastModified?: string + title: string + isLive: boolean + language: string + admin: { + id: string + email: string + username: string + } +} + +export const FORM_PAGER_FRAGMENT = gql` + fragment PagerForm on Form { + id + created + lastModified + title + isLive + language + admin { + id + email + username + } + } +` diff --git a/ui/graphql/fragment/form.public.fragment.ts b/ui/graphql/fragment/form.public.fragment.ts new file mode 100644 index 00000000..5e08d433 --- /dev/null +++ b/ui/graphql/fragment/form.public.fragment.ts @@ -0,0 +1,177 @@ +import { gql } from '@apollo/client/core' + +export interface FormPublicPageButtonFragment { + id: string + url?: string + action?: string + text?: string + bgColor?: string + activeColor?: string + color?: string +} + +export interface FormPublicPageFragment { + id: string + show: boolean + title?: string + paragraph?: string + buttonText?: string + buttons: FormPublicPageButtonFragment[] +} + +export interface FormPublicFieldOptionFragment { + key?: string + title?: string + value: string +} + +export interface FormPublicFieldLogicFragment { + id: string + action: string + formula: string + jumpTo?: string + require?: boolean + visible?: boolean + disable?: boolean +} + +export interface FormPublicFieldFragment { + id: string + title: string + slug?: string + type: string + description: string + required: boolean + defaultValue: string + + options: FormPublicFieldOptionFragment[] + + logic: FormPublicFieldLogicFragment[] + + rating?: { + steps?: number + shape?: string + } +} + +export interface FormPublicDesignFragment { + colors: { + background: string + question: string + answer: string + button: string + buttonActive: string + buttonText: string + } + font?: string + layout?: string +} + +export interface FormPublicFragment { + id?: string + title: string + created: string + language: string + showFooter: boolean + fields: FormPublicFieldFragment[] + design: FormPublicDesignFragment + startPage: FormPublicPageFragment + endPage: FormPublicPageFragment +} + +export const FORM_PUBLIC_FRAGMENT = gql` + fragment PublicForm on Form { + id + title + language + showFooter + + fields { + id + title + slug + type + description + required + defaultValue + + logic { + id + formula + action + disable + jumpTo + require + visible + } + + options { + id + key + title + value + } + + logic { + id + action + formula + jumpTo + require + visible + disable + } + rating { + steps + shape + } + } + + design { + colors { + background + question + answer + button + buttonActive + buttonText + } + font + layout + } + + startPage { + id + show + title + paragraph + buttonText + buttons { + id + url + action + text + bgColor + activeColor + color + } + } + + endPage { + id + show + title + paragraph + buttonText + buttons { + id + url + action + text + bgColor + activeColor + color + } + } + } +` diff --git a/ui/graphql/fragment/submission.fragment.ts b/ui/graphql/fragment/submission.fragment.ts new file mode 100644 index 00000000..40915278 --- /dev/null +++ b/ui/graphql/fragment/submission.fragment.ts @@ -0,0 +1,63 @@ +import { gql } from '@apollo/client/core' + +interface FormFieldSubmissionFragment { + id: string + title: string + required: boolean +} + +export interface SubmissionFieldFragment { + id: string + value: string + type: string + + field?: FormFieldSubmissionFragment +} + +export interface SubmissionFragment { + id: string + created: string + lastModified?: string + percentageComplete: number + timeElapsed: number + geoLocation: { + country: string + city: string + } + device: { + type: string + name: string + } + + fields: SubmissionFieldFragment[] +} + +export const SUBMISSION_FRAGMENT = gql` + fragment Submission on Submission { + id + created + lastModified + percentageComplete + timeElapsed + geoLocation { + country + city + } + device { + type + name + } + + fields { + id + value + type + + field { + id + title + required + } + } + } +` diff --git a/ui/graphql/fragment/user.pager.fragment.ts b/ui/graphql/fragment/user.pager.fragment.ts new file mode 100644 index 00000000..28aec8c1 --- /dev/null +++ b/ui/graphql/fragment/user.pager.fragment.ts @@ -0,0 +1,19 @@ +import { gql } from '@apollo/client/core' + +export interface UserPagerFragment { + id: string + roles: string[] + verifiedEmail: boolean + email: string + created: string +} + +export const USER_PAGER_FRAGMENT = gql` + fragment User on User { + id + roles + verifiedEmail + email + created + } +` diff --git a/ui/graphql/mutation/form.create.mutation.ts b/ui/graphql/mutation/form.create.mutation.ts new file mode 100644 index 00000000..a758f11b --- /dev/null +++ b/ui/graphql/mutation/form.create.mutation.ts @@ -0,0 +1,45 @@ +import { MutationHookOptions, MutationTuple, useMutation } from '@apollo/client' +import { gql } from '@apollo/client/core' +import { FORM_FRAGMENT, FormFragment } from '../fragment/form.fragment' + +interface Data { + form: FormFragment +} + +interface Variables { + form: { + isLive: boolean + language: string + showFooter?: boolean + title: string + } +} + +const MUTATION = gql` + mutation createForm($form: FormCreateInput!) { + form: createForm(form: $form) { + ...Form + } + } + + ${FORM_FRAGMENT} +` + +export const useFormCreateMutation = ( + options: MutationHookOptions<Data, Variables> = {} +): MutationTuple<Data, Variables> => { + const oldUpdate = options.update + + options.update = (cache, result, options) => { + cache.evict({ + fieldName: 'listForms', + }) + cache.gc() + + if (oldUpdate) { + oldUpdate(cache, result, options) + } + } + + return useMutation<Data, Variables>(MUTATION, options) +} diff --git a/ui/graphql/mutation/form.delete.mutation.ts b/ui/graphql/mutation/form.delete.mutation.ts new file mode 100644 index 00000000..a8699f8b --- /dev/null +++ b/ui/graphql/mutation/form.delete.mutation.ts @@ -0,0 +1,24 @@ +import { MutationHookOptions, MutationTuple, useMutation } from '@apollo/client' +import { gql } from '@apollo/client/core' + +interface Data { + form: { + id + } +} + +interface Variables { + id: string +} + +const MUTATION = gql` + mutation deleteForm($id: ID!) { + form: deleteForm(id: $id) { + id + } + } +` + +export const useFormDeleteMutation = ( + data?: MutationHookOptions<Data, Variables> +): MutationTuple<Data, Variables> => useMutation<Data, Variables>(MUTATION, data) diff --git a/ui/graphql/mutation/form.update.mutation.ts b/ui/graphql/mutation/form.update.mutation.ts new file mode 100644 index 00000000..602395a2 --- /dev/null +++ b/ui/graphql/mutation/form.update.mutation.ts @@ -0,0 +1,25 @@ +import { MutationHookOptions, MutationTuple, useMutation } from '@apollo/client' +import { gql } from '@apollo/client/core' +import { FORM_FRAGMENT, FormFragment } from '../fragment/form.fragment' + +interface Data { + form: FormFragment +} + +interface Variables { + form: FormFragment +} + +const MUTATION = gql` + mutation updateForm($form: FormUpdateInput!) { + form: updateForm(form: $form) { + ...Form + } + } + + ${FORM_FRAGMENT} +` + +export const useFormUpdateMutation = ( + data?: MutationHookOptions<Data, Variables> +): MutationTuple<Data, Variables> => useMutation<Data, Variables>(MUTATION, data) diff --git a/ui/graphql/mutation/login.mutation.ts b/ui/graphql/mutation/login.mutation.ts new file mode 100644 index 00000000..b2a8a4d2 --- /dev/null +++ b/ui/graphql/mutation/login.mutation.ts @@ -0,0 +1,22 @@ +import { gql } from '@apollo/client/core' + +export interface LoginMutationData { + tokens: { + access: string + refresh: string + } +} + +export interface LoginMutationVariables { + username: string + password: string +} + +export const LOGIN_MUTATION = gql` + mutation authLogin($username: String!, $password: String!) { + tokens: authLogin(username: $username, password: $password) { + access: accessToken + refresh: refreshToken + } + } +` diff --git a/ui/graphql/mutation/profile.update.mutation.ts b/ui/graphql/mutation/profile.update.mutation.ts new file mode 100644 index 00000000..ba2baf8b --- /dev/null +++ b/ui/graphql/mutation/profile.update.mutation.ts @@ -0,0 +1,34 @@ +import { MutationHookOptions, MutationTuple, useMutation } from '@apollo/client' +import { gql } from '@apollo/client/core' +import { ADMIN_PROFILE_FRAGMENT } from '../fragment/admin.profile.fragment' +import { AdminUserFragment } from '../fragment/admin.user.fragment' + +export interface Data { + user: AdminUserFragment +} + +export interface Variables { + user: { + email?: string + firstName?: string + id: string + language?: string + lastName?: string + password?: string + username?: string + } +} + +export const MUTATION = gql` + mutation updateProfile($user: ProfileUpdateInput!) { + form: updateProfile(user: $user) { + ...AdminProfile + } + } + + ${ADMIN_PROFILE_FRAGMENT} +` + +export const useProfileUpdateMutation = ( + data?: MutationHookOptions<Data, Variables> +): MutationTuple<Data, Variables> => useMutation<Data, Variables>(MUTATION, data) diff --git a/ui/graphql/mutation/register.mutation.ts b/ui/graphql/mutation/register.mutation.ts new file mode 100644 index 00000000..b120d7c6 --- /dev/null +++ b/ui/graphql/mutation/register.mutation.ts @@ -0,0 +1,32 @@ +import { MutationHookOptions, MutationTuple, useMutation } from '@apollo/client' +import { gql } from '@apollo/client/core' + +interface Data { + tokens: { + access: string + refresh: string + } +} + +export interface RegisterUserData { + username: string + email: string + password: string +} + +interface Variables { + user: RegisterUserData +} + +const MUTATION = gql` + mutation authRegister($user: UserCreateInput!) { + tokens: authRegister(user: $user) { + access: accessToken + refresh: refreshToken + } + } +` + +export const useRegisterMutation = ( + data?: MutationHookOptions<Data, Variables> +): MutationTuple<Data, Variables> => useMutation<Data, Variables>(MUTATION, data) diff --git a/ui/graphql/mutation/submission.finish.mutation.ts b/ui/graphql/mutation/submission.finish.mutation.ts new file mode 100644 index 00000000..57c94706 --- /dev/null +++ b/ui/graphql/mutation/submission.finish.mutation.ts @@ -0,0 +1,21 @@ +import { gql } from '@apollo/client/core' + +export interface SubmissionFinishMutationData { + submission: { + id: string + percentageComplete: string + } +} + +export interface SubmissionFinishMutationVariables { + submission: string +} + +export const SUBMISSION_FINISH_MUTATION = gql` + mutation submissionFinish($submission: ID!) { + submission: submissionFinish(submission: $submission) { + id + percentageComplete + } + } +` diff --git a/ui/graphql/mutation/submission.set.field.mutation.ts b/ui/graphql/mutation/submission.set.field.mutation.ts new file mode 100644 index 00000000..c8a75aa8 --- /dev/null +++ b/ui/graphql/mutation/submission.set.field.mutation.ts @@ -0,0 +1,26 @@ +import { gql } from '@apollo/client/core' + +export interface SubmissionSetFieldMutationData { + submission: { + id: string + percentageComplete: string + } +} + +export interface SubmissionSetFieldMutationVariables { + submission: string + field: { + token: string + field: string + data: string + } +} + +export const SUBMISSION_SET_FIELD_MUTATION = gql` + mutation submissionSetField($submission: ID!, $field: SubmissionSetFieldInput!) { + submission: submissionSetField(submission: $submission, field: $field) { + id + percentageComplete + } + } +` diff --git a/ui/graphql/mutation/submission.start.mutation.ts b/ui/graphql/mutation/submission.start.mutation.ts new file mode 100644 index 00000000..3ec91acd --- /dev/null +++ b/ui/graphql/mutation/submission.start.mutation.ts @@ -0,0 +1,28 @@ +import { gql } from '@apollo/client/core' + +export interface SubmissionStartMutationData { + submission: { + id: string + percentageComplete: string + } +} + +export interface SubmissionStartMutationVariables { + form: string + submission: { + token: string + device: { + type: string + name: string + } + } +} + +export const SUBMISSION_START_MUTATION = gql` + mutation submissionStart($form: ID!, $submission: SubmissionStartInput!) { + submission: submissionStart(form: $form, submission: $submission) { + id + percentageComplete + } + } +` diff --git a/ui/graphql/mutation/user.delete.mutation.ts b/ui/graphql/mutation/user.delete.mutation.ts new file mode 100644 index 00000000..48e59dae --- /dev/null +++ b/ui/graphql/mutation/user.delete.mutation.ts @@ -0,0 +1,24 @@ +import { MutationHookOptions, MutationTuple, useMutation } from '@apollo/client' +import { gql } from '@apollo/client/core' + +interface Data { + form: { + id + } +} + +interface Variables { + id: string +} + +const MUTATION = gql` + mutation deleteUser($id: ID!) { + form: deleteUser(id: $id) { + id + } + } +` + +export const useUserDeleteMutation = ( + data?: MutationHookOptions<Data, Variables> +): MutationTuple<Data, Variables> => useMutation<Data, Variables>(MUTATION, data) diff --git a/ui/graphql/mutation/user.update.mutation.ts b/ui/graphql/mutation/user.update.mutation.ts new file mode 100644 index 00000000..e9059fdb --- /dev/null +++ b/ui/graphql/mutation/user.update.mutation.ts @@ -0,0 +1,25 @@ +import { MutationHookOptions, MutationTuple, useMutation } from '@apollo/client' +import { gql } from '@apollo/client/core' +import { ADMIN_USER_FRAGMENT, AdminUserFragment } from '../fragment/admin.user.fragment' + +interface Data { + user: AdminUserFragment +} + +interface Variables { + user: AdminUserFragment +} + +const MUTATION = gql` + mutation updateUser($user: UserUpdateInput!) { + form: updateUser(user: $user) { + ...AdminUser + } + } + + ${ADMIN_USER_FRAGMENT} +` + +export const useUserUpdateMutation = ( + data?: MutationHookOptions<Data, Variables> +): MutationTuple<Data, Variables> => useMutation<Data, Variables>(MUTATION, data) diff --git a/ui/graphql/query/admin.profile.query.ts b/ui/graphql/query/admin.profile.query.ts new file mode 100644 index 00000000..f97f09b1 --- /dev/null +++ b/ui/graphql/query/admin.profile.query.ts @@ -0,0 +1,21 @@ +import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client' +import { gql } from '@apollo/client/core' +import { ADMIN_PROFILE_FRAGMENT, AdminProfileFragment } from '../fragment/admin.profile.fragment' + +interface Data { + user: AdminProfileFragment +} + +export const QUERY = gql` + query adminMe { + user: me { + ...AdminProfile + } + } + + ${ADMIN_PROFILE_FRAGMENT} +` + +export const useProfileQuery = ( + options?: QueryHookOptions<Data, unknown> +): QueryResult<Data, unknown> => useQuery<Data, unknown>(QUERY, options) diff --git a/ui/graphql/query/admin.statistic.query.ts b/ui/graphql/query/admin.statistic.query.ts new file mode 100644 index 00000000..162e47c0 --- /dev/null +++ b/ui/graphql/query/admin.statistic.query.ts @@ -0,0 +1,29 @@ +import { gql } from '@apollo/client/core' + +export interface AdminStatisticQueryData { + forms: { + total: number + } + submissions: { + total: number + } + users: { + total: number + } +} + +export interface AdminStatisticQueryVariables {} + +export const ADMIN_STATISTIC_QUERY = gql` + query statistics { + forms: getFormStatistic { + total + } + submissions: getSubmissionStatistic { + total + } + users: getUserStatistic { + total + } + } +` diff --git a/ui/graphql/query/admin.user.query.ts b/ui/graphql/query/admin.user.query.ts new file mode 100644 index 00000000..b01b873a --- /dev/null +++ b/ui/graphql/query/admin.user.query.ts @@ -0,0 +1,20 @@ +import { gql } from '@apollo/client/core' +import { ADMIN_USER_FRAGMENT, AdminUserFragment } from '../fragment/admin.user.fragment' + +export interface AdminUserQueryData { + user: AdminUserFragment +} + +export interface AdminUserQueryVariables { + id: string +} + +export const ADMIN_USER_QUERY = gql` + query getUserById($id: ID!) { + user: getUserById(id: $id) { + ...AdminUser + } + } + + ${ADMIN_USER_FRAGMENT} +` diff --git a/ui/graphql/query/form.pager.query.ts b/ui/graphql/query/form.pager.query.ts new file mode 100644 index 00000000..13af394c --- /dev/null +++ b/ui/graphql/query/form.pager.query.ts @@ -0,0 +1,37 @@ +import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client' +import { gql } from '@apollo/client/core' +import { FORM_PAGER_FRAGMENT, FormPagerFragment } from '../fragment/form.pager.fragment' + +interface Data { + pager: { + entries: FormPagerFragment[] + + total: number + limit: number + start: number + } +} + +interface Variables { + start?: number + limit?: number +} + +const QUERY = gql` + query listForms($start: Int, $limit: Int) { + pager: listForms(start: $start, limit: $limit) { + entries { + ...PagerForm + } + total + limit + start + } + } + + ${FORM_PAGER_FRAGMENT} +` + +export const useFormPagerQuery = ( + options?: QueryHookOptions<Data, Variables> +): QueryResult<Data, Variables> => useQuery<Data, Variables>(QUERY, options) diff --git a/ui/graphql/query/form.public.query.ts b/ui/graphql/query/form.public.query.ts new file mode 100644 index 00000000..10580f74 --- /dev/null +++ b/ui/graphql/query/form.public.query.ts @@ -0,0 +1,25 @@ +import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client' +import { gql } from '@apollo/client/core' +import { FORM_PUBLIC_FRAGMENT, FormPublicFragment } from '../fragment/form.public.fragment' + +interface Data { + form: FormPublicFragment +} + +interface Variables { + id: string +} + +const QUERY = gql` + query getFormById($id: ID!) { + form: getFormById(id: $id) { + ...PublicForm + } + } + + ${FORM_PUBLIC_FRAGMENT} +` + +export const useFormPublicQuery = ( + options?: QueryHookOptions<Data, Variables> +): QueryResult<Data, Variables> => useQuery<Data, Variables>(QUERY, options) diff --git a/ui/graphql/query/form.query.ts b/ui/graphql/query/form.query.ts new file mode 100644 index 00000000..aa137451 --- /dev/null +++ b/ui/graphql/query/form.query.ts @@ -0,0 +1,25 @@ +import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client' +import { gql } from '@apollo/client/core' +import { FORM_FRAGMENT, FormFragment } from '../fragment/form.fragment' + +export interface Data { + form: FormFragment +} + +interface Variables { + id: string +} + +const QUERY = gql` + query getFormById($id: ID!) { + form: getFormById(id: $id) { + ...Form + } + } + + ${FORM_FRAGMENT} +` + +export const useFormQuery = ( + options?: QueryHookOptions<Data, Variables> +): QueryResult<Data, Variables> => useQuery<Data, Variables>(QUERY, options) diff --git a/ui/graphql/query/me.query.ts b/ui/graphql/query/me.query.ts new file mode 100644 index 00000000..9b02f40d --- /dev/null +++ b/ui/graphql/query/me.query.ts @@ -0,0 +1,23 @@ +import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client' +import { gql } from '@apollo/client/core' + +interface Data { + me: { + id: string + username: string + roles: string[] + } +} + +const QUERY = gql` + query me { + me { + id + roles + username + } + } +` + +export const useMeQuery = (options?: QueryHookOptions<Data, unknown>): QueryResult<Data, unknown> => + useQuery<Data, unknown>(QUERY, options) diff --git a/ui/graphql/query/settings.query.ts b/ui/graphql/query/settings.query.ts new file mode 100644 index 00000000..4679846d --- /dev/null +++ b/ui/graphql/query/settings.query.ts @@ -0,0 +1,32 @@ +import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client' +import { gql } from '@apollo/client/core' + +interface Data { + disabledSignUp: { + value: boolean + } + loginNote: { + value: string + } + hideContrib: { + value: string + } +} + +const QUERY = gql` + query settings { + disabledSignUp: getSetting(key: "SIGNUP_DISABLED") { + value: isTrue + } + loginNote: getSetting(key: "LOGIN_NOTE") { + value + } + hideContrib: getSetting(key: "HIDE_CONTRIB") { + value: isTrue + } + } +` + +export const useSettingsQuery = ( + options?: QueryHookOptions<Data, unknown> +): QueryResult<Data, unknown> => useQuery<Data, unknown>(QUERY, options) diff --git a/ui/graphql/query/status.query.ts b/ui/graphql/query/status.query.ts new file mode 100644 index 00000000..ebb8893c --- /dev/null +++ b/ui/graphql/query/status.query.ts @@ -0,0 +1,20 @@ +import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client' +import { gql } from '@apollo/client/core' + +interface Data { + status: { + version: string + } +} + +const QUERY = gql` + query status { + status { + version + } + } +` + +export const useStatusQuery = ( + options?: QueryHookOptions<Data, unknown> +): QueryResult<Data, unknown> => useQuery<Data, unknown>(QUERY, options) diff --git a/ui/graphql/query/submission.pager.query.ts b/ui/graphql/query/submission.pager.query.ts new file mode 100644 index 00000000..972f1608 --- /dev/null +++ b/ui/graphql/query/submission.pager.query.ts @@ -0,0 +1,53 @@ +import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client' +import { gql } from '@apollo/client/core' +import { useImperativeQuery } from '../../components/use.imerative.query' +import { FORM_PAGER_FRAGMENT, FormPagerFragment } from '../fragment/form.pager.fragment' +import { SUBMISSION_FRAGMENT, SubmissionFragment } from '../fragment/submission.fragment' + +interface Data { + pager: { + entries: SubmissionFragment[] + + total: number + limit: number + start: number + } + + form: FormPagerFragment +} + +interface Variables { + form: string + start?: number + limit?: number + filter?: { + finished?: boolean + excludeEmpty?: boolean + } +} + +const QUERY = gql` + query listSubmissions($form: ID!, $start: Int, $limit: Int, $filter: SubmissionPagerFilterInput) { + form: getFormById(id: $form) { + ...PagerForm + } + + pager: listSubmissions(form: $form, start: $start, limit: $limit, filter: $filter) { + entries { + ...Submission + } + total + limit + start + } + } + + ${SUBMISSION_FRAGMENT} + ${FORM_PAGER_FRAGMENT} +` + +export const useSubmissionPagerQuery = ( + options?: QueryHookOptions<Data, Variables> +): QueryResult<Data, Variables> => useQuery<Data, Variables>(QUERY, options) + +export const useSubmissionPagerImperativeQuery = () => useImperativeQuery<Data, Variables>(QUERY) diff --git a/ui/graphql/query/user.pager.query.ts b/ui/graphql/query/user.pager.query.ts new file mode 100644 index 00000000..be09fd71 --- /dev/null +++ b/ui/graphql/query/user.pager.query.ts @@ -0,0 +1,37 @@ +import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client' +import { gql } from '@apollo/client/core' +import { USER_PAGER_FRAGMENT, UserPagerFragment } from '../fragment/user.pager.fragment' + +interface Data { + pager: { + entries: UserPagerFragment[] + + total: number + limit: number + start: number + } +} + +interface Variables { + start?: number + limit?: number +} + +const QUERY = gql` + query listUsers($start: Int, $limit: Int) { + pager: listUsers(start: $start, limit: $limit) { + entries { + ...User + } + total + limit + start + } + } + + ${USER_PAGER_FRAGMENT} +` + +export const useUserPagerQuery = ( + options?: QueryHookOptions<Data, Variables> +): QueryResult<Data, Variables> => useQuery<Data, Variables>(QUERY, options) diff --git a/ui/i18n.ts b/ui/i18n.ts new file mode 100644 index 00000000..1dc3c32e --- /dev/null +++ b/ui/i18n.ts @@ -0,0 +1,20 @@ +import i18n from "i18next" +import detector from "i18next-browser-languagedetector" +import {initReactI18next} from "react-i18next" +import {resources} from './locales' + +export const languages = Object.keys(resources) + +i18n + .use(detector) + .use(initReactI18next) + .init({ + fallbackLng: 'en', + resources, + defaultNS: 'common', + react: { + useSuspense: process.browser, + transSupportBasicHtmlNodes: true, + transKeepBasicHtmlNodesFor: ['br', 'strong', 'i', 'em', 'u'], + } + }) diff --git a/ui/locales/ar/admin.json b/ui/locales/ar/admin.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/ui/locales/ar/admin.json @@ -0,0 +1 @@ +{} diff --git a/ui/locales/ar/common.json b/ui/locales/ar/common.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/ui/locales/ar/common.json @@ -0,0 +1 @@ +{} diff --git a/ui/locales/ar/form.json b/ui/locales/ar/form.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/ui/locales/ar/form.json @@ -0,0 +1 @@ +{} diff --git a/ui/locales/ar/index.ts b/ui/locales/ar/index.ts new file mode 100644 index 00000000..fc04e63b --- /dev/null +++ b/ui/locales/ar/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const ar = { + language, + admin, + common, + form, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/ar/language.json b/ui/locales/ar/language.json new file mode 100644 index 00000000..097daa3e --- /dev/null +++ b/ui/locales/ar/language.json @@ -0,0 +1,11 @@ +{ + "cn": "繁體中文", + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "pl": "Polski", + "pt": "Português", + "ru": "русский" +} diff --git a/ui/locales/ar/login.json b/ui/locales/ar/login.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/ui/locales/ar/login.json @@ -0,0 +1 @@ +{} diff --git a/ui/locales/ar/profile.json b/ui/locales/ar/profile.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/ui/locales/ar/profile.json @@ -0,0 +1 @@ +{} diff --git a/ui/locales/ar/register.json b/ui/locales/ar/register.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/ui/locales/ar/register.json @@ -0,0 +1 @@ +{} diff --git a/ui/locales/ar/statistic.json b/ui/locales/ar/statistic.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/ui/locales/ar/statistic.json @@ -0,0 +1 @@ +{} diff --git a/ui/locales/ar/submission.json b/ui/locales/ar/submission.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/ui/locales/ar/submission.json @@ -0,0 +1 @@ +{} diff --git a/ui/locales/ar/type.json b/ui/locales/ar/type.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/ui/locales/ar/type.json @@ -0,0 +1 @@ +{} diff --git a/ui/locales/ar/user.json b/ui/locales/ar/user.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/ui/locales/ar/user.json @@ -0,0 +1 @@ +{} diff --git a/ui/locales/ar/validation.json b/ui/locales/ar/validation.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/ui/locales/ar/validation.json @@ -0,0 +1 @@ +{} diff --git a/ui/locales/cn/admin.json b/ui/locales/cn/admin.json new file mode 100644 index 00000000..0bfdce17 --- /dev/null +++ b/ui/locales/cn/admin.json @@ -0,0 +1,9 @@ +{ + "administration": "管理", + "forms": "表单", + "home": "主页", + "profile": "个人资料", + "submissions": "提交", + "username": "用户名", + "users": "用户数" +} diff --git a/ui/locales/cn/common.json b/ui/locales/cn/common.json new file mode 100644 index 00000000..94c7957d --- /dev/null +++ b/ui/locales/cn/common.json @@ -0,0 +1,10 @@ +{ + "admin": "管理员", + "checkingCredentials": "检查凭证", + "loadingCredentials": "加载凭证", + "login": "登录", + "logout": "登出", + "profile": "个人资料", + "recover": "忘记密码", + "register": "创建帐号" +} diff --git a/ui/locales/cn/form.json b/ui/locales/cn/form.json new file mode 100644 index 00000000..e1cba586 --- /dev/null +++ b/ui/locales/cn/form.json @@ -0,0 +1,114 @@ +{ + "baseData": { + "isLive": "活着", + "language": "语言", + "showFooter": "显示页脚", + "title": "标题" + }, + "baseDataTab": "基础数据", + "building": "建筑形式", + "confirmDelete": "您确定删除所有提交的表格吗?", + "continue": "继续", + "create": "建立新表格", + "createNow": "救", + "created": "表格已建立", + "creationError": "无法建立表格", + "deleteError": "无法删除表格", + "deleteNow": "立即删除!", + "deleted": "表格已删除", + "design": { + "color": { + "answer": "答案颜色", + "background": "背景颜色", + "button": "按钮颜色", + "buttonActive": "按钮活动颜色", + "buttonText": "按钮文字颜色", + "question": "问题颜色" + }, + "font": "字形", + "layout": { + "card": "卡片", + "slider": "滑杆" + }, + "layouts": "布局" + }, + "designTab": "设计", + "endPage": { + "action": "行动", + "activeColor": "主动色", + "addButton": "添加按钮", + "bgColor": "背景颜色", + "buttons": "纽扣", + "color": "颜色", + "continueButtonText": "继续按钮文字", + "paragraph": "段", + "paragraphInfo": "使用markdown进行高级格式化", + "show": "显示", + "text": "文本", + "title": "标题", + "url": "网址" + }, + "endPageTab": "结束页", + "fieldsTab": "表格栏位", + "hooks": { + "add": "添加", + "confirmDelete": "空", + "deleteNow": "空", + "enabled": "已启用" + }, + "hooksTab": "WebHooks", + "loading": "加载表格", + "logic": { + "add": "添加逻辑" + }, + "mange": "编辑表单“ {{title}} ”", + "new": "新表格", + "next": "下一个", + "notifications": { + "add": "添加通知", + "enabled": "已启用", + "fromEmail": "发件人电子邮件", + "fromEmailInfo": "确保您的邮件服务器可以通过此电子邮件发送", + "fromField": "发件人电子邮件", + "fromFieldInfo": "带有电子邮件的字段,将设置Reply-To标头", + "htmlTemplate": "HTML模板", + "htmlTemplateInfo": "您还可以使用<u> MJML <\/u>创建电子邮件模板", + "subject": "学科", + "toEmail": "你的邮件", + "toEmailInfo": "如果未设置,将发送给表单管理员", + "toField": "电子邮件栏位", + "toFieldInfo": "带有电子邮件的收据字段" + }, + "notificationsTab": "通知", + "previous": "上一步", + "restart": "重新启动表格", + "row": { + "admin": "所有者", + "created": "已建立", + "isLive": "生活", + "language": "语言", + "lastModified": "最后修改", + "menu": "空", + "title": "标题" + }, + "startPage": { + "action": "行动", + "activeColor": "主动色", + "addButton": "添加按钮", + "bgColor": "背景颜色", + "buttons": "纽扣", + "color": "颜色", + "continueButtonText": "继续按钮文字", + "paragraph": "段", + "paragraphInfo": "使用markdown进行高级格式化", + "show": "显示", + "text": "文本", + "title": "标题", + "url": "网址" + }, + "startPageTab": "首页", + "submitted": "感谢您提交!", + "updateError": "无法更新表格", + "updateNow": "救", + "updated": "表格已更新" +} diff --git a/ui/locales/cn/index.ts b/ui/locales/cn/index.ts new file mode 100644 index 00000000..ebdf9469 --- /dev/null +++ b/ui/locales/cn/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const cn = { + admin, + common, + form, + language, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/cn/language.json b/ui/locales/cn/language.json new file mode 100644 index 00000000..5a599e83 --- /dev/null +++ b/ui/locales/cn/language.json @@ -0,0 +1,12 @@ +{ + "cn": "繁體中文", + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "ja": "空", + "pl": "Polski", + "pt": "Português", + "ru": "русский" +} diff --git a/ui/locales/cn/login.json b/ui/locales/cn/login.json new file mode 100644 index 00000000..d83b8fc9 --- /dev/null +++ b/ui/locales/cn/login.json @@ -0,0 +1,8 @@ +{ + "invalidLoginCredentials": "用户名\/密码无效", + "loginNow": "现在登录", + "note": "注意", + "passwordPlaceholder": "密码", + "usernamePlaceholder": "用户名", + "welcomeBack": "欢迎回来!" +} diff --git a/ui/locales/cn/profile.json b/ui/locales/cn/profile.json new file mode 100644 index 00000000..3ce71b15 --- /dev/null +++ b/ui/locales/cn/profile.json @@ -0,0 +1,12 @@ +{ + "confirmPassword": "确认密码", + "email": "电子邮件", + "firstName": "名字", + "language": "语言", + "lastName": "姓", + "password": "密码", + "updateError": "无法更新个人资料", + "updateNow": "保存", + "updated": "个人资料已更新", + "username": "用户名" +} diff --git a/ui/locales/cn/register.json b/ui/locales/cn/register.json new file mode 100644 index 00000000..53d1f243 --- /dev/null +++ b/ui/locales/cn/register.json @@ -0,0 +1,6 @@ +{ + "credentialsAlreadyInUse": "一些数据已在使用中!", + "gotoLogin": "已经注册?登陆", + "registerNow": "现在注册", + "welcome": "欢迎,也请确认您的电子邮件" +} diff --git a/ui/locales/cn/statistic.json b/ui/locales/cn/statistic.json new file mode 100644 index 00000000..186aaa3a --- /dev/null +++ b/ui/locales/cn/statistic.json @@ -0,0 +1,5 @@ +{ + "totalForms": "表格总数", + "totalSubmissions": "提交总数", + "totalUsers": "总用户" +} diff --git a/ui/locales/cn/submission.json b/ui/locales/cn/submission.json new file mode 100644 index 00000000..4a471cfb --- /dev/null +++ b/ui/locales/cn/submission.json @@ -0,0 +1,17 @@ +{ + "add": "添加提交", + "city": "市", + "country": "国家", + "created": "已建立", + "device": { + "name": "设备名称", + "type": "设备类型" + }, + "edit": "编辑", + "export": "导出", + "field": "栏位", + "lastModified": "最后一次变更", + "progress": "进展", + "submission": "提交", + "value": "值" +} diff --git a/ui/locales/cn/type.json b/ui/locales/cn/type.json new file mode 100644 index 00000000..526da6aa --- /dev/null +++ b/ui/locales/cn/type.json @@ -0,0 +1,76 @@ +{ + "add": "新增栏位", + "confirmDelete": "确定要删除此字段吗?请检查它在任何地方都没有被引用!", + "date": { + "default": "预设日期", + "max": "最长日期", + "min": "最小日期", + "name": "日期" + }, + "deleteNow": "删除栏位", + "description": "描述", + "descriptionInfo": "使用markdown进行高级格式化", + "dropdown": { + "addOption": "添加选项", + "default": "默认值", + "name": "落下", + "options": "选件", + "removeOption": "去掉", + "titlePlaceholder": "标题", + "valuePlaceholder": "值" + }, + "email": { + "default": "默认电子邮件", + "name": "电子邮件" + }, + "hidden": { + "default": "默认值", + "name": "隐" + }, + "link": { + "default": "默认链接", + "name": "网址" + }, + "number": { + "default": "默认号码", + "name": "数" + }, + "radio": { + "addOption": "添加选项", + "default": "默认值", + "name": "无线电开关", + "options": "选件", + "removeOption": "删除", + "titlePlaceholder": "标题", + "valuePlaceholder": "值" + }, + "rating": { + "clearNote": "再次单击以删除默认值", + "default": "默认值", + "name": "评分" + }, + "required": "需要", + "requiredInfo": "如果需要,必须设置默认值以使用户能够提交表单!", + "slider": { + "default": "默认值", + "max": "最大值", + "min": "最小值", + "name": "滑杆", + "step": "每步大小" + }, + "slug": "Slug", + "slugInfo": "使用slug传递默认动态作为url get参数slug = value", + "textarea": { + "default": "默认值", + "name": "文字区" + }, + "textfield": { + "default": "默认值", + "name": "文字行" + }, + "title": "标题", + "yes_no": { + "default": "默认值", + "name": "是\/否" + } +} diff --git a/ui/locales/cn/user.json b/ui/locales/cn/user.json new file mode 100644 index 00000000..86e49876 --- /dev/null +++ b/ui/locales/cn/user.json @@ -0,0 +1,18 @@ +{ + "baseData": "基础数据", + "confirmDelete": "您确定要删除该用户吗?", + "deleteError": "无法删除用户", + "deleteNow": "立即删除!", + "deleted": "用户已删除", + "loading": "正在加载用户", + "mange": "编辑用户“ {{email}} ”", + "row": { + "created": "已建立", + "email": "电子邮件", + "menu": "空", + "roles": "角色" + }, + "updateError": "无法更新用户", + "updateNow": "救", + "updated": "用户已更新" +} diff --git a/ui/locales/cn/validation.json b/ui/locales/cn/validation.json new file mode 100644 index 00000000..2bf44925 --- /dev/null +++ b/ui/locales/cn/validation.json @@ -0,0 +1,20 @@ +{ + "emailFieldRequired": "请选择一个电子邮件字段", + "emailRequired": "请提供电子邮件", + "invalidEmail": "必须是有效的电子邮件!", + "invalidNumber": "必须是一个有效的数字!", + "invalidSlug": "Slug只能包含小写字母az,0-9和下划线", + "invalidUrl": "必须是有效的网址", + "languageRequired": "请选择一种语言", + "mandatoryFieldsMissing": "必填字段缺失", + "passwordConfirmMismatch": "您输入的两个密码不匹配!", + "passwordConfirmRequired": "请确认您的密码!", + "passwordMinLength": "必须大于或等于5个字符!", + "passwordRequired": "请输入您的密码!", + "subjectRequired": "请提供一个主题", + "templateRequired": "请提供模板", + "titleRequired": "请提供标题", + "urlRequired": "请提供一个链接", + "usernameRequired": "请提供一个用户名", + "valueRequired": "请提供一个值" +} diff --git a/ui/locales/da/admin.json b/ui/locales/da/admin.json new file mode 100644 index 00000000..eff103bb --- /dev/null +++ b/ui/locales/da/admin.json @@ -0,0 +1,3 @@ +{ + "administration": "Administration" +} diff --git a/ui/locales/da/common.json b/ui/locales/da/common.json new file mode 100644 index 00000000..f91a9a05 --- /dev/null +++ b/ui/locales/da/common.json @@ -0,0 +1,5 @@ +{ + "profile": "Profil", + "recover": "Mistet adgangskode", + "register": "Opret konto" +} diff --git a/ui/locales/da/form.json b/ui/locales/da/form.json new file mode 100644 index 00000000..a574f19b --- /dev/null +++ b/ui/locales/da/form.json @@ -0,0 +1,46 @@ +{ + "continue": "Fortsæt", + "design": { + "layout": { + "card": "Kort" + } + }, + "fieldsTab": "Formularfelter", + "hooks": { + "add": "Tilføj", + "confirmDelete": "Tom", + "deleteNow": "Tom", + "enabled": "Aktiveret" + }, + "hooksTab": "WebHooks", + "logic": { + "add": "Tilføj logik" + }, + "next": "Næste", + "notifications": { + "add": "Tilføj meddelelse", + "htmlTemplate": "HTML-skabelon", + "subject": "Emne" + }, + "notificationsTab": "Meddelelser", + "previous": "Forrige", + "startPage": { + "action": "Handling", + "activeColor": "Aktiv farve", + "addButton": "Tilføj-knappen", + "bgColor": "Baggrundsfarve", + "buttons": "Knapper", + "color": "Farve", + "continueButtonText": "Tekst på fortsæt-knappen", + "paragraph": "Afsnit", + "show": "Vis", + "text": "Tekst", + "title": "Titel", + "url": "URL" + }, + "startPageTab": "Startside", + "submitted": "Tak for din indsendelse!", + "updateError": "Var ikke i stand til at opdatere formularen", + "updateNow": "Gem", + "updated": "Formular opdateret" +} diff --git a/ui/locales/da/index.ts b/ui/locales/da/index.ts new file mode 100644 index 00000000..bcf0255e --- /dev/null +++ b/ui/locales/da/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const da = { + language, + admin, + common, + form, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/da/language.json b/ui/locales/da/language.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/ui/locales/da/language.json @@ -0,0 +1 @@ +{} diff --git a/ui/locales/da/login.json b/ui/locales/da/login.json new file mode 100644 index 00000000..a4512933 --- /dev/null +++ b/ui/locales/da/login.json @@ -0,0 +1,5 @@ +{ + "note": "Bemærk", + "passwordPlaceholder": "Adgangskode", + "usernamePlaceholder": "Brugernavn" +} diff --git a/ui/locales/da/profile.json b/ui/locales/da/profile.json new file mode 100644 index 00000000..6b9d109c --- /dev/null +++ b/ui/locales/da/profile.json @@ -0,0 +1,10 @@ +{ + "confirmPassword": "Bekræft kodeord", + "email": "E-mail", + "firstName": "Fornavn", + "language": "Sprog", + "lastName": "Efternavn", + "password": "Adgangskode", + "updated": "Profil opdateret", + "username": "Brugernavn" +} diff --git a/ui/locales/da/register.json b/ui/locales/da/register.json new file mode 100644 index 00000000..d4aa7365 --- /dev/null +++ b/ui/locales/da/register.json @@ -0,0 +1,5 @@ +{ + "credentialsAlreadyInUse": "Nogle data er allerede i brug!", + "gotoLogin": "Har du en konto? Gå til login", + "welcome": "Velkommen, bekræft venligst også din e-mail" +} diff --git a/ui/locales/da/statistic.json b/ui/locales/da/statistic.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/ui/locales/da/statistic.json @@ -0,0 +1 @@ +{} diff --git a/ui/locales/da/submission.json b/ui/locales/da/submission.json new file mode 100644 index 00000000..7eb91c82 --- /dev/null +++ b/ui/locales/da/submission.json @@ -0,0 +1,11 @@ +{ + "add": "Tilføj indsendelse", + "city": "By", + "country": "Land", + "created": "Oprettet", + "edit": "Redigere", + "lastModified": "Sidste ændring", + "progress": "Fremskridt", + "submission": "Indsendelse", + "value": "Værdi" +} diff --git a/ui/locales/da/type.json b/ui/locales/da/type.json new file mode 100644 index 00000000..9ff69802 --- /dev/null +++ b/ui/locales/da/type.json @@ -0,0 +1,15 @@ +{ + "add": "Tilføj felt", + "confirmDelete": "Er du sikker på, at du ønsker at slette dette felt? Undersøg evt. om feltet er refereret til fra noget sted.", + "date": { + "default": "Standarddato", + "max": "Maksimumsdato", + "min": "Minimumsdato", + "name": "Dato" + }, + "deleteNow": "Slet felt", + "description": "Beskrivelse", + "slider": { + "default": "Standardværdi" + } +} diff --git a/ui/locales/da/user.json b/ui/locales/da/user.json new file mode 100644 index 00000000..f303b8fa --- /dev/null +++ b/ui/locales/da/user.json @@ -0,0 +1,15 @@ +{ + "confirmDelete": "Er du sikker på at du ønsker at slette denne bruger?", + "deleteError": "Var ikke i stand til at opdatere brugeren", + "deleteNow": "Slet nu!", + "deleted": "Bruger slettet", + "loading": "Indlæser bruger", + "mange": "Rediger bruger \"{{email}}\"", + "row": { + "created": "Oprettet", + "menu": "Tom" + }, + "updateError": "Var ikke i stand til at opdatere brugeren", + "updateNow": "Gem", + "updated": "Bruger opdateret" +} diff --git a/ui/locales/da/validation.json b/ui/locales/da/validation.json new file mode 100644 index 00000000..e171d9cb --- /dev/null +++ b/ui/locales/da/validation.json @@ -0,0 +1,19 @@ +{ + "emailFieldRequired": "Vælg venligst et e-mail-felt", + "emailRequired": "Angiv venligst en e-mail", + "invalidEmail": "Skal være en gyldig e-mail!", + "invalidNumber": "Skal være et gyldigt nummer!", + "invalidSlug": "Slug må kun indeholde små bogstaver fra a-z, 0-9 og _", + "invalidUrl": "Skal være en gyldig URL", + "languageRequired": "Vælg venligst et sprog", + "mandatoryFieldsMissing": "Obligatoriske felter mangler", + "passwordConfirmRequired": "Bekræft venligst din adgangskode!", + "passwordMinLength": "Skal være længere end eller lig med 5 tegn!", + "passwordRequired": "Indtast venligst din adgangskode!", + "subjectRequired": "Angiv venligst et emne", + "templateRequired": "Angiv venligst en skabelon", + "titleRequired": "Angiv venligst en titel", + "urlRequired": "Angiv venligst en URL", + "usernameRequired": "Angiv venligst et brugernavn", + "valueRequired": "Angiv venligst en værdi" +} diff --git a/ui/locales/de/admin.json b/ui/locales/de/admin.json new file mode 100644 index 00000000..7837acbd --- /dev/null +++ b/ui/locales/de/admin.json @@ -0,0 +1,9 @@ +{ + "administration": "Verwaltung", + "forms": "Formulare", + "home": "Home", + "profile": "Profil", + "submissions": "Eingaben", + "username": "Benutzername", + "users": "Benutzer" +} diff --git a/ui/locales/de/common.json b/ui/locales/de/common.json new file mode 100644 index 00000000..7f94c1d5 --- /dev/null +++ b/ui/locales/de/common.json @@ -0,0 +1,10 @@ +{ + "admin": "Administration", + "checkingCredentials": "Zugangsdaten werden geprüft", + "loadingCredentials": "Lade Zugangsdaten", + "login": "Anmelden", + "logout": "Abmelden", + "profile": "Profil", + "recover": "Passwort vergessen", + "register": "Benutzer erstellen" +} diff --git a/ui/locales/de/form.json b/ui/locales/de/form.json new file mode 100644 index 00000000..f27d52fd --- /dev/null +++ b/ui/locales/de/form.json @@ -0,0 +1,114 @@ +{ + "baseData": { + "isLive": "Öffentlich", + "language": "Sprache", + "showFooter": "Fußzeile anzeigen", + "title": "Titel" + }, + "baseDataTab": "Basisdaten", + "building": "Formular wird aufgebaut", + "confirmDelete": "Wollen Sie dieses Formular mit allen Einträgen löschen?", + "continue": "Fortsetzen", + "create": "Neues Formular erstellen", + "createNow": "Speichern", + "created": "Formular erstellt", + "creationError": "Formular konnte nicht erstellt werden", + "deleteError": "Formular konnte nicht gelöscht werden", + "deleteNow": "Jetzt löschen!", + "deleted": "Formular gelöscht", + "design": { + "color": { + "answer": "Antwortfarbe", + "background": "Hintergrundfarbe", + "button": "Farbe der Schaltfläche", + "buttonActive": "Farbe der aktiven Schaltfläche", + "buttonText": "Farbe des Schaltflächentextes", + "question": "Fragenfarbe" + }, + "font": "Schriftart", + "layout": { + "card": "Karte", + "slider": "Schieberegler" + }, + "layouts": "Layout" + }, + "designTab": "Design", + "endPage": { + "action": "Aktion", + "activeColor": "Aktive Farbe", + "addButton": "Aktion hinzufügen", + "bgColor": "Hintergrundfarbe", + "buttons": "Aktionen", + "color": "Textfarbe", + "continueButtonText": "Text der Schaltfläche Weiter", + "paragraph": "Absatz", + "paragraphInfo": "Verwenden Sie Markdown für erweiterte Formatierung", + "show": "Anzeigen", + "text": "Text", + "title": "Titel", + "url": "URL" + }, + "endPageTab": "Endseite", + "fieldsTab": "Formularfelder", + "hooks": { + "add": "Hinzufügen", + "confirmDelete": "Wollen Sie diesen Webhook wirklich löschen?", + "deleteNow": "Nun löschen", + "enabled": "Aktiv" + }, + "hooksTab": "Webhooks", + "loading": "Formular wird geladen", + "logic": { + "add": "Logik hinzufügen" + }, + "mange": "Formular \"{{title}}\" bearbeiten", + "new": "Neues Formular", + "next": "Nächste", + "notifications": { + "add": "Benachrichtigung hinzufügen", + "enabled": "Aktiv", + "fromEmail": "Absender-E-Mail", + "fromEmailInfo": "Stellen Sie sicher, dass Ihr Mailserver von dieser E-Mail senden kann", + "fromField": "Absender-E-Mail", + "fromFieldInfo": "Feld mit E-Mail, setzt den Reply-To-Header", + "htmlTemplate": "HTML-Vorlage", + "htmlTemplateInfo": "Sie können auch <u>MJML<\/u> verwenden, um Ihre E-Mail-Vorlagen zu erstellen", + "subject": "Betreff", + "toEmail": "Ihre E-Mail", + "toEmailInfo": "Als Standard wird die E-Mail des Administrators verwendet", + "toField": "E-Mail-Feld", + "toFieldInfo": "Feld mit E-Mail für den Empfang" + }, + "notificationsTab": "Benachrichtigungen", + "previous": "Vorherige", + "restart": "Formular neu starten", + "row": { + "admin": "Verwalter", + "created": "Erstellt", + "isLive": "Öffentlich", + "language": "Sprache", + "lastModified": "Letzte Änderung", + "menu": "Aktionen", + "title": "Titel" + }, + "startPage": { + "action": "Aktion", + "activeColor": "Aktive Farbe", + "addButton": "Aktion hinzufügen", + "bgColor": "Hintergrundfarbe", + "buttons": "Aktionen", + "color": "Textfarbe", + "continueButtonText": "Text der Schaltfläche Weiter", + "paragraph": "Absatz", + "paragraphInfo": "Verwenden Sie Markdown für erweiterte Formatierung", + "show": "Anzeigen", + "text": "Text", + "title": "Titel", + "url": "URL" + }, + "startPageTab": "Startseite", + "submitted": "Vielen Dank für Ihre Eingaben!", + "updateError": "Formular konnte nicht aktualisiert werden", + "updateNow": "Speichern", + "updated": "Formular aktualisiert" +} diff --git a/ui/locales/de/index.ts b/ui/locales/de/index.ts new file mode 100644 index 00000000..87019264 --- /dev/null +++ b/ui/locales/de/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const de = { + admin, + common, + form, + language, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/de/language.json b/ui/locales/de/language.json new file mode 100644 index 00000000..75435f85 --- /dev/null +++ b/ui/locales/de/language.json @@ -0,0 +1,12 @@ +{ + "cn": "繁體中文", + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "ja": "ja", + "pl": "Polski", + "pt": "Português", + "ru": "русский" +} diff --git a/ui/locales/de/login.json b/ui/locales/de/login.json new file mode 100644 index 00000000..13e68e62 --- /dev/null +++ b/ui/locales/de/login.json @@ -0,0 +1,8 @@ +{ + "invalidLoginCredentials": "Benutzername und\/oder Passwort sind falsch", + "loginNow": "Jetzt anmelden", + "note": "Hinweis", + "passwordPlaceholder": "Passwort", + "usernamePlaceholder": "Benutzername", + "welcomeBack": "Willkommen zurück!" +} diff --git a/ui/locales/de/profile.json b/ui/locales/de/profile.json new file mode 100644 index 00000000..af64a631 --- /dev/null +++ b/ui/locales/de/profile.json @@ -0,0 +1,12 @@ +{ + "confirmPassword": "Passwort bestätigen", + "email": "E-Mail", + "firstName": "Vorname", + "language": "Sprache", + "lastName": "Nachname", + "password": "Passwort", + "updateError": "Profil konnte nicht aktualisiert werden", + "updateNow": "Speichern", + "updated": "Profil aktualisieren", + "username": "Benutzername" +} diff --git a/ui/locales/de/register.json b/ui/locales/de/register.json new file mode 100644 index 00000000..535b2f2e --- /dev/null +++ b/ui/locales/de/register.json @@ -0,0 +1,6 @@ +{ + "credentialsAlreadyInUse": "Einige Daten werden bereits verwendet!", + "gotoLogin": "Sie haben schon einen Account? Weiter zur Anmeldung", + "registerNow": "Jetzt registrieren", + "welcome": "Willkommen, bitte bestätige noch deine E-Mail" +} diff --git a/ui/locales/de/statistic.json b/ui/locales/de/statistic.json new file mode 100644 index 00000000..832061e6 --- /dev/null +++ b/ui/locales/de/statistic.json @@ -0,0 +1,5 @@ +{ + "totalForms": "Anzahl der Formulare", + "totalSubmissions": "Anzahl der Eingaben", + "totalUsers": "Anzahl der Benutzer" +} diff --git a/ui/locales/de/submission.json b/ui/locales/de/submission.json new file mode 100644 index 00000000..d757fa37 --- /dev/null +++ b/ui/locales/de/submission.json @@ -0,0 +1,17 @@ +{ + "add": "Neue Eingabe starten", + "city": "Stadt", + "country": "Land", + "created": "Erstellt", + "device": { + "name": "Gerätename", + "type": "Gerätetyp" + }, + "edit": "Formular bearbeiten", + "export": "Exportieren", + "field": "Feld", + "lastModified": "Letzte Änderung", + "progress": "Fortschritt", + "submission": "Eingabe", + "value": "Wert" +} diff --git a/ui/locales/de/type.json b/ui/locales/de/type.json new file mode 100644 index 00000000..61755fcd --- /dev/null +++ b/ui/locales/de/type.json @@ -0,0 +1,76 @@ +{ + "add": "Feld hinzufügen", + "confirmDelete": "Wollen Sie das Feld wirklich löschen? Bitte achten Sie darauf, dass es keine Referenzen mehr auf dieses Feld gibt!", + "date": { + "default": "Standarddatum", + "max": "Neustes mögliches Datum", + "min": "Ältestes mögliches Datum", + "name": "Datum" + }, + "deleteNow": "Feld löschen", + "description": "Beschreibung", + "descriptionInfo": "Verwenden Sie Markdown für erweiterte Formatierung", + "dropdown": { + "addOption": "Auswahl hinzufügen", + "default": "Standardwert", + "name": "Dropdown-Liste", + "options": "Auswahl", + "removeOption": "Entfernen", + "titlePlaceholder": "Titel", + "valuePlaceholder": "Wert" + }, + "email": { + "default": "Standard-E-Mail", + "name": "E-Mail" + }, + "hidden": { + "default": "Standardwert", + "name": "Versteckt" + }, + "link": { + "default": "Standard-URL", + "name": "URL" + }, + "number": { + "default": "Standardzahl", + "name": "Zahl" + }, + "radio": { + "addOption": "Auswahl hinzufügen", + "default": "Standardwert", + "name": "Auswahlliste", + "options": "Auswahl", + "removeOption": "Entfernen", + "titlePlaceholder": "Titel", + "valuePlaceholder": "Wert" + }, + "rating": { + "clearNote": "Klicken Sie erneut, um den Standardwert zu entfernen", + "default": "Standardbewertung", + "name": "Bewertung" + }, + "required": "Pflichtfeld", + "requiredInfo": "Bei Bedarf muss der Standardwert festgelegt werden, damit Benutzer ein Formular senden können!", + "slider": { + "default": "Standardwert", + "max": "Maximalwert", + "min": "Minimalwert", + "name": "Schieberegler", + "step": "Schrittweite" + }, + "slug": "Schnecke", + "slugInfo": "Verwenden Sie slug, um die Standard-Dynamik als URL-Parameter \"?slug=value\" zu übergeben", + "textarea": { + "default": "Standardwert", + "name": "Mehrzeiliger Text" + }, + "textfield": { + "default": "Standardwert", + "name": "Einzeiliger Text" + }, + "title": "Titel", + "yes_no": { + "default": "Standardwert", + "name": "Ja \/ Nein" + } +} diff --git a/ui/locales/de/user.json b/ui/locales/de/user.json new file mode 100644 index 00000000..42cd4e28 --- /dev/null +++ b/ui/locales/de/user.json @@ -0,0 +1,18 @@ +{ + "baseData": "Basisdaten", + "confirmDelete": "Wollen sie diesen Benutzer wirklich löschen?", + "deleteError": "Benutzer konnte nicht gelöscht werden", + "deleteNow": "Jetzt löschen!", + "deleted": "Benutzer gelöscht", + "loading": "Benutzer wird geladen", + "mange": "Benutzer \"{{email}}\" bearbeiten", + "row": { + "created": "Erstellt", + "email": "E-Mail", + "menu": "Aktionen", + "roles": "Rolle" + }, + "updateError": "Konnte Benutzer nicht aktualisieren", + "updateNow": "Speichern", + "updated": "Benutzer aktualisiert" +} diff --git a/ui/locales/de/validation.json b/ui/locales/de/validation.json new file mode 100644 index 00000000..b206d676 --- /dev/null +++ b/ui/locales/de/validation.json @@ -0,0 +1,20 @@ +{ + "emailFieldRequired": "Bitte ein E-Mail Feld auswählen", + "emailRequired": "Bitte eine E-Mail angeben", + "invalidEmail": "Muss eine gültige E-Mail sein!", + "invalidNumber": "Muss eine gültige Zahl sein!", + "invalidSlug": "Kann nur Kleinbuchstaben a–z, 0–9 und _ enthalten", + "invalidUrl": "Muss eine gültige URL sein", + "languageRequired": "Bitte eine Sprache angeben", + "mandatoryFieldsMissing": "Es fehlen Pflichtfelder", + "passwordConfirmMismatch": "Die beiden eingegebenen Passwörter stimmen nicht überein!", + "passwordConfirmRequired": "Bitte bestätigen Sie Ihr Passwort!", + "passwordMinLength": "Passwort muss mindestens 5 Zeichen haben!", + "passwordRequired": "Bitte ein Passwort angeben", + "subjectRequired": "Bitte einen Betreff angeben", + "templateRequired": "Bitte eine Vorlage angeben", + "titleRequired": "Bitte einen Titel angeben", + "urlRequired": "Bitte eine URL angeben", + "usernameRequired": "Bitte einen Benutzernamen angeben", + "valueRequired": "Bitte einen Wert angeben" +} diff --git a/ui/locales/en/admin.json b/ui/locales/en/admin.json new file mode 100644 index 00000000..2ad91ada --- /dev/null +++ b/ui/locales/en/admin.json @@ -0,0 +1,9 @@ +{ + "administration": "Administration", + "forms": "Forms", + "home": "Home", + "profile": "Profile", + "submissions": "Submissions", + "username": "Username", + "users": "Users" +} diff --git a/ui/locales/en/common.json b/ui/locales/en/common.json new file mode 100644 index 00000000..9b5fe44e --- /dev/null +++ b/ui/locales/en/common.json @@ -0,0 +1,10 @@ +{ + "admin": "Admin", + "checkingCredentials": "Checking Credentials", + "loadingCredentials": "Loading Credentials", + "login": "Login", + "logout": "Logout", + "profile": "Profile", + "recover": "Lost Password", + "register": "Create Account" +} diff --git a/ui/locales/en/form.json b/ui/locales/en/form.json new file mode 100644 index 00000000..a856acec --- /dev/null +++ b/ui/locales/en/form.json @@ -0,0 +1,117 @@ +{ + "baseData": { + "isLive": "Is Live", + "language": "Language", + "showFooter": "Show Footer", + "title": "Title" + }, + "baseDataTab": "Base Data", + "building": "Building Form", + "confirmDelete": "Do you really want to delete this form with all submissions?", + "continue": "Continue", + "create": "Create new form", + "createNow": "Save", + "created": "Form Created", + "creationError": "Could not create form", + "deleteError": "Could not delete form", + "deleteNow": "Delete Now!", + "deleted": "Form deleted", + "design": { + "color": { + "answer": "Answer Color", + "background": "Background Color", + "button": "Button Color", + "buttonActive": "Button Active Color", + "buttonText": "Button Text Color", + "question": "Question Color" + }, + "font": "Font", + "layout": { + "card": "Card", + "slider": "Slider" + }, + "layouts": "Layout" + }, + "designTab": "Design", + "endPage": { + "action": "Action", + "activeColor": "Active Color", + "addButton": "Add Button", + "bgColor": "Background Color", + "buttons": "Buttons", + "color": "Color", + "continueButtonText": "Continue Button Text", + "paragraph": "Paragraph", + "paragraphInfo": "Use markdown for advanced formatting", + "show": "Show", + "text": "Text", + "title": "Title", + "url": "Url" + }, + "endPageTab": "End Page", + "fieldsTab": "Form Fields", + "hooks": { + "add": "Add", + "enabled": "Enabled" + }, + "hooksTab": "WebHooks", + "loading": "Loading Form", + "logic": { + "action": { + "disable": "Disable", + "jumpTo": "Jump To", + "require": "Require", + "visible": "Visible" + }, + "add": "Add Logic" + }, + "mange": "Edit Form \"{{title}}\"", + "new": "New Form", + "next": "Next", + "notifications": { + "add": "Add Notification", + "enabled": "Enabled", + "fromEmail": "Sender Email", + "fromEmailInfo": "Make sure your mailserver can send from this email", + "fromField": "Sender Email", + "fromFieldInfo": "Field with Email, will set the Reply-To header", + "htmlTemplate": "HTML Template", + "htmlTemplateInfo": "You can also use <u>MJML<\/u> to create your email templates", + "subject": "Subject", + "toEmail": "Your Email", + "toEmailInfo": "If not set will send to the admin of the form", + "toField": "Email Field", + "toFieldInfo": "Field with Email for receipt" + }, + "notificationsTab": "Notifications", + "previous": "Previous", + "restart": "Restart Form", + "row": { + "admin": "Owner", + "created": "Created", + "isLive": "Live", + "language": "Language", + "lastModified": "Last Modified", + "title": "Title" + }, + "startPage": { + "action": "Action", + "activeColor": "Active Color", + "addButton": "Add Button", + "bgColor": "Background Color", + "buttons": "Buttons", + "color": "Color", + "continueButtonText": "Continue Button Text", + "paragraph": "Paragraph", + "paragraphInfo": "Use markdown for advanced formatting", + "show": "Show", + "text": "Text", + "title": "Title", + "url": "Url" + }, + "startPageTab": "Start Page", + "submitted": "Thank you for your submission!", + "updateError": "Could not update form", + "updateNow": "Save", + "updated": "Form updated" +} diff --git a/ui/locales/en/index.ts b/ui/locales/en/index.ts new file mode 100644 index 00000000..2b62c154 --- /dev/null +++ b/ui/locales/en/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const en = { + admin, + common, + form, + language, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/en/language.json b/ui/locales/en/language.json new file mode 100644 index 00000000..097daa3e --- /dev/null +++ b/ui/locales/en/language.json @@ -0,0 +1,11 @@ +{ + "cn": "繁體中文", + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "pl": "Polski", + "pt": "Português", + "ru": "русский" +} diff --git a/ui/locales/en/login.json b/ui/locales/en/login.json new file mode 100644 index 00000000..f2c4df64 --- /dev/null +++ b/ui/locales/en/login.json @@ -0,0 +1,8 @@ +{ + "invalidLoginCredentials": "username \/ password are invalid", + "loginNow": "Login Now", + "note": "Note", + "passwordPlaceholder": "Password", + "usernamePlaceholder": "Username", + "welcomeBack": "Welcome back!" +} diff --git a/ui/locales/en/profile.json b/ui/locales/en/profile.json new file mode 100644 index 00000000..23a68628 --- /dev/null +++ b/ui/locales/en/profile.json @@ -0,0 +1,12 @@ +{ + "confirmPassword": "Confirm Password", + "email": "Email", + "firstName": "First Name", + "language": "Language", + "lastName": "Last Name", + "password": "Password", + "updateError": "Could not update Profile", + "updateNow": "Save", + "updated": "Profile updated", + "username": "Username" +} diff --git a/ui/locales/en/register.json b/ui/locales/en/register.json new file mode 100644 index 00000000..8381b4f0 --- /dev/null +++ b/ui/locales/en/register.json @@ -0,0 +1,6 @@ +{ + "credentialsAlreadyInUse": "Some data already in use!", + "gotoLogin": "Have an account? Go to login", + "registerNow": "Register Now", + "welcome": "Welcome, please also confirm your email" +} diff --git a/ui/locales/en/statistic.json b/ui/locales/en/statistic.json new file mode 100644 index 00000000..97643c68 --- /dev/null +++ b/ui/locales/en/statistic.json @@ -0,0 +1,5 @@ +{ + "totalForms": "Total Forms", + "totalSubmissions": "Total Submissions", + "totalUsers": "Total Users" +} diff --git a/ui/locales/en/submission.json b/ui/locales/en/submission.json new file mode 100644 index 00000000..75a25c80 --- /dev/null +++ b/ui/locales/en/submission.json @@ -0,0 +1,17 @@ +{ + "add": "Add Submission", + "city": "City", + "country": "Country", + "created": "Created", + "device": { + "name": "Device Name", + "type": "Device Type" + }, + "edit": "Edit", + "export": "Export", + "field": "Field", + "lastModified": "Last Change", + "progress": "Progress", + "submission": "Submission", + "value": "Value" +} diff --git a/ui/locales/en/type.json b/ui/locales/en/type.json new file mode 100644 index 00000000..3db45d6d --- /dev/null +++ b/ui/locales/en/type.json @@ -0,0 +1,87 @@ +{ + "add": "Add Field", + "confirmDelete": "Really remove this field? Check that it is not referenced anywhere!", + "checkbox": { + "addOption": "Add Checkbox", + "default": "Default Value", + "name": "Checkbox", + "options": "Checkboxes", + "removeOption": "Remove" + }, + "date": { + "default": "Default Date", + "max": "Max Date", + "min": "Min Date", + "name": "Date" + }, + "deleteNow": "Delete Field", + "description": "Description", + "descriptionInfo": "Use markdown for advanced formatting", + "dropdown": { + "addOption": "Add Option", + "default": "Default Value", + "name": "Dropdown", + "options": "Options", + "removeOption": "Remove", + "titlePlaceholder": "Title", + "valuePlaceholder": "Value" + }, + "email": { + "default": "Default Email", + "name": "Email" + }, + "hidden": { + "default": "Default Value", + "name": "Hidden" + }, + "link": { + "default": "Default Link", + "name": "URL" + }, + "location": { + "name": "Map Location", + "default": "Default Location" + }, + "number": { + "default": "Default Number", + "name": "Number" + }, + "radio": { + "addOption": "Add Option", + "default": "Default Value", + "name": "Radio Switch", + "options": "Options", + "removeOption": "Remove", + "titlePlaceholder": "Title", + "valuePlaceholder": "Value" + }, + "rating": { + "clearNote": "Click again to remove the default value", + "default": "Default Value", + "name": "Rating" + }, + "required": "Required", + "requiredInfo": "If required, default value must be set to enable users to submit form!", + "slider": { + "default": "Default Value", + "max": "Max Value", + "min": "Min Value", + "name": "Slider", + "step": "Step Size" + }, + "slug": "Slug", + "slugInfo": "Use slug to pass the default dynamic as url parameter ?slug=value", + "textarea": { + "default": "Default Value", + "name": "Text Area" + }, + "textfield": { + "default": "Default Value", + "name": "Text Line" + }, + "title": "Title", + "yes_no": { + "default": "Default Value", + "name": "Yes \/ No" + } +} diff --git a/ui/locales/en/user.json b/ui/locales/en/user.json new file mode 100644 index 00000000..dcebd9aa --- /dev/null +++ b/ui/locales/en/user.json @@ -0,0 +1,17 @@ +{ + "baseData": "Base Data", + "confirmDelete": "Are you sure delete this user?", + "deleteError": "could not delete user", + "deleteNow": "Delete Now!", + "deleted": "User deleted", + "loading": "Loading User", + "mange": "Edit User \"{{email}}\"", + "row": { + "created": "Created", + "email": "Email", + "roles": "Role" + }, + "updateError": "Could not update user", + "updateNow": "Save", + "updated": "User updated" +} diff --git a/ui/locales/en/validation.json b/ui/locales/en/validation.json new file mode 100644 index 00000000..eb3e8112 --- /dev/null +++ b/ui/locales/en/validation.json @@ -0,0 +1,20 @@ +{ + "emailFieldRequired": "Please select an Email Field", + "emailRequired": "Please provide an Email", + "invalidEmail": "Must be a valid email!", + "invalidNumber": "Must be a valid number!", + "invalidSlug": "Slug can only contain lowercase a-z, 0-9 and _", + "invalidUrl": "Must be a valid URL", + "languageRequired": "Please select a Language", + "mandatoryFieldsMissing": "Mandatory fields missing", + "passwordConfirmMismatch": "The two passwords that you entered do not match!", + "passwordConfirmRequired": "Please confirm your password!", + "passwordMinLength": "Must be longer than or equal to 5 characters!", + "passwordRequired": "Please input your password!", + "subjectRequired": "Please provide a subject", + "templateRequired": "Please provide a template", + "titleRequired": "Please provide a title", + "urlRequired": "Please provide a Url", + "usernameRequired": "Please provide a Username", + "valueRequired": "Please provide a Value" +} diff --git a/ui/locales/es/admin.json b/ui/locales/es/admin.json new file mode 100644 index 00000000..6bf5c978 --- /dev/null +++ b/ui/locales/es/admin.json @@ -0,0 +1,9 @@ +{ + "administration": "Administración", + "forms": "Formularios", + "home": "Inicio", + "profile": "Perfil", + "submissions": "Envíos", + "username": "Nombre de usuario", + "users": "Usuarios" +} diff --git a/ui/locales/es/common.json b/ui/locales/es/common.json new file mode 100644 index 00000000..f716eecf --- /dev/null +++ b/ui/locales/es/common.json @@ -0,0 +1,9 @@ +{ + "admin": "Administración", + "checkingCredentials": "Verificación de credenciales", + "loadingCredentials": "Cargando credenciales", + "login": "Iniciar sesión", + "logout": "Cerrar sesión", + "recover": "Recuperar contraseña", + "register": "Crear una cuenta" +} diff --git a/ui/locales/es/form.json b/ui/locales/es/form.json new file mode 100644 index 00000000..49659488 --- /dev/null +++ b/ui/locales/es/form.json @@ -0,0 +1,100 @@ +{ + "baseData": { + "isLive": "Es en vivo", + "language": "Idioma", + "showFooter": "Mostrar pie de página", + "title": "Título" + }, + "baseDataTab": "Datos Generales", + "building": "Formulario de construcción", + "confirmDelete": "¿Estás seguro de eliminar este formulario con todos los envíos?", + "create": "Crear nuevo formulario", + "createNow": "Guardar", + "created": "Formulario creado", + "creationError": "No se pudo crear el formulario", + "deleteError": "No se pudo eliminar el formulario", + "deleteNow": "¡Eliminar ahora!", + "deleted": "Formulario eliminado", + "design": { + "color": { + "answer": "Color de respuesta", + "background": "Color de fondo", + "button": "Color del boton", + "buttonActive": "Color activo del botón", + "buttonText": "Color del texto del botón", + "question": "Color de la pregunta" + }, + "font": "Fuente" + }, + "designTab": "Diseño", + "endPage": { + "action": "Acción", + "activeColor": "Color activo", + "addButton": "Agregar botón", + "bgColor": "Color de fondo", + "buttons": "Botones", + "color": "Color", + "continueButtonText": "Continuar texto del botón", + "paragraph": "Párrafo", + "paragraphInfo": "Use markdown para formateo avanzado", + "show": "mostrar", + "text": "Texto", + "title": "Título", + "url": "Url" + }, + "endPageTab": "Página final", + "fieldsTab": "Campos", + "hooks": { + "add": "Agregar", + "confirmDelete": "Vacío", + "deleteNow": "Vacío", + "enabled": "Habilitado" + }, + "hooksTab": "WebHooks", + "loading": "Formulario de carga", + "mange": "Editar formulario \" {{title}} \"", + "new": "Nuevo formulario", + "notifications": { + "enabled": "Habilitado", + "fromEmail": "Correo electrónico del remitente", + "fromEmailInfo": "Asegúrese de que su servidor de correo pueda enviar desde este correo electrónico", + "fromField": "Correo electrónico del remitente", + "fromFieldInfo": "Asegúrese de que su servidor de correo pueda enviar desde este correo electrónico", + "htmlTemplate": "Plantilla HTML", + "htmlTemplateInfo": "También puede usar <u> MJML <\/u> para crear sus plantillas de correo electrónico", + "subject": "Tema", + "toEmail": "Tu correo electrónico", + "toEmailInfo": "Si no está configurado, se enviará al administrador del formulario", + "toField": "Correo electrónico de destino", + "toFieldInfo": "Dirección de correo electrónico que recibirá las notificaiones" + }, + "restart": "Reiniciar formulario", + "row": { + "admin": "Propietario", + "created": "Creado", + "isLive": "En Vivo", + "language": "Idioma", + "lastModified": "Última modificación", + "title": "Título" + }, + "startPage": { + "action": "Acción", + "activeColor": "Color activo", + "addButton": "Agregar botón", + "bgColor": "Color de fondo", + "buttons": "Botones", + "color": "Color", + "continueButtonText": "Texto del botón continuar", + "paragraph": "Párrafo", + "paragraphInfo": "Use markdown para formateo avanzado", + "show": "mostrar", + "text": "Texto", + "title": "Título", + "url": "Url" + }, + "startPageTab": "Página de inicio", + "submitted": "Gracias por tu presentación!", + "updateError": "No se pudo actualizar el formulario", + "updateNow": "Guardar", + "updated": "Formulario actualizado" +} diff --git a/ui/locales/es/index.ts b/ui/locales/es/index.ts new file mode 100644 index 00000000..3c549c6a --- /dev/null +++ b/ui/locales/es/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const es = { + admin, + common, + form, + language, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/es/language.json b/ui/locales/es/language.json new file mode 100644 index 00000000..097daa3e --- /dev/null +++ b/ui/locales/es/language.json @@ -0,0 +1,11 @@ +{ + "cn": "繁體中文", + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "pl": "Polski", + "pt": "Português", + "ru": "русский" +} diff --git a/ui/locales/es/login.json b/ui/locales/es/login.json new file mode 100644 index 00000000..0cd62ce3 --- /dev/null +++ b/ui/locales/es/login.json @@ -0,0 +1,8 @@ +{ + "invalidLoginCredentials": "nombre de usuario \/ contraseña no son válidos", + "loginNow": "Inicia sesión ahora", + "note": "Nota", + "passwordPlaceholder": "Contraseña", + "usernamePlaceholder": "Nombre de usuario", + "welcomeBack": "¡Bienvenido!" +} diff --git a/ui/locales/es/profile.json b/ui/locales/es/profile.json new file mode 100644 index 00000000..9fda436d --- /dev/null +++ b/ui/locales/es/profile.json @@ -0,0 +1,10 @@ +{ + "email": "Correo electrónico", + "firstName": "Nombre", + "language": "Idioma", + "lastName": "Apellido", + "updateError": "No se pudo actualizar el perfil", + "updateNow": "Guardar", + "updated": "Perfil actualizado", + "username": "Nombre de usuario" +} diff --git a/ui/locales/es/register.json b/ui/locales/es/register.json new file mode 100644 index 00000000..4f694d6e --- /dev/null +++ b/ui/locales/es/register.json @@ -0,0 +1,6 @@ +{ + "credentialsAlreadyInUse": "¡Algunos datos ya están en uso!", + "gotoLogin": "¿Ya tienes una cuenta? Inicia sesión", + "registerNow": "Regístrate ahora", + "welcome": "Bienvenido, comprueba tu correo electrónico" +} diff --git a/ui/locales/es/statistic.json b/ui/locales/es/statistic.json new file mode 100644 index 00000000..330ee02b --- /dev/null +++ b/ui/locales/es/statistic.json @@ -0,0 +1,5 @@ +{ + "totalForms": "Formularios totales", + "totalSubmissions": "Envíos totales", + "totalUsers": "Usuarios totales" +} diff --git a/ui/locales/es/submission.json b/ui/locales/es/submission.json new file mode 100644 index 00000000..568ab12c --- /dev/null +++ b/ui/locales/es/submission.json @@ -0,0 +1,16 @@ +{ + "add": "Agregar Envío", + "city": "Ciudad", + "country": "País", + "created": "Creado", + "device": { + "name": "Nombre del dispositivo", + "type": "Tipo de dispositivo" + }, + "edit": "Editar", + "field": "Campo", + "lastModified": "Ultimo cambio", + "progress": "Progreso", + "submission": "Envío", + "value": "Valor" +} diff --git a/ui/locales/es/type.json b/ui/locales/es/type.json new file mode 100644 index 00000000..d8496e47 --- /dev/null +++ b/ui/locales/es/type.json @@ -0,0 +1,68 @@ +{ + "confirmDelete": "¿Eliminar realmente este campo? ¡Compruebe que no esté referenciado en ningún lado!", + "date": { + "default": "Fecha predeterminada", + "max": "Fecha máxima", + "min": "Fecha min", + "name": "Fecha" + }, + "deleteNow": "Eliminar campo", + "description": "Descripción", + "descriptionInfo": "Use markdown para formateo avanzado", + "dropdown": { + "addOption": "Agregar opción", + "default": "Valor por defecto", + "name": "Desplegable", + "options": "Opciones", + "removeOption": "Eliminar", + "titlePlaceholder": "Título", + "valuePlaceholder": "Valor" + }, + "email": { + "default": "Email predeterminado", + "name": "Correo electrónico" + }, + "hidden": { + "default": "Valor por defecto", + "name": "Oculto" + }, + "link": { + "default": "Enlace predeterminado", + "name": "URL" + }, + "number": { + "default": "Número predeterminado", + "name": "Número" + }, + "radio": { + "addOption": "Agregar opción", + "default": "Valor por defecto", + "name": "Interruptor de radio", + "options": "Opciones", + "removeOption": "Eliminar", + "titlePlaceholder": "Título", + "valuePlaceholder": "Valor" + }, + "rating": { + "clearNote": "Haga clic nuevamente para eliminar el valor predeterminado", + "default": "Valor por defecto", + "name": "Clasificación" + }, + "required": "Necesario", + "requiredInfo": "Si es necesario, el valor predeterminado debe establecerse para que los usuarios puedan enviar el formulario.", + "slug": "Slug", + "slugInfo": "Utilice slug para pasar la dinámica predeterminada como parámetro de url? Slug = value", + "textarea": { + "default": "Valor por defecto", + "name": "Área de texto" + }, + "textfield": { + "default": "Valor por defecto", + "name": "Línea de texto" + }, + "title": "Título", + "yes_no": { + "default": "Valor por defecto", + "name": "Sí No" + } +} diff --git a/ui/locales/es/user.json b/ui/locales/es/user.json new file mode 100644 index 00000000..139be733 --- /dev/null +++ b/ui/locales/es/user.json @@ -0,0 +1,18 @@ +{ + "baseData": "Datos Generales", + "confirmDelete": "¿Estás seguro de eliminar a este usuario?", + "deleteError": "no se pudo eliminar el usuario", + "deleteNow": "¡Elimínalo ahora!", + "deleted": "Usuario eliminado", + "loading": "Cargando usuario", + "mange": "Editar usuario \" {{email}} \"", + "row": { + "created": "Creado", + "email": "Correo electrónico", + "menu": "Vacío", + "roles": "Roles" + }, + "updateError": "No se pudo actualizar el usuario", + "updateNow": "Guardar", + "updated": "Usuario actualizado" +} diff --git a/ui/locales/es/validation.json b/ui/locales/es/validation.json new file mode 100644 index 00000000..b5da2469 --- /dev/null +++ b/ui/locales/es/validation.json @@ -0,0 +1,18 @@ +{ + "emailFieldRequired": "Por favor, introduzca una dirección de correo electrónico", + "emailRequired": "Por favor, introduzca una dirección de correo electrónico", + "invalidEmail": "¡Debe ser una dirección de correo electrónico válida!", + "invalidNumber": "¡Debe ser un número válido!", + "invalidSlug": "Slug solo puede contener minúsculas az, 0-9 y _", + "invalidUrl": "Debe ser una URL válida", + "languageRequired": "Por favor, seleccione un idioma", + "mandatoryFieldsMissing": "Faltan campos obligatorios", + "passwordMinLength": "¡Debe tener 5 caracteres o más!", + "passwordRequired": "Por favor, introduzca su contraseña!", + "subjectRequired": "Por favor, introduzca un tema", + "templateRequired": "Por favor, introduzca una plantilla", + "titleRequired": "Por favor, introduzca un título", + "urlRequired": "Por favor, introduzca un URL", + "usernameRequired": "Por favor, introduzca un nombre de usuario", + "valueRequired": "Por favor, introduzca un valor" +} diff --git a/ui/locales/fr/admin.json b/ui/locales/fr/admin.json new file mode 100644 index 00000000..95298999 --- /dev/null +++ b/ui/locales/fr/admin.json @@ -0,0 +1,9 @@ +{ + "administration": "Administration", + "forms": "Formulaires", + "home": "Accueil", + "profile": "Profil", + "submissions": "Soumissions", + "username": "Identifiant", + "users": "Utilisateurs" +} diff --git a/ui/locales/fr/common.json b/ui/locales/fr/common.json new file mode 100644 index 00000000..d9d58f21 --- /dev/null +++ b/ui/locales/fr/common.json @@ -0,0 +1,10 @@ +{ + "admin": "Admin", + "checkingCredentials": "Vérification des informations d'identification", + "loadingCredentials": "Chargement des informations d'identification", + "login": "S'identifier", + "logout": "Se déconnecter", + "profile": "Profil", + "recover": "Mot de passe perdu", + "register": "Créer un compte" +} diff --git a/ui/locales/fr/form.json b/ui/locales/fr/form.json new file mode 100644 index 00000000..9f89afc7 --- /dev/null +++ b/ui/locales/fr/form.json @@ -0,0 +1,114 @@ +{ + "baseData": { + "isLive": "Actif", + "language": "Langue", + "showFooter": "Afficher le pied de page", + "title": "Titre" + }, + "baseDataTab": "Paramètres", + "building": "Construction du formulaire", + "confirmDelete": "Êtes-vous sûr de supprimer ce formulaire avec toutes ses soumissions?", + "continue": "Continuer", + "create": "Créer un nouveau formulaire", + "createNow": "Enregistrer", + "created": "Formulaire créé", + "creationError": "Impossible de créer le formulaire", + "deleteError": "Impossible de supprimer le formulaire", + "deleteNow": "Supprimer", + "deleted": "Formulaire supprimé", + "design": { + "color": { + "answer": "Couleur des réponses", + "background": "Couleur de l'arrière-plan", + "button": "Couleur de l'arrière-plan du bouton", + "buttonActive": "Couleur du texte du bouton au survol", + "buttonText": "Couleur du texte du bouton", + "question": "Couleur des questions" + }, + "font": "Police de caractère", + "layout": { + "card": "Carte", + "slider": "Carousel" + }, + "layouts": "Disposition" + }, + "designTab": "Design", + "endPage": { + "action": "Action", + "activeColor": "Couleur du texte au survol", + "addButton": "Ajouter un bouton", + "bgColor": "Couleur de l'arrière plan", + "buttons": "Boutons", + "color": "Couleur", + "continueButtonText": "Texte du bouton continuer", + "paragraph": "Paragraphe", + "paragraphInfo": "Utiliser markdown pour le formatage avancé", + "show": "Afficher", + "text": "Texte", + "title": "Titre", + "url": "URL" + }, + "endPageTab": "Page de fin", + "fieldsTab": "Champs de formulaire", + "hooks": { + "add": "Ajouter", + "confirmDelete": "Confirmer la suppression", + "deleteNow": "Supprimer", + "enabled": "Activé" + }, + "hooksTab": "Webhook", + "loading": "Chargement du formulaire", + "logic": { + "add": "Ajouter une logique" + }, + "mange": "Modifier le formulaire \" {{title}} \"", + "new": "Nouveau formulaire", + "next": "Suivant", + "notifications": { + "add": "Ajouter une notification", + "enabled": "Activé", + "fromEmail": "Email de l'expéditeur", + "fromEmailInfo": "Assurez-vous que votre serveur de messagerie peut envoyer à partir de cet email", + "fromField": "Email de l'expéditeur", + "fromFieldInfo": "Champ avec email, définira l'en-tête Répondre à", + "htmlTemplate": "Modèle HTML", + "htmlTemplateInfo": "Vous pouvez également utiliser <u> MJML <\/u> pour créer vos modèles de courrier électronique", + "subject": "Sujet", + "toEmail": "Votre email", + "toEmailInfo": "S'il n'est pas défini, il sera envoyé à l'administrateur du formulaire", + "toField": "Champ de messagerie", + "toFieldInfo": "Champ avec email pour réception" + }, + "notificationsTab": "Notifications", + "previous": "Précédent", + "restart": "Nouvelle soumission", + "row": { + "admin": "Propriétaire", + "created": "Créé", + "isLive": "Actif", + "language": "Langue", + "lastModified": "Dernière modification", + "menu": "Actions", + "title": "Titre" + }, + "startPage": { + "action": "Action", + "activeColor": "Couleur du texte au survol", + "addButton": "Ajouter un bouton", + "bgColor": "Couleur de l'arrière plan", + "buttons": "Boutons", + "color": "Couleur du texte", + "continueButtonText": "Texte du bouton continuer", + "paragraph": "Paragraphe", + "paragraphInfo": "Utiliser markdown pour le formatage avancé", + "show": "Afficher", + "text": "Texte", + "title": "Titre", + "url": "URL" + }, + "startPageTab": "Page de démarrage", + "submitted": "Merci pour votre soumission!", + "updateError": "Impossible de mettre à jour le formulaire", + "updateNow": "Enregistrer", + "updated": "Formulaire mis à jour" +} diff --git a/ui/locales/fr/index.ts b/ui/locales/fr/index.ts new file mode 100644 index 00000000..6166a450 --- /dev/null +++ b/ui/locales/fr/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const fr = { + admin, + common, + form, + language, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/fr/language.json b/ui/locales/fr/language.json new file mode 100644 index 00000000..fa558f59 --- /dev/null +++ b/ui/locales/fr/language.json @@ -0,0 +1,12 @@ +{ + "cn": "繁體中文", + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "ja": "Vide", + "pl": "Polski", + "pt": "Português", + "ru": "русский" +} diff --git a/ui/locales/fr/login.json b/ui/locales/fr/login.json new file mode 100644 index 00000000..2f0d80fb --- /dev/null +++ b/ui/locales/fr/login.json @@ -0,0 +1,8 @@ +{ + "invalidLoginCredentials": "Identifiant \/ mot de passe invalide", + "loginNow": "Connexion", + "note": "Note", + "passwordPlaceholder": "Mot de passe", + "usernamePlaceholder": "Identifiant", + "welcomeBack": "Bienvenue !" +} diff --git a/ui/locales/fr/profile.json b/ui/locales/fr/profile.json new file mode 100644 index 00000000..f4f3d2e3 --- /dev/null +++ b/ui/locales/fr/profile.json @@ -0,0 +1,12 @@ +{ + "confirmPassword": "Confirmer le mot de passe", + "email": "Email", + "firstName": "Prénom", + "language": "Langue", + "lastName": "Nom de famille", + "password": "Mot de passe", + "updateError": "Impossible de mettre à jour le profil", + "updateNow": "Enregistrer", + "updated": "Profil mis à jour", + "username": "Identifiant" +} diff --git a/ui/locales/fr/register.json b/ui/locales/fr/register.json new file mode 100644 index 00000000..52514649 --- /dev/null +++ b/ui/locales/fr/register.json @@ -0,0 +1,6 @@ +{ + "credentialsAlreadyInUse": "L'identifiant et\/ou l'email sont déjà utilisés !", + "gotoLogin": "Déjà un compte ? Connectez-vous", + "registerNow": "Créer un compte", + "welcome": "Bienvenue. Un email de confirmation vous a été envoyé." +} diff --git a/ui/locales/fr/statistic.json b/ui/locales/fr/statistic.json new file mode 100644 index 00000000..4f265bbe --- /dev/null +++ b/ui/locales/fr/statistic.json @@ -0,0 +1,5 @@ +{ + "totalForms": "Nombre de formulaires", + "totalSubmissions": "Nombre de soumissions", + "totalUsers": "Nombre d'utilisateurs" +} diff --git a/ui/locales/fr/submission.json b/ui/locales/fr/submission.json new file mode 100644 index 00000000..9c59b690 --- /dev/null +++ b/ui/locales/fr/submission.json @@ -0,0 +1,17 @@ +{ + "add": "Ajouter une soumission", + "city": "Ville", + "country": "Pays", + "created": "Créé", + "device": { + "name": "Type de l'appareil", + "type": "User agent" + }, + "edit": "Éditer", + "export": "Exporter", + "field": "Champ", + "lastModified": "Dernier changement", + "progress": "Progression", + "submission": "Soumission", + "value": "Valeur" +} diff --git a/ui/locales/fr/type.json b/ui/locales/fr/type.json new file mode 100644 index 00000000..06ebf455 --- /dev/null +++ b/ui/locales/fr/type.json @@ -0,0 +1,76 @@ +{ + "add": "Ajouter un champ", + "confirmDelete": "Voulez-vous vraiment supprimer ce champ ? Vérifiez qu'il n'est référencé nulle part !", + "date": { + "default": "Date par défaut", + "max": "Date max", + "min": "Date min", + "name": "Date" + }, + "deleteNow": "Supprimer le champ", + "description": "Description", + "descriptionInfo": "Utiliser markdown pour le formatage avancé", + "dropdown": { + "addOption": "Ajouter une option", + "default": "Valeur par défaut", + "name": "Menu déroulant", + "options": "Options", + "removeOption": "Supprimer", + "titlePlaceholder": "Label", + "valuePlaceholder": "Valeur" + }, + "email": { + "default": "Email par défaut", + "name": "Email" + }, + "hidden": { + "default": "Valeur par défaut", + "name": "Caché" + }, + "link": { + "default": "Lien par défaut", + "name": "URL" + }, + "number": { + "default": "Nombre par défaut", + "name": "Nombre" + }, + "radio": { + "addOption": "Ajouter une option", + "default": "Valeur par défaut", + "name": "Choix simple (radio)", + "options": "Options", + "removeOption": "Supprimer", + "titlePlaceholder": "Label", + "valuePlaceholder": "Valeur" + }, + "rating": { + "clearNote": "Cliquez à nouveau pour supprimer la valeur par défaut", + "default": "Valeur par défaut", + "name": "Évaluation" + }, + "required": "Obligatoire", + "requiredInfo": "Si obligatoire, la valeur par défaut doit être définie pour permettre aux utilisateurs de soumettre le formulaire !", + "slider": { + "default": "Valeur par défaut", + "max": "Valeur max", + "min": "Valeur min", + "name": "Carousel", + "step": "Taille de l'étape" + }, + "slug": "Slug", + "slugInfo": "Utiliser le slug pour passer en paramètre d'URL ?slug=valeur", + "textarea": { + "default": "Valeur par défaut", + "name": "Texte long" + }, + "textfield": { + "default": "Valeur par défaut", + "name": "Texte court" + }, + "title": "Label", + "yes_no": { + "default": "Valeur par défaut", + "name": "Oui \/ Non" + } +} diff --git a/ui/locales/fr/user.json b/ui/locales/fr/user.json new file mode 100644 index 00000000..c9f6462f --- /dev/null +++ b/ui/locales/fr/user.json @@ -0,0 +1,18 @@ +{ + "baseData": "Profil de l'utilisateur", + "confirmDelete": "Voulez-vous vraiment supprimer cet utilisateur ?", + "deleteError": "L'utilisateur n'a pas pu être supprimé", + "deleteNow": "Supprimer", + "deleted": "Utilisateur supprimé", + "loading": "Chargement de l'utilisateur", + "mange": "Modifier l'utilisateur : {{email}}", + "row": { + "created": "Créé", + "email": "Email", + "menu": "Actions", + "roles": "Rôle" + }, + "updateError": "Impossible de mettre à jour l'utilisateur", + "updateNow": "Enregistrer", + "updated": "Utilisateur mis à jour" +} diff --git a/ui/locales/fr/validation.json b/ui/locales/fr/validation.json new file mode 100644 index 00000000..5bcf0f28 --- /dev/null +++ b/ui/locales/fr/validation.json @@ -0,0 +1,20 @@ +{ + "emailFieldRequired": "Veuillez sélectionner un champ email", + "emailRequired": "Veuillez fournir un email", + "invalidEmail": "Le format de l'email n'est pas valide", + "invalidNumber": "Doit être un nombre valide", + "invalidSlug": "Le slug ne peut contenir que des caractères minuscules a-z, 0-9 et _", + "invalidUrl": "Le format de l'URL n'est pas valide", + "languageRequired": "Veuillez sélectionner une langue", + "mandatoryFieldsMissing": "Champs obligatoires manquants", + "passwordConfirmMismatch": "Les mots de passe entrées sont différents", + "passwordConfirmRequired": "Confirmez votre mot de passe", + "passwordMinLength": "Doit être supérieur ou égal à 5 caractères", + "passwordRequired": "Veuillez saisir votre mot de passe", + "subjectRequired": "Veuillez fournir un sujet", + "templateRequired": "Veuillez fournir un modèle", + "titleRequired": "Veuillez saisir un titre", + "urlRequired": "Veuillez saisir une URL", + "usernameRequired": "Veuillez saisir un identifiant", + "valueRequired": "Veuillez saisir une valeur" +} diff --git a/ui/locales/hi/admin.json b/ui/locales/hi/admin.json new file mode 100644 index 00000000..464f1823 --- /dev/null +++ b/ui/locales/hi/admin.json @@ -0,0 +1,9 @@ +{ + "administration": "एडमिनिस्ट्रेशन", + "forms": "फार्म", + "home": "होम", + "profile": "प्रोफ़ाइल", + "submissions": "सब्-मिशन्", + "username": "यूजरनेम", + "users": "यूज़र्" +} diff --git a/ui/locales/hi/common.json b/ui/locales/hi/common.json new file mode 100644 index 00000000..ba340d85 --- /dev/null +++ b/ui/locales/hi/common.json @@ -0,0 +1,10 @@ +{ + "admin": "एडमिन", + "checkingCredentials": "चेकिंग क्रेडेंशियल", + "loadingCredentials": "लोडिंग क्रेडेंशियल", + "login": "लॉग इन करें", + "logout": "लॉग आउट करें", + "profile": "प्रोफ़ाइल", + "recover": "फॉरगेट पासवर्ड?", + "register": "अकाउंट बनाएँ" +} diff --git a/ui/locales/hi/form.json b/ui/locales/hi/form.json new file mode 100644 index 00000000..dffb954a --- /dev/null +++ b/ui/locales/hi/form.json @@ -0,0 +1,7 @@ +{ + "confirmDelete": "क्या आप वास्तव में सभी सबमिशन के साथ इस फॉर्म को हटाना चाहते हैं?", + "fieldsTab": "फॉर्म फ़ील्ड", + "startPage": { + "paragraphInfo": "Formatting के लिए मार्कडाउन का उपयोग करें" + } +} diff --git a/ui/locales/hi/index.ts b/ui/locales/hi/index.ts new file mode 100644 index 00000000..58b78299 --- /dev/null +++ b/ui/locales/hi/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const hi = { + language, + admin, + common, + form, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/hi/language.json b/ui/locales/hi/language.json new file mode 100644 index 00000000..71bb626a --- /dev/null +++ b/ui/locales/hi/language.json @@ -0,0 +1,11 @@ +{ + "cn": "繁體中文", + "de": "Deutsch", + "en": "अंग्रेज़ी", + "es": "स्पेनोलि", + "fr": "फ़्रैंकैसी", + "it": "Italiano", + "pl": "पोल्स्की", + "pt": "पुर्तगाली", + "ru": "pусский" +} diff --git a/ui/locales/hi/login.json b/ui/locales/hi/login.json new file mode 100644 index 00000000..1921a4ad --- /dev/null +++ b/ui/locales/hi/login.json @@ -0,0 +1,8 @@ +{ + "invalidLoginCredentials": "यूजरनेम \/ पासवर्ड अमान्य हैं", + "loginNow": "अभी लॉगिन करें", + "note": "नोट", + "passwordPlaceholder": "पासवर्ड", + "usernamePlaceholder": "यूजरनेम ", + "welcomeBack": "वापसी पर स्वागत है!" +} diff --git a/ui/locales/hi/profile.json b/ui/locales/hi/profile.json new file mode 100644 index 00000000..1a5a50a0 --- /dev/null +++ b/ui/locales/hi/profile.json @@ -0,0 +1,12 @@ +{ + "confirmPassword": "पासवर्ड की पुष्टि कीजिये", + "email": "ईमेल", + "firstName": "नाम", + "language": "भाषा", + "lastName": "सरनेम ", + "password": "पासवर्ड", + "updateError": "प्रोफ़ाइल अपडेट नहीं हो पाई", + "updateNow": "सेव करे", + "updated": "प्रोफ़ाइल अपडेट हो गयी", + "username": "यूजरनेम" +} diff --git a/ui/locales/hi/register.json b/ui/locales/hi/register.json new file mode 100644 index 00000000..16c6a186 --- /dev/null +++ b/ui/locales/hi/register.json @@ -0,0 +1,6 @@ +{ + "credentialsAlreadyInUse": "कुछ डेटा पहले से उपयोग में है!", + "gotoLogin": "खाता है? लॉग इन करें", + "registerNow": "अभी रजिस्टर करें", + "welcome": "नमस्ते, कृपया अपने ईमेल की पुष्टि भी करें" +} diff --git a/ui/locales/hi/statistic.json b/ui/locales/hi/statistic.json new file mode 100644 index 00000000..16cf9945 --- /dev/null +++ b/ui/locales/hi/statistic.json @@ -0,0 +1,5 @@ +{ + "totalForms": "संपूर्ण फार्म", + "totalSubmissions": "संपूर्ण सब्-मिशन्", + "totalUsers": "संपूर्ण यूज़र्" +} diff --git a/ui/locales/hi/submission.json b/ui/locales/hi/submission.json new file mode 100644 index 00000000..dd8de299 --- /dev/null +++ b/ui/locales/hi/submission.json @@ -0,0 +1,17 @@ +{ + "add": "ऐड सब्-मिशन्", + "city": "शहर", + "country": "देश", + "created": "बन गया", + "device": { + "name": "Device Name", + "type": "Device Type" + }, + "edit": "एडिट करें", + "export": "एक्सपोर्ट", + "field": "फील्ड", + "lastModified": "अंतिम परिवर्तन", + "progress": "प्रगति", + "submission": "सब्-मिशन्", + "value": "वैल्यू" +} diff --git a/ui/locales/hi/type.json b/ui/locales/hi/type.json new file mode 100644 index 00000000..0ccba80e --- /dev/null +++ b/ui/locales/hi/type.json @@ -0,0 +1,4 @@ +{ + "deleteNow": "फ़ील्ड हटाएं", + "slugInfo": "Url पैरामीटर के रूप में डिफ़ॉल्ट डायनामिक पास करने के लिए स्लग का उपयोग करें? " +} diff --git a/ui/locales/hi/user.json b/ui/locales/hi/user.json new file mode 100644 index 00000000..157aac06 --- /dev/null +++ b/ui/locales/hi/user.json @@ -0,0 +1,5 @@ +{ + "mange": "संपादित करें उपयोगकर्ता \"{ईमेल}}} \"{{email}}", + "updateError": "उपयोगकर्ता को अपडेट नहीं किया जा सका", + "updateNow": "सहेजें☻" +} diff --git a/ui/locales/hi/validation.json b/ui/locales/hi/validation.json new file mode 100644 index 00000000..3d3b0c4f --- /dev/null +++ b/ui/locales/hi/validation.json @@ -0,0 +1,12 @@ +{ + "emailFieldRequired": "कृपया एक ईमेल फ़ील्ड का चयन करें", + "emailRequired": "कृपया एक ईमेल प्रदान करें", + "invalidNumber": "एक वैध संख्या होनी चाहिए!", + "invalidSlug": "स्लग में केवल लोअरकेस हो सकता है, 0-9 और _", + "languageRequired": "कृपया एक भाषा का चयन करें", + "mandatoryFieldsMissing": "अनिवार्य क्षेत्र गायब हैं", + "passwordMinLength": "5 पात्रों से अधिक या बराबर होना चाहिए!", + "subjectRequired": "कृपया एक विषय प्रदान करें", + "titleRequired": "कृपया एक शीर्षक प्रदान करें", + "urlRequired": "कृपया एक URL प्रदान करें" +} diff --git a/ui/locales/index.ts b/ui/locales/index.ts new file mode 100644 index 00000000..5ddf31b5 --- /dev/null +++ b/ui/locales/index.ts @@ -0,0 +1,39 @@ +import { ar } from './ar' +import { cn } from './cn' +import { da } from './da' +import { de } from './de' +import { en } from './en' +import { es } from './es' +import { fr } from './fr' +import { hi } from './hi' +import { it } from './it' +import { ja } from './ja' +import { nl } from './nl' +import { pl } from './pl' +import { pt_BR } from './pt_BR' +import { pt_PT } from './pt_PT' +import { ru } from './ru' +import { sv } from './sv' +import { ta } from './ta' +import { uk } from './uk' + +export const resources = { + en, + ar, + cn, + da, + nl, + fr, + de, + hi, + it, + ja, + pl, + pt_BR, + pt_PT, + ru, + es, + sv, + ta, + uk, +} diff --git a/ui/locales/it/admin.json b/ui/locales/it/admin.json new file mode 100644 index 00000000..2251b50e --- /dev/null +++ b/ui/locales/it/admin.json @@ -0,0 +1,8 @@ +{ + "forms": "Moduli", + "home": "casa", + "profile": "Profilo", + "submissions": "proposte", + "username": "nome utente", + "users": "Utenti" +} diff --git a/ui/locales/it/common.json b/ui/locales/it/common.json new file mode 100644 index 00000000..b523f4b6 --- /dev/null +++ b/ui/locales/it/common.json @@ -0,0 +1,10 @@ +{ + "admin": "Admin", + "checkingCredentials": "Verifica delle credenziali", + "loadingCredentials": "Caricamento delle credenziali", + "login": "Entra", + "logout": "Logout", + "profile": "Profilo", + "recover": "Password dimenticata", + "register": "Crea account" +} diff --git a/ui/locales/it/form.json b/ui/locales/it/form.json new file mode 100644 index 00000000..183150ef --- /dev/null +++ b/ui/locales/it/form.json @@ -0,0 +1,90 @@ +{ + "baseData": { + "isLive": "È in diretta", + "language": "linguaggio", + "showFooter": "Mostra piè di pagina", + "title": "Titolo" + }, + "baseDataTab": "Dati di base", + "building": "Modulo di costruzione", + "confirmDelete": "Sei sicuro di eliminare questo modulo con tutti gli invii?", + "create": "Crea un nuovo modulo", + "createNow": "Salva", + "created": "Modulo creato", + "creationError": "Impossibile creare il modulo", + "deleteError": "Impossibile eliminare il modulo", + "deleteNow": "Cancella ora!", + "deleted": "Modulo eliminato", + "design": { + "color": { + "answer": "Rispondi al colore", + "background": "Colore di sfondo", + "button": "Colore pulsante", + "buttonActive": "Pulsante Colore attivo", + "buttonText": "Colore testo pulsante", + "question": "Domanda di colore" + }, + "font": "Font" + }, + "designTab": "Design", + "endPage": { + "action": "Azione", + "activeColor": "Colore attivo", + "addButton": "Aggiungi pulsante", + "bgColor": "Colore di sfondo", + "buttons": "pulsanti", + "color": "Colore", + "continueButtonText": "Continua pulsante testo", + "paragraph": "Paragrafo", + "show": "Mostrare", + "text": "Testo", + "title": "Titolo", + "url": "url" + }, + "endPageTab": "Pagina finale", + "loading": "Modulo di caricamento", + "mange": "Modifica modulo \" {{title}} \"", + "new": "Nuovo modulo", + "notifications": { + "enabled": "Abilitato", + "fromEmail": "Email del mittente", + "fromEmailInfo": "Assicurati che il tuo mailserver possa inviare da questa email", + "fromField": "Email del mittente", + "fromFieldInfo": "Campo con e-mail, imposterà l'intestazione Rispondi a", + "htmlTemplate": "Modello HTML", + "htmlTemplateInfo": "Puoi anche utilizzare <u> MJML <\/u> per creare i tuoi modelli di email", + "subject": "Soggetto", + "toEmail": "La tua email", + "toEmailInfo": "Se non impostato, verrà inviato all'amministratore del modulo", + "toField": "Campo email", + "toFieldInfo": "Campo con e-mail per la ricevuta" + }, + "restart": "Riavvia modulo", + "row": { + "admin": "Proprietario", + "created": "Creato", + "isLive": "Vivere", + "language": "linguaggio", + "lastModified": "Ultima modifica", + "title": "Titolo" + }, + "startPage": { + "action": "Azione", + "activeColor": "Colore attivo", + "addButton": "Aggiungi pulsante", + "bgColor": "Colore di sfondo", + "buttons": "pulsanti", + "color": "Colore", + "continueButtonText": "Continua pulsante testo", + "paragraph": "Paragrafo", + "show": "Mostrare", + "text": "Testo", + "title": "Titolo", + "url": "url" + }, + "startPageTab": "Pagina iniziale", + "submitted": "Grazie per la vostra presentazione!", + "updateError": "Impossibile aggiornare il modulo", + "updateNow": "Salva", + "updated": "Modulo aggiornato" +} diff --git a/ui/locales/it/index.ts b/ui/locales/it/index.ts new file mode 100644 index 00000000..28995baf --- /dev/null +++ b/ui/locales/it/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const it = { + admin, + common, + form, + language, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/it/language.json b/ui/locales/it/language.json new file mode 100644 index 00000000..097daa3e --- /dev/null +++ b/ui/locales/it/language.json @@ -0,0 +1,11 @@ +{ + "cn": "繁體中文", + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "pl": "Polski", + "pt": "Português", + "ru": "русский" +} diff --git a/ui/locales/it/login.json b/ui/locales/it/login.json new file mode 100644 index 00000000..bd501709 --- /dev/null +++ b/ui/locales/it/login.json @@ -0,0 +1,7 @@ +{ + "invalidLoginCredentials": "nome utente \/ password non sono validi", + "loginNow": "Accedi ora", + "passwordPlaceholder": "Parola d'ordine", + "usernamePlaceholder": "Nome utente", + "welcomeBack": "Ben tornato!" +} diff --git a/ui/locales/it/profile.json b/ui/locales/it/profile.json new file mode 100644 index 00000000..273f9732 --- /dev/null +++ b/ui/locales/it/profile.json @@ -0,0 +1,10 @@ +{ + "email": "E-mail", + "firstName": "Nome di battesimo", + "language": "linguaggio", + "lastName": "Cognome", + "updateError": "Impossibile aggiornare il profilo", + "updateNow": "Salva", + "updated": "profilo aggiornato", + "username": "Nome utente" +} diff --git a/ui/locales/it/register.json b/ui/locales/it/register.json new file mode 100644 index 00000000..bef3e4fe --- /dev/null +++ b/ui/locales/it/register.json @@ -0,0 +1,6 @@ +{ + "credentialsAlreadyInUse": "Alcuni dati già in uso!", + "gotoLogin": "Avere un conto? Vai al login", + "registerNow": "Iscriviti ora", + "welcome": "Benvenuto, conferma anche la tua email" +} diff --git a/ui/locales/it/statistic.json b/ui/locales/it/statistic.json new file mode 100644 index 00000000..d5b83cdb --- /dev/null +++ b/ui/locales/it/statistic.json @@ -0,0 +1,5 @@ +{ + "totalForms": "Moduli totali", + "totalSubmissions": "Totale invii", + "totalUsers": "Utenti totali" +} diff --git a/ui/locales/it/submission.json b/ui/locales/it/submission.json new file mode 100644 index 00000000..132a661d --- /dev/null +++ b/ui/locales/it/submission.json @@ -0,0 +1,16 @@ +{ + "add": "Aggiungi invio", + "city": "Città", + "country": "Nazione", + "created": "Creato", + "device": { + "name": "Nome del dispositivo", + "type": "Tipo di dispositivo" + }, + "edit": "modificare", + "field": "Campo", + "lastModified": "Ultima modifica", + "progress": "Progresso", + "submission": "Presentazione", + "value": "Valore" +} diff --git a/ui/locales/it/type.json b/ui/locales/it/type.json new file mode 100644 index 00000000..dc6a157f --- /dev/null +++ b/ui/locales/it/type.json @@ -0,0 +1,65 @@ +{ + "confirmDelete": "Rimuovere davvero questo campo? Controlla che non sia referenziato da nessuna parte!", + "date": { + "default": "Data predefinita", + "max": "Data massima", + "min": "Data minima", + "name": "Data" + }, + "deleteNow": "Elimina campo", + "description": "Descrizione", + "dropdown": { + "addOption": "Aggiungi opzione", + "default": "Valore predefinito", + "name": "Cadere in picchiata", + "options": "Opzioni", + "removeOption": "Rimuovere", + "titlePlaceholder": "Titolo", + "valuePlaceholder": "Valore" + }, + "email": { + "default": "Email predefinita", + "name": "E-mail" + }, + "hidden": { + "default": "Valore predefinito", + "name": "Nascosto" + }, + "link": { + "default": "Link predefinito", + "name": "URL" + }, + "number": { + "default": "Numero predefinito", + "name": "Numero" + }, + "radio": { + "addOption": "Aggiungi opzione", + "default": "Valore predefinito", + "name": "Interruttore radio", + "options": "Opzioni", + "removeOption": "Rimuovere", + "titlePlaceholder": "Titolo", + "valuePlaceholder": "Valore" + }, + "rating": { + "clearNote": "Fare di nuovo clic per rimuovere il valore predefinito", + "default": "Valore predefinito", + "name": "Valutazione" + }, + "required": "necessario", + "requiredInfo": "Se necessario, è necessario impostare il valore predefinito per consentire agli utenti di inviare il modulo!", + "textarea": { + "default": "Valore predefinito", + "name": "Area di testo" + }, + "textfield": { + "default": "Valore predefinito", + "name": "Riga di testo" + }, + "title": "Titolo", + "yes_no": { + "default": "Valore predefinito", + "name": "Si No" + } +} diff --git a/ui/locales/it/user.json b/ui/locales/it/user.json new file mode 100644 index 00000000..7ad9ddee --- /dev/null +++ b/ui/locales/it/user.json @@ -0,0 +1,17 @@ +{ + "baseData": "Dati di base", + "confirmDelete": "Sei sicuro di eliminare questo utente?", + "deleteError": "impossibile eliminare l'utente", + "deleteNow": "Cancella ora!", + "deleted": "Utente cancellato", + "loading": "Caricamento utente", + "mange": "Modifica utente \" {{email}} \"", + "row": { + "created": "Creato", + "email": "E-mail", + "roles": "Ruolo" + }, + "updateError": "Impossibile aggiornare l'utente", + "updateNow": "Salva", + "updated": "Utente aggiornato" +} diff --git a/ui/locales/it/validation.json b/ui/locales/it/validation.json new file mode 100644 index 00000000..46daa835 --- /dev/null +++ b/ui/locales/it/validation.json @@ -0,0 +1,15 @@ +{ + "emailFieldRequired": "Seleziona un campo e-mail", + "emailRequired": "Si prega di fornire una e-mail", + "invalidEmail": "Deve essere un'e-mail valida!", + "invalidUrl": "Deve essere un URL valido", + "languageRequired": "Seleziona una lingua", + "mandatoryFieldsMissing": "Campi obbligatori mancanti", + "passwordMinLength": "Deve essere più lungo o uguale a 5 caratteri!", + "passwordRequired": "Per favore inserisci la tua password!", + "subjectRequired": "Si prega di fornire un argomento", + "templateRequired": "Si prega di fornire un modello", + "titleRequired": "Si prega di fornire un titolo", + "usernameRequired": "Fornisci un nome utente", + "valueRequired": "Si prega di fornire un valore" +} diff --git a/ui/locales/ja/admin.json b/ui/locales/ja/admin.json new file mode 100644 index 00000000..8d03153f --- /dev/null +++ b/ui/locales/ja/admin.json @@ -0,0 +1,9 @@ +{ + "administration": "管理", + "forms": "フォーム", + "home": "ホーム", + "profile": "プロフィール", + "submissions": "回答", + "username": "ユーザー名", + "users": "ユーザー" +} diff --git a/ui/locales/ja/common.json b/ui/locales/ja/common.json new file mode 100644 index 00000000..ff9ca907 --- /dev/null +++ b/ui/locales/ja/common.json @@ -0,0 +1,10 @@ +{ + "admin": "管理", + "checkingCredentials": "認証を確認しています", + "loadingCredentials": "認証情報を読み込んでいます", + "login": "ログイン", + "logout": "ログアウト", + "profile": "プロフィール", + "recover": "パスワードを忘れた場合", + "register": "アカウント作成" +} diff --git a/ui/locales/ja/form.json b/ui/locales/ja/form.json new file mode 100644 index 00000000..f04d8432 --- /dev/null +++ b/ui/locales/ja/form.json @@ -0,0 +1,120 @@ +{ + "baseData": { + "isLive": "受付中", + "language": "言語", + "showFooter": "フッターを表示", + "title": "題名" + }, + "baseDataTab": "基本データ", + "building": "フォーム作成中", + "confirmDelete": "このフォームをすべての回答とともに削除します。よろしいですか?", + "continue": "続ける", + "create": "新規フォームの作成", + "createNow": "保存", + "created": "フォームを作成しました", + "creationError": "フォームの作成でエラー", + "deleteError": "フォームの削除でエラー", + "deleteNow": "すぐに削除!", + "deleted": "フォームを削除しました", + "design": { + "color": { + "answer": "回答の色", + "background": "背景色", + "button": "ボタン色", + "buttonActive": "アクティブなボタン色", + "buttonText": "ボタンテキスト色", + "question": "質問の色" + }, + "font": "フォント", + "layout": { + "card": "カード", + "slider": "スライド" + }, + "layouts": "レイアウト" + }, + "designTab": "デザイン", + "endPage": { + "action": "アクション", + "activeColor": "アクティブ色", + "addButton": "ボタンを追加する", + "bgColor": "背景色", + "buttons": "ボタン", + "color": "色", + "continueButtonText": "Continue ボタンのテキスト", + "paragraph": "段落", + "paragraphInfo": "markdown を使えば詳細な書式を設定できます", + "show": "表示する", + "text": "テキスト", + "title": "タイトル", + "url": "URL" + }, + "endPageTab": "終了ページ", + "fieldsTab": "フォームの項目", + "hooks": { + "add": "追加する", + "confirmDelete": "削除します。よろしいですか?", + "deleteNow": "すぐに削除", + "enabled": "有効" + }, + "hooksTab": "WebHook", + "loading": "フォームを読み込んでいます", + "logic": { + "action": { + "disable": "無効に", + "jumpTo": "ジャンプ先", + "require": "必須", + "visible": "表示" + }, + "add": "ロジックを追加" + }, + "mange": "「{{title}}」のフォームを編集", + "new": "新規フォーム", + "next": "次", + "notifications": { + "add": "通知を追加", + "enabled": "有効", + "fromEmail": "送信者メールアドレス", + "fromEmailInfo": "お使いのメールサーバーがこのメールからの送信ができることを確認すること", + "fromField": "送信者アドレス項目", + "fromFieldInfo": "メールにReply-To(返信先)として設定するアドレスのフォーム項目", + "htmlTemplate": "HTML テンプレート", + "htmlTemplateInfo": "メールテンプレートには、<u>MJML<\/u> も使えます", + "subject": "件名", + "toEmail": "受信者アドレス", + "toEmailInfo": "設定しなければ、このフォームの作成者のメールアドレスに送信します", + "toField": "受信者メールアドレスの項目", + "toFieldInfo": "回答受け付けメールの送信先アドレスとして利用するフォームの項目" + }, + "notificationsTab": "通知", + "previous": "前", + "restart": "最初から", + "row": { + "admin": "オーナー", + "created": "作成", + "isLive": "受付中", + "language": "言語", + "lastModified": "最終更新", + "menu": "メニュー", + "title": "題名" + }, + "startPage": { + "action": "アクション", + "activeColor": "アクティブ色", + "addButton": "ボタンを追加する", + "bgColor": "背景色", + "buttons": "ボタン", + "color": "色", + "continueButtonText": "Continue ボタンのテキスト", + "paragraph": "段落", + "paragraphInfo": "markdown を使えば詳細な書式を設定できます", + "show": "表示する", + "text": "テキスト", + "title": "タイトル", + "url": "URL" + }, + "startPageTab": "開始ページ", + "submitted": "回答ありがとうございます。", + "updateError": "フォームの更新でエラー", + "updateNow": "保存", + "updated": "フォームを更新しました" +} diff --git a/ui/locales/ja/index.ts b/ui/locales/ja/index.ts new file mode 100644 index 00000000..b05c0280 --- /dev/null +++ b/ui/locales/ja/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const ja = { + admin, + common, + form, + language, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/ja/language.json b/ui/locales/ja/language.json new file mode 100644 index 00000000..5203f0fd --- /dev/null +++ b/ui/locales/ja/language.json @@ -0,0 +1,12 @@ +{ + "cn": "繁体字中国語", + "de": "ドイツ語", + "en": "英語", + "es": "スペイン語", + "fr": "フランス語", + "it": "イタリア語", + "ja": "日本語", + "pl": "ポーランド語", + "pt": "ポルトガル語", + "ru": "ロシア語" +} diff --git a/ui/locales/ja/login.json b/ui/locales/ja/login.json new file mode 100644 index 00000000..1263abaa --- /dev/null +++ b/ui/locales/ja/login.json @@ -0,0 +1,8 @@ +{ + "invalidLoginCredentials": "ユーザー名またはパスワードが無効です", + "loginNow": "ログイン", + "note": "メモ", + "passwordPlaceholder": "パスワード", + "usernamePlaceholder": "ユーザー名", + "welcomeBack": "お帰りなさい!" +} diff --git a/ui/locales/ja/profile.json b/ui/locales/ja/profile.json new file mode 100644 index 00000000..8cd1e162 --- /dev/null +++ b/ui/locales/ja/profile.json @@ -0,0 +1,12 @@ +{ + "confirmPassword": "パスワードの確認", + "email": "メール", + "firstName": "姓", + "language": "言語", + "lastName": "名", + "password": "パスワード", + "updateError": "プロフィールの更新でエラー", + "updateNow": "保存", + "updated": "プロフィールを更新しました", + "username": "ユーザー名" +} diff --git a/ui/locales/ja/register.json b/ui/locales/ja/register.json new file mode 100644 index 00000000..f402088e --- /dev/null +++ b/ui/locales/ja/register.json @@ -0,0 +1,6 @@ +{ + "credentialsAlreadyInUse": "データのいくつかがすでに使われているものです", + "gotoLogin": "アカウントをお持ちですか? ログインをご利用ください", + "registerNow": "登録する", + "welcome": "ようこそ。メールもご確認ください。" +} diff --git a/ui/locales/ja/statistic.json b/ui/locales/ja/statistic.json new file mode 100644 index 00000000..14d95c00 --- /dev/null +++ b/ui/locales/ja/statistic.json @@ -0,0 +1,5 @@ +{ + "totalForms": "すべてのフォーム数", + "totalSubmissions": "すべての回答数", + "totalUsers": "ユーザー数" +} diff --git a/ui/locales/ja/submission.json b/ui/locales/ja/submission.json new file mode 100644 index 00000000..7e74d691 --- /dev/null +++ b/ui/locales/ja/submission.json @@ -0,0 +1,17 @@ +{ + "add": "回答を追加する", + "city": "市区町村", + "country": "国", + "created": "作成", + "device": { + "name": "デバイス名", + "type": "デバイスの種類" + }, + "edit": "編集", + "export": "出力", + "field": "項目", + "lastModified": "最終更新", + "progress": "進行状況", + "submission": "回答", + "value": "値" +} diff --git a/ui/locales/ja/type.json b/ui/locales/ja/type.json new file mode 100644 index 00000000..e2216728 --- /dev/null +++ b/ui/locales/ja/type.json @@ -0,0 +1,76 @@ +{ + "add": "項目を追加する", + "confirmDelete": "このフィールドを削除します。他から参照されていないことを確認してください。削除してよろしいですか?", + "date": { + "default": "既定の日付", + "max": "最大日付", + "min": "最小日付", + "name": "日付" + }, + "deleteNow": "項目を削除する", + "description": "説明", + "descriptionInfo": "markdown を使えば詳細な書式を設定できます", + "dropdown": { + "addOption": "選択肢を追加", + "default": "既定の値", + "name": "ドロップダウン", + "options": "選択肢", + "removeOption": "削除", + "titlePlaceholder": "表示名", + "valuePlaceholder": "値" + }, + "email": { + "default": "既定のメールアドレス", + "name": "メールアドレス" + }, + "hidden": { + "default": "既定の値", + "name": "非表示" + }, + "link": { + "default": "既定のリンク", + "name": "URL" + }, + "number": { + "default": "既定の値", + "name": "数" + }, + "radio": { + "addOption": "選択肢を追加", + "default": "既定の値", + "name": "ラジオボタン", + "options": "選択肢", + "removeOption": "削除する", + "titlePlaceholder": "表示名", + "valuePlaceholder": "値" + }, + "rating": { + "clearNote": "既定の値をリセットするには、再度クリック", + "default": "既定の値", + "name": "評価" + }, + "required": "必須項目", + "requiredInfo": "ユーザーが回答を送信できるよう、必要に応じて既定の値を設定する必要があります。", + "slider": { + "default": "既定の値", + "max": "最大値", + "min": "最小値", + "name": "スライド", + "step": "ステップの大きさ" + }, + "slug": "スラッグ(Slug)", + "slugInfo": "URLのパラメーターで値を設定するためにスラッグ(Slug)を利用できます ?slug=value", + "textarea": { + "default": "既定の値", + "name": "テキストエリア" + }, + "textfield": { + "default": "既定の値", + "name": "テキスト行" + }, + "title": "項目名", + "yes_no": { + "default": "既定の値", + "name": "はい・いいえ" + } +} diff --git a/ui/locales/ja/user.json b/ui/locales/ja/user.json new file mode 100644 index 00000000..c672219c --- /dev/null +++ b/ui/locales/ja/user.json @@ -0,0 +1,18 @@ +{ + "baseData": "基本データ", + "confirmDelete": "このユーザーを削除します。よろしいですか?", + "deleteError": "ユーザーの削除でエラー", + "deleteNow": "すぐに削除", + "deleted": "ユーザーを削除しました", + "loading": "ユーザーを読み込んでいます", + "mange": "「{{email}}」ユーザーの編集", + "row": { + "created": "作成", + "email": "メールアドレス", + "menu": "メニュー", + "roles": "権限" + }, + "updateError": "ユーザー情報の更新でエラー", + "updateNow": "保存", + "updated": "ユーザー情報を更新しました" +} diff --git a/ui/locales/ja/validation.json b/ui/locales/ja/validation.json new file mode 100644 index 00000000..94dc45d8 --- /dev/null +++ b/ui/locales/ja/validation.json @@ -0,0 +1,20 @@ +{ + "emailFieldRequired": "メールアドレスの項目を選んでください", + "emailRequired": "メールアドレスを入力してください", + "invalidEmail": "有効なメールアドレスではありません!", + "invalidNumber": "数字として認識できません!", + "invalidSlug": "スラッグ(Slug)では、小文字の a-z、 0-9 そして _ だけしか使えません", + "invalidUrl": "有効な URL ではありません", + "languageRequired": "言語を選んでください", + "mandatoryFieldsMissing": "必要な項目が入力されていません", + "passwordConfirmMismatch": "入力した2つのパスワードが一致しません!", + "passwordConfirmRequired": "パスワードを確認してください。", + "passwordMinLength": "5 文字以上を入力してください!", + "passwordRequired": "パスワードを入力してください!", + "subjectRequired": "件名を入力してください", + "templateRequired": "テンプレートを入力してください", + "titleRequired": "項目名を入力してください", + "urlRequired": "URL を入力してください", + "usernameRequired": "ユーザー名を入力してください", + "valueRequired": "値を入力してください" +} diff --git a/ui/locales/missing.ts b/ui/locales/missing.ts new file mode 100644 index 00000000..fecb3987 --- /dev/null +++ b/ui/locales/missing.ts @@ -0,0 +1,78 @@ +const { readFileSync } = require('fs'); +const glob = require('glob'); +const { program } = require('commander'); +const merge = require('lodash.merge'); + +const dirs: string[] = [] + +program.version('1.0.0'); +program.arguments('<limit>') + .action((limit) => { + dirs.push( + ...limit + .split(',') + .map(l => `locales/${l}/`) + ) + }) + .option('-l, --limit <limit>', 'check only given languages') + .parse(process.argv); + +let all = {} + +glob.sync('locales/**/*.json').forEach(file => { + try { + const original = JSON.parse(readFileSync(file).toString('utf-8')) + + all = merge( + all, + { + [file.replace(/^.*\/([a-z]+)\.json$/, '$1')]: original, + } + ) + } catch (e) { + console.error('could not process file', file, e) + } +}) + +const compare = (original, compareTo, path, file: string) => { + const oKeys = Object.keys(original) + const aKeys = Object.keys(compareTo) + + const missing = aKeys.filter(k => !oKeys.includes(k)) + + missing.forEach(k => { + console.log(`MISSING ${file} > ${[...path, k].join('.')}`) + }) + + oKeys.forEach(k => { + if (typeof original[k] === 'object') { + compare(original[k], compareTo[k], [...path, k], file) + } + }) +} + +dirs.forEach(dir => { + const files: string[] = glob.sync(`${dir}*.json`) + + const existingFiles: string[] = files.map(file => file.replace(/^.*\/([a-z]+)\.json$/, '$1')) + Object + .keys(all) + .filter(file => !existingFiles.includes(file)) + .forEach(file => { + console.log(`MISSING ${dir}${file}.json`) + }) + + files.forEach(file => { + try { + compare( + JSON.parse(readFileSync(file).toString('utf-8')), + all[file.replace(/^.*\/([a-z]+)\.json$/, '$1')], + [], + file + ) + } catch (e) { + console.error('could not process file', file, e) + } + }) +}) + diff --git a/ui/locales/nl/admin.json b/ui/locales/nl/admin.json new file mode 100644 index 00000000..814ab050 --- /dev/null +++ b/ui/locales/nl/admin.json @@ -0,0 +1,8 @@ +{ + "administration": "Administratie", + "forms": "Formulieren", + "profile": "Profil", + "submissions": "Inzendingen", + "username": "Gebruikersnaam", + "users": "Gebruikers" +} diff --git a/ui/locales/nl/common.json b/ui/locales/nl/common.json new file mode 100644 index 00000000..a23bec3d --- /dev/null +++ b/ui/locales/nl/common.json @@ -0,0 +1,8 @@ +{ + "loadingCredentials": "Inloggegevens laden", + "login": "Inloggen", + "logout": "Uitloggen", + "profile": "Profil", + "recover": "Wachtwoord vergeten", + "register": "Account aanmaken" +} diff --git a/ui/locales/nl/form.json b/ui/locales/nl/form.json new file mode 100644 index 00000000..cee3fab6 --- /dev/null +++ b/ui/locales/nl/form.json @@ -0,0 +1,25 @@ +{ + "continue": "Ga door", + "design": { + "layout": { + "card": "Kaart" + } + }, + "fieldsTab": "Formuliervelden", + "hooks": { + "add": "Toevoegen", + "enabled": "Ingeschakeld" + }, + "logic": { + "add": "Logica toevoegen" + }, + "next": "Volgende", + "notifications": { + "add": "Melding toevoegen" + }, + "notificationsTab": "Meldingen", + "previous": "Vorige", + "startPage": { + "paragraphInfo": "Gebruik markdown voor geavanceerde opmaak" + } +} diff --git a/ui/locales/nl/index.ts b/ui/locales/nl/index.ts new file mode 100644 index 00000000..eeee2ebc --- /dev/null +++ b/ui/locales/nl/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const nl = { + language, + admin, + common, + form, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/nl/language.json b/ui/locales/nl/language.json new file mode 100644 index 00000000..097daa3e --- /dev/null +++ b/ui/locales/nl/language.json @@ -0,0 +1,11 @@ +{ + "cn": "繁體中文", + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "pl": "Polski", + "pt": "Português", + "ru": "русский" +} diff --git a/ui/locales/nl/login.json b/ui/locales/nl/login.json new file mode 100644 index 00000000..5941c3be --- /dev/null +++ b/ui/locales/nl/login.json @@ -0,0 +1,6 @@ +{ + "invalidLoginCredentials": "gebruikersnaam \/ wachtwoord zijn ongeldig", + "passwordPlaceholder": "Wachtwoord", + "usernamePlaceholder": "Gebruikersnaam", + "welcomeBack": "Welkom terug!" +} diff --git a/ui/locales/nl/profile.json b/ui/locales/nl/profile.json new file mode 100644 index 00000000..16c0fc13 --- /dev/null +++ b/ui/locales/nl/profile.json @@ -0,0 +1,10 @@ +{ + "confirmPassword": "Bevestig wachtwoord", + "email": "E-mail", + "firstName": "Voornaam", + "language": "Taal", + "lastName": "Achternaam", + "password": "Wachtwoord", + "updated": "Profiel bijgewerkt", + "username": "Gebruikersnaam" +} diff --git a/ui/locales/nl/register.json b/ui/locales/nl/register.json new file mode 100644 index 00000000..281d38d9 --- /dev/null +++ b/ui/locales/nl/register.json @@ -0,0 +1,5 @@ +{ + "credentialsAlreadyInUse": "Sommige gegevens zijn al in gebruik!", + "registerNow": "Registreer nu", + "welcome": "Welkom, bevestig ook uw email" +} diff --git a/ui/locales/nl/statistic.json b/ui/locales/nl/statistic.json new file mode 100644 index 00000000..841864ce --- /dev/null +++ b/ui/locales/nl/statistic.json @@ -0,0 +1,5 @@ +{ + "totalForms": "Totaal aantal formulieren", + "totalSubmissions": "Totaal aantal inzendingen", + "totalUsers": "Totaal aantal gebruikers" +} diff --git a/ui/locales/nl/submission.json b/ui/locales/nl/submission.json new file mode 100644 index 00000000..71a3f80b --- /dev/null +++ b/ui/locales/nl/submission.json @@ -0,0 +1,13 @@ +{ + "add": "Inzending toevoegen", + "city": "Stad", + "country": "Land", + "created": "Gemaakt", + "device": { + "type": "Type apparaat" + }, + "edit": "Bewerken", + "field": "Veld", + "lastModified": "Laatste wijziging", + "value": "Waarde" +} diff --git a/ui/locales/nl/type.json b/ui/locales/nl/type.json new file mode 100644 index 00000000..4b9588bb --- /dev/null +++ b/ui/locales/nl/type.json @@ -0,0 +1,38 @@ +{ + "add": "Veld toevoegen", + "confirmDelete": "Dit veld echt verwijderen? Controleer of er nergens naar verwezen wordt!", + "deleteNow": "Veld verwijderen", + "descriptionInfo": "Gebruik markdown voor geavanceerde opmaak", + "email": { + "name": "E-mail" + }, + "hidden": { + "default": "Standaardwaarde" + }, + "radio": { + "addOption": "Optie toevoegen", + "default": "Standaardwaarde", + "titlePlaceholder": "Titel", + "valuePlaceholder": "Waarde" + }, + "rating": { + "default": "Standaardwaarde" + }, + "slider": { + "default": "Standaardwaarde", + "name": "Schuifregelaar", + "step": "Stapgrootte" + }, + "textarea": { + "default": "Standaardwaarde", + "name": "Tekstgebied" + }, + "textfield": { + "default": "Standaardwaarde" + }, + "title": "Titel", + "yes_no": { + "default": "Standaardwaarde", + "name": "Ja \/ Nee" + } +} diff --git a/ui/locales/nl/user.json b/ui/locales/nl/user.json new file mode 100644 index 00000000..3ceb99db --- /dev/null +++ b/ui/locales/nl/user.json @@ -0,0 +1,15 @@ +{ + "baseData": "Basisgegevens", + "confirmDelete": "Weet je zeker dat je deze gebruiker verwijdert?", + "deleteError": "kon gebruiker niet verwijderen", + "deleteNow": "Verwijder nu!", + "deleted": "Gebruiker verwijderd", + "loading": "Gebruiker laden", + "mange": "Gebruiker bewerken \" {{email}} \"", + "row": { + "created": "Gemaakt", + "email": "E-mail", + "roles": "Rol" + }, + "updated": "Gebruiker bijgewerkt" +} diff --git a/ui/locales/nl/validation.json b/ui/locales/nl/validation.json new file mode 100644 index 00000000..44f3a5a2 --- /dev/null +++ b/ui/locales/nl/validation.json @@ -0,0 +1,18 @@ +{ + "emailFieldRequired": "Selecteer een e-mail veld", + "emailRequired": "Geef een e-mail", + "invalidEmail": "Moet een geldig e-mailadres zijn!", + "invalidNumber": "Moet een geldig nummer zijn!", + "invalidUrl": "Moet een geldige URL zijn", + "languageRequired": "Selecteer een taal", + "mandatoryFieldsMissing": "Verplichte velden ontbreken", + "passwordConfirmRequired": "Bevestig uw wachtwoord!", + "passwordMinLength": "Moet langer zijn dan of gelijk zijn aan 5 tekens!", + "passwordRequired": "Voer uw wachtwoord in!", + "subjectRequired": "Geef een onderwerp", + "templateRequired": "Geef een sjabloon", + "titleRequired": "Geef een titel op", + "urlRequired": "Geef een Url", + "usernameRequired": "Geef een gebruikersnaam op", + "valueRequired": "Geef een waarde" +} diff --git a/ui/locales/pl/admin.json b/ui/locales/pl/admin.json new file mode 100644 index 00000000..46dc5acd --- /dev/null +++ b/ui/locales/pl/admin.json @@ -0,0 +1,9 @@ +{ + "administration": "Zarządzanie", + "forms": "Formularze", + "home": "Dom", + "profile": "Profil", + "submissions": "Zgłoszenia", + "username": "Nazwa Użytkownika", + "users": "Użytkownicy" +} diff --git a/ui/locales/pl/common.json b/ui/locales/pl/common.json new file mode 100644 index 00000000..c1f6808b --- /dev/null +++ b/ui/locales/pl/common.json @@ -0,0 +1,10 @@ +{ + "admin": "Admin", + "checkingCredentials": "Sprawdzanie poświadczeń", + "loadingCredentials": "Ładowanie poświadczeń", + "login": "Zaloguj się", + "logout": "Wyloguj", + "profile": "Profil", + "recover": "Zapomniałem hasła", + "register": "Utwórz konto" +} diff --git a/ui/locales/pl/form.json b/ui/locales/pl/form.json new file mode 100644 index 00000000..c08b6bda --- /dev/null +++ b/ui/locales/pl/form.json @@ -0,0 +1,111 @@ +{ + "baseData": { + "isLive": "Jest na żywo", + "language": "Język", + "showFooter": "Pokaż stopkę", + "title": "Tytuł" + }, + "baseDataTab": "Dane podstawowe", + "building": "Formularz budowlany", + "confirmDelete": "Czy na pewno usuniesz ten formularz ze wszystkimi zgłoszeniami?", + "continue": "Kontynuuj", + "create": "Utwórz nowy formularz", + "createNow": "Zapisać", + "created": "Formularz utworzony", + "creationError": "Nie można utworzyć formularza", + "deleteError": "Nie można usunąć formularza", + "deleteNow": "Usuń teraz!", + "deleted": "Formularz usunięty", + "design": { + "color": { + "answer": "Kolor odpowiedzi", + "background": "Kolor tła", + "button": "Kolor przycisku", + "buttonActive": "Przycisk Aktywny kolor", + "buttonText": "Kolor tekstu przycisku", + "question": "Kolor pytania" + }, + "font": "Czcionka", + "layout": { + "card": "Karta", + "slider": "Slider" + }, + "layouts": "Wygląd" + }, + "designTab": "Projekt", + "endPage": { + "action": "Akcja", + "activeColor": "Aktywny kolor", + "addButton": "Dodaj przycisk", + "bgColor": "Kolor tła", + "buttons": "guziki", + "color": "Kolor", + "continueButtonText": "Tekst przycisku Kontynuuj", + "paragraph": "Ustęp", + "show": "Pokazać", + "text": "Tekst", + "title": "Tytuł", + "url": "URL" + }, + "endPageTab": "Strona końcowa", + "fieldsTab": "Pola formularza", + "hooks": { + "add": "Dodaj", + "confirmDelete": "Pusty", + "deleteNow": "Pusty", + "enabled": "Aktywny" + }, + "hooksTab": "WebHooki", + "loading": "Ładowanie formularza", + "logic": { + "add": "Dodaj logikę" + }, + "mange": "Edytuj formularz „ {{title}} ”", + "new": "Nowa forma", + "next": "Dalej", + "notifications": { + "add": "Dodaj powiadomienie", + "enabled": "Włączone", + "fromEmail": "E-mail nadawcy", + "fromEmailInfo": "Upewnij się, że Twój serwer pocztowy może wysyłać z tego e-maila", + "fromField": "E-mail nadawcy", + "fromFieldInfo": "Pole z e-mailem ustawi nagłówek odpowiedzi", + "htmlTemplate": "Szablon HTML", + "htmlTemplateInfo": "Możesz również użyć <u> MJML <\/u> aby utworzyć szablony e-mail", + "subject": "Przedmiot", + "toEmail": "Twój email", + "toEmailInfo": "Jeśli nie ustawione, wyśle do administratora formularza", + "toField": "Pole e-mail", + "toFieldInfo": "Pole z adresem e-mail do odbioru" + }, + "notificationsTab": "Powiadomienia", + "previous": "Poprzedni", + "restart": "Uruchom ponownie formularz", + "row": { + "admin": "Właściciel", + "created": "Utworzony", + "isLive": "Relacja na żywo", + "language": "Język", + "lastModified": "Ostatnio zmodyfikowany", + "title": "Tytuł" + }, + "startPage": { + "action": "Akcja", + "activeColor": "Aktywny kolor", + "addButton": "Dodaj przycisk", + "bgColor": "Kolor tła", + "buttons": "guziki", + "color": "Kolor", + "continueButtonText": "Tekst przycisku Kontynuuj", + "paragraph": "Ustęp", + "show": "Pokazać", + "text": "Tekst", + "title": "Tytuł", + "url": "URL" + }, + "startPageTab": "Strona startowa", + "submitted": "Dziękujemy za zgłoszenie!", + "updateError": "Nie można zaktualizować formularza", + "updateNow": "Zapisać", + "updated": "Formularz zaktualizowany" +} diff --git a/ui/locales/pl/index.ts b/ui/locales/pl/index.ts new file mode 100644 index 00000000..05bb27a5 --- /dev/null +++ b/ui/locales/pl/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const pl = { + admin, + common, + form, + language, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/pl/language.json b/ui/locales/pl/language.json new file mode 100644 index 00000000..c83c1bdf --- /dev/null +++ b/ui/locales/pl/language.json @@ -0,0 +1,12 @@ +{ + "cn": "繁體中文", + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "ja": "Pusty", + "pl": "Polski", + "pt": "Português", + "ru": "русский" +} diff --git a/ui/locales/pl/login.json b/ui/locales/pl/login.json new file mode 100644 index 00000000..d755ce02 --- /dev/null +++ b/ui/locales/pl/login.json @@ -0,0 +1,8 @@ +{ + "invalidLoginCredentials": "nazwa użytkownika \/ hasło są nieprawidłowe", + "loginNow": "Zaloguj się teraz", + "note": "Notatka", + "passwordPlaceholder": "Hasło", + "usernamePlaceholder": "Nazwa Użytkownika", + "welcomeBack": "Witamy z powrotem!" +} diff --git a/ui/locales/pl/profile.json b/ui/locales/pl/profile.json new file mode 100644 index 00000000..a797f6be --- /dev/null +++ b/ui/locales/pl/profile.json @@ -0,0 +1,12 @@ +{ + "confirmPassword": "Powtórz Hasło", + "email": "E-mail", + "firstName": "Imię", + "language": "Język", + "lastName": "Nazwisko", + "password": "Hasło", + "updateError": "Nie można zaktualizować profilu", + "updateNow": "Zapisz", + "updated": "Profil zaktualizowany", + "username": "Nazwa Użytkownika" +} diff --git a/ui/locales/pl/register.json b/ui/locales/pl/register.json new file mode 100644 index 00000000..86c7d351 --- /dev/null +++ b/ui/locales/pl/register.json @@ -0,0 +1,6 @@ +{ + "credentialsAlreadyInUse": "Niektóre dane są już w użyciu!", + "gotoLogin": "Masz już konto? Zaloguj się", + "registerNow": "Zarejestruj się teraz", + "welcome": "Witamy, proszę potwierdzić swój adres e-mail" +} diff --git a/ui/locales/pl/statistic.json b/ui/locales/pl/statistic.json new file mode 100644 index 00000000..9bbb2fb6 --- /dev/null +++ b/ui/locales/pl/statistic.json @@ -0,0 +1,5 @@ +{ + "totalForms": "Formularze ogółem", + "totalSubmissions": "Wszystkich zgłoszeń", + "totalUsers": "Wszystkich użytkowników" +} diff --git a/ui/locales/pl/submission.json b/ui/locales/pl/submission.json new file mode 100644 index 00000000..aa206f02 --- /dev/null +++ b/ui/locales/pl/submission.json @@ -0,0 +1,17 @@ +{ + "add": "Dodaj zgłoszenie", + "city": "Miasto", + "country": "Kraj", + "created": "Utworzony", + "device": { + "name": "Nazwa urządzenia", + "type": "Rodzaj urządzenia" + }, + "edit": "Edytuj", + "export": "Exportuj", + "field": "Pole", + "lastModified": "Ostatnia zmiana", + "progress": "Postęp", + "submission": "Zgłoszenie", + "value": "Wartość" +} diff --git a/ui/locales/pl/type.json b/ui/locales/pl/type.json new file mode 100644 index 00000000..f303d0ce --- /dev/null +++ b/ui/locales/pl/type.json @@ -0,0 +1,73 @@ +{ + "add": "Dodaj pole", + "confirmDelete": "Czy naprawdę chcesz usunąć to pole? Sprawdź, czy nigdzie się nie odwołuje!", + "date": { + "default": "Domyślna data", + "max": "Maksymalna data", + "min": "Min. Data", + "name": "Data" + }, + "deleteNow": "Usuń pole", + "description": "Opis", + "dropdown": { + "addOption": "Dodaj opcję", + "default": "Domyślna wartość", + "name": "Upuścić", + "options": "Opcje", + "removeOption": "Usunąć", + "titlePlaceholder": "Tytuł", + "valuePlaceholder": "Wartość" + }, + "email": { + "default": "Domyślny adres e-mail", + "name": "E-mail" + }, + "hidden": { + "default": "Domyślna wartość", + "name": "Ukryty" + }, + "link": { + "default": "Domyślny link", + "name": "URL" + }, + "number": { + "default": "Domyślny numer", + "name": "Numer" + }, + "radio": { + "addOption": "Dodaj opcję", + "default": "Domyślna wartość", + "name": "Przełącznik radiowy", + "options": "Opcje", + "removeOption": "Usunąć", + "titlePlaceholder": "Tytuł", + "valuePlaceholder": "Wartość" + }, + "rating": { + "clearNote": "Kliknij ponownie, aby usunąć wartość domyślną", + "default": "Domyślna wartość", + "name": "Ocena" + }, + "required": "wymagany", + "requiredInfo": "W razie potrzeby należy ustawić wartość domyślną, aby umożliwić użytkownikom przesłanie formularza!", + "slider": { + "default": "Domyślna wartość", + "max": "Maksymalna wartość", + "min": "Minimalna wartość", + "name": "Slider", + "step": "Rozdzielczość " + }, + "textarea": { + "default": "Domyślna wartość", + "name": "Obszar tekstowy" + }, + "textfield": { + "default": "Domyślna wartość", + "name": "Linia tekstu" + }, + "title": "Tytuł", + "yes_no": { + "default": "Domyślna wartość", + "name": "Tak nie" + } +} diff --git a/ui/locales/pl/user.json b/ui/locales/pl/user.json new file mode 100644 index 00000000..5f49aa15 --- /dev/null +++ b/ui/locales/pl/user.json @@ -0,0 +1,18 @@ +{ + "baseData": "Dane podstawowe", + "confirmDelete": "Czy na pewno chcesz usunąć tego użytkownika?", + "deleteError": "nie można usunąć użytkownika", + "deleteNow": "Usuń teraz!", + "deleted": "Usunięto użytkownika", + "loading": "Ładowanie użytkownika", + "mange": "Edytuj użytkownika „ {{email}} ”", + "row": { + "created": "Utworzono", + "email": "E-mail", + "menu": "Pusty", + "roles": "Rola" + }, + "updateError": "Nie można zaktualizować użytkownika", + "updateNow": "Zapisz", + "updated": "Użytkownik zaktualizowany" +} diff --git a/ui/locales/pl/validation.json b/ui/locales/pl/validation.json new file mode 100644 index 00000000..17808c42 --- /dev/null +++ b/ui/locales/pl/validation.json @@ -0,0 +1,18 @@ +{ + "emailFieldRequired": "Wybierz pole e-mail", + "emailRequired": "Proszę podać e-mail", + "invalidEmail": "Musi być prawidłowym adresem e-mail!", + "invalidNumber": "Podaj poprawną liczbę!", + "invalidUrl": "Musi być prawidłowym adresem URL", + "languageRequired": "Proszę wybierz język", + "mandatoryFieldsMissing": "Brak pól obowiązkowych", + "passwordConfirmMismatch": "Hasła się nie zgadzają!", + "passwordConfirmRequired": "Proszę powtórz swoje hasło!", + "passwordMinLength": "Musi być równy lub dłuższy niż 5 znaków.", + "passwordRequired": "Proszę podać hasło!", + "subjectRequired": "Podaj temat", + "templateRequired": "Proszę podać szablon", + "titleRequired": "Proszę podać tytuł", + "usernameRequired": "Podaj nazwę użytkownika", + "valueRequired": "Podaj wartość" +} diff --git a/ui/locales/pt_BR/admin.json b/ui/locales/pt_BR/admin.json new file mode 100644 index 00000000..30f3658c --- /dev/null +++ b/ui/locales/pt_BR/admin.json @@ -0,0 +1,9 @@ +{ + "administration": "Administração", + "forms": "Formulários", + "home": "Casa", + "profile": "Perfil", + "submissions": "Submissões", + "username": "Nome do usuário", + "users": "Comercial" +} diff --git a/ui/locales/pt_BR/common.json b/ui/locales/pt_BR/common.json new file mode 100644 index 00000000..186d6dcb --- /dev/null +++ b/ui/locales/pt_BR/common.json @@ -0,0 +1,9 @@ +{ + "admin": "Admin", + "checkingCredentials": "Verificando credenciais", + "loadingCredentials": "Carregando credenciais", + "login": "Conecte-se", + "logout": "Sair", + "recover": "Senha perdida", + "register": "Criar Conta" +} diff --git a/ui/locales/pt_BR/form.json b/ui/locales/pt_BR/form.json new file mode 100644 index 00000000..7f1a57a7 --- /dev/null +++ b/ui/locales/pt_BR/form.json @@ -0,0 +1,98 @@ +{ + "baseData": { + "isLive": "Está vivo", + "language": "Língua", + "showFooter": "Mostrar rodapé", + "title": "Título" + }, + "baseDataTab": "Dados Base", + "building": "Formulário de construção", + "confirmDelete": "Tem certeza de que excluiu este formulário com todos os envios?", + "create": "Criar novo formulário", + "createNow": "Salve ", + "created": "Formulário criado", + "creationError": "Não foi possível criar o formulário", + "deleteError": "Não foi possível excluir o formulário", + "deleteNow": "Excluir agora!", + "deleted": "Formulário excluído", + "design": { + "color": { + "answer": "Cor da resposta", + "background": "Cor de fundo", + "button": "Cor do botao", + "buttonActive": "Cor ativa do botão", + "buttonText": "Cor do texto do botão", + "question": "Pergunta Color" + }, + "font": "Fonte" + }, + "designTab": "Projeto", + "endPage": { + "action": "Açao", + "activeColor": "Cor ativa", + "addButton": "Botão Adicionar", + "bgColor": "Cor de fundo", + "buttons": "Botões", + "color": "Cor", + "continueButtonText": "Texto do botão Continuar", + "paragraph": "Parágrafo", + "paragraphInfo": "Use markdown para formatação avançada", + "show": "exposição", + "text": "Texto", + "title": "Título", + "url": "URL" + }, + "endPageTab": "Página final", + "fieldsTab": "Campos do Formulário", + "hooks": { + "add": "Adicionar", + "deleteNow": "Vazio", + "enabled": "Habilitado" + }, + "loading": "Carregando Formulário", + "mange": "Editar formulário \" {{title}} \"", + "new": "Nova forma", + "notifications": { + "enabled": "ativado", + "fromEmail": "E-mail do remetente", + "fromEmailInfo": "Verifique se o seu servidor de e-mail pode enviar deste e-mail", + "fromField": "E-mail do remetente", + "fromFieldInfo": "Campo com email, definirá o cabeçalho de resposta a", + "htmlTemplate": "Modelo HTML", + "htmlTemplateInfo": "Você também pode usar o <u> MJML <\/u> para criar seus modelos de email", + "subject": "Sujeito", + "toEmail": "Seu email", + "toEmailInfo": "Se não definido, será enviado ao administrador do formulário", + "toField": "Campo Email", + "toFieldInfo": "Campo com e-mail para recebimento" + }, + "restart": "Reiniciar formulário", + "row": { + "admin": "Proprietário", + "created": "Criada", + "isLive": "Viver", + "language": "Língua", + "lastModified": "Última modificação", + "title": "Título" + }, + "startPage": { + "action": "Açao", + "activeColor": "Cor ativa", + "addButton": "Botão Adicionar", + "bgColor": "Cor de fundo", + "buttons": "Botões", + "color": "Cor", + "continueButtonText": "Texto do botão Continuar", + "paragraph": "Parágrafo", + "paragraphInfo": "Use markdown para formatação avançada", + "show": "exposição", + "text": "Texto", + "title": "Título", + "url": "URL" + }, + "startPageTab": "Página inicial", + "submitted": "Obrigado pela sua submissão!", + "updateError": "Não foi possível atualizar o formulário", + "updateNow": "Salve ", + "updated": "Formulário atualizado" +} diff --git a/ui/locales/pt_BR/index.ts b/ui/locales/pt_BR/index.ts new file mode 100644 index 00000000..a98d2bbc --- /dev/null +++ b/ui/locales/pt_BR/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const pt_BR = { + admin, + common, + form, + language, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/pt_BR/language.json b/ui/locales/pt_BR/language.json new file mode 100644 index 00000000..097daa3e --- /dev/null +++ b/ui/locales/pt_BR/language.json @@ -0,0 +1,11 @@ +{ + "cn": "繁體中文", + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "pl": "Polski", + "pt": "Português", + "ru": "русский" +} diff --git a/ui/locales/pt_BR/login.json b/ui/locales/pt_BR/login.json new file mode 100644 index 00000000..2216f851 --- /dev/null +++ b/ui/locales/pt_BR/login.json @@ -0,0 +1,8 @@ +{ + "invalidLoginCredentials": "nome de usuário \/ senha inválidos", + "loginNow": "Conecte-se agora", + "note": "Observação", + "passwordPlaceholder": "Senha", + "usernamePlaceholder": "Nome do usuário", + "welcomeBack": "Bem vindo de volta!" +} diff --git a/ui/locales/pt_BR/profile.json b/ui/locales/pt_BR/profile.json new file mode 100644 index 00000000..a726d4c4 --- /dev/null +++ b/ui/locales/pt_BR/profile.json @@ -0,0 +1,10 @@ +{ + "email": "O email", + "firstName": "Primeiro nome", + "language": "Língua", + "lastName": "Último nome", + "updateError": "Não foi possível atualizar o perfil", + "updateNow": "Salve ", + "updated": "perfil atualizado", + "username": "Nome do usuário" +} diff --git a/ui/locales/pt_BR/register.json b/ui/locales/pt_BR/register.json new file mode 100644 index 00000000..58b8d883 --- /dev/null +++ b/ui/locales/pt_BR/register.json @@ -0,0 +1,6 @@ +{ + "credentialsAlreadyInUse": "Alguns dados já estão em uso!", + "gotoLogin": "Ter uma conta? Ir para o login", + "registerNow": "Registrar agora", + "welcome": "Bem-vindo, confirme também o seu email" +} diff --git a/ui/locales/pt_BR/statistic.json b/ui/locales/pt_BR/statistic.json new file mode 100644 index 00000000..e67efcc4 --- /dev/null +++ b/ui/locales/pt_BR/statistic.json @@ -0,0 +1,5 @@ +{ + "totalForms": "Total de formulários", + "totalSubmissions": "Total de envios", + "totalUsers": "Total de Usuários" +} diff --git a/ui/locales/pt_BR/submission.json b/ui/locales/pt_BR/submission.json new file mode 100644 index 00000000..246c9456 --- /dev/null +++ b/ui/locales/pt_BR/submission.json @@ -0,0 +1,17 @@ +{ + "add": "Adicionar submissão", + "city": "Cidade", + "country": "País", + "created": "Criada", + "device": { + "name": "Nome do dispositivo", + "type": "Tipo de dispositivo" + }, + "edit": "Editar", + "export": "Exportar", + "field": "Campo", + "lastModified": "Última mudança", + "progress": "Progresso", + "submission": "Submissão", + "value": "Valor" +} diff --git a/ui/locales/pt_BR/type.json b/ui/locales/pt_BR/type.json new file mode 100644 index 00000000..10f69b56 --- /dev/null +++ b/ui/locales/pt_BR/type.json @@ -0,0 +1,67 @@ +{ + "confirmDelete": "Deseja mesmo remover este campo? Verifique se não está referenciado em nenhum lugar!", + "date": { + "default": "Data padrão", + "max": "Data máxima", + "min": "Data mínima", + "name": "Encontro" + }, + "deleteNow": "Excluir campo", + "description": "Descrição", + "descriptionInfo": "Use markdown para formatação avançada", + "dropdown": { + "addOption": "Adicionar opção", + "default": "Valor padrão", + "name": "Suspenso", + "options": "Opções", + "removeOption": "Retirar", + "titlePlaceholder": "Título", + "valuePlaceholder": "Valor" + }, + "email": { + "default": "Email padrão", + "name": "O email" + }, + "hidden": { + "default": "Valor padrão", + "name": "Escondido" + }, + "link": { + "default": "Link padrão", + "name": "URL" + }, + "number": { + "default": "Número padrão", + "name": "Número" + }, + "radio": { + "addOption": "Adicionar opção", + "default": "Valor padrão", + "name": "Interruptor de rádio", + "options": "Opções", + "removeOption": "Retirar", + "titlePlaceholder": "Título", + "valuePlaceholder": "Valor" + }, + "rating": { + "clearNote": "Clique novamente para remover o valor padrão", + "default": "Valor padrão", + "name": "Avaliação" + }, + "required": "Requeridos", + "requiredInfo": "Se necessário, o valor padrão deve ser definido para permitir que os usuários enviem o formulário!", + "slug": "Slug", + "textarea": { + "default": "Valor padrão", + "name": "Área de texto" + }, + "textfield": { + "default": "Valor padrão", + "name": "Linha de texto" + }, + "title": "Título", + "yes_no": { + "default": "Valor padrão", + "name": "Sim não" + } +} diff --git a/ui/locales/pt_BR/user.json b/ui/locales/pt_BR/user.json new file mode 100644 index 00000000..7da0991b --- /dev/null +++ b/ui/locales/pt_BR/user.json @@ -0,0 +1,17 @@ +{ + "baseData": "Dados Base", + "confirmDelete": "Tem certeza de que excluir este usuário?", + "deleteError": "não foi possível excluir o usuário", + "deleteNow": "Excluir agora!", + "deleted": "Usuário excluído", + "loading": "Carregando usuário", + "mange": "Editar usuário \" {{email}} \"", + "row": { + "created": "Criada", + "email": "O email", + "roles": "Função" + }, + "updateError": "Não foi possível atualizar o usuário", + "updateNow": "Salve ", + "updated": "Usuário atualizado" +} diff --git a/ui/locales/pt_BR/validation.json b/ui/locales/pt_BR/validation.json new file mode 100644 index 00000000..dc5f360f --- /dev/null +++ b/ui/locales/pt_BR/validation.json @@ -0,0 +1,18 @@ +{ + "emailFieldRequired": "Selecione um campo de email", + "emailRequired": "Forneça um email", + "invalidEmail": "Deve ser um email válido!", + "invalidNumber": "Deve ser um número válido!", + "invalidSlug": "Slug só pode conter caracteres minúsculos de a-z, 0-9 e _", + "invalidUrl": "Deve ser um URL válido", + "languageRequired": "Por favor selecione um idioma", + "mandatoryFieldsMissing": "Campos obrigatórios ausentes", + "passwordMinLength": "Deve ser maior ou igual a 5 caracteres!", + "passwordRequired": "Por favor insira a sua senha!", + "subjectRequired": "Forneça um assunto", + "templateRequired": "Forneça um modelo", + "titleRequired": "Forneça um título", + "urlRequired": "Por favor, escreva um link para um endereço web", + "usernameRequired": "Forneça um nome de usuário", + "valueRequired": "Forneça um valor" +} diff --git a/ui/locales/pt_PT/admin.json b/ui/locales/pt_PT/admin.json new file mode 100644 index 00000000..30f3658c --- /dev/null +++ b/ui/locales/pt_PT/admin.json @@ -0,0 +1,9 @@ +{ + "administration": "Administração", + "forms": "Formulários", + "home": "Casa", + "profile": "Perfil", + "submissions": "Submissões", + "username": "Nome do usuário", + "users": "Comercial" +} diff --git a/ui/locales/pt_PT/common.json b/ui/locales/pt_PT/common.json new file mode 100644 index 00000000..186d6dcb --- /dev/null +++ b/ui/locales/pt_PT/common.json @@ -0,0 +1,9 @@ +{ + "admin": "Admin", + "checkingCredentials": "Verificando credenciais", + "loadingCredentials": "Carregando credenciais", + "login": "Conecte-se", + "logout": "Sair", + "recover": "Senha perdida", + "register": "Criar Conta" +} diff --git a/ui/locales/pt_PT/form.json b/ui/locales/pt_PT/form.json new file mode 100644 index 00000000..7f1a57a7 --- /dev/null +++ b/ui/locales/pt_PT/form.json @@ -0,0 +1,98 @@ +{ + "baseData": { + "isLive": "Está vivo", + "language": "Língua", + "showFooter": "Mostrar rodapé", + "title": "Título" + }, + "baseDataTab": "Dados Base", + "building": "Formulário de construção", + "confirmDelete": "Tem certeza de que excluiu este formulário com todos os envios?", + "create": "Criar novo formulário", + "createNow": "Salve ", + "created": "Formulário criado", + "creationError": "Não foi possível criar o formulário", + "deleteError": "Não foi possível excluir o formulário", + "deleteNow": "Excluir agora!", + "deleted": "Formulário excluído", + "design": { + "color": { + "answer": "Cor da resposta", + "background": "Cor de fundo", + "button": "Cor do botao", + "buttonActive": "Cor ativa do botão", + "buttonText": "Cor do texto do botão", + "question": "Pergunta Color" + }, + "font": "Fonte" + }, + "designTab": "Projeto", + "endPage": { + "action": "Açao", + "activeColor": "Cor ativa", + "addButton": "Botão Adicionar", + "bgColor": "Cor de fundo", + "buttons": "Botões", + "color": "Cor", + "continueButtonText": "Texto do botão Continuar", + "paragraph": "Parágrafo", + "paragraphInfo": "Use markdown para formatação avançada", + "show": "exposição", + "text": "Texto", + "title": "Título", + "url": "URL" + }, + "endPageTab": "Página final", + "fieldsTab": "Campos do Formulário", + "hooks": { + "add": "Adicionar", + "deleteNow": "Vazio", + "enabled": "Habilitado" + }, + "loading": "Carregando Formulário", + "mange": "Editar formulário \" {{title}} \"", + "new": "Nova forma", + "notifications": { + "enabled": "ativado", + "fromEmail": "E-mail do remetente", + "fromEmailInfo": "Verifique se o seu servidor de e-mail pode enviar deste e-mail", + "fromField": "E-mail do remetente", + "fromFieldInfo": "Campo com email, definirá o cabeçalho de resposta a", + "htmlTemplate": "Modelo HTML", + "htmlTemplateInfo": "Você também pode usar o <u> MJML <\/u> para criar seus modelos de email", + "subject": "Sujeito", + "toEmail": "Seu email", + "toEmailInfo": "Se não definido, será enviado ao administrador do formulário", + "toField": "Campo Email", + "toFieldInfo": "Campo com e-mail para recebimento" + }, + "restart": "Reiniciar formulário", + "row": { + "admin": "Proprietário", + "created": "Criada", + "isLive": "Viver", + "language": "Língua", + "lastModified": "Última modificação", + "title": "Título" + }, + "startPage": { + "action": "Açao", + "activeColor": "Cor ativa", + "addButton": "Botão Adicionar", + "bgColor": "Cor de fundo", + "buttons": "Botões", + "color": "Cor", + "continueButtonText": "Texto do botão Continuar", + "paragraph": "Parágrafo", + "paragraphInfo": "Use markdown para formatação avançada", + "show": "exposição", + "text": "Texto", + "title": "Título", + "url": "URL" + }, + "startPageTab": "Página inicial", + "submitted": "Obrigado pela sua submissão!", + "updateError": "Não foi possível atualizar o formulário", + "updateNow": "Salve ", + "updated": "Formulário atualizado" +} diff --git a/ui/locales/pt_PT/index.ts b/ui/locales/pt_PT/index.ts new file mode 100644 index 00000000..1a12371e --- /dev/null +++ b/ui/locales/pt_PT/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const pt_PT = { + admin, + common, + form, + language, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/pt_PT/language.json b/ui/locales/pt_PT/language.json new file mode 100644 index 00000000..097daa3e --- /dev/null +++ b/ui/locales/pt_PT/language.json @@ -0,0 +1,11 @@ +{ + "cn": "繁體中文", + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "pl": "Polski", + "pt": "Português", + "ru": "русский" +} diff --git a/ui/locales/pt_PT/login.json b/ui/locales/pt_PT/login.json new file mode 100644 index 00000000..2216f851 --- /dev/null +++ b/ui/locales/pt_PT/login.json @@ -0,0 +1,8 @@ +{ + "invalidLoginCredentials": "nome de usuário \/ senha inválidos", + "loginNow": "Conecte-se agora", + "note": "Observação", + "passwordPlaceholder": "Senha", + "usernamePlaceholder": "Nome do usuário", + "welcomeBack": "Bem vindo de volta!" +} diff --git a/ui/locales/pt_PT/profile.json b/ui/locales/pt_PT/profile.json new file mode 100644 index 00000000..a726d4c4 --- /dev/null +++ b/ui/locales/pt_PT/profile.json @@ -0,0 +1,10 @@ +{ + "email": "O email", + "firstName": "Primeiro nome", + "language": "Língua", + "lastName": "Último nome", + "updateError": "Não foi possível atualizar o perfil", + "updateNow": "Salve ", + "updated": "perfil atualizado", + "username": "Nome do usuário" +} diff --git a/ui/locales/pt_PT/register.json b/ui/locales/pt_PT/register.json new file mode 100644 index 00000000..58b8d883 --- /dev/null +++ b/ui/locales/pt_PT/register.json @@ -0,0 +1,6 @@ +{ + "credentialsAlreadyInUse": "Alguns dados já estão em uso!", + "gotoLogin": "Ter uma conta? Ir para o login", + "registerNow": "Registrar agora", + "welcome": "Bem-vindo, confirme também o seu email" +} diff --git a/ui/locales/pt_PT/statistic.json b/ui/locales/pt_PT/statistic.json new file mode 100644 index 00000000..e67efcc4 --- /dev/null +++ b/ui/locales/pt_PT/statistic.json @@ -0,0 +1,5 @@ +{ + "totalForms": "Total de formulários", + "totalSubmissions": "Total de envios", + "totalUsers": "Total de Usuários" +} diff --git a/ui/locales/pt_PT/submission.json b/ui/locales/pt_PT/submission.json new file mode 100644 index 00000000..246c9456 --- /dev/null +++ b/ui/locales/pt_PT/submission.json @@ -0,0 +1,17 @@ +{ + "add": "Adicionar submissão", + "city": "Cidade", + "country": "País", + "created": "Criada", + "device": { + "name": "Nome do dispositivo", + "type": "Tipo de dispositivo" + }, + "edit": "Editar", + "export": "Exportar", + "field": "Campo", + "lastModified": "Última mudança", + "progress": "Progresso", + "submission": "Submissão", + "value": "Valor" +} diff --git a/ui/locales/pt_PT/type.json b/ui/locales/pt_PT/type.json new file mode 100644 index 00000000..10f69b56 --- /dev/null +++ b/ui/locales/pt_PT/type.json @@ -0,0 +1,67 @@ +{ + "confirmDelete": "Deseja mesmo remover este campo? Verifique se não está referenciado em nenhum lugar!", + "date": { + "default": "Data padrão", + "max": "Data máxima", + "min": "Data mínima", + "name": "Encontro" + }, + "deleteNow": "Excluir campo", + "description": "Descrição", + "descriptionInfo": "Use markdown para formatação avançada", + "dropdown": { + "addOption": "Adicionar opção", + "default": "Valor padrão", + "name": "Suspenso", + "options": "Opções", + "removeOption": "Retirar", + "titlePlaceholder": "Título", + "valuePlaceholder": "Valor" + }, + "email": { + "default": "Email padrão", + "name": "O email" + }, + "hidden": { + "default": "Valor padrão", + "name": "Escondido" + }, + "link": { + "default": "Link padrão", + "name": "URL" + }, + "number": { + "default": "Número padrão", + "name": "Número" + }, + "radio": { + "addOption": "Adicionar opção", + "default": "Valor padrão", + "name": "Interruptor de rádio", + "options": "Opções", + "removeOption": "Retirar", + "titlePlaceholder": "Título", + "valuePlaceholder": "Valor" + }, + "rating": { + "clearNote": "Clique novamente para remover o valor padrão", + "default": "Valor padrão", + "name": "Avaliação" + }, + "required": "Requeridos", + "requiredInfo": "Se necessário, o valor padrão deve ser definido para permitir que os usuários enviem o formulário!", + "slug": "Slug", + "textarea": { + "default": "Valor padrão", + "name": "Área de texto" + }, + "textfield": { + "default": "Valor padrão", + "name": "Linha de texto" + }, + "title": "Título", + "yes_no": { + "default": "Valor padrão", + "name": "Sim não" + } +} diff --git a/ui/locales/pt_PT/user.json b/ui/locales/pt_PT/user.json new file mode 100644 index 00000000..7da0991b --- /dev/null +++ b/ui/locales/pt_PT/user.json @@ -0,0 +1,17 @@ +{ + "baseData": "Dados Base", + "confirmDelete": "Tem certeza de que excluir este usuário?", + "deleteError": "não foi possível excluir o usuário", + "deleteNow": "Excluir agora!", + "deleted": "Usuário excluído", + "loading": "Carregando usuário", + "mange": "Editar usuário \" {{email}} \"", + "row": { + "created": "Criada", + "email": "O email", + "roles": "Função" + }, + "updateError": "Não foi possível atualizar o usuário", + "updateNow": "Salve ", + "updated": "Usuário atualizado" +} diff --git a/ui/locales/pt_PT/validation.json b/ui/locales/pt_PT/validation.json new file mode 100644 index 00000000..dc5f360f --- /dev/null +++ b/ui/locales/pt_PT/validation.json @@ -0,0 +1,18 @@ +{ + "emailFieldRequired": "Selecione um campo de email", + "emailRequired": "Forneça um email", + "invalidEmail": "Deve ser um email válido!", + "invalidNumber": "Deve ser um número válido!", + "invalidSlug": "Slug só pode conter caracteres minúsculos de a-z, 0-9 e _", + "invalidUrl": "Deve ser um URL válido", + "languageRequired": "Por favor selecione um idioma", + "mandatoryFieldsMissing": "Campos obrigatórios ausentes", + "passwordMinLength": "Deve ser maior ou igual a 5 caracteres!", + "passwordRequired": "Por favor insira a sua senha!", + "subjectRequired": "Forneça um assunto", + "templateRequired": "Forneça um modelo", + "titleRequired": "Forneça um título", + "urlRequired": "Por favor, escreva um link para um endereço web", + "usernameRequired": "Forneça um nome de usuário", + "valueRequired": "Forneça um valor" +} diff --git a/ui/locales/ru/admin.json b/ui/locales/ru/admin.json new file mode 100644 index 00000000..6227df9e --- /dev/null +++ b/ui/locales/ru/admin.json @@ -0,0 +1,9 @@ +{ + "administration": "Администрирования", + "forms": "Формы", + "home": "Дом", + "profile": "Профиль", + "submissions": "Ответы на формы", + "username": "Имя пользователя", + "users": "Пользователи" +} diff --git a/ui/locales/ru/common.json b/ui/locales/ru/common.json new file mode 100644 index 00000000..c1e57ce7 --- /dev/null +++ b/ui/locales/ru/common.json @@ -0,0 +1,10 @@ +{ + "admin": "Администратор", + "checkingCredentials": "Проверка учетных данных", + "loadingCredentials": "Загрузка учетных данных", + "login": "Авторизоваться", + "logout": "Выйти", + "profile": "Профиль", + "recover": "Забыли пароль?", + "register": "Создать учетную запись" +} diff --git a/ui/locales/ru/form.json b/ui/locales/ru/form.json new file mode 100644 index 00000000..98692793 --- /dev/null +++ b/ui/locales/ru/form.json @@ -0,0 +1,98 @@ +{ + "baseData": { + "isLive": "Опубликована?", + "language": "Язык", + "showFooter": "Показать нижний колонтитул", + "title": "Заголовок" + }, + "baseDataTab": "Базовые данные", + "building": "Создание формы", + "confirmDelete": "Вы уверены, что удалите эту форму со всеми представлениями?", + "create": "Создать новую форму", + "createNow": "Сохранить", + "created": "Форма создана", + "creationError": "Не удалось создать форму", + "deleteError": "Не удалось удалить форму", + "deleteNow": "Удалить сейчас!", + "deleted": "Форма удалена", + "design": { + "color": { + "answer": "Цвет ответа", + "background": "Фоновый цвет", + "button": "Цвет кнопки", + "buttonActive": "Цвет активной кнопки", + "buttonText": "Цвет текста кнопки", + "question": "Цвет вопроса" + }, + "font": "Шрифт" + }, + "designTab": "Дизайн", + "endPage": { + "action": "Действие", + "activeColor": "Активный цвет", + "addButton": "Добавить кнопку", + "bgColor": "Цвет фона", + "buttons": "Кнопки", + "color": "Цвет", + "continueButtonText": "Продолжить текст кнопки", + "paragraph": "Пункт", + "paragraphInfo": "Используйте markdown для расширенного форматирования", + "show": "Показать", + "text": "Текст", + "title": "заглавие", + "url": "Веб-сайт" + }, + "endPageTab": "Конечная страница", + "fieldsTab": "Поля формы", + "hooks": { + "add": "Добавить", + "enabled": "Включено" + }, + "hooksTab": "Хуки", + "loading": "Форма загрузки", + "mange": "Изменить форму \" {{title}} \"", + "new": "Новая форма", + "notifications": { + "enabled": "Включено", + "fromEmail": "Электронная почта отправителя", + "fromEmailInfo": "Убедитесь, что ваш почтовый сервер может отправлять с этого письма", + "fromField": "Электронная почта отправителя", + "fromFieldInfo": "Поле с адресом электронной почты, установит заголовок Reply-To", + "htmlTemplate": "HTML шаблон", + "htmlTemplateInfo": "Вы также можете использовать <u> MJML <\/u> для создания своих шаблонов электронной почты", + "subject": "Тема", + "toEmail": "Ваш адрес электронной почты", + "toEmailInfo": "Если не установлен, отправит администратору формы", + "toField": "Поле электронной почты", + "toFieldInfo": "Поле с адресом электронной почты для получения" + }, + "restart": "Перезапустить форму", + "row": { + "admin": "Владелец", + "created": "Создан", + "isLive": "Опубликовать", + "language": "Язык", + "lastModified": "Последнее изменение", + "title": "заглавие" + }, + "startPage": { + "action": "Действие", + "activeColor": "Активный цвет", + "addButton": "Добавить кнопку", + "bgColor": "Цвет фона", + "buttons": "Кнопки", + "color": "Цвет", + "continueButtonText": "Текст кнопки \"Продолжить\"", + "paragraph": "Параграф", + "paragraphInfo": "Используйте markdown для расширенного форматирования", + "show": "Показать", + "text": "Текст", + "title": "Заголовок", + "url": "URL" + }, + "startPageTab": "Начальная страница", + "submitted": "Спасибо за ваш вклад!", + "updateError": "Не удалось обновить форму", + "updateNow": "Сохранить", + "updated": "Форма обновлена" +} diff --git a/ui/locales/ru/index.ts b/ui/locales/ru/index.ts new file mode 100644 index 00000000..d2e72c8d --- /dev/null +++ b/ui/locales/ru/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const ru = { + admin, + common, + form, + language, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/ru/language.json b/ui/locales/ru/language.json new file mode 100644 index 00000000..097daa3e --- /dev/null +++ b/ui/locales/ru/language.json @@ -0,0 +1,11 @@ +{ + "cn": "繁體中文", + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "pl": "Polski", + "pt": "Português", + "ru": "русский" +} diff --git a/ui/locales/ru/login.json b/ui/locales/ru/login.json new file mode 100644 index 00000000..ad223bf7 --- /dev/null +++ b/ui/locales/ru/login.json @@ -0,0 +1,8 @@ +{ + "invalidLoginCredentials": "имя пользователя \/ пароль неверны", + "loginNow": "Войти сейчас", + "note": "Примечание", + "passwordPlaceholder": "Пароль", + "usernamePlaceholder": "Имя пользователя", + "welcomeBack": "Добро пожаловать!" +} diff --git a/ui/locales/ru/profile.json b/ui/locales/ru/profile.json new file mode 100644 index 00000000..34596c3f --- /dev/null +++ b/ui/locales/ru/profile.json @@ -0,0 +1,10 @@ +{ + "email": "Электронное письмо", + "firstName": "Имя", + "language": "Язык", + "lastName": "Фамилия", + "updateError": "Не удалось обновить профиль", + "updateNow": "Сохранить", + "updated": "Профиль обновлен", + "username": "Имя пользователя" +} diff --git a/ui/locales/ru/register.json b/ui/locales/ru/register.json new file mode 100644 index 00000000..45ce8f1c --- /dev/null +++ b/ui/locales/ru/register.json @@ -0,0 +1,6 @@ +{ + "credentialsAlreadyInUse": "Некоторые данные уже используются!", + "gotoLogin": "Уже есть аккаунт? Войти", + "registerNow": "Зарегистрируйтесь сейчас", + "welcome": "Добро пожаловать, пожалуйста, также подтвердите ваш адрес электронной почты" +} diff --git a/ui/locales/ru/statistic.json b/ui/locales/ru/statistic.json new file mode 100644 index 00000000..f4250bbc --- /dev/null +++ b/ui/locales/ru/statistic.json @@ -0,0 +1,5 @@ +{ + "totalForms": "Всего форм", + "totalSubmissions": "Всего заявок", + "totalUsers": "Всего пользователей" +} diff --git a/ui/locales/ru/submission.json b/ui/locales/ru/submission.json new file mode 100644 index 00000000..0fd70380 --- /dev/null +++ b/ui/locales/ru/submission.json @@ -0,0 +1,17 @@ +{ + "add": "Добавить представление", + "city": "Город", + "country": "Страна", + "created": "Создан", + "device": { + "name": "Имя устройства", + "type": "Тип устройства" + }, + "edit": "Редактировать", + "export": "Экспорт", + "field": "Поле", + "lastModified": "Последнее изменение", + "progress": "Прогресс", + "submission": "Ответы на формы", + "value": "Значение" +} diff --git a/ui/locales/ru/type.json b/ui/locales/ru/type.json new file mode 100644 index 00000000..9c79862b --- /dev/null +++ b/ui/locales/ru/type.json @@ -0,0 +1,68 @@ +{ + "confirmDelete": "Действительно удалить это поле? Убедитесь, что на него нигде нет ссылок!", + "date": { + "default": "Дата по умолчанию", + "max": "Макс Дата", + "min": "Мин Дата", + "name": "Дата" + }, + "deleteNow": "Удалить поле", + "description": "Описание", + "descriptionInfo": "Используйте markdown для расширенного форматирования", + "dropdown": { + "addOption": "Добавить опцию", + "default": "Значение по умолчанию", + "name": "Выпадающий список", + "options": "Опции", + "removeOption": "Удалить", + "titlePlaceholder": "Заголовок", + "valuePlaceholder": "Значение" + }, + "email": { + "default": "Электронная почта по умолчанию", + "name": "Электронное письмо" + }, + "hidden": { + "default": "Значение по умолчанию", + "name": "Скрытый" + }, + "link": { + "default": "Ссылка по умолчанию", + "name": "URL" + }, + "number": { + "default": "Цифра по умолчанию", + "name": "Число" + }, + "radio": { + "addOption": "Добавить опцию", + "default": "Значение по умолчанию", + "name": "Выбор из нескольких вариантов", + "options": "Опции", + "removeOption": "Удалить", + "titlePlaceholder": "Заголовок", + "valuePlaceholder": "Значение" + }, + "rating": { + "clearNote": "Нажмите еще раз, чтобы удалить значение по умолчанию", + "default": "Значение по умолчанию", + "name": "Рейтинг" + }, + "required": "Обязательный", + "requiredInfo": "При необходимости, должно быть установлено значение по умолчанию, чтобы пользователи могли отправить форму!", + "slug": "Slug", + "slugInfo": "Используйте slug для передачи динамического значения по умолчанию в качестве параметра url? slug = value", + "textarea": { + "default": "Значение по умолчанию", + "name": "Текстовая область" + }, + "textfield": { + "default": "Значение по умолчанию", + "name": "Текстовая строка" + }, + "title": "Заголовок", + "yes_no": { + "default": "Значение по умолчанию", + "name": "Да \/ Нет" + } +} diff --git a/ui/locales/ru/user.json b/ui/locales/ru/user.json new file mode 100644 index 00000000..4fd14226 --- /dev/null +++ b/ui/locales/ru/user.json @@ -0,0 +1,17 @@ +{ + "baseData": "Базовые данные", + "confirmDelete": "Вы уверены, что удалили этого пользователя?", + "deleteError": "не удалось удалить пользователя", + "deleteNow": "Удалить сейчас!", + "deleted": "Пользователь удален", + "loading": "Загрузка пользователя", + "mange": "Изменить пользователя \" {{email}} \"", + "row": { + "created": "Создан", + "email": "Электронное письмо", + "roles": "Роль" + }, + "updateError": "Не удалось обновить пользователя", + "updateNow": "Сохранить", + "updated": "Пользователь обновлен" +} diff --git a/ui/locales/ru/validation.json b/ui/locales/ru/validation.json new file mode 100644 index 00000000..121b3a1e --- /dev/null +++ b/ui/locales/ru/validation.json @@ -0,0 +1,18 @@ +{ + "emailFieldRequired": "Пожалуйста, выберите поле электронной почты", + "emailRequired": "Пожалуйста, укажите адрес электронной почты", + "invalidEmail": "Должен быть действительный адрес электронной почты!", + "invalidNumber": "Число должно быть валидным!", + "invalidSlug": "Slug может содержать только буквы az, 0-9 и _ в нижнем регистре.", + "invalidUrl": "Должен быть действительный URL", + "languageRequired": "Пожалуйста, выберите язык", + "mandatoryFieldsMissing": "Обязательные поля отсутствуют", + "passwordMinLength": "Должно быть длиннее или равно 5 символам!", + "passwordRequired": "Пожалуйста, введите ваш пароль!", + "subjectRequired": "Пожалуйста, укажите тему", + "templateRequired": "Пожалуйста, предоставьте шаблон", + "titleRequired": "Пожалуйста, укажите название", + "urlRequired": "Укажите URL", + "usernameRequired": "Пожалуйста, укажите имя пользователя", + "valueRequired": "Пожалуйста, укажите ценность" +} diff --git a/ui/locales/sort.ts b/ui/locales/sort.ts new file mode 100644 index 00000000..3f5c3322 --- /dev/null +++ b/ui/locales/sort.ts @@ -0,0 +1,52 @@ +const fs = require('fs'); +const glob = require('glob'); +const { program } = require('commander'); + +program.version('1.0.0'); +program + .option('-f, --force', 'force write to existing files') + +program.parse(process.argv); + +const sort = obj => { + if (typeof obj !== 'object') { + return obj + } + + const result = {} + + Object + .keys(obj) + .sort() + .map(key => { + result[key] = sort(obj[key]) + }) + + return result +} + +glob.sync('locales/*/').forEach(dir => { + const files: string[] = glob.sync(`${dir}*.json`) + + files.forEach(file => { + try { + const raw = fs.readFileSync(file) + const original = JSON.parse(raw) + const sorted = sort(original) + const next = JSON.stringify(sorted, null, 2) + "\n" + + if (raw != next) { + if (!program.force) { + console.log('changes found, but skipped', file) + return + } + + console.log('updated', file) + fs.writeFileSync(file, next) + } + } catch (e) { + console.error('could not process file', file, e) + } + }) +}) + diff --git a/ui/locales/sv/admin.json b/ui/locales/sv/admin.json new file mode 100644 index 00000000..67258b9a --- /dev/null +++ b/ui/locales/sv/admin.json @@ -0,0 +1,9 @@ +{ + "administration": "Administration", + "forms": "Blanketter", + "home": "Hem", + "profile": "Profil", + "submissions": "Inlämningar", + "username": "Användarnamn", + "users": "Användare" +} diff --git a/ui/locales/sv/common.json b/ui/locales/sv/common.json new file mode 100644 index 00000000..f5ae3996 --- /dev/null +++ b/ui/locales/sv/common.json @@ -0,0 +1,8 @@ +{ + "admin": "Admin", + "login": "Logga in", + "logout": "Logga ut", + "profile": "Profil", + "recover": "Förlorat lösenord", + "register": "Skapa ett konto" +} diff --git a/ui/locales/sv/form.json b/ui/locales/sv/form.json new file mode 100644 index 00000000..173b1315 --- /dev/null +++ b/ui/locales/sv/form.json @@ -0,0 +1,37 @@ +{ + "continue": "Fortsätta", + "design": { + "layout": { + "card": "Kort", + "slider": "Skjutreglage" + }, + "layouts": "Layout" + }, + "endPage": { + "paragraphInfo": "Använd markdown för avancerad formatering" + }, + "fieldsTab": "Formulärfält", + "hooks": { + "add": "Lägg till", + "enabled": "Aktiverad" + }, + "logic": { + "add": "Lägg till logik" + }, + "next": "Nästa", + "notifications": { + "add": "Lägg till meddelande" + }, + "notificationsTab": "Meddelanden", + "previous": "Föregående", + "startPage": { + "paragraphInfo": "Använd markdown för avancerad formatering", + "show": "Visa", + "text": "Text", + "title": "Titel" + }, + "startPageTab": "Startsida", + "submitted": "Tack för din bidrag!", + "updateNow": "Spara", + "updated": "Formuläret har uppdaterats" +} diff --git a/ui/locales/sv/index.ts b/ui/locales/sv/index.ts new file mode 100644 index 00000000..b8146aab --- /dev/null +++ b/ui/locales/sv/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const sv = { + language, + admin, + common, + form, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/sv/language.json b/ui/locales/sv/language.json new file mode 100644 index 00000000..097daa3e --- /dev/null +++ b/ui/locales/sv/language.json @@ -0,0 +1,11 @@ +{ + "cn": "繁體中文", + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "pl": "Polski", + "pt": "Português", + "ru": "русский" +} diff --git a/ui/locales/sv/login.json b/ui/locales/sv/login.json new file mode 100644 index 00000000..5419c77f --- /dev/null +++ b/ui/locales/sv/login.json @@ -0,0 +1,7 @@ +{ + "invalidLoginCredentials": "användarnamn och lösenord är ogiltiga", + "loginNow": "Logga in nu", + "passwordPlaceholder": "Lösenord", + "usernamePlaceholder": "Användarnamn", + "welcomeBack": "Välkommen tillbaka!" +} diff --git a/ui/locales/sv/profile.json b/ui/locales/sv/profile.json new file mode 100644 index 00000000..76e99cd1 --- /dev/null +++ b/ui/locales/sv/profile.json @@ -0,0 +1,9 @@ +{ + "email": "E-post", + "firstName": "Förnamn", + "language": "Språk", + "lastName": "Efternamn", + "password": "Lösenord", + "updateNow": "Spara", + "username": "Användarnamn" +} diff --git a/ui/locales/sv/register.json b/ui/locales/sv/register.json new file mode 100644 index 00000000..6bdbbf45 --- /dev/null +++ b/ui/locales/sv/register.json @@ -0,0 +1,5 @@ +{ + "gotoLogin": "Har du ett konto? Gå till inloggning", + "registerNow": "Registrera dig nu", + "welcome": "Välkommen, vänligen bekräfta även din e-postadress." +} diff --git a/ui/locales/sv/statistic.json b/ui/locales/sv/statistic.json new file mode 100644 index 00000000..68204f88 --- /dev/null +++ b/ui/locales/sv/statistic.json @@ -0,0 +1,5 @@ +{ + "totalForms": "Totalt antal formulär", + "totalSubmissions": "Totalt antal inlämningar", + "totalUsers": "Totalt antal användare" +} diff --git a/ui/locales/sv/submission.json b/ui/locales/sv/submission.json new file mode 100644 index 00000000..31306103 --- /dev/null +++ b/ui/locales/sv/submission.json @@ -0,0 +1,16 @@ +{ + "add": "Lägg till inlämning", + "city": "Stad", + "country": "Land", + "created": "Skapad", + "device": { + "name": "Enhetsnamn", + "type": "Enhetstyp" + }, + "edit": "Redigera", + "field": "Fält", + "lastModified": "Senaste ändringen", + "progress": "Framsteg", + "submission": "Inlämning", + "value": "Värde" +} diff --git a/ui/locales/sv/type.json b/ui/locales/sv/type.json new file mode 100644 index 00000000..80067768 --- /dev/null +++ b/ui/locales/sv/type.json @@ -0,0 +1,58 @@ +{ + "add": "Lägg till fält", + "date": { + "default": "Standarddatum", + "name": "Datum" + }, + "deleteNow": "Ta bort fält", + "description": "Beskrivning", + "descriptionInfo": "Använd markdown för avancerad formatering", + "dropdown": { + "addOption": "Lägg till alternativ", + "default": "Standardvärde", + "options": "Alternativ", + "removeOption": "Ta bort", + "titlePlaceholder": "Titel", + "valuePlaceholder": "Värde" + }, + "email": { + "name": "E-post" + }, + "hidden": { + "default": "Standardvärde", + "name": "Dold" + }, + "radio": { + "addOption": "Lägg till alternativ", + "default": "Standardvärde", + "options": "Alternativ", + "removeOption": "Ta bort", + "titlePlaceholder": "Titel", + "valuePlaceholder": "Värde" + }, + "rating": { + "clearNote": "Klicka igen för att ta bort standardvärdet.", + "default": "Standardvärde", + "name": "Betyg" + }, + "required": "Krävs", + "slider": { + "default": "Standardvärde", + "min": "Minsta värde", + "name": "Skjutreglage", + "step": "Stegstorlek" + }, + "textarea": { + "default": "Standardvärde", + "name": "Textområde" + }, + "textfield": { + "default": "Standardvärde", + "name": "Textrad" + }, + "title": "Titel", + "yes_no": { + "default": "Standardvärde", + "name": "Ja \/ Nej" + } +} diff --git a/ui/locales/sv/user.json b/ui/locales/sv/user.json new file mode 100644 index 00000000..d204245b --- /dev/null +++ b/ui/locales/sv/user.json @@ -0,0 +1,13 @@ +{ + "confirmDelete": "Är du säker på att ta bort den här användaren?", + "deleteNow": "Ta bort nu!", + "deleted": "Användaren har tagits bort", + "row": { + "created": "Skapad", + "email": "E-post", + "roles": "Roll" + }, + "updateError": "Kunde inte uppdatera användaren", + "updateNow": "Spara", + "updated": "Användaren har uppdaterats" +} diff --git a/ui/locales/sv/validation.json b/ui/locales/sv/validation.json new file mode 100644 index 00000000..ed4f999b --- /dev/null +++ b/ui/locales/sv/validation.json @@ -0,0 +1,11 @@ +{ + "invalidNumber": "Måste vara ett giltigt nummer!", + "languageRequired": "Välj ett språk", + "mandatoryFieldsMissing": "Obligatoriska fält saknas", + "passwordRequired": "Vänligen ange ditt lösenord!", + "subjectRequired": "Ange ett ämne", + "templateRequired": "Ange en mall", + "titleRequired": "Ange en titel", + "usernameRequired": "Ange ett användarnamn", + "valueRequired": "Ange ett värde" +} diff --git a/ui/locales/ta/admin.json b/ui/locales/ta/admin.json new file mode 100644 index 00000000..de6ce685 --- /dev/null +++ b/ui/locales/ta/admin.json @@ -0,0 +1,3 @@ +{ + "administration": "நிர்வாகம்" +} diff --git a/ui/locales/ta/common.json b/ui/locales/ta/common.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/ui/locales/ta/common.json @@ -0,0 +1 @@ +{} diff --git a/ui/locales/ta/form.json b/ui/locales/ta/form.json new file mode 100644 index 00000000..2f394ee7 --- /dev/null +++ b/ui/locales/ta/form.json @@ -0,0 +1,25 @@ +{ + "endPage": { + "paragraphInfo": "மேம்பட்ட வடிவமைப்பிற்கு மார்க் டவுன் பயன்படுத்தவும்" + }, + "fieldsTab": "படிவ புலங்கள்", + "hooks": { + "add": "சேர்", + "enabled": "இயக்கப்பட்டது" + }, + "hooksTab": "வெப்ஹூக்ஸ்", + "notifications": { + "toField": "மின்னஞ்சல் புலம்", + "toFieldInfo": "பெறவேண்டிய மின்னஞ்சல் புலம்" + }, + "restart": "படிவத்தை மறுதொடக்கம் செய்யுங்கள்", + "row": { + "admin": "உரிமையாளர்", + "created": "உருவாக்கப்பட்டது", + "isLive": "உள்ளது", + "language": "மொழி" + }, + "startPage": { + "paragraphInfo": "மேம்பட்ட வடிவமைப்பிற்கு மார்க் டவுன் பயன்படுத்தவும்" + } +} diff --git a/ui/locales/ta/index.ts b/ui/locales/ta/index.ts new file mode 100644 index 00000000..7c4690a4 --- /dev/null +++ b/ui/locales/ta/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const ta = { + admin, + common, + form, + language, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/ta/language.json b/ui/locales/ta/language.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/ui/locales/ta/language.json @@ -0,0 +1 @@ +{} diff --git a/ui/locales/ta/login.json b/ui/locales/ta/login.json new file mode 100644 index 00000000..9275f79b --- /dev/null +++ b/ui/locales/ta/login.json @@ -0,0 +1,3 @@ +{ + "note": "குறிப்பு" +} diff --git a/ui/locales/ta/profile.json b/ui/locales/ta/profile.json new file mode 100644 index 00000000..917fc407 --- /dev/null +++ b/ui/locales/ta/profile.json @@ -0,0 +1,10 @@ +{ + "email": "மின்னஞ்சல்", + "firstName": "முதல் பெயர்", + "language": "மொழி", + "lastName": "கடைசி பெயர்", + "updateError": "பயனர் சுயவிவரத்தை புதுப்பிக்க முடியவில்லை", + "updateNow": "சேமி", + "updated": "பயனர் சுயவிவரம் புதுப்பிக்கப்பட்டது", + "username": "பயனர்பெயர்" +} diff --git a/ui/locales/ta/register.json b/ui/locales/ta/register.json new file mode 100644 index 00000000..a8c09a08 --- /dev/null +++ b/ui/locales/ta/register.json @@ -0,0 +1,6 @@ +{ + "credentialsAlreadyInUse": "சில தரவு ஏற்கனவே பயன்பாட்டில் உள்ளது!", + "gotoLogin": "கணக்கு உள்ளதா? உள்நுழைக", + "registerNow": "இப்போதே பதிவு செய்க", + "welcome": "வருக, உங்கள் மின்னஞ்சலையும் உறுதிப்படுத்தவும்" +} diff --git a/ui/locales/ta/statistic.json b/ui/locales/ta/statistic.json new file mode 100644 index 00000000..db34e08e --- /dev/null +++ b/ui/locales/ta/statistic.json @@ -0,0 +1,5 @@ +{ + "totalForms": "மொத்த படிவங்கள்", + "totalSubmissions": "மொத்த சமர்ப்பிப்புகள்", + "totalUsers": "மொத்த பயனர்கள்" +} diff --git a/ui/locales/ta/submission.json b/ui/locales/ta/submission.json new file mode 100644 index 00000000..69cf600b --- /dev/null +++ b/ui/locales/ta/submission.json @@ -0,0 +1,16 @@ +{ + "add": "சமர்ப்பிப்பைச் சேர்க்கவும்", + "city": "நகரம்", + "country": "நாடு", + "created": "உருவாக்கப்பட்டது", + "device": { + "name": "சாதனத்தின் பெயர்", + "type": "கருவியின் வகை" + }, + "edit": "தொகு", + "field": "புலம்", + "lastModified": "கடைசி மாற்றம்", + "progress": "முன்னேற்றம்", + "submission": "சமர்ப்பிப்பு", + "value": "மதிப்பு" +} diff --git a/ui/locales/ta/type.json b/ui/locales/ta/type.json new file mode 100644 index 00000000..2e1cb055 --- /dev/null +++ b/ui/locales/ta/type.json @@ -0,0 +1,55 @@ +{ + "confirmDelete": "இந்த புலத்தை உண்மையில் அகற்றவா? இது எங்கும் குறிப்பிடப்படவில்லை என்பதை சரிபார்க்கவும்!", + "date": { + "name": "தேதி" + }, + "deleteNow": "புலத்தை நீக்கு", + "description": "விளக்கம்", + "descriptionInfo": "மேம்பட்ட வடிவமைப்பிற்கு மார்க் டவுன் பயன்படுத்தவும்", + "dropdown": { + "addOption": "விருப்பத்தைச் சேர்", + "default": "இயல்புநிலை மதிப்பு", + "name": "கீழ்பட்டியல்", + "options": "விருப்பங்கள்", + "removeOption": "அகற்று", + "titlePlaceholder": "தலைப்பு", + "valuePlaceholder": "மதிப்பு" + }, + "email": { + "default": "இயல்புநிலை மின்னஞ்சல்", + "name": "மின்னஞ்சல்" + }, + "hidden": { + "default": "இயல்புநிலை மதிப்பு", + "name": "மறைக்கப்பட்டுள்ளது" + }, + "link": { + "default": "இயல்புநிலை இணையதள இணைப்பு", + "name": "URL" + }, + "number": { + "default": "இயல்புநிலை எண்", + "name": "எண்" + }, + "radio": { + "addOption": "விருப்பத்தைச் சேர்", + "default": "இயல்புநிலை மதிப்பு", + "name": "ரேடியோ சுவிட்ச்", + "options": "விருப்பங்கள்", + "removeOption": "அகற்று", + "titlePlaceholder": "தலைப்பு", + "valuePlaceholder": "மதிப்பு" + }, + "rating": { + "clearNote": "இயல்புநிலை மதிப்பை அகற்ற மீண்டும் கிளிக் செய்க", + "default": "இயல்புநிலை மதிப்பு", + "name": "மதிப்பீடு" + }, + "required": "தேவை", + "requiredInfo": "தேவைப்பட்டால், பயனர்களை படிவத்தை சமர்ப்பிக்க இயல்புநிலை மதிப்பு அமைக்கப்பட வேண்டும்!", + "slug": "வாக்கியம்", + "slugInfo": "இயல்புநிலை டைனமிக் ஐ URL அளவுருவாக அனுப்ப வாக்கியம் பயன்படுத்தவா?slug = மதிப்பு", + "textarea": { + "default": "இயல்புநிலை மதிப்பு" + } +} diff --git a/ui/locales/ta/user.json b/ui/locales/ta/user.json new file mode 100644 index 00000000..5a989f87 --- /dev/null +++ b/ui/locales/ta/user.json @@ -0,0 +1,14 @@ +{ + "confirmDelete": "இந்த பயனரை நீக்க நிச்சயமாக விரும்புகிறீர்களா?", + "deleteError": "பயனரை நீக்க முடியவில்லை", + "deleteNow": "இப்போது நீக்கு!", + "deleted": "பயனர் நீக்கப்பட்டார்", + "loading": "பயனரை ஏற்றுகிறது", + "mange": "பயனரைத் திருத்து \" {{email}} \"", + "row": { + "created": "உருவாக்கப்பட்டது" + }, + "updateError": "பயனரைப் புதுப்பிக்க முடியவில்லை", + "updateNow": "சேமி", + "updated": "பயனர் புதுப்பிக்கப்பட்டது" +} diff --git a/ui/locales/ta/validation.json b/ui/locales/ta/validation.json new file mode 100644 index 00000000..a379451c --- /dev/null +++ b/ui/locales/ta/validation.json @@ -0,0 +1,18 @@ +{ + "emailFieldRequired": "தயவுசெய்து ஒரு மின்னஞ்சல் புலத்தைத் தேர்ந்தெடுக்கவும்", + "emailRequired": "தயவுசெய்து ஒரு மின்னஞ்சல் வழங்கவும்", + "invalidEmail": "சரியான மின்னஞ்சலாக இருக்க வேண்டும்!", + "invalidNumber": "சரியான எண்ணாக இருக்க வேண்டும்!", + "invalidSlug": "வாக்கியம்ில் சிறிய எழுத்துக்கள், 0-9 மற்றும் _ மட்டுமே இருக்க முடியும்", + "invalidUrl": "சரியான URL ஆக இருக்க வேண்டும்", + "languageRequired": "ஒரு மொழியைத் தேர்ந்தெடுக்கவும்", + "mandatoryFieldsMissing": "கட்டாய புலங்கள் இல்லை", + "passwordMinLength": "5 எழுத்துக்களைவிட நீளமாகவோ அல்லது சமமாகவோ இருக்க வேண்டும்!", + "passwordRequired": "உங்கள் கடவுச்சொல்லை உள்ளிடவும்!", + "subjectRequired": "தயவுசெய்து ஒரு பொருளை வழங்கவும்", + "templateRequired": "ஒரு டெம்ப்ளேட்டை வழங்கவும்", + "titleRequired": "ஒரு தலைப்பை வழங்கவும்", + "urlRequired": "தயவுசெய்து ஒரு URL ஐ வழங்கவும்", + "usernameRequired": "பயனர்பெயரை வழங்கவும்", + "valueRequired": "ஒரு மதிப்பை வழங்கவும்" +} diff --git a/ui/locales/uk/admin.json b/ui/locales/uk/admin.json new file mode 100644 index 00000000..84bc1e2e --- /dev/null +++ b/ui/locales/uk/admin.json @@ -0,0 +1,9 @@ +{ + "administration": "Адміністрування", + "forms": "Форми", + "home": "Головна", + "profile": "Профіль", + "submissions": "Подані форми", + "username": "Ім'я користувача", + "users": "Користувачі" +} diff --git a/ui/locales/uk/common.json b/ui/locales/uk/common.json new file mode 100644 index 00000000..ff801056 --- /dev/null +++ b/ui/locales/uk/common.json @@ -0,0 +1,9 @@ +{ + "admin": "Адміністратор", + "checkingCredentials": "Перевірка облікових даних", + "loadingCredentials": "Завантаження облікових даних", + "login": "Увійти", + "logout": "Вийти", + "recover": "Забули пароль?", + "register": "Створити акаунт" +} diff --git a/ui/locales/uk/form.json b/ui/locales/uk/form.json new file mode 100644 index 00000000..404e224f --- /dev/null +++ b/ui/locales/uk/form.json @@ -0,0 +1,101 @@ +{ + "baseData": { + "isLive": "Опублікована?", + "language": "Мова", + "showFooter": "Показати нижній колонтитул", + "title": "Заголовок" + }, + "baseDataTab": "Основні дані", + "building": "Створення форми", + "confirmDelete": "Ви дійсно хочете видалити цю форму із всіма відповідями на неї?", + "create": "Створити нову форму", + "createNow": "Зберегти", + "created": "Форму створено", + "creationError": "Не вдалося створити форму", + "deleteError": "Не вдалося видалити форму", + "deleteNow": "Видалити зараз!", + "deleted": "Форму видалено", + "design": { + "color": { + "answer": "Колір відповіді", + "background": "Колір тла", + "button": "Колір кнопки", + "buttonActive": "Колір активного тексту кнопки", + "buttonText": "Колір тексту кнопки", + "question": "Колір питання" + }, + "font": "Шрифт" + }, + "designTab": "Дизайн", + "endPage": { + "action": "Дія", + "activeColor": "Активний колір", + "addButton": "Додати кнопку", + "bgColor": "Колір тла", + "buttons": "Кнопки", + "color": "Колір", + "continueButtonText": "Текст кнопки \"Продовжити\"", + "paragraph": "Додатковий текст", + "paragraphInfo": "Використовуйте markdown для розширеного форматування", + "show": "Показати", + "text": "Текст", + "title": "Заголовок", + "url": "URL-адреса" + }, + "endPageTab": "Кінцева сторінка", + "fieldsTab": "Поля форми", + "hooks": { + "add": "Додати", + "confirmDelete": "Видалити", + "deleteNow": "Видалити зараз?", + "enabled": "Активовано" + }, + "hooksTab": "WebHooks", + "loading": "Завантажуємо форму", + "mange": "Редагувати форму \" {{title}} \"", + "new": "Створити форму", + "notifications": { + "enabled": "Активовано", + "fromEmail": "Електронна пошта відправника", + "fromEmailInfo": "Переконайтеся, що ваш поштовий сервер може надсилати повідомлення з цієї електронної пошти", + "fromField": "Електронна пошта відправника", + "fromFieldInfo": "Поле з електронною поштою, встановить заголовок «Reply-To»", + "htmlTemplate": "HTML-шаблон", + "htmlTemplateInfo": "Ви також можете використовувати <u> MJML <\/u> для створення шаблонів електронної пошти", + "subject": "Тема", + "toEmail": "Ваша електронна пошта", + "toEmailInfo": "Якщо не встановлено, надішле адміністратору форми", + "toField": "Поле електронної пошти", + "toFieldInfo": "Поле з електронною поштою для отримання" + }, + "restart": "Перезапустити форму", + "row": { + "admin": "Власник", + "created": "Створено", + "isLive": "Опубліковано", + "language": "Мова", + "lastModified": "Востаннє змінено", + "menu": "Меню", + "title": "Заголовок" + }, + "startPage": { + "action": "Дія", + "activeColor": "Активний колір", + "addButton": "Додати кнопку", + "bgColor": "Колір тла", + "buttons": "Кнопки", + "color": "Колір", + "continueButtonText": "Текст кнопки \"Продовжити\"", + "paragraph": "Додатковий текст", + "paragraphInfo": "Використовуйте markdown для розширеного форматування", + "show": "Показати", + "text": "Текст", + "title": "Заголовок", + "url": "URL-адреса" + }, + "startPageTab": "Початкова сторінка", + "submitted": "Дякуємо за Вашу увагу!", + "updateError": "Не вдалось оновити форму", + "updateNow": "Зберегти", + "updated": "Форму оновлено" +} diff --git a/ui/locales/uk/index.ts b/ui/locales/uk/index.ts new file mode 100644 index 00000000..b34c44c9 --- /dev/null +++ b/ui/locales/uk/index.ts @@ -0,0 +1,27 @@ +import admin from './admin.json' +import common from './common.json' +import form from './form.json' +import language from './language.json' +import login from './login.json' +import profile from './profile.json' +import register from './register.json' +import statistic from './statistic.json' +import submission from './submission.json' +import type from './type.json' +import user from './user.json' +import validation from './validation.json' + +export const uk = { + admin, + common, + form, + language, + login, + profile, + register, + statistic, + submission, + type, + user, + validation, +} diff --git a/ui/locales/uk/language.json b/ui/locales/uk/language.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/ui/locales/uk/language.json @@ -0,0 +1 @@ +{} diff --git a/ui/locales/uk/login.json b/ui/locales/uk/login.json new file mode 100644 index 00000000..bd4caeda --- /dev/null +++ b/ui/locales/uk/login.json @@ -0,0 +1,8 @@ +{ + "invalidLoginCredentials": "ім'я користувача або пароль були введені неправильно!", + "loginNow": "Увійти зараз", + "note": "Примітка", + "passwordPlaceholder": "Пароль", + "usernamePlaceholder": "Ім'я користувача", + "welcomeBack": "З поверненням!" +} diff --git a/ui/locales/uk/profile.json b/ui/locales/uk/profile.json new file mode 100644 index 00000000..6cd788e2 --- /dev/null +++ b/ui/locales/uk/profile.json @@ -0,0 +1,10 @@ +{ + "email": "Email", + "firstName": "Ім'я", + "language": "Мова", + "lastName": "Прізвище", + "updateError": "Не вдалося оновити профіль", + "updateNow": "Зберегти", + "updated": "Профіль оновлено", + "username": "Ім'я користувача" +} diff --git a/ui/locales/uk/register.json b/ui/locales/uk/register.json new file mode 100644 index 00000000..d8b5ab66 --- /dev/null +++ b/ui/locales/uk/register.json @@ -0,0 +1,6 @@ +{ + "credentialsAlreadyInUse": "Деякі дані вже використовуються!", + "gotoLogin": "Маєте обліковий запис? Перейти до входу", + "registerNow": "Зареєструватися зараз", + "welcome": "Ласкаво просимо, будь ласка, також підтвердьте свою електронну пошту" +} diff --git a/ui/locales/uk/statistic.json b/ui/locales/uk/statistic.json new file mode 100644 index 00000000..f59f67f0 --- /dev/null +++ b/ui/locales/uk/statistic.json @@ -0,0 +1,5 @@ +{ + "totalForms": "Усього форм", + "totalSubmissions": "Загальна кількість заявок", + "totalUsers": "Всього користувачів" +} diff --git a/ui/locales/uk/submission.json b/ui/locales/uk/submission.json new file mode 100644 index 00000000..cef1dcb4 --- /dev/null +++ b/ui/locales/uk/submission.json @@ -0,0 +1,17 @@ +{ + "add": "Додати подання", + "city": "Місто", + "country": "Країна", + "created": "Створено", + "device": { + "name": "Ім'я пристрою", + "type": "Тип пристрою" + }, + "edit": "Редагувати", + "export": "Експорт", + "field": "Поле", + "lastModified": "Остання зміна", + "progress": "Прогрес", + "submission": "Заповнені форми", + "value": "Значення" +} diff --git a/ui/locales/uk/type.json b/ui/locales/uk/type.json new file mode 100644 index 00000000..a4192afe --- /dev/null +++ b/ui/locales/uk/type.json @@ -0,0 +1,68 @@ +{ + "confirmDelete": "Справді видалити це поле? Переконайтеся, що на нього ніде немає посилань!", + "date": { + "default": "Дата за замовчуванням", + "max": "Максимальна дата", + "min": "Мінімальна дата", + "name": "Дата" + }, + "deleteNow": "Видалити поле", + "description": "Опис", + "descriptionInfo": "Використовуйте markdown для розширеного форматування", + "dropdown": { + "addOption": "Додати варіант", + "default": "Значення за замовчуванням", + "name": "Випадаюче меню", + "options": "Варіанти", + "removeOption": "Видалити", + "titlePlaceholder": "Заголовок", + "valuePlaceholder": "Значення" + }, + "email": { + "default": "Електронна пошта за замовчуванням", + "name": "Email" + }, + "hidden": { + "default": "Значення за замовчуванням", + "name": "Приховано" + }, + "link": { + "default": "Посилання за замовчуванням", + "name": "URL" + }, + "number": { + "default": "Число за замовчуванням", + "name": "Число" + }, + "radio": { + "addOption": "Додати варіант", + "default": "Значення за замовчуванням", + "name": "Один з декількох", + "options": "Варіанти", + "removeOption": "Видалити", + "titlePlaceholder": "Заголовок", + "valuePlaceholder": "Значення" + }, + "rating": { + "clearNote": "Клацніть ще раз, щоб видалити значення за замовчуванням", + "default": "Значення за замовчуванням", + "name": "Рейтинг (від\/до)" + }, + "required": "Обов'язково", + "requiredInfo": "Якщо потрібно, значення за замовчуванням повинно бути встановлене, щоб користувачі могли подавати форму!", + "slug": "Slug", + "slugInfo": "Використовуйте slug для передачі значення як параметр в url?slug=value", + "textarea": { + "default": "Значення за замовчуванням", + "name": "Область тексту" + }, + "textfield": { + "default": "Значення за замовчуванням", + "name": "Рядок тексту" + }, + "title": "Заголовок", + "yes_no": { + "default": "Значення за замовчуванням", + "name": "Так \/ Ні" + } +} diff --git a/ui/locales/uk/user.json b/ui/locales/uk/user.json new file mode 100644 index 00000000..23c425f4 --- /dev/null +++ b/ui/locales/uk/user.json @@ -0,0 +1,18 @@ +{ + "baseData": "Основні дані", + "confirmDelete": "Ви впевнені у видаленні цього користувача?", + "deleteError": "не вдалося видалити користувача", + "deleteNow": "Видалити зараз!", + "deleted": "Користувача видалено", + "loading": "Завантаження користувача", + "mange": "Редагувати користувача \" {{email}} \"", + "row": { + "created": "Створено", + "email": "Email", + "menu": "Меню", + "roles": "Роль" + }, + "updateError": "Не вдалося оновити користувача", + "updateNow": "Зберегти", + "updated": "Користувача оновлено" +} diff --git a/ui/locales/uk/validation.json b/ui/locales/uk/validation.json new file mode 100644 index 00000000..d8ac8486 --- /dev/null +++ b/ui/locales/uk/validation.json @@ -0,0 +1,18 @@ +{ + "emailFieldRequired": "Виберіть оберіть поле електронної пошти", + "emailRequired": "Будь ласка, введіть адресу електронної пошти", + "invalidEmail": "Має бути дійсною адресою електронної пошти!", + "invalidNumber": "Має бути припустимим числом!", + "invalidSlug": "Slug може містити лише малі літери az, 0-9 та _", + "invalidUrl": "Має бути дійсною URL-адресою", + "languageRequired": "Виберіть мову", + "mandatoryFieldsMissing": "Обов’язкові поля відсутні", + "passwordMinLength": "Має бути довшим або рівним 5 символам!", + "passwordRequired": "Будь ласка, введіть ваш пароль!", + "subjectRequired": "Будь ласка, надайте тему", + "templateRequired": "Будь ласка, введіть шаблон", + "titleRequired": "Будь ласка, введіть заголовок", + "urlRequired": "Укажіть URL-адресу", + "usernameRequired": "Введіть ім’я користувача", + "valueRequired": "Будь ласка, заповніть поле" +} diff --git a/ui/next-env.d.ts b/ui/next-env.d.ts new file mode 100644 index 00000000..2532e77a --- /dev/null +++ b/ui/next-env.d.ts @@ -0,0 +1,4 @@ +/// <reference types="next" /> + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/ui/next.config.js b/ui/next.config.js new file mode 100644 index 00000000..e8e5320f --- /dev/null +++ b/ui/next.config.js @@ -0,0 +1,31 @@ +const p = require('./package.json') +const optimizedImages = require('next-optimized-images') +const withPlugins = require('next-compose-plugins') + +const environment = process.env.NODE_ENV ? process.env.NODE_ENV : 'dev'; +const version = p.version; + +module.exports = withPlugins([ + optimizedImages({ + + }), + { + images: { + disableStaticImages: true, + }, + poweredByHeader: true, + productionBrowserSourceMaps: true, + publicRuntimeConfig: { + environment, + endpoint: process.env.ENDPOINT || '/graphql', + spa: !!process.env.SPA || false, + mainBackground: process.env.MAIN_BACKGROUND || '#8FA2A6' + }, + serverRuntimeConfig: { + endpoint: process.env.SERVER_ENDPOINT || process.env.ENDPOINT || '/graphql', + }, + env: { + version, + } + } +]) diff --git a/ui/next.config.type.ts b/ui/next.config.type.ts new file mode 100644 index 00000000..1c668762 --- /dev/null +++ b/ui/next.config.type.ts @@ -0,0 +1,11 @@ +export interface NextConfigType { + publicRuntimeConfig: { + environment: string, + endpoint: string + spa?: boolean + mainBackground?: string + } + serverRuntimeConfig: { + endpoint: string + } +} diff --git a/ui/package.json b/ui/package.json new file mode 100644 index 00000000..3f132289 --- /dev/null +++ b/ui/package.json @@ -0,0 +1,77 @@ +{ + "name": "ohmyform-react", + "version": "1.0.3", + "license": "AGPL-3.0-or-later", + "scripts": { + "start:dev": "next dev -p 4000", + "build": "next build", + "lint": "eslint pages/ store/ components/ graphql/", + "type-check": "tsc --pretty", + "export": "cross-env SPA=1 next build && cross-env SPA=1 next export", + "start": "next start -p $PORT", + "translation:sort": "cross-env TS_NODE_TRANSPILE_ONLY=true ts-node-script locales/sort.ts", + "translation:missing": "cross-env TS_NODE_TRANSPILE_ONLY=true ts-node locales/missing.ts" + }, + "dependencies": { + "@ant-design/icons": "^4.7.0", + "@apollo/client": "^3.5.9", + "antd": "^4.18.8", + "cross-env": "^7.0.3", + "dayjs": "^1.10.7", + "debug": "^4.3.3", + "exceljs": "^4.3.0", + "expressionparser": "^1.1.5", + "graphql": "^16.3.0", + "i18next": "^21.6.12", + "i18next-browser-languagedetector": "^6.1.3", + "imagemin-optipng": "^8.0.0", + "isomorphic-fetch": "^3.0.0", + "jimp": "^0.16.1", + "leaflet": "^1.7.1", + "next": "^12.1.0", + "next-compose-plugins": "^2.2.1", + "next-optimized-images": "^2.6.2", + "next-redux-wrapper": "^7.0.5", + "polished": "^4.1.4", + "react": "^17.0.2", + "react-color": "^2.19.3", + "react-dom": "^17.0.2", + "react-github-button": "^0.1.11", + "react-i18next": "^11.15.5", + "react-icons": "^4.3.1", + "react-id-swiper": "^4.0.0", + "react-leaflet": "^3.2.5", + "react-markdown": "^8.0.0", + "react-redux": "^7.2.6", + "redux": "^4.1.2", + "redux-devtools-extension": "^2.13.9", + "redux-thunk": "^2.4.1", + "responsive-loader": "^2.3.0", + "sass": "^1.49.9", + "styled-components": "^5.3.3", + "swiper": "^8.0.6" + }, + "devDependencies": { + "@types/leaflet": "^1.7.9", + "@types/mathjs": "^9.4.2", + "@types/node": "^16.11.17", + "@types/node-fetch": "^3.0.3", + "@types/react": "^17.0.39", + "@types/styled-components": "^5.1.23", + "@types/swiper": "^6.0.0", + "@typescript-eslint/eslint-plugin": "^5.12.1", + "@typescript-eslint/parser": "^5.12.1", + "commander": "^9.0.0", + "eslint": "^8.10.0", + "eslint-config-prettier": "^8.4.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-prettier": "^4.0.0", + "eslint-plugin-react": "^7.29.2", + "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-unused-imports": "^2.0.0", + "lodash.merge": "^4.6.2", + "prettier": "^2.5.1", + "ts-node": "^10.5.0", + "typescript": "^4.5.5" + } +} diff --git a/ui/pages/_app.tsx b/ui/pages/_app.tsx new file mode 100644 index 00000000..59ca6737 --- /dev/null +++ b/ui/pages/_app.tsx @@ -0,0 +1,55 @@ +import { ApolloProvider } from '@apollo/client' +import 'antd/dist/antd.css' +import 'assets/global.scss' +import 'assets/variables.scss' +import debug from 'debug' +import 'i18n' +import getConfig from 'next/config' +import { AppInitialProps, AppType } from 'next/dist/shared/lib/utils' +import Head from 'next/head' +import React, { useEffect } from 'react' +import { wrapper } from 'store' +import getClient from '../graphql/client' +import { NextConfigType } from '../next.config.type' + +const { publicRuntimeConfig } = getConfig() as NextConfigType + +const App: AppType = ({ Component, pageProps }) => { + + useEffect(() => { + if (publicRuntimeConfig.environment !== 'production') { + debug.enable('*,-micromark') + } + }) + + useEffect(() => { + if (!/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) { + return + } + + const resize = () => { + const vh = window.innerHeight * 0.01; + document.documentElement.style.setProperty('--vh', `${vh}px`); + } + + window.addEventListener('resize', resize) + + return () => window.removeEventListener('resize', resize) + }) + + return ( + <ApolloProvider client={getClient()}> + <Head> + <title>OhMyForm + + + + + ) +} + +App.getInitialProps = (): AppInitialProps => ({ + pageProps: {}, +}) + +export default wrapper.withRedux(App) diff --git a/ui/pages/admin/forms/[id]/index.tsx b/ui/pages/admin/forms/[id]/index.tsx new file mode 100644 index 00000000..34960d09 --- /dev/null +++ b/ui/pages/admin/forms/[id]/index.tsx @@ -0,0 +1,211 @@ +import { Button, Form, Input, message, Tabs } from 'antd' +import { useForm } from 'antd/lib/form/Form' +import { cleanInput } from 'components/clean.input' +import { BaseDataTab } from 'components/form/admin/base.data.tab' +import { DesignTab } from 'components/form/admin/design.tab' +import { EndPageTab } from 'components/form/admin/end.page.tab' +import { FieldsTab } from 'components/form/admin/fields.tab' +import { NotificationsTab } from 'components/form/admin/notifications.tab' +import { StartPageTab } from 'components/form/admin/start.page.tab' +import { Structure } from 'components/structure' +import { withAuth } from 'components/with.auth' +import debug from 'debug' +import { useFormUpdateMutation } from 'graphql/mutation/form.update.mutation' +import { NextPage } from 'next' +import Link from 'next/link' +import { useRouter } from 'next/router' +import React, { useState } from 'react' +import { useTranslation } from 'react-i18next' +import { HooksTab } from '../../../../components/form/admin/hooks.tab' +import { + FormFieldFragment, + FormFieldOptionKeysFragment, +} from '../../../../graphql/fragment/form.fragment' +import { Data, useFormQuery } from '../../../../graphql/query/form.query' + +const logger = debug('page/admin/form/[id]') + +const Index: NextPage = () => { + const { t } = useTranslation() + const router = useRouter() + const [form] = useForm() + const [saving, setSaving] = useState(false) + const [fields, setFields] = useState([]) + const [update] = useFormUpdateMutation() + + const processNext = (next: Data) => { + return { + form: { + ...next.form, + fields: next.form.fields + .map((field) => { + const keys: FormFieldOptionKeysFragment = {} + + field.options.forEach((option) => { + if (option.key) { + try { + keys[option.key] = JSON.parse(option.value) + } catch (e) { + logger('invalid option value %O', e) + } + } + }) + + return { + ...field, + defaultValue: field.defaultValue ? JSON.parse(field.defaultValue) : null, + options: field.options.filter((option) => !option.key), + optionKeys: keys, + } + }) + .sort((a, b) => a.idx - b.idx), + }, + } + } + + const { data, loading, error } = useFormQuery({ + variables: { + id: router.query.id as string, + }, + onCompleted: (next) => { + const processed = processNext(next) + form.setFieldsValue(processed) + setFields(processed.form.fields) + }, + }) + + const save = async (formData: Data) => { + setSaving(true) + + formData.form.fields = formData.form.fields + .filter((e) => e && e.type) + .map(({ optionKeys, ...field }, index) => { + const options = field.options + + if (optionKeys) { + Object.keys(optionKeys).forEach((key) => { + if (optionKeys[key] === undefined) { + return + } + + options.push({ + id: null, // TODO improve this + value: JSON.stringify(optionKeys[key]), + key, + }) + }) + } + + return { + ...field, + defaultValue: field.defaultValue !== null ? JSON.stringify(field.defaultValue) : null, + options, + idx: index, + } + }) + + try { + const next = processNext( + ( + await update({ + variables: cleanInput(formData), + }) + ).data + ) + + form.setFieldsValue(next) + setFields(next.form.fields) + + await message.success(t('form:updated')) + } catch (e) { + console.error('failed to save', e) + await message.error(t('form:updateError')) + } + + setSaving(false) + } + + if (error) { + return ( + + Not Found + + ) + } + + return ( + + + , + , + ]} + style={{ paddingTop: 0 }} + > +
{ + // TODO process errors + await message.error(t('validation:mandatoryFieldsMissing')) + }} + labelCol={{ + xs: { span: 24 }, + sm: { span: 6 }, + }} + wrapperCol={{ + xs: { span: 24 }, + sm: { span: 18 }, + }} + > + + + + + + + + + + + + + +
+
+ ) +} + +export default withAuth(Index, ['admin']) diff --git a/ui/pages/admin/forms/[id]/submissions.tsx b/ui/pages/admin/forms/[id]/submissions.tsx new file mode 100644 index 00000000..7bd53c7a --- /dev/null +++ b/ui/pages/admin/forms/[id]/submissions.tsx @@ -0,0 +1,148 @@ +import { Button, Progress, Table } from 'antd' +import { PaginationProps } from 'antd/es/pagination' +import { ProgressProps } from 'antd/lib/progress' +import { ColumnsType } from 'antd/lib/table/interface' +import { DateTime } from 'components/date.time' +import Structure from 'components/structure' +import { TimeAgo } from 'components/time.ago' +import { withAuth } from 'components/with.auth' +import dayjs from 'dayjs' +import { NextPage } from 'next' +import Link from 'next/link' +import { useRouter } from 'next/router' +import React, { useState } from 'react' +import { useTranslation } from 'react-i18next' +import { ExportSubmissionAction } from '../../../../components/form/admin/export.submission.action' +import { SubmissionValues } from '../../../../components/form/admin/submission.values' +import { FormPagerFragment } from '../../../../graphql/fragment/form.pager.fragment' +import { SubmissionFragment } from '../../../../graphql/fragment/submission.fragment' +import { useSubmissionPagerQuery } from '../../../../graphql/query/submission.pager.query' + +const Submissions: NextPage = () => { + const { t } = useTranslation() + const router = useRouter() + const [pagination, setPagination] = useState({ + pageSize: 25, + }) + const [form, setForm] = useState() + const [entries, setEntries] = useState() + const { loading, refetch } = useSubmissionPagerQuery({ + variables: { + form: router.query.id as string, + limit: pagination.pageSize, + start: Math.max(0, pagination.current - 1) * pagination.pageSize || 0, + filter: { + excludeEmpty: true, + }, + }, + onCompleted: ({ pager, form }) => { + setPagination({ + ...pagination, + total: pager.total, + }) + setForm(form) + setEntries(pager.entries) + }, + }) + + const columns: ColumnsType = [ + { + title: t('submission:progress'), + render(_, row) { + const props: ProgressProps = { + status: 'active', + percent: Math.round(row.percentageComplete * 100), + } + + if (row.percentageComplete >= 1) { + props.status = 'success' + } else if (dayjs().diff(dayjs(row.lastModified), 'hour') > 4) { + props.status = 'exception' + } + + return + }, + }, + { + title: t('submission:created'), + dataIndex: 'created', + render(date: string) { + return + }, + responsive: ['lg'], + }, + { + title: t('submission:lastModified'), + dataIndex: 'lastModified', + render(date: string) { + return + }, + responsive: ['lg'], + }, + ] + + return ( + ( + + )} + />, + + + , + , + ]} + > + + }, + rowExpandable(record) { + return record.percentageComplete > 0 + }, + }} + onChange={async (next) => { + setPagination(next) + await refetch() + }} + /> + + ) +} + +export default withAuth(Submissions, ['admin']) diff --git a/ui/pages/admin/forms/create.tsx b/ui/pages/admin/forms/create.tsx new file mode 100644 index 00000000..7815dfd3 --- /dev/null +++ b/ui/pages/admin/forms/create.tsx @@ -0,0 +1,131 @@ +import { Button, Form, Input, message, Tabs } from 'antd' +import { cleanInput } from 'components/clean.input' +import { BaseDataTab } from 'components/form/admin/base.data.tab' +import Structure from 'components/structure' +import { withAuth } from 'components/with.auth' +import { FormFragment } from 'graphql/fragment/form.fragment' +import { useFormCreateMutation } from 'graphql/mutation/form.create.mutation' +import { NextPage } from 'next' +import { useRouter } from 'next/router' +import React, { useState } from 'react' +import { useTranslation } from 'react-i18next' + +interface FormData { + form: FormFragment +} + +const Create: NextPage = () => { + const { t } = useTranslation() + const router = useRouter() + const [form] = Form.useForm() + const [saving, setSaving] = useState(false) + const [create] = useFormCreateMutation() + + const save = async (formData: FormData) => { + setSaving(true) + + try { + const next = ( + await create({ + variables: cleanInput(formData), + }) + ).data + + await message.success(t('form:created')) + + await router.replace('/admin/forms/[id]', `/admin/forms/${next.form.id}`) + } catch (e) { + console.error('failed to save', e) + await message.error(t('form:creationError')) + } + + setSaving(false) + } + + return ( + + {t('form:createNow')} + , + ]} + style={{ paddingTop: 0 }} + > +
{ + // TODO process errors + await message.error(t('validation:mandatoryFieldsMissing')) + }} + labelCol={{ + xs: { span: 24 }, + sm: { span: 6 }, + }} + wrapperCol={{ + xs: { span: 24 }, + sm: { span: 18 }, + }} + > + + + + + + + + + + + + + + + + + + + + + + + + +
+ ) +} + +export default withAuth(Create, ['admin']) diff --git a/ui/pages/admin/forms/index.tsx b/ui/pages/admin/forms/index.tsx new file mode 100644 index 00000000..8d77d993 --- /dev/null +++ b/ui/pages/admin/forms/index.tsx @@ -0,0 +1,202 @@ +import { + DeleteOutlined, + EditOutlined, + GlobalOutlined, + UnorderedListOutlined, + WarningOutlined, +} from '@ant-design/icons/lib' +import { Button, message, Popconfirm, Space, Table, Tag, Tooltip } from 'antd' +import { PaginationProps } from 'antd/es/pagination' +import { ColumnsType } from 'antd/lib/table/interface' +import { DateTime } from 'components/date.time' +import { FormIsLive } from 'components/form/admin/is.live' +import Structure from 'components/structure' +import { TimeAgo } from 'components/time.ago' +import { withAuth } from 'components/with.auth' +import { NextPage } from 'next' +import Link from 'next/link' +import React, { useState } from 'react' +import { useTranslation } from 'react-i18next' +import { useWindowSize } from '../../../components/use.window.size' +import { FormPagerFragment } from '../../../graphql/fragment/form.pager.fragment' +import { useFormDeleteMutation } from '../../../graphql/mutation/form.delete.mutation' +import { useFormPagerQuery } from '../../../graphql/query/form.pager.query' + +const Index: NextPage = () => { + const { t } = useTranslation() + const { width } = useWindowSize() + const [pagination, setPagination] = useState({ + pageSize: 25, + }) + const [entries, setEntries] = useState() + const { loading, refetch, error } = useFormPagerQuery({ + variables: { + limit: pagination.pageSize, + start: Math.max(0, pagination.current - 1) * pagination.pageSize || 0, + }, + onCompleted: ({ pager }) => { + setPagination({ + ...pagination, + total: pager.total, + }) + setEntries(pager.entries) + }, + }) + const [executeDelete] = useFormDeleteMutation() + + const deleteForm = async (id: string) => { + try { + await executeDelete({ + variables: { + id, + }, + }) + const next = entries.filter((entry) => entry.id !== id) + if (next.length === 0) { + setPagination({ ...pagination, current: 1 }) + } else { + setEntries(next) + } + + await message.success(t('form:deleted')) + } catch (e) { + await message.error(t('form:deleteError')) + } + } + + const columns: ColumnsType = [ + { + title: t('form:row.isLive'), + dataIndex: 'isLive', + render(live: boolean) { + return + }, + responsive: ['md'], + }, + { + title: t('form:row.title'), + dataIndex: 'title', + }, + { + title: t('form:row.admin'), + dataIndex: 'admin', + render(_, { admin: user }) { + if (!user) { + return + } + + return ( + + + + + + ) + }, + responsive: ['lg'], + }, + { + title: t('form:row.language'), + dataIndex: 'language', + render(lang: string) { + return t(`language:${lang}`) + }, + responsive: ['lg'], + }, + { + title: t('form:row.created'), + dataIndex: 'created', + render(date: string) { + return + }, + responsive: ['lg'], + }, + { + title: t('form:row.lastModified'), + dataIndex: 'lastModified', + render(date: string) { + return + }, + responsive: ['md'], + }, + { + title: t('form:row.menu'), + align: 'right', + render(_, row) { + return ( + + + + + + + + + + + + deleteForm(row.id)} + okText={t('form:deleteNow')} + okButtonProps={{ danger: true }} + > + + + + {row.isLive && ( + + )} + + {!row.isLive && ( + + + + )} + + + + ) + }, + }, + ] + + return ( + + + , + ]} + error={error?.message} + > +
{ + setPagination(next) + await refetch() + }} + /> + + ) +} + +export default withAuth(Index, ['admin']) diff --git a/ui/pages/admin/index.tsx b/ui/pages/admin/index.tsx new file mode 100644 index 00000000..213755f8 --- /dev/null +++ b/ui/pages/admin/index.tsx @@ -0,0 +1,42 @@ +import { useQuery } from '@apollo/client' +import { Col, Row, Statistic } from 'antd' +import Structure from 'components/structure' +import { withAuth } from 'components/with.auth' +import { NextPage } from 'next' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { + ADMIN_STATISTIC_QUERY, + AdminStatisticQueryData, + AdminStatisticQueryVariables, +} from '../../graphql/query/admin.statistic.query' + +const Index: NextPage = () => { + const { t } = useTranslation() + const { data, loading } = useQuery( + ADMIN_STATISTIC_QUERY + ) + + return ( + + + + + + + + + + + + + + + + ) +} + +export default withAuth(Index, ['admin']) diff --git a/ui/pages/admin/profile.tsx b/ui/pages/admin/profile.tsx new file mode 100644 index 00000000..3d5c2787 --- /dev/null +++ b/ui/pages/admin/profile.tsx @@ -0,0 +1,202 @@ +import { Button, Divider, Form, Input, message, Select } from 'antd' +import { useForm } from 'antd/lib/form/Form' +import { NextPage } from 'next' +import { useRouter } from 'next/router' +import React, { useState } from 'react' +import { useTranslation } from 'react-i18next' +import Structure from '../../components/structure' +import { withAuth } from '../../components/with.auth' +import { useProfileUpdateMutation } from '../../graphql/mutation/profile.update.mutation' +import { useProfileQuery } from '../../graphql/query/admin.profile.query' +import { languages } from '../../i18n' + +interface FormData { + user: { + id: string + username: string + email: string + language: string + firstName: string + lastName: string + } + password: string + confirm: string +} + +const Profile: NextPage = () => { + const { t } = useTranslation() + const [form] = useForm() + const [saving, setSaving] = useState(false) + const router = useRouter() + + const { loading } = useProfileQuery({ + onCompleted: (next) => { + form.setFieldsValue(next) + }, + onError(e) { + void router.push('/') + }, + }) + + const [update] = useProfileUpdateMutation() + + const save = async (data: FormData) => { + setSaving(true) + + try { + const next = ( + await update({ + variables: { + user: { + ...data.user, + password: data.password && data.password === data.confirm ? data.password : undefined, + }, + }, + }) + ).data + + form.setFieldsValue(next) + + await message.success(t('profile:updated')) + } catch (e) { + console.error('failed to save', e) + await message.error(t('profile:updateError')) + } + + setSaving(false) + } + + return ( + + {t('profile:updateNow')} + , + ]} + > +
{ + // TODO process errors + await message.error(t('validation:mandatoryFieldsMissing')) + }} + labelCol={{ + xs: { span: 24 }, + sm: { span: 6 }, + }} + wrapperCol={{ + xs: { span: 24 }, + sm: { span: 18 }, + }} + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {() => ( + ({ + validator(_, value) { + if (!value || getFieldValue('password') === value) { + return Promise.resolve() + } + return Promise.reject(new Error(t('validation:passwordConfirmMismatch'))) + }, + }), + ]} + > + + + )} + + +
+ ) +} + +export default withAuth(Profile) diff --git a/ui/pages/admin/users/[id]/index.tsx b/ui/pages/admin/users/[id]/index.tsx new file mode 100644 index 00000000..c28bd884 --- /dev/null +++ b/ui/pages/admin/users/[id]/index.tsx @@ -0,0 +1,103 @@ +import { useQuery } from '@apollo/client' +import { Button, Form, Input, message, Tabs } from 'antd' +import { useForm } from 'antd/lib/form/Form' +import Structure from 'components/structure' +import { withAuth } from 'components/with.auth' +import { NextPage } from 'next' +import { useRouter } from 'next/router' +import React, { useState } from 'react' +import { useTranslation } from 'react-i18next' +import { cleanInput } from '../../../../components/clean.input' +import { BaseDataTab } from '../../../../components/user/admin/base.data.tab' +import { useUserUpdateMutation } from '../../../../graphql/mutation/user.update.mutation' +import { + ADMIN_USER_QUERY, + AdminUserQueryData, + AdminUserQueryVariables, +} from '../../../../graphql/query/admin.user.query' + +const Index: NextPage = () => { + const { t } = useTranslation() + const router = useRouter() + const [form] = useForm() + const [saving, setSaving] = useState(false) + + const { data, loading } = useQuery( + ADMIN_USER_QUERY, + { + variables: { + id: router.query.id as string, + }, + onCompleted: (next) => { + form.setFieldsValue(next) + }, + } + ) + + const [update] = useUserUpdateMutation() + + const save = async (formData: AdminUserQueryData) => { + setSaving(true) + try { + const next = ( + await update({ + variables: cleanInput(formData), + }) + ).data + + form.setFieldsValue(next) + + await message.success(t('user:updated')) + } catch (e) { + console.error('failed to save', e) + await message.error(t('user:updateError')) + } + + setSaving(false) + } + + return ( + + {t('user:updateNow')} + , + ]} + style={{ paddingTop: 0 }} + > +
{ + // TODO process errors + await message.error(t('validation:mandatoryFieldsMissing')) + }} + labelCol={{ + xs: { span: 24 }, + sm: { span: 6 }, + }} + wrapperCol={{ + xs: { span: 24 }, + sm: { span: 18 }, + }} + > + + + + + + + + +
+ ) +} + +export default withAuth(Index, ['admin']) diff --git a/ui/pages/admin/users/index.tsx b/ui/pages/admin/users/index.tsx new file mode 100644 index 00000000..899ac21b --- /dev/null +++ b/ui/pages/admin/users/index.tsx @@ -0,0 +1,132 @@ +import { DeleteOutlined, EditOutlined } from '@ant-design/icons/lib' +import { Button, message, Popconfirm, Space, Table, Tag } from 'antd' +import { PaginationProps } from 'antd/es/pagination' +import { ColumnsType } from 'antd/lib/table/interface' +import Structure from 'components/structure' +import { withAuth } from 'components/with.auth' +import { NextPage } from 'next' +import Link from 'next/link' +import React, { useState } from 'react' +import { useTranslation } from 'react-i18next' +import { DateTime } from '../../../components/date.time' +import { useWindowSize } from '../../../components/use.window.size' +import { UserRole } from '../../../components/user/role' +import { UserPagerFragment } from '../../../graphql/fragment/user.pager.fragment' +import { useUserDeleteMutation } from '../../../graphql/mutation/user.delete.mutation' +import { useUserPagerQuery } from '../../../graphql/query/user.pager.query' + +const Index: NextPage = () => { + const { width } = useWindowSize() + const { t } = useTranslation() + const [pagination, setPagination] = useState({ + pageSize: 10, + }) + const [entries, setEntries] = useState() + const { loading, refetch, error } = useUserPagerQuery({ + variables: { + limit: pagination.pageSize, + start: Math.max(0, pagination.current - 1) * pagination.pageSize || 0, + }, + onCompleted: ({ pager }) => { + setPagination({ + ...pagination, + total: pager.total, + }) + setEntries(pager.entries) + }, + }) + const [executeDelete] = useUserDeleteMutation() + + const deleteUser = async (id: string) => { + try { + await executeDelete({ + variables: { + id, + }, + }) + const next = entries.filter((entry) => entry.id !== id) + if (next.length === 0) { + setPagination({ ...pagination, current: 1 }) + } else { + setEntries(next) + } + await message.success(t('user:deleted')) + } catch (e) { + await message.error(t('user:deleteError')) + } + } + + const columns: ColumnsType = [ + { + title: t('user:row.roles'), + dataIndex: 'roles', + render(roles: string[]) { + return + }, + responsive: ['md'], + }, + { + title: t('user:row.email'), + render(_, row) { + return {row.email} + }, + }, + { + title: t('user:row.created'), + dataIndex: 'created', + render(date: string) { + return + }, + responsive: ['lg'], + }, + { + title: t('user:row.menu'), + align: 'right', + render(_, row) { + return ( + + + + + + deleteUser(row.id)} + okText={t('user:deleteNow')} + okButtonProps={{ danger: true }} + > + + + + ) + }, + }, + ] + + return ( + +
{ + setPagination(next) + await refetch() + }} + /> + + ) +} + +export default withAuth(Index, ['admin']) diff --git a/ui/pages/form/[id]/index.module.scss b/ui/pages/form/[id]/index.module.scss new file mode 100644 index 00000000..2f2db7d2 --- /dev/null +++ b/ui/pages/form/[id]/index.module.scss @@ -0,0 +1,3 @@ + +.page { +} diff --git a/ui/pages/form/[id]/index.tsx b/ui/pages/form/[id]/index.tsx new file mode 100644 index 00000000..1700fedf --- /dev/null +++ b/ui/pages/form/[id]/index.tsx @@ -0,0 +1,55 @@ +import { ErrorPage } from 'components/error.page' +import { LoadingPage } from 'components/loading.page' +import { NextPage } from 'next' +import { useRouter } from 'next/router' +import React, { useEffect } from 'react' +import { useTranslation } from 'react-i18next' +import { CardLayout } from '../../../components/form/layouts/card' +import { SliderLayout } from '../../../components/form/layouts/slider' +import { useSubmission } from '../../../components/use.submission' +import { useFormPublicQuery } from '../../../graphql/query/form.public.query' + +const Index: NextPage = () => { + const { t, i18n } = useTranslation() + const router = useRouter() + const submission = useSubmission(router.query.id as string) + + const { loading, data, error } = useFormPublicQuery({ + variables: { + id: router.query.id as string, + }, + }) + + useEffect(() => { + // check form language to switch to! + if (!data) { + return + } + + if (i18n.language !== data.form.language) { + // TODO prompt for language change if is not a match! + i18n + .changeLanguage(data.form.language) + .catch((e: Error) => console.error('failed to change language', e)) + } + }, [data]) + + if (loading) { + return + } + + if (error) { + return + } + + switch (data.form.design.layout) { + case 'card': + return + + case 'slider': + default: + return + } +} + +export default Index diff --git a/ui/pages/form/index.tsx b/ui/pages/form/index.tsx new file mode 100644 index 00000000..ddab3ce0 --- /dev/null +++ b/ui/pages/form/index.tsx @@ -0,0 +1,8 @@ +import { ErrorPage } from 'components/error.page' +import { NextPage } from 'next' +import React from 'react' + +const Index: NextPage = () => { + return +} +export default Index diff --git a/ui/pages/index.tsx b/ui/pages/index.tsx new file mode 100644 index 00000000..325c150b --- /dev/null +++ b/ui/pages/index.tsx @@ -0,0 +1,100 @@ +import { Alert, Layout } from 'antd' +import { AuthFooter } from 'components/auth/footer' +import { GetStaticProps, NextPage } from 'next' +import getConfig from 'next/config' +import { useRouter } from 'next/router' +import React, { useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { LoadingPage } from '../components/loading.page' +import { Omf } from '../components/omf' +import { useStatusQuery } from '../graphql/query/status.query' +import { NextConfigType } from '../next.config.type' + +const { publicRuntimeConfig } = getConfig() as NextConfigType + +const Index: NextPage = () => { + const router = useRouter() + const { t } = useTranslation() + const [loading, setLoading] = useState( + publicRuntimeConfig.spa || (process.browser && router.pathname !== window.location.pathname) + ) + const status = useStatusQuery() + + useEffect(() => { + if (router.pathname !== window.location.pathname) { + let href = router.asPath + const as = router.asPath + const possible = [ + /(\/form\/)[^/]+/i, /(\/admin\/forms\/)[^/]+/i, /(\/admin\/users\/)[^/]+/i, + ] + + possible.forEach((r) => { + if (r.test(as)) { + href = href.replace(r, '$1[id]') + } + }) + + router.replace(href, as).catch((e: Error) => { + console.error('failed redirect', e) + }) + } + }) + + useEffect(() => { + if (loading) { + setTimeout(() => { + setLoading(false) + }, 10000) + } + }, [loading]) + + if (loading) { + return + } + + return ( + + +
+ {'OhMyForm'} +
+ + {status.error && ( + + )} + +
+ ) +} + +export const getStaticProps: GetStaticProps = async () => { + // just to be conforming with eslint + await Promise.resolve() + + return { + revalidate: 10, + props: {}, + } +} + +export default Index diff --git a/ui/pages/login/confirm/[code].tsx b/ui/pages/login/confirm/[code].tsx new file mode 100644 index 00000000..0ba0ae81 --- /dev/null +++ b/ui/pages/login/confirm/[code].tsx @@ -0,0 +1,28 @@ +import { Alert } from 'antd' +import { AuthFooter } from 'components/auth/footer' +import { AuthLayout } from 'components/auth/layout' +import { NextPage } from 'next' +import React from 'react' +import { Omf } from '../../../components/omf' + +const Index: NextPage = () => { + return ( + + + + + + + ) +} + +export default Index diff --git a/ui/pages/login/index.module.scss b/ui/pages/login/index.module.scss new file mode 100644 index 00000000..0c7fb8a4 --- /dev/null +++ b/ui/pages/login/index.module.scss @@ -0,0 +1,11 @@ + +.otherActions { + width: 100%; + justify-content: center; + display: flex; + + + @media (max-width: 600px) { + flex-direction: column; + } +} diff --git a/ui/pages/login/index.tsx b/ui/pages/login/index.tsx new file mode 100644 index 00000000..04f782f0 --- /dev/null +++ b/ui/pages/login/index.tsx @@ -0,0 +1,148 @@ +import { useMutation } from '@apollo/client' +import { Alert, Button, Form, Input, message } from 'antd' +import { useForm } from 'antd/lib/form/Form' +import { AuthFooter } from 'components/auth/footer' +import { AuthLayout } from 'components/auth/layout' +import { setAuth } from 'components/with.auth' +import { + LOGIN_MUTATION, + LoginMutationData, + LoginMutationVariables, +} from 'graphql/mutation/login.mutation' +import { NextPage } from 'next' +import Link from 'next/link' +import { useRouter } from 'next/router' +import React, { useState } from 'react' +import { useTranslation } from 'react-i18next' +import ReactMarkdown from 'react-markdown' +import { Omf } from '../../components/omf' +import { useSettingsQuery } from '../../graphql/query/settings.query' +import scss from './index.module.scss' + +const Index: NextPage = () => { + const { t } = useTranslation() + const [form] = useForm() + const router = useRouter() + const [loading, setLoading] = useState(false) + const [login] = useMutation(LOGIN_MUTATION) + const { data } = useSettingsQuery() + + const finish = async (data: LoginMutationVariables) => { + setLoading(true) + try { + const result = await login({ + variables: data, + }) + + setAuth(result.data.tokens.access, result.data.tokens.refresh) + + await message.success(t('login:welcomeBack')) + + await router.push('/admin') + } catch (e) { + await message.error(t('login:invalidLoginCredentials')) + } + + setLoading(false) + } + + const failed = async () => { + await message.error(t('validation:mandatoryFieldsMissing')) + } + + return ( + + +
+
+ {'OhMyForm'} +
+ + {data && data.loginNote.value && ( + {data.loginNote.value}} + style={{ + marginBottom: 24, + }} + /> + )} + + + + + + + + + + + + + + + {(!data || !data.disabledSignUp.value) && ( + + + + )} + + + + + + + +
+ ) +} + +export default Index diff --git a/ui/pages/login/recover.tsx b/ui/pages/login/recover.tsx new file mode 100644 index 00000000..fecd79f0 --- /dev/null +++ b/ui/pages/login/recover.tsx @@ -0,0 +1,28 @@ +import { Alert } from 'antd' +import { AuthFooter } from 'components/auth/footer' +import { AuthLayout } from 'components/auth/layout' +import { NextPage } from 'next' +import React from 'react' +import { Omf } from '../../components/omf' + +const Recover: NextPage = () => { + return ( + + + + + + + ) +} + +export default Recover diff --git a/ui/pages/register.module.scss b/ui/pages/register.module.scss new file mode 100644 index 00000000..473cd7eb --- /dev/null +++ b/ui/pages/register.module.scss @@ -0,0 +1,19 @@ + +.otherActions { + width: 100%; + justify-content: center; + display: flex; + + button { + overflow: hidden; + text-overflow: ellipsis; + + span { + overflow: hidden; + } + } + + @media (max-width: 600px) { + flex-direction: column; + } +} diff --git a/ui/pages/register.tsx b/ui/pages/register.tsx new file mode 100644 index 00000000..24ce4c9f --- /dev/null +++ b/ui/pages/register.tsx @@ -0,0 +1,138 @@ +import { Button, Form, Input, message } from 'antd' +import { useForm } from 'antd/lib/form/Form' +import { AuthFooter } from 'components/auth/footer' +import { AuthLayout } from 'components/auth/layout' +import { setAuth } from 'components/with.auth' +import { RegisterUserData, useRegisterMutation } from 'graphql/mutation/register.mutation' +import { NextPage } from 'next' +import Link from 'next/link' +import { useRouter } from 'next/router' +import React, { useState } from 'react' +import { useTranslation } from 'react-i18next' +import { ErrorPage } from '../components/error.page' +import { Omf } from '../components/omf' +import { useSettingsQuery } from '../graphql/query/settings.query' +import scss from './register.module.scss' + +const Register: NextPage = () => { + const { t } = useTranslation() + const [form] = useForm() + const router = useRouter() + const [loading, setLoading] = useState(false) + const { data } = useSettingsQuery() + + const [register] = useRegisterMutation() + + const finish = async (data: RegisterUserData) => { + setLoading(true) + + try { + const result = await register({ + variables: { + user: data, + }, + }) + + setAuth(result.data.tokens.access, result.data.tokens.refresh) + + await message.success(t('register:welcome')) + + await router.push('/') + } catch (e) { + await message.error(t('register:credentialsAlreadyInUse')) + setLoading(false) + } + } + + const failed = async () => { + await message.error(t('validation:mandatoryFieldsMissing')) + } + + if (data && data.disabledSignUp.value) { + return + } + + return ( + + +
+
+ {'OhMyForm'} +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ ) +} + +export default Register diff --git a/ui/public/favicon.ico b/ui/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..3660ce959c6ee4fc0f7e74b0b50618e89eddc30e GIT binary patch literal 37898 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 & redux.AnyAction + +export const actionTypes: { [key: string]: ActionTypes } = { + INIT: 'AUTH_INIT', + LOGOUT: 'AUTH_LOGOUT', + UPDATE_SETTINGS: 'AUTH_UPDATE_SETTINGS', +} + +const initialState: AuthState = {} + +export const auth: Reducer = (state = initialState): AuthState => { + return state +} diff --git a/ui/store/index.ts b/ui/store/index.ts new file mode 100644 index 00000000..6ad93198 --- /dev/null +++ b/ui/store/index.ts @@ -0,0 +1,28 @@ +import { createWrapper, HYDRATE } from 'next-redux-wrapper' +import { AnyAction, applyMiddleware, combineReducers, createStore, Store } from 'redux' +import { composeWithDevTools } from 'redux-devtools-extension' +import thunkMiddleware from 'redux-thunk' +import { auth, AuthState } from './auth' + +export interface State { + auth: AuthState +} + +const root = (state: State, action: AnyAction): State => { + switch (action.type) { + case HYDRATE: + return { ...state, ...action.payload } as State + } + + const combined = combineReducers({ + auth, + }) + + return combined(state, action) +} + +const makeStore = () => { + return createStore(root, undefined, composeWithDevTools(applyMiddleware(thunkMiddleware))) +} + +export const wrapper = createWrapper>(makeStore, { debug: false }) diff --git a/ui/tsconfig.json b/ui/tsconfig.json new file mode 100644 index 00000000..5ea2f8b4 --- /dev/null +++ b/ui/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": false, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true + }, + "exclude": [ + "node_modules", + "locales/missing.ts", + "locales/sort.ts" + ], + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx" + ] +} diff --git a/ui/yarn.lock b/ui/yarn.lock new file mode 100644 index 00000000..238219fa --- /dev/null +++ b/ui/yarn.lock @@ -0,0 +1,6443 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ant-design/colors@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@ant-design/colors/-/colors-6.0.0.tgz#9b9366257cffcc47db42b9d0203bb592c13c0298" + integrity sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ== + dependencies: + "@ctrl/tinycolor" "^3.4.0" + +"@ant-design/icons-svg@^4.2.1": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz#8630da8eb4471a4aabdaed7d1ff6a97dcb2cf05a" + integrity sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw== + +"@ant-design/icons@^4.7.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-4.7.0.tgz#8c3cbe0a556ba92af5dc7d1e70c0b25b5179af0f" + integrity sha512-aoB4Z7JA431rt6d4u+8xcNPPCrdufSRMUOpxa1ab6mz1JCQZOEVolj2WVs/tDFmN62zzK30mNelEsprLYsSF3g== + dependencies: + "@ant-design/colors" "^6.0.0" + "@ant-design/icons-svg" "^4.2.1" + "@babel/runtime" "^7.11.2" + classnames "^2.2.6" + rc-util "^5.9.4" + +"@ant-design/react-slick@~0.28.1": + version "0.28.4" + resolved "https://registry.yarnpkg.com/@ant-design/react-slick/-/react-slick-0.28.4.tgz#8b296b87ad7c7ae877f2a527b81b7eebd9dd29a9" + integrity sha512-j9eAHTn7GxbXUFNknJoHS2ceAsqrQi2j8XykjZE1IXCD8kJF+t28EvhBLniDpbOsBk/3kjalnhriTfZcjBHNqg== + dependencies: + "@babel/runtime" "^7.10.4" + classnames "^2.2.5" + json2mq "^0.2.0" + lodash "^4.17.21" + resize-observer-polyfill "^1.5.0" + +"@apollo/client@^3.5.9": + version "3.5.9" + resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.5.9.tgz#306c1f8453d56dbb4ff1afaaaf16b3b719db696c" + integrity sha512-Qq3OE3GpyPG2fYXBzi1n4QXcKZ11c6jHdrXK2Kkn9SD+vUymSrllXsldqnKUK9tslxKqkKzNrkCXkLv7PxwfSQ== + dependencies: + "@graphql-typed-document-node/core" "^3.0.0" + "@wry/context" "^0.6.0" + "@wry/equality" "^0.5.0" + "@wry/trie" "^0.3.0" + graphql-tag "^2.12.3" + hoist-non-react-statics "^3.3.2" + optimism "^0.16.1" + prop-types "^15.7.2" + symbol-observable "^4.0.0" + ts-invariant "^0.9.4" + tslib "^2.3.0" + zen-observable-ts "^1.2.0" + +"@babel/code-frame@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + +"@babel/generator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.7.tgz#b42bf46a3079fa65e1544135f32e7958f048adbb" + integrity sha512-/ST3Sg8MLGY5HVYmrjOgL60ENux/HfO/CsUh7y4MalThufhE/Ff/6EibFDHi4jiDCaWfJKoqbE6oTh21c5hrRg== + dependencies: + "@babel/types" "^7.16.7" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.16.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" + integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-environment-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" + integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== + dependencies: + "@babel/helper-get-function-arity" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helper-get-function-arity@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" + integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-hoist-variables@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + +"@babel/highlight@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.7.tgz#81a01d7d675046f0d96f82450d9d9578bdfd6b0b" + integrity sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.7.tgz#d372dda9c89fcec340a82630a9f533f2fe15877e" + integrity sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA== + +"@babel/runtime-corejs3@^7.10.2": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.16.7.tgz#a762745fe8b4d61a26444a9151e6586d36044dde" + integrity sha512-MiYR1yk8+TW/CpOD0CyX7ve9ffWTKqLk/L6pk8TPl0R8pNi+1pFY8fH9yET55KlvukQ4PAWfXsGr2YHVjcI4Pw== + dependencies: + core-js-pure "^3.19.0" + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.16.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa" + integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.16.7", "@babel/runtime@^7.7.2": + version "7.17.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941" + integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/traverse@^7.4.5": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.7.tgz#dac01236a72c2560073658dd1a285fe4e0865d76" + integrity sha512-8KWJPIb8c2VvY8AJrydh6+fVRo2ODx1wYBU2398xJVq0JomuLBZmVQzLPBblJgHIGYG4znCpUZUZ0Pt2vdmVYQ== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.7.tgz#4ed19d51f840ed4bd5645be6ce40775fecf03159" + integrity sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + +"@cspotcode/source-map-consumer@0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" + integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== + +"@cspotcode/source-map-support@0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" + integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== + dependencies: + "@cspotcode/source-map-consumer" "0.8.0" + +"@ctrl/tinycolor@^3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz#c3c5ae543c897caa9c2a68630bed355be5f9990f" + integrity sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ== + +"@emotion/is-prop-valid@^0.8.8": + version "0.8.8" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" + integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== + dependencies: + "@emotion/memoize" "0.7.4" + +"@emotion/memoize@0.7.4": + version "0.7.4" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" + integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== + +"@emotion/stylis@^0.8.4": + version "0.8.5" + resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" + integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== + +"@emotion/unitless@^0.7.4": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" + integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== + +"@eslint/eslintrc@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.0.tgz#7ce1547a5c46dfe56e1e45c3c9ed18038c721c6a" + integrity sha512-igm9SjJHNEJRiUnecP/1R5T3wKLEJ7pL6e2P+GUSfCd0dGjPYYZve08uzw8L2J8foVHFz+NGu12JxRcU2gGo6w== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.3.1" + globals "^13.9.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@fast-csv/format@4.3.5": + version "4.3.5" + resolved "https://registry.yarnpkg.com/@fast-csv/format/-/format-4.3.5.tgz#90d83d1b47b6aaf67be70d6118f84f3e12ee1ff3" + integrity sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A== + dependencies: + "@types/node" "^14.0.1" + lodash.escaperegexp "^4.1.2" + lodash.isboolean "^3.0.3" + lodash.isequal "^4.5.0" + lodash.isfunction "^3.0.9" + lodash.isnil "^4.0.0" + +"@fast-csv/parse@4.3.6": + version "4.3.6" + resolved "https://registry.yarnpkg.com/@fast-csv/parse/-/parse-4.3.6.tgz#ee47d0640ca0291034c7aa94039a744cfb019264" + integrity sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA== + dependencies: + "@types/node" "^14.0.1" + lodash.escaperegexp "^4.1.2" + lodash.groupby "^4.6.0" + lodash.isfunction "^3.0.9" + lodash.isnil "^4.0.0" + lodash.isundefined "^3.0.1" + lodash.uniq "^4.5.0" + +"@graphql-typed-document-node/core@^3.0.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.1.tgz#076d78ce99822258cf813ecc1e7fa460fa74d052" + integrity sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg== + +"@humanwhocodes/config-array@^0.9.2": + version "0.9.2" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914" + integrity sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@icons/material@^0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8" + integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw== + +"@jimp/bmp@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/bmp/-/bmp-0.16.1.tgz#6e2da655b2ba22e721df0795423f34e92ef13768" + integrity sha512-iwyNYQeBawrdg/f24x3pQ5rEx+/GwjZcCXd3Kgc+ZUd+Ivia7sIqBsOnDaMZdKCBPlfW364ekexnlOqyVa0NWg== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + bmp-js "^0.1.0" + +"@jimp/core@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/core/-/core-0.16.1.tgz#68c4288f6ef7f31a0f6b859ba3fb28dae930d39d" + integrity sha512-la7kQia31V6kQ4q1kI/uLimu8FXx7imWVajDGtwUG8fzePLWDFJyZl0fdIXVCL1JW2nBcRHidUot6jvlRDi2+g== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + any-base "^1.1.0" + buffer "^5.2.0" + exif-parser "^0.1.12" + file-type "^9.0.0" + load-bmfont "^1.3.1" + mkdirp "^0.5.1" + phin "^2.9.1" + pixelmatch "^4.0.2" + tinycolor2 "^1.4.1" + +"@jimp/custom@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/custom/-/custom-0.16.1.tgz#28b659c59e20a1d75a0c46067bd3f4bd302cf9c5" + integrity sha512-DNUAHNSiUI/j9hmbatD6WN/EBIyeq4AO0frl5ETtt51VN1SvE4t4v83ZA/V6ikxEf3hxLju4tQ5Pc3zmZkN/3A== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/core" "^0.16.1" + +"@jimp/gif@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/gif/-/gif-0.16.1.tgz#d1f7c3a58f4666482750933af8b8f4666414f3ca" + integrity sha512-r/1+GzIW1D5zrP4tNrfW+3y4vqD935WBXSc8X/wm23QTY9aJO9Lw6PEdzpYCEY+SOklIFKaJYUAq/Nvgm/9ryw== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + gifwrap "^0.9.2" + omggif "^1.0.9" + +"@jimp/jpeg@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/jpeg/-/jpeg-0.16.1.tgz#3b7bb08a4173f2f6d81f3049b251df3ee2ac8175" + integrity sha512-8352zrdlCCLFdZ/J+JjBslDvml+fS3Z8gttdml0We759PnnZGqrnPRhkOEOJbNUlE+dD4ckLeIe6NPxlS/7U+w== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + jpeg-js "0.4.2" + +"@jimp/plugin-blit@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-blit/-/plugin-blit-0.16.1.tgz#09ea919f9d326de3b9c2826fe4155da37dde8edb" + integrity sha512-fKFNARm32RoLSokJ8WZXHHH2CGzz6ire2n1Jh6u+XQLhk9TweT1DcLHIXwQMh8oR12KgjbgsMGvrMVlVknmOAg== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-blur@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-blur/-/plugin-blur-0.16.1.tgz#e614fa002797dcd662e705d4cea376e7db968bf5" + integrity sha512-1WhuLGGj9MypFKRcPvmW45ht7nXkOKu+lg3n2VBzIB7r4kKNVchuI59bXaCYQumOLEqVK7JdB4glaDAbCQCLyw== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-circle@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-circle/-/plugin-circle-0.16.1.tgz#20e3194a67ca29740aba2630fd4d0a89afa27491" + integrity sha512-JK7yi1CIU7/XL8hdahjcbGA3V7c+F+Iw+mhMQhLEi7Q0tCnZ69YJBTamMiNg3fWPVfMuvWJJKOBRVpwNTuaZRg== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-color@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-color/-/plugin-color-0.16.1.tgz#0f298ba74dee818b663834cd80d53e56f3755233" + integrity sha512-9yQttBAO5SEFj7S6nJK54f+1BnuBG4c28q+iyzm1JjtnehjqMg6Ljw4gCSDCvoCQ3jBSYHN66pmwTV74SU1B7A== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + tinycolor2 "^1.4.1" + +"@jimp/plugin-contain@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-contain/-/plugin-contain-0.16.1.tgz#3c5f5c495fd9bb08a970739d83694934f58123f2" + integrity sha512-44F3dUIjBDHN+Ym/vEfg+jtjMjAqd2uw9nssN67/n4FdpuZUVs7E7wadKY1RRNuJO+WgcD5aDQcsvurXMETQTg== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-cover@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-cover/-/plugin-cover-0.16.1.tgz#0e8caec16a40abe15b1b32e5383a603a3306dc41" + integrity sha512-YztWCIldBAVo0zxcQXR+a/uk3/TtYnpKU2CanOPJ7baIuDlWPsG+YE4xTsswZZc12H9Kl7CiziEbDtvF9kwA/Q== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-crop@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-crop/-/plugin-crop-0.16.1.tgz#b362497c873043fe47ba881ab08604bf7226f50f" + integrity sha512-UQdva9oQzCVadkyo3T5Tv2CUZbf0klm2cD4cWMlASuTOYgaGaFHhT9st+kmfvXjKL8q3STkBu/zUPV6PbuV3ew== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-displace@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-displace/-/plugin-displace-0.16.1.tgz#4dd9db518c3e78de9d723f86a234bf98922afe8d" + integrity sha512-iVAWuz2+G6Heu8gVZksUz+4hQYpR4R0R/RtBzpWEl8ItBe7O6QjORAkhxzg+WdYLL2A/Yd4ekTpvK0/qW8hTVw== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-dither@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-dither/-/plugin-dither-0.16.1.tgz#b47de2c0bb09608bed228b41c3cd01a85ec2d45b" + integrity sha512-tADKVd+HDC9EhJRUDwMvzBXPz4GLoU6s5P7xkVq46tskExYSptgj5713J5Thj3NMgH9Rsqu22jNg1H/7tr3V9Q== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-fisheye@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-fisheye/-/plugin-fisheye-0.16.1.tgz#f625047b6cdbe1b83b89e9030fd025ab19cdb1a4" + integrity sha512-BWHnc5hVobviTyIRHhIy9VxI1ACf4CeSuCfURB6JZm87YuyvgQh5aX5UDKtOz/3haMHXBLP61ZBxlNpMD8CG4A== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-flip@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-flip/-/plugin-flip-0.16.1.tgz#7a99ea22bde802641017ed0f2615870c144329bb" + integrity sha512-KdxTf0zErfZ8DyHkImDTnQBuHby+a5YFdoKI/G3GpBl3qxLBvC+PWkS2F/iN3H7wszP7/TKxTEvWL927pypT0w== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-gaussian@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-gaussian/-/plugin-gaussian-0.16.1.tgz#0845e314085ccd52e34fad9a83949bc0d81a68e8" + integrity sha512-u9n4wjskh3N1mSqketbL6tVcLU2S5TEaFPR40K6TDv4phPLZALi1Of7reUmYpVm8mBDHt1I6kGhuCJiWvzfGyg== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-invert@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-invert/-/plugin-invert-0.16.1.tgz#7e6f5a15707256f3778d06921675bbcf18545c97" + integrity sha512-2DKuyVXANH8WDpW9NG+PYFbehzJfweZszFYyxcaewaPLN0GxvxVLOGOPP1NuUTcHkOdMFbE0nHDuB7f+sYF/2w== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-mask@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-mask/-/plugin-mask-0.16.1.tgz#e7f2460e05c3cda7af5e76f33ccb0579f66f90df" + integrity sha512-snfiqHlVuj4bSFS0v96vo2PpqCDMe4JB+O++sMo5jF5mvGcGL6AIeLo8cYqPNpdO6BZpBJ8MY5El0Veckhr39Q== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-normalize@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-normalize/-/plugin-normalize-0.16.1.tgz#032dfd88eefbc4dedc8b1b2d243832e4f3af30c8" + integrity sha512-dOQfIOvGLKDKXPU8xXWzaUeB0nvkosHw6Xg1WhS1Z5Q0PazByhaxOQkSKgUryNN/H+X7UdbDvlyh/yHf3ITRaw== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-print@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-print/-/plugin-print-0.16.1.tgz#66b803563f9d109825970714466e6ab9ae639ff6" + integrity sha512-ceWgYN40jbN4cWRxixym+csyVymvrryuKBQ+zoIvN5iE6OyS+2d7Mn4zlNgumSczb9GGyZZESIgVcBDA1ezq0Q== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + load-bmfont "^1.4.0" + +"@jimp/plugin-resize@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-resize/-/plugin-resize-0.16.1.tgz#65e39d848ed13ba2d6c6faf81d5d590396571d10" + integrity sha512-u4JBLdRI7dargC04p2Ha24kofQBk3vhaf0q8FwSYgnCRwxfvh2RxvhJZk9H7Q91JZp6wgjz/SjvEAYjGCEgAwQ== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-rotate@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-rotate/-/plugin-rotate-0.16.1.tgz#53fb5d51a4b3d05af9c91c2a8fffe5d7a1a47c8c" + integrity sha512-ZUU415gDQ0VjYutmVgAYYxC9Og9ixu2jAGMCU54mSMfuIlmohYfwARQmI7h4QB84M76c9hVLdONWjuo+rip/zg== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-scale@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-scale/-/plugin-scale-0.16.1.tgz#89f6ba59feed3429847ed226aebda33a240cc647" + integrity sha512-jM2QlgThIDIc4rcyughD5O7sOYezxdafg/2Xtd1csfK3z6fba3asxDwthqPZAgitrLgiKBDp6XfzC07Y/CefUw== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-shadow@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-shadow/-/plugin-shadow-0.16.1.tgz#a7af892a740febf41211e10a5467c3c5c521a04c" + integrity sha512-MeD2Is17oKzXLnsphAa1sDstTu6nxscugxAEk3ji0GV1FohCvpHBcec0nAq6/czg4WzqfDts+fcPfC79qWmqrA== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugin-threshold@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-threshold/-/plugin-threshold-0.16.1.tgz#34f3078f9965145b7ae26c53a32ad74b1195bbf5" + integrity sha512-iGW8U/wiCSR0+6syrPioVGoSzQFt4Z91SsCRbgNKTAk7D+XQv6OI78jvvYg4o0c2FOlwGhqz147HZV5utoSLxA== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + +"@jimp/plugins@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugins/-/plugins-0.16.1.tgz#9f08544c97226d6460a16ced79f57e85bec3257b" + integrity sha512-c+lCqa25b+4q6mJZSetlxhMoYuiltyS+ValLzdwK/47+aYsq+kcJNl+TuxIEKf59yr9+5rkbpsPkZHLF/V7FFA== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/plugin-blit" "^0.16.1" + "@jimp/plugin-blur" "^0.16.1" + "@jimp/plugin-circle" "^0.16.1" + "@jimp/plugin-color" "^0.16.1" + "@jimp/plugin-contain" "^0.16.1" + "@jimp/plugin-cover" "^0.16.1" + "@jimp/plugin-crop" "^0.16.1" + "@jimp/plugin-displace" "^0.16.1" + "@jimp/plugin-dither" "^0.16.1" + "@jimp/plugin-fisheye" "^0.16.1" + "@jimp/plugin-flip" "^0.16.1" + "@jimp/plugin-gaussian" "^0.16.1" + "@jimp/plugin-invert" "^0.16.1" + "@jimp/plugin-mask" "^0.16.1" + "@jimp/plugin-normalize" "^0.16.1" + "@jimp/plugin-print" "^0.16.1" + "@jimp/plugin-resize" "^0.16.1" + "@jimp/plugin-rotate" "^0.16.1" + "@jimp/plugin-scale" "^0.16.1" + "@jimp/plugin-shadow" "^0.16.1" + "@jimp/plugin-threshold" "^0.16.1" + timm "^1.6.1" + +"@jimp/png@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/png/-/png-0.16.1.tgz#f24cfc31529900b13a2dd9d4fdb4460c1e4d814e" + integrity sha512-iyWoCxEBTW0OUWWn6SveD4LePW89kO7ZOy5sCfYeDM/oTPLpR8iMIGvZpZUz1b8kvzFr27vPst4E5rJhGjwsdw== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + pngjs "^3.3.3" + +"@jimp/tiff@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/tiff/-/tiff-0.16.1.tgz#0e8756695687d7574b6bc73efab0acd4260b7a12" + integrity sha512-3K3+xpJS79RmSkAvFMgqY5dhSB+/sxhwTFA9f4AVHUK0oKW+u6r52Z1L0tMXHnpbAdR9EJ+xaAl2D4x19XShkQ== + dependencies: + "@babel/runtime" "^7.7.2" + utif "^2.0.1" + +"@jimp/types@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/types/-/types-0.16.1.tgz#0dbab37b3202315c91010f16c31766d35a2322cc" + integrity sha512-g1w/+NfWqiVW4CaXSJyD28JQqZtm2eyKMWPhBBDCJN9nLCN12/Az0WFF3JUAktzdsEC2KRN2AqB1a2oMZBNgSQ== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/bmp" "^0.16.1" + "@jimp/gif" "^0.16.1" + "@jimp/jpeg" "^0.16.1" + "@jimp/png" "^0.16.1" + "@jimp/tiff" "^0.16.1" + timm "^1.6.1" + +"@jimp/utils@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/utils/-/utils-0.16.1.tgz#2f51e6f14ff8307c4aa83d5e1a277da14a9fe3f7" + integrity sha512-8fULQjB0x4LzUSiSYG6ZtQl355sZjxbv8r9PPAuYHzS9sGiSHJQavNqK/nKnpDsVkU88/vRGcE7t3nMU0dEnVw== + dependencies: + "@babel/runtime" "^7.7.2" + regenerator-runtime "^0.13.3" + +"@mrmlnc/readdir-enhanced@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" + integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== + dependencies: + call-me-maybe "^1.0.1" + glob-to-regexp "^0.3.0" + +"@next/env@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.0.tgz#73713399399b34aa5a01771fb73272b55b22c314" + integrity sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ== + +"@next/swc-android-arm64@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.0.tgz#865ba3a9afc204ff2bdeea49dd64d58705007a39" + integrity sha512-/280MLdZe0W03stA69iL+v6I+J1ascrQ6FrXBlXGCsGzrfMaGr7fskMa0T5AhQIVQD4nA/46QQWxG//DYuFBcA== + +"@next/swc-darwin-arm64@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.0.tgz#08e8b411b8accd095009ed12efbc2f1d4d547135" + integrity sha512-R8vcXE2/iONJ1Unf5Ptqjk6LRW3bggH+8drNkkzH4FLEQkHtELhvcmJwkXcuipyQCsIakldAXhRbZmm3YN1vXg== + +"@next/swc-darwin-x64@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.0.tgz#fcd684497a76e8feaca88db3c394480ff0b007cd" + integrity sha512-ieAz0/J0PhmbZBB8+EA/JGdhRHBogF8BWaeqR7hwveb6SYEIJaDNQy0I+ZN8gF8hLj63bEDxJAs/cEhdnTq+ug== + +"@next/swc-linux-arm-gnueabihf@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.0.tgz#9ec6380a27938a5799aaa6035c205b3c478468a7" + integrity sha512-njUd9hpl6o6A5d08dC0cKAgXKCzm5fFtgGe6i0eko8IAdtAPbtHxtpre3VeSxdZvuGFh+hb0REySQP9T1ttkog== + +"@next/swc-linux-arm64-gnu@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.0.tgz#7f4196dff1049cea479607c75b81033ae2dbd093" + integrity sha512-OqangJLkRxVxMhDtcb7Qn1xjzFA3s50EIxY7mljbSCLybU+sByPaWAHY4px97ieOlr2y4S0xdPKkQ3BCAwyo6Q== + +"@next/swc-linux-arm64-musl@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.0.tgz#b445f767569cdc2dddee785ca495e1a88c025566" + integrity sha512-hB8cLSt4GdmOpcwRe2UzI5UWn6HHO/vLkr5OTuNvCJ5xGDwpPXelVkYW/0+C3g5axbDW2Tym4S+MQCkkH9QfWA== + +"@next/swc-linux-x64-gnu@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.0.tgz#67610e9be4fbc987de7535f1bcb17e45fe12f90e" + integrity sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A== + +"@next/swc-linux-x64-musl@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.0.tgz#ea19a23db08a9f2e34ac30401f774cf7d1669d31" + integrity sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw== + +"@next/swc-win32-arm64-msvc@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.0.tgz#eadf054fc412085659b98e145435bbba200b5283" + integrity sha512-T/3gIE6QEfKIJ4dmJk75v9hhNiYZhQYAoYm4iVo1TgcsuaKLFa+zMPh4056AHiG6n9tn2UQ1CFE8EoybEsqsSw== + +"@next/swc-win32-ia32-msvc@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.0.tgz#68faeae10c89f698bf9d28759172b74c9c21bda1" + integrity sha512-iwnKgHJdqhIW19H9PRPM9j55V6RdcOo6rX+5imx832BCWzkDbyomWnlzBfr6ByUYfhohb8QuH4hSGEikpPqI0Q== + +"@next/swc-win32-x64-msvc@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz#d27e7e76c87a460a4da99c5bfdb1618dcd6cd064" + integrity sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg== + +"@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.stat@^1.1.2": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" + integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== + +"@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" + +"@react-leaflet/core@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@react-leaflet/core/-/core-1.1.1.tgz#827fd05bb542cf874116176d8ef48d5b12163f81" + integrity sha512-7PGLWa9MZ5x/cWy8EH2VzI4T8q5WpuHbixzCDXqixP/WyqwIrg5NDUPgYuFnB4IEIZF+6nA265mYzswFo/h1Pw== + +"@sindresorhus/is@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" + integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== + +"@tsconfig/node10@^1.0.7": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" + integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== + +"@tsconfig/node12@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" + integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== + +"@tsconfig/node14@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" + integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== + +"@tsconfig/node16@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" + integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== + +"@types/debug@^4.0.0": + version "4.1.7" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" + integrity sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg== + dependencies: + "@types/ms" "*" + +"@types/geojson@*": + version "7946.0.8" + resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.8.tgz#30744afdb385e2945e22f3b033f897f76b1f12ca" + integrity sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA== + +"@types/hast@^2.0.0": + version "2.3.4" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc" + integrity sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g== + dependencies: + "@types/unist" "*" + +"@types/hoist-non-react-statics@*", "@types/hoist-non-react-statics@^3.3.0": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" + integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + +"@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + +"@types/leaflet@^1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.7.9.tgz#7993d34f14cfa88c45b3d490daba39a3a1be9a2b" + integrity sha512-H8vPgD49HKzqM41ArHGZM70g/tfhp8W+JcPxfnF+5H/Xvp+xiP+KQOUNWU8U89fqS1Jj3cpRY/+nbnaHFzwnFA== + dependencies: + "@types/geojson" "*" + +"@types/mathjs@^9.4.2": + version "9.4.2" + resolved "https://registry.yarnpkg.com/@types/mathjs/-/mathjs-9.4.2.tgz#beec20340d768171fed8331b08fb321d218ec6e1" + integrity sha512-GF5g1vJmvKdWIWsE53XX7EDAyCaZ9p6gaYm1xhlXn5JjrY/NJrOfJN3fBxS3wyZpVh3QqKoMkS2WjFwxWMHOTw== + dependencies: + mathjs "*" + +"@types/mdast@^3.0.0": + version "3.0.10" + resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" + integrity sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA== + dependencies: + "@types/unist" "*" + +"@types/mdurl@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9" + integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA== + +"@types/ms@*": + version "0.7.31" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" + integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== + +"@types/node-fetch@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-3.0.3.tgz#9d969c9a748e841554a40ee435d26e53fa3ee899" + integrity sha512-HhggYPH5N+AQe/OmN6fmhKmRRt2XuNJow+R3pQwJxOOF9GuwM7O2mheyGeIrs5MOIeNjDEdgdoyHBOrFeJBR3g== + dependencies: + node-fetch "*" + +"@types/node@^14.0.1": + version "14.18.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.4.tgz#b722d6c91f156d9359aeb20f2d7d06337b15c603" + integrity sha512-swe3lD4izOJWHuxvsZdDFRq6S9i6koJsXOnQKYekhSO5JTizMVirUFgY/bUsaOJQj8oSD4oxmRYPBM/0b6jpdw== + +"@types/node@^16.11.17": + version "16.11.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.17.tgz#ae146499772e33fc6382e1880bc567e41a528586" + integrity sha512-C1vTZME8cFo8uxY2ui41xcynEotVkczIVI5AjLmy5pkpBv/FtG+jhtOlfcPysI8VRVwoOMv6NJm44LGnoMSWkw== + +"@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-redux@^7.1.20": + version "7.1.21" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.21.tgz#f32bbaf7cbc4b93f51e10d340aa54035c084b186" + integrity sha512-bLdglUiBSQNzWVVbmNPKGYYjrzp3/YDPwfOH3nLEz99I4awLlaRAPWjo6bZ2POpxztFWtDDXIPxBLVykXqBt+w== + dependencies: + "@types/hoist-non-react-statics" "^3.3.0" + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + redux "^4.0.0" + +"@types/react@*": + version "17.0.38" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.38.tgz#f24249fefd89357d5fa71f739a686b8d7c7202bd" + integrity sha512-SI92X1IA+FMnP3qM5m4QReluXzhcmovhZnLNm3pyeQlooi02qI7sLiepEYqT678uNiyc25XfCqxREFpy3W7YhQ== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/react@^17.0.39": + version "17.0.39" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.39.tgz#d0f4cde092502a6db00a1cded6e6bf2abb7633ce" + integrity sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug== + 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== + +"@types/styled-components@^5.1.23": + version "5.1.23" + resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-5.1.23.tgz#11e5740047f292b42a042c60c0ef16b58d5adef6" + integrity sha512-zt8oQGU6XB4LH1Xpq169YnAVmt22+swzHJvyKMyTZu/z8+afvgKjjg0s79aAodgNSf36ZOEG6DyVAW/JhLH2Nw== + dependencies: + "@types/hoist-non-react-statics" "*" + "@types/react" "*" + csstype "^3.0.2" + +"@types/swiper@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@types/swiper/-/swiper-6.0.0.tgz#9934ecd569611b660a2a9bf200f25ce5ba4b4d63" + integrity sha512-QPZRgxZ+ivXXtzV43B3LxpXUIC7FE/EoKM+rtxngmgt2M7eeUYypZhyqZD8UxJtlBcUDw/ATGoVeSNpvBBrz2w== + dependencies: + swiper "*" + +"@types/unist@*", "@types/unist@^2.0.0": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" + integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== + +"@typescript-eslint/eslint-plugin@^5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.12.1.tgz#b2cd3e288f250ce8332d5035a2ff65aba3374ac4" + integrity sha512-M499lqa8rnNK7mUv74lSFFttuUsubIRdAbHcVaP93oFcKkEmHmLqy2n7jM9C8DVmFMYK61ExrZU6dLYhQZmUpw== + dependencies: + "@typescript-eslint/scope-manager" "5.12.1" + "@typescript-eslint/type-utils" "5.12.1" + "@typescript-eslint/utils" "5.12.1" + debug "^4.3.2" + functional-red-black-tree "^1.0.1" + ignore "^5.1.8" + regexpp "^3.2.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.12.1.tgz#b090289b553b8aa0899740d799d0f96e6f49771b" + integrity sha512-6LuVUbe7oSdHxUWoX/m40Ni8gsZMKCi31rlawBHt7VtW15iHzjbpj2WLiToG2758KjtCCiLRKZqfrOdl3cNKuw== + dependencies: + "@typescript-eslint/scope-manager" "5.12.1" + "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/typescript-estree" "5.12.1" + debug "^4.3.2" + +"@typescript-eslint/scope-manager@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.12.1.tgz#58734fd45d2d1dec49641aacc075fba5f0968817" + integrity sha512-J0Wrh5xS6XNkd4TkOosxdpObzlYfXjAFIm9QxYLCPOcHVv1FyyFCPom66uIh8uBr0sZCrtS+n19tzufhwab8ZQ== + dependencies: + "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/visitor-keys" "5.12.1" + +"@typescript-eslint/type-utils@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.12.1.tgz#8d58c6a0bb176b5e9a91581cda1a7f91a114d3f0" + integrity sha512-Gh8feEhsNLeCz6aYqynh61Vsdy+tiNNkQtc+bN3IvQvRqHkXGUhYkUi+ePKzP0Mb42se7FDb+y2SypTbpbR/Sg== + dependencies: + "@typescript-eslint/utils" "5.12.1" + debug "^4.3.2" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.12.1.tgz#46a36a28ff4d946821b58fe5a73c81dc2e12aa89" + integrity sha512-hfcbq4qVOHV1YRdhkDldhV9NpmmAu2vp6wuFODL71Y0Ixak+FLeEU4rnPxgmZMnGreGEghlEucs9UZn5KOfHJA== + +"@typescript-eslint/typescript-estree@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.12.1.tgz#6a9425b9c305bcbc38e2d1d9a24c08e15e02b722" + integrity sha512-ahOdkIY9Mgbza7L9sIi205Pe1inCkZWAHE1TV1bpxlU4RZNPtXaDZfiiFWcL9jdxvW1hDYZJXrFm+vlMkXRbBw== + dependencies: + "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/visitor-keys" "5.12.1" + debug "^4.3.2" + globby "^11.0.4" + is-glob "^4.0.3" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.12.1.tgz#447c24a05d9c33f9c6c64cb48f251f2371eef920" + integrity sha512-Qq9FIuU0EVEsi8fS6pG+uurbhNTtoYr4fq8tKjBupsK5Bgbk2I32UGm0Sh+WOyjOPgo/5URbxxSNV6HYsxV4MQ== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.12.1" + "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/typescript-estree" "5.12.1" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/visitor-keys@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.12.1.tgz#f722da106c8f9695ae5640574225e45af3e52ec3" + integrity sha512-l1KSLfupuwrXx6wc0AuOmC7Ko5g14ZOQ86wJJqRbdLbXLK02pK/DPiDDqCc7BqqiiA04/eAA6ayL0bgOrAkH7A== + dependencies: + "@typescript-eslint/types" "5.12.1" + eslint-visitor-keys "^3.0.0" + +"@wry/context@^0.6.0": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.6.1.tgz#c3c29c0ad622adb00f6a53303c4f965ee06ebeb2" + integrity sha512-LOmVnY1iTU2D8tv4Xf6MVMZZ+juIJ87Kt/plMijjN20NMAXGmH4u8bS1t0uT74cZ5gwpocYueV58YwyI8y+GKw== + dependencies: + tslib "^2.3.0" + +"@wry/equality@^0.5.0": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.5.2.tgz#72c8a7a7d884dff30b612f4f8464eba26c080e73" + integrity sha512-oVMxbUXL48EV/C0/M7gLVsoK6qRHPS85x8zECofEZOVvxGmIPLA9o5Z27cc2PoAyZz1S2VoM2A7FLAnpfGlneA== + dependencies: + tslib "^2.3.0" + +"@wry/trie@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.3.1.tgz#2279b790f15032f8bcea7fc944d27988e5b3b139" + integrity sha512-WwB53ikYudh9pIorgxrkHKrQZcCqNM/Q/bDzZBffEaGUKGuHrRb3zZUT9Sh2qw9yogC7SsdRmQ1ER0pqvd3bfw== + dependencies: + tslib "^2.3.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-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^8.4.1, acorn@^8.7.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" + integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== + +ajv-keywords@^3.1.0, ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5: + 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" + +ansi-regex@^5.0.1: + 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.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" + +antd@^4.18.8: + version "4.18.8" + resolved "https://registry.yarnpkg.com/antd/-/antd-4.18.8.tgz#abd7a54790311c7ced41123cf9f96e47582c629b" + integrity sha512-eT701hvqy3m7y06pfx6j0onsXOslym7+iNrTHH8cytzQd1Bbefc6Jm7deRnOqjEkSeZM5iJlw2SpBn1+0Cu+Ig== + dependencies: + "@ant-design/colors" "^6.0.0" + "@ant-design/icons" "^4.7.0" + "@ant-design/react-slick" "~0.28.1" + "@babel/runtime" "^7.12.5" + "@ctrl/tinycolor" "^3.4.0" + classnames "^2.2.6" + copy-to-clipboard "^3.2.0" + lodash "^4.17.21" + memoize-one "^6.0.0" + moment "^2.25.3" + rc-cascader "~3.2.1" + rc-checkbox "~2.3.0" + rc-collapse "~3.1.0" + rc-dialog "~8.6.0" + rc-drawer "~4.4.2" + rc-dropdown "~3.2.5" + rc-field-form "~1.22.0-2" + rc-image "~5.2.5" + rc-input-number "~7.3.0" + rc-mentions "~1.6.1" + rc-menu "~9.2.1" + rc-motion "^2.4.4" + rc-notification "~4.5.7" + rc-pagination "~3.1.9" + rc-picker "~2.5.17" + rc-progress "~3.2.1" + rc-rate "~2.9.0" + rc-resize-observer "^1.2.0" + rc-select "~14.0.0-alpha.15" + rc-slider "~9.7.4" + rc-steps "~4.1.0" + rc-switch "~3.2.0" + rc-table "~7.23.0" + rc-tabs "~11.10.0" + rc-textarea "~0.3.0" + rc-tooltip "~5.1.1" + rc-tree "~5.4.3" + rc-tree-select "~5.1.1" + rc-trigger "^5.2.10" + rc-upload "~4.3.0" + rc-util "^5.14.0" + scroll-into-view-if-needed "^2.2.25" + +any-base@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/any-base/-/any-base-1.1.0.tgz#ae101a62bc08a597b4c9ab5b7089d456630549fe" + integrity sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg== + +anymatch@~3.1.2: + 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" + +arch@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" + integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== + +archive-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/archive-type/-/archive-type-4.0.0.tgz#f92e72233056dfc6969472749c267bdb046b1d70" + integrity sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA= + dependencies: + file-type "^4.2.0" + +archiver-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" + integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== + dependencies: + glob "^7.1.4" + graceful-fs "^4.2.0" + lazystream "^1.0.0" + lodash.defaults "^4.2.0" + lodash.difference "^4.5.0" + lodash.flatten "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.union "^4.6.0" + normalize-path "^3.0.0" + readable-stream "^2.0.0" + +archiver@^5.0.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.0.tgz#dd3e097624481741df626267564f7dd8640a45ba" + integrity sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg== + dependencies: + archiver-utils "^2.1.0" + async "^3.2.0" + buffer-crc32 "^0.2.1" + readable-stream "^3.6.0" + readdir-glob "^1.0.0" + tar-stream "^2.2.0" + zip-stream "^4.1.0" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +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" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-includes@^3.1.3, array-includes@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" + integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + is-string "^1.0.7" + +array-tree-filter@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-tree-filter/-/array-tree-filter-2.1.0.tgz#873ac00fec83749f255ac8dd083814b4f6329190" + integrity sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw== + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + dependencies: + array-uniq "^1.0.1" + +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-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +array.prototype.flatmap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" + integrity sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + es-abstract "^1.19.0" + +arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +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= + +async-validator@^4.0.2: + version "4.0.7" + resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-4.0.7.tgz#034a0fd2103a6b2ebf010da75183bec299247afe" + integrity sha512-Pj2IR7u8hmUEDOwB++su6baaRi+QvsgajuFB9j95foM1N2gy5HM4z60hfusIO0fBPG5uLAEl6yCJr1jNSVugEQ== + +async@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.2.tgz#2eb7671034bb2194d45d30e31e24ec7e7f9670cd" + integrity sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g== + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +axe-core@^4.3.5: + version "4.3.5" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.5.tgz#78d6911ba317a8262bfee292aeafcc1e04b49cc5" + integrity sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA== + +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== + +"babel-plugin-styled-components@>= 1.12.0": + version "2.0.2" + resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.2.tgz#0fac11402dc9db73698b55847ab1dc73f5197c54" + integrity sha512-7eG5NE8rChnNTDxa6LQfynwgHTVOYYaHJbUYSlOhk8QBXIQiMBKq4gyfHBBKPrxUcVBXVJL61ihduCpCQbuNbw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-module-imports" "^7.16.0" + babel-plugin-syntax-jsx "^6.18.0" + lodash "^4.17.11" + +babel-plugin-syntax-jsx@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= + +bail@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" + integrity sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw== + +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.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +big-integer@^1.6.17: + version "1.6.51" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" + integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== + +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== + +bin-build@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bin-build/-/bin-build-3.0.0.tgz#c5780a25a8a9f966d8244217e6c1f5082a143861" + integrity sha512-jcUOof71/TNAI2uM5uoUaDq2ePcVBQ3R/qhxAz1rX7UfvduAL/RXD3jXzvn8cVcDJdGVkiR1shal3OH0ImpuhA== + dependencies: + decompress "^4.0.0" + download "^6.2.2" + execa "^0.7.0" + p-map-series "^1.0.0" + tempfile "^2.0.0" + +bin-check@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bin-check/-/bin-check-4.1.0.tgz#fc495970bdc88bb1d5a35fc17e65c4a149fc4a49" + integrity sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA== + dependencies: + execa "^0.7.0" + executable "^4.1.0" + +bin-version-check@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/bin-version-check/-/bin-version-check-4.0.0.tgz#7d819c62496991f80d893e6e02a3032361608f71" + integrity sha512-sR631OrhC+1f8Cvs8WyVWOA33Y8tgwjETNPyyD/myRBXLkfS/vl74FmH/lFcRl9KY3zwGh7jFhvyk9vV3/3ilQ== + dependencies: + bin-version "^3.0.0" + semver "^5.6.0" + semver-truncate "^1.1.2" + +bin-version@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bin-version/-/bin-version-3.1.0.tgz#5b09eb280752b1bd28f0c9db3f96f2f43b6c0839" + integrity sha512-Mkfm4iE1VFt4xd4vH+gx+0/71esbfus2LsnCGe8Pi4mndSPyT+NGES/Eg99jx8/lUGWfu3z2yuB/bt5UB+iVbQ== + dependencies: + execa "^1.0.0" + find-versions "^3.0.0" + +bin-wrapper@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bin-wrapper/-/bin-wrapper-4.1.0.tgz#99348f2cf85031e3ef7efce7e5300aeaae960605" + integrity sha512-hfRmo7hWIXPkbpi0ZltboCMVrU+0ClXR/JgbCKKjlDjQf6igXa7OwdqNcFWQZPZTgiY7ZpzE3+LjjkLiTN2T7Q== + dependencies: + bin-check "^4.1.0" + bin-version-check "^4.0.0" + download "^7.1.0" + import-lazy "^3.1.0" + os-filter-obj "^2.0.0" + pify "^4.0.1" + +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== + +binary@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" + integrity sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk= + dependencies: + buffers "~0.1.1" + chainsaw "~0.1.0" + +bl@^1.0.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" + integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +bl@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +bluebird@~3.4.1: + version "3.4.7" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + integrity sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM= + +bmp-js@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/bmp-js/-/bmp-js-0.1.0.tgz#e05a63f796a6c1ff25f4771ec7adadc148c07233" + integrity sha1-4Fpj95amwf8l9Hcex62twUjAcjM= + +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@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.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" + +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + +buffer-equal@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b" + integrity sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs= + +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + +buffer-indexof-polyfill@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz#d2732135c5999c64b277fcf9b1abe3498254729c" + integrity sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A== + +buffer@^5.2.0, buffer@^5.2.1, buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +buffers@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" + integrity sha1-skV5w77U1tOWru5tmorn9Ugqt7s= + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cacheable-request@^2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" + integrity sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0= + dependencies: + clone-response "1.0.2" + get-stream "3.0.0" + http-cache-semantics "3.8.1" + keyv "3.0.0" + lowercase-keys "1.0.0" + normalize-url "2.0.1" + responselike "1.0.2" + +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" + +call-me-maybe@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" + integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= + +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== + +camelize@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" + integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs= + +caniuse-lite@^1.0.30001283: + version "1.0.30001312" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz#e11eba4b87e24d22697dae05455d5aea28550d5f" + integrity sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ== + +caw@^2.0.0, caw@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/caw/-/caw-2.0.1.tgz#6c3ca071fc194720883c2dc5da9b074bfc7e9e95" + integrity sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA== + dependencies: + get-proxy "^2.0.0" + isurl "^1.0.0-alpha5" + tunnel-agent "^0.6.0" + url-to-options "^1.0.1" + +chainsaw@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" + integrity sha1-XqtQsor+WAdNDVgpE4iCi15fvJg= + dependencies: + traverse ">=0.3.0 <0.4" + +chalk@^2.0.0, chalk@^2.4.2: + 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.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" + +character-entities@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.1.tgz#98724833e1e27990dee0bd0f2b8a859c3476aac7" + integrity sha512-OzmutCf2Kmc+6DrFrrPS8/tDh2+DpnrfzdICHWhcVC9eOd0N1PXmQEE1a8iM4IziIAG+8tmTq3K+oo0ubH6RRQ== + +"chokidar@>=3.0.0 <4.0.0": + version "3.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +classnames@2.x, classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" + integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== + +clone-response@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= + dependencies: + mimic-response "^1.0.0" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +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== + +comma-separated-tokens@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.2.tgz#d4c25abb679b7751c880be623c1179780fe1dd98" + integrity sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg== + +commander@^2.8.1: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.0.0.tgz#86d58f24ee98126568936bd1d3574e0308a99a40" + integrity sha512-JJfP2saEKbQqvW+FI93OYUB4ByV5cizMpFMiiJI8xDbBvQvSkIk0VvQdn1CZ8mqAO8Loq2h0gYTYtDFUZUeERw== + +complex.js@^2.0.15: + version "2.0.15" + resolved "https://registry.yarnpkg.com/complex.js/-/complex.js-2.0.15.tgz#7add6848b4c1d12aa9262f7df925ebe7a51a7406" + integrity sha512-gDBvQU8IG139ZBQTSo2qvDFP+lANMGluM779csXOr6ny1NUtA3wkUnCFjlDNH/moAVfXtvClYt6G0zarFbtz5w== + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +compress-commons@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.1.tgz#df2a09a7ed17447642bad10a85cc9a19e5c42a7d" + integrity sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ== + dependencies: + buffer-crc32 "^0.2.13" + crc32-stream "^4.0.2" + normalize-path "^3.0.0" + readable-stream "^3.6.0" + +compute-scroll-into-view@^1.0.17: + version "1.0.17" + resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz#6a88f18acd9d42e9cf4baa6bec7e0522607ab7ab" + integrity sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg== + +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= + +config-chain@^1.1.11: + version "1.1.13" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" + integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + +content-disposition@^0.5.2: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +copy-to-clipboard@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" + integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw== + dependencies: + toggle-selection "^1.0.6" + +core-js-pure@^3.19.0: + version "3.20.2" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.20.2.tgz#5d263565f0e34ceeeccdc4422fae3e84ca6b8c0f" + integrity sha512-CmWHvSKn2vNL6p6StNp1EmMIfVY/pqn3JLAjfZQ8WZGPOlGoO92EkX9/Mk81i6GxvoPXjUqEQnpM3rJ5QxxIOg== + +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== + +crc-32@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208" + integrity sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA== + dependencies: + exit-on-epipe "~1.0.1" + printj "~1.1.0" + +crc32-stream@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.2.tgz#c922ad22b38395abe9d3870f02fa8134ed709007" + integrity sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w== + dependencies: + crc-32 "^1.2.0" + readable-stream "^3.4.0" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-env@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" + integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== + dependencies: + cross-spawn "^7.0.1" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^7.0.1, 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" + +css-color-keywords@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" + integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU= + +css-to-react-native@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.0.0.tgz#62dbe678072a824a689bcfee011fc96e02a7d756" + integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ== + dependencies: + camelize "^1.0.0" + css-color-keywords "^1.0.0" + postcss-value-parser "^4.0.2" + +csstype@^3.0.2: + version "3.0.10" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" + integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== + +damerau-levenshtein@^1.0.7: + 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@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b" + integrity sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA== + +date-fns@2.x: + version "2.28.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" + integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw== + +dayjs@1.x, dayjs@^1.10.7, dayjs@^1.8.34: + version "1.10.7" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.7.tgz#2cf5f91add28116748440866a0a1d26f3a6ce468" + integrity sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig== + +debug@^2.2.0, debug@^2.3.3: + 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@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + +decimal.js@^10.3.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + +decode-named-character-reference@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.1.tgz#57b2bd9112659cacbc449d3577d7dadb8e1f3d1b" + integrity sha512-YV/0HQHreRwKb7uBopyIkLG17jG6Sv2qUchk9qSoVJ2f+flwRsPNBO0hAnjt6mTNYUT+vw9Gy2ihXg4sUWPi2w== + dependencies: + character-entities "^2.0.0" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +decompress-response@^3.2.0, decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + +decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" + integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ== + dependencies: + file-type "^5.2.0" + is-stream "^1.1.0" + tar-stream "^1.5.2" + +decompress-tarbz2@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" + integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== + dependencies: + decompress-tar "^4.1.0" + file-type "^6.1.0" + is-stream "^1.1.0" + seek-bzip "^1.0.5" + unbzip2-stream "^1.0.9" + +decompress-targz@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" + integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== + dependencies: + decompress-tar "^4.1.1" + file-type "^5.2.0" + is-stream "^1.1.0" + +decompress-unzip@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" + integrity sha1-3qrM39FK6vhVePczroIQ+bSEj2k= + dependencies: + file-type "^3.8.0" + get-stream "^2.2.0" + pify "^2.3.0" + yauzl "^2.4.2" + +decompress@^4.0.0, decompress@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.1.tgz#007f55cc6a62c055afa37c07eb6a4ee1b773f118" + integrity sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ== + dependencies: + decompress-tar "^4.0.0" + decompress-tarbz2 "^4.0.0" + decompress-targz "^4.0.0" + decompress-unzip "^4.0.1" + graceful-fs "^4.1.10" + make-dir "^1.0.0" + pify "^2.3.0" + strip-dirs "^2.0.0" + +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" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +dequal@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.2.tgz#85ca22025e3a87e65ef75a7a437b35284a7e319d" + integrity sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +diff@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +dir-glob@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034" + integrity sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag== + dependencies: + arrify "^1.0.1" + path-type "^3.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" + +dom-align@^1.7.0: + version "1.12.2" + resolved "https://registry.yarnpkg.com/dom-align/-/dom-align-1.12.2.tgz#0f8164ebd0c9c21b0c790310493cd855892acd4b" + integrity sha512-pHuazgqrsTFrGU2WLDdXxCFabkdQDx72ddkraZNih1KsMcN5qsRSTR9O4VJRlwTPCPb5COYg3LOfiMHHcPInHg== + +dom-walk@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" + integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== + +dom7@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/dom7/-/dom7-4.0.2.tgz#b3595f34c9658d72e88bb6fa6a6e7b430d4bd5fd" + integrity sha512-Ji4t3Y/vNQg6Q9bR+Syx6Td8qiq8116LE9h4OzbPuxdxK7DyyX7i8EXkYgBX6+EiX6+oYXDTH5BSN29G/n4jug== + dependencies: + ssr-window "^4.0.0" + +dom7@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/dom7/-/dom7-4.0.4.tgz#8b68c5d8e5e2ed0fddb1cb93e433bc9060c8f3fb" + integrity sha512-DSSgBzQ4rJWQp1u6o+3FVwMNnT5bzQbMb+o31TjYYeRi05uAcpF8koxdfzeoe5ElzPmua7W7N28YJhF7iEKqIw== + dependencies: + ssr-window "^4.0.0" + +download@^6.2.2: + version "6.2.5" + resolved "https://registry.yarnpkg.com/download/-/download-6.2.5.tgz#acd6a542e4cd0bb42ca70cfc98c9e43b07039714" + integrity sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA== + dependencies: + caw "^2.0.0" + content-disposition "^0.5.2" + decompress "^4.0.0" + ext-name "^5.0.0" + file-type "5.2.0" + filenamify "^2.0.0" + get-stream "^3.0.0" + got "^7.0.0" + make-dir "^1.0.0" + p-event "^1.0.0" + pify "^3.0.0" + +download@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/download/-/download-7.1.0.tgz#9059aa9d70b503ee76a132897be6dec8e5587233" + integrity sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ== + dependencies: + archive-type "^4.0.0" + caw "^2.0.1" + content-disposition "^0.5.2" + decompress "^4.2.0" + ext-name "^5.0.0" + file-type "^8.1.0" + filenamify "^2.0.0" + get-stream "^3.0.0" + got "^8.3.1" + make-dir "^1.2.0" + p-event "^2.1.0" + pify "^3.0.0" + +duplexer2@~0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" + integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME= + dependencies: + readable-stream "^2.0.2" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + +emoji-regex@^9.2.2: + 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@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +es-abstract@^1.19.0, es-abstract@^1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" + integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== + 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-shared-array-buffer "^1.0.1" + is-string "^1.0.7" + is-weakref "^1.0.1" + 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" + +escape-latex@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/escape-latex/-/escape-latex-1.2.0.tgz#07c03818cf7dac250cce517f4fda1b001ef2bca1" + integrity sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw== + +escape-string-regexp@^1.0.2, 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-prettier@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.4.0.tgz#8e6d17c7436649e98c4c2189868562921ef563de" + integrity sha512-CFotdUcMY18nGRo5KGsnNxpznzhkopOcOo0InID+sgQssPrzjvsyKZPvOgymTFeHrFuC3Tzdf2YndhXtULK9Iw== + +eslint-plugin-jsx-a11y@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz#cdbf2df901040ca140b6ec14715c988889c2a6d8" + integrity sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g== + dependencies: + "@babel/runtime" "^7.16.3" + aria-query "^4.2.2" + array-includes "^3.1.4" + ast-types-flow "^0.0.7" + axe-core "^4.3.5" + axobject-query "^2.2.0" + damerau-levenshtein "^1.0.7" + emoji-regex "^9.2.2" + has "^1.0.3" + jsx-ast-utils "^3.2.1" + language-tags "^1.0.5" + minimatch "^3.0.4" + +eslint-plugin-prettier@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz#8b99d1e4b8b24a762472b4567992023619cb98e0" + integrity sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ== + dependencies: + prettier-linter-helpers "^1.0.0" + +eslint-plugin-react-hooks@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz#318dbf312e06fab1c835a4abef00121751ac1172" + integrity sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA== + +eslint-plugin-react@^7.29.2: + version "7.29.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.29.2.tgz#2d4da69d30d0a736efd30890dc6826f3e91f3f7c" + integrity sha512-ypEBTKOy5liFQXZWMchJ3LN0JX1uPI6n7MN7OPHKacqXAxq5gYC30TdO7wqGYQyxD1OrzpobdHC3hDmlRWDg9w== + dependencies: + array-includes "^3.1.4" + array.prototype.flatmap "^1.2.5" + doctrine "^2.1.0" + estraverse "^5.3.0" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.1.2" + object.entries "^1.1.5" + object.fromentries "^2.0.5" + object.hasown "^1.1.0" + object.values "^1.1.5" + prop-types "^15.8.1" + resolve "^2.0.0-next.3" + semver "^6.3.0" + string.prototype.matchall "^4.0.6" + +eslint-plugin-unused-imports@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-2.0.0.tgz#d8db8c4d0cfa0637a8b51ce3fd7d1b6bc3f08520" + integrity sha512-3APeS/tQlTrFa167ThtP0Zm0vctjr4M44HMpeg1P4bK6wItarumq0Ma82xorMKdFsWpphQBlRPzw/pxiVELX1A== + dependencies: + eslint-rule-composer "^0.3.0" + +eslint-rule-composer@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" + integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== + +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-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +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-visitor-keys@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz#eee4acea891814cda67a7d8812d9647dd0179af2" + integrity sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA== + +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@^8.10.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.10.0.tgz#931be395eb60f900c01658b278e05b6dae47199d" + integrity sha512-tcI1D9lfVec+R4LE1mNDnzoJ/f71Kl/9Cv4nG47jOueCMBrCCKYXr4AUVS7go6mWYGFD4+EoN6+eXSrEbRzXVw== + dependencies: + "@eslint/eslintrc" "^1.2.0" + "@humanwhocodes/config-array" "^0.9.2" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.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 "^6.0.1" + globals "^13.6.0" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^4.1.0" + 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" + regexpp "^3.2.0" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^9.3.1: + version "9.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd" + integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ== + dependencies: + acorn "^8.7.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^3.3.0" + +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, estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +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== + +exceljs@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/exceljs/-/exceljs-4.3.0.tgz#939bc0d4c59c200acadb7051be34d25c109853c4" + integrity sha512-hTAeo5b5TPvf8Z02I2sKIT4kSfCnOO2bCxYX8ABqODCdAjppI3gI9VYiGCQQYVcBaBSKlFDMKlAQRqC+kV9O8w== + dependencies: + archiver "^5.0.0" + dayjs "^1.8.34" + fast-csv "^4.3.1" + jszip "^3.5.0" + readable-stream "^3.6.0" + saxes "^5.0.1" + tmp "^0.2.0" + unzipper "^0.10.11" + uuid "^8.3.0" + +exec-buffer@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/exec-buffer/-/exec-buffer-3.2.0.tgz#b1686dbd904c7cf982e652c1f5a79b1e5573082b" + integrity sha512-wsiD+2Tp6BWHoVv3B+5Dcx6E7u5zky+hUwOHjuH2hKSLR3dvRmX8fk8UD8uqQixHs4Wk6eDmiegVrMPjKj7wpA== + dependencies: + execa "^0.7.0" + p-finally "^1.0.0" + pify "^3.0.0" + rimraf "^2.5.4" + tempfile "^2.0.0" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +executable@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" + integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg== + dependencies: + pify "^2.2.0" + +exif-parser@^0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/exif-parser/-/exif-parser-0.1.12.tgz#58a9d2d72c02c1f6f02a0ef4a9166272b7760922" + integrity sha1-WKnS1ywCwfbwKg70qRZicrd2CSI= + +exit-on-epipe@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" + integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw== + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expressionparser@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/expressionparser/-/expressionparser-1.1.5.tgz#b16bc45e7557be437c2259e2ab0abd8b857e979b" + integrity sha512-9GldsRvXhcJ+ZPiK7fel5KBpgU+LjjQjnyWQVugJcvRc99lXTBICwXKaQV2laZ1KUlTVUBnMmFpgtkMVwwMiHA== + +ext-list@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" + integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA== + dependencies: + mime-db "^1.28.0" + +ext-name@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ext-name/-/ext-name-5.0.0.tgz#70781981d183ee15d13993c8822045c506c8f0a6" + integrity sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ== + dependencies: + ext-list "^2.0.0" + sort-keys-length "^1.0.0" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +fast-csv@^4.3.1: + version "4.3.6" + resolved "https://registry.yarnpkg.com/fast-csv/-/fast-csv-4.3.6.tgz#70349bdd8fe4d66b1130d8c91820b64a21bc4a63" + integrity sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw== + dependencies: + "@fast-csv/format" "4.3.5" + "@fast-csv/parse" "4.3.6" + +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-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + +fast-glob@^2.0.2: + version "2.2.7" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" + integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== + dependencies: + "@mrmlnc/readdir-enhanced" "^2.2.1" + "@nodelib/fs.stat" "^1.1.2" + glob-parent "^3.1.0" + is-glob "^4.0.0" + merge2 "^1.2.3" + micromatch "^3.1.10" + +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" + +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= + dependencies: + pend "~1.2.0" + +fetch-blob@^3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.1.3.tgz#a7dca4855e39d3e3c5a1da62d4ee335c37d26012" + integrity sha512-ax1Y5I9w+9+JiM+wdHkhBoxew+zG4AJ2SvAD1v1szpddUIiPERVGBxrMcB2ZqW0Y3PP8bOWYv2zqQq1Jp2kqUQ== + dependencies: + web-streams-polyfill "^3.0.3" + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +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" + +file-loader@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-3.0.1.tgz#f8e0ba0b599918b51adfe45d66d1e771ad560faa" + integrity sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw== + dependencies: + loader-utils "^1.0.2" + schema-utils "^1.0.0" + +file-type@5.2.0, file-type@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" + integrity sha1-LdvqfHP/42No365J3DOMBYwritY= + +file-type@^10.7.0: + version "10.11.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-10.11.0.tgz#2961d09e4675b9fb9a3ee6b69e9cd23f43fd1890" + integrity sha512-uzk64HRpUZyTGZtVuvrjP0FYxzQrBf4rojot6J65YMEbwBLB0CWm0CLojVpwpmFmxcE/lkvYICgfcGozbBq6rw== + +file-type@^3.8.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" + integrity sha1-JXoHg4TR24CHvESdEH1SpSZyuek= + +file-type@^4.2.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-4.4.0.tgz#1b600e5fca1fbdc6e80c0a70c71c8dba5f7906c5" + integrity sha1-G2AOX8ofvcboDApwxxyNul95BsU= + +file-type@^6.1.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" + integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== + +file-type@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-8.1.0.tgz#244f3b7ef641bbe0cca196c7276e4b332399f68c" + integrity sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ== + +file-type@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-9.0.0.tgz#a68d5ad07f486414dfb2c8866f73161946714a18" + integrity sha512-Qe/5NJrgIOlwijpq3B7BEpzPFcgzggOTagZmkXQY4LA6bsXKTUstK7Wp12lEJ/mLKTpvIZxmIuRcLYWT6ov9lw== + +filename-reserved-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" + integrity sha1-q/c9+rc10EVECr/qLZHzieu/oik= + +filenamify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-2.1.0.tgz#88faf495fb1b47abfd612300002a16228c677ee9" + integrity sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA== + dependencies: + filename-reserved-regex "^2.0.0" + strip-outer "^1.0.0" + trim-repeated "^1.0.0" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +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-versions@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-3.2.0.tgz#10297f98030a786829681690545ef659ed1d254e" + integrity sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww== + dependencies: + semver-regex "^2.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.4" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2" + integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw== + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +formdata-polyfill@^4.0.10: + version "4.0.10" + resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" + integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== + dependencies: + fetch-blob "^3.1.2" + +fraction.js@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.2.tgz#13e420a92422b6cf244dff8690ed89401029fbe8" + integrity sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA== + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +from2@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +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.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +fstream@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" + integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +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-proxy@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/get-proxy/-/get-proxy-2.1.0.tgz#349f2b4d91d44c4d4d4e9cba2ad90143fac5ef93" + integrity sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw== + dependencies: + npm-conf "^1.1.0" + +get-stream@3.0.0, get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +get-stream@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" + integrity sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4= + dependencies: + object-assign "^4.0.1" + pinkie-promise "^2.0.0" + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +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" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +gifwrap@^0.9.2: + version "0.9.2" + resolved "https://registry.yarnpkg.com/gifwrap/-/gifwrap-0.9.2.tgz#348e286e67d7cf57942172e1e6f05a71cee78489" + integrity sha512-fcIswrPaiCDAyO8xnWvHSZdWChjKXUanKKpAiWWJ/UTkEi/aYKn5+90e7DE820zbEaVR9CE2y4z9bzhQijZ0BA== + dependencies: + image-q "^1.1.1" + omggif "^1.0.10" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + 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-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob-to-regexp@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" + integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= + +glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: + 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" + +global@~4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" + integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== + dependencies: + min-document "^2.19.0" + process "^0.11.10" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.6.0, globals@^13.9.0: + version "13.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" + integrity sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg== + dependencies: + type-fest "^0.20.2" + +globby@^11.0.4: + 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" + +globby@^8.0.1: + version "8.0.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d" + integrity sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w== + dependencies: + array-union "^1.0.1" + dir-glob "2.0.0" + fast-glob "^2.0.2" + glob "^7.1.2" + ignore "^3.3.5" + pify "^3.0.0" + slash "^1.0.0" + +got@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" + integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw== + dependencies: + decompress-response "^3.2.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-plain-obj "^1.1.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + p-cancelable "^0.3.0" + p-timeout "^1.1.1" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + url-parse-lax "^1.0.0" + url-to-options "^1.0.1" + +got@^8.3.1: + version "8.3.2" + resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" + integrity sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw== + dependencies: + "@sindresorhus/is" "^0.7.0" + cacheable-request "^2.1.1" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + into-stream "^3.1.0" + is-retry-allowed "^1.1.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + mimic-response "^1.0.0" + p-cancelable "^0.4.0" + p-timeout "^2.0.1" + pify "^3.0.0" + safe-buffer "^5.1.1" + timed-out "^4.0.1" + url-parse-lax "^3.0.0" + url-to-options "^1.0.1" + +graceful-fs@^4.1.10: + version "4.2.9" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" + integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== + +graceful-fs@^4.1.2, graceful-fs@^4.2.0, graceful-fs@^4.2.2: + version "4.2.8" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== + +graphql-tag@^2.12.3: + version "2.12.6" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" + integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== + dependencies: + tslib "^2.1.0" + +graphql@^16.3.0: + version "16.3.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.3.0.tgz#a91e24d10babf9e60c706919bb182b53ccdffc05" + integrity sha512-xm+ANmA16BzCT5pLjuXySbQVFwH3oJctUVdy81w1sV0vBU0KgDdBGtxQOUd5zqOBk/JayAFeG8Dlmeq74rjm/A== + +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-symbol-support-x@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== + +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-to-string-tag-x@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== + dependencies: + has-symbol-support-x "^1.4.1" + +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-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +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" + +hast-util-whitespace@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz#4fc1086467cc1ef5ba20673cb6b03cec3a970f1c" + integrity sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg== + +hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +html-escaper@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +html-parse-stringify@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2" + integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg== + dependencies: + void-elements "3.1.0" + +http-cache-semantics@3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== + +i18next-browser-languagedetector@^6.1.3: + version "6.1.3" + resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-6.1.3.tgz#9bc47fb4a5db86d567318895df343d2d1b9692f3" + integrity sha512-T+oGXHXtrur14CGnZZ7qQ07X38XJQEI00b/4ILrtO6xPbwTlQ1wtMZC2H+tBULixHuVUXv8LKbxfjyITJkezUg== + dependencies: + "@babel/runtime" "^7.14.6" + +i18next@^21.6.12: + version "21.6.12" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-21.6.12.tgz#5080a611af98f4104062a88452b30704b29fa924" + integrity sha512-xlGTPdu2g5PZEUIE6TA1mQ9EIAAv9nMFONzgwAIrKL/KTmYYWufQNGgOmp5Og1PvgUji+6i1whz0rMdsz1qaKw== + dependencies: + "@babel/runtime" "^7.12.0" + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore@^3.3.5: + version "3.3.10" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" + integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== + +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, ignore@^5.1.8, ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +image-q@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/image-q/-/image-q-1.1.1.tgz#fc84099664460b90ca862d9300b6bfbbbfbf8056" + integrity sha1-/IQJlmRGC5DKhi2TALa/u7+/gFY= + +imagemin-optipng@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/imagemin-optipng/-/imagemin-optipng-8.0.0.tgz#b88e5cf6da25cc8479e07cdf38c3ae0479df7ef2" + integrity sha512-CUGfhfwqlPjAC0rm8Fy+R2DJDBGjzy2SkfyT09L8rasnF9jSoHFqJ1xxSZWK6HVPZBMhGPMxCTL70OgTHlLF5A== + dependencies: + exec-buffer "^3.0.0" + is-png "^2.0.0" + optipng-bin "^7.0.0" + +imagemin@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/imagemin/-/imagemin-6.1.0.tgz#62508b465728fea36c03cdc07d915fe2d8cf9e13" + integrity sha512-8ryJBL1CN5uSHpiBMX0rJw79C9F9aJqMnjGnrd/1CafegpNuA81RBAAru/jQQEOWlOJJlpRnlcVFF6wq+Ist0A== + dependencies: + file-type "^10.7.0" + globby "^8.0.1" + make-dir "^1.0.0" + p-pipe "^1.1.0" + pify "^4.0.1" + replace-ext "^1.0.0" + +img-loader@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/img-loader/-/img-loader-3.0.2.tgz#423d39cb45f017e88c7959b2740226ce4c9001aa" + integrity sha512-rSriLKgvi85Km7ppSF+AEAM3nU4fxpvCkaXtC/IoCEU7jfks55bEANFs0bB9YXYkxY9JurZQIZFtXh5Gue3upw== + dependencies: + loader-utils "^1.1.0" + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= + +immutable@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23" + integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw== + +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" + +import-lazy@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-3.1.0.tgz#891279202c8a2280fdbd6674dbd8da1a1dfc67cc" + integrity sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ== + +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.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@^1.3.4: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +inline-style-parser@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" + integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== + +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" + +into-stream@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" + integrity sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY= + dependencies: + from2 "^2.1.1" + p-is-promise "^1.1.0" + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +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-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-buffer@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" + integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== + +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: + version "2.8.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" + integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== + dependencies: + has "^1.0.3" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +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-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.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-function@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" + integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-natural-number@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" + integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg= + +is-negative-zero@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +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@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +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-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" + integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== + +is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-plain-obj@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.0.0.tgz#06c0999fd7574edf5a906ba5644ad0feb3a84d22" + integrity sha512-NXRbBtUdBioI73y/HmOhogw/U5msYPC9DAtGkJXeFcFWSFZw0mCUsPxk/snTuJHzNKA8kLBK4rH97RMB1BfCXw== + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-png@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-png/-/is-png-2.0.0.tgz#ee8cbc9e9b050425cedeeb4a6fb74a649b0a4a8d" + integrity sha512-4KPGizaVGj2LK7xwJIz8o5B2ubu1D/vcQsgOGFEDlpcvgZHto4gBnyd0ig7Ws+67ixmwKoNmu0hYnpo6AaKb5g== + +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-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" + integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== + +is-shared-array-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" + integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== + +is-stream@^1.0.0, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +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-weakref@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +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= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isomorphic-fetch@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz#0267b005049046d2421207215d45d6a262b8b8b4" + integrity sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA== + dependencies: + node-fetch "^2.6.1" + whatwg-fetch "^3.4.1" + +isurl@^1.0.0-alpha5: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== + dependencies: + has-to-string-tag-x "^1.2.0" + is-object "^1.0.1" + +javascript-natural-sort@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59" + integrity sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k= + +jimp@^0.16.1: + version "0.16.1" + resolved "https://registry.yarnpkg.com/jimp/-/jimp-0.16.1.tgz#192f851a30e5ca11112a3d0aa53137659a78ca7a" + integrity sha512-+EKVxbR36Td7Hfd23wKGIeEyHbxShZDX6L8uJkgVW3ESA9GiTEPK08tG1XI2r/0w5Ch0HyJF5kPqF9K7EmGjaw== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/custom" "^0.16.1" + "@jimp/plugins" "^0.16.1" + "@jimp/types" "^0.16.1" + regenerator-runtime "^0.13.3" + +jpeg-js@0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.2.tgz#8b345b1ae4abde64c2da2fe67ea216a114ac279d" + integrity sha512-+az2gi/hvex7eLTMTlbRLOhH6P6WFdk2ITI8HJsaH2VqYO0I594zXSYEP+tf4FW+8Cy68ScDXoAsQdyQanv3sw== + +"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@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= + +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-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= + +json2mq@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/json2mq/-/json2mq-0.2.0.tgz#b637bd3ba9eabe122c83e9720483aeb10d2c904a" + integrity sha1-tje9O6nqvhIsg+lyBIOusQ0skEo= + dependencies: + string-convert "^0.2.0" + +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" + +json5@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== + dependencies: + minimist "^1.2.5" + +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.2.1: + 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" + +jszip@^3.5.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.7.1.tgz#bd63401221c15625a1228c556ca8a68da6fda3d9" + integrity sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg== + dependencies: + lie "~3.3.0" + pako "~1.0.2" + readable-stream "~2.3.6" + set-immediate-shim "~1.0.1" + +keyv@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" + integrity sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA== + dependencies: + json-buffer "3.0.0" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +kleur@^4.0.3: + version "4.1.4" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d" + integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA== + +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" + +lazystream@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" + integrity sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw== + dependencies: + readable-stream "^2.0.5" + +leaflet@^1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.7.1.tgz#10d684916edfe1bf41d688a3b97127c0322a2a19" + integrity sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw== + +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" + +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + +listenercount@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937" + integrity sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc= + +load-bmfont@^1.3.1, load-bmfont@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/load-bmfont/-/load-bmfont-1.4.1.tgz#c0f5f4711a1e2ccff725a7b6078087ccfcddd3e9" + integrity sha512-8UyQoYmdRDy81Brz6aLAUhfZLwr5zV0L3taTQ4hju7m6biuwiWiJXjPhBJxbUQJA8PrkvJ/7Enqmwk2sM14soA== + dependencies: + buffer-equal "0.0.1" + mime "^1.3.4" + parse-bmfont-ascii "^1.0.3" + parse-bmfont-binary "^1.0.5" + parse-bmfont-xml "^1.1.4" + phin "^2.9.1" + xhr "^2.0.1" + xtend "^4.0.0" + +loader-utils@^1.0.2, loader-utils@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" + integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^1.0.1" + +loader-utils@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" + integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +lodash-es@^4.17.15: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.difference@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" + integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw= + +lodash.escaperegexp@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" + integrity sha1-ZHYsSGGAglGKw99Mz11YhtriA0c= + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + +lodash.groupby@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.groupby/-/lodash.groupby-4.6.0.tgz#0b08a1dcf68397c397855c3239783832df7403d1" + integrity sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E= + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= + +lodash.isfunction@^3.0.9: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" + integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw== + +lodash.isnil@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/lodash.isnil/-/lodash.isnil-4.0.0.tgz#49e28cd559013458c814c5479d3c663a21bfaa6c" + integrity sha1-SeKM1VkBNFjIFMVHnTxmOiG/qmw= + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + +lodash.isundefined@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz#23ef3d9535565203a66cefd5b830f848911afb48" + integrity sha1-I+89lTVWUgOmbO/VuDD4SJEa+0g= + +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.union@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +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" + +lowercase-keys@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= + +lowercase-keys@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +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@^1.0.0, make-dir@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== + dependencies: + pify "^3.0.0" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +material-colors@^1.2.1: + version "1.2.6" + resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46" + integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg== + +mathjs@*: + version "10.0.2" + resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-10.0.2.tgz#bf73f825ee9788d5a001e67383d1ce3d19d05f31" + integrity sha512-QCbsqJ2iBCJP/yTj9Dg45SWecwVf5fxe8sZo4SyerthHVydpxRL33hU0MynwAHqz1XglSGkSKk7QzTD8U8wPFg== + dependencies: + "@babel/runtime" "^7.16.5" + complex.js "^2.0.15" + decimal.js "^10.3.1" + escape-latex "^1.2.0" + fraction.js "^4.1.2" + javascript-natural-sort "^0.7.1" + seedrandom "^3.0.5" + tiny-emitter "^2.1.0" + typed-function "^2.0.0" + +mdast-util-definitions@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-5.1.0.tgz#b6d10ef00a3c4cf191e8d9a5fa58d7f4a366f817" + integrity sha512-5hcR7FL2EuZ4q6lLMUK5w4lHT2H3vqL9quPvYZ/Ku5iifrirfMHiGdhxdXMUbUkDmz5I+TYMd7nbaxUhbQkfpQ== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + unist-util-visit "^3.0.0" + +mdast-util-from-markdown@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz#84df2924ccc6c995dec1e2368b2b208ad0a76268" + integrity sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + decode-named-character-reference "^1.0.0" + mdast-util-to-string "^3.1.0" + micromark "^3.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-decode-string "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + unist-util-stringify-position "^3.0.0" + uvu "^0.5.0" + +mdast-util-to-hast@^12.1.0: + version "12.1.1" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-12.1.1.tgz#89a2bb405eaf3b05eb8bf45157678f35eef5dbca" + integrity sha512-qE09zD6ylVP14jV4mjLIhDBOrpFdShHZcEsYvvKGABlr9mGbV7mTlRWdoFxL/EYSTNDiC9GZXy7y8Shgb9Dtzw== + dependencies: + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + "@types/mdurl" "^1.0.0" + mdast-util-definitions "^5.0.0" + mdurl "^1.0.0" + micromark-util-sanitize-uri "^1.0.0" + unist-builder "^3.0.0" + unist-util-generated "^2.0.0" + unist-util-position "^4.0.0" + unist-util-visit "^4.0.0" + +mdast-util-to-string@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz#56c506d065fbf769515235e577b5a261552d56e9" + integrity sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA== + +mdurl@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= + +memoize-one@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" + integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== + +merge2@^1.2.3, 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== + +micromark-core-commonmark@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz#edff4c72e5993d93724a3c206970f5a15b0585ad" + integrity sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-factory-destination "^1.0.0" + micromark-factory-label "^1.0.0" + micromark-factory-space "^1.0.0" + micromark-factory-title "^1.0.0" + micromark-factory-whitespace "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-chunked "^1.0.0" + micromark-util-classify-character "^1.0.0" + micromark-util-html-tag-name "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-resolve-all "^1.0.0" + micromark-util-subtokenize "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.1" + uvu "^0.5.0" + +micromark-factory-destination@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz#fef1cb59ad4997c496f887b6977aa3034a5a277e" + integrity sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-factory-label@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz#6be2551fa8d13542fcbbac478258fb7a20047137" + integrity sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-factory-space@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz#cebff49968f2b9616c0fcb239e96685cb9497633" + integrity sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-factory-title@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz#7e09287c3748ff1693930f176e1c4a328382494f" + integrity sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-factory-whitespace@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz#e991e043ad376c1ba52f4e49858ce0794678621c" + integrity sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-character@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-1.1.0.tgz#d97c54d5742a0d9611a68ca0cd4124331f264d86" + integrity sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg== + dependencies: + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-chunked@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz#5b40d83f3d53b84c4c6bce30ed4257e9a4c79d06" + integrity sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g== + dependencies: + micromark-util-symbol "^1.0.0" + +micromark-util-classify-character@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz#cbd7b447cb79ee6997dd274a46fc4eb806460a20" + integrity sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-combine-extensions@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz#91418e1e74fb893e3628b8d496085639124ff3d5" + integrity sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA== + dependencies: + micromark-util-chunked "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-decode-numeric-character-reference@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz#dcc85f13b5bd93ff8d2868c3dba28039d490b946" + integrity sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w== + dependencies: + micromark-util-symbol "^1.0.0" + +micromark-util-decode-string@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz#942252ab7a76dec2dbf089cc32505ee2bc3acf02" + integrity sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-symbol "^1.0.0" + +micromark-util-encode@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz#2c1c22d3800870ad770ece5686ebca5920353383" + integrity sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA== + +micromark-util-html-tag-name@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.0.0.tgz#75737e92fef50af0c6212bd309bc5cb8dbd489ed" + integrity sha512-NenEKIshW2ZI/ERv9HtFNsrn3llSPZtY337LID/24WeLqMzeZhBEE6BQ0vS2ZBjshm5n40chKtJ3qjAbVV8S0g== + +micromark-util-normalize-identifier@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz#4a3539cb8db954bbec5203952bfe8cedadae7828" + integrity sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg== + dependencies: + micromark-util-symbol "^1.0.0" + +micromark-util-resolve-all@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz#a7c363f49a0162e931960c44f3127ab58f031d88" + integrity sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw== + dependencies: + micromark-util-types "^1.0.0" + +micromark-util-sanitize-uri@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz#27dc875397cd15102274c6c6da5585d34d4f12b2" + integrity sha512-cCxvBKlmac4rxCGx6ejlIviRaMKZc0fWm5HdCHEeDWRSkn44l6NdYVRyU+0nT1XC72EQJMZV8IPHF+jTr56lAg== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-encode "^1.0.0" + micromark-util-symbol "^1.0.0" + +micromark-util-subtokenize@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz#ff6f1af6ac836f8bfdbf9b02f40431760ad89105" + integrity sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA== + dependencies: + micromark-util-chunked "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-util-symbol@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz#b90344db62042ce454f351cf0bebcc0a6da4920e" + integrity sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ== + +micromark-util-types@^1.0.0, micromark-util-types@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-1.0.2.tgz#f4220fdb319205812f99c40f8c87a9be83eded20" + integrity sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w== + +micromark@^3.0.0: + version "3.0.10" + resolved "https://registry.yarnpkg.com/micromark/-/micromark-3.0.10.tgz#1eac156f0399d42736458a14b0ca2d86190b457c" + integrity sha512-ryTDy6UUunOXy2HPjelppgJ2sNfcPz1pLlMdA6Rz9jPzhLikWXv/irpWV/I2jd68Uhmny7hHxAlAhk4+vWggpg== + dependencies: + "@types/debug" "^4.0.0" + debug "^4.0.0" + decode-named-character-reference "^1.0.0" + micromark-core-commonmark "^1.0.1" + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-chunked "^1.0.0" + micromark-util-combine-extensions "^1.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-encode "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-resolve-all "^1.0.0" + micromark-util-sanitize-uri "^1.0.0" + micromark-util-subtokenize "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.1" + uvu "^0.5.0" + +micromatch@^3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +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" + +mime-db@^1.28.0: + version "1.51.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" + integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== + +mime@^1.3.4: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.0.3: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= + dependencies: + dom-walk "^0.1.0" + +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" + +minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +"mkdirp@>=0.5 0", mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +moment@^2.24.0, moment@^2.25.3: + version "2.29.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" + integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== + +mri@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" + integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== + +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== + +nanoid@^3.1.30: + version "3.3.1" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" + integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +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-compose-plugins@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/next-compose-plugins/-/next-compose-plugins-2.2.1.tgz#020fc53f275a7e719d62521bef4300fbb6fde5ab" + integrity sha512-OjJ+fV15FXO2uQXQagLD4C0abYErBjyjE0I0FHpOEIB8upw0hg1ldFP6cqHTJBH1cZqy96OeR3u1dJ+Ez2D4Bg== + +next-optimized-images@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/next-optimized-images/-/next-optimized-images-2.6.2.tgz#8974a2186758c50e1a263c6866dbec5c25280db5" + integrity sha512-yH/f3eLmoQ/TxvWRiSuM6AuF3tR1s4nePdHPTm9gl4lAaGEKxTGaSuUL+ZxE5j/c/ITrnHVHibQzOz1Jl8euQw== + dependencies: + chalk "^2.4.2" + figures "^3.0.0" + file-loader "^3.0.1" + imagemin "^6.1.0" + img-loader "^3.0.1" + raw-loader "^2.0.0" + url-loader "^1.1.2" + +next-redux-wrapper@^7.0.5: + version "7.0.5" + resolved "https://registry.yarnpkg.com/next-redux-wrapper/-/next-redux-wrapper-7.0.5.tgz#109cd3fe02183b18fbd094924cfcbd21262039dc" + integrity sha512-UFXdAWG5i+GFT8+Hoqpx3GArkPh34fVWF9YoA2VSHlBzsrPtnRd7NWM6FNSYUennpommTpWJ09mu+r/1UxyIkg== + +next@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/next/-/next-12.1.0.tgz#c33d753b644be92fc58e06e5a214f143da61dd5d" + integrity sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q== + dependencies: + "@next/env" "12.1.0" + caniuse-lite "^1.0.30001283" + postcss "8.4.5" + styled-jsx "5.0.0" + use-subscription "1.5.1" + optionalDependencies: + "@next/swc-android-arm64" "12.1.0" + "@next/swc-darwin-arm64" "12.1.0" + "@next/swc-darwin-x64" "12.1.0" + "@next/swc-linux-arm-gnueabihf" "12.1.0" + "@next/swc-linux-arm64-gnu" "12.1.0" + "@next/swc-linux-arm64-musl" "12.1.0" + "@next/swc-linux-x64-gnu" "12.1.0" + "@next/swc-linux-x64-musl" "12.1.0" + "@next/swc-win32-arm64-msvc" "12.1.0" + "@next/swc-win32-ia32-msvc" "12.1.0" + "@next/swc-win32-x64-msvc" "12.1.0" + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-fetch@*: + version "3.1.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.1.0.tgz#714f4922dc270239487654eaeeab86b8206cb52e" + integrity sha512-QU0WbIfMUjd5+MUzQOYhenAazakV7Irh1SGkWCsRzBwvm4fAhzEUaHMJ6QLP7gWT6WO9/oH2zhKMMGMuIrDyKw== + dependencies: + data-uri-to-buffer "^4.0.0" + fetch-blob "^3.1.2" + formdata-polyfill "^4.0.10" + +node-fetch@^2.6.1: + version "2.6.6" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89" + integrity sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA== + dependencies: + whatwg-url "^5.0.0" + +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== + +normalize-url@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" + integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== + dependencies: + prepend-http "^2.0.0" + query-string "^5.0.1" + sort-keys "^2.0.0" + +npm-conf@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" + integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw== + dependencies: + config-chain "^1.1.11" + pify "^3.0.0" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +object-assign@^4.0.1, object-assign@^4.1.0, 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-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.11.0, object-inspect@^1.9.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" + integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== + +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-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +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.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" + integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.fromentries@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" + integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.hasown@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5" + integrity sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +object.values@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" + integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +omggif@^1.0.10, omggif@^1.0.9: + version "1.0.10" + resolved "https://registry.yarnpkg.com/omggif/-/omggif-1.0.10.tgz#ddaaf90d4a42f532e9e7cb3a95ecdd47f17c7b19" + integrity sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +optimism@^0.16.1: + version "0.16.1" + resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.16.1.tgz#7c8efc1f3179f18307b887e18c15c5b7133f6e7d" + integrity sha512-64i+Uw3otrndfq5kaoGNoY7pvOhSsjFEN4bdEFh80MWVk/dbgJfMv7VFDeCT8LxNAlEVhQmdVEbfE7X2nWNIIg== + dependencies: + "@wry/context" "^0.6.0" + "@wry/trie" "^0.3.0" + +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" + +optipng-bin@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/optipng-bin/-/optipng-bin-7.0.1.tgz#beb8e55a52f8a26f885ee57ab44fcf62397d6972" + integrity sha512-W99mpdW7Nt2PpFiaO+74pkht7KEqkXkeRomdWXfEz3SALZ6hns81y/pm1dsGZ6ItUIfchiNIP6ORDr1zETU1jA== + dependencies: + bin-build "^3.0.0" + bin-wrapper "^4.0.0" + +os-filter-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/os-filter-obj/-/os-filter-obj-2.0.0.tgz#1c0b62d5f3a2442749a2d139e6dddee6e81d8d16" + integrity sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg== + dependencies: + arch "^2.1.0" + +p-cancelable@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" + integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== + +p-cancelable@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" + integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== + +p-event@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-event/-/p-event-1.3.0.tgz#8e6b4f4f65c72bc5b6fe28b75eda874f96a4a085" + integrity sha1-jmtPT2XHK8W2/ii3XtqHT5akoIU= + dependencies: + p-timeout "^1.1.1" + +p-event@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/p-event/-/p-event-2.3.1.tgz#596279ef169ab2c3e0cae88c1cfbb08079993ef6" + integrity sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA== + dependencies: + p-timeout "^2.0.1" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-is-promise@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= + +p-map-series@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-1.0.0.tgz#bf98fe575705658a9e1351befb85ae4c1f07bdca" + integrity sha1-v5j+V1cFZYqeE1G++4WuTB8Hvco= + dependencies: + p-reduce "^1.0.0" + +p-pipe@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-pipe/-/p-pipe-1.2.0.tgz#4b1a11399a11520a67790ee5a0c1d5881d6befe9" + integrity sha1-SxoROZoRUgpneQ7loMHViB1r7+k= + +p-reduce@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" + integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= + +p-timeout@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" + integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y= + dependencies: + p-finally "^1.0.0" + +p-timeout@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" + integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== + dependencies: + p-finally "^1.0.0" + +pako@^1.0.5, pako@~1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-bmfont-ascii@^1.0.3: + version "1.0.6" + resolved "https://registry.yarnpkg.com/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz#11ac3c3ff58f7c2020ab22769079108d4dfa0285" + integrity sha1-Eaw8P/WPfCAgqyJ2kHkQjU36AoU= + +parse-bmfont-binary@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz#d038b476d3e9dd9db1e11a0b0e53a22792b69006" + integrity sha1-0Di0dtPp3Z2x4RoLDlOiJ5K2kAY= + +parse-bmfont-xml@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz#015319797e3e12f9e739c4d513872cd2fa35f389" + integrity sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ== + dependencies: + xml-parse-from-string "^1.0.0" + xml2js "^0.4.5" + +parse-headers@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.4.tgz#9eaf2d02bed2d1eff494331ce3df36d7924760bf" + integrity sha512-psZ9iZoCNFLrgRjZ1d8mn0h9WRqJwFxM9q3x7iUjN/YT2OksthDJ5TiPCu2F38kS4zutqfW+YdVVkBZZx3/1aw== + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + +phin@^2.9.1: + version "2.9.3" + resolved "https://registry.yarnpkg.com/phin/-/phin-2.9.3.tgz#f9b6ac10a035636fb65dfc576aaaa17b8743125c" + integrity sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^2.2.0, pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pixelmatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-4.0.2.tgz#8f47dcec5011b477b67db03c243bc1f3085e8854" + integrity sha1-j0fc7FARtHe2fbA8JDvB8wheiFQ= + dependencies: + pngjs "^3.0.0" + +pngjs@^3.0.0, pngjs@^3.3.3: + version "3.4.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" + integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== + +polished@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/polished/-/polished-4.1.4.tgz#640293ba834109614961a700fdacbb6599fb12d0" + integrity sha512-Nq5Mbza+Auo7N3sQb1QMFaQiDO+4UexWuSGR7Cjb4Sw11SZIJcrrFtiZ+L0jT9MBsUsxDboHVASbCLbE1rnECg== + dependencies: + "@babel/runtime" "^7.16.7" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +postcss-value-parser@^4.0.2: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@8.4.5: + version "8.4.5" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" + integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== + dependencies: + nanoid "^3.1.30" + picocolors "^1.0.0" + source-map-js "^1.0.1" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" + integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== + +printj@~1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" + integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.7.2: + version "15.8.0" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.0.tgz#d237e624c45a9846e469f5f31117f970017ff588" + integrity sha512-fDGekdaHh65eI3lMi5OnErU6a8Ighg2KjcjQxO7m8VHyWjcPyj5kiOgV1LQDOOOgVy3+5FgjXvdSSX7B8/5/4g== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +property-information@^6.0.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.1.1.tgz#5ca85510a3019726cb9afed4197b7b8ac5926a22" + integrity sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w== + +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +raw-loader@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-2.0.0.tgz#e2813d9e1e3f80d1bbade5ad082e809679e20c26" + integrity sha512-kZnO5MoIyrojfrPWqrhFNLZemIAX8edMOCp++yC5RKxzFB3m92DqKNhKlU6+FvpOhWtvyh3jOaD7J6/9tpdIKg== + dependencies: + loader-utils "^1.1.0" + schema-utils "^1.0.0" + +rc-align@^4.0.0: + version "4.0.11" + resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-4.0.11.tgz#8198c62db266bc1b8ef05e56c13275bf72628a5e" + integrity sha512-n9mQfIYQbbNTbefyQnRHZPWuTEwG1rY4a9yKlIWHSTbgwI+XUMGRYd0uJ5pE2UbrNX0WvnMBA1zJ3Lrecpra/A== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + dom-align "^1.7.0" + lodash "^4.17.21" + rc-util "^5.3.0" + resize-observer-polyfill "^1.5.1" + +rc-cascader@~3.2.1: + version "3.2.6" + resolved "https://registry.yarnpkg.com/rc-cascader/-/rc-cascader-3.2.6.tgz#499cf7f65625569eff6dc3854612298de4f24093" + integrity sha512-3CmlJP7jPVlP5jT+O3PrP8E9yxees48Na7Hiir84ktcw11pUUU5YawAhuRoSc09SGVvRcP70a9gCu94Hqp3ZwA== + dependencies: + "@babel/runtime" "^7.12.5" + array-tree-filter "^2.1.0" + classnames "^2.3.1" + rc-select "~14.0.0-alpha.23" + rc-tree "~5.4.3" + rc-util "^5.6.1" + +rc-checkbox@~2.3.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/rc-checkbox/-/rc-checkbox-2.3.2.tgz#f91b3678c7edb2baa8121c9483c664fa6f0aefc1" + integrity sha512-afVi1FYiGv1U0JlpNH/UaEXdh6WUJjcWokj/nUN2TgG80bfG+MDdbfHKlLcNNba94mbjy2/SXJ1HDgrOkXGAjg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + +rc-collapse@~3.1.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/rc-collapse/-/rc-collapse-3.1.2.tgz#76028a811b845d03d9460ccc409c7ea8ad09db14" + integrity sha512-HujcKq7mghk/gVKeI6EjzTbb8e19XUZpakrYazu1MblEZ3Hu3WBMSN4A3QmvbF6n1g7x6lUlZvsHZ5shABWYOQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.3.4" + rc-util "^5.2.1" + shallowequal "^1.1.0" + +rc-dialog@~8.6.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/rc-dialog/-/rc-dialog-8.6.0.tgz#3b228dac085de5eed8c6237f31162104687442e7" + integrity sha512-GSbkfqjqxpZC5/zc+8H332+q5l/DKUhpQr0vdX2uDsxo5K0PhvaMEVjyoJUTkZ3+JstEADQji1PVLVb/2bJeOQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + rc-motion "^2.3.0" + rc-util "^5.6.1" + +rc-drawer@~4.4.2: + version "4.4.3" + resolved "https://registry.yarnpkg.com/rc-drawer/-/rc-drawer-4.4.3.tgz#2094937a844e55dc9644236a2d9fba79c344e321" + integrity sha512-FYztwRs3uXnFOIf1hLvFxIQP9MiZJA+0w+Os8dfDh/90X7z/HqP/Yg+noLCIeHEbKln1Tqelv8ymCAN24zPcfQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + rc-util "^5.7.0" + +rc-dropdown@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/rc-dropdown/-/rc-dropdown-3.2.0.tgz#da6c2ada403842baee3a9e909a0b1a91ba3e1090" + integrity sha512-j1HSw+/QqlhxyTEF6BArVZnTmezw2LnSmRk6I9W7BCqNCKaRwleRmMMs1PHbuaG8dKHVqP6e21RQ7vPBLVnnNw== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + rc-trigger "^5.0.4" + +rc-dropdown@~3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/rc-dropdown/-/rc-dropdown-3.2.5.tgz#c211e571d29d15e7f725b5a75fc8c7f371fc3348" + integrity sha512-dVO2eulOSbEf+F4OyhCY5iGiMVhUYY/qeXxL7Ex2jDBt/xc89jU07mNoowV6aWxwVOc70pxEINff0oM2ogjluA== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + rc-trigger "^5.0.4" + +rc-field-form@~1.22.0-2: + version "1.22.1" + resolved "https://registry.yarnpkg.com/rc-field-form/-/rc-field-form-1.22.1.tgz#0bd2f4e730ff2f071529d00bef28e062362890f5" + integrity sha512-LweU7nBeqmC5r3HDUjRprcOXXobHXp/TGIxD7ppBq5FX6Iptt3ibdpRVg4RSyNulBNGHOuknHlRcguuIpvVMVg== + dependencies: + "@babel/runtime" "^7.8.4" + async-validator "^4.0.2" + rc-util "^5.8.0" + +rc-image@~5.2.5: + version "5.2.5" + resolved "https://registry.yarnpkg.com/rc-image/-/rc-image-5.2.5.tgz#44e6ffc842626827960e7ab72e1c0d6f3a8ce440" + integrity sha512-qUfZjYIODxO0c8a8P5GeuclYXZjzW4hV/5hyo27XqSFo1DmTCs2HkVeQObkcIk5kNsJtgsj1KoPThVsSc/PXOw== + dependencies: + "@babel/runtime" "^7.11.2" + classnames "^2.2.6" + rc-dialog "~8.6.0" + rc-util "^5.0.6" + +rc-input-number@~7.3.0: + version "7.3.4" + resolved "https://registry.yarnpkg.com/rc-input-number/-/rc-input-number-7.3.4.tgz#674aea98260250287d36e330a7e065b174486e9d" + integrity sha512-W9uqSzuvJUnz8H8vsVY4kx+yK51SsAxNTwr8SNH4G3XqQNocLVmKIibKFRjocnYX1RDHMND9FFbgj2h7E7nvGA== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-util "^5.9.8" + +rc-mentions@~1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/rc-mentions/-/rc-mentions-1.6.1.tgz#46035027d64aa33ef840ba0fbd411871e34617ae" + integrity sha512-LDzGI8jJVGnkhpTZxZuYBhMz3avcZZqPGejikchh97xPni/g4ht714Flh7DVvuzHQ+BoKHhIjobHnw1rcP8erg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + rc-menu "^9.0.0" + rc-textarea "^0.3.0" + rc-trigger "^5.0.4" + rc-util "^5.0.1" + +rc-menu@^9.0.0: + version "9.1.1" + resolved "https://registry.yarnpkg.com/rc-menu/-/rc-menu-9.1.1.tgz#c44b9d8a9af6d1c26cf9cfeb9776b216bcee060d" + integrity sha512-yavNNsTgWOlUYwOrJtO8s1Hn0haUvc/x5ozx9KA/H0VspOksIFeWOp7lsEQ3juWyBI2VltDxWQ2DHc65OhZ5pg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.4.3" + rc-overflow "^1.2.0" + rc-trigger "^5.1.2" + rc-util "^5.12.0" + shallowequal "^1.1.0" + +rc-menu@~9.2.1: + version "9.2.1" + resolved "https://registry.yarnpkg.com/rc-menu/-/rc-menu-9.2.1.tgz#6fbe47f4846363bb81a5a21f0960026c3ada497a" + integrity sha512-UbEtn3rflJ8zS+etYGTVQuzy7Fm+yWXR5c0Rl6ecNTS/dPknRyWAyhJcbeR0Hu1+RdQT+0VCqrUPrgKnm4iY+w== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.4.3" + rc-overflow "^1.2.0" + rc-trigger "^5.1.2" + rc-util "^5.12.0" + shallowequal "^1.1.0" + +rc-motion@^2.0.0, rc-motion@^2.0.1, rc-motion@^2.2.0, rc-motion@^2.3.0, rc-motion@^2.3.4, rc-motion@^2.4.3, rc-motion@^2.4.4: + version "2.4.4" + resolved "https://registry.yarnpkg.com/rc-motion/-/rc-motion-2.4.4.tgz#e995d5fa24fc93065c24f714857cf2677d655bb0" + integrity sha512-ms7n1+/TZQBS0Ydd2Q5P4+wJTSOrhIrwNxLXCZpR7Fa3/oac7Yi803HDALc2hLAKaCTQtw9LmQeB58zcwOsqlQ== + dependencies: + "@babel/runtime" "^7.11.1" + classnames "^2.2.1" + rc-util "^5.2.1" + +rc-notification@~4.5.7: + version "4.5.7" + resolved "https://registry.yarnpkg.com/rc-notification/-/rc-notification-4.5.7.tgz#265e6e6a0c1a0fac63d6abd4d832eb8ff31522f1" + integrity sha512-zhTGUjBIItbx96SiRu3KVURcLOydLUHZCPpYEn1zvh+re//Tnq/wSxN4FKgp38n4HOgHSVxcLEeSxBMTeBBDdw== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.2.0" + rc-util "^5.0.1" + +rc-overflow@^1.0.0, rc-overflow@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/rc-overflow/-/rc-overflow-1.2.2.tgz#95b0222016c0cdbdc0db85f569c262e7706a5f22" + integrity sha512-X5kj9LDU1ue5wHkqvCprJWLKC+ZLs3p4He/oxjZ1Q4NKaqKBaYf5OdSzRSgh3WH8kSdrfU8LjvlbWnHgJOEkNQ== + dependencies: + "@babel/runtime" "^7.11.1" + classnames "^2.2.1" + rc-resize-observer "^1.0.0" + rc-util "^5.5.1" + +rc-pagination@~3.1.9: + version "3.1.15" + resolved "https://registry.yarnpkg.com/rc-pagination/-/rc-pagination-3.1.15.tgz#e05eddf4c15717a5858290bed0857e27e2f957ff" + integrity sha512-4L3fot8g4E+PjWEgoVGX0noFCg+8ZFZmeLH4vsnZpB3O2T2zThtakjNxG+YvSaYtyMVT4B+GLayjKrKbXQpdAg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + +rc-picker@~2.5.17: + version "2.5.19" + resolved "https://registry.yarnpkg.com/rc-picker/-/rc-picker-2.5.19.tgz#73d07546fac3992f0bfabf2789654acada39e46f" + integrity sha512-u6myoCu/qiQ0vLbNzSzNrzTQhs7mldArCpPHrEI6OUiifs+IPXmbesqSm0zilJjfzrZJLgYeyyOMSznSlh0GKA== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + date-fns "2.x" + dayjs "1.x" + moment "^2.24.0" + rc-trigger "^5.0.4" + rc-util "^5.4.0" + shallowequal "^1.1.0" + +rc-progress@~3.2.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/rc-progress/-/rc-progress-3.2.2.tgz#319afe140f7e25cde2c1378b236a76905b551cf1" + integrity sha512-hvYqiFxFQeDGzY8AuARqp4vEGSD54W0KMg8cCcLFyT2tRJnxQyND/9vyUzVMYuaHexou06QsvLoqyBc3BPDVbg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + rc-util "^5.16.1" + +rc-rate@~2.9.0: + version "2.9.1" + resolved "https://registry.yarnpkg.com/rc-rate/-/rc-rate-2.9.1.tgz#e43cb95c4eb90a2c1e0b16ec6614d8c43530a731" + integrity sha512-MmIU7FT8W4LYRRHJD1sgG366qKtSaKb67D0/vVvJYR0lrCuRrCiVQ5qhfT5ghVO4wuVIORGpZs7ZKaYu+KMUzA== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-util "^5.0.1" + +rc-resize-observer@^1.0.0, rc-resize-observer@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/rc-resize-observer/-/rc-resize-observer-1.1.2.tgz#214bc5d0de19e0a5fcd7d8352d9c1560dd7531b7" + integrity sha512-Qp+1x6D88FxyWBFRYP95IV9A1o0xlkC6qhiTX3YakE+o86QH9IzC7UVnltwmm4Q8uYH+E3F/HRmEiuxXJECdSw== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + rc-util "^5.15.0" + resize-observer-polyfill "^1.5.1" + +rc-resize-observer@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/rc-resize-observer/-/rc-resize-observer-1.2.0.tgz#9f46052f81cdf03498be35144cb7c53fd282c4c7" + integrity sha512-6W+UzT3PyDM0wVCEHfoW3qTHPTvbdSgiA43buiy8PzmeMnfgnDeb9NjdimMXMl3/TcrvvWl5RRVdp+NqcR47pQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + rc-util "^5.15.0" + resize-observer-polyfill "^1.5.1" + +rc-select@~14.0.0-alpha.15, rc-select@~14.0.0-alpha.8: + version "14.0.0-alpha.19" + resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-14.0.0-alpha.19.tgz#74196366a7769cf1932d426b0b805e7ac7899b65" + integrity sha512-It7e5bQHxkx7Y9ZiKjvLOm208aJYccsDBvUhWMRYtcYMXDrnoVPXdE8WLB+buzVCrjawcTxDv7ZK92ewuavG5A== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.0.1" + rc-overflow "^1.0.0" + rc-trigger "^5.0.4" + rc-util "^5.16.1" + rc-virtual-list "^3.2.0" + +rc-select@~14.0.0-alpha.23: + version "14.0.0-alpha.27" + resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-14.0.0-alpha.27.tgz#8d2a766245776db7632b82b0b6950fb5d955e362" + integrity sha512-vXf7i0+2PCYSLTFJhJAPPRSo5a2hVbSaaMqHryEH4omcqnx7XgfAtSlzN3vdMGxuEokibM6S2PrRRipVvLkBgg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.0.1" + rc-overflow "^1.0.0" + rc-trigger "^5.0.4" + rc-util "^5.16.1" + rc-virtual-list "^3.2.0" + +rc-slider@~9.7.4: + version "9.7.5" + resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-9.7.5.tgz#193141c68e99b1dc3b746daeb6bf852946f5b7f4" + integrity sha512-LV/MWcXFjco1epPbdw1JlLXlTgmWpB9/Y/P2yinf8Pg3wElHxA9uajN21lJiWtZjf5SCUekfSP6QMJfDo4t1hg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-tooltip "^5.0.1" + rc-util "^5.16.1" + shallowequal "^1.1.0" + +rc-steps@~4.1.0: + version "4.1.4" + resolved "https://registry.yarnpkg.com/rc-steps/-/rc-steps-4.1.4.tgz#0ba82db202d59ca52d0693dc9880dd145b19dc23" + integrity sha512-qoCqKZWSpkh/b03ASGx1WhpKnuZcRWmvuW+ZUu4mvMdfvFzVxblTwUM+9aBd0mlEUFmt6GW8FXhMpHkK3Uzp3w== + dependencies: + "@babel/runtime" "^7.10.2" + classnames "^2.2.3" + rc-util "^5.0.1" + +rc-switch@~3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/rc-switch/-/rc-switch-3.2.2.tgz#d001f77f12664d52595b4f6fb425dd9e66fba8e8" + integrity sha512-+gUJClsZZzvAHGy1vZfnwySxj+MjLlGRyXKXScrtCTcmiYNPzxDFOxdQ/3pK1Kt/0POvwJ/6ALOR8gwdXGhs+A== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + rc-util "^5.0.1" + +rc-table@~7.23.0: + version "7.23.0" + resolved "https://registry.yarnpkg.com/rc-table/-/rc-table-7.23.0.tgz#e5f76998ecf3246147d45ed311417c08886e6507" + integrity sha512-Q1gneB2+lUa8EzCCfbrq+jO1qNSwQv1RUUXKB84W/Stdp4EvGOt2+QqGyfotMNM4JUw0fgGLwY+WjnhUhnLuQQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-resize-observer "^1.1.0" + rc-util "^5.14.0" + shallowequal "^1.1.0" + +rc-tabs@~11.10.0: + version "11.10.5" + resolved "https://registry.yarnpkg.com/rc-tabs/-/rc-tabs-11.10.5.tgz#53bbb642d04b307f8ce86e318ab99d519507b29b" + integrity sha512-DDuUdV6b9zGRYLtjI5hyejWLKoz1QiLWNgMeBzc3aMeQylZFhTYnFGdDc6HRqj5IYearNTsFPVSA+6VIT8g5cg== + dependencies: + "@babel/runtime" "^7.11.2" + classnames "2.x" + rc-dropdown "^3.2.0" + rc-menu "^9.0.0" + rc-resize-observer "^1.0.0" + rc-util "^5.5.0" + +rc-textarea@^0.3.0, rc-textarea@~0.3.0: + version "0.3.7" + resolved "https://registry.yarnpkg.com/rc-textarea/-/rc-textarea-0.3.7.tgz#987142891efdedb774883c07e2f51b318fde5a11" + integrity sha512-yCdZ6binKmAQB13hc/oehh0E/QRwoPP1pjF21aHBxlgXO3RzPF6dUu4LG2R4FZ1zx/fQd2L1faktulrXOM/2rw== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + rc-resize-observer "^1.0.0" + rc-util "^5.7.0" + shallowequal "^1.1.0" + +rc-tooltip@^5.0.1, rc-tooltip@~5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/rc-tooltip/-/rc-tooltip-5.1.1.tgz#94178ed162d0252bc4993b725f5dc2ac0fccf154" + integrity sha512-alt8eGMJulio6+4/uDm7nvV+rJq9bsfxFDCI0ljPdbuoygUscbsMYb6EQgwib/uqsXQUvzk+S7A59uYHmEgmDA== + dependencies: + "@babel/runtime" "^7.11.2" + rc-trigger "^5.0.0" + +rc-tree-select@~5.1.1: + version "5.1.3" + resolved "https://registry.yarnpkg.com/rc-tree-select/-/rc-tree-select-5.1.3.tgz#492f76adec6b4f69beedb0ad59595cd79f671d62" + integrity sha512-nfOhsUM3SiEo/Kt+LhinC3LI3VJGCU4+TCRBAmdt0frV3Ix9GAoC3aIaHIUs2tkDf3X0qOmf6qYcyUn/RaIuoQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-select "~14.0.0-alpha.8" + rc-tree "~5.4.3" + rc-util "^5.16.1" + +rc-tree@~5.4.3: + version "5.4.3" + resolved "https://registry.yarnpkg.com/rc-tree/-/rc-tree-5.4.3.tgz#8674644964e17e5ab9b111c5aa18676f673e7bd0" + integrity sha512-WAHV8FkBerulj9J/+61+Qn0TD/Zo37PrDG8/45WomzGTYavxFMur9YguKjQj/J+NxjVJzrJL3lvdSZsumfdbiA== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.0.1" + rc-util "^5.16.1" + rc-virtual-list "^3.4.1" + +rc-trigger@^5.0.0, rc-trigger@^5.0.4, rc-trigger@^5.1.2, rc-trigger@^5.2.10: + version "5.2.10" + resolved "https://registry.yarnpkg.com/rc-trigger/-/rc-trigger-5.2.10.tgz#8a0057a940b1b9027eaa33beec8a6ecd85cce2b1" + integrity sha512-FkUf4H9BOFDaIwu42fvRycXMAvkttph9AlbCZXssZDVzz2L+QZ0ERvfB/4nX3ZFPh1Zd+uVGr1DEDeXxq4J1TA== + dependencies: + "@babel/runtime" "^7.11.2" + classnames "^2.2.6" + rc-align "^4.0.0" + rc-motion "^2.0.0" + rc-util "^5.5.0" + +rc-upload@~4.3.0: + version "4.3.3" + resolved "https://registry.yarnpkg.com/rc-upload/-/rc-upload-4.3.3.tgz#e237aa525e5313fa16f4d04d27f53c2f0e157bb8" + integrity sha512-YoJ0phCRenMj1nzwalXzciKZ9/FAaCrFu84dS5pphwucTC8GUWClcDID/WWNGsLFcM97NqIboDqrV82rVRhW/w== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-util "^5.2.0" + +rc-util@^5.0.1, rc-util@^5.0.6, rc-util@^5.0.7, rc-util@^5.12.0, rc-util@^5.14.0, rc-util@^5.15.0, rc-util@^5.16.1, rc-util@^5.2.0, rc-util@^5.2.1, rc-util@^5.3.0, rc-util@^5.4.0, rc-util@^5.5.0, rc-util@^5.5.1, rc-util@^5.6.1, rc-util@^5.7.0, rc-util@^5.8.0, rc-util@^5.9.4, rc-util@^5.9.8: + version "5.16.1" + resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.16.1.tgz#374db7cb735512f05165ddc3d6b2c61c21b8b4e3" + integrity sha512-kSCyytvdb3aRxQacS/71ta6c+kBWvM1v8/2h9d/HaNWauc3qB8pLnF20PJ8NajkNN8gb+rR1l0eWO+D4Pz+LLQ== + dependencies: + "@babel/runtime" "^7.12.5" + react-is "^16.12.0" + shallowequal "^1.1.0" + +rc-virtual-list@^3.2.0, rc-virtual-list@^3.4.1: + version "3.4.2" + resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.4.2.tgz#1078327aa7230b5e456d679ed2ce99f3c036ebd1" + integrity sha512-OyVrrPvvFcHvV0ssz5EDZ+7Rf5qLat/+mmujjchNw5FfbJWNDwkpQ99EcVE6+FtNRmX9wFa1LGNpZLUTvp/4GQ== + dependencies: + classnames "^2.2.6" + rc-resize-observer "^1.0.0" + rc-util "^5.0.7" + +react-color@^2.19.3: + version "2.19.3" + resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.19.3.tgz#ec6c6b4568312a3c6a18420ab0472e146aa5683d" + integrity sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA== + dependencies: + "@icons/material" "^0.2.4" + lodash "^4.17.15" + lodash-es "^4.17.15" + material-colors "^1.2.1" + prop-types "^15.5.10" + reactcss "^1.2.0" + tinycolor2 "^1.4.1" + +react-dom@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler "^0.20.2" + +react-github-button@^0.1.11: + version "0.1.11" + resolved "https://registry.yarnpkg.com/react-github-button/-/react-github-button-0.1.11.tgz#fc61e1f1e1371169d3618c1ba37306ba04081e56" + integrity sha1-/GHh8eE3EWnTYYwbo3MGugQIHlY= + dependencies: + prop-types "^15.5.10" + +react-i18next@^11.15.5: + version "11.15.5" + resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.15.5.tgz#3de940a1c5a27956d8265663ca67494881f385e8" + integrity sha512-vBWuVEQgrhZrGKpyv8FmJ7Zs5jRQWl794Tte7yzJ0okZqqi3jd6j2pLYNg441WcREsbIOvWdiDXbY7W6E93p1A== + dependencies: + "@babel/runtime" "^7.14.5" + html-escaper "^2.0.2" + html-parse-stringify "^3.0.1" + +react-icons@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.3.1.tgz#2fa92aebbbc71f43d2db2ed1aed07361124e91ca" + integrity sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ== + +react-id-swiper@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/react-id-swiper/-/react-id-swiper-4.0.0.tgz#eed938c5a4bf464a5cd7316a1bf6778581f47f2f" + integrity sha512-BFY8VQYgc1ECkT1Ek6MYSF8MADjWYZctdeRlMA202mjGcdjq1Bugfhg207KHTjGWKWZlY/7/nxFShqQo74RslA== + dependencies: + object-assign "^4.1.1" + +react-is@^16.12.0, react-is@^16.13.1, react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^17.0.0, react-is@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +react-leaflet@^3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/react-leaflet/-/react-leaflet-3.2.5.tgz#bec0bfab9dd8c2b030ea630f7a0687a60322ca7d" + integrity sha512-Z3KZ+4SijsRbbrt2I1a3ZDY6+V6Pm91eYTdxTN18G6IOkFRsJo1BuSPLFnyFrlF3WDjQFPEcTPkEgD1VEeAoBg== + dependencies: + "@react-leaflet/core" "^1.1.1" + +react-markdown@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.0.tgz#3243296a59ddb0f451d262cc2e11123674b416c2" + integrity sha512-qbrWpLny6Ef2xHqnYqtot948LXP+4FtC+MWIuaN1kvSnowM+r1qEeEHpSaU0TDBOisQuj+Qe6eFY15cNL3gLAw== + dependencies: + "@types/hast" "^2.0.0" + "@types/unist" "^2.0.0" + comma-separated-tokens "^2.0.0" + hast-util-whitespace "^2.0.0" + prop-types "^15.0.0" + property-information "^6.0.0" + react-is "^17.0.0" + remark-parse "^10.0.0" + remark-rehype "^10.0.0" + space-separated-tokens "^2.0.0" + style-to-object "^0.3.0" + unified "^10.0.0" + unist-util-visit "^4.0.0" + vfile "^5.0.0" + +react-redux@^7.2.6: + version "7.2.6" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.6.tgz#49633a24fe552b5f9caf58feb8a138936ddfe9aa" + integrity sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ== + dependencies: + "@babel/runtime" "^7.15.4" + "@types/react-redux" "^7.1.20" + hoist-non-react-statics "^3.3.2" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-is "^17.0.2" + +react@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +reactcss@^1.2.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd" + integrity sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A== + dependencies: + lodash "^4.0.1" + +readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdir-glob@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.1.tgz#f0e10bb7bf7bfa7e0add8baffdc54c3f7dbee6c4" + integrity sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA== + dependencies: + minimatch "^3.0.4" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +redux-devtools-extension@^2.13.9: + version "2.13.9" + resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.9.tgz#6b764e8028b507adcb75a1cae790f71e6be08ae7" + integrity sha512-cNJ8Q/EtjhQaZ71c8I9+BPySIBVEKssbPpskBfsXqb8HJ002A3KRVHfeRzwRo6mGPqsm7XuHTqNSNeS1Khig0A== + +redux-thunk@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.1.tgz#0dd8042cf47868f4b29699941de03c9301a75714" + integrity sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q== + +redux@^4.0.0, redux@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.2.tgz#140f35426d99bb4729af760afcf79eaaac407104" + integrity sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw== + dependencies: + "@babel/runtime" "^7.9.2" + +regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexp.prototype.flags@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" + integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +remark-parse@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-10.0.1.tgz#6f60ae53edbf0cf38ea223fe643db64d112e0775" + integrity sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-from-markdown "^1.0.0" + unified "^10.0.0" + +remark-rehype@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-10.1.0.tgz#32dc99d2034c27ecaf2e0150d22a6dcccd9a6279" + integrity sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw== + dependencies: + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + mdast-util-to-hast "^12.1.0" + unified "^10.0.0" + +repeat-element@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +replace-ext@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a" + integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw== + +resize-observer-polyfill@^1.5.0, resize-observer-polyfill@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" + integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@^2.0.0-next.3: + version "2.0.0-next.3" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.3.tgz#d41016293d4a8586a39ca5d9b5f15cbea1f55e46" + integrity sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +responselike@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= + dependencies: + lowercase-keys "^1.0.0" + +responsive-loader@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/responsive-loader/-/responsive-loader-2.3.0.tgz#3123b6db1dd8aeee37c4d7805e3f45d2e8f5edc1" + integrity sha512-8GyyasTKdOfTMDvYy/mBpyV2EM7hz7zWoKdxpocA60eX1jM2udsb+ji03haZWeGnTkQvOplXVqHsev9952dWng== + dependencies: + loader-utils "^2.0.0" + schema-utils "^3.0.0" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@2, rimraf@^2.5.4: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +sade@^1.7.3: + version "1.8.0" + resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.0.tgz#c9905381e236953a635450803633902095e8ec36" + integrity sha512-NRfCA8AVYuAA7Hu8bs18od6J4BdcXXwOv6OJuNgwbw8LcLK8JKwaM3WckLZ+MGyPJUS/ivVgK3twltrOIJJnug== + dependencies: + mri "^1.1.0" + +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +sass@^1.49.9: + version "1.49.9" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.49.9.tgz#b15a189ecb0ca9e24634bae5d1ebc191809712f9" + integrity sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A== + dependencies: + chokidar ">=3.0.0 <4.0.0" + immutable "^4.0.0" + source-map-js ">=0.6.2 <2.0.0" + +sax@>=0.6.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + +scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +schema-utils@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +scroll-into-view-if-needed@^2.2.25: + version "2.2.28" + resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.28.tgz#5a15b2f58a52642c88c8eca584644e01703d645a" + integrity sha512-8LuxJSuFVc92+0AdNv4QOxRL4Abeo1DgLnGNkn1XlaujPH/3cCFz3QI60r2VNu4obJJROzgnIUw5TKQkZvZI1w== + dependencies: + compute-scroll-into-view "^1.0.17" + +seedrandom@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.5.tgz#54edc85c95222525b0c7a6f6b3543d8e0b3aa0a7" + integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg== + +seek-bzip@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4" + integrity sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ== + dependencies: + commander "^2.8.1" + +semver-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-2.0.0.tgz#a93c2c5844539a770233379107b38c7b4ac9d338" + integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw== + +semver-truncate@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/semver-truncate/-/semver-truncate-1.1.2.tgz#57f41de69707a62709a7e0104ba2117109ea47e8" + integrity sha1-V/Qd5pcHpicJp+AQS6IRcQnqR+g= + dependencies: + semver "^5.3.0" + +semver@^5.3.0, semver@^5.5.0, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +set-immediate-shim@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E= + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@~1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +shallowequal@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" + integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.0: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +sort-keys-length@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188" + integrity sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg= + dependencies: + sort-keys "^1.0.0" + +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0= + dependencies: + is-plain-obj "^1.0.0" + +sort-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" + integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= + dependencies: + is-plain-obj "^1.0.0" + +"source-map-js@>=0.6.2 <2.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf" + integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA== + +source-map-js@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-url@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== + +source-map@^0.5.0, source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +space-separated-tokens@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.1.tgz#43193cec4fb858a2ce934b7f98b7f2c18107098b" + integrity sha512-ekwEbFp5aqSPKaqeY1PGrlGQxPNaq+Cnx4+bE2D8sciBQrHpbwoBbawqTN2+6jPs9IdWxxiUcN0K2pkczD3zmw== + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +ssr-window@^4.0.0, ssr-window@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/ssr-window/-/ssr-window-4.0.2.tgz#dc6b3ee37be86ac0e3ddc60030f7b3bc9b8553be" + integrity sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ== + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= + +string-convert@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97" + integrity sha1-aYLMMEn7tM2F+LJFaLnZvznu/5c= + +string.prototype.matchall@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" + integrity sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + regexp.prototype.flags "^1.3.1" + side-channel "^1.0.4" + +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-dirs@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" + integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g== + dependencies: + is-natural-number "^4.0.1" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strip-outer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" + integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg== + dependencies: + escape-string-regexp "^1.0.2" + +style-to-object@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46" + integrity sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA== + dependencies: + inline-style-parser "0.1.1" + +styled-components@^5.3.3: + version "5.3.3" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.3.tgz#312a3d9a549f4708f0fb0edc829eb34bde032743" + integrity sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/traverse" "^7.4.5" + "@emotion/is-prop-valid" "^0.8.8" + "@emotion/stylis" "^0.8.4" + "@emotion/unitless" "^0.7.4" + babel-plugin-styled-components ">= 1.12.0" + css-to-react-native "^3.0.0" + hoist-non-react-statics "^3.0.0" + shallowequal "^1.1.0" + supports-color "^5.5.0" + +styled-jsx@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.0.tgz#816b4b92e07b1786c6b7111821750e0ba4d26e77" + integrity sha512-qUqsWoBquEdERe10EW8vLp3jT25s/ssG1/qX5gZ4wu15OZpmSMFI2v+fWlRhLfykA5rFtlJ1ME8A8pm/peV4WA== + +supports-color@^5.3.0, supports-color@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +swiper@*: + version "7.4.1" + resolved "https://registry.yarnpkg.com/swiper/-/swiper-7.4.1.tgz#99fc586d1335b45250d2c6b3128dc91f8047d3e7" + integrity sha512-dhbL4tpYFvHug1J7GnKElfTi6EYhlZy/vNZRhHkWFyUsWZ1Vovipxj3la5gqllMogygXJMe3zvVv+f6eppvWiA== + dependencies: + dom7 "^4.0.2" + ssr-window "^4.0.2" + +swiper@^8.0.6: + version "8.0.6" + resolved "https://registry.yarnpkg.com/swiper/-/swiper-8.0.6.tgz#3996d3212cb73b93e9f274e18ea58c029340c7c7" + integrity sha512-Ssyu1+FeNATF/G8e84QG+ZUNtUOAZ5vngdgxzczh0oWZPhGUVgkdv+BoePUuaCXLAFXnwVpNjgLIcGnxMdmWPA== + dependencies: + dom7 "^4.0.4" + ssr-window "^4.0.2" + +symbol-observable@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" + integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== + +tar-stream@^1.5.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== + dependencies: + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" + +tar-stream@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + +temp-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" + integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= + +tempfile@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tempfile/-/tempfile-2.0.0.tgz#6b0446856a9b1114d1856ffcbe509cccb0977265" + integrity sha1-awRGhWqbERTRhW/8vlCczLCXcmU= + dependencies: + temp-dir "^1.0.0" + uuid "^3.0.1" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +timed-out@^4.0.0, timed-out@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= + +timm@^1.6.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/timm/-/timm-1.7.1.tgz#96bab60c7d45b5a10a8a4d0f0117c6b7e5aff76f" + integrity sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw== + +tiny-emitter@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" + integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== + +tinycolor2@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803" + integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA== + +tmp@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toggle-selection@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" + integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI= + +totalist@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/totalist/-/totalist-2.0.0.tgz#db6f1e19c0fa63e71339bbb8fba89653c18c7eec" + integrity sha512-+Y17F0YzxfACxTyjfhnJQEe7afPA0GSpYlFkl2VFMxYP7jshQf9gXV7cH47EfToBumFThfKBvfAcoUn6fdNeRQ== + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + +"traverse@>=0.3.0 <0.4": + version "0.3.9" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" + integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk= + +trim-repeated@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" + integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE= + dependencies: + escape-string-regexp "^1.0.2" + +trough@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/trough/-/trough-2.0.2.tgz#94a3aa9d5ce379fc561f6244905b3f36b7458d96" + integrity sha512-FnHq5sTMxC0sk957wHDzRnemFnNBvt/gSY99HzK8F7UP5WAbvP70yX5bd7CjEQkN+TjdxwI7g7lJ6podqrG2/w== + +ts-invariant@^0.9.4: + version "0.9.4" + resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.9.4.tgz#42ac6c791aade267dd9dc65276549df5c5d71cac" + integrity sha512-63jtX/ZSwnUNi/WhXjnK8kz4cHHpYS60AnmA6ixz17l7E12a5puCWFlNpkne5Rl0J8TBPVHpGjsj4fxs8ObVLQ== + dependencies: + tslib "^2.1.0" + +ts-node@^10.5.0: + version "10.5.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.5.0.tgz#618bef5854c1fbbedf5e31465cbb224a1d524ef9" + integrity sha512-6kEJKwVxAJ35W4akuiysfKwKmjkbYxwQMTBaAxo9KKAx/Yd26mPUyhGz3ji+EsJoAgrLqVsYHNuuYwQe22lbtw== + dependencies: + "@cspotcode/source-map-support" "0.7.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.0" + yn "3.1.1" + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.1.0, tslib@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +typed-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/typed-function/-/typed-function-2.0.0.tgz#15ab3825845138a8b1113bd89e60cd6a435739e8" + integrity sha512-Hhy1Iwo/e4AtLZNK10ewVVcP2UEs408DS35ubP825w/YgSBK1KVLwALvvIG4yX75QJrxjCpcWkzkVRB0BwwYlA== + +typescript@^4.5.5: + version "4.5.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3" + integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== + +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + +unbzip2-stream@^1.0.9: + version "1.4.3" + resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" + integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== + dependencies: + buffer "^5.2.1" + through "^2.3.8" + +unified@^10.0.0: + version "10.1.1" + resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.1.tgz#345e349e3ab353ab612878338eb9d57b4dea1d46" + integrity sha512-v4ky1+6BN9X3pQrOdkFIPWAaeDsHPE1svRDxq7YpTc2plkIqFMwukfqM+l0ewpP9EfwARlt9pPFAeWYhHm8X9w== + dependencies: + "@types/unist" "^2.0.0" + bail "^2.0.0" + extend "^3.0.0" + is-buffer "^2.0.0" + is-plain-obj "^4.0.0" + trough "^2.0.0" + vfile "^5.0.0" + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +unist-builder@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-3.0.0.tgz#728baca4767c0e784e1e64bb44b5a5a753021a04" + integrity sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ== + dependencies: + "@types/unist" "^2.0.0" + +unist-util-generated@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-2.0.0.tgz#86fafb77eb6ce9bfa6b663c3f5ad4f8e56a60113" + integrity sha512-TiWE6DVtVe7Ye2QxOVW9kqybs6cZexNwTwSMVgkfjEReqy/xwGpAXb99OxktoWwmL+Z+Epb0Dn8/GNDYP1wnUw== + +unist-util-is@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-5.1.1.tgz#e8aece0b102fa9bc097b0fef8f870c496d4a6236" + integrity sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ== + +unist-util-position@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-4.0.1.tgz#f8484b2da19a897a0180556d160c28633070dbb9" + integrity sha512-mgy/zI9fQ2HlbOtTdr2w9lhVaiFUHWQnZrFF2EUoVOqtAUdzqMtNiD99qA5a1IcjWVR8O6aVYE9u7Z2z1v0SQA== + +unist-util-stringify-position@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-3.0.0.tgz#d517d2883d74d0daa0b565adc3d10a02b4a8cde9" + integrity sha512-SdfAl8fsDclywZpfMDTVDxA2V7LjtRDTOFd44wUJamgl6OlVngsqWjxvermMYf60elWHbxhuRCZml7AnuXCaSA== + dependencies: + "@types/unist" "^2.0.0" + +unist-util-visit-parents@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-4.1.1.tgz#e83559a4ad7e6048a46b1bdb22614f2f3f4724f2" + integrity sha512-1xAFJXAKpnnJl8G7K5KgU7FY55y3GcLIXqkzUj5QF/QVP7biUm0K0O2oqVkYsdjzJKifYeWn9+o6piAK2hGSHw== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + +unist-util-visit-parents@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-5.1.0.tgz#44bbc5d25f2411e7dfc5cecff12de43296aa8521" + integrity sha512-y+QVLcY5eR/YVpqDsLf/xh9R3Q2Y4HxkZTp7ViLDU6WtJCEcPmRzW1gpdWDCDIqIlhuPDXOgttqPlykrHYDekg== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + +unist-util-visit@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-3.1.0.tgz#9420d285e1aee938c7d9acbafc8e160186dbaf7b" + integrity sha512-Szoh+R/Ll68QWAyQyZZpQzZQm2UPbxibDvaY8Xc9SUtYgPsDzx5AWSk++UUt2hJuow8mvwR+rG+LQLw+KsuAKA== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + unist-util-visit-parents "^4.0.0" + +unist-util-visit@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-4.1.0.tgz#f41e407a9e94da31594e6b1c9811c51ab0b3d8f5" + integrity sha512-n7lyhFKJfVZ9MnKtqbsqkQEk5P1KShj0+//V7mAcoI6bpbUjh3C/OG8HVD+pBihfh6Ovl01m8dkcv9HNqYajmQ== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + unist-util-visit-parents "^5.0.0" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +unzipper@^0.10.11: + version "0.10.11" + resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.10.11.tgz#0b4991446472cbdb92ee7403909f26c2419c782e" + integrity sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw== + dependencies: + big-integer "^1.6.17" + binary "~0.3.0" + bluebird "~3.4.1" + buffer-indexof-polyfill "~1.0.0" + duplexer2 "~0.1.4" + fstream "^1.0.12" + graceful-fs "^4.2.2" + listenercount "~1.0.1" + readable-stream "~2.3.6" + setimmediate "~1.0.4" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url-loader@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-1.1.2.tgz#b971d191b83af693c5e3fea4064be9e1f2d7f8d8" + integrity sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg== + dependencies: + loader-utils "^1.1.0" + mime "^2.0.3" + schema-utils "^1.0.0" + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= + dependencies: + prepend-http "^1.0.1" + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= + dependencies: + prepend-http "^2.0.0" + +url-to-options@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= + +use-subscription@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1" + integrity sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA== + dependencies: + object-assign "^4.1.1" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +utif@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/utif/-/utif-2.0.1.tgz#9e1582d9bbd20011a6588548ed3266298e711759" + integrity sha512-Z/S1fNKCicQTf375lIP9G8Sa1H/phcysstNrrSdZKj1f9g58J4NMgb5IgiEZN9/nLMPDwF0W7hdOe9Qq2IYoLg== + dependencies: + pako "^1.0.5" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +uuid@^3.0.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +uuid@^8.3.0: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +uvu@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.2.tgz#c145e7f4b5becf80099cf22fd8a4a05f0112b2c0" + integrity sha512-m2hLe7I2eROhh+tm3WE5cTo/Cv3WQA7Oc9f7JB6uWv+/zVKvfAm53bMyOoGOSZeQ7Ov2Fu9pLhFr7p07bnT20w== + dependencies: + dequal "^2.0.0" + diff "^5.0.0" + kleur "^4.0.3" + sade "^1.7.3" + totalist "^2.0.0" + +v8-compile-cache-lib@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz#0582bcb1c74f3a2ee46487ceecf372e46bce53e8" + integrity sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA== + +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +vfile-message@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-3.1.0.tgz#5437035aa43185ff4b9210d32fada6c640e59143" + integrity sha512-4QJbBk+DkPEhBXq3f260xSaWtjE4gPKOfulzfMFF8ZNwaPZieWsg3iVlcmF04+eebzpcpeXOOFMfrYzJHVYg+g== + dependencies: + "@types/unist" "^2.0.0" + unist-util-stringify-position "^3.0.0" + +vfile@^5.0.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-5.2.1.tgz#9278072d576e320917204a3291eec0b346c4ed5d" + integrity sha512-vXW5XKbELM6mLj88kmkJ+gjFGZ/2gTmpdqPDjs3y+qbvI5i7md7rba/+pbYEawa7t22W7ynywPV6lUUAS1WiYg== + dependencies: + "@types/unist" "^2.0.0" + is-buffer "^2.0.0" + unist-util-stringify-position "^3.0.0" + vfile-message "^3.0.0" + +void-elements@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" + integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk= + +web-streams-polyfill@^3.0.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz#a6b74026b38e4885869fb5c589e90b95ccfc7965" + integrity sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + +whatwg-fetch@^3.4.1: + version "3.6.2" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" + integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +xhr@^2.0.1: + version "2.6.0" + resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d" + integrity sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA== + dependencies: + global "~4.4.0" + is-function "^1.0.1" + parse-headers "^2.0.0" + xtend "^4.0.0" + +xml-parse-from-string@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28" + integrity sha1-qQKekp09vN7RafPG4oI42VpdWig= + +xml2js@^0.4.5: + version "0.4.23" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" + integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yauzl@^2.4.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +zen-observable-ts@^1.2.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.2.3.tgz#c2f5ccebe812faf0cfcde547e6004f65b1a6d769" + integrity sha512-hc/TGiPkAWpByykMwDcem3SdUgA4We+0Qb36bItSuJC9xD0XVBZoFHYoadAomDSNf64CG8Ydj0Qb8Od8BUWz5g== + dependencies: + zen-observable "0.8.15" + +zen-observable@0.8.15: + version "0.8.15" + resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" + integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== + +zip-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.0.tgz#51dd326571544e36aa3f756430b313576dc8fc79" + integrity sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A== + dependencies: + archiver-utils "^2.1.0" + compress-commons "^4.1.0" + readable-stream "^3.6.0"