Full Code of ijemmao/igbo_api for AI

master 15227552784b cached
441 files
17.4 MB
4.6M tokens
449 symbols
1 requests
Copy disabled (too large) Download .txt
Showing preview only (18,998K chars total). Download the full file to get everything.
Repository: ijemmao/igbo_api
Branch: master
Commit: 15227552784b
Files: 441
Total size: 17.4 MB

Directory structure:
gitextract_on7951nt/

├── .dockerignore
├── .eslintignore
├── .github/
│   ├── CODE_OF_CONDUCT.md
│   ├── CONTRIBUTING.md
│   ├── FIREBASE_CONFIG.md
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   ├── doc_issue.md
│   │   └── feature_request.md
│   ├── pull_request_template.md
│   └── workflows/
│       ├── deploy.yml
│       ├── dockerize.yml
│       ├── integration.yml
│       ├── lint.yml
│       └── release.yml
├── .gitignore
├── .npmrc
├── .prettierignore
├── .prettierrc.json
├── .releaserc
├── @types/
│   ├── bcrypt.d.ts
│   ├── body-parser.d.ts
│   ├── compression.d.ts
│   ├── console.d.ts
│   ├── diacriticless.d.ts
│   ├── environment.d.ts
│   ├── express-rate-limit.d.ts
│   ├── is-word.d.ts
│   ├── morgan.d.ts
│   ├── react-scroll.d.ts
│   ├── shelljs.d.ts
│   ├── string-similarity.d.ts
│   ├── supertest.d.ts
│   └── uuid.d.ts
├── Dockerfile
├── LICENSE.md
├── README.md
├── __mocks__/
│   ├── @chakra-ui/
│   │   └── react.tsx
│   ├── @sendgrid/
│   │   └── mail.ts
│   ├── axios.ts
│   ├── bcrypt.ts
│   ├── firebase/
│   │   ├── app.ts
│   │   ├── auth.ts
│   │   └── functions.ts
│   ├── firebase-admin.ts
│   ├── firebase-functions/
│   │   └── v1.ts
│   ├── i18next.ts
│   ├── mongoose.ts
│   ├── next/
│   │   ├── font/
│   │   │   └── google.ts
│   │   └── router.ts
│   ├── react-firebase-hooks/
│   │   └── auth.ts
│   ├── shelljs.ts
│   ├── stripe.ts
│   └── uuid.ts
├── __tests__/
│   ├── __mocks__/
│   │   ├── data.mock.json
│   │   ├── documentData.ts
│   │   └── genericWords.mock.json
│   ├── api-json.test.ts
│   ├── api-mongo.test.ts
│   ├── developers.test.ts
│   ├── examples.test.ts
│   ├── nsibidi_characters.test.ts
│   ├── parse.test.ts
│   ├── shared/
│   │   ├── commands.ts
│   │   ├── constants.ts
│   │   ├── uiFixtures.ts
│   │   └── utils.ts
│   └── stripe.test.ts
├── commitlint.config.js
├── cypress/
│   ├── e2e/
│   │   └── client.cy.js
│   ├── fixtures/
│   │   └── example.json
│   ├── plugins/
│   │   └── index.js
│   └── support/
│       ├── commands.js
│       └── e2e.js
├── cypress.config.js
├── docker-compose.yml
├── env.d.ts
├── eslint.config.mjs
├── firebase.json
├── functions/
│   ├── .gitignore
│   ├── index.js
│   ├── next-i18next.config.js
│   ├── next.config.js
│   ├── package.json
│   ├── postcss.config.js
│   └── tailwind.config.js
├── jest.backend.config.ts
├── jest.backend.database.config.ts
├── jest.frontend.config.ts
├── migrate-mongo-config.js
├── migrations/
│   ├── 20201106045436-add-suggestion-properties.js
│   ├── 20201108164925-add-exampleForWordSuggestion-field.js
│   ├── 20201109083748-remove-examples-from-words.js
│   ├── 20201118192335-add-merged-by.js
│   ├── 20201121195224-add-updated-on-for-words-and-examples.js
│   ├── 20201206042142-add-accented-field.js
│   ├── 20201213020925-uid-fields-on-suggestions.js
│   ├── 20210225022115-create-dialects.js
│   ├── 20210225235148-update-variations-to-array.js
│   ├── 20210306224633-add-dialects-for-word-suggestions-and-generic-words.js
│   ├── 20210325194345-add-central-igbo.js
│   ├── 20210331134705-remove-developer-origin.js
│   ├── 20210426171953-remove-normalized-field.js
│   ├── 20210814210437-pre-populate-dialects.js
│   ├── 20210820170937-merge-accented-and-word.js
│   ├── 20210820175620-merge-accented-and-example.js
│   ├── 20210822145619-change-central-to-standard.js
│   ├── 20210831163032-add-is-complete-word.js
│   ├── 20210903175644-remove-is-complete-word.js
│   ├── 20211030133331-add-active-and-passive-verbs.js
│   ├── 20211121214701-add-nyms.js
│   ├── 20211218192401-add-isComplete.js
│   ├── 20220107155512-add-nsibidi.js
│   ├── 20220125175808-restructure-dialects.js
│   ├── 20220208140327-example-pronunciations.js
│   ├── 20220216030851-remove-verb-prefixes.js
│   ├── 20220301211505-convert-unix-to-iso.js
│   ├── 20220308132126-add-is-accented.js
│   ├── 20220406005107-add-tenses.js
│   ├── 20220423222134-add-attributes.js
│   ├── 20220425130741-extend-example-sentences-with-style-and-meaning.js
│   ├── 20220808024209-add-borrowed-term-field.js
│   ├── 20220808033804-add-tags.js
│   ├── 20220808042906-replace-nyms-for-related-terms.js
│   ├── 20221014123241-add-is-stem.js
│   ├── 20221030034746-restructure-definitions.js
│   ├── 20221030054330-connect-example-associated-definitions.js
│   ├── 20221107022314-resturcture-dialects-as-arrays.js
│   ├── 20221124200346-expand-headword.js
│   ├── 20221207003231-nominal-modifier.js
│   ├── 20221217204603-definitions-with-nsibidi.js
│   ├── 20230112035359-add-is-common.js
│   ├── 20230118013604-convert-stems-to-object-id.js
│   ├── 20230201191800-convert-medial-to-active.js
│   ├── 20230201193438-add-present-passive-to-verbs.js
│   ├── 20230314160556-convert-frequency-to-number.js
│   ├── 20230409220217-convert-igbo-definitions-to-include-nsibidi.js
│   ├── 20230522011130-pronunciation-to-pronunciations.js
│   ├── 20230526231511-example-suggestions-approvals-denials-review.js
│   ├── 20230607004329-trim-headword-and-tenses-whitespace-fix.js
│   ├── 20240908000598-create-default-igbo-api-project.js
│   ├── 20240908000599-change-source-to-origin.js
│   ├── 20240908000600-generalize-examples.js
│   ├── 20240908162526-assign-projectid-to-each-collection.js
│   ├── 20240913215339-move-example-pronunciations-to-translations.js
│   ├── 20240928023848-add-languages-to-corpus.js
│   ├── 20240928024053-add-types-to-projecs.js
│   ├── 20241116014146-add-bit-rate-audio-pronunciation.js
│   ├── 20241203060241-insert-owner-firebase-id-on-project.js
│   ├── 20241203060300-connect-paywall-to-project.js
│   ├── 20241206235108-remove-crowdsourcing.js
│   ├── 20250212184340-add-viewableSectionIds-to-example-suggestions.js
│   └── 20250417110353-migrate-igbo-speech-example-suggestions.js
├── next-env.d.ts
├── next-i18next.config.js
├── next.config.js
├── package.json
├── postcss.config.js
├── public/
│   └── .hosting
├── script.js
├── src/
│   ├── APIs/
│   │   ├── FlagsAPI.ts
│   │   ├── RedisAPI.ts
│   │   └── __tests__/
│   │       └── FlagsAPI.test.ts
│   ├── __data__/
│   │   └── assetStub.ts
│   ├── __tests__/
│   │   ├── Card/
│   │   │   └── Card.test.tsx
│   │   ├── Demo/
│   │   │   └── Demo.test.tsx
│   │   ├── FadeIn/
│   │   │   └── FadeIn.test.tsx
│   │   ├── Input/
│   │   │   └── Input.test.tsx
│   │   ├── Statistics/
│   │   │   ├── Stat.test.tsx
│   │   │   └── Statistics.test.tsx
│   │   ├── components/
│   │   │   └── TestContext.tsx
│   │   └── shared/
│   │       ├── fixtures.ts
│   │       └── script.ts
│   ├── app.ts
│   ├── config.ts
│   ├── controllers/
│   │   ├── __tests__/
│   │   │   ├── developers.test.ts
│   │   │   ├── examples.test.ts
│   │   │   ├── speechToText.test.ts
│   │   │   ├── stripe.test.ts
│   │   │   └── translation.test.ts
│   │   ├── developers.ts
│   │   ├── email.ts
│   │   ├── examples.ts
│   │   ├── nsibidi.ts
│   │   ├── speechToText.ts
│   │   ├── stats.ts
│   │   ├── stripe/
│   │   │   ├── __mocks__/
│   │   │   │   └── webhooks.ts
│   │   │   ├── __tests__/
│   │   │   │   └── index.test.ts
│   │   │   ├── index.ts
│   │   │   └── webhooks.ts
│   │   ├── translation.ts
│   │   ├── types.ts
│   │   ├── utils/
│   │   │   ├── __mocks__/
│   │   │   │   └── fetchBase64Data.ts
│   │   │   ├── __tests__/
│   │   │   │   ├── minimizeVerbsAndSuffixes.test.ts
│   │   │   │   ├── parseAWS.test.ts
│   │   │   │   └── queries.test.ts
│   │   │   ├── buildDocs.ts
│   │   │   ├── convertToSkipAndLimit.ts
│   │   │   ├── fetchBase64Data.ts
│   │   │   ├── index.ts
│   │   │   ├── minimizeVerbsAndSuffixes.ts
│   │   │   ├── minimizeWords.ts
│   │   │   ├── parseAWS.ts
│   │   │   ├── parseRange.ts
│   │   │   ├── queries.ts
│   │   │   ├── searchWordUsingEnglish.ts
│   │   │   ├── searchWordUsingIgbo.ts
│   │   │   ├── sortDocsBy.ts
│   │   │   └── types.ts
│   │   └── words.ts
│   ├── dictionaries/
│   │   ├── buildDictionaries.ts
│   │   ├── en-ig/
│   │   │   └── en-ig_normalized_expanded.json
│   │   ├── ig-en/
│   │   │   ├── ig-en.json
│   │   │   ├── ig-en_1000_common.json
│   │   │   ├── ig-en_expanded.json
│   │   │   └── ig-en_normalized_expanded.json
│   │   ├── nsibidi/
│   │   │   └── nsibidi_dictionary.ts
│   │   └── seed.ts
│   ├── functions/
│   │   └── __tests__/
│   │       └── functions.test.ts
│   ├── functions.ts
│   ├── general.css
│   ├── lib/
│   │   └── gtag.js
│   ├── middleware/
│   │   ├── __tests__/
│   │   │   ├── authorizeCheckoutSession.test.ts
│   │   │   ├── authorizePortalSession.test.ts
│   │   │   └── developerAuthorization.test.ts
│   │   ├── analytics.ts
│   │   ├── attachRedisClient.ts
│   │   ├── authorizeCheckoutSession.ts
│   │   ├── authorizePortalSession.ts
│   │   ├── cache.ts
│   │   ├── developerAuthorization.ts
│   │   ├── errorHandler.ts
│   │   ├── helpers/
│   │   │   ├── __tests__/
│   │   │   │   ├── authorizeDeveloperUsage.test.ts
│   │   │   │   ├── createDeveloperUsage.test.ts
│   │   │   │   └── findDeveloperUsage.test.ts
│   │   │   ├── authorizeDeveloperUsage.ts
│   │   │   ├── createDeveloperUsage.ts
│   │   │   ├── findDeveloper.ts
│   │   │   └── findDeveloperUsage.ts
│   │   ├── logger.ts
│   │   ├── noCache.ts
│   │   ├── validId.ts
│   │   ├── validateAdminApiKey.ts
│   │   ├── validateApiKey.ts
│   │   ├── validateDeveloperBody.ts
│   │   ├── validateStripeSignature.ts
│   │   └── validateUpdateDeveloperBody.ts
│   ├── models/
│   │   ├── Developer.ts
│   │   ├── DeveloperUsage.ts
│   │   ├── Example.ts
│   │   ├── NsibidiCharacter.ts
│   │   ├── Stat.ts
│   │   ├── Word.ts
│   │   └── plugins/
│   │       └── index.ts
│   ├── pages/
│   │   ├── 404/
│   │   │   └── index.page.tsx
│   │   ├── APIs/
│   │   │   ├── DevelopersAPI.ts
│   │   │   ├── PredictionAPI.ts
│   │   │   ├── __mocks__/
│   │   │   │   └── DevelopersAPI.ts
│   │   │   └── __tests__/
│   │   │       ├── DevelopersAPI.test.tsx
│   │   │       └── PredictionAPI.test.tsx
│   │   ├── App.tsx
│   │   ├── __tests__/
│   │   │   └── App.test.tsx
│   │   ├── _app.page.tsx
│   │   ├── _document.page.tsx
│   │   ├── about/
│   │   │   └── index.page.tsx
│   │   ├── assets/
│   │   │   └── favicon/
│   │   │       └── site.webmanifest
│   │   ├── atoms/
│   │   │   ├── audioAtoms.ts
│   │   │   ├── dashboardAtoms.ts
│   │   │   ├── feedbackAtoms.ts
│   │   │   ├── index.ts
│   │   │   └── predictionAtoms.ts
│   │   ├── components/
│   │   │   ├── CallToAction/
│   │   │   │   ├── CallToAction.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Card/
│   │   │   │   ├── Card.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Demo/
│   │   │   │   ├── Demo.tsx
│   │   │   │   ├── components/
│   │   │   │   │   ├── IgboAPI.tsx
│   │   │   │   │   ├── IgboSpeech/
│   │   │   │   │   │   ├── components/
│   │   │   │   │   │   │   ├── AudioOptions/
│   │   │   │   │   │   │   │   ├── AudioOption.tsx
│   │   │   │   │   │   │   │   └── index.tsx
│   │   │   │   │   │   │   ├── AudioPlayer/
│   │   │   │   │   │   │   │   ├── AudioPlayerBase.tsx
│   │   │   │   │   │   │   │   ├── RecordButton.tsx
│   │   │   │   │   │   │   │   ├── UploadButton.tsx
│   │   │   │   │   │   │   │   └── index.tsx
│   │   │   │   │   │   │   ├── ConvertToTextButton.tsx
│   │   │   │   │   │   │   ├── DragState.tsx
│   │   │   │   │   │   │   ├── ResultText.tsx
│   │   │   │   │   │   │   └── ValidAudioType.ts
│   │   │   │   │   │   └── index.tsx
│   │   │   │   │   ├── StartBuilding.tsx
│   │   │   │   │   └── Translate.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Donate/
│   │   │   │   ├── Donate.tsx
│   │   │   │   └── index.ts
│   │   │   ├── FadeIn/
│   │   │   │   ├── FadeIn.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Features/
│   │   │   │   ├── Features.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Footer/
│   │   │   │   ├── Footer.tsx
│   │   │   │   ├── __tests__/
│   │   │   │   │   └── Footer.test.tsx
│   │   │   │   └── index.ts
│   │   │   ├── GitHubStars/
│   │   │   │   ├── GitHubStars.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Input/
│   │   │   │   ├── Input.tsx
│   │   │   │   └── index.ts
│   │   │   ├── LastCall/
│   │   │   │   ├── LastCall.tsx
│   │   │   │   └── index.ts
│   │   │   ├── MentionedIn/
│   │   │   │   ├── MentionedIn.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Navbar/
│   │   │   │   ├── Navbar.tsx
│   │   │   │   ├── NavigationMenu.tsx
│   │   │   │   ├── NavigationOptions.tsx
│   │   │   │   ├── __tests__/
│   │   │   │   │   ├── Navbar.test.tsx
│   │   │   │   │   ├── NavigationMenu.test.tsx
│   │   │   │   │   └── NavigationOptions.test.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Products/
│   │   │   │   ├── Products.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Statistics/
│   │   │   │   ├── Stat.tsx
│   │   │   │   ├── Statistics.tsx
│   │   │   │   └── index.ts
│   │   │   └── UseCases/
│   │   │       ├── UseCaseCard.tsx
│   │   │       ├── UseCases.tsx
│   │   │       └── index.ts
│   │   ├── dashboard/
│   │   │   ├── __tests__/
│   │   │   │   ├── credentials.page.test.tsx
│   │   │   │   ├── dashboard.test.tsx
│   │   │   │   ├── layout.test.tsx
│   │   │   │   ├── plans.page.test.tsx
│   │   │   │   └── profile.test.tsx
│   │   │   ├── components/
│   │   │   │   ├── DashboardMenu.tsx
│   │   │   │   ├── DashboardNavigationMenu.tsx
│   │   │   │   └── __tests__/
│   │   │   │       ├── DashboardMenu.test.tsx
│   │   │   │       └── DashboardNavigationMenu.test.tsx
│   │   │   ├── credentials.page.tsx
│   │   │   ├── dashboard.tsx
│   │   │   ├── error.tsx
│   │   │   ├── index.page.tsx
│   │   │   ├── layout.tsx
│   │   │   ├── plans.page.tsx
│   │   │   ├── profile.page.tsx
│   │   │   └── shared/
│   │   │       └── pricingFeatures.tsx
│   │   ├── hooks/
│   │   │   ├── __mocks__/
│   │   │   │   └── useCallable.ts
│   │   │   ├── useCallable.ts
│   │   │   └── useRecorder.ts
│   │   ├── index.page.tsx
│   │   ├── managers/
│   │   │   ├── AuthManager.tsx
│   │   │   └── __tests__/
│   │   │       └── AuthManager.test.tsx
│   │   ├── pricing/
│   │   │   ├── __tests__/
│   │   │   │   └── _index.page.test.tsx
│   │   │   ├── _index.page.tsx
│   │   │   ├── components/
│   │   │   │   ├── PricingCard.tsx
│   │   │   │   └── __tests__/
│   │   │   │       └── PricingCard.test.tsx
│   │   │   └── types.ts
│   │   ├── privacy/
│   │   │   └── index.page.tsx
│   │   ├── shared/
│   │   │   └── useCases.ts
│   │   ├── signup/
│   │   │   ├── index.page.tsx
│   │   │   └── login.tsx
│   │   ├── terms/
│   │   │   └── index.page.tsx
│   │   └── utils/
│   │       ├── getAWSAsset.ts
│   │       └── isProduction.ts
│   ├── public/
│   │   └── locales/
│   │       ├── en/
│   │       │   ├── about.json
│   │       │   ├── common.json
│   │       │   ├── index.js
│   │       │   └── signup.json
│   │       └── ig/
│   │           ├── about.json
│   │           ├── common.json
│   │           ├── index.js
│   │           └── signup.json
│   ├── routers/
│   │   ├── index.ts
│   │   ├── router.ts
│   │   ├── routerV2.ts
│   │   ├── siteRouter.ts
│   │   ├── stripeRouter.ts
│   │   └── testRouter.ts
│   ├── server.ts
│   ├── services/
│   │   ├── __tests__/
│   │   │   ├── database.test.ts
│   │   │   └── stripe.test.ts
│   │   ├── database.ts
│   │   ├── firebase-admin.ts
│   │   ├── firebaseConfigs.ts
│   │   ├── stripe.ts
│   │   └── words.ts
│   ├── shared/
│   │   ├── constants/
│   │   │   ├── AccountStatus.ts
│   │   │   ├── ApiType.ts
│   │   │   ├── ApiTypeToRoute.ts
│   │   │   ├── ApiUsageLimit.ts
│   │   │   ├── ChakraTheme.ts
│   │   │   ├── DefaultAudios.ts
│   │   │   ├── DemoOption.ts
│   │   │   ├── Dialect.ts
│   │   │   ├── DialectEnum.ts
│   │   │   ├── Endpoint.ts
│   │   │   ├── ExampleStyleEnum.ts
│   │   │   ├── ExampleStyles.ts
│   │   │   ├── Feedback.ts
│   │   │   ├── LanguageEnum.ts
│   │   │   ├── PartTypes.ts
│   │   │   ├── Plan.ts
│   │   │   ├── SentenceTypes.ts
│   │   │   ├── StatTypes.ts
│   │   │   ├── StopWords.ts
│   │   │   ├── SuggestionSourceEnum.ts
│   │   │   ├── Tenses.ts
│   │   │   ├── Version.ts
│   │   │   ├── WordAttributeEnum.ts
│   │   │   ├── WordAttributes.ts
│   │   │   ├── WordClass.ts
│   │   │   ├── WordClassEnum.ts
│   │   │   ├── WordTagEnum.ts
│   │   │   ├── WordTags.ts
│   │   │   ├── diacriticCodes.ts
│   │   │   ├── errorMessages.ts
│   │   │   ├── navigationLinks.ts
│   │   │   └── parseFileLocations.ts
│   │   └── utils/
│   │       ├── __tests__/
│   │       │   ├── createRegExp.test.ts
│   │       │   └── getErrorMessage.test.ts
│   │       ├── blobToBase64.ts
│   │       ├── blobUrlToBase64.ts
│   │       ├── createQueryRegex.ts
│   │       ├── createRegExp.ts
│   │       ├── documentUtils.ts
│   │       ├── getErrorMessage.ts
│   │       ├── normalization.js
│   │       ├── removeAccents.ts
│   │       ├── removePrefix.ts
│   │       ├── replaceAbbreviations.ts
│   │       └── wrapConsole.ts
│   ├── siteConstants.ts
│   ├── styles.css
│   └── types/
│       ├── databaseStats.ts
│       ├── developer.ts
│       ├── developerUsage.ts
│       ├── example.ts
│       ├── express.ts
│       ├── formFields.ts
│       ├── index.ts
│       ├── nsibidiCharacter.ts
│       ├── stat.ts
│       └── word.ts
├── tailwind.config.js
├── testSetup.ts
├── theme.config.jsx
├── tsconfig.json
└── tsconfig.test.json

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

================================================
FILE: .dockerignore
================================================
node_modules

================================================
FILE: .eslintignore
================================================
node_modules
dist
build

================================================
FILE: .github/CODE_OF_CONDUCT.md
================================================
# Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
  address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [kedu@nkowaokwu.com](mailto:kedu@nkowaokwu.com). All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/


================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contributing to the Igbo API

If you have questions about the Igbo API (not a bug report), please ask a question in our [Slack community](https://nkowaokwu.com/volunteer) as a volunteer.

Contributions are always welcome. Before contributing please read the [Code of Conduct](./CODE_OF_CONDUCT.md) section.

## Reporting bugs
Before opening a new issue, look for existing [issues](https://github.com/nkowaokwu/igbo_api/issues) to avoid duplication. If the issue does not exist yet, [create one](https://github.com/nkowaokwu/igbo_api/issues/new).

* Please post any relevant code samples or screenshots
* If the bug involves an error, please post the **stack trace**
* Please fully detail the nature of the bug by filling out the issue template

## Requesting new features
* Before opening a new issue, look for existing [issues](https://github.com/nkowaokwu/igbo_api/issues) to avoid duplication. If the issue does not exist yet, [create one](https://github.com/nkowaokwu/igbo_api/issues/new).
* Please fully detail the nature of the feature request by filling out the request template

## Areas of contribution
There are plenty of opportunities to support and help maintain this repo. This includes, but is not limited to:

1. Request new features for the Igbo API
2. Fixing typos in code or sample/mock data
3. Update the README or write documentation for implementations
4. Convert files from JS to TS
5. So much more...

If you have more ideas of how to improve the Igbo API, reach out to Ijemma on [Slack](https://nkowaokwu.com/volunteer) as a volunteer.

## Accepting work
Once you find an issue you would like to work on, you can request to have that issue assigned to you to begin work. 

**Note:** Multiple people can be assigned to the same ticket. Issue assignment is only meant to help **track** who's working on what. This means that multiple contributors can be working on the same issue.

## Fork the repo

Please ensure that you fork this repo before making any changes. This will ensure that you are not only able to make changes in your own work environment but also able to submit PRs.

**This repo is set up to only accept PRs from forked repos**

## Pull Request Process

### Before Opening a Pull Request

Double-check to make sure that you have done the following things:

1. If implementing a feature request, create new unit tests to increase confidence in your changes.
    * **You're code will be unable to get merged without new unit tests**
2. Check to see if your changes are non-breaking by running `npm run test`
3. And install or build dependencies are removed
    * You can run `npm run clean` to remove unwanted files.
4. Update the README.md with details of changes to the interface, this includes new environment 
   variables, exposed ports, useful file locations, and container parameters.

### After Opening a Pull Request
1. Open a pull request and assign at least one reviewer, [@ijemmao](https://github.com/ijemmao).
2. You may merge the pull request in once the following things happen
    * All the tests pass against your branch build
    * You have the sign-off from both reviewers

## Coding Style

This project follows the [AirBnb JavaScript Style Guide](https://github.com/airbnb/javascript).


================================================
FILE: .github/FIREBASE_CONFIG.md
================================================
# Firebase Configuration Guide

This project relies on Firebase Cloud Functions to execute the Igbo API business logic.

Individual contributors need to integrate their own Firebase project config to be able to run the project locally and merge forked changes.

## Step 1: Create a Firebase Project

Please follow this [Firebase Getting Started Guide](https://firebase.google.com/docs/web/setup) to create your own Firebase project.

## Step 1a: Log into Firebase via Terminal (CLI)

In your terminal, log into your Firebase account by running the command and following the prompts:

```bash
npx firebase login
```

## Step 1b: Select the Blaze, pay as you go Firebase plan

Make sure to update your Billing options for your Firebase project. This will allow your project to use emulators. Don't worry, it's free 😉

## Step 2: Replace the `default` Firebase Project ID

Within [.firebaserc](https://github.com/nkowaokwu/igbo_api/blob/master/.firebaserc), replace the project ID `igbo-api-bb22d` with your new Firebase project ID

## Step 3: Replace the Firebase Config file

Within [firebase.ts](https://github.com/nkowaokwu/igbo_api/blob/master/src/services/firebase.ts#L5-L13), replace the `FIREBASE_CONFIG` object with your firebase project config object

## Step 4: Select your default project

Run the following command to select your default Firebase project:

```bash
npx firebase use default
```

Selecting a Firebase project is important for Firebase to know which project configure it should use when starting your dev environment.

## Step 5: Merging forked changes into main repo

Congrats 🎉 You're ready to start making your first changes to your repo. Please refer to our [Contributing Guide](https://github.com/nkowaokwu/igbo_api/blob/master/.github/CONTRIBUTING.md) to learn how to contribute to the project.


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**
 - OS: [e.g. iOS]
 - Browser [e.g. chrome, safari]
 - Version [e.g. 22]

**Smartphone (please complete the following information):**
 - Device: [e.g. iPhone6]
 - OS: [e.g. iOS8.1]
 - Browser [e.g. stock browser, safari]
 - Version [e.g. 22]

**Additional context**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/doc_issue.md
================================================
---
name: Docs feedback
about: Suggest feedback, ideas, or any new forms of contributions
title: ''
labels: ''
assignees: ''
---

<!-- Thank you for contributing to Igbo API 📑 ✍️. -->
<!-- We appreciate your feedback, ideas, and contributions. -->
<!-- Before filing this issue, please make sure to check if there's already a similar issue open in our Docs project Board. -->

## Title of the Issue

[📑 Docs]: 

## What Docs changes are you proposing?

## What will this task cover?

### Next steps
(Highlight if there is anything the Project lead or product owner can do to he;p here. 
Secondly, what are the next steps to get this task done?)


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .github/pull_request_template.md
================================================
## Describe your changes
<!--- Thoughtfully think through your changes. Think of your audience, this PR is public! -->

## Issue ticket number and link
Closed <!--- <insert issue number with # to have GitHub automatically close the issue - https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword> -->

## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->

## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->

## Screenshots (if appropriate):
<!--- Replace this section with a screenshot or N/A if there are no screenshots -->


================================================
FILE: .github/workflows/deploy.yml
================================================
name: Deploy to Firebase

on:
  push:
    branches:
      - master
env:
  FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
  FIREBASE_CONFIG: ${{ secrets.FIREBASE_CONFIG }}
  FIREBASE_SERVICE_ACCOUNT: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
  GCLOUD_PROJECT: ${{ secrets.GCLOUD_PROJECT }}
  MAIN_KEY: ${{ secrets.MAIN_KEY }}
  MONGO_URI: ${{ secrets.MONGO_URI }}
  SENDGRID_API_KEY: ${{ secrets.SENDGRID_API_KEY }}
  SENDGRID_NEW_DEVELOPER_ACCOUNT_TEMPLATE: ${{ secrets.NEW_DEVELOPER_ACCOUNT_TEMPLATE }}
  GA_TRACKING_ID: ${{ secrets.GA_TRACKING_ID }}
  GA_API_SECRET: ${{ secrets.GA_API_SECRET }}
  REDIS_HOST: ${{ secrets.REDIS_HOST }}
  REDIS_URL: ${{ secrets.REDIS_URL }}
  REDIS_PORT: ${{ secrets.REDIS_PORT }}
  REDIS_USERNAME: ${{ secrets.REDIS_USERNAME }}
  REDIS_STATUS: ${{ secrets.REDIS_STATUS }}
  REDIS_PASSWORD: ${{ secrets.REDIS_PASSWORD }}
  GITHUB_STATS_TOKEN: ${{ secrets.STATS_TOKEN }}
  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
  AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
  AWS_REGION: ${{ secrets.AWS_REGION }}
  STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}
  STRIPE_ENDPOINT_SECRET: ${{ secrets.STRIPE_ENDPOINT_SECRET }}
  NODE_ENV: production

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v3
      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: '20'
      - name: Install Project Dependencies
        run: |
          rm -rf ./node_modules; npm install
          npm install -g firebase-tools
      - name: Install Cloud Dependencies
        run: |
          cd functions; rm -rf ./node_modules/; npm install; cd ..; pwd
          firebase use default --token $FIREBASE_TOKEN
      - name: Create .env
        run: touch ./functions/.env
      - name: Update .env
        uses: SpicyPizza/create-envfile@v2.0
        with:
          envkey_ENV_VPC_CONNECTOR: ${{ secrets.VPC_CONNECTOR }}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
          envkey_ENV_REDIS_PORT: ${{ secrets.REDIS_PORT }}
          envkey_ENV_MONGO_URI: ${{ secrets.MONGO_URI }}
          envkey_ENV_REDIS_URL: ${{ secrets.REDIS_URL }}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
          envkey_ENV_REDIS_HOST: ${{ secrets.REDIS_HOST }}
          envkey_ENV_CLIENT_TEST: false
          envkey_ENV_REDIS_USERNAME: ${{ secrets.REDIS_USERNAME }}
          envkey_ENV_FIREBASE_CONFIG: ${{ secrets.FIREBASE_CONFIG }}
          envkey_ENV_FIREBASE_SERVICE_ACCOUNT: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
          envkey_ENV_REDIS_STATUS: true
          envkey_ENV_REDIS_PASSWORD: ${{ secrets.REDIS_PASSWORD }}
          envkey_ENV_MAIN_KEY: ${{ secrets.MAIN_KEY }}
          envkey_ENV_REPLICA_SET: true
          envkey_ANALYTICS_GA_TRACKING_ID: ${{ secrets.GA_TRACKING_ID }}
          envkey_ANALYTICS_GA_API_SECRET: ${{ secrets.GA_API_SECRET }}
          envkey_SENDGRID_API_KEY: ${{ secrets.SENDGRID_API_KEY }}
          envkey_SENDGRID_NEW_DEVELOPER_ACCOUNT_TEMPLATE: ${{ secrets.NEW_DEVELOPER_ACCOUNT_TEMPLATE }}
          envkey_GITHUB_STATS_TOKEN: ${{ secrets.STATS_TOKEN }}
          envkey_AWS_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
          envkey_AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY_ID }}
          envkey_AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          envkey_AWS_REGION:  ${{ secrets.AWS_REGION }}
          envkey_RUNTIME_ENV: "production"
          envkey_STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}
          envkey_STRIPE_ENDPOINT_SECRET: ${{ secrets.STRIPE_ENDPOINT_SECRET }}
          envkey_ENV_SPEECH_TO_TEXT_API: ${{ secrets.ENV_SPEECH_TO_TEXT_API }}
          envkey_ENV_IGBO_STT_URL: ${{ secrets.ENV_IGBO_STT_URL }}
          envkey_ENV_IGBO_TO_ENGLISH_URL: ${{ secrets.ENV_IGBO_TO_ENGLISH_URL }}
          envkey_ENV_ENGLISH_TO_IGBO_URL: ${{ secrets.ENV_ENGLISH_TO_IGBO_URL }}
          directory: functions
      - name: Build Production Project
        run: |
          firebase functions:config:set runtime.env=production --token $FIREBASE_TOKEN
          npm run build
      - name: Migrate MongoDB Data
        run: |
          firebase functions:config:set env.redis_status=true runtime.env=production --token $FIREBASE_TOKEN
          npm run migrate-up
      - name: Deploy Production Firebase Functions
        run: |
          firebase deploy --project=igbo-api-bb22d --only functions
      - name: Deploy Production Firebase Hosting
        run: |
          firebase deploy --project=igbo-api-bb22d --only hosting
        env:
          FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
      - name: Delete .env
        run: rm -rf ./functions/.env


================================================
FILE: .github/workflows/dockerize.yml
================================================
name: Dockerize Igbo API

on:
  push:
    branches:
      - master

jobs:
  dockerize:
    name: Dockerize
    runs-on: ubuntu-latest

    steps:
      - name: Git checkout
        uses: actions/checkout@v2
      - name: Use Node.js @20
        uses: actions/setup-node@v1
        with:
          node-version: 20
      - name: Log into Docker Account
        run: echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin
        env:
          DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
          DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
      - name: Build Docker Image
        run: docker build -t igbo_api .
      - name: Push Docker Image
        run: |
          docker tag igbo_api $DOCKER_USERNAME/igbo_api_server
          docker push $DOCKER_USERNAME/igbo_api_server
        env:
          DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}


================================================
FILE: .github/workflows/integration.yml
================================================
name: Test Suite

on:
  workflow_dispatch:
  pull_request:

env:
  FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
  CI: test
  NODE_ENV: test
  MAIN_KEY: ${{ secrets.MAIN_KEY }}

jobs:
  test:
    name: Build and Test
    runs-on: ubuntu-latest
    timeout-minutes: 15

    strategy:
      matrix:
        node-version: [20.x]
        mongodb-version: [5.0, 6.0]

    steps:
      - name: Git checkout
        uses: actions/checkout@v2
      - name: Use Node.js @${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}
      - name: Start MongoDB
        uses: supercharge/mongodb-github-action@1.3.0
        with:
          mongodb-version: ${{ matrix.mongodb-version }}
      - name: Install Project Dependencies
        run: |
          rm -rf ./node_modules; npm install
          npm install -g firebase-tools
      - name: Build Server
        run: |
          npm run build
      - name: Test Server Build Process
        run: npm run test:build
      - name: Test Backend
        run: npm run jest:backend
      - name: Test Frontend
        run: npm run jest:frontend


================================================
FILE: .github/workflows/lint.yml
================================================
name: Lint

on: push

jobs:
  run-linters:
    name: Run linters
    runs-on: ubuntu-latest

    steps:
      - name: Git checkout
        uses: actions/checkout@v2

      - name: Use Node.js v20
        uses: actions/setup-node@v1
        with:
          node-version: 20

      - name: Install Node.js dependencies
        run: npm install

      - name: Run ESLint
        run: npx eslint ./src

      - name: Run TS
        run: npx tsc --noEmit

================================================
FILE: .github/workflows/release.yml
================================================
name: Release

on:
  push:
    branches:
      - master

jobs:
  release:
    name: Release
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
          persist-credentials: false
      - name: Use Node.js v20
        uses: actions/setup-node@v1
        with:
          node-version: 20
      - name: Install Dependencies
        run: npm install
      - name: Release
        env:
          GITHUB_TOKEN: ${{ secrets.RELEASE_ACCESS_TOKEN }}
        run: npx semantic-release


================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# MongoDB Database
dump/
db/
mongos/

# Transpiled code
build/

# VSCode
.vscode/

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Built files
build/

# Dependency directories
node_modules/
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)
web_modules/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Output of database backup
*.tar.*

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env*

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache

# Next.js build output
.next
out

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# Stores VSCode versions used for testing VSCode extensions
.vscode-test
.vscode

# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

# Cypress
./cypress/

# Jest
__tests__/__mocks__/dictionaries/

# Backup directories
./igbo_api_db
./aws_pronunciations

# misc
.DS_Store

# Firebase
src/services/firebase.ts
functions/node_modules
functions/src
functions/dictionaries
functions/yarn.lock
functions/pnpm-lock.yaml
yarn.lock
pnpm-lock.yaml
.idea
.firebaserc


================================================
FILE: .npmrc
================================================
engine-strict = true


================================================
FILE: .prettierignore
================================================
**/*.d.ts

================================================
FILE: .prettierrc.json
================================================
{
  "parser": "flow",
  "printWidth": 100,
  "singleQuote": true,
  "trailingComma": "es5",
  "semi": true,
  "tabWidth": 2
}


================================================
FILE: .releaserc
================================================
{
  "branches": ["master"],
  "plugins": [
    ["@semantic-release/commit-analyzer", {
      "preset": "angular",
      "releaseRules": [
        {"type": "docs", "scope": "README", "release": "patch"},
        {"type": "refactor", "release": "patch"},
        {"type": "style", "release": "patch"}
      ],
      "parserOpts": {
        "noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES"]
      }
    }],
    ["@semantic-release/release-notes-generator", {
      "preset": "angular",
      "parserOpts": {
        "noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES"]
      },
      "writerOpts": {
        "commitsSort": ["subject", "scope"]
      }
    }],
    ["@semantic-release/changelog", {
      "changelogFile": "CHANGELOG.md",
      "changelogTitle": "Igbo API Changelog"
    }],
    ["@semantic-release/npm", {
      "npmPublish": false
    }],
    ["@semantic-release/git", {
      "assets": ["dist/**/*.{js,css}", "docs", "package.json"],
      "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
    }]
  ]
}


================================================
FILE: @types/bcrypt.d.ts
================================================
declare module 'bcrypt';


================================================
FILE: @types/body-parser.d.ts
================================================
declare module 'body-parser';


================================================
FILE: @types/compression.d.ts
================================================
declare module 'compression';


================================================
FILE: @types/console.d.ts
================================================
declare global {
  interface Console {
    green(message?: any, ...optionalParams: any[]): void;
    blue(message?: any, ...optionalParams: any[]): void;
    red(message?: any, ...optionalParams: any[]): void;
  }
}

export {};


================================================
FILE: @types/diacriticless.d.ts
================================================
declare module 'diacriticless';

================================================
FILE: @types/environment.d.ts
================================================
declare global {
  namespace NodeJS {
    interface ProcessEnv {
      // @ts-expect-error  Nodejs process override
      readonly NODE_ENV: 'development' | 'production' | 'test' | 'build';
    }
  }
}

export {};


================================================
FILE: @types/express-rate-limit.d.ts
================================================
declare module 'express-rate-limit';


================================================
FILE: @types/is-word.d.ts
================================================
declare module 'is-word';


================================================
FILE: @types/morgan.d.ts
================================================
declare module 'morgan';


================================================
FILE: @types/react-scroll.d.ts
================================================
declare module 'react-scroll';


================================================
FILE: @types/shelljs.d.ts
================================================
declare module 'shelljs';


================================================
FILE: @types/string-similarity.d.ts
================================================
declare module 'string-similarity';


================================================
FILE: @types/supertest.d.ts
================================================
declare module 'supertest';

================================================
FILE: @types/uuid.d.ts
================================================
declare module 'uuid';


================================================
FILE: Dockerfile
================================================
FROM node:18

WORKDIR /app

COPY package.json ./

RUN npm install

COPY . .

RUN npm run build

ENV PORT=8080
ENV CONTAINER_HOST=mongodb

EXPOSE 8080

CMD ["npm", "start"]

================================================
FILE: LICENSE.md
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright 2023 Nkọwa okwu

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# Igbo API

[![Deploy to Firebase](https://github.com/nkowaokwu/igbo_api/actions/workflows/deploy.yml/badge.svg)](https://github.com/nkowaokwu/igbo_api/actions/workflows/deploy.yml) [![Dockerize Igbo API](https://github.com/nkowaokwu/igbo_api/actions/workflows/dockerize.yml/badge.svg)](https://github.com/nkowaokwu/igbo_api/actions/workflows/dockerize.yml)

[Contributing](./.github/CONTRIBUTING.md) | [Documentation](https://igboapi.com/docs) | [Code of Conduct](./.github/CODE_OF_CONDUCT.md) | [Slack Channel](https://igboapi.slack.com)

> Igbo is the principal native language of the Igbo people, an ethnic group of southeastern Nigeria, and is spoken by approx 45 million people with more than 20 different dialects.

## Demo

[Try the Igbo API here](https://igboapi.com)

## Get Started

Visit our [docs website](https://docs.igboapi.com) to get started with using the Igbo API.

Visit the [Igbo API Docs repo](https://github.com/nkowaokwu/igbo_api_docs) to help improve our docs.


================================================
FILE: __mocks__/@chakra-ui/react.tsx
================================================
import React from 'react';
import * as Chakra from '../../node_modules/@chakra-ui/react';

export const Tooltip = ({ children }: { children: any }) => <>{children}</>;
export const {
  Box,
  Drawer,
  DrawerBody,
  DrawerContent,
  DrawerFooter,
  DrawerHeader,
  DrawerOverlay,
  Center,
  Square,
  Collapse,
  Container,
  Flex,
  Grid,
  GridItem,
  SimpleGrid,
  Link,
  Stack,
  Select,
  Wrap,
  HStack,
  VStack,
  Button,
  Checkbox,
  CheckboxGroup,
  Radio,
  RadioGroup,
  RangeSlider,
  RangeSliderTrack,
  RangeSliderFilledTrack,
  RangeSliderThumb,
  Slider,
  SliderTrack,
  SliderFilledTrack,
  SliderThumb,
  SliderMark,
  Switch,
  Textarea,
  Input,
  InputGroup,
  InputLeftElement,
  InputRightElement,
  Code,
  Badge,
  Divider,
  Tag,
  TagLabel,
  TagLeftIcon,
  TagRightIcon,
  TagCloseButton,
  PinInput,
  PinInputField,
  Progress,
  CircularProgress,
  CircularProgressLabel,
  List,
  ListItem,
  ListIcon,
  OrderedList,
  UnorderedList,
  Heading,
  // Tooltip,
  Skeleton,
  Stat,
  StatLabel,
  StatNumber,
  StatHelpText,
  AccordionButton,
  Accordion,
  AccordionIcon,
  AccordionItem,
  AccordionPanel,
  Spinner,
  Tabs,
  TabList,
  TabPanel,
  TabPanels,
  Tab,
  Text,
  Image,
  Icon,
  IconButton,
  Hide,
  Fade,
  SlideFade,
  FormControl,
  FormLabel,
  AlertDialog,
  AlertDialogBody,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogContent,
  AlertDialogOverlay,
  Menu,
  MenuButton,
  MenuList,
  MenuItem,
  MenuItemOption,
  MenuGroup,
  MenuOptionGroup,
  MenuDivider,
  Modal,
  ModalOverlay,
  ModalContent,
  ModalHeader,
  ModalFooter,
  ModalBody,
  ModalCloseButton,
  Popover,
  PopoverTrigger,
  PopoverContent,
  PopoverHeader,
  PopoverBody,
  PopoverFooter,
  PopoverArrow,
  PopoverCloseButton,
  PopoverAnchor,
  Show,
  Avatar,
  AvatarBadge,
  AvatarGroup,
  Portal,
  PortalManager,
  forwardRef,
  popperCSSVars,
  VisuallyHidden,
  useBreakpoint,
  useDisclosure,
  usePopover,
  usePrevious,
  useStyleConfig,
  useTheme,
  useToast,
  chakra,
  extendTheme,
  createMultiStyleConfigHelpers,
  ChakraProvider,
} = Chakra;

export const useBreakpointValue = (breakpoints: any) => Object.values(breakpoints)[0];

export default Chakra;


================================================
FILE: __mocks__/@sendgrid/mail.ts
================================================
export default {};


================================================
FILE: __mocks__/axios.ts
================================================
export const mockRequest = jest.fn((config) => config);
export const request = jest.fn(() => ({ data: {}, catch: jest.fn(() => ({ data: {} })) }));
// @ts-expect-error request
mockRequest.request = request;

export default mockRequest;


================================================
FILE: __mocks__/bcrypt.ts
================================================
export const hash = jest.fn(() => 'hashed-password');


================================================
FILE: __mocks__/firebase/app.ts
================================================
export const initializeApp = jest.fn();
export const getApps = jest.fn(() => []);
export const getApp = jest.fn();


================================================
FILE: __mocks__/firebase/auth.ts
================================================
export const getAuth = jest.fn(() => ({
  currentUser: {
    uid: 'uid',
    getIdToken: () => 'uid-id-token',
  },
}));
export const connectAuthEmulator = jest.fn();


================================================
FILE: __mocks__/firebase/functions.ts
================================================
export const getFunctions = jest.fn(() => ({}));
export const connectFunctionsEmulator = jest.fn();


================================================
FILE: __mocks__/firebase-admin.ts
================================================
export const auth = jest.fn(() => ({
  verifyIdToken: jest.fn((id) => ({
    uid: id,
  })),
}));


================================================
FILE: __mocks__/firebase-functions/v1.ts
================================================
export const https = {
  onCall: jest.fn(),
};


================================================
FILE: __mocks__/i18next.ts
================================================
import * as i18next from '../node_modules/i18next';

export const changeLanguage = jest.fn();

export default i18next;


================================================
FILE: __mocks__/mongoose.ts
================================================
import mongoose from 'mongoose';
export { Types, Schema, Document } from 'mongoose';
import Plan from '../src/shared/constants/Plan';

export class Model {
  local = {};
  constructor(value: object) {
    this.local = { ...value, toJSON: () => value, id: 'static', plan: Plan.STARTER };
  }

  static find() {
    return [];
  }

  static findOne() {
    return {
      id: 'static',
      type: 'static',
      toJSON: () => ({ id: 'static', type: 'static' }),
      save: () => ({
        id: 'static',
        type: 'static',
        toJSON: () => ({
          id: 'static',
          type: 'static',
        }),
      }),
    };
  }

  save() {
    return { ...this.local, save: () => ({ ...this.local, toJSON: () => this.local }) };
  }
}

export const closeMock = jest.fn();
export const modelMock = jest.fn(() => Model);
const connection = {
  readyState: 1,
  close: closeMock,
  model: modelMock,
};

export default {
  ...mongoose,
  connection,
  createConnection: jest.fn(() => connection),
  on: jest.fn(),
};


================================================
FILE: __mocks__/next/font/google.ts
================================================
export const Inter = jest.fn(() => ({ style: { fontFamily: 'inter' } }));


================================================
FILE: __mocks__/next/router.ts
================================================
import * as next from 'next/dist/client/router';

export const routerPushMock = jest.fn();
export const useRouter = jest.fn(() => ({
  push: routerPushMock,
}));

export default next;


================================================
FILE: __mocks__/react-firebase-hooks/auth.ts
================================================
import { decodedIdTokenFixture } from '../../__tests__/shared/uiFixtures';

export const onAuthStateChanged = jest.fn(() => () => {});

export const useAuthState = jest.fn(() => [decodedIdTokenFixture(), false]);


================================================
FILE: __mocks__/shelljs.ts
================================================
export default {
  mkdir: jest.fn(),
};


================================================
FILE: __mocks__/stripe.ts
================================================
class Stripe {
  apiKey = '';
  prices = {
    list: jest.fn(() => ({ data: [{ id: 'price_id' }] })),
  };
  checkout = {
    sessions: {
      create: jest.fn(() => ({ url: 'checkout_session_url' })),
      retrieve: jest.fn(() => ({ customer: 'checkout_session_customer' })),
    },
  };
  billingPortal = {
    sessions: {
      create: jest.fn(() => ({ url: 'portal_session_url' })),
    },
  };
  webhooks = {
    constructEvent: jest.fn(() => ({ object: {} })),
  };

  constructor(apiKey: string) {
    this.apiKey = apiKey;
  }
}

export default Stripe;


================================================
FILE: __mocks__/uuid.ts
================================================
export const v4 = jest.fn(() => 'generated-uuid');


================================================
FILE: __tests__/__mocks__/data.mock.json
================================================
{
    "ànì": [
        {
            "wordClass": "noun",
            "definitions": [
                "A. land; ground; soil"
            ],
            "examples": [],
            "phrases": {
                "ànì apìtì": {
                    "definitions": [
                        "swamp"
                    ],
                    "examples": []
                },
                "ànị èdò": {
                    "definitions": [
                        "Atanị area"
                    ],
                    "examples": []
                },
                "ànì ezè": {
                    "definitions": [
                        "kingdom"
                    ],
                    "examples": []
                },
                "ànì isī": {
                    "definitions": [
                        "skull of head"
                    ],
                    "examples": []
                },
                "ànị mmadù": {
                    "definitions": [
                        "A. foreign country; another person’s land",
                        "B. land of the living (opposed to ànì mmụọ)"
                    ],
                    "examples": []
                },
                "ànì mmanụ anwū nà mmili ala efī": {
                    "definitions": [
                        "promised land (land of milk and honey)"
                    ],
                    "examples": []
                },
                "ànị mmānya": {
                    "definitions": [
                        "dregs of wine"
                    ],
                    "examples": []
                },
                "ànì mmarùbe": {
                    "definitions": [
                        "earthquake"
                    ],
                    "examples": []
                },
                "ànị mmụọ": {
                    "definitions": [
                        "land of the dead (opposed to ànị mmadù, land of the living) (Christian usage) hell; Hades"
                    ],
                    "examples": [
                        "Ọ līdàlù n’ànị mmụọ He descended into hell"
                    ]
                },
                "ànì obì": {
                    "definitions": [
                        "place of abode; settlement"
                    ],
                    "examples": []
                },
                "ànì ogwē akā": {
                    "definitions": [
                        "forearm"
                    ],
                    "examples": []
                },
                "ànì okwū": {
                    "definitions": [
                        "most important part of the story"
                    ],
                    "examples": []
                },
                "ànì olū": {
                    "definitions": [
                        "land overflowed in wet season"
                    ],
                    "examples": []
                },
                "ànì ọcha": {
                    "definitions": [
                        "A. dry land, not overflowed in wet season",
                        "B. Igbo land"
                    ],
                    "examples": []
                },
                "ànị ōma jìjìjì": {
                    "definitions": [
                        "earthquake"
                    ],
                    "examples": []
                },
                "ànì ọnà ọcha nà ọnā èdò": {
                    "definitions": [
                        "land of gold and silver"
                    ],
                    "examples": []
                },
                "ànì ụkwū": {
                    "definitions": [
                        "heel of the foot"
                    ],
                    "examples": []
                },
                "ànì ụlō": {
                    "definitions": [
                        "clay soil"
                    ],
                    "examples": []
                },
                "akwụ ànì": {
                    "definitions": [
                        "white ant (the type that lives in the ground) (literally palmnut of the ground)"
                    ],
                    "examples": []
                },
                "àrụ ànì": {
                    "definitions": [
                        "quietness"
                    ],
                    "examples": []
                },
                "awa ànì": {
                    "definitions": [
                        "division, plot, of land"
                    ],
                    "examples": []
                },
                "-bọ ànì": {
                    "definitions": [
                        "scratch, paw the ground (of fowls, dogs)"
                    ],
                    "examples": []
                },
                "-dị ànì": {
                    "definitions": [
                        "be low"
                    ],
                    "examples": [
                        "Oche à dì ànì This chair is low"
                    ]
                },
                "-do ànì": {
                    "definitions": [
                        "settle a country; establish peace"
                    ],
                    "examples": []
                },
                "-dolu ànì": {
                    "definitions": [
                        "put down"
                    ],
                    "examples": []
                },
                "-dolu àrụ ànì": {
                    "definitions": [
                        "take things easy"
                    ],
                    "examples": []
                },
                "enu ànì": {
                    "definitions": [
                        "dry land (as opposed to water); high land between Asaba and Agbor"
                    ],
                    "examples": []
                },
                "enū nà ànì": {
                    "definitions": [
                        "‘up and down’; blouse and wrapper made of same material"
                    ],
                    "examples": []
                },
                "-fè ànì": {
                    "definitions": [
                        "prepare land for planting by propitiating the gods concerned"
                    ],
                    "examples": []
                },
                "-gbabo ànì": {
                    "definitions": [
                        "kick up the ground"
                    ],
                    "examples": []
                },
                "-gbakìlì ànì": {
                    "definitions": [
                        "run hither and thither; make fuss; be dilatory, going hither and thither without anything being seen done by the person; dilly- dally"
                    ],
                    "examples": []
                },
                "-kpa okē ànì": {
                    "definitions": [
                        "make boundary between lands"
                    ],
                    "examples": []
                },
                "-kpọbo ànì": {
                    "definitions": [
                        "level ground; break ground for planting"
                    ],
                    "examples": []
                },
                "-kpọ isi ànì": {
                    "definitions": [
                        "prostrate; cringe; worship; beg"
                    ],
                    "examples": []
                },
                "-kpọ ànì": {
                    "definitions": [
                        "clear ground by burning"
                    ],
                    "examples": []
                },
                "-lu ànì": {
                    "definitions": [
                        "arrive at a settlement or conclusion"
                    ],
                    "examples": []
                },
                "-lụ ànì": {
                    "definitions": [
                        "wreak havoc; commit treachery, abominably wicked or cruel act"
                    ],
                    "examples": []
                },
                "-lụcha ànì": {
                    "definitions": [
                        "cultivate land; clear weeds"
                    ],
                    "examples": []
                },
                "ǹgwu ànì": {
                    "definitions": [
                        "tool for digging; digger"
                    ],
                    "examples": []
                },
                "ǹtọ ànì": {
                    "definitions": [
                        "foundation; origin"
                    ],
                    "examples": []
                },
                "òbì n’ànà alā ajā": {
                    "definitions": [
                        "one who lives underground but does not absorb earth (i.e. masquerade)"
                    ],
                    "examples": []
                },
                "onu ànì": {
                    "definitions": [
                        "low tone"
                    ],
                    "examples": []
                },
                "Ọ nà-èkwu n’onu ànì": {
                    "definitions": [
                        "He is speaking in low tones"
                    ],
                    "examples": []
                },
                "onye ànì": {
                    "definitions": [
                        "fellow countryman"
                    ],
                    "examples": []
                },
                "onye ànị mmadù": {
                    "definitions": [
                        "foreigner; stranger"
                    ],
                    "examples": []
                },
                "ọkpụ ànì": {
                    "definitions": [
                        "ancient; long-established"
                    ],
                    "examples": []
                },
                "òkpụkpa ànì": {
                    "definitions": [
                        "making of boundary"
                    ],
                    "examples": []
                },
                "ọmụ ànì": {
                    "definitions": [
                        "bottom"
                    ],
                    "examples": []
                },
                "ọrụ ànì": {
                    "definitions": [
                        "dregs (of wine)"
                    ],
                    "examples": []
                },
                "òsụsụ ànì": {
                    "definitions": [
                        "cutting, clearing of bush preparatory to farming"
                    ],
                    "examples": []
                },
                "-pu n’ànì": {
                    "definitions": [
                        "be native or home-born, indigenous (literally grow, sprout in the soil)"
                    ],
                    "examples": []
                },
                "-rulu ànì": {
                    "definitions": [
                        "stoop down"
                    ],
                    "examples": []
                },
                "-runata ànì": {
                    "definitions": [
                        "stoop down a bit"
                    ],
                    "examples": []
                },
                "-sekpùlu ànì": {
                    "definitions": [
                        "worship; bow, kneel down; give honour to"
                    ],
                    "examples": []
                },
                "-sù isi n’ànì": {
                    "definitions": [
                        "fall headlong; throw oneself headlong"
                    ],
                    "examples": []
                },
                "-sù n’ànì": {
                    "definitions": [
                        "thump on the ground; set down heavily"
                    ],
                    "examples": []
                },
                "-tò anya n’ànì": {
                    "definitions": [
                        "be observant, watchful, careful; take notice of; watch (literally lay the eye to the ground)"
                    ],
                    "examples": []
                },
                "-tò ntì n’ànì": {
                    "definitions": [
                        "hearken; pay attention (literally lay the ear to the ground)"
                    ],
                    "examples": []
                },
                "-tò ǹtọ ànì": {
                    "definitions": [
                        "lay foundation"
                    ],
                    "examples": []
                },
                "ụgbọ ànì": {
                    "definitions": [
                        "lorry; car"
                    ],
                    "examples": []
                },
                "ùsọ ànì": {
                    "definitions": [
                        "A. boundary (of farmland)",
                        "B. bank of river"
                    ],
                    "examples": []
                },
                "-wa ànì": {
                    "definitions": [
                        "break up land by digging; divide land for planting; dig ground"
                    ],
                    "examples": []
                },
                "-wedàta ànì": {
                    "definitions": [
                        "bring down; humble; humiliate"
                    ],
                    "examples": [
                        "B. Ànì, Ànà the Earth Spirit, regarded as the mother of all men, the queen of the underworld, and the custodian of public morality"
                    ]
                },
                "Ajaànà": {
                    "definitions": [
                        "aspect of the earth related to death rites"
                    ],
                    "examples": []
                },
                "Ànìegbòka": {
                    "definitions": [
                        "person’s name"
                    ],
                    "examples": []
                },
                "Ànìèmeka": {
                    "definitions": [
                        "person’s name (literally The land has done very well)"
                    ],
                    "examples": []
                },
                "Ànị ēzi": {
                    "definitions": [
                        "the shrine of Ànì owned by the head of a compound, kept in front of his house"
                    ],
                    "examples": []
                },
                "Ànị Ònìchà": {
                    "definitions": [
                        "secret place worshipped by Onitsha people"
                    ],
                    "examples": []
                },
                "alụlụ Ànì": {
                    "definitions": [
                        "injustice; maltreatment; wickedness"
                    ],
                    "examples": []
                },
                "ezē Ànì": {
                    "definitions": [
                        "life-size status of carved wood, representing Ànì"
                    ],
                    "examples": []
                },
                "nsọ Ànì": {
                    "definitions": [
                        "abomination"
                    ],
                    "examples": []
                },
                "-rù Ànì": {
                    "definitions": [
                        "sacrifice to Ànì"
                    ],
                    "examples": []
                }
            },
            "variations": [
                "ànà"
            ]
        }
    ],
    "ama": [
        {
            "wordClass": "n.",
            "definition": "(also èzi amā) space in front of the compound, outside thecompound wall and beginning from the main gate; street:",
            "examples": [
                "Ama Madùnààgụ Madụnaagụ street"
            ],
            "phrases": {
                "-nò n’ama": {
                    "definition": "(fig.) menstruate:",
                    "examples": [
                        "Nwaànyì nò n’ama The woman is menstruating"
                    ]
                },
                "-pù ama": {
                    "definition": "go to the toilet (lit. go out to the fore-compound beyond the",
                    "examples": [
                        "main compound door):",
                        "Anà m apù amā I am going to the toilet"
                    ]
                },
                "-pù n’ama": {
                    "definition": "reach age of menstruation",
                    "examples": [
                        "Nwaànyì pùlù n’ama The girl has reached puberty"
                    ]
                },
                "ụzò ezi amā": {
                    "definition": "main entrance to a compound",
                    "examples": []
                }
            },
            "variations": []
        }
    ],
    "agụū": [
        {
            "wordClass": "n.",
            "definition": "hunger; desire; eagerness",
            "examples": [],
            "phrases": {
                "(agụū) -gụ": {
                    "definition": "be hungry",
                    "examples": []
                },
                "agụū mmīli": {
                    "definition": "thirst",
                    "examples": []
                },
                "-gụ agụū": {
                    "definition": "hunger; desire; long for ( -gụ 2. desire)",
                    "examples": []
                }
            },
            "variations": []
        }
    ],
    "n'oge": [
        {
            "wordClass": "tester",
            "definition": "tester",
            "examples": ["tester"],
            "phrases": {},
            "variations": []
        }
    ],
    "-zu-zu": [
        {
            "wordClass": "tester",
            "definition": "tester",
            "examples": ["tester"],
            "phrases": {},
            "variations": []
        }
    ],
    "bịa": [
        {
            "wordClass": "verb",
            "definitions": [
                "come"
            ],
            "examples": [],
            "phrases": {
                "òbịbịa": {
                    "definitions": [
                        "coming; advent"
                    ],
                    "examples": []
                },
                "Òbịbịaā Kraìst": {
                    "definitions": [
                        "Advent"
                    ],
                    "examples": []
                },
                "-bịachi anya": {
                    "definitions": [
                        "come regularly"
                    ],
                    "examples": []
                },
                "-bịachìgha": {
                    "definitions": [
                        "come; return"
                    ],
                    "examples": []
                },
                "bịadị(lì)": {
                    "definitions": [
                        "by the way, ..."
                    ],
                    "examples": []
                },
                "-bịakèta": {
                    "definitions": [
                        "come nearer"
                    ],
                    "examples": []
                },
                "-bịakwute": {
                    "definitions": [
                        "come near to (a person)"
                    ],
                    "examples": []
                },
                "-bịalu": {
                    "definitions": [
                        "arrive at; reach"
                    ],
                    "examples": []
                },
                "-bịa ǹso": {
                    "definitions": [
                        "approach"
                    ],
                    "examples": []
                },
                "-bịa(sò) n’àzụ": {
                    "definitions": [
                        "come after"
                    ],
                    "examples": []
                },
                "arō nā-abịa": {
                    "definitions": [
                        "A. next year (compare arō òzọ)",
                        "B. coming year(s)"
                    ],
                    "examples": []
                },
                "-sibịa": {
                    "definitions": [
                        "come from; come (by way of)"
                    ],
                    "examples": []
                }
            },
            "variations": []
        }
    ],
    "ndị ndi": [
        {
            "wordClass": "n.",
            "definition": "nation; people, those (plural of onye)",
            "examples": [],
            "phrases": {
                "ndị à": {
                    "definition": "these:",
                    "examples": [
                        "Akwà ndị à bụ òke ǹkè m These clothes are my share"
                    ]
                },
                "ndị afù": {
                    "definition": "those",
                    "examples": []
                },
                "ndị aghā": {
                    "definition": "soldiers; warriors",
                    "examples": []
                },
                "ndi be": {
                    "definition": "household; people of the house; fellow townsfolk",
                    "examples": []
                },
                "ndi gboo": {
                    "definition": "the ancients",
                    "examples": []
                },
                "ndị īchiè": {
                    "definition": "chiefs, titled persons (alive or departed)",
                    "examples": []
                },
                "ndi ikènyà": {
                    "definition": "elders; grown men; principal men",
                    "examples": []
                },
                "ndị ikpē": {
                    "definition": "the judges",
                    "examples": []
                },
                "ndi isī": {
                    "definition": "chiefs, headmen",
                    "examples": []
                },
                "Ndi Isi Ōji": {
                    "definition": "the Africans",
                    "examples": []
                },
                "ndi ìsì": {
                    "definition": "blind people",
                    "examples": []
                },
                "ndị kọtùma": {
                    "definition": "court-messengers",
                    "examples": []
                },
                "ndị mbụ nà ndị": {
                    "definition": "the ancestors",
                    "examples": []
                },
                "àbò": {
                    "definition": "dead people (spirits)",
                    "examples": []
                },
                "ndị mpùm": {
                    "definition": "highwaymen; robbers; bandits",
                    "examples": []
                },
                "ndị mūlụ": {
                    "definition": "parents",
                    "examples": []
                },
                "ndị nche atụlū": {
                    "definition": "shepherds",
                    "examples": []
                },
                "ndị ǹkè nya": {
                    "definition": "his own people",
                    "examples": []
                },
                "ndị nkịtị": {
                    "definition": "common people",
                    "examples": []
                },
                "ndị ntā": {
                    "definition": "hunters",
                    "examples": []
                },
                "ndị nwufù": {
                    "definition": "those yonder",
                    "examples": []
                },
                "ndinyom": {
                    "definition": "women; females",
                    "examples": []
                },
                "ndi ochiè": {
                    "definition": "the ancients",
                    "examples": []
                },
                "Ndi ōji": {
                    "definition": "Africans; black people",
                    "examples": []
                },
                "ndị okènyè": {
                    "definition": "elders",
                    "examples": []
                },
                "ndi orī": {
                    "definition": "rogues; highwaymen",
                    "examples": []
                },
                "ndi orù": {
                    "definition": "slaves",
                    "examples": []
                },
                "ndi ōsu": {
                    "definition": "people owned by deities; outcasts",
                    "examples": []
                },
                "ndị ozī": {
                    "definition": "messengers; the apostles",
                    "examples": []
                },
                "ndị ọkù": {
                    "definition": "fishermen",
                    "examples": []
                },
                "ndị ọnwò": {
                    "definition": "some people",
                    "examples": []
                },
                "ndi ōta ōjị": {
                    "definition": "nickname used only by the Igbo to describe the Yoruba",
                    "examples": []
                },
                "ndị òyì": {
                    "definition": "friends",
                    "examples": []
                },
                "ndi Ukà": {
                    "definition": "the Christians",
                    "examples": []
                },
                "ndị ùlà": {
                    "definition": "deceivers; cunning people",
                    "examples": []
                },
                "ùwà ndi mmọọ": {
                    "definition": "the world of spirits",
                    "examples": []
                },
                "ùwà ndi oyìbo": {
                    "definition": "luxurious pleasure-loving way of life or living; extravagant",
                    "examples": [
                        "life (lit. the world of the white people)"
                    ]
                }
            },
            "variations": []
        }
    ]
}

================================================
FILE: __tests__/__mocks__/documentData.ts
================================================
import mongoose from 'mongoose';

const { ObjectId } = mongoose.Types;

const wordId = new ObjectId('5f864d7401203866b6546dd3');
const exampleId = new ObjectId('5f864d7401203866b6546dd3');
const developerData = {
  name: 'Developer',
  email: 'developer@example.com',
  password: 'password',
};

const malformedDeveloperData = {
  email: 'developer@example.com',
  password: 'password',
};

export { wordId, exampleId, developerData, malformedDeveloperData };


================================================
FILE: __tests__/__mocks__/genericWords.mock.json
================================================
{
  "meru": [
      "aal"
  ],
  "ọria": [
      "aals",
      "dreggy",
      "gregor",
      "outreness",
      "sclerae",
      "typhomalarial"
  ],
  "maa mma": [
      "aaron",
      "attritive",
      "bewonder",
      "brutely",
      "charmful",
      "charming",
      "charmingest",
      "charmingly",
      "charmingness",
      "charmwise",
      "mallear",
      "mammered",
      "mirate",
      "palated",
      "shaly",
      "sheerest",
      "stabbed",
      "stabbingly",
      "trefle"
  ],
  "ụgbụ": [
      "aaronic",
      "chider",
      "clabbery",
      "dragnet",
      "dragnets",
      "fibrilliferous",
      "flabbergasts",
      "honeycombing",
      "hortation",
      "netherstone",
      "netmaker",
      "netmen",
      "nets",
      "nettlebird",
      "nettlers",
      "nettles",
      "nettlier",
      "rousters",
      "semencontra"
  ],
  "aburu ihe": [
      "aaronical"
  ],
  "mbughari": [
      "aaronite",
      "improvership",
      "migrationist",
      "migratorial",
      "nontransportation",
      "removableness",
      "retransport",
      "retransportation",
      "sokemanry",
      "transshaping",
      "transshipment",
      "transshipping",
      "transumption",
      "trolleying",
      "upswallow"
  ],
  "mmọnụ": [
      "aaronitic"
  ],
  "arr.. .arrarrarr": [
      "aarrgh"
  ],
  "Aarrghh": [
      "aarrghh"
  ],
  "Akara": [
      "aas",
      "arvo",
      "marksman",
      "score"
  ],
  "agbada": [
      "abacate",
      "bowknot",
      "buttstrapped",
      "cuittled",
      "descensional",
      "doweled",
      "downcourt",
      "downgrading",
      "downhanging",
      "downy",
      "downier",
      "downily",
      "downing",
      "downless",
      "galivanted",
      "galivanting",
      "gallivanting",
      "gibbeted",
      "gibbetted",
      "imboldened",
      "incaged",
      "lowbrows",
      "lowering",
      "poled",
      "scabious",
      "staggarts"
  ],
  "acinjọ": [
      "abacinate"
  ],
  "nkwụsị": [
      "abacination",
      "abatement",
      "abbroachment",
      "abdication",
      "abearance",
      "abecedary",
      "abjection",
      "abrasions",
      "absquatulation",
      "abthanage",
      "anileness",
      "annuation",
      "annulation",
      "annullation",
      "breakback",
      "breakfront",
      "breakouts",
      "breakpoint",
      "breakpoints",
      "buffability",
      "cancellations",
      "ceaselessness",
      "celation",
      "cessation",
      "cessations",
      "cesspits",
      "curbline",
      "curtails",
      "curtalaxes",
      "cutability",
      "cutbacks",
      "cutdown",
      "cutdowns",
      "cutinisation",
      "cutinization",
      "cutireaction",
      "cutoffs",
      "cuttages",
      "decancellation",
      "decantation",
      "decurrences",
      "decussis",
      "deflowerment",
      "degage",
      "deglaciation",
      "degranulation",
      "demagnetizing",
      "demersion",
      "desegmentation",
      "desegregation",
      "desertions",
      "desistance",
      "desistence",
      "desisting",
      "detachedness",
      "detaching",
      "detachment",
      "detergency",
      "determa",
      "deterrability",
      "deterrable",
      "dethronement",
      "detumescence",
      "dimercurion",
      "dimerization",
      "dimication",
      "diminutival",
      "diminutiveness",
      "disconnectedness",
      "disconnection",
      "disconnections",
      "disconnectiveness",
      "discontinuance",
      "discontinuances",
      "discontinuation",
      "discontinuations",
      "discontinuity",
      "discontinuities",
      "discontinuousness",
      "disenactment",
      "dishallucination",
      "dislocation",
      "dislocations",
      "distensions",
      "disthroning",
      "dorsiventrality",
      "dowage",
      "dowing",
      "dowitch",
      "dowment",
      "dumpiness",
      "dumpings",
      "exarticulation",
      "exsection",
      "footing",
      "footingly",
      "hagdown",
      "halids",
      "halisteresis",
      "halteres",
      "haltingness",
      "halts",
      "halurgy",
      "hebetation",
      "interceptions",
      "interfraternity",
      "interjection",
      "interlays",
      "intermination",
      "intermission",
      "intermissions",
      "intermissive",
      "intermittencies",
      "interpunctuation",
      "interresistance",
      "interruptedness",
      "interrupter",
      "interruptible",
      "interruption",
      "interruptions",
      "interruptory",
      "intersection",
      "intersectional",
      "irreduction",
      "junction",
      "junctional",
      "junctions",
      "juncture",
      "junctures",
      "layship",
      "lapses",
      "limpingness",
      "lowdown",
      "lurch",
      "manumission",
      "miscontinuance",
      "mistrysting",
      "nasuteness",
      "neurotension",
      "neutralization",
      "neutralizations",
      "neutroclusion",
      "nondesisting",
      "nontraction",
      "nugacities",
      "obtusion",
      "offtrack",
      "outhumors",
      "outlays",
      "outpension",
      "outromance",
      "outsparspying",
      "outstations",
      "outstunt",
      "outstunts",
      "palliation",
      "perstringe",
      "perstringement",
      "pushdowns",
      "putdown",
      "putdowns",
      "quakerishness",
      "quakerization",
      "queerish",
      "queerishness",
      "queerness",
      "quiescence",
      "quitches",
      "quitemoca",
      "rabattement",
      "rebatement",
      "refrainment",
      "rescindment",
      "rescission",
      "rescissions",
      "riddance",
      "riddances",
      "rubdown",
      "secundation",
      "severance",
      "solvency",
      "spinescence",
      "spinoseness",
      "splashdown",
      "splashdowns",
      "sploshes",
      "sprachle",
      "sprackness",
      "squattiness",
      "squegging",
      "stackstand",
      "staginess",
      "stagnation",
      "stagnatory",
      "standerwort",
      "standoff",
      "standoffish",
      "standoffishness",
      "standouts",
      "standpipe",
      "stationariness",
      "stealability",
      "steely",
      "steelie",
      "stepdown",
      "stepdowns",
      "stoat",
      "stoating",
      "stopback",
      "stopband",
      "stopblock",
      "stopdice",
      "stoper",
      "stopgap",
      "stopgaps",
      "stophound",
      "stopover",
      "stopovers",
      "stoppage",
      "stoppages",
      "stopper",
      "stoppeur",
      "stopping",
      "stoppit",
      "stopples",
      "stops",
      "stopship",
      "stopway",
      "stopwatches",
      "stopwork",
      "straticulation",
      "suppressiveness",
      "susurration",
      "tenement",
      "tenementization",
      "terminuses",
      "thyroidization",
      "unstation",
      "unstopple",
      "washdown"
  ],
  "ndị ọchịchị": [
      "abacist",
      "adjutants",
      "administrators",
      "authorities",
      "countians",
      "governments",
      "imperialised",
      "imperialists",
      "justiciaries",
      "mandators",
      "nongovernment",
      "pituitaries",
      "prefectures",
      "proconsuls",
      "rulers",
      "sheikdoms"
  ],
  "nwee obi": [
      "aback",
      "belated",
      "coheartedness",
      "greathearted",
      "heartdeep",
      "heartened",
      "heartweed",
      "highhearted",
      "hothearted",
      "younghearted",
      "ironhearted",
      "largehearted",
      "leadenhearted",
      "leadenheartedness",
      "lighthearted",
      "lionhearted",
      "palehearted",
      "smallhearted",
      "soundhearted",
      "sourhearted",
      "sweethearted",
      "sweethearting",
      "tamehearted",
      "tenderheart",
      "tigerhearted",
      "tubehearted",
      "uphearted",
      "waxhearted"
  ],
  "arụ ọrụ": [
      "abactinal",
      "abactinally",
      "abaction",
      "abactor",
      "abacuses",
      "abashments",
      "aberrations",
      "ablatives",
      "abreaction",
      "abreactions",
      "abreacts",
      "activized",
      "aedility",
      "aedilities",
      "afunctional",
      "antireactionary",
      "apicial",
      "artificialism",
      "atticisms",
      "bework",
      "bisection",
      "bisections",
      "bodgery",
      "bodywork",
      "bodyworks",
      "busyness",
      "busynesses",
      "busywork",
      "busyworks",
      "cabalism",
      "caballed",
      "capacitated",
      "careered",
      "caseworks",
      "coactive",
      "coemployment",
      "coemploys",
      "cofunction",
      "collaborative",
      "constructional",
      "constructively",
      "constructiveness",
      "counterproductiveness",
      "cutwork",
      "cutworks",
      "deadworks",
      "disavowable",
      "disworkmanship",
      "doodling",
      "efficacies",
      "efficacious",
      "efficaciousness",
      "embodiments",
      "encyclical",
      "errability",
      "feltwork",
      "functional",
      "functionalism",
      "functionalistic",
      "functionalized",
      "functionally",
      "functionarism",
      "functionated",
      "functionation",
      "functioned",
      "functionlessness",
      "gerated",
      "goaled",
      "guddled",
      "hyperfunctional",
      "imperation",
      "inaction",
      "inactions",
      "inchoacy",
      "industrializing",
      "industrialness",
      "inoperability",
      "inoperable",
      "inoperation",
      "interworked",
      "invectiveness",
      "inworks",
      "ironworked",
      "isotactic",
      "labored",
      "laboured",
      "labouredness",
      "lathwork",
      "machinability",
      "machinated",
      "machined",
      "machinized",
      "machinofacture",
      "malefactory",
      "malfunction",
      "malfunctioned",
      "maloperation",
      "manipulated",
      "meatworks",
      "mechanality",
      "mechanizations",
      "mechanized",
      "mechanizing",
      "minaciousness",
      "misacts",
      "mischances",
      "miscomputation",
      "miscomputing",
      "mismoshes",
      "misobservance",
      "mousetrapped",
      "munificency",
      "needleworked",
      "nonfactious",
      "oarsmanship",
      "oisivity",
      "onerative",
      "operational",
      "operationally",
      "operosity",
      "oracularness",
      "outvaunted",
      "outworker",
      "outworking",
      "outworks",
      "overactivity",
      "painstakingness",
      "parafunction",
      "paraoperation",
      "perfunctionary",
      "pilework",
      "pointillism",
      "practicabilities",
      "preeffectively",
      "preemploy",
      "preoperation",
      "previses",
      "projectivity",
      "ragwork",
      "reactive",
      "repairableness",
      "servomechanical",
      "servomechanically",
      "servulate",
      "solvated",
      "stational",
      "subfunction",
      "subfunctional",
      "technicalness",
      "temporariness",
      "timeworks",
      "topworked",
      "topworking",
      "unaction",
      "unactionable",
      "undereyed",
      "underfaction",
      "underwork",
      "underworked",
      "underwrought",
      "undriven",
      "uneruptive",
      "unfactious",
      "unfactitious",
      "unfunctional",
      "unfunctionally",
      "unoperatable",
      "unperformance",
      "unsalness",
      "unschematic",
      "unserviceability",
      "unserviceably",
      "unsoldiery",
      "unworkability",
      "unworkable",
      "unworkableness",
      "unworkably",
      "upwork",
      "verminousness",
      "wageworking",
      "workability",
      "workaday",
      "workaholic",
      "workaway",
      "workfolks",
      "workful",
      "workhorse",
      "workhoused",
      "worky",
      "workings",
      "workingwonan",
      "workload",
      "workloads",
      "workmanly",
      "workmanliness",
      "workpiece",
      "workshy",
      "worksome",
      "workstand",
      "workup",
      "workups",
      "workways",
      "workwise",
      "worrisomeness"
  ],
  "weghachi": [
      "abaddon",
      "ablude",
      "abortin",
      "abrege",
      "abrenunciate",
      "alvite",
      "cuissen",
      "prenotify",
      "rclame",
      "reaver",
      "rebronze",
      "rebulk",
      "rechoose",
      "recidivate",
      "reclaimer",
      "reclame",
      "recorporify",
      "recrop",
      "recrudesced",
      "recultivate",
      "regradated",
      "reimpose",
      "reinduces",
      "reinducts",
      "reinstitute",
      "relearnt",
      "renegotiate",
      "reoffered",
      "repossess",
      "reprised",
      "restitute",
      "restore",
      "restorer",
      "restores",
      "retore",
      "revote",
      "verste"
  ],
  "ajuju": [
      "abadite",
      "abask",
      "adder",
      "aesculaceous",
      "aldermanly",
      "ampulated",
      "axiation",
      "bibaciousness",
      "cheery",
      "conspecific",
      "dismeasurable",
      "eohippuses",
      "episematic",
      "epithetic",
      "epitritic",
      "esteriferous",
      "exiguousness",
      "extogenous",
      "hyponasty",
      "interrog",
      "interrogable",
      "interrogated",
      "interrogation",
      "interrogator",
      "interviewee",
      "interviewer",
      "isophotal",
      "isopiestic",
      "jargoned",
      "lyophilized",
      "lithified",
      "monobromized",
      "nondetailed",
      "occiduous",
      "oenotheraceous",
      "operculiferous",
      "overabused",
      "overpracticed",
      "overprecisely",
      "pachyotous",
      "pachypodous",
      "pachypterous",
      "parricided",
      "pentapolitan",
      "predespondency",
      "preexceptional",
      "preextend",
      "pustulated",
      "questionability",
      "questorship",
      "quizzery",
      "quizziness",
      "quizzity",
      "repudiation",
      "repudiative",
      "scutulated",
      "sesquiseptimal",
      "stilliform",
      "subquestion",
      "succussion",
      "tephritic",
      "theocentric",
      "unblessed",
      "unboasted",
      "unbombastic",
      "unbraceleted",
      "unenquired",
      "unidextral",
      "uninterrogated",
      "unquestioned",
      "unskewed",
      "unsuffixed",
      "unvesiculated",
      "velured",
      "welladvised",
      "wittily"
  ],
  "abaf": [
      "abaff"
  ],
  "ndaba": [
      "abaisance",
      "abigails",
      "abondance",
      "abruptio",
      "abruptness",
      "amphigory",
      "bastards",
      "beamsmen",
      "boutel",
      "boutell",
      "boutre",
      "capnomancy",
      "catabiotic",
      "catamenial",
      "catamount",
      "ceriomyces",
      "ceruminous",
      "checkbird",
      "coincidence",
      "coincidences",
      "coincidency",
      "contorniate",
      "crashworthiness",
      "crebrity",
      "cricke",
      "cronyisms",
      "czardom",
      "daribah",
      "dawdler",
      "defaulters",
      "doctorbird",
      "dropwort",
      "falconbill",
      "falconers",
      "falconries",
      "fallacies",
      "fallibleness",
      "falterers",
      "felicitates",
      "felloes",
      "flouncey",
      "forlornity",
      "foulish",
      "gabback",
      "gabbard",
      "gabbart",
      "gabbarts",
      "gravelling",
      "yacks",
      "implunge",
      "incage",
      "incrimination",
      "infanglement",
      "interveniency",
      "jeopards",
      "latirostres",
      "loadstone",
      "lodestone",
      "lunars",
      "misdeal",
      "misorder",
      "mistfall",
      "mordant",
      "naticoid",
      "overadornment",
      "paba",
      "palladinize",
      "panderly",
      "panimmunity",
      "portcrayon",
      "potamic",
      "potamophilous",
      "potlid",
      "putrescine",
      "putridity",
      "rapaciousness",
      "rapeye",
      "reladle",
      "scolders",
      "sublimableness",
      "sublimations",
      "tomboyishness",
      "underconstumble",
      "validity",
      "validities",
      "validness"
  ],
  "abaiss": [
      "abaissed"
  ],
  "agbaka": [
      "abakas",
      "jincamas",
      "jinxed"
  ],
  "iwepụ": [
      "abalation",
      "abalienating",
      "ablactation",
      "ablation",
      "ablaut",
      "albation",
      "alienize",
      "aminated",
      "aminating",
      "amination",
      "anlaut",
      "avolation",
      "desegregating",
      "detruncate",
      "deturn",
      "disestablishing",
      "dislimning",
      "dislustering",
      "disparting",
      "flus",
      "flush",
      "flusher",
      "flushness",
      "flusk",
      "flusker",
      "flusteration",
      "limose",
      "unageing",
      "unbracing",
      "unflush",
      "uninert",
      "uninstituted",
      "uninstitutive",
      "uninterlinked",
      "uninterposing",
      "unmoaning",
      "unmoralizing",
      "unmount",
      "unmourning",
      "unseal",
      "unspit",
      "unstill",
      "unwebbed"
  ],
  "na-asọ oyi": [
      "abalienate",
      "abhorrently",
      "abhorrer",
      "abhorring",
      "abhorson",
      "abominably",
      "abominate",
      "abominates",
      "abominating",
      "atramentous",
      "avocative",
      "beevish",
      "besteading",
      "defenestrates",
      "derogative",
      "despites",
      "desponsate",
      "disglorify",
      "disgusted",
      "disgustedly",
      "disgustful",
      "disgustfully",
      "disgusting",
      "disgustingly",
      "disgustingness",
      "ensnaringly",
      "enwreathing",
      "homoousious",
      "humping",
      "imbreviating",
      "imbricating",
      "immerging",
      "infamizing",
      "loathful",
      "loathfully",
      "loathing",
      "loathingly",
      "loathsome",
      "oppugnant",
      "oragious",
      "ovarious",
      "polyphyletically",
      "preverifying",
      "ragesome",
      "raticidal",
      "repellent",
      "repellently",
      "replunges",
      "reprehensibly",
      "reprobative",
      "reprobatively",
      "reprobatory",
      "repugnant",
      "repugnantness",
      "repugned",
      "repulsed",
      "repulser",
      "repulsers",
      "repulsion",
      "repulsive",
      "repulsiveness",
      "repulsor",
      "repulsory",
      "sluicy",
      "snooling",
      "staminigerous",
      "superseding",
      "torpedinous",
      "uglifying"
  ],
  "dị iche": [
      "abalienated",
      "alienated",
      "counterpillar",
      "deferent",
      "deviant",
      "deviational",
      "deviatory",
      "differ",
      "differed",
      "differentiant",
      "differs",
      "difformed",
      "dissimilar",
      "divergement",
      "divergent",
      "isogamous",
      "nonvarious",
      "sective",
      "uncellar"
  ],
  "nhichapụ ahapu": [
      "abalienation"
  ],
  "abalon": [
      "abalones"
  ],
  "abam": [
      "abamp",
      "imber"
  ],
  "abamere": [
      "abampere",
      "abamperes"
  ],
  "akụ": [
      "abamps",
      "ardors",
      "arils",
      "arrowplate",
      "arrowroots",
      "arrows",
      "asset",
      "assets",
      "bankrolled",
      "bassing",
      "berg",
      "bergs",
      "clapholt",
      "clapnet",
      "founts",
      "jardon",
      "knox",
      "nuts",
      "nutsedge",
      "nutsedges",
      "palt",
      "shafts",
      "tck",
      "treasr",
      "treasure",
      "treasurership",
      "treasures",
      "tressour",
      "tressure",
      "tressures"
  ],
  "hapụ": [
      "aband",
      "ablauts",
      "abscind",
      "acquit",
      "adhibit",
      "allose",
      "alqueire",
      "disavow",
      "dismit",
      "forego",
      "forsay",
      "forsake",
      "forsar",
      "forsee",
      "forslake",
      "forspend",
      "freeish",
      "letgame",
      "lethe",
      "lett",
      "letten",
      "letup",
      "liberalise",
      "liberalize",
      "malease",
      "obmit",
      "olease",
      "omit",
      "omittable",
      "prelease",
      "reforsake",
      "relead",
      "release",
      "releaser",
      "releasor",
      "relegate",
      "releivo",
      "releve",
      "relever",
      "relinquish",
      "remit",
      "renounces",
      "rerelease",
      "saki",
      "underlease",
      "unhung",
      "unleal",
      "unride",
      "withholden"
  ],
  "gbahapụ": [
      "abandon",
      "forleit",
      "forslow"
  ],
  "agbahapụ": [
      "abandonable",
      "abandoners",
      "abandoning",
      "abandonment",
      "abandonments",
      "forsakes",
      "forsung",
      "forswore",
      "forsworn"
  ],
  "agbahapụwo": [
      "abandoned",
      "forsaken",
      "forsaker",
      "forsaking",
      "forsook"
  ],
  "gbahapụrụ": [
      "abandonedly",
      "abandoner",
      "deserted",
      "desertedly",
      "deserter"
  ],
  "gbahapu": [
      "abandonee",
      "abandum"
  ],
  "na-ahapụ": [
      "abandons",
      "abnegating",
      "aborning",
      "aforegoing",
      "berreaving",
      "forgoing",
      "forswearing",
      "leaving",
      "letups",
      "omening",
      "permissive",
      "relinquishes",
      "relinquishing",
      "surreys",
      "unleashing",
      "vacating"
  ],
  "mgbapụ": [
      "abannition",
      "ascape",
      "asylums",
      "baxter",
      "cirrigrade",
      "detune",
      "divesture",
      "eruptiveness",
      "escapado",
      "escapage",
      "escapement",
      "escapements",
      "excur",
      "flectional",
      "haploidies",
      "littling",
      "outplot",
      "outsmarts",
      "outstorm",
      "overcape",
      "preexplosion",
      "prorsal",
      "severities",
      "whipray"
  ],
  "ndiegwu": [
      "abantes",
      "abdominals",
      "abuttals",
      "agyria",
      "amercers",
      "aorists",
      "argylls",
      "argyrite",
      "argyrol",
      "aryans",
      "arpeggios",
      "augites",
      "avians",
      "aviarists",
      "babbools",
      "babied",
      "bactrites",
      "balked",
      "balking",
      "banewort",
      "bdelliums",
      "berkeleyite",
      "bibliotist",
      "byliner",
      "biliverdic",
      "boehmeria",
      "boehmites",
      "bogeymen",
      "bogeys",
      "bopyrid",
      "borborygmic",
      "bourgeois",
      "bourgeoisie",
      "bringal",
      "bringall",
      "brinjal",
      "bryozoans",
      "brombenzyl",
      "bromidic",
      "bromuret",
      "bromvoel",
      "cacodyls",
      "caenolestes",
      "caenozoic",
      "cajoling",
      "calombigas",
      "cardiorrhexis",
      "caudocephalad",
      "cavalieres",
      "cavallas",
      "cenozoic",
      "cestraciontes",
      "charadriiformes",
      "chauvinists",
      "chemosterilants",
      "chylopoiesis",
      "chytridiales",
      "chytridiose",
      "chungking",
      "cyanates",
      "cichlids",
      "craniotabes",
      "craniotomies",
      "crenothrix",
      "cresphontes",
      "cudava",
      "dabchicks",
      "danceress",
      "danseurs",
      "danseuses",
      "dasypaedes",
      "dermochelys",
      "derrickmen",
      "dictyotales",
      "dinichthys",
      "dithyrambos",
      "doyleys",
      "dolomedes",
      "dreikanters",
      "drepanoid",
      "eugenicists",
      "exterminatrix",
      "fagoters",
      "felworts",
      "fishways",
      "flubdubs",
      "gabardines",
      "gabby",
      "gabblers",
      "gabbros",
      "gaberdines",
      "galyacs",
      "galvanocauteries",
      "ganglioform",
      "ganglioneural",
      "ganglionic",
      "gangwayed",
      "gardevin",
      "gavelmen",
      "gibby",
      "ginkgoes",
      "gorinesses",
      "gowans",
      "guggles",
      "guglets",
      "gullies",
      "harmonicas",
      "herniotomies",
      "heterozygotes",
      "hiphuggers",
      "honkytonks",
      "hushpuppies",
      "yakking",
      "iatrotechnics",
      "yaupers",
      "interppoliesh",
      "jackhammers",
      "joggers",
      "jugging",
      "juggins",
      "jugginses",
      "jugglers",
      "juking",
      "kayoes",
      "kayoing",
      "kalymmaukion",
      "kalymmocyte",
      "kalyptra",
      "kalyptras",
      "kalkvis",
      "kalpaks",
      "kaoliangs",
      "kibitzers",
      "kinescoping",
      "kingcups",
      "kyrios",
      "kleptomaniacs",
      "labialising",
      "lackeying",
      "ladylintywhite",
      "lagorchestes",
      "lagothrix",
      "leptomeninx",
      "lyddites",
      "lienopancreatic",
      "limpers",
      "lindabrides",
      "llanos",
      "lordoses",
      "lucubrator",
      "lud",
      "ludefisk",
      "lulavs",
      "lullilooing",
      "luteotrophic",
      "magdalens",
      "mahjonggs",
      "maladministers",
      "malaxermen",
      "manhattans",
      "marchionesses",
      "marylanders",
      "marlinspike",
      "messeigneurs",
      "mootmen",
      "mordants",
      "musicians",
      "musterdevillers",
      "narraganset",
      "neoliths",
      "nig",
      "noncircumvallated",
      "osteectomies",
      "oudemian",
      "paedophilia",
      "pagurids",
      "palaeodictyoptera",
      "parvuli",
      "pedophilia",
      "phalansterian",
      "philodendrons",
      "philtres",
      "pyoid",
      "pissants",
      "plebicolist",
      "praters",
      "preattuning",
      "pterodactyls",
      "pussyfooting",
      "rappees",
      "rhyolites",
      "rhodizonic",
      "rhombohedrons",
      "rucervine",
      "saiyids",
      "sallymen",
      "salpingotomies",
      "salviniales",
      "saracens",
      "sarcocollin",
      "sebastichthys",
      "selenates",
      "selenides",
      "selensilver",
      "semishrubby",
      "sennegrass",
      "sherryvallies",
      "subofficers",
      "sultanas",
      "sultanesque",
      "teacupfuls",
      "tephromyelitic",
      "torpedomen",
      "tumblerlike",
      "umbrettes",
      "vaginalectomies",
      "vahines",
      "valkyries",
      "valkyrs",
      "vanaheim",
      "vandalroot",
      "vandykes",
      "vannermen",
      "vaudevillians",
      "vaudevillist",
      "velocipedes",
      "vespertiliones",
      "vicomtesses",
      "vikinglike",
      "violoncellists",
      "vireos",
      "voodooed",
      "vulcanizers",
      "wamefuls",
      "wannigans",
      "waverers",
      "wodgy",
      "wrymouths",
      "xenogenies",
      "xylans",
      "zebrinnies",
      "zitherists"
  ],
  "onyinye": [
      "abaris",
      "abbotric",
      "abbott",
      "aberdevine",
      "abider",
      "abjunctive",
      "abkar",
      "abogados",
      "abrook",
      "abrus",
      "affenpinscher",
      "allottery",
      "almagests",
      "almeries",
      "almoravid",
      "almoravides",
      "almshouse",
      "almsmoney",
      "alroot",
      "alvus",
      "aruspicy",
      "avowance",
      "avowant",
      "avowries",
      "awards",
      "bestowage",
      "bestowals",
      "bethankit",
      "bifidities",
      "birgand",
      "bobby",
      "boccis",
      "bockey",
      "bonification",
      "bounty",
      "bounties",
      "bovinity",
      "buccina",
      "carbunculation",
      "casuarinales",
      "cerebroparietal",
      "chesteine",
      "cicatrice",
      "compound",
      "contributary",
      "contribute",
      "contribution",
      "contributions",
      "contributory",
      "contributories",
      "crepance",
      "culerage",
      "darzee",
      "demesnial",
      "demy",
      "demob",
      "derfly",
      "dispowder",
      "donable",
      "donal",
      "donary",
      "donaries",
      "donat",
      "donatary",
      "donation",
      "donationes",
      "donations",
      "donatively",
      "donatives",
      "donator",
      "donatory",
      "doncy",
      "eelgrass",
      "eelgrasses",
      "endowers",
      "endowing",
      "endowment",
      "endowments",
      "enounces",
      "feazings",
      "foregift",
      "gabardine",
      "gabeler",
      "gaberdine",
      "garbardine",
      "genecor",
      "genevoise",
      "gerendum",
      "giffgaff",
      "gift",
      "gifted",
      "giftedly",
      "giftedness",
      "giftie",
      "gifts",
      "gifture",
      "giftware",
      "gipper",
      "gypper",
      "girshes",
      "giusto",
      "gleamiest",
      "gleamily",
      "glees",
      "glenoid",
      "gliddery",
      "glovey",
      "graces",
      "graticulation",
      "graticule",
      "gratiola",
      "harpocrates",
      "hebdomadal",
      "hoardward",
      "homodermy",
      "incitations",
      "kibitz",
      "limail",
      "limoid",
      "martenot",
      "matador",
      "matagory",
      "materia",
      "materializee",
      "materiarian",
      "matildas",
      "matral",
      "medimnus",
      "megadontic",
      "meshy",
      "montpelier",
      "morgengift",
      "oblation",
      "offbeats",
      "offer",
      "offeree",
      "offering",
      "offerings",
      "offertory",
      "offertorial",
      "offertories",
      "pacificating",
      "pacos",
      "pasta",
      "pfund",
      "philanthropine",
      "philanthropinum",
      "philatelic",
      "pynot",
      "pissoir",
      "platemark",
      "plauditory",
      "plop",
      "porrection",
      "praiseproof",
      "presentment",
      "presentness",
      "presents",
      "priapismic",
      "priapisms",
      "priapulid",
      "priapuloid",
      "priapulus",
      "priapuses",
      "prie",
      "prier",
      "priers",
      "prise",
      "prising",
      "prius",
      "privets",
      "privy",
      "privier",
      "priviest",
      "priviledge",
      "prize",
      "prizers",
      "prizes",
      "prizetaker",
      "prizing",
      "proappreciation",
      "prosstoa",
      "prostoa",
      "psammophilous",
      "psis",
      "psoadic",
      "psocine",
      "psoriasiform",
      "psoriatiform",
      "pugarees",
      "pugil",
      "quodlibet",
      "raspis",
      "runty",
      "souchet",
      "souushy",
      "subsidizations",
      "subspecialization",
      "substratospheric",
      "suraddition",
      "surpreciation",
      "taliage",
      "talipot",
      "tomin",
      "tribunitiary",
      "ungift"
  ],
  "ekwuru": [
      "abarticular",
      "abridgedly",
      "abrotine",
      "adits",
      "adumbrates",
      "adverbs",
      "affusedaffusing",
      "alliterated",
      "assagaied",
      "auriscopic",
      "bellied",
      "berates",
      "bespoken",
      "betusked",
      "bevined",
      "ceroma",
      "cultive",
      "deviants",
      "elixed",
      "encratic",
      "equatorwards",
      "erosible",
      "fielden",
      "hebraically",
      "highline",
      "liliated",
      "mordanted",
      "neuron",
      "oufought",
      "pledable",
      "provant",
      "readvocated",
      "sluiced",
      "telemetered",
      "telson",
      "verbified",
      "verrucated"
  ],
  "nkwarụ": [
      "abarticulation",
      "adverbial",
      "blemish",
      "blemished",
      "blemisher",
      "cactiform",
      "chuffiness",
      "crippied",
      "cumbrance",
      "debilissima",
      "debonairty",
      "debussy",
      "decadation",
      "decadence",
      "decadency",
      "decadent",
      "decadentism",
      "decadents",
      "decameral",
      "decamerous",
      "decidence",
      "decident",
      "decompression",
      "decrescence",
      "decretum",
      "defacement",
      "defect",
      "defecter",
      "defecters",
      "defectibility",
      "defectible",
      "defecting",
      "defectious",
      "defective",
      "defectively",
      "defectiveness",
      "defectless",
      "defectlessness",
      "defectology",
      "defectors",
      "defectoscope",
      "defects",
      "defectuous",
      "defoedation",
      "deformative",
      "deformedness",
      "deformism",
      "demipremise",
      "demisability",
      "depreciations",
      "disability",
      "disabilities",
      "disablement",
      "disableness",
      "disabling",
      "disabusal",
      "disabuses",
      "disaccordance",
      "disadvance",
      "disalign",
      "disamenity",
      "disanimate",
      "disarrangement",
      "disarrangements",
      "disarranges",
      "disarranging",
      "disarrest",
      "disavowal",
      "discastle",
      "discharity",
      "discomfiture",
      "discommune",
      "discommunity",
      "discomposedness",
      "discradle",
      "disdiaclastic",
      "disenabled",
      "disestablishment",
      "disfame",
      "disfigure",
      "disfigurement",
      "disfigurements",
      "disfigurer",
      "disfigures",
      "disformity",
      "disimprovement",
      "disunities",
      "falcular",
      "falderal",
      "felwort",
      "handicap",
      "handicapped",
      "handicapper",
      "handicapping",
      "handicaps",
      "inabilities",
      "incapacitated",
      "inconceivabilities",
      "infirmity",
      "infirmness",
      "intermastoid",
      "interpeal",
      "invalidness",
      "maimed",
      "maimedly",
      "maimedness",
      "malformation",
      "outfabled",
      "outwealth",
      "pallidity",
      "pallidness",
      "scabridity",
      "tractabilities",
      "unawkwardly",
      "unawkwardness"
  ],
  "wedata": [
      "abase",
      "ablate",
      "depreciate",
      "devaluate",
      "downgate",
      "downgrade",
      "downgraded",
      "downrange",
      "downsized",
      "downtrod",
      "humbugged",
      "humify",
      "humphed",
      "lowered",
      "lowish",
      "lowry",
      "lowrie",
      "minienize",
      "minimise",
      "minimize",
      "subindicate",
      "sublanate",
      "sublimize",
      "subnitrate"
  ],
  "kwadoro": [
      "abased",
      "abed",
      "abends",
      "accede",
      "acceded",
      "accinged",
      "accommodated",
      "accosted",
      "accreted",
      "adduced",
      "advocated",
      "affaires",
      "aliped",
      "alveated",
      "approved",
      "approvedly",
      "approver",
      "arided",
      "arrowed",
      "artificialize",
      "autonomist",
      "autonomize",
      "autonomousness",
      "autopsied",
      "autosled",
      "autotomize",
      "autunite",
      "cabineted",
      "cabinetted",
      "cawed",
      "componed",
      "condoned",
      "confirmed",
      "confirmee",
      "cooeed",
      "cooperated",
      "cooperite",
      "coopted",
      "corroboreed",
      "elided",
      "eluted",
      "embargoed",
      "embowered",
      "empaneled",
      "empanelled",
      "endothecial",
      "ensured",
      "entablatured",
      "entity",
      "equiparable",
      "favored",
      "favoured",
      "federate",
      "federated",
      "fitified",
      "homologated",
      "homologised",
      "homologized",
      "hosted",
      "isonomous",
      "landfast",
      "lapsided",
      "legitimatised",
      "legitimatized",
      "legitimised",
      "legitimized",
      "ligitimized",
      "monilated",
      "monographed",
      "monospored",
      "monosubstituted",
      "nasalized",
      "nidified",
      "palisaded",
      "powered",
      "premixed",
      "pretrain",
      "pretraining",
      "propended",
      "propending",
      "propends",
      "propined",
      "ratify",
      "ratified",
      "recommended",
      "recommissioned",
      "reserpinized",
      "sanatory",
      "sided",
      "sidelined",
      "sidled",
      "sophronized",
      "stablished",
      "suable",
      "subleased",
      "succoured",
      "superelated",
      "superendorsed",
      "supportable",
      "sustainedly",
      "taprooted",
      "validated",
      "viduated"
  ],
  "dị ala": [
      "abasedly",
      "condescendent",
      "depreciating",
      "descendible",
      "downcast",
      "downlike",
      "loiter",
      "low",
      "lowable",
      "lowbred",
      "lowder",
      "lowy",
      "lowigite",
      "lowishly",
      "lowly",
      "lowlier",
      "lowlihood",
      "menial",
      "nether",
      "presignificant",
      "subinferior"
  ],
  "nkwenye": [
      "abasedness",
      "abdications",
      "abridgement",
      "accedence",
      "accidencies",
      "accidies",
      "acclimatement",
      "acclivities",
      "accorders",
      "accosts",
      "accreditations",
      "accretions",
      "acknowledgements",
      "acknowledgments",
      "adamitical",
      "adamitism",
      "adance",
      "adinvention",
      "adjection",
      "adpromission",
      "adstipulation",
      "affenspalte",
      "affirmativeness",
      "afflation",
      "affusion",
      "affusions",
      "agreeability",
      "agrement",
      "agrements",
      "algesia",
      "allogeneity",
      "anticonformity",
      "anticonformities",
      "antiscepticism",
      "antisensuality",
      "antisensuously",
      "antisensuousness",
      "antithesis",
      "approvable",
      "approval",
      "aseismicity",
      "assent",
      "assentation",
      "assents",
      "assertiveness",
      "assiduities",
      "assuages",
      "assurgency",
      "atonicity",
      "atresy",
      "attalid",
      "attriteness",
      "audacity",
      "autocraticalness",
      "autocriticism",
      "belie",
      "belied",
      "belief",
      "believability",
      "believable",
      "believableness",
      "boldin",
      "borism",
      "bromisms",
      "cenosity",
      "certifiability",
      "certifiableness",
      "chaussures",
      "cleromancy",
      "coaffirmation",
      "coeligenous",
      "coerces",
      "cognizability",
      "coheretic",
      "coindication",
      "collegialism",
      "collegiality",
      "colliquativeness",
      "colloquialism",
      "colloquiality",
      "colloquialness",
      "compresence",
      "concent",
      "concentual",
      "conceptible",
      "conceptiveness",
      "conceptualisation",
      "concession",
      "concessionaires",
      "concessionaries",
      "concessions",
      "concessiveness",
      "conciliarism",
      "concipiency",
      "concomitance",
      "concomitancy",
      "concurrence",
      "concurrency",
      "condensance",
      "condescendence",
      "condescensions",
      "condiction",
      "condignity",
      "condonance",
      "condonation",
      "condonations",
      "condonement",
      "conducibly",
      "conduciveness",
      "confederations",
      "conferrable",
      "confervaceous",
      "confidences",
      "confidentness",
      "confirmability",
      "confirmation",
      "confirmational",
      "confirmations",
      "confirmative",
      "confirmatively",
      "confirmedness",
      "confirmity",
      "confirmment",
      "confisticating",
      "confix",
      "confluences",
      "confraternity",
      "confraternities",
      "conification",
      "conjectures",
      "connivances",
      "conopid",
      "conscionable",
      "conscionableness",
      "conscription",
      "conscriptional",
      "conscripttion",
      "consenescence",
      "consenescency",
      "consension",
      "consensual",
      "consensually",
      "consent",
      "consentaneous",
      "consentaneously",
      "consentfully",
      "consentience",
      "consentingly",
      "consentively",
      "consentment",
      "consignataries",
      "consortship",
      "constitutiveness",
      "consubstantiality",
      "consularity",
      "consummativeness",
      "consumptiveness",
      "contiguity",
      "contiguousness",
      "contorsive",
      "contrantiscion",
      "contrariousness",
      "contriteness",
      "controvert",
      "controvertibility",
      "contund",
      "conusance",
      "conviction",
      "convictions",
      "convictiveness",
      "convincedness",
      "convincibility",
      "convivial",
      "conviviality",
      "convolutions",
      "corrodibility",
      "counterstatement",
      "credence",
      "credenciveness",
      "credendum",
      "credibilities",
      "credible",
      "credibleness",
      "creditive",
      "credulities",
      "creed",
      "creedal",
      "creedalism",
      "creeded",
      "creedmore",
      "creolism",
      "crotalism",
      "crustiness",
      "cullibility",
      "debonairity",
      "decadianome",
      "deceptory",
      "definitiveness",
      "dehiscence",
      "demitranslucence",
      "demoraliser",
      "denitrification",
      "deposing",
      "depositation",
      "deposition",
      "disaccord",
      "disaccredit",
      "disaffiliation",
      "disaffirmation",
      "disagglomeration",
      "disapproval",
      "disapprovals",
      "disassiduity",
      "disavowance",
      "disavowment",
      "disavows",
      "disceptation",
      "discerpibleness",
      "discodactylous",
      "discommendableness",
      "discomposure",
      "disconcertedness",
      "disconcertment",
      "disconfirm",
      "disconfirmation",
      "discongruity",
      "disconsent",
      "disconsideration",
      "discredit",
      "discredits",
      "disedification",
      "disfaith",
      "disfavors",
      "disherison",
      "disheritment",
      "disinclination",
      "disinclinations",
      "disincrust",
      "disinvolvement",
      "disobligingness",
      "disordinance",
      "disproval",
      "dissuasion",
      "disusance",
      "dogmatisation",
      "doleance",
      "emanatism",
      "empiricism",
      "emplastration",
      "emporetic",
      "endearments",
      "endorsation",
      "endorsement",
      "endorsements",
      "faldistory",
      "firmation",
      "foreassurance",
      "geldability",
      "hypercriticism",
      "yieldableness",
      "yieldance",
      "inconceivability",
      "inconfusion",
      "inconfutable",
      "incorporalness",
      "incredibility",
      "incumbencies",
      "intendible",
      "intercept",
      "intercision",
      "intercombination",
      "intercommonable",
      "intercontradiction",
      "interconvertible",
      "intercrust",
      "intercurrence",
      "interdenominational",
      "interdenominationalism",
      "interinsurance",
      "interinsurer",
      "interjudgment",
      "interluency",
      "interment",
      "internecion",
      "interpolity",
      "interreceive",
      "interregency",
      "interreges",
      "interregimental",
      "interregnum",
      "interrenalism",
      "interresistibility",
      "intersusceptation",
      "intertransmission",
      "intertribal",
      "intranscalency",
      "intransitiveness",
      "intransmissible",
      "knottiness",
      "legibly",
      "loginesses",
      "misallowance",
      "misbelief",
      "miscoloration",
      "misputting",
      "monophysitism",
      "mutined",
      "muting",
      "mutiny",
      "nonaffirmation",
      "nonamazement",
      "nonassonance",
      "noncombustibility",
      "noncommitment",
      "noncommittalism",
      "noncommittalness",
      "nonconfession",
      "nonconjugation",
      "nonconsignment",
      "nonconsistorial",
      "noncontradiction",
      "nonconviction",
      "noncorroboration",
      "noncredibility",
      "nonfrangibility",
      "nonfusibility",
      "noninsertion",
      "nonopposition",
      "nonpermission",
      "nonstipulation",
      "nonvalidation",
      "nonvendibility",
      "nonverticality",
      "nonverticalness",
      "nullification",
      "opsonification",
      "overbelief",
      "overthrust",
      "oxidability",
      "oxidizability",
      "parvanimity",
      "pedotrophy",
      "pernancy",
      "preacceptance",
      "preconfirmation",
      "preconsumption",
      "predesirous",
      "predisadvantage",
      "predistrust",
      "preeffect",
      "preelection",
      "preexhaustion",
      "preexposures",
      "prenotification",
      "preresponsibility",
      "presuggestion",
      "presumption",
      "presumptions",
      "presumptive",
      "pretabulation",
      "priestianity",
      "proinsurance",
      "promitosis",
      "propolitics",
      "propulsity",
      "provenance",
      "ptyalism",
      "pulsatility",
      "putrescibility",
      "putridness",
      "ratification",
      "reaffirmations",
      "reassertion",
      "rebutment",
      "recompliance",
      "reconfirmation",
      "reconfirmations",
      "reeligibility",
      "reeligibleness",
      "releasability",
      "releasibility",
      "reliquism",
      "rendible",
      "semivitrification",
      "sinophilism",
      "solidifiability",
      "solidification",
      "stagflation",
      "stipulation",
      "stipulations",
      "subhypothesis",
      "substantialization",
      "substantiations",
      "substantiveness",
      "subsureties",
      "superbelievable",
      "supersatisfaction",
      "supersatisfy",
      "supersensible",
      "supersensibleness",
      "supersilent",
      "supposition",
      "suppositionary",
      "surrection",
      "tenderability",
      "terminologies",
      "transcendible",
      "unaccommodatingness",
      "unaffiliation",
      "unaffirmation",
      "unbackward",
      "unbiliousness",
      "uncleansedness",
      "unclerical",
      "unclimactic",
      "uncommendableness",
      "unconfess",
      "unconscionableness",
      "unconstellated",
      "underventilation",
      "unfirmness",
      "unoppositional",
      "unperseverance",
      "unscrupulosity",
      "unstaginess",
      "unsteadiness",
      "unsulfureness",
      "untowardness",
      "untranscendent",
      "unvitreosity",
      "vendibilities",
      "vendibleness",
      "ventrosity",
      "verification",
      "verifications",
      "verificative",
      "verificatory",
      "volitional"
  ],
  "mmechuihu": [
      "abasement",
      "abjectedness",
      "appallment",
      "befoulment",
      "begrace",
      "butolism",
      "cenesthesia",
      "cenospecies",
      "cynosures",
      "demulsification",
      "disappropriation",
      "disgracement",
      "displeasures",
      "embarrassment",
      "endpleasure",
      "humiliation",
      "humiliations",
      "jennerization",
      "misevaluation",
      "nonextermination"
  ],
  "mmebi iwu": [
      "abasements",
      "abbotcies",
      "abnormalised",
      "annulment",
      "atrienses",
      "awlessness",
      "badnesses",
      "blunder",
      "contrarieties",
      "contravention",
      "corruptor",
      "crimination",
      "criminologies",
      "deamidation",
      "debilitates",
      "debilitations",
      "debullition",
      "decadarchy",
      "declinational",
      "deflagrations",
      "deflationary",
      "delinition",
      "demilitarisation",
      "demilitarising",
      "demilitarization",
      "deminudity",
      "deperition",
      "derangement",
      "derangements",
      "detracter",
      "detrimentalness",
      "evilnesses",
      "expromission",
      "illegalisation",
      "illegality",
      "illegalities",
      "illegalization",
      "illegalness",
      "illicitness",
      "imperturbation",
      "impropriation",
      "infestment",
      "infraction",
      "infractions",
      "infraglacial",
      "infringements",
      "infringes",
      "irremission",
      "lawlessness",
      "malexecution",
      "malignance",
      "misbill",
      "misbilling",
      "misgovernance",
      "offward",
      "offwards",
      "outacts",
      "outbringing",
      "outlawries",
      "outpoison",
      "outraces",
      "outranges",
      "overdevelopment",
      "perjurement",
      "perlocution",
      "perpession",
      "polluters",
      "sinistration",
      "spooneyness",
      "sporangiform",
      "sporogony",
      "transgressed",
      "transgression",
      "transgressional",
      "transgressions",
      "transgressors",
      "trespassory",
      "uncorruptedness",
      "uncorruptness",
      "violatory",
      "wicked",
      "wickedness",
      "wrongdo"
  ],
  "ihe ojoo": [
      "abaser",
      "abasic",
      "abastral",
      "abhorrences",
      "abhorrent",
      "abysmal",
      "abominability",
      "abominable",
      "abominated",
      "abominator",
      "abrim",
      "abstersiveness",
      "adversariness",
      "aggradational",
      "aggrades",
      "aggrandiser",
      "aggravator",
      "ahorse",
      "antrorsely",
      "badarian",
      "badchan",
      "baddish",
      "baddishness",
      "badgemen",
      "badgerly",
      "bads",
      "bardcraft",
      "bastardizes",
      "befile",
      "befoul",
      "begaudy",
      "bemusedly",
      "bepurple",
      "bevil",
      "bezant",
      "bigness",
      "bignesses",
      "bignoniaceous",
      "biohazard",
      "blaggard",
      "blague",
      "blandish",
      "blaunner",
      "blunderful",
      "blunter",
      "boerdom",
      "brisque",
      "brittler",
      "broguish",
      "bromous",
      "chagrined",
      "chagrinned",
      "chagrins",
      "cowgrass",
      "czardases",
      "damnous",
      "degrain",
      "deprave",
      "deruinate",
      "deserticolous",
      "detersive",
      "detrusive",
      "direfulness",
      "disgarnish",
      "disgorge",
      "dosser",
      "ecraseur",
      "endevil",
      "enkindler",
      "enkindles",
      "ensculpture",
      "ervil",
      "evil",
      "evilmouthed",
      "evilness",
      "evils",
      "evilwishing",
      "favillous",
      "flavous",
      "fluvious",
      "foppishness",
      "fouettes",
      "foul",
      "fouled",
      "foulminded",
      "fouls",
      "foulsome",
      "grimful",
      "grimy",
      "gruesome",
      "gruesomer",
      "gruesomest",
      "haranguer",
      "harangues",
      "harmotomic",
      "harmproof",
      "harpier",
      "harquebusade",
      "harquebuse",
      "harrage",
      "haustellous",
      "hideous",
      "hideousness",
      "homotaxeous",
      "imprecator",
      "imprecators",
      "incivilities",
      "inique",
      "liquesce",
      "loasaceous",
      "malconformation",
      "malfeasant",
      "malignancies",
      "maligner",
      "maligns",
      "maltreats",
      "malversation",
      "malverse",
      "medusal",
      "mischiefful",
      "misculture",
      "miserabilism",
      "miserabilistic",
      "misexposition",
      "misexpound",
      "misfortunate",
      "misgrowth",
      "misplant",
      "monstrousness",
      "mortice",
      "nasty",
      "notoriousness",
      "obsignatory",
      "ominous",
      "outcavil",
      "oxamic",
      "oxphony",
      "pagandom",
      "pangamy",
      "pangamic",
      "pangamous",
      "pangenic",
      "pangyrical",
      "panurgy",
      "perfervent",
      "perfervidness",
      "perhazard",
      "perihernial",
      "perilunes",
      "perirenal",
      "perjures",
      "pernicion",
      "pessomancy",
      "pestersome",
      "phaenomenal",
      "phytic",
      "plang",
      "plangorous",
      "poricidal",
      "prickliness",
      "pulicides",
      "ramulous",
      "rucky",
      "ruesome",
      "scandaliser",
      "scandalization",
      "scandalmongering",
      "scandalmonging",
      "scandent",
      "sciomantic",
      "sclent",
      "scoundrel",
      "scoundrelism",
      "scoundrelship",
      "scurrier",
      "snasty",
      "soriferous",
      "spoucher",
      "subnormality",
      "taintedness",
      "thuggeries",
      "transnormal",
      "tzardoms",
      "ugliness",
      "uglinesses",
      "unacerbic",
      "unhideousness",
      "unvexatious",
      "vagarity",
      "vassality",
      "venomly",
      "verminy",
      "vexatious",
      "viciousness",
      "vignin",
      "vile",
      "vilely",
      "vileness",
      "villainy",
      "villainous",
      "villainousness",
      "vinolence",
      "whimsicalities",
      "wrecky",
      "wretch",
      "wronger"
  ],
  "ihe mgbochi": [
      "abasers",
      "ammonifier",
      "antiarins",
      "antiasthmatic",
      "antibodies",
      "antiboss",
      "antient",
      "antiepicenter",
      "antierosive",
      "antifaction",
      "antifoggant",
      "antifogmatic",
      "antilogies",
      "antiparalytic",
      "antiparasitical",
      "antiparticles",
      "antipastic",
      "antiperspirant",
      "antiperspirants",
      "antiphoner",
      "antiphons",
      "antiphrastical",
      "antiplague",
      "antiplastic",
      "antipoints",
      "antipolitics",
      "antipragmatical",
      "antiprism",
      "antirabic",
      "antirabies",
      "antirationalist",
      "antireactionaries",
      "antirent",
      "antiresonator",
      "antiutilitarian",
      "antivermicular",
      "antivice",
      "barcone",
      "bardship",
      "baryon",
      "barlock",
      "barrator",
      "barrer",
      "barricader",
      "barricades",
      "barricoes",
      "barrier",
      "barriers",
      "barringer",
      "bastardization",
      "berrier",
      "binders",
      "binnacles",
      "birotatory",
      "bistorts",
      "blandiloquence",
      "blockier",
      "blocklike",
      "bludgeoner",
      "bludger",
      "bodstick",
      "bollards",
      "bonzer",
      "bordels",
      "bounder",
      "bounders",
      "bracherer",
      "brachets",
      "brack",
      "braker",
      "bridgetree",
      "brier",
      "brierroot",
      "briers",
      "burrier",
      "buttress",
      "cachinnator",
      "cacotrophy",
      "canstick",
      "capsulitis",
      "catbriers",
      "cauls",
      "cestraction",
      "chainplate",
      "cyphellate",
      "clampers",
      "clysis",
      "clonorchiasis",
      "colotomy",
      "comism",
      "concocter",
      "constrainer",
      "contingence",
      "contingency",
      "contingencies",
      "contingents",
      "contragredience",
      "contrail",
      "contraposit",
      "contrapositives",
      "contraprops",
      "contrivancy",
      "countermeasures",
      "counterpoint",
      "counterpoints",
      "countersense",
      "craniectomy",
      "craniom",
      "criers",
      "curbers",
      "curbs",
      "curdle",
      "curdler",
      "curdlers",
      "curdles",
      "currier",
      "currieries",
      "curriers",
      "curtaining",
      "curvate",
      "curvative",
      "curvature",
      "curvatures",
      "defiber",
      "detachableness",
      "deterrer",
      "detrusor",
      "embargoes",
      "embargos",
      "embarque",
      "enchainements",
      "encrimson",
      "encroachments",
      "entanglements",
      "epidermical",
      "flapperism",
      "foldcourse",
      "forints",
      "formants",
      "fornices",
      "furriers",
      "girding",
      "grecism",
      "halterproof",
      "handcarts",
      "haplonts",
      "haranguers",
      "hashery",
      "hedgetaper",
      "hemiclastic",
      "herpetic",
      "hiccoughs",
      "hinderlings",
      "hinderlins",
      "hypercycle",
      "hyperspherical",
      "hurdle",
      "hurlock",
      "immunises",
      "impeder",
      "impeders",
      "impediment",
      "impedimentary",
      "impediments",
      "impedition",
      "impendent",
      "impingement",
      "imprime",
      "inceptors",
      "incontraction",
      "insinuator",
      "instigation",
      "intercepts",
      "intermundium",
      "interstices",
      "intertex",
      "inwalls",
      "irradiator",
      "irruptions",
      "kerbs",
      "lacework",
      "lamasery",
      "lancets",
      "lanciform",
      "lankier",
      "lascars",
      "limitaries",
      "limiter",
      "limiters",
      "limners",
      "manacles",
      "mitoses",
      "momisms",
      "mopusses",
      "movent",
      "obstacle",
      "obstant",
      "obstructer",
      "obstructor",
      "overdares",
      "overrestriction",
      "pacesetter",
      "pacesetters",
      "pacificator",
      "padder",
      "palliament",
      "pamperedness",
      "pannellation",
      "panotype",
      "parapet",
      "parodyproof",
      "pastosity",
      "perrier",
      "petticoats",
      "pickproof",
      "pimpernel",
      "pimpernels",
      "piscatorial",
      "placaters",
      "placets",
      "plagiaries",
      "plagium",
      "plotproof",
      "porphyrogeniture",
      "prancers",
      "precourse",
      "predispersion",
      "preprohibition",
      "prequestion",
      "presphygmic",
      "pulmotors",
      "punstress",
      "rimption",
      "rumpot",
      "shuttlecock",
      "shuttlecocked",
      "snaphance",
      "snipperty",
      "spirket",
      "stragulum",
      "subletter",
      "tapstress",
      "tarriers",
      "towcock",
      "treacles",
      "unbracelet",
      "undertint",
      "unfragile",
      "unlashes",
      "upcourse",
      "veiledness",
      "verier",
      "vernacles",
      "waldenses",
      "wrangler"
  ],
  "na-eweda ala": [
      "abases",
      "abasing"
  ],
  "ghaa": [
      "abashed",
      "bared",
      "blots",
      "bursera",
      "defuze",
      "denasalize",
      "denitrize",
      "grate",
      "greener",
      "mashed",
      "rears",
      "recuses",
      "redeed",
      "refringe",
      "rubiate",
      "snaste",
      "snathes",
      "trink",
      "whank"
  ],
  "nzuzu": [
      "abashedly",
      "abscise",
      "abscision",
      "abscondence",
      "abstruseness",
      "abstrusenesses",
      "abstrusity",
      "absurd",
      "absurder",
      "absurdest",
      "absurdity",
      "absurdities",
      "absurdly",
      "absurdness",
      "absurdum",
      "astuteness",
      "babbishly",
      "befool",
      "befoolment",
      "befools",
      "befuddlement",
      "blotchiness",
      "blurredness",
      "blurriness",
      "bolly",
      "boobishness",
      "brawnedness",
      "brinkmanship",
      "brinksmanship",
      "brusqueness",
      "celsitude",
      "chalcidic",
      "chalcomancy",
      "chazy",
      "cinefaction",
      "cravenness",
      "craziness",
      "currishness",
      "decoke",
      "dementedness",
      "disensanity",
      "drouthy",
      "drouthiness",
      "dullity",
      "encumbrous",
      "erumpent",
      "flemish",
      "flukiness",
      "folly",
      "follying",
      "follyproof",
      "fooless",
      "foolfish",
      "foolfishes",
      "foolhardihood",
      "foolhardily",
      "foolhardiness",
      "foolhardiship",
      "foolheadedness",
      "foolify",
      "fooling",
      "foolish",
      "foolishly",
      "foolishness",
      "foolproof",
      "foolproofness",
      "foolscap",
      "foolscaps",
      "foolship",
      "foulness",
      "frenziedness",
      "frivolous",
      "frivolousness",
      "frogginess",
      "frumpishness",
      "fumishness",
      "golly",
      "idence",
      "idiocy",
      "idiocyclophanous",
      "idiocies",
      "idiocrasy",
      "idiocratic",
      "idiogenous",
      "idion",
      "idiosome",
      "idiotcy",
      "idiotcies",
      "idiotic",
      "idioticalness",
      "idiotise",
      "idiotism",
      "idiotisms",
      "idiotry",
      "idoneousness",
      "ignobleness",
      "ignoblesse",
      "ilks",
      "illth",
      "ilth",
      "imbruing",
      "impollute",
      "imprecision",
      "infamation",
      "infamized",
      "infatuated",
      "infatuatedly",
      "infatuatedness",
      "infatuation",
      "infelicities",
      "innuate",
      "insipidity",
      "irascibleness",
      "irishness",
      "irksomeness",
      "irriguousness",
      "lamely",
      "lasciviousness",
      "limberest",
      "limbiest",
      "limbous",
      "limivorous",
      "limnophilous",
      "limpish",
      "litheness",
      "lumpiness",
      "luscious",
      "lusciousness",
      "lushness",
      "maddeningness",
      "misanalyzely",
      "miscasualty",
      "miscegine",
      "mischancy",
      "miscite",
      "miscites",
      "miscreance",
      "miscreation",
      "miscredulity",
      "misdeem",
      "misdentition",
      "misgivings",
      "misingenuity",
      "misposition",
      "misproposal",
      "mispursuit",
      "mistraces",
      "misture",
      "molly",
      "murky",
      "nervish",
      "nervure",
      "nesty",
      "nold",
      "nongrass",
      "nonseditiously",
      "nonseditiousness",
      "nonsensation",
      "nonsensibility",
      "nonsensible",
      "nonsensibleness",
      "nonsensic",
      "nonsensicality",
      "nonsensicalness",
      "nonsensitively",
      "nonsensitiveness",
      "nonsententiously",
      "nonsententiousness",
      "nonserious",
      "nonseriously",
      "nonseriousness",
      "nonsymphonious",
      "nonsimulation",
      "nonsynoptical",
      "nonsolicitousness",
      "nonspaciousness",
      "nonspheral",
      "nonspirituousness",
      "nonspuriousness",
      "nonsubconsciousness",
      "nonsuggestion",
      "nonsusceptiness",
      "nonsusceptivity",
      "nonsuspect",
      "nonsuspensiveness",
      "nonsweating",
      "nullibiety",
      "occlusive",
      "occlusiveness",
      "occlusor",
      "overfoolish",
      "overfoolishness",
      "perspicacity",
      "pudginess",
      "rascal",
      "ripely",
      "scabish",
      "sciomancy",
      "scopulousness",
      "scottishness",
      "scoundrelly",
      "scraggedness",
      "scrumptiousness",
      "scuggery",
      "scupful",
      "scurfiness",
      "scurrilousness",
      "scutal",
      "silly",
      "sillyhood",
      "sillyhow",
      "sillyish",
      "sillyism",
      "silliness",
      "silverness",
      "synoeciousness",
      "skolly",
      "slobber",
      "snithy",
      "snobber",
      "snobbess",
      "snobbish",
      "snobdom",
      "snobism",
      "snobocracy",
      "snooty",
      "snooziness",
      "spendthriftness",
      "spongiousness",
      "squamoseness",
      "stolidity",
      "strangury",
      "stupendous",
      "stupidest",
      "stupidish",
      "stupidity",
      "stupidities",
      "stupidly",
      "stupidness",
      "stupor",
      "stupors",
      "stupose",
      "stupration",
      "thugdom",
      "thuggess",
      "tomfoolishness",
      "umbraciousness",
      "uncrisp",
      "unfoolish",
      "unglittery",
      "unjolly",
      "unstupid",
      "unstupidly",
      "unstupidness",
      "unsurplice",
      "unvoracious",
      "unwise",
      "unwisely",
      "vagulous",
      "vulgare",
      "vulgars",
      "vulgarwise",
      "vulgates",
      "vulgo",
      "vulguses",
      "vulnose",
      "vulval",
      "vulvocrural",
      "wambliness",
      "waspiness",
      "wasterfulness",
      "whiggess",
      "whiggishness",
      "whimsicality",
      "whimsicalness",
      "whizziness",
      "whute",
      "wigdom",
      "wiggishness",
      "wilfulness",
      "wiliness",
      "wisecracks",
      "wistful",
      "wistfulness",
      "witterness",
      "witting",
      "wittingite",
      "wittolly",
      "wizenedness"
  ],
  "mbibi": [
      "abashedness",
      "affrontee",
      "almohades",
      "amputator",
      "arrgt",
      "arrhizal",
      "aspersions",
      "bacillicide",
      "baybush",
      "baygall",
      "beshadow",
      "beshadows",
      "besmirch",
      "besmooths",
      "besotment",
      "bespatters",
      "bespurt",
      "bewreck",
      "biodegradation",
      "brattle",
      "brummagen",
      "casehardening",
      "catabasion",
      "corrasion",
      "damascener",
      "damaskeening",
      "damenization",
      "damndests",
      "damnifying",
      "dawdles",
      "debarration",
      "debases",
      "debellate",
      "debordment",
      "deburr",
      "decadrachm",
      "decandrous",
      "decarbonising",
      "decarnate",
      "decastere",
      "decastylos",
      "decasualise",
      "decatholicize",
      "declasse",
      "declassee",
      "decretorial",
      "decumanus",
      "defatigation",
      "defatting",
      "deglutinating",
      "degradability",
      "degradation",
      "degradations",
      "degradement",
      "degraduation",
      "delapsion",
      "delassement",
      "demast",
      "dematerialisation",
      "dematerialise",
      "dematerialising",
      "demibrute",
      "demiracle",
      "demnition",
      "demobilisation",
      "demobilization",
      "demobilizations",
      "demolishment",
      "demolition",
      "demolitionist",
      "deossification",
      "depasturation",
      "depasture",
      "deplorability",
      "depravation",
      "depuration",
      "deraignment",
      "desmodont",
      "despoilment",
      "despoilments",
      "despouse",
      "destitution",
      "destoolment",
      "destress",
      "destroyer",
      "destruction",
      "destructional",
      "destructionism",
      "destructionist",
      "destructions",
      "destructivism",
      "destructivity",
      "destructory",
      "detrition",
      "detruncation",
      "detrusion",
      "devaluation",
      "devast",
      "devastation",
      "devastations",
      "devastator",
      "devitalisation",
      "devocalization",
      "disbarment",
      "disbarments",
      "discession",
      "disharmonised",
      "disintegration",
      "dismantlement",
      "dismastment",
      "dogedoms",
      "doomage",
      "doombook",
      "doomer",
      "doomfully",
      "doomfulness",
      "doomlike",
      "dooms",
      "doomsayer",
      "doomsman",
      "doomstead",
      "doomster",
      "dorsomedial",
      "dorsomesal",
      "dumfounderment",
      "enddamage",
      "enrobement",
      "envapor",
      "exteriorisation",
      "extirpation",
      "extrinsicalness",
      "extrinsication",
      "havoc",
      "kashering",
      "landwrack",
      "langsettle",
      "mayhap",
      "malshapen",
      "misbrand",
      "morbility",
      "mumpishness",
      "murrion",
      "mutescence",
      "mutilation",
      "obelion",
      "oblivescence",
      "offscouring",
      "offscourings",
      "outblaze",
      "outbreath",
      "outdrop",
      "outserts",
      "outsins",
      "perishment",
      "perlustration",
      "pharisaicalness",
      "posthumousness",
      "ramosity",
      "ramosities",
      "ravage",
      "ravages",
      "ravaging",
      "reprehensory",
      "ritratto",
      "ruchings",
      "ruction",
      "rufflement",
      "ruin",
      "ruinable",
      "ruination",
      "ruinations",
      "ruinator",
      "ruiner",
      "ruinlike",
      "sorbability",
      "torpidness",
      "torquers",
      "unharrowed",
      "unshading",
      "unsharp",
      "volatilisation",
      "wastages",
      "wreaks"
  ],
  "abashị": [
      "abashes"
  ],
  "ịkụda": [
      "abashing",
      "damasking",
      "queering",
      "thwacking"
  ]
}

================================================
FILE: __tests__/api-json.test.ts
================================================
import isEqual from 'lodash/isEqual';
import { NO_PROVIDED_TERM } from '../src/shared/constants/errorMessages';
import { searchTerm } from './shared/commands';

describe('JSON Dictionary', () => {
  describe('/GET words', () => {
    it.skip('return back word information', async () => {
      const keyword = 'agụū';
      const res = await searchTerm(keyword);
      expect(res.status).toEqual(200);
      Object.keys(res.body).forEach((key) => {
        expect(['(agụū) -gụ', '-gụ agụū', 'agụū mmīli', keyword]).toContain(key);
      });
      expect(res.body[keyword][0].wordClass).toEqual('NNC');
    });

    it('return an error for searching no word', async () => {
      const res = await searchTerm();
      expect(res.status).toEqual(400);
      expect(res.body.error).toEqual(NO_PROVIDED_TERM);
    });

    it.skip('return the same term information', async () => {
      const { status, body: normalizeData } = await searchTerm('ndi ndi');
      expect(status).toEqual(200);
      const { status: rawStatus, body: rawData } = await searchTerm('ndị ndi');
      expect(rawStatus).toEqual(200);
      expect(isEqual(normalizeData, rawData)).toEqual(true);
    });

    it('return term using variation', async () => {
      const res = await searchTerm('-mu-mù');
      expect(res.status).toEqual(200);
      expect(res.body['-mụ-mù']).toHaveLength(1);
    });
  });
});


================================================
FILE: __tests__/api-mongo.test.ts
================================================
import mongoose from 'mongoose';
import { forEach, has, isEqual, uniqBy, some, every } from 'lodash';
import stringSimilarity from 'string-similarity';
import diacriticless from 'diacriticless';
import { wordSchema } from '../src/models/Word';
import WordClass from '../src/shared/constants/WordClass';
import {
  WORD_KEYS_V1,
  WORD_KEYS_V2,
  EXAMPLE_KEYS_V1,
  EXCLUDE_KEYS,
  INVALID_ID,
  NONEXISTENT_ID,
  MAIN_KEY,
} from './shared/constants';
import { getWords, getWord, getWordsV2, getWordV2 } from './shared/commands';
import { expectUniqSetsOfResponses } from './shared/utils';
import createRegExp from '../src/shared/utils/createRegExp';
import { createDbConnection, handleCloseConnection } from '../src/services/database';
import Tenses from '../src/shared/constants/Tenses';
import { IncomingWord as WordType } from '../src/types';
import WordClassEnum from '../src/shared/constants/WordClassEnum';

jest.unmock('mongoose');

const { ObjectId } = mongoose.Types;

describe('MongoDB Words', () => {
  describe('mongodb collection', () => {
    it('populate mongodb with words', async () => {
      const connection = createDbConnection();
      const Word = connection.model('Word', wordSchema);
      const word = {
        word: 'word',
        definitions: [
          {
            wordClass: 'NNC',
            definitions: ['first definition', 'second definition'],
          },
        ],
        dialects: [
          {
            variations: [],
            dialects: ['NSA'],
            pronunciation: '',
            word: 'dialectalWord',
          },
        ],
        examples: [new ObjectId(), new ObjectId()],
        stems: [],
        tenses: {},
      };
      const validWord = new Word(word);
      const savedWord = await validWord.save();
      await handleCloseConnection(connection);
      expect(savedWord.id).not.toEqual(undefined);
      expect(savedWord.word).toEqual('word');
      // @ts-expect-error wordClass
      expect(savedWord.definitions[0].wordClass).toEqual('NNC');
      expect(savedWord.tenses).not.toEqual(undefined);
      const wordRes = await getWord(savedWord.id, { dialects: true }, {});
      expect(wordRes.status).toEqual(200);
      expect(wordRes.body.dialects.dialectalWord).not.toEqual(undefined);
      const v2WordRes = await getWordV2(savedWord.id, { dialects: true }, {});
      expect(v2WordRes.status).toEqual(200);
      expect(v2WordRes.body.data.dialects[0].word).toEqual('dialectalWord');
    });

    it('fail populate mongodb with incorrect variations', async () => {
      const connection = createDbConnection();
      const Word = connection.model('Word', wordSchema);
      const word = {
        word: 'word',
        definitions: [
          {
            wordClass: 'NNC',
            definitions: ['first definition', 'second definition'],
          },
        ],
        dialects: {
          variations: [],
          dialects: ['mismatch'],
          pronunciation: '',
          word: 'dialectalWord',
        },
        examples: [new ObjectId(), new ObjectId()],
        stems: [],
      };
      const validWord = new Word(word);
      await validWord.save().catch(async (err) => {
        await handleCloseConnection(connection);
        expect(err.message.includes('dialects')).toEqual(true);
      });
    });

    it('throw an error for invalid data', async () => {
      const connection = createDbConnection();
      const Word = connection.model('Word', wordSchema);
      const word = {
        definitions: [
          {
            wordClass: 'n.',
            definitions: ['first definition', 'second definition'],
          },
        ],
        examples: ['first example'],
        stems: [],
      };
      const validWord = new Word(word);
      await validWord.save().catch(async (err) => {
        await handleCloseConnection(connection);
        expect(err).not.toEqual(undefined);
      });
    });
  });

  describe('/GET mongodb words V1', () => {
    it('return word information', async () => {
      const keyword = 'bia';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(2);
      forEach(res.body, (word) => {
        Object.keys(word).forEach((key) => {
          expect(WORD_KEYS_V1.includes(key)).toBeTruthy();
        });
      });
    });

    it('return back word information by searching definition', async () => {
      const keyword = 'smallpox';
      const words = ['kịtịkpā', 'ùlì', 'ajō ọfịa'];
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      forEach(res.body, (word) => expect(words).toContain(word.word));
    });

    it("return back 'king' documents", async () => {
      const keyword = 'king';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body).toHaveLength(10);
    });

    it("return back 'kings' (plural) documents", async () => {
      const keyword = 'kings';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body).toHaveLength(10);
    });

    it('return back words related to paradoxa (within paraenthesis)', async () => {
      const keyword = 'paradoxa';
      const words = ['òkwùma', 'osisi'];
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      forEach(res.body, (word) => expect(words).toContain(word.word));
    });

    it('return back ada without Adaeze', async () => {
      const keyword = 'ada';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body).toHaveLength(10);
    });

    it('return back Adaeze without ada', async () => {
      const keyword = 'adaeze';
      const words = ['àda èzè', 'Àdaèzè'];
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      forEach(res.body, (word) => expect(words).toContain(word.word));
    });

    it("return gbā ọ̄sọ̄ by searching 'run'", async () => {
      const keyword = 'run';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body).toHaveLength(10);
    });

    it("return words using stop word ('who') as search keyword", async () => {
      const keyword = 'who';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body).toHaveLength(10);
    });

    it("return words using stop word ('what') as search keyword", async () => {
      const keyword = 'what';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body).toHaveLength(10);
    });

    it('return word information with dialects query', async () => {
      const keyword = 'bia';
      const res = await getWords({ keyword, dialects: true }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(2);
      forEach(res.body, (word) => {
        expect(word.dialects).not.toEqual(undefined);
      });
    });

    it('return word information without dialects with malformed dialects query', async () => {
      const keyword = 'bia';
      const res = await getWords({ keyword, dialects: 'fdsafds' }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(2);
      forEach(res.body, (word) => {
        expect(word.dialects).toEqual(undefined);
      });
    });

    it('return word information with examples query', async () => {
      const keyword = 'bia';
      const res = await getWords({ keyword, examples: true }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(2);
      forEach(res.body, (word) => {
        expect(word.examples.length).toBeGreaterThanOrEqual(0);
      });
    });

    it('return word information without examples with malformed examples query', async () => {
      const keyword = 'bia';
      const res = await getWords({ keyword, examples: 'fdsafds' }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(2);
      forEach(res.body, (word) => {
        expect(word.examples).toEqual(undefined);
      });
    });

    it('return word information with the filter query', async () => {
      const filter = 'bia';
      const res = await getWords({ filter: { word: filter } }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(2);
      forEach(res.body, (word) => {
        Object.keys(word).forEach((key) => {
          expect(WORD_KEYS_V1.includes(key)).toBeTruthy();
        });
      });
    });

    it('return one word', async () => {
      const res = await getWords({}, { apiKey: MAIN_KEY });
      expect(res.status).toEqual(200);
      const result = await getWord(res.body[0].id, {}, {});
      expect(result.status).toEqual(200);
      Object.keys(result.body).forEach((key) => {
        expect(WORD_KEYS_V1.includes(key)).toBeTruthy();
      });
    });

    it('return an error for incorrect word id', async () => {
      const res = await getWords({}, {});
      expect(res.status).toEqual(200);
      const result = await getWord(NONEXISTENT_ID, {}, {});
      expect(result.status).toEqual(404);
      expect(result.error).not.toEqual(undefined);
    });

    it("return an error because document doesn't exist", async () => {
      const res = await getWord(INVALID_ID, {}, {});
      expect(res.status).toEqual(400);
      expect(res.body.error).not.toEqual(undefined);
    });

    it('return at most twenty five words per request with range query', async () => {
      const res = await Promise.all([
        getWords({ range: true }, {}),
        getWords({ range: '[10,34]' }, {}),
        getWords({ range: '[35,59]' }, {}),
      ]);
      expectUniqSetsOfResponses(res, 25);
    });

    it('return at most four words per request with range query', async () => {
      const res = await getWords({ range: '[5,8]' }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeLessThanOrEqual(4);
    });

    it('return at most ten words because of a large range', async () => {
      const res = await getWords({ range: '[10,40]' }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeLessThanOrEqual(10);
    });

    it('return at most ten words because of a tiny range', async () => {
      const res = await getWords({ range: '[10,9]' }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeLessThanOrEqual(10);
    });

    it('return at most ten words because of an invalid range', async () => {
      const res = await getWords({ range: 'incorrect' }, {});
      expect(res.status).toEqual(400);
      expect(res.body.error).not.toEqual(undefined);
    });

    it('return at most ten words per request with range query', async () => {
      const res = await Promise.all([
        getWords({ range: true }, {}),
        getWords({ range: '[10,19]' }, {}),
        getWords({ range: '[20,29]' }, {}),
        getWords({ range: [30, 39] }, {}),
      ]);
      expectUniqSetsOfResponses(res);
    });

    it('return at most ten words per request due to pagination', async () => {
      const res = await Promise.all([
        getWords({}, {}),
        getWords({ page: '1' }, {}),
        getWords({ page: '2' }, {}),
      ]);
      expectUniqSetsOfResponses(res);
    });

    it('return ignore case', async () => {
      const lowerCase = 'tree';
      const upperCase = 'Tree';
      const res = await Promise.all([
        getWords({ keyword: lowerCase }, {}),
        getWords({ keyword: upperCase }, {}),
      ]);
      expect(res[1].body.length).toBeGreaterThanOrEqual(res[0].body.length);
    });

    it('return only ten words', async () => {
      const keyword = 'woman';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body).toHaveLength(10);
    });

    it('return only ten words with the filter query', async () => {
      const filter = 'woman';
      const res = await getWords({ filter: { word: filter } }, {});
      expect(res.status).toEqual(200);
      expect(res.body).toHaveLength(10);
    });

    it('throw an error due to negative page number', async () => {
      const keyword = 'woman';
      const res = await getWords({ keyword, page: -1 }, {});
      expect(res.status).toEqual(400);
      expect(res.body.error).not.toEqual(undefined);
    });

    it('throw an error due to invalid page number', async () => {
      const filter = 'woman';
      const res = await getWords({ filter: { word: filter }, page: 'fake' }, {});
      expect(res.status).toEqual(400);
      expect(res.body.error).not.toEqual(undefined);
    });

    it.skip("return nothing because it's an incomplete word", async () => {
      const keyword = 'ak';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeLessThanOrEqual(1);
    });

    it('return igbo words when given english with an exact match', async () => {
      const keyword = 'animal; meat';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body).toHaveLength(1);
      expect(res.body[0].word).toEqual('anụ');
    });

    it('return igbo words when given english with a partial match', async () => {
      const keyword = 'animal';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(3);
      forEach(res.body, (word) => {
        Object.keys(word).forEach((key) => {
          expect(WORD_KEYS_V1.includes(key)).toBeTruthy();
        });
      });
    });

    it('return igbo word by searching variation', async () => {
      const keyword = 'mili';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body).toHaveLength(2); // Expecting mmilī (variation is milī) and -mìlị
      expect(uniqBy(res.body, (word: WordType) => word.id).length).toEqual(res.body.length);
      forEach(res.body, (word) => {
        Object.keys(word).forEach((key) => {
          expect(WORD_KEYS_V1.includes(key)).toBeTruthy();
        });
      });
    });

    it('return multiple word objects by searching variation', async () => {
      const keyword = '-mu-mù';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeLessThanOrEqual(10);
      expect(res.body[0].word).toEqual('-mụ-mù');
      expect(res.body[0].variations).toEqual(['-mu-mù']);
    });

    it('return unique words when searching for term', async () => {
      const keyword = 'ànùnù';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeLessThanOrEqual(5);
      expect(uniqBy(res.body, (word: WordType) => word.id).length).toEqual(res.body.length);
      forEach(res.body, (word) => {
        Object.keys(word).forEach((key) => {
          expect(WORD_KEYS_V1.includes(key)).toBeTruthy();
        });
      });
    });

    it('not include _id and __v keys', async () => {
      const keyword = 'elephant';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(2);
      expect(
        every(res.body, (word) => {
          Object.keys(word).forEach((key) => {
            expect(WORD_KEYS_V1.includes(key)).toBeTruthy();
          });
          Object.keys(word).forEach((key) => {
            expect(EXCLUDE_KEYS).not.toContain(key);
          });

          expect(
            every(word.examples, (example) => {
              EXAMPLE_KEYS_V1.forEach((key) => {
                expect(has(word, key)).toBeTruthy();
              });
              Object.keys(example).forEach((key) => {
                expect(EXCLUDE_KEYS).not.toContain(key);
              });
            })
          );
        })
      );
    });

    it.skip('return a sorted list of igbo terms when using english', async () => {
      const keyword = 'water';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(5);
      const responseBody: WordType[] = res.body;
      expect(
        every(responseBody, (word, index) => {
          if (index === 0) {
            return true;
          }
          const prevWord = res.body[index - 1].definitions[0] || '';
          const currentWord = word.definitions[0] || '';
          const prevWordDifference =
            stringSimilarity.compareTwoStrings(keyword, diacriticless(prevWord)) * 100;
          const nextWordDifference =
            stringSimilarity.compareTwoStrings(keyword, diacriticless(currentWord)) * 100;
          return prevWordDifference >= nextWordDifference;
        })
      ).toEqual(true);
    });

    it('return a list of igbo terms when using english by using single quotes', async () => {
      const keyword = "'water'";
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(1);
    });

    it('also return a list of igbo terms when using english by using double quotes', async () => {
      const keyword = '"water"';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(1);
    });

    it('not return any words when wrapping an igbo word in quotes', async () => {
      const keyword = '"nkanka"';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body).toHaveLength(0);
    });

    it('return words with no keyword as an application using MAIN_KEY', async () => {
      const res = await getWords({}, { apiKey: MAIN_KEY });
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeLessThanOrEqual(10);
    });

    it('return no words with no keyword as a developer', async () => {
      const res = await getWords({}, {});
      expect(res.status).toEqual(200);
      expect(res.body).toHaveLength(0);
    });

    it('return accented word', async () => {
      const res = await getWords({}, {});
      expect(res.status).toEqual(200);
      forEach(res.body, (word) => {
        expect(word.word).not.toEqual(undefined);
      });
    });

    it('return hard matched words with strict query', async () => {
      const keyword = 'akwa';
      const res = await getWords({ keyword, strict: true }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(1);
      forEach(res.body, (word) => {
        const { wordReg: wordRegex } = createRegExp(word.word);
        expect(word.word).toMatch(wordRegex);
      });
    });

    it('return loosely matched words without strict query', async () => {
      const keyword = 'akwa';
      const res = await getWords({ keyword, strict: false }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(4);
      forEach(res.body, (word) => {
        const { wordReg: wordRegex } = createRegExp(word.word);
        expect(word.word).toMatch(wordRegex);
      });
    });

    it('return a word by searching with nested dialect word', async () => {
      const keyword = 'akwa-dialect';
      const res = await getWords({ keyword, dialects: true }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(1);
      forEach(res.body, (word) => {
        expect(word.dialects[`${word.word}-dialect`]).not.toEqual(undefined);
      });
    });

    it('return a word that is a common noun', async () => {
      const connection = createDbConnection();
      const Word = connection.model('Word', wordSchema);
      const word = {
        word: 'standardIgboWord',
        definitions: [
          {
            wordClass: 'NNC',
            definitions: ['first definition', 'second definition'],
          },
        ],
        dialects: [],
        examples: [new ObjectId(), new ObjectId()],
        attributes: {
          isStandardIgbo: true,
        },
        stems: [],
      };
      const validWord = new Word(word);
      await validWord.save();
      await handleCloseConnection(connection);
      const res = await getWords({ keyword: word.word, wordClasses: '[NNC]' }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(1);
      forEach(res.body, (wordRes) => {
        expect(wordRes.attributes.isStandardIgbo).toEqual(true);
      });
      const noRes = await getWords({ keyword: word.word, wordClasses: ['ADJ'] }, {});
      expect(noRes.status).toEqual(200);
      expect(noRes.body).toHaveLength(0);
    });

    it('return all tenses', async () => {
      const keyword = 'bịa';
      const res = await getWords({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(1);
      forEach(res.body, (word) => {
        if (word.definitions[0].wordClass === WordClass.AV.value) {
          expect(word.tenses[Tenses.PRESENT_PASSIVE.value]).not.toBe(undefined);
        } else if (word.definitions[0].wordClass === WordClass.PV.value) {
          expect(word.tenses[Tenses.PRESENT_PASSIVE.value]).not.toBe(undefined);
        }
      });
    });
  });

  describe('/GET mongodb words V2', () => {
    it.skip('return word parts of mgba for noun deconstruction', async () => {
      const keyword = 'mgba';
      const res = await getWordsV2({ keyword }, {});
      expect(res.status).toEqual(200);
      const gbaWord = res.body.data.find(({ word }: { word: string }) => word === 'gba');
      expect(gbaWord).toBeTruthy();
    });
    it('return word information', async () => {
      const keyword = 'bia';
      const res = await getWordsV2({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body.data.length).toBeGreaterThanOrEqual(2);
      forEach(res.body.data, (word) => {
        Object.keys(word).forEach((key) => {
          expect(WORD_KEYS_V2).toContain(key);
        });
        const { wordClass }: { wordClass: WordClassEnum } = word.definitions[0];
        expect(WordClass[wordClass]).not.toBe(undefined);
      });
    });
    it('return one word', async () => {
      const res = await getWordsV2({}, { apiKey: MAIN_KEY });
      expect(res.status).toEqual(200);
      const result = await getWordV2(res.body.data[0].id, {}, {});
      expect(result.status).toEqual(200);
      Object.keys(result.body.data).forEach((key) => {
        expect(WORD_KEYS_V2.includes(key)).toBeTruthy();
      });
      const { wordClass }: { wordClass: WordClassEnum } = result.body.data.definitions[0];
      expect(WordClass[wordClass]).not.toBe(undefined);
    });
    it("return words using stop word ('who') as search keyword", async () => {
      const keyword = 'who';
      const res = await getWordsV2({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body.data).toHaveLength(10);
    });
    it("return words using stop word ('what') as search keyword", async () => {
      const keyword = 'what';
      const res = await getWordsV2({ keyword }, {});
      expect(res.status).toEqual(200);
      expect(res.body.data).toHaveLength(10);
    });
  });
});


================================================
FILE: __tests__/developers.test.ts
================================================
import {
  createDeveloper,
  getDeveloper,
  getExample,
  getExamples,
  getWord,
  getWords,
} from './shared/commands';
import { developerData, malformedDeveloperData, wordId, exampleId } from './__mocks__/documentData';

jest.unmock('mongoose');

// TODO: Re-enable test
describe.skip('Developers', () => {
  describe('/POST mongodb developers', () => {
    it('create a new developer', async () => {
      const res = await createDeveloper(developerData);
      expect(res.status).toEqual(200);
      expect(res.body.message).not.toEqual(undefined);
    });

    it('throw an error while creating a new developer', async () => {
      const res = await createDeveloper(malformedDeveloperData);
      expect(res.status).toEqual(400);
      expect(res.body.error).not.toEqual(undefined);
    });

    it('throw an error by using the same email for new developers', async () => {
      const repeatedDeveloper = {
        ...developerData,
        email: 'email@example.com',
      };
      const res = await createDeveloper(repeatedDeveloper);
      expect(res.status).toEqual(200);
      const result = await createDeveloper(repeatedDeveloper);
      expect(result.status).toEqual(400);
      expect(result.body.error).not.toEqual(undefined);
    });
  });

  describe('Using Developer API Keys', () => {
    it('get all words with API key', async () => {
      const developerRes = await createDeveloper(developerData);
      expect(developerRes.status).toEqual(200);
      await new Promise((resolve) => {
        setTimeout(resolve, 5000);
      });
      const res = await getWords({}, { apiKey: developerRes.body.apiKey });
      expect(res.status).toEqual(200);
    });

    it('search for a word with API key', async () => {
      const developerRes = await createDeveloper(developerData);
      expect(developerRes.status).toEqual(200);
      const res = await getWord(wordId, {}, { apiKey: developerRes.body.apiKey });
      expect(res.status).toEqual(404);
    });

    it('get examples with API key', async () => {
      const developerRes = await createDeveloper(developerData);
      expect(developerRes.status).toEqual(200);
      const res = await getExamples({}, { apiKey: developerRes.body.apiKey });
      expect(res.status).toEqual(200);
    });

    it('search for an example with API key', async () => {
      const developerRes = await createDeveloper(developerData);
      expect(developerRes.status).toEqual(200);
      const res = await getExample(exampleId, {}, { apiKey: developerRes.body.apiKey });
      expect(res.status).toEqual(404);
    });

    it('throw an error getting words with invalid API key', async () => {
      const res = await getWords({}, { apiKey: 'invalid key' });
      expect(res.status).toEqual(401);
      expect(res.body.error).not.toEqual(undefined);
    });

    it('throw an error getting a word with invalid API key', async () => {
      const res = await getWord(wordId, {}, { apiKey: 'invalid key' });
      expect(res.status).toEqual(401);
      expect(res.body.error).not.toEqual(undefined);
    });

    it('throw an error getting examples with invalid API key', async () => {
      const res = await getExamples({}, { apiKey: 'invalid key' });
      expect(res.status).toEqual(401);
      expect(res.body.error).not.toEqual(undefined);
    });

    it('throw an error getting an example with invalid API key', async () => {
      const res = await getExample(exampleId, {}, { apiKey: 'invalid key' });
      expect(res.status).toEqual(401);
      expect(res.body.error).not.toEqual(undefined);
    });

    it('throw no error getting examples with mismatching origin', async () => {
      const developerRes = await createDeveloper(developerData);
      expect(developerRes.status).toEqual(200);
      const res = await getExamples({}, { apiKey: developerRes.body.apiKey, origin: 'invalid' });
      expect(res.status).toEqual(200);
    });

    it('increase the count by maxing usage limit', async () => {
      const developerRes = await createDeveloper(developerData);
      expect(developerRes.status).toEqual(200);
      const wordsRes = await getWords({ keyword: 'eat' }, {});
      const limitWordId = wordsRes.body[0].id;
      await getWord(limitWordId, {}, { apiKey: developerRes.body.apiKey });
      await getWord(limitWordId, {}, { apiKey: developerRes.body.apiKey });
      const res = await getWord(limitWordId, { apiLimit: 2 }, { apiKey: developerRes.body.apiKey });
      expect(res.status).toEqual(403);
    });

    it('should return developer document with correct credentials', async () => {
      const developerRes = await createDeveloper(developerData);
      const developerDetailsRes = await getDeveloper(developerRes.body.id, {
        apiKey: developerRes.body.apiKey,
      });
      expect(developerDetailsRes.status).toEqual(200);
      expect(developerDetailsRes.body.developer).toMatchObject({
        usage: expect.objectContaining({
          date: expect.any(String),
          count: 0,
        }),
        name: expect.any(String),
        apiKey: expect.any(String),
        email: expect.any(String),
        password: expect.any(String),
        createdAt: expect.any(String),
        updatedAt: expect.any(String),
        id: expect.any(String),
      });
    });

    it('should throw an error getting developer document with invalid credentials', async () => {
      const developerRes = await createDeveloper(developerData);
      const res = await getDeveloper(developerRes.body.id, { apiKey: 'invalid api key' });
      expect(res.body.status).toEqual(403);
      expect(res.body.error).not.toEqual(undefined);
    });
  });
});


================================================
FILE: __tests__/examples.test.ts
================================================
import { forEach, has, isEqual } from 'lodash';
import { getExamples, getExample, getExamplesV2, getExampleV2 } from './shared/commands';
import {
  MAIN_KEY,
  EXAMPLE_KEYS_V1,
  EXAMPLE_KEYS_V2,
  INVALID_ID,
  NONEXISTENT_ID,
} from './shared/constants';
import { expectUniqSetsOfResponses } from './shared/utils';
import ExampleStyleEnum from '../src/shared/constants/ExampleStyleEnum';

jest.unmock('mongoose');

describe('MongoDB Examples', () => {
  describe('/GET mongodb examples V1', () => {
    it('return no examples by searching', async () => {
      const res = await getExamples({}, {});
      expect(res.status).toEqual(200);
      expect(res.body).toHaveLength(0);
    });

    it('return an example by searching', async () => {
      const res = await getExamples({}, { apiKey: MAIN_KEY });
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeLessThanOrEqual(10);
    });

    it('return an example by searching with style', async () => {
      const res = await getExamples({ style: ExampleStyleEnum.PROVERB }, { apiKey: MAIN_KEY });
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeGreaterThanOrEqual(1);
      expect(res.body[0].style).toEqual(ExampleStyleEnum.PROVERB);
    });

    it('return one example', async () => {
      const res = await getExamples({}, { apiKey: MAIN_KEY });
      const result = await getExample(res.body[0].id, {}, {});
      expect(result.status).toEqual(200);
      EXAMPLE_KEYS_V1.forEach((key) => {
        expect(has(result.body, key)).toBeTruthy();
      });
    });

    it('return an error for incorrect example id', async () => {
      await getExamples({}, {});
      const result = await getExample(NONEXISTENT_ID, {}, {});
      expect(result.status).toEqual(404);
      expect(result.error).not.toEqual(undefined);
    });

    it("return an error because document doesn't exist", async () => {
      const res = await getExample(INVALID_ID, {}, {});
      expect(res.status).toEqual(400);
      expect(res.body.error).not.toEqual(undefined);
    });

    it('return at most ten example per request with range query', async () => {
      const res = await Promise.all([
        getExamples({ range: '[0,9]' }, {}),
        getExamples({ range: [10, 19] }, {}),
        getExamples({ range: '[20,29]' }, {}),
        getExamples({ range: '[30,39]' }, {}),
      ]);
      expectUniqSetsOfResponses(res);
    });

    it('return different sets of example suggestions for pagination', async () => {
      const res = await Promise.all([
        getExamples({ page: 0 }, {}),
        getExamples({ page: 1 }, {}),
        getExamples({ page: 2 }, {}),
      ]);
      expectUniqSetsOfResponses(res);
    });

    it('return prioritize range over page', async () => {
      const res = await Promise.all([
        getExamples({ page: '1' }, { apiKey: MAIN_KEY }),
        getExamples({ page: '1', range: '[100,109]' }, { apiKey: MAIN_KEY }),
      ]);
      expect(isEqual(res[0].body, res[1].body)).toEqual(false);
    });

    it('return words with no keyword as an application using MAIN_KEY', async () => {
      const res = await getExamples({}, { apiKey: MAIN_KEY });
      expect(res.status).toEqual(200);
      expect(res.body.length).toBeLessThanOrEqual(10);
    });

    it('return no examples with no keyword as a developer', async () => {
      const res = await getExamples({}, {});
      expect(res.status).toEqual(200);
      expect(res.body).toHaveLength(0);
    });

    it('return accented keyword', async () => {
      const keyword = 'Òbìàgèlì bì n’Àba';
      const res = await getExamples({ keyword }, {});
      expect(res.status).toEqual(200);
      forEach(res.body, (example) => {
        expect(example.igbo).not.toEqual(undefined);
      });
    });

    it('return accented example', async () => {
      const res = await getExamples({}, {});
      expect(res.status).toEqual(200);
      forEach(res.body, (example) => {
        expect(example.igbo).not.toEqual(undefined);
      });
    });

    it('return examples by style', async () => {
      const res = await getExamples({ style: ExampleStyleEnum.PROVERB }, {});
      expect(res.status).toEqual(200);
      forEach(res.body, (example) => {
        expect(example.style).toEqual(ExampleStyleEnum.PROVERB);
      });
    });
  });

  describe('/GET mongodb examples V2', () => {
    it('return one example', async () => {
      const res = await getExamplesV2({}, { apiKey: MAIN_KEY });
      const result = await getExampleV2(res.body.data[0].id, {}, {});
      expect(result.status).toEqual(200);
      Object.keys(result.body.data).forEach((key) => {
        expect(EXAMPLE_KEYS_V2).toContain(key);
      });
    });
  });
});


================================================
FILE: __tests__/nsibidi_characters.test.ts
================================================
import { getNsibidiCharactersV2 } from './shared/commands';

jest.unmock('mongoose');

describe('MongoDB Nsibidi Characters', () => {
  describe('/GET mongodb nsibidi characters V2', () => {
    it('return nsibidi character by searching', async () => {
      const res = await getNsibidiCharactersV2({ keyword: '123' }, {});
      expect(res.status).toEqual(200);
    });
  });
});


================================================
FILE: __tests__/parse.test.ts
================================================
import fs from 'fs';
import { keys } from 'lodash';
import replaceAbbreviations from '../src/shared/utils/replaceAbbreviations';
import { searchTerm, searchMockedTerm } from './shared/commands';

const mocksDir = `${__dirname}/__mocks__`;
if (!fs.existsSync(mocksDir)) {
  fs.mkdirSync(mocksDir);
}

describe('Parse', () => {
  describe('Dictionaries', () => {
    it('create dictionaries', async () => {
      await import('../src/dictionaries/buildDictionaries').catch((err) => {
        throw err;
      });
    });

    it('keep same-cell text in the definition property', async () => {
      const keyword = 'ama';
      const res = await searchTerm(keyword);
      expect(res.status).toEqual(200);
      expect(keys(res.body).length).toBeGreaterThanOrEqual(2);
      expect(res.body[keyword][0].definitions.length).toBeGreaterThanOrEqual(1);
      expect(res.body[keyword][0].examples).toHaveLength(1);
    });

    it('include the correct A. B. text for ewu chī', async () => {
      const keyword = 'chi';
      const {
        body: { chi: res },
      } = await searchTerm(keyword);
      const termDefinitions = res[0].definitions;
      expect(termDefinitions.length).toBeGreaterThanOrEqual(2);
    });

    it('include all words -kwù-', async () => {
      const keyword = '-kwù-';
      const res = await searchTerm(keyword);
      expect(res.status).toEqual(200);
      expect(keys(res.body).length).toBeGreaterThanOrEqual(1);
    });
  });

  describe('Utils', () => {
    describe('Regex Search', () => {
      it('return term information without included dashes', async () => {
        const res = searchMockedTerm('bia');
        keys(res).forEach((key) => {
          expect(key.charAt(0)).toEqual('b');
        });
      });

      it('return term with apostrophe by using spaces', async () => {
        const res = searchMockedTerm('n oge');
        expect(keys(res)[0]).toEqual("n'oge");
      });

      it('return term with space with non word characters', async () => {
        const res = searchMockedTerm('n oge');
        expect(keys(res)[0]).toEqual("n'oge");
      });

      it('return term with apostrophe by using apostrophe', async () => {
        const res = searchMockedTerm('ànì');
        expect(keys(res)[0]).toEqual('ànì');
      });

      it('return all matching terms', async () => {
        const keyword = 'be';
        const res = await searchTerm(keyword);
        expect(res.status).toEqual(200);
        expect(keys(res.body).length).toBeGreaterThanOrEqual(6);
      });
    });

    describe('Abbreviations', () => {
      it('replace all present valid abbreviations', async () => {
        const withAbbreviations = 'n. noun. num. num.eral aux. v. aux.v. infl. suff.';
        const withoutAbbreviations = replaceAbbreviations(withAbbreviations);
        expect(withoutAbbreviations).toEqual(
          'noun noun. numeral num.eral auxiliary verb aux.verb inflectional suffix'
        );
      });
    });
  });
});


================================================
FILE: __tests__/shared/commands.ts
================================================
import request from 'supertest';
import { Types } from 'mongoose';
import app from '../../src/app';
import {
  API_ROUTE,
  API_ROUTE_V2,
  FALLBACK_API_KEY,
  LOCAL_ROUTE,
  STRIPE_ROUTE,
  TEST_ROUTE,
} from './constants';
import createRegExp from '../../src/shared/utils/createRegExp';
import { resultsFromDictionarySearch } from '../../src/services/words';
import mockedData from '../__mocks__/data.mock.json';
import ExampleStyleEnum from '../../src/shared/constants/ExampleStyleEnum';

type Id = string | Types.ObjectId;

type Query = Partial<{
  range: string | [number, number] | boolean,
  keyword: string,
  style: ExampleStyleEnum,
  page: string | number,
  apiLimit: number,
  dialects: string | boolean,
  examples: string | boolean,
  strict: string | boolean,
  wordClasses: string | string[],
  filter: Partial<{ word: string }> | string,
}>;
type Options = Partial<{
  apiKey: string,
  origin: string,
}>;

const server = request(app);

export const createDeveloper = (data: object) => server.post(`${API_ROUTE}/developers`).send(data);

export const getDeveloper = (id: Id, options: Options) =>
  server
    .get(`${API_ROUTE}/developers/${id}`)
    .set('Authorization', `Bearer ${options.apiKey || FALLBACK_API_KEY}`)
    .set('X-API-Key', options.apiKey || FALLBACK_API_KEY);

/* Searches for words using the data in MongoDB V2 */
export const getWords = (query: Query, options: Options) =>
  server
    .get(`${API_ROUTE}/words`)
    .query(query)
    .set('X-API-Key', options.apiKey || FALLBACK_API_KEY);

export const getWord = (id: Id, query: Query, options: Options) =>
  server
    .get(`${API_ROUTE}/words/${id}`)
    .query(query)
    .set('X-API-Key', options.apiKey || FALLBACK_API_KEY);

/* Searches for words using the data in MongoDB V2 */
export const getWordsV2 = (query: Query, options: Options) =>
  server
    .get(`${API_ROUTE_V2}/words`)
    .query(query)
    .set('X-API-Key', options.apiKey || FALLBACK_API_KEY);

export const getWordV2 = (id: Id, query: Query, options: Options) =>
  server
    .get(`${API_ROUTE_V2}/words/${id}`)
    .query(query)
    .set('X-API-Key', options.apiKey || FALLBACK_API_KEY);

/* Searches for examples using the data in MongoDB V1 */
export const getExample = (id: Id, query: Query, options: Options) =>
  server
    .get(`${API_ROUTE}/examples/${id}`)
    .query(query)
    .set('X-API-Key', options.apiKey || FALLBACK_API_KEY);

export const getExamples = (query: Query, options: Options) =>
  server
    .get(`${API_ROUTE}/examples`)
    .query(query)
    .set('X-API-Key', options.apiKey || FALLBACK_API_KEY);

/* Searches for examples using the data in MongoDB V2 */
export const getExampleV2 = (id: Id, query: Query, options: Options) =>
  server
    .get(`${API_ROUTE_V2}/examples/${id}`)
    .query(query)
    .set('X-API-Key', options.apiKey || FALLBACK_API_KEY);
export const getExamplesV2 = (query: Query, options: Options) =>
  server
    .get(`${API_ROUTE_V2}/examples`)
    .query(query)
    .set('X-API-Key', options.apiKey || FALLBACK_API_KEY);

/* Searches for Nsibidi characters using the data in MongoDB V1 */
export const getNsibidiCharacter = (id: Id, query: Query, options: Options) =>
  server
    .get(`${API_ROUTE}/nsibidi/${id}`)
    .query(query)
    .set('X-API-Key', options.apiKey || FALLBACK_API_KEY);

/* Searches for Nsibidi characters using the data in MongoDB V2 */
export const getNsibidiCharacterV2 = (id: Id, query: Query, options: Options) =>
  server
    .get(`${API_ROUTE_V2}/nsibidi/${id}`)
    .query(query)
    .set('X-API-Key', options.apiKey || FALLBACK_API_KEY);

export const getNsibidiCharactersV2 = (query: Query, options: Options) =>
  server
    .get(`${API_ROUTE_V2}/nsibidi`)
    .query(query)
    .set('X-API-Key', options.apiKey || FALLBACK_API_KEY);

/* Hits the POST /populate route to seed the local MongoDB database */
export const populateAPI = () => server.post(`${TEST_ROUTE}/populate`);

/* Uses data in JSON */
export const searchTerm = (term?: string) =>
  server.get(`${TEST_ROUTE}/words`).query({ keyword: term || '' });

export const getLocalUrlRoute = (route = LOCAL_ROUTE) => server.get(route);

/* Uses data in __mocks__ folder */
export const searchMockedTerm = (term: string) => {
  const { wordReg: regexTerm } = createRegExp(term);
  return resultsFromDictionarySearch(regexTerm, term, mockedData);
};

/* Stripe */
export const postCheckoutSession = (data: { developerId: string, lookupKey: string }) =>
  server.post(`${STRIPE_ROUTE}/checkout`).send(data);
export const postPortalSession = (data: { sessionId: string }) =>
  server.post(`${STRIPE_ROUTE}/portal`).send(data);
export const postWebhook = () => server.post(`${STRIPE_ROUTE}/webhook`);


================================================
FILE: __tests__/shared/constants.ts
================================================
import mongoose from 'mongoose';
import Version from '../../src/shared/constants/Version';

export const LOCAL_ROUTE = '/';
export const API_ROUTE = `/api/${Version.VERSION_1}`;
export const API_ROUTE_V2 = `/api/${Version.VERSION_2}`;
export const TEST_ROUTE = `/api/${Version.VERSION_1}/test`;
export const STRIPE_ROUTE = '/stripe';
export const API_URL = 'https://igboapi.com';

export const WORD_KEYS_V1 = [
  'variations',
  'definitions',
  'stems',
  'id',
  'word',
  'wordClass',
  'pronunciation',
  'relatedTerms',
  'hypernyms',
  'hyponyms',
  'nsibidi',
  'attributes',
];
export const WORD_KEYS_V2 = [
  'variations',
  'definitions',
  'stems',
  'id',
  'word',
  'pronunciation',
  'relatedTerms',
  'hypernyms',
  'hyponyms',
  'attributes',
  'tags',
];
export const EXAMPLE_KEYS_V1 = [
  'igbo',
  'english',
  'meaning',
  'nsibidi',
  'style',
  'associatedWords',
  'id',
  'pronunciation',
  'updatedAt',
  'createdAt',
];
export const EXAMPLE_KEYS_V2 = [
  'igbo',
  'english',
  'meaning',
  'style',
  'type',
  'associatedWords',
  'associatedDefinitionsSchemas',
  'id',
  'nsibidi',
  'pronunciations',
  'updatedAt',
  'createdAt',
];
export const EXCLUDE_KEYS = ['__v', '_id'];
export const SITE_TITLE = 'The First African Language API';
export const DOCS_SITE_TITLE = 'Igbo API Documentation';
export const INVALID_ID = 'fdsafdsad';
export const NONEXISTENT_ID = new mongoose.Types.ObjectId();
export const MAIN_KEY = 'main_key';
export const FALLBACK_API_KEY = 'fallback_api_key';


================================================
FILE: __tests__/shared/uiFixtures.ts
================================================
import { DecodedIdToken } from 'firebase-admin/auth';

export const decodedIdTokenFixture = (data: object = {}): DecodedIdToken => ({
  aud: 'aud',
  auth_time: Date.now(),
  email: 'uid@gmail.com',
  email_verified: false,
  exp: Date.now() + 1000,
  firebase: {
    identities: {},
    sign_in_provider: 'google.com',
  },
  iat: Date.now(),
  iss: 'project_id',
  sub: 'sub',
  uid: 'uid',
  ...data,
});


================================================
FILE: __tests__/shared/utils.ts
================================================
import { forEach, difference, map } from 'lodash';
import { expect } from '@jest/globals';

export const expectUniqSetsOfResponses = (res: any[], responseLength = 10) => {
  forEach(res, (docsRes, index) => {
    expect(docsRes.status).toEqual(200);
    expect(docsRes.body.length).toBeLessThanOrEqual(responseLength);
    if (index !== 0) {
      const prevDocsIds = map(res[index].body, ({ id }) => ({ id }));
      const currentDocsIds = map(docsRes.body, ({ id }) => ({ id }));
      expect(difference(prevDocsIds, currentDocsIds)).toHaveLength(prevDocsIds.length);
    }
  });
};


================================================
FILE: __tests__/stripe.test.ts
================================================
import { postCheckoutSession, postPortalSession, postWebhook } from './shared/commands';

jest.unmock('mongoose');

describe('Stripe', () => {
  describe('/POST Stripe Checkout', () => {
    it('redirect to checkout session', async () => {
      const res = await postCheckoutSession({ developerId: 'developerId', lookupKey: '123' });
      expect(res.status).toEqual(303);
      expect(res.headers.location).toEqual('checkout_session_url');
    });

    it('fail to redirect to checkout session missing developerId', async () => {
      // @ts-expect-error lookupKey
      const res = await postCheckoutSession({ lookupKey: '123' });
      expect(res.status).toEqual(400);
    });

    it('fail to redirect to checkout session missing lookupKey', async () => {
      // @ts-expect-error developerId
      const res = await postCheckoutSession({ developerId: '123' });
      expect(res.status).toEqual(400);
    });
  });
  describe('/POST Stripe Portal', () => {
    it('redirect to portal session', async () => {
      const res = await postPortalSession({ sessionId: 'sessionId' });
      expect(res.status).toEqual(303);
      expect(res.headers.location).toEqual('portal_session_url');
    });

    it('fail to redirect to portal session missing sessionId', async () => {
      // @ts-expect-error sessionId
      const res = await postCheckoutSession({});
      expect(res.status).toEqual(400);
    });
  });

  describe('/POST Stripe Webhook', () => {
    it('handle webhooks', async () => {
      const res = await postWebhook();
      expect(res.status).toEqual(200);
    });
  });
});


================================================
FILE: commitlint.config.js
================================================
module.exports = {
  extends: ['@commitlint/config-conventional'],
};


================================================
FILE: cypress/e2e/client.cy.js
================================================
import { v4 as uuid } from 'uuid';

describe('Igbo API Homepage', () => {
  beforeEach(() => {
    cy.visit('/');
  });

  describe('Outside links', () => {
    beforeEach(() => {
      cy.viewport('macbook-16');
    });

    it('navigate to Nkọwa okwu website', () => {
      cy.findByTestId('nkowaokwu-link').click({ force: true });
      cy.url().should('equal', 'https://nkowaokwu.com/home');
      cy.contains('Internal Server Error').should('not.exist');
    });
  });

  describe('Desktop', () => {
    beforeEach(() => {
      cy.viewport('macbook-16');
    });

    it('execute JS in browser and renders API homepage', () => {
      cy.get('h1').contains('The First African Language API');
      cy.contains('An unexpected error has occurred.').should('not.exist');
    });

    it('render the About page', () => {
      cy.get('li').contains('About').click({ force: true });
      cy.findByText('Contact');
      cy.contains('kedu@nkowaokwu.com');
    });

    it('render the Privacy page', () => {
      cy.findByText('Privacy Policy').click();
      cy.get('h1').contains('Privacy Policy').should('exist');
    });

    it('render the Terms or Service page', () => {
      cy.findByText('Terms of Service').click();
      cy.findByText('Terms and Conditions').should('exist');
    });

    describe('Try it Out', () => {
      it('enter a word and select flag', () => {
        cy.visit('/');
        cy.findByTestId('try-it-out-input').clear({ force: true }).type('biko', { force: true });
        cy.findByTestId('dialects-flag').click();
        cy.get('button').contains('Submit').click();
        cy.get('code')
          .contains('http://localhost:8080/api/v1/words?keyword=biko&dialects=true')
          .should('exist');
      });
    });

    describe('Register Account', () => {
      beforeEach(() => {
        cy.visit('/signup');
      });

      it('render the Sign Up page', () => {
        cy.findByText('Sign up.');
      });

      it('fill out the sign up form and submit for developer account', () => {
        const email = `${uuid()}@testing.com`;
        cy.intercept('POST', '**developers').as('postDeveloper');
        cy.findByTestId('signup-name-input').clear().type('Developer');
        cy.findByTestId('signup-email-input').clear().type(email);
        cy.findByTestId('signup-password-input').clear().type('password');
        cy.findByText('Create account').click();
        cy.wait('@postDeveloper').then((res) => {
          expect(res.response.statusCode).to.equal(200);
          cy.findByText('Success! Check your email');
        });
      });

      it('fill out the sign up form and submit for developer account and get an error', () => {
        const email = `${uuid()}@testing.com`;
        cy.intercept('POST', '**developers').as('postDeveloper');
        cy.findByTestId('signup-name-input').clear().type('Developer');
        cy.findByTestId('signup-email-input').clear().type(email);
        cy.findByTestId('signup-password-input').clear().type('password');
        cy.findByText('Create account').click();
        cy.wait('@postDeveloper');
        cy.reload();
        cy.findByTestId('signup-name-input').clear().type('Developer');
        cy.findByTestId('signup-email-input').clear().type(email);
        cy.findByTestId('signup-password-input').clear().type('password');
        cy.findByText('Create account').click();
        cy.wait('@postDeveloper').then((res) => {
          expect(res.response.statusCode).to.equal(400);
          cy.findByText('Create account').should('not.exist');
          cy.findByText('Success! Check your email').should('not.exist');
        });
      });
    });
  });

  describe('Mobile', () => {
    beforeEach(() => {
      cy.viewport('iphone-6');
    });

    it('render the About page', () => {
      cy.findByTestId('drop-down-button').click();
      cy.get('button').contains('About').click({ force: true });
      cy.findByText('Contact');
      cy.contains('kedu@nkowaokwu.com');
    });
    it('render the Sign up page', () => {
      cy.findByTestId('drop-down-button').click();
      cy.get('button').contains('Sign Up').click({ force: true });
      cy.findByText('Sign up.');
    });

    it('navigate to Nkọwa okwu', () => {
      cy.visit('/');
      cy.scrollTo(0, -300);
      cy.findByTestId('nkowaokwu-link').click({ force: true });
    });
  });
});


================================================
FILE: cypress/fixtures/example.json
=========================================
Download .txt
gitextract_on7951nt/

├── .dockerignore
├── .eslintignore
├── .github/
│   ├── CODE_OF_CONDUCT.md
│   ├── CONTRIBUTING.md
│   ├── FIREBASE_CONFIG.md
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   ├── doc_issue.md
│   │   └── feature_request.md
│   ├── pull_request_template.md
│   └── workflows/
│       ├── deploy.yml
│       ├── dockerize.yml
│       ├── integration.yml
│       ├── lint.yml
│       └── release.yml
├── .gitignore
├── .npmrc
├── .prettierignore
├── .prettierrc.json
├── .releaserc
├── @types/
│   ├── bcrypt.d.ts
│   ├── body-parser.d.ts
│   ├── compression.d.ts
│   ├── console.d.ts
│   ├── diacriticless.d.ts
│   ├── environment.d.ts
│   ├── express-rate-limit.d.ts
│   ├── is-word.d.ts
│   ├── morgan.d.ts
│   ├── react-scroll.d.ts
│   ├── shelljs.d.ts
│   ├── string-similarity.d.ts
│   ├── supertest.d.ts
│   └── uuid.d.ts
├── Dockerfile
├── LICENSE.md
├── README.md
├── __mocks__/
│   ├── @chakra-ui/
│   │   └── react.tsx
│   ├── @sendgrid/
│   │   └── mail.ts
│   ├── axios.ts
│   ├── bcrypt.ts
│   ├── firebase/
│   │   ├── app.ts
│   │   ├── auth.ts
│   │   └── functions.ts
│   ├── firebase-admin.ts
│   ├── firebase-functions/
│   │   └── v1.ts
│   ├── i18next.ts
│   ├── mongoose.ts
│   ├── next/
│   │   ├── font/
│   │   │   └── google.ts
│   │   └── router.ts
│   ├── react-firebase-hooks/
│   │   └── auth.ts
│   ├── shelljs.ts
│   ├── stripe.ts
│   └── uuid.ts
├── __tests__/
│   ├── __mocks__/
│   │   ├── data.mock.json
│   │   ├── documentData.ts
│   │   └── genericWords.mock.json
│   ├── api-json.test.ts
│   ├── api-mongo.test.ts
│   ├── developers.test.ts
│   ├── examples.test.ts
│   ├── nsibidi_characters.test.ts
│   ├── parse.test.ts
│   ├── shared/
│   │   ├── commands.ts
│   │   ├── constants.ts
│   │   ├── uiFixtures.ts
│   │   └── utils.ts
│   └── stripe.test.ts
├── commitlint.config.js
├── cypress/
│   ├── e2e/
│   │   └── client.cy.js
│   ├── fixtures/
│   │   └── example.json
│   ├── plugins/
│   │   └── index.js
│   └── support/
│       ├── commands.js
│       └── e2e.js
├── cypress.config.js
├── docker-compose.yml
├── env.d.ts
├── eslint.config.mjs
├── firebase.json
├── functions/
│   ├── .gitignore
│   ├── index.js
│   ├── next-i18next.config.js
│   ├── next.config.js
│   ├── package.json
│   ├── postcss.config.js
│   └── tailwind.config.js
├── jest.backend.config.ts
├── jest.backend.database.config.ts
├── jest.frontend.config.ts
├── migrate-mongo-config.js
├── migrations/
│   ├── 20201106045436-add-suggestion-properties.js
│   ├── 20201108164925-add-exampleForWordSuggestion-field.js
│   ├── 20201109083748-remove-examples-from-words.js
│   ├── 20201118192335-add-merged-by.js
│   ├── 20201121195224-add-updated-on-for-words-and-examples.js
│   ├── 20201206042142-add-accented-field.js
│   ├── 20201213020925-uid-fields-on-suggestions.js
│   ├── 20210225022115-create-dialects.js
│   ├── 20210225235148-update-variations-to-array.js
│   ├── 20210306224633-add-dialects-for-word-suggestions-and-generic-words.js
│   ├── 20210325194345-add-central-igbo.js
│   ├── 20210331134705-remove-developer-origin.js
│   ├── 20210426171953-remove-normalized-field.js
│   ├── 20210814210437-pre-populate-dialects.js
│   ├── 20210820170937-merge-accented-and-word.js
│   ├── 20210820175620-merge-accented-and-example.js
│   ├── 20210822145619-change-central-to-standard.js
│   ├── 20210831163032-add-is-complete-word.js
│   ├── 20210903175644-remove-is-complete-word.js
│   ├── 20211030133331-add-active-and-passive-verbs.js
│   ├── 20211121214701-add-nyms.js
│   ├── 20211218192401-add-isComplete.js
│   ├── 20220107155512-add-nsibidi.js
│   ├── 20220125175808-restructure-dialects.js
│   ├── 20220208140327-example-pronunciations.js
│   ├── 20220216030851-remove-verb-prefixes.js
│   ├── 20220301211505-convert-unix-to-iso.js
│   ├── 20220308132126-add-is-accented.js
│   ├── 20220406005107-add-tenses.js
│   ├── 20220423222134-add-attributes.js
│   ├── 20220425130741-extend-example-sentences-with-style-and-meaning.js
│   ├── 20220808024209-add-borrowed-term-field.js
│   ├── 20220808033804-add-tags.js
│   ├── 20220808042906-replace-nyms-for-related-terms.js
│   ├── 20221014123241-add-is-stem.js
│   ├── 20221030034746-restructure-definitions.js
│   ├── 20221030054330-connect-example-associated-definitions.js
│   ├── 20221107022314-resturcture-dialects-as-arrays.js
│   ├── 20221124200346-expand-headword.js
│   ├── 20221207003231-nominal-modifier.js
│   ├── 20221217204603-definitions-with-nsibidi.js
│   ├── 20230112035359-add-is-common.js
│   ├── 20230118013604-convert-stems-to-object-id.js
│   ├── 20230201191800-convert-medial-to-active.js
│   ├── 20230201193438-add-present-passive-to-verbs.js
│   ├── 20230314160556-convert-frequency-to-number.js
│   ├── 20230409220217-convert-igbo-definitions-to-include-nsibidi.js
│   ├── 20230522011130-pronunciation-to-pronunciations.js
│   ├── 20230526231511-example-suggestions-approvals-denials-review.js
│   ├── 20230607004329-trim-headword-and-tenses-whitespace-fix.js
│   ├── 20240908000598-create-default-igbo-api-project.js
│   ├── 20240908000599-change-source-to-origin.js
│   ├── 20240908000600-generalize-examples.js
│   ├── 20240908162526-assign-projectid-to-each-collection.js
│   ├── 20240913215339-move-example-pronunciations-to-translations.js
│   ├── 20240928023848-add-languages-to-corpus.js
│   ├── 20240928024053-add-types-to-projecs.js
│   ├── 20241116014146-add-bit-rate-audio-pronunciation.js
│   ├── 20241203060241-insert-owner-firebase-id-on-project.js
│   ├── 20241203060300-connect-paywall-to-project.js
│   ├── 20241206235108-remove-crowdsourcing.js
│   ├── 20250212184340-add-viewableSectionIds-to-example-suggestions.js
│   └── 20250417110353-migrate-igbo-speech-example-suggestions.js
├── next-env.d.ts
├── next-i18next.config.js
├── next.config.js
├── package.json
├── postcss.config.js
├── public/
│   └── .hosting
├── script.js
├── src/
│   ├── APIs/
│   │   ├── FlagsAPI.ts
│   │   ├── RedisAPI.ts
│   │   └── __tests__/
│   │       └── FlagsAPI.test.ts
│   ├── __data__/
│   │   └── assetStub.ts
│   ├── __tests__/
│   │   ├── Card/
│   │   │   └── Card.test.tsx
│   │   ├── Demo/
│   │   │   └── Demo.test.tsx
│   │   ├── FadeIn/
│   │   │   └── FadeIn.test.tsx
│   │   ├── Input/
│   │   │   └── Input.test.tsx
│   │   ├── Statistics/
│   │   │   ├── Stat.test.tsx
│   │   │   └── Statistics.test.tsx
│   │   ├── components/
│   │   │   └── TestContext.tsx
│   │   └── shared/
│   │       ├── fixtures.ts
│   │       └── script.ts
│   ├── app.ts
│   ├── config.ts
│   ├── controllers/
│   │   ├── __tests__/
│   │   │   ├── developers.test.ts
│   │   │   ├── examples.test.ts
│   │   │   ├── speechToText.test.ts
│   │   │   ├── stripe.test.ts
│   │   │   └── translation.test.ts
│   │   ├── developers.ts
│   │   ├── email.ts
│   │   ├── examples.ts
│   │   ├── nsibidi.ts
│   │   ├── speechToText.ts
│   │   ├── stats.ts
│   │   ├── stripe/
│   │   │   ├── __mocks__/
│   │   │   │   └── webhooks.ts
│   │   │   ├── __tests__/
│   │   │   │   └── index.test.ts
│   │   │   ├── index.ts
│   │   │   └── webhooks.ts
│   │   ├── translation.ts
│   │   ├── types.ts
│   │   ├── utils/
│   │   │   ├── __mocks__/
│   │   │   │   └── fetchBase64Data.ts
│   │   │   ├── __tests__/
│   │   │   │   ├── minimizeVerbsAndSuffixes.test.ts
│   │   │   │   ├── parseAWS.test.ts
│   │   │   │   └── queries.test.ts
│   │   │   ├── buildDocs.ts
│   │   │   ├── convertToSkipAndLimit.ts
│   │   │   ├── fetchBase64Data.ts
│   │   │   ├── index.ts
│   │   │   ├── minimizeVerbsAndSuffixes.ts
│   │   │   ├── minimizeWords.ts
│   │   │   ├── parseAWS.ts
│   │   │   ├── parseRange.ts
│   │   │   ├── queries.ts
│   │   │   ├── searchWordUsingEnglish.ts
│   │   │   ├── searchWordUsingIgbo.ts
│   │   │   ├── sortDocsBy.ts
│   │   │   └── types.ts
│   │   └── words.ts
│   ├── dictionaries/
│   │   ├── buildDictionaries.ts
│   │   ├── en-ig/
│   │   │   └── en-ig_normalized_expanded.json
│   │   ├── ig-en/
│   │   │   ├── ig-en.json
│   │   │   ├── ig-en_1000_common.json
│   │   │   ├── ig-en_expanded.json
│   │   │   └── ig-en_normalized_expanded.json
│   │   ├── nsibidi/
│   │   │   └── nsibidi_dictionary.ts
│   │   └── seed.ts
│   ├── functions/
│   │   └── __tests__/
│   │       └── functions.test.ts
│   ├── functions.ts
│   ├── general.css
│   ├── lib/
│   │   └── gtag.js
│   ├── middleware/
│   │   ├── __tests__/
│   │   │   ├── authorizeCheckoutSession.test.ts
│   │   │   ├── authorizePortalSession.test.ts
│   │   │   └── developerAuthorization.test.ts
│   │   ├── analytics.ts
│   │   ├── attachRedisClient.ts
│   │   ├── authorizeCheckoutSession.ts
│   │   ├── authorizePortalSession.ts
│   │   ├── cache.ts
│   │   ├── developerAuthorization.ts
│   │   ├── errorHandler.ts
│   │   ├── helpers/
│   │   │   ├── __tests__/
│   │   │   │   ├── authorizeDeveloperUsage.test.ts
│   │   │   │   ├── createDeveloperUsage.test.ts
│   │   │   │   └── findDeveloperUsage.test.ts
│   │   │   ├── authorizeDeveloperUsage.ts
│   │   │   ├── createDeveloperUsage.ts
│   │   │   ├── findDeveloper.ts
│   │   │   └── findDeveloperUsage.ts
│   │   ├── logger.ts
│   │   ├── noCache.ts
│   │   ├── validId.ts
│   │   ├── validateAdminApiKey.ts
│   │   ├── validateApiKey.ts
│   │   ├── validateDeveloperBody.ts
│   │   ├── validateStripeSignature.ts
│   │   └── validateUpdateDeveloperBody.ts
│   ├── models/
│   │   ├── Developer.ts
│   │   ├── DeveloperUsage.ts
│   │   ├── Example.ts
│   │   ├── NsibidiCharacter.ts
│   │   ├── Stat.ts
│   │   ├── Word.ts
│   │   └── plugins/
│   │       └── index.ts
│   ├── pages/
│   │   ├── 404/
│   │   │   └── index.page.tsx
│   │   ├── APIs/
│   │   │   ├── DevelopersAPI.ts
│   │   │   ├── PredictionAPI.ts
│   │   │   ├── __mocks__/
│   │   │   │   └── DevelopersAPI.ts
│   │   │   └── __tests__/
│   │   │       ├── DevelopersAPI.test.tsx
│   │   │       └── PredictionAPI.test.tsx
│   │   ├── App.tsx
│   │   ├── __tests__/
│   │   │   └── App.test.tsx
│   │   ├── _app.page.tsx
│   │   ├── _document.page.tsx
│   │   ├── about/
│   │   │   └── index.page.tsx
│   │   ├── assets/
│   │   │   └── favicon/
│   │   │       └── site.webmanifest
│   │   ├── atoms/
│   │   │   ├── audioAtoms.ts
│   │   │   ├── dashboardAtoms.ts
│   │   │   ├── feedbackAtoms.ts
│   │   │   ├── index.ts
│   │   │   └── predictionAtoms.ts
│   │   ├── components/
│   │   │   ├── CallToAction/
│   │   │   │   ├── CallToAction.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Card/
│   │   │   │   ├── Card.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Demo/
│   │   │   │   ├── Demo.tsx
│   │   │   │   ├── components/
│   │   │   │   │   ├── IgboAPI.tsx
│   │   │   │   │   ├── IgboSpeech/
│   │   │   │   │   │   ├── components/
│   │   │   │   │   │   │   ├── AudioOptions/
│   │   │   │   │   │   │   │   ├── AudioOption.tsx
│   │   │   │   │   │   │   │   └── index.tsx
│   │   │   │   │   │   │   ├── AudioPlayer/
│   │   │   │   │   │   │   │   ├── AudioPlayerBase.tsx
│   │   │   │   │   │   │   │   ├── RecordButton.tsx
│   │   │   │   │   │   │   │   ├── UploadButton.tsx
│   │   │   │   │   │   │   │   └── index.tsx
│   │   │   │   │   │   │   ├── ConvertToTextButton.tsx
│   │   │   │   │   │   │   ├── DragState.tsx
│   │   │   │   │   │   │   ├── ResultText.tsx
│   │   │   │   │   │   │   └── ValidAudioType.ts
│   │   │   │   │   │   └── index.tsx
│   │   │   │   │   ├── StartBuilding.tsx
│   │   │   │   │   └── Translate.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Donate/
│   │   │   │   ├── Donate.tsx
│   │   │   │   └── index.ts
│   │   │   ├── FadeIn/
│   │   │   │   ├── FadeIn.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Features/
│   │   │   │   ├── Features.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Footer/
│   │   │   │   ├── Footer.tsx
│   │   │   │   ├── __tests__/
│   │   │   │   │   └── Footer.test.tsx
│   │   │   │   └── index.ts
│   │   │   ├── GitHubStars/
│   │   │   │   ├── GitHubStars.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Input/
│   │   │   │   ├── Input.tsx
│   │   │   │   └── index.ts
│   │   │   ├── LastCall/
│   │   │   │   ├── LastCall.tsx
│   │   │   │   └── index.ts
│   │   │   ├── MentionedIn/
│   │   │   │   ├── MentionedIn.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Navbar/
│   │   │   │   ├── Navbar.tsx
│   │   │   │   ├── NavigationMenu.tsx
│   │   │   │   ├── NavigationOptions.tsx
│   │   │   │   ├── __tests__/
│   │   │   │   │   ├── Navbar.test.tsx
│   │   │   │   │   ├── NavigationMenu.test.tsx
│   │   │   │   │   └── NavigationOptions.test.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Products/
│   │   │   │   ├── Products.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Statistics/
│   │   │   │   ├── Stat.tsx
│   │   │   │   ├── Statistics.tsx
│   │   │   │   └── index.ts
│   │   │   └── UseCases/
│   │   │       ├── UseCaseCard.tsx
│   │   │       ├── UseCases.tsx
│   │   │       └── index.ts
│   │   ├── dashboard/
│   │   │   ├── __tests__/
│   │   │   │   ├── credentials.page.test.tsx
│   │   │   │   ├── dashboard.test.tsx
│   │   │   │   ├── layout.test.tsx
│   │   │   │   ├── plans.page.test.tsx
│   │   │   │   └── profile.test.tsx
│   │   │   ├── components/
│   │   │   │   ├── DashboardMenu.tsx
│   │   │   │   ├── DashboardNavigationMenu.tsx
│   │   │   │   └── __tests__/
│   │   │   │       ├── DashboardMenu.test.tsx
│   │   │   │       └── DashboardNavigationMenu.test.tsx
│   │   │   ├── credentials.page.tsx
│   │   │   ├── dashboard.tsx
│   │   │   ├── error.tsx
│   │   │   ├── index.page.tsx
│   │   │   ├── layout.tsx
│   │   │   ├── plans.page.tsx
│   │   │   ├── profile.page.tsx
│   │   │   └── shared/
│   │   │       └── pricingFeatures.tsx
│   │   ├── hooks/
│   │   │   ├── __mocks__/
│   │   │   │   └── useCallable.ts
│   │   │   ├── useCallable.ts
│   │   │   └── useRecorder.ts
│   │   ├── index.page.tsx
│   │   ├── managers/
│   │   │   ├── AuthManager.tsx
│   │   │   └── __tests__/
│   │   │       └── AuthManager.test.tsx
│   │   ├── pricing/
│   │   │   ├── __tests__/
│   │   │   │   └── _index.page.test.tsx
│   │   │   ├── _index.page.tsx
│   │   │   ├── components/
│   │   │   │   ├── PricingCard.tsx
│   │   │   │   └── __tests__/
│   │   │   │       └── PricingCard.test.tsx
│   │   │   └── types.ts
│   │   ├── privacy/
│   │   │   └── index.page.tsx
│   │   ├── shared/
│   │   │   └── useCases.ts
│   │   ├── signup/
│   │   │   ├── index.page.tsx
│   │   │   └── login.tsx
│   │   ├── terms/
│   │   │   └── index.page.tsx
│   │   └── utils/
│   │       ├── getAWSAsset.ts
│   │       └── isProduction.ts
│   ├── public/
│   │   └── locales/
│   │       ├── en/
│   │       │   ├── about.json
│   │       │   ├── common.json
│   │       │   ├── index.js
│   │       │   └── signup.json
│   │       └── ig/
│   │           ├── about.json
│   │           ├── common.json
│   │           ├── index.js
│   │           └── signup.json
│   ├── routers/
│   │   ├── index.ts
│   │   ├── router.ts
│   │   ├── routerV2.ts
│   │   ├── siteRouter.ts
│   │   ├── stripeRouter.ts
│   │   └── testRouter.ts
│   ├── server.ts
│   ├── services/
│   │   ├── __tests__/
│   │   │   ├── database.test.ts
│   │   │   └── stripe.test.ts
│   │   ├── database.ts
│   │   ├── firebase-admin.ts
│   │   ├── firebaseConfigs.ts
│   │   ├── stripe.ts
│   │   └── words.ts
│   ├── shared/
│   │   ├── constants/
│   │   │   ├── AccountStatus.ts
│   │   │   ├── ApiType.ts
│   │   │   ├── ApiTypeToRoute.ts
│   │   │   ├── ApiUsageLimit.ts
│   │   │   ├── ChakraTheme.ts
│   │   │   ├── DefaultAudios.ts
│   │   │   ├── DemoOption.ts
│   │   │   ├── Dialect.ts
│   │   │   ├── DialectEnum.ts
│   │   │   ├── Endpoint.ts
│   │   │   ├── ExampleStyleEnum.ts
│   │   │   ├── ExampleStyles.ts
│   │   │   ├── Feedback.ts
│   │   │   ├── LanguageEnum.ts
│   │   │   ├── PartTypes.ts
│   │   │   ├── Plan.ts
│   │   │   ├── SentenceTypes.ts
│   │   │   ├── StatTypes.ts
│   │   │   ├── StopWords.ts
│   │   │   ├── SuggestionSourceEnum.ts
│   │   │   ├── Tenses.ts
│   │   │   ├── Version.ts
│   │   │   ├── WordAttributeEnum.ts
│   │   │   ├── WordAttributes.ts
│   │   │   ├── WordClass.ts
│   │   │   ├── WordClassEnum.ts
│   │   │   ├── WordTagEnum.ts
│   │   │   ├── WordTags.ts
│   │   │   ├── diacriticCodes.ts
│   │   │   ├── errorMessages.ts
│   │   │   ├── navigationLinks.ts
│   │   │   └── parseFileLocations.ts
│   │   └── utils/
│   │       ├── __tests__/
│   │       │   ├── createRegExp.test.ts
│   │       │   └── getErrorMessage.test.ts
│   │       ├── blobToBase64.ts
│   │       ├── blobUrlToBase64.ts
│   │       ├── createQueryRegex.ts
│   │       ├── createRegExp.ts
│   │       ├── documentUtils.ts
│   │       ├── getErrorMessage.ts
│   │       ├── normalization.js
│   │       ├── removeAccents.ts
│   │       ├── removePrefix.ts
│   │       ├── replaceAbbreviations.ts
│   │       └── wrapConsole.ts
│   ├── siteConstants.ts
│   ├── styles.css
│   └── types/
│       ├── databaseStats.ts
│       ├── developer.ts
│       ├── developerUsage.ts
│       ├── example.ts
│       ├── express.ts
│       ├── formFields.ts
│       ├── index.ts
│       ├── nsibidiCharacter.ts
│       ├── stat.ts
│       └── word.ts
├── tailwind.config.js
├── testSetup.ts
├── theme.config.jsx
├── tsconfig.json
└── tsconfig.test.json
Download .txt
SYMBOL INDEX (449 symbols across 148 files)

FILE: @types/console.d.ts
  type Console (line 2) | interface Console {

FILE: @types/environment.d.ts
  type ProcessEnv (line 3) | interface ProcessEnv {

FILE: __mocks__/mongoose.ts
  class Model (line 5) | class Model {
    method constructor (line 7) | constructor(value: object) {
    method find (line 11) | static find() {
    method findOne (line 15) | static findOne() {
    method save (line 31) | save() {

FILE: __mocks__/stripe.ts
  class Stripe (line 1) | class Stripe {
    method constructor (line 21) | constructor(apiKey: string) {

FILE: __tests__/shared/commands.ts
  type Id (line 17) | type Id = string | Types.ObjectId;
  type Query (line 19) | type Query = Partial<{
  type Options (line 31) | type Options = Partial<{

FILE: __tests__/shared/constants.ts
  constant LOCAL_ROUTE (line 4) | const LOCAL_ROUTE = '/';
  constant API_ROUTE (line 5) | const API_ROUTE = `/api/${Version.VERSION_1}`;
  constant API_ROUTE_V2 (line 6) | const API_ROUTE_V2 = `/api/${Version.VERSION_2}`;
  constant TEST_ROUTE (line 7) | const TEST_ROUTE = `/api/${Version.VERSION_1}/test`;
  constant STRIPE_ROUTE (line 8) | const STRIPE_ROUTE = '/stripe';
  constant API_URL (line 9) | const API_URL = 'https://igboapi.com';
  constant WORD_KEYS_V1 (line 11) | const WORD_KEYS_V1 = [
  constant WORD_KEYS_V2 (line 25) | const WORD_KEYS_V2 = [
  constant EXAMPLE_KEYS_V1 (line 38) | const EXAMPLE_KEYS_V1 = [
  constant EXAMPLE_KEYS_V2 (line 50) | const EXAMPLE_KEYS_V2 = [
  constant EXCLUDE_KEYS (line 64) | const EXCLUDE_KEYS = ['__v', '_id'];
  constant SITE_TITLE (line 65) | const SITE_TITLE = 'The First African Language API';
  constant DOCS_SITE_TITLE (line 66) | const DOCS_SITE_TITLE = 'Igbo API Documentation';
  constant INVALID_ID (line 67) | const INVALID_ID = 'fdsafdsad';
  constant NONEXISTENT_ID (line 68) | const NONEXISTENT_ID = new mongoose.Types.ObjectId();
  constant MAIN_KEY (line 69) | const MAIN_KEY = 'main_key';
  constant FALLBACK_API_KEY (line 70) | const FALLBACK_API_KEY = 'fallback_api_key';

FILE: env.d.ts
  type ProcessEnv (line 3) | interface ProcessEnv {

FILE: migrations/20201106045436-add-suggestion-properties.js
  method up (line 2) | async up(db) {
  method down (line 12) | async down(db) {

FILE: migrations/20201108164925-add-exampleForWordSuggestion-field.js
  method up (line 2) | async up(db) {
  method down (line 11) | async down(db) {

FILE: migrations/20201109083748-remove-examples-from-words.js
  method up (line 2) | async up(db) {
  method down (line 11) | async down(db) {

FILE: migrations/20201118192335-add-merged-by.js
  method up (line 2) | async up(db) {
  method down (line 11) | async down(db) {

FILE: migrations/20201121195224-add-updated-on-for-words-and-examples.js
  method up (line 2) | async up(db) {
  method down (line 11) | async down(db) {

FILE: migrations/20201206042142-add-accented-field.js
  method up (line 2) | async up(db) {
  method down (line 13) | async down(db) {

FILE: migrations/20201213020925-uid-fields-on-suggestions.js
  method up (line 2) | async up(db) {
  method down (line 18) | async down(db) {

FILE: migrations/20210225022115-create-dialects.js
  method up (line 35) | async up(db) {
  method down (line 45) | async down(db) {

FILE: migrations/20210225235148-update-variations-to-array.js
  method up (line 35) | async up(db) {
  method down (line 45) | async down(db) {

FILE: migrations/20210306224633-add-dialects-for-word-suggestions-and-generic-words.js
  method up (line 35) | async up(db) {
  method down (line 45) | async down(db) {

FILE: migrations/20210325194345-add-central-igbo.js
  method up (line 2) | async up(db) {
  method down (line 11) | async down(db) {

FILE: migrations/20210331134705-remove-developer-origin.js
  method up (line 2) | async up(db) {
  method down (line 10) | async down(db) {

FILE: migrations/20210426171953-remove-normalized-field.js
  method up (line 2) | async up(db) {
  method down (line 11) | async down(db) {

FILE: migrations/20210814210437-pre-populate-dialects.js
  method up (line 22) | async up(db) {
  method down (line 47) | async down(db) {

FILE: migrations/20210820170937-merge-accented-and-word.js
  method up (line 22) | async up(db) {
  method down (line 70) | async down(db) {

FILE: migrations/20210820175620-merge-accented-and-example.js
  method up (line 2) | async up(db) {
  method down (line 32) | async down(db) {

FILE: migrations/20210822145619-change-central-to-standard.js
  method up (line 2) | async up(db) {
  method down (line 14) | async down(db) {

FILE: migrations/20210831163032-add-is-complete-word.js
  method up (line 2) | async up(db) {
  method down (line 11) | async down(db) {

FILE: migrations/20210903175644-remove-is-complete-word.js
  method up (line 2) | async up(db) {
  method down (line 11) | async down(db) {

FILE: migrations/20211030133331-add-active-and-passive-verbs.js
  method up (line 2) | async up(db) {
  method down (line 19) | async down(db) {

FILE: migrations/20211121214701-add-nyms.js
  method up (line 2) | async up(db) {
  method down (line 16) | async down(db) {

FILE: migrations/20211218192401-add-isComplete.js
  method up (line 52) | async up(db) {
  method down (line 66) | async down(db) {

FILE: migrations/20220107155512-add-nsibidi.js
  method up (line 2) | async up(db) {
  method down (line 11) | async down(db) {

FILE: migrations/20220125175808-restructure-dialects.js
  method up (line 99) | async up(db) {
  method down (line 114) | async down(db) {

FILE: migrations/20220208140327-example-pronunciations.js
  method up (line 2) | async up(db) {
  method down (line 11) | async down(db) {

FILE: migrations/20220216030851-remove-verb-prefixes.js
  method up (line 47) | async up(db) {
  method down (line 62) | async down(db) {

FILE: migrations/20220301211505-convert-unix-to-iso.js
  method up (line 44) | async up(db) {
  method down (line 62) | async down(db) {

FILE: migrations/20220308132126-add-is-accented.js
  method up (line 2) | async up(db) {
  method down (line 11) | async down(db) {

FILE: migrations/20220406005107-add-tenses.js
  method up (line 242) | async up(db) {
  method down (line 259) | async down(db) {

FILE: migrations/20220423222134-add-attributes.js
  method up (line 2) | async up(db) {
  method down (line 24) | async down(db) {

FILE: migrations/20220425130741-extend-example-sentences-with-style-and-meaning.js
  method up (line 2) | async up(db) {
  method down (line 16) | async down(db) {

FILE: migrations/20220808024209-add-borrowed-term-field.js
  method up (line 2) | async up(db) {
  method down (line 22) | async down(db) {

FILE: migrations/20220808033804-add-tags.js
  method up (line 2) | async up(db) {
  method down (line 15) | async down(db) {

FILE: migrations/20220808042906-replace-nyms-for-related-terms.js
  method up (line 2) | async up(db) {
  method down (line 18) | async down(db) {

FILE: migrations/20221014123241-add-is-stem.js
  method up (line 2) | async up(db) {
  method down (line 11) | async down(db) {

FILE: migrations/20221030034746-restructure-definitions.js
  method up (line 5) | async up(db) {
  method down (line 47) | async down(db) {

FILE: migrations/20221030054330-connect-example-associated-definitions.js
  method up (line 35) | async up(db) {
  method down (line 50) | async down(db) {

FILE: migrations/20221107022314-resturcture-dialects-as-arrays.js
  method up (line 54) | async up(db) {
  method down (line 69) | async down(db) {

FILE: migrations/20221124200346-expand-headword.js
  method up (line 2) | async up(db) {
  method down (line 16) | async down(db) {

FILE: migrations/20221207003231-nominal-modifier.js
  method up (line 43) | async up(db) {
  method down (line 58) | async down(db) {

FILE: migrations/20221217204603-definitions-with-nsibidi.js
  method up (line 21) | async up(db) {
  method down (line 28) | async down(db) {

FILE: migrations/20230112035359-add-is-common.js
  method up (line 2) | async up(db) {
  method down (line 11) | async down(db) {

FILE: migrations/20230118013604-convert-stems-to-object-id.js
  method up (line 49) | async up(db) {
  method down (line 64) | async down(db) {

FILE: migrations/20230201191800-convert-medial-to-active.js
  method up (line 10) | async up(db) {
  method down (line 24) | async down() {

FILE: migrations/20230201193438-add-present-passive-to-verbs.js
  method up (line 26) | async up(db) {
  method down (line 40) | async down(db) {

FILE: migrations/20230314160556-convert-frequency-to-number.js
  method up (line 2) | async up(db) {
  method down (line 24) | async down(db) {

FILE: migrations/20230409220217-convert-igbo-definitions-to-include-nsibidi.js
  method up (line 64) | async up(db) {
  method down (line 78) | async down(db) {

FILE: migrations/20230522011130-pronunciation-to-pronunciations.js
  method up (line 26) | async up(db) {
  method down (line 40) | async down(db) {

FILE: migrations/20230526231511-example-suggestions-approvals-denials-review.js
  method up (line 50) | async up(db) {
  method down (line 57) | async down(db) {

FILE: migrations/20230607004329-trim-headword-and-tenses-whitespace-fix.js
  method up (line 103) | async up(db) {
  method down (line 108) | async down(db) {

FILE: migrations/20240908000598-create-default-igbo-api-project.js
  method up (line 4) | async up(db) {
  method down (line 16) | async down(db) {

FILE: migrations/20240908000599-change-source-to-origin.js
  method up (line 24) | async up(db) {
  method down (line 33) | async down(db) {

FILE: migrations/20240908000600-generalize-examples.js
  method up (line 40) | async up(db) {
  method down (line 49) | async down(db) {

FILE: migrations/20240908162526-assign-projectid-to-each-collection.js
  method up (line 2) | async up(db) {
  method down (line 30) | async down(db) {

FILE: migrations/20240913215339-move-example-pronunciations-to-translations.js
  method up (line 45) | async up(db) {
  method down (line 56) | async down(db) {

FILE: migrations/20240928023848-add-languages-to-corpus.js
  method up (line 2) | async up(db) {
  method down (line 14) | async down(db) {

FILE: migrations/20240928024053-add-types-to-projecs.js
  method up (line 2) | async up(db) {
  method down (line 14) | async down(db) {

FILE: migrations/20241116014146-add-bit-rate-audio-pronunciation.js
  method up (line 2) | async up(db) {
  method down (line 13) | async down(db) {

FILE: migrations/20241203060241-insert-owner-firebase-id-on-project.js
  method up (line 24) | async up(db) {
  method down (line 47) | async down(db) {

FILE: migrations/20241203060300-connect-paywall-to-project.js
  method up (line 28) | async up(db) {
  method down (line 66) | async down(db) {

FILE: migrations/20241206235108-remove-crowdsourcing.js
  method up (line 2) | async up(db) {
  method down (line 16) | async down() {}

FILE: migrations/20250212184340-add-viewableSectionIds-to-example-suggestions.js
  method up (line 2) | async up(db) {
  method down (line 16) | async down() {}

FILE: migrations/20250417110353-migrate-igbo-speech-example-suggestions.js
  method up (line 3) | async up(db) {
  method down (line 41) | async down() {}

FILE: src/APIs/FlagsAPI.ts
  type HandleFlags (line 5) | type HandleFlags = {

FILE: src/APIs/RedisAPI.ts
  type RedisClient (line 10) | type RedisClient = {
  type GetValue (line 16) | type GetValue = {

FILE: src/__tests__/shared/fixtures.ts
  type RequestOptions (line 23) | interface RequestOptions {

FILE: src/config.ts
  constant RUNTIME_ENV (line 13) | const RUNTIME_ENV = defineString('RUNTIME_ENV').value();
  constant ENV_REPLICA_SET (line 14) | const ENV_REPLICA_SET = defineBoolean('ENV_REPLICA_SET').value();
  constant ENV_MONGO_URI (line 15) | const ENV_MONGO_URI = defineString('ENV_MONGO_URI').value();
  constant ENV_FIREBASE_CONFIG (line 16) | const ENV_FIREBASE_CONFIG = defineString('ENV_FIREBASE_CONFIG').value();
  constant ENV_FIREBASE_SERVICE_ACCOUNT (line 17) | const ENV_FIREBASE_SERVICE_ACCOUNT = defineString('ENV_FIREBASE_SERVICE_...
  constant ENV_CLIENT_TEST (line 18) | const ENV_CLIENT_TEST = defineBoolean('ENV_CLIENT_TEST').value();
  constant SENDGRID_API_KEY_SOURCE (line 21) | const SENDGRID_API_KEY_SOURCE = defineString('SENDGRID_API_KEY').value();
  constant SENDGRID_NEW_DEVELOPER_ACCOUNT_TEMPLATE_SOURCE (line 22) | const SENDGRID_NEW_DEVELOPER_ACCOUNT_TEMPLATE_SOURCE = defineString(
  constant ENV_MAIN_KEY (line 27) | const ENV_MAIN_KEY = defineString('ENV_MAIN_KEY').value();
  constant ENV_SPEECH_TO_TEXT_API (line 30) | const ENV_SPEECH_TO_TEXT_API = defineString('ENV_SPEECH_TO_TEXT_API').va...
  constant ENV_IGBO_STT_URL (line 31) | const ENV_IGBO_STT_URL = defineString('ENV_IGBO_STT_URL').value();
  constant ENV_IGBO_TO_ENGLISH_URL (line 32) | const ENV_IGBO_TO_ENGLISH_URL = defineString('ENV_IGBO_TO_ENGLISH_URL')....
  constant ENV_ENGLISH_TO_IGBO_URL (line 33) | const ENV_ENGLISH_TO_IGBO_URL = defineString('ENV_ENGLISH_TO_IGBO_URL')....
  constant ANALYTICS_GA_TRACKING_ID (line 36) | const ANALYTICS_GA_TRACKING_ID = defineString('ANALYTICS_GA_TRACKING_ID'...
  constant ANALYTICS_GA_API_SECRET (line 37) | const ANALYTICS_GA_API_SECRET = defineString('ANALYTICS_GA_API_SECRET')....
  constant ENV_REDIS_PORT (line 40) | const ENV_REDIS_PORT = defineInt('ENV_REDIS_PORT').value();
  constant ENV_REDIS_URL (line 41) | const ENV_REDIS_URL = defineString('ENV_REDIS_URL').value();
  constant ENV_REDIS_HOST (line 42) | const ENV_REDIS_HOST = defineString('ENV_REDIS_HOST').value();
  constant ENV_REDIS_USERNAME (line 43) | const ENV_REDIS_USERNAME = defineString('ENV_REDIS_USERNAME').value();
  constant ENV_REDIS_PASSWORD (line 44) | const ENV_REDIS_PASSWORD = defineString('ENV_REDIS_PASSWORD').value();
  constant GITHUB_STATS_TOKEN_SOURCE (line 47) | const GITHUB_STATS_TOKEN_SOURCE = defineString('GITHUB_STATS_TOKEN').val...
  constant STRIPE_SECRET_KEY_SOURCE (line 50) | const STRIPE_SECRET_KEY_SOURCE = defineString('STRIPE_SECRET_KEY').value();
  constant STRIPE_ENDPOINT_SECRET_SOURCE (line 51) | const STRIPE_ENDPOINT_SECRET_SOURCE = defineString('STRIPE_ENDPOINT_SECR...
  constant DB_NAME (line 69) | const DB_NAME = 'igbo_api';
  constant TEST_DB_NAME (line 70) | const TEST_DB_NAME = 'test_igbo_api';
  constant PORT (line 75) | const PORT = process.env.PORT || 8080;
  constant PROD_LIMIT (line 76) | const PROD_LIMIT = 500;
  constant MONGO_HOST (line 77) | const MONGO_HOST = process.env.CONTAINER_HOST || '127.0.0.1';
  constant REPLICA_SET_NAME (line 78) | const REPLICA_SET_NAME = 'rs0';
  constant FIRST_REPLICA_SET_PORT (line 79) | const FIRST_REPLICA_SET_PORT = '2717';
  constant SECOND_REPLICA_SET_PORT (line 80) | const SECOND_REPLICA_SET_PORT = '2727';
  constant THIRD_REPLICA_SET_PORT (line 81) | const THIRD_REPLICA_SET_PORT = '2737';
  constant FALLBACK_MONGO_PORT (line 82) | const FALLBACK_MONGO_PORT = '27017';
  constant REPLICA_SET_MONGO_ROOT (line 83) | const REPLICA_SET_MONGO_ROOT =
  constant FALLBACK_MONGO_ROOT (line 87) | const FALLBACK_MONGO_ROOT = `mongodb://${MONGO_HOST}:${FALLBACK_MONGO_PO...
  constant MONGO_ROOT (line 88) | const MONGO_ROOT = useReplicaSet ? REPLICA_SET_MONGO_ROOT : FALLBACK_MON...
  constant QUERIES (line 89) | const QUERIES = useReplicaSet ? `?replicaSet=${REPLICA_SET_NAME}` : '';
  constant TEST_MONGO_URI (line 90) | const TEST_MONGO_URI = `${MONGO_ROOT}/${TEST_DB_NAME}`;
  constant LOCAL_MONGO_URI (line 91) | const LOCAL_MONGO_URI = `${MONGO_ROOT}/${DB_NAME}`;
  constant MONGO_URI (line 92) | const MONGO_URI = isTestingEnvironment
  constant FIREBASE_CONFIG (line 97) | const FIREBASE_CONFIG = ENV_FIREBASE_CONFIG;
  constant FIREBASE_SERVICE_ACCOUNT (line 98) | const FIREBASE_SERVICE_ACCOUNT = ENV_FIREBASE_SERVICE_ACCOUNT;
  constant CLIENT_TEST (line 99) | const CLIENT_TEST = ENV_CLIENT_TEST;
  constant CORS_CONFIG (line 101) | const CORS_CONFIG = {
  constant API_ROUTE (line 107) | const API_ROUTE = isProduction ? 'https://igboapi.com' : `http://localho...
  constant API_DOCS (line 108) | const API_DOCS = 'https://docs.igboapi.com';
  constant SPEECH_TO_TEXT_API (line 111) | const SPEECH_TO_TEXT_API = isProduction ? ENV_SPEECH_TO_TEXT_API : 'http...
  constant IGBO_STT_API (line 112) | const IGBO_STT_API = ENV_IGBO_STT_URL;
  constant IGBO_TO_ENGLISH_API (line 113) | const IGBO_TO_ENGLISH_API = ENV_IGBO_TO_ENGLISH_URL;
  constant ENGLIGH_TO_IGBO_API (line 114) | const ENGLIGH_TO_IGBO_API = ENV_ENGLISH_TO_IGBO_URL;
  constant SENDGRID_API_KEY (line 116) | const SENDGRID_API_KEY = SENDGRID_API_KEY_SOURCE || '';
  constant SENDGRID_NEW_DEVELOPER_ACCOUNT_TEMPLATE (line 117) | const SENDGRID_NEW_DEVELOPER_ACCOUNT_TEMPLATE =
  constant API_FROM_EMAIL (line 119) | const API_FROM_EMAIL = 'kedu@nkowaokwu.com';
  constant MAIN_KEY (line 127) | const MAIN_KEY = ENV_MAIN_KEY || 'main_key';
  constant GA_TRACKING_ID (line 130) | const GA_TRACKING_ID = ANALYTICS_GA_TRACKING_ID;
  constant GA_API_SECRET (line 131) | const GA_API_SECRET = ANALYTICS_GA_API_SECRET;
  constant GA_URL (line 132) | const GA_URL = 'https://www.google-analytics.com/mp/collect';
  constant DEBUG_GA_URL (line 133) | const DEBUG_GA_URL = 'https://www.google-analytics.com/debug/mp/collect';
  constant REDIS_HOST (line 136) | const REDIS_HOST = ENV_REDIS_HOST;
  constant REDIS_PORT (line 137) | const REDIS_PORT = ENV_REDIS_PORT;
  constant REDIS_USERNAME (line 138) | const REDIS_USERNAME = ENV_REDIS_USERNAME;
  constant REDIS_PASSWORD (line 139) | const REDIS_PASSWORD = ENV_REDIS_PASSWORD;
  constant REDIS_URL (line 140) | const REDIS_URL = ENV_REDIS_URL;
  constant REDIS_CACHE_EXPIRATION (line 142) | const REDIS_CACHE_EXPIRATION = 604800;
  constant GITHUB_STATS_TOKEN (line 145) | const GITHUB_STATS_TOKEN = GITHUB_STATS_TOKEN_SOURCE;
  constant STRIPE_SECRET_KEY (line 148) | const STRIPE_SECRET_KEY =
  constant STRIPE_ENDPOINT_SECRET (line 150) | const STRIPE_ENDPOINT_SECRET = STRIPE_ENDPOINT_SECRET_SOURCE || 'local_e...

FILE: src/controllers/__tests__/developers.test.ts
  class Developer (line 15) | class Developer {
    method constructor (line 17) | constructor(value: object) {
    method find (line 21) | static find() {
    method findOne (line 25) | static findOne() {}
    method save (line 27) | save() {

FILE: src/controllers/developers.ts
  constant TEST_EMAIL (line 10) | const TEST_EMAIL = 'developer@example.com';
  constant DEFAULT_PASSWORD (line 13) | const DEFAULT_PASSWORD = 'UNDEFINED_PASSWORD';
  type DeveloperDocument (line 17) | type DeveloperDocument = Document<unknown, any, DeveloperType> &

FILE: src/controllers/email.ts
  type EmailTemplate (line 13) | type EmailTemplate = {
  type DeveloperEmailConfig (line 59) | type DeveloperEmailConfig = {

FILE: src/controllers/examples.ts
  type SearchExamplesArg (line 46) | type SearchExamplesArg = {

FILE: src/controllers/speechToText.ts
  type AudioMetadata (line 7) | interface AudioMetadata {
  type Prediction (line 12) | interface Prediction {

FILE: src/controllers/stats.ts
  constant DEFAULT_STAT (line 8) | const DEFAULT_STAT = {
  constant DEFAULT_LENGTH (line 12) | const DEFAULT_LENGTH: DeveloperType[] = [];

FILE: src/controllers/stripe/webhooks.ts
  type Event (line 6) | interface Event {

FILE: src/controllers/translation.ts
  type Translation (line 9) | interface Translation {
  type LanguageCode (line 13) | type LanguageCode = `${LanguageEnum}`
  type SupportedLanguage (line 15) | type SupportedLanguage = {
  constant SUPPORTED_TRANSLATIONS (line 21) | const SUPPORTED_TRANSLATIONS: { [key in LanguageCode]: SupportedLanguage...

FILE: src/controllers/types.ts
  type ResponseData (line 4) | type ResponseData = {
  type ExampleResponseData (line 8) | interface ExampleResponseData extends ResponseData {
  type WordResponseData (line 12) | interface WordResponseData extends ResponseData {
  type Filters (line 16) | type Filters = {

FILE: src/controllers/utils/buildDocs.ts
  type NestedDoc (line 18) | type NestedDoc = { _id?: string, __v?: number };

FILE: src/controllers/utils/convertToSkipAndLimit.ts
  constant DEFAULT_RESPONSE_LIMIT (line 1) | const DEFAULT_RESPONSE_LIMIT = 10;
  constant MAX_RESPONSE_LIMIT (line 2) | const MAX_RESPONSE_LIMIT = 25;

FILE: src/controllers/utils/minimizeWords.ts
  type MinimizedWord (line 13) | type MinimizedWord = Omit<

FILE: src/controllers/utils/parseAWS.ts
  constant AWS_AUDIO_PRONUNCIATIONS_DELIMITER (line 1) | const AWS_AUDIO_PRONUNCIATIONS_DELIMITER = '/audio-pronunciations/';

FILE: src/controllers/utils/queries.ts
  type Keywords (line 10) | type Keywords = Keyword[];

FILE: src/controllers/utils/searchWordUsingEnglish.ts
  type EnglishSearch (line 10) | type EnglishSearch = {

FILE: src/controllers/utils/searchWordUsingIgbo.ts
  type IgboSearch (line 17) | type IgboSearch = {

FILE: src/controllers/utils/sortDocsBy.ts
  constant MATCHING_DEFINITION_INDEX (line 9) | const MATCHING_DEFINITION_INDEX = 1000;
  constant MATCHING_DEFINITION_INDEX_FACTOR (line 10) | const MATCHING_DEFINITION_INDEX_FACTOR = 100;
  constant WORD_LENGTH_FACTOR (line 11) | const WORD_LENGTH_FACTOR = 100;
  constant WORD_LENGTH_DIFFERENCE_FACTOR (line 12) | const WORD_LENGTH_DIFFERENCE_FACTOR = 15;
  constant IS_COMMON (line 13) | const IS_COMMON = 1000;
  constant IS_COMMON_THRESHOLD (line 14) | const IS_COMMON_THRESHOLD = -700;
  constant SIMILARITY_FACTOR (line 15) | const SIMILARITY_FACTOR = 100;
  constant EXACT_MATCH_FACTOR (line 16) | const EXACT_MATCH_FACTOR = 2000;
  constant SIMILAR_WORD_THRESHOLD (line 17) | const SIMILAR_WORD_THRESHOLD = 1.5;
  constant NO_FACTOR (line 18) | const NO_FACTOR = 0;

FILE: src/controllers/utils/types.ts
  type Meta (line 3) | type Meta = {
  type MinimizedWord (line 13) | type MinimizedWord = {
  type WordData (line 18) | type WordData = {
  type Solution (line 23) | type Solution = {
  type TopSolution (line 30) | type TopSolution = { solution: Solution, metaData: Meta };
  type Keyword (line 32) | type Keyword = {
  type Flags (line 41) | type Flags = {

FILE: src/controllers/words.ts
  constant IGNORE_ENGLISH_WORDS (line 21) | const IGNORE_ENGLISH_WORDS = [

FILE: src/dictionaries/seed.ts
  constant WRITE_DB_DELAY (line 17) | const WRITE_DB_DELAY = 15000;

FILE: src/functions.ts
  type SpeechToTextRequest (line 7) | interface SpeechToTextRequest {
  type TranscriptionAudio (line 11) | interface TranscriptionAudio {
  type TranslationRequest (line 16) | interface TranslationRequest {
  type DictionaryRequest (line 22) | interface DictionaryRequest {
  constant TEST_ONLY (line 124) | const TEST_ONLY = { demoInternal };

FILE: src/lib/gtag.js
  constant GA_TRACKING_ID (line 1) | const GA_TRACKING_ID = process.env.NEXT_PUBLIC_GA_ID;

FILE: src/middleware/analytics.ts
  type TrackingEvent (line 11) | interface TrackingEvent {

FILE: src/middleware/helpers/__tests__/createDeveloperUsage.test.ts
  class DeveloperUsage (line 9) | class DeveloperUsage {
    method constructor (line 10) | constructor() {

FILE: src/middleware/validateApiKey.ts
  constant FALLBACK_API_KEY (line 6) | const FALLBACK_API_KEY = 'fallback_api_key';

FILE: src/pages/APIs/DevelopersAPI.ts
  constant API_ROUTE (line 7) | const API_ROUTE = !isProduction() ? 'http://localhost:8080' : 'https://i...

FILE: src/pages/APIs/PredictionAPI.ts
  type Prediction (line 7) | interface Prediction {
  type Dictionary (line 11) | interface Dictionary {
  type SpeechToTextResponse (line 15) | interface SpeechToTextResponse extends Prediction {}
  type TranslationResponse (line 17) | interface TranslationResponse extends Translation {}
  type DictionaryResponse (line 19) | interface DictionaryResponse extends Dictionary {}

FILE: src/pages/_document.page.tsx
  class MyDocument (line 5) | class MyDocument extends Document {
    method getInitialProps (line 6) | static async getInitialProps(context: any) {
    method render (line 11) | render() {

FILE: src/pages/atoms/audioAtoms.ts
  type DefaultAudio (line 3) | interface DefaultAudio {

FILE: src/pages/components/Demo/components/IgboSpeech/components/AudioPlayer/UploadButton.tsx
  constant ACCEPT_FILE_TYPES (line 6) | const ACCEPT_FILE_TYPES = Object.values(ValidAudioType).join(', ');

FILE: src/pages/components/Demo/components/IgboSpeech/components/ConvertToTextButton.tsx
  type ConvertedAudio (line 19) | interface ConvertedAudio {

FILE: src/pages/components/Demo/components/IgboSpeech/components/DragState.tsx
  constant ACCEPT_FILE_TYPES (line 6) | const ACCEPT_FILE_TYPES = Object.values(ValidAudioType).join(', ');

FILE: src/pages/components/Demo/components/IgboSpeech/components/ValidAudioType.ts
  type ValidAudioType (line 1) | enum ValidAudioType {

FILE: src/pages/components/MentionedIn/MentionedIn.tsx
  constant NIGERIAN_TRIBUNE (line 5) | const NIGERIAN_TRIBUNE = {
  constant UIU (line 10) | const UIU = {
  constant BUILT_IN_AFRICA (line 14) | const BUILT_IN_AFRICA = {
  constant NUESROOM (line 18) | const NUESROOM = {
  constant WEDEYCODE (line 22) | const WEDEYCODE = {
  constant NASDAQ (line 26) | const NASDAQ = {
  constant TECHPOINT (line 30) | const TECHPOINT = {

FILE: src/pages/dashboard/layout.tsx
  constant DEFAULT_DEVELOPER (line 16) | const DEFAULT_DEVELOPER = {

FILE: src/pages/dashboard/shared/pricingFeatures.tsx
  type FeatureCategory (line 5) | enum FeatureCategory {
  type PricingFeatureCategory (line 11) | interface PricingFeatureCategory {
  type PricingFeature (line 16) | interface PricingFeature {

FILE: src/pages/hooks/useRecorder.ts
  constant MAX_AUDIO_SIZE (line 8) | const MAX_AUDIO_SIZE = 5000000;

FILE: src/pages/pricing/types.ts
  type PricingTier (line 1) | interface PricingTier {

FILE: src/pages/utils/getAWSAsset.ts
  constant AWS_URL (line 1) | const AWS_URL = 'https://nkowaokwu.s3.us-west-1.amazonaws.com/assets';

FILE: src/routers/router.ts
  constant FIFTEEN_MINUTES (line 20) | const FIFTEEN_MINUTES = 15 * 60 * 1000;
  constant REQUESTS_PER_MS (line 21) | const REQUESTS_PER_MS = 20;

FILE: src/services/database.ts
  constant DISCONNECTED (line 4) | const DISCONNECTED = 0;

FILE: src/services/firebaseConfigs.ts
  type FirebaseConfig (line 1) | interface FirebaseConfig {
  constant STAGING_FIREBASE_CONFIG (line 11) | const STAGING_FIREBASE_CONFIG: FirebaseConfig = {
  constant PRODUCTION_FIREBASE_CONFIG (line 20) | const PRODUCTION_FIREBASE_CONFIG: FirebaseConfig = {

FILE: src/shared/constants/AccountStatus.ts
  type AccountStatus (line 3) | enum AccountStatus {
  type Status (line 14) | type Status = AccountStatus | Stripe.Subscription.Status;

FILE: src/shared/constants/ApiType.ts
  type ApiType (line 1) | enum ApiType {

FILE: src/shared/constants/DefaultAudios.ts
  constant DEFAULT_AUDIOS (line 1) | const DEFAULT_AUDIOS = [

FILE: src/shared/constants/DemoOption.ts
  type DemoOption (line 1) | enum DemoOption {

FILE: src/shared/constants/DialectEnum.ts
  type DialectEnum (line 1) | enum DialectEnum {

FILE: src/shared/constants/Endpoint.ts
  type Endpoint (line 1) | enum Endpoint {

FILE: src/shared/constants/ExampleStyleEnum.ts
  type ExampleStyleEnum (line 1) | enum ExampleStyleEnum {

FILE: src/shared/constants/Feedback.ts
  type Feedback (line 1) | enum Feedback {

FILE: src/shared/constants/LanguageEnum.ts
  type LanguageEnum (line 2) | enum LanguageEnum {

FILE: src/shared/constants/Plan.ts
  type Plan (line 1) | enum Plan {

FILE: src/shared/constants/StatTypes.ts
  type StatTypes (line 1) | enum StatTypes {

FILE: src/shared/constants/SuggestionSourceEnum.ts
  type SuggestionSourceEnum (line 2) | enum SuggestionSourceEnum {

FILE: src/shared/constants/Version.ts
  type Version (line 1) | enum Version {

FILE: src/shared/constants/WordAttributeEnum.ts
  type WordAttributeEnum (line 1) | enum WordAttributeEnum {

FILE: src/shared/constants/WordClassEnum.ts
  type WordClassEnum (line 1) | enum WordClassEnum {

FILE: src/shared/constants/WordTagEnum.ts
  type WordTagEnum (line 1) | enum WordTagEnum {

FILE: src/shared/constants/diacriticCodes.ts
  constant OVERDOT_UPPERCASE_N (line 3) | const OVERDOT_UPPERCASE_N = 7748;
  constant GRAVE_UPPERCASE_N (line 4) | const GRAVE_UPPERCASE_N = 504;
  constant GRAVE_ACUTE_UPPERCASE_N (line 5) | const GRAVE_ACUTE_UPPERCASE_N = 323;
  constant UNDERDOT_UPPERCASE_I (line 6) | const UNDERDOT_UPPERCASE_I = 7882;
  constant UNDERDOT_UPPERCASE_O (line 7) | const UNDERDOT_UPPERCASE_O = 7884;
  constant UNDERDOT_UPPERCASE_U (line 8) | const UNDERDOT_UPPERCASE_U = 7908;
  constant GRAVE_UPPERCASE_A (line 9) | const GRAVE_UPPERCASE_A = 192;
  constant GRAVE_ACUTE_UPPERCASE_A (line 10) | const GRAVE_ACUTE_UPPERCASE_A = 193;
  constant MACRON_UPPERCASE_A (line 11) | const MACRON_UPPERCASE_A = 256;
  constant GRAVE_UPPERCASE_E (line 12) | const GRAVE_UPPERCASE_E = 200;
  constant GRAVE_ACUTE_UPPERCASE_E (line 13) | const GRAVE_ACUTE_UPPERCASE_E = 201;
  constant MACRON_UPPERCASE_E (line 14) | const MACRON_UPPERCASE_E = 274;
  constant GRAVE_UPPERCASE_I (line 15) | const GRAVE_UPPERCASE_I = 204;
  constant GRAVE_ACUTE_UPPERCASE_I (line 16) | const GRAVE_ACUTE_UPPERCASE_I = 205;
  constant MACRON_UPPERCASE_I (line 17) | const MACRON_UPPERCASE_I = 298;
  constant GRAVE_UPPERCASE_O (line 18) | const GRAVE_UPPERCASE_O = 210;
  constant GRAVE_ACUTE_UPPERCASE_O (line 19) | const GRAVE_ACUTE_UPPERCASE_O = 211;
  constant MACRON_UPPERCASE_O (line 20) | const MACRON_UPPERCASE_O = 332;
  constant GRAVE_UPPERCASE_U (line 21) | const GRAVE_UPPERCASE_U = 217;
  constant GRAVE_ACUTE_UPPERCASE_U (line 22) | const GRAVE_ACUTE_UPPERCASE_U = 218;
  constant MACRON_UPPERCASE_U (line 23) | const MACRON_UPPERCASE_U = 362;
  constant OVERDOT_LOWERCASE_N (line 25) | const OVERDOT_LOWERCASE_N = 7749;
  constant GRAVE_LOWERCASE_N (line 26) | const GRAVE_LOWERCASE_N = 505;
  constant GRAVE_ACUTE_LOWERCASE_N (line 27) | const GRAVE_ACUTE_LOWERCASE_N = 324;
  constant UNDERDOT_LOWERCASE_I (line 28) | const UNDERDOT_LOWERCASE_I = 7883;
  constant UNDERDOT_LOWERCASE_O (line 29) | const UNDERDOT_LOWERCASE_O = 7885;
  constant UNDERDOT_LOWERCASE_U (line 30) | const UNDERDOT_LOWERCASE_U = 7909;
  constant GRAVE_LOWERCASE_A (line 31) | const GRAVE_LOWERCASE_A = 224;
  constant GRAVE_ACUTE_LOWERCASE_A (line 32) | const GRAVE_ACUTE_LOWERCASE_A = 225;
  constant MACRON_LOWERCASE_A (line 33) | const MACRON_LOWERCASE_A = 257;
  constant GRAVE_LOWERCASE_E (line 34) | const GRAVE_LOWERCASE_E = 232;
  constant GRAVE_ACUTE_LOWERCASE_E (line 35) | const GRAVE_ACUTE_LOWERCASE_E = 233;
  constant MACRON_LOWERCASE_E (line 36) | const MACRON_LOWERCASE_E = 275;
  constant GRAVE_LOWERCASE_I (line 37) | const GRAVE_LOWERCASE_I = 236;
  constant GRAVE_ACUTE_LOWERCASE_I (line 38) | const GRAVE_ACUTE_LOWERCASE_I = 237;
  constant MACRON_LOWERCASE_I (line 39) | const MACRON_LOWERCASE_I = 229;
  constant GRAVE_LOWERCASE_O (line 40) | const GRAVE_LOWERCASE_O = 242;
  constant GRAVE_ACUTE_LOWERCASE_O (line 41) | const GRAVE_ACUTE_LOWERCASE_O = 243;
  constant MACRON_LOWERCASE_O (line 42) | const MACRON_LOWERCASE_O = 333;
  constant GRAVE_LOWERCASE_U (line 43) | const GRAVE_LOWERCASE_U = 249;
  constant GRAVE_ACUTE_LOWERCASE_U (line 44) | const GRAVE_ACUTE_LOWERCASE_U = 250;
  constant MACRON_LOWERCASE_U (line 45) | const MACRON_LOWERCASE_U = 363;
  constant ALL_DIACRITICS (line 48) | const ALL_DIACRITICS = '\u00B4\u0301\u0060\u00AF\u0304\u0323\u0300';

FILE: src/shared/constants/errorMessages.ts
  constant NO_PROVIDED_TERM (line 1) | const NO_PROVIDED_TERM = 'No search term provided. Use the keyword query...

FILE: src/shared/constants/navigationLinks.ts
  type NavigationType (line 3) | enum NavigationType {
  type NavigationLink (line 8) | interface NavigationLink {

FILE: src/shared/constants/parseFileLocations.ts
  constant READ_FILE_FORMAT (line 2) | const READ_FILE_FORMAT = 'utf8';
  constant DICTIONARIES_DIR (line 4) | const DICTIONARIES_DIR =
  constant BUILD_DICTIONARIES_DIR (line 8) | const BUILD_DICTIONARIES_DIR = `${mainPath}/../dist/dictionaries/ig-en`;

FILE: src/shared/utils/createRegExp.ts
  type SearchRegExp (line 5) | interface SearchRegExp {

FILE: src/siteConstants.ts
  constant PORT (line 2) | const PORT = 8080;
  constant API_FROM_EMAIL (line 3) | const API_FROM_EMAIL = 'kedu@nkowaokwu.com';
  constant APP_URL (line 4) | const APP_URL = 'https://igboapi.com';
  constant API_ROUTE (line 5) | const API_ROUTE = APP_URL;
  constant DICTIONARY_APP_URL (line 6) | const DICTIONARY_APP_URL = 'https://nkowaokwu.com';
  constant VOLUNTEER_PAGE_URL (line 7) | const VOLUNTEER_PAGE_URL = 'https://nkowaokwu.com/volunteer';
  constant SPEECH_TO_TEXT_APP_URL (line 8) | const SPEECH_TO_TEXT_APP_URL = 'https://speech.igboapi.com';
  constant GITHUB_REPO (line 9) | const GITHUB_REPO = 'https://github.com/nkowaokwu/igbo_api';
  constant GITHUB_CONTRIBUTORS (line 10) | const GITHUB_CONTRIBUTORS = 'https://api.github.com/repos/nkowaokwu/igbo...
  constant GITHUB_STARS (line 11) | const GITHUB_STARS = 'https://api.github.com/repos/nkowaokwu/igbo_api';
  constant SERVER_DOMAIN (line 12) | const SERVER_DOMAIN =
  constant TWITTER (line 18) | const TWITTER = 'https://twitter.com/nkowaokwu';
  constant INSTAGRAM (line 19) | const INSTAGRAM = 'https://www.instagram.com/nkowaokwu';
  constant LINKEDIN (line 20) | const LINKEDIN = 'https://www.linkedin.com/company/nkowa-okwu';
  constant YOUTUBE (line 21) | const YOUTUBE = 'https://www.youtube.com/c/IjemmaOnwuzulike';
  constant NKOWAOKWU (line 24) | const NKOWAOKWU = 'https://nkowaokwu.com';
  constant NKOWAOKWU_CHROME (line 25) | const NKOWAOKWU_CHROME = 'https://nkowaokwu.com/chrome';
  constant SABBI_DASHBOARD (line 26) | const SABBI_DASHBOARD = 'https://dashboard.sabbidata.com';
  constant HUGGING_FACE (line 29) | const HUGGING_FACE = 'https://huggingface.co/nkowaokwu';
  constant KAGGLE (line 30) | const KAGGLE = 'https://www.kaggle.com/organizations/nkowaokwu';
  constant DONATE_URL (line 33) | const DONATE_URL = 'https://donate.stripe.com/dR62aP6UlcmE3kIfYY';

FILE: src/types/databaseStats.ts
  type ProjectStats (line 1) | interface ProjectStats extends DatabaseStats, GitHubStats {}
  type DatabaseStats (line 3) | interface DatabaseStats {
  type GitHubStats (line 14) | interface GitHubStats {

FILE: src/types/developer.ts
  type DeveloperClientData (line 5) | interface DeveloperClientData {
  type Developer (line 16) | interface Developer extends DeveloperClientData {
  type DeveloperDocument (line 23) | interface DeveloperDocument extends Developer, Document {
  type DeveloperResponse (line 27) | interface DeveloperResponse extends Developer {

FILE: src/types/developerUsage.ts
  type DeveloperUsage (line 4) | interface DeveloperUsage {
  type DeveloperUsageDocument (line 13) | interface DeveloperUsageDocument extends DeveloperUsage, Document {

FILE: src/types/example.ts
  type ExampleBase (line 5) | type ExampleBase = {
  type IncomingExample (line 14) | type IncomingExample = ExampleBase & {
  type OutgoingExample (line 19) | type OutgoingExample = IncomingExample & {};
  type OutgoingLegacyExample (line 21) | type OutgoingLegacyExample = ExampleBase & {
  type Translation (line 27) | type Translation = {
  type Pronunciation (line 33) | type Pronunciation = {
  type ExampleDocument (line 42) | interface ExampleDocument extends IncomingExample, Document {

FILE: src/types/express.ts
  type StripeBody (line 7) | type StripeBody = {
  type Query (line 15) | type Query = {
  type IgboAPIRequest (line 30) | interface IgboAPIRequest extends ExpressRequest {
  type MiddleWare (line 43) | interface MiddleWare {
  type ErrorMiddleWare (line 47) | interface ErrorMiddleWare {

FILE: src/types/formFields.ts
  type FormFieldName (line 1) | interface FormFieldName {

FILE: src/types/nsibidiCharacter.ts
  type NsibidiCharacter (line 3) | type NsibidiCharacter = {
  type NsibidiCharacterDocument (line 11) | interface NsibidiCharacterDocument extends NsibidiCharacter, Document {

FILE: src/types/stat.ts
  type Stat (line 4) | interface Stat {
  type StatDocument (line 10) | interface StatDocument extends Stat, Document {

FILE: src/types/word.ts
  type WordClass (line 6) | type WordClass = string | WordDialect;
  type Definition (line 8) | interface Definition {
  type WordDialect (line 17) | interface WordDialect {
  type LegacyWordDialect (line 26) | interface LegacyWordDialect {
  type Attribute (line 30) | type Attribute = { [key in WordAttributeEnum]: boolean };
  type WordBase (line 32) | interface WordBase {
  type IncomingWord (line 48) | interface IncomingWord extends WordBase {
  type IncomingLegacyWord (line 55) | interface IncomingLegacyWord extends WordBase {
  type OutgoingWord (line 63) | interface OutgoingWord extends IncomingWord {}
  type OutgoingLegacyWord (line 65) | interface OutgoingLegacyWord extends IncomingLegacyWord {}
  type WordType (line 67) | type WordType = OutgoingWord | Document<OutgoingWord> | Document<Outgoin...
  type PartialWordType (line 68) | type PartialWordType =

FILE: theme.config.jsx
  method useNextSeoProps (line 9) | useNextSeoProps() {
Copy disabled (too large) Download .json
Condensed preview — 441 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (21,467K chars).
[
  {
    "path": ".dockerignore",
    "chars": 12,
    "preview": "node_modules"
  },
  {
    "path": ".eslintignore",
    "chars": 23,
    "preview": "node_modules\ndist\nbuild"
  },
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "chars": 3232,
    "preview": "# Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "chars": 3245,
    "preview": "# Contributing to the Igbo API\n\nIf you have questions about the Igbo API (not a bug report), please ask a question in ou"
  },
  {
    "path": ".github/FIREBASE_CONFIG.md",
    "chars": 1825,
    "preview": "# Firebase Configuration Guide\n\nThis project relies on Firebase Cloud Functions to execute the Igbo API business logic.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 834,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the b"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/doc_issue.md",
    "chars": 645,
    "preview": "---\nname: Docs feedback\nabout: Suggest feedback, ideas, or any new forms of contributions\ntitle: ''\nlabels: ''\nassignees"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 595,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your fea"
  },
  {
    "path": ".github/pull_request_template.md",
    "chars": 919,
    "preview": "## Describe your changes\n<!--- Thoughtfully think through your changes. Think of your audience, this PR is public! -->\n\n"
  },
  {
    "path": ".github/workflows/deploy.yml",
    "chars": 9426,
    "preview": "name: Deploy to Firebase\n\non:\n  push:\n    branches:\n      - master\nenv:\n  FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/dockerize.yml",
    "chars": 877,
    "preview": "name: Dockerize Igbo API\n\non:\n  push:\n    branches:\n      - master\n\njobs:\n  dockerize:\n    name: Dockerize\n    runs-on: "
  },
  {
    "path": ".github/workflows/integration.yml",
    "chars": 1148,
    "preview": "name: Test Suite\n\non:\n  workflow_dispatch:\n  pull_request:\n\nenv:\n  FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}\n  CI: t"
  },
  {
    "path": ".github/workflows/lint.yml",
    "chars": 449,
    "preview": "name: Lint\n\non: push\n\njobs:\n  run-linters:\n    name: Run linters\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Gi"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 560,
    "preview": "name: Release\n\non:\n  push:\n    branches:\n      - master\n\njobs:\n  release:\n    name: Release\n    runs-on: ubuntu-latest\n\n"
  },
  {
    "path": ".gitignore",
    "chars": 2137,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# MongoDB Database\ndump/\ndb/\nmongos/\n"
  },
  {
    "path": ".npmrc",
    "chars": 21,
    "preview": "engine-strict = true\n"
  },
  {
    "path": ".prettierignore",
    "chars": 9,
    "preview": "**/*.d.ts"
  },
  {
    "path": ".prettierrc.json",
    "chars": 126,
    "preview": "{\n  \"parser\": \"flow\",\n  \"printWidth\": 100,\n  \"singleQuote\": true,\n  \"trailingComma\": \"es5\",\n  \"semi\": true,\n  \"tabWidth\""
  },
  {
    "path": ".releaserc",
    "chars": 1063,
    "preview": "{\n  \"branches\": [\"master\"],\n  \"plugins\": [\n    [\"@semantic-release/commit-analyzer\", {\n      \"preset\": \"angular\",\n      "
  },
  {
    "path": "@types/bcrypt.d.ts",
    "chars": 25,
    "preview": "declare module 'bcrypt';\n"
  },
  {
    "path": "@types/body-parser.d.ts",
    "chars": 30,
    "preview": "declare module 'body-parser';\n"
  },
  {
    "path": "@types/compression.d.ts",
    "chars": 30,
    "preview": "declare module 'compression';\n"
  },
  {
    "path": "@types/console.d.ts",
    "chars": 228,
    "preview": "declare global {\n  interface Console {\n    green(message?: any, ...optionalParams: any[]): void;\n    blue(message?: any,"
  },
  {
    "path": "@types/diacriticless.d.ts",
    "chars": 31,
    "preview": "declare module 'diacriticless';"
  },
  {
    "path": "@types/environment.d.ts",
    "chars": 214,
    "preview": "declare global {\n  namespace NodeJS {\n    interface ProcessEnv {\n      // @ts-expect-error  Nodejs process override\n    "
  },
  {
    "path": "@types/express-rate-limit.d.ts",
    "chars": 37,
    "preview": "declare module 'express-rate-limit';\n"
  },
  {
    "path": "@types/is-word.d.ts",
    "chars": 26,
    "preview": "declare module 'is-word';\n"
  },
  {
    "path": "@types/morgan.d.ts",
    "chars": 25,
    "preview": "declare module 'morgan';\n"
  },
  {
    "path": "@types/react-scroll.d.ts",
    "chars": 31,
    "preview": "declare module 'react-scroll';\n"
  },
  {
    "path": "@types/shelljs.d.ts",
    "chars": 26,
    "preview": "declare module 'shelljs';\n"
  },
  {
    "path": "@types/string-similarity.d.ts",
    "chars": 36,
    "preview": "declare module 'string-similarity';\n"
  },
  {
    "path": "@types/supertest.d.ts",
    "chars": 27,
    "preview": "declare module 'supertest';"
  },
  {
    "path": "@types/uuid.d.ts",
    "chars": 23,
    "preview": "declare module 'uuid';\n"
  },
  {
    "path": "Dockerfile",
    "chars": 171,
    "preview": "FROM node:18\n\nWORKDIR /app\n\nCOPY package.json ./\n\nRUN npm install\n\nCOPY . .\n\nRUN npm run build\n\nENV PORT=8080\nENV CONTAI"
  },
  {
    "path": "LICENSE.md",
    "chars": 11340,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 987,
    "preview": "# Igbo API\n\n[![Deploy to Firebase](https://github.com/nkowaokwu/igbo_api/actions/workflows/deploy.yml/badge.svg)](https:"
  },
  {
    "path": "__mocks__/@chakra-ui/react.tsx",
    "chars": 2217,
    "preview": "import React from 'react';\nimport * as Chakra from '../../node_modules/@chakra-ui/react';\n\nexport const Tooltip = ({ chi"
  },
  {
    "path": "__mocks__/@sendgrid/mail.ts",
    "chars": 19,
    "preview": "export default {};\n"
  },
  {
    "path": "__mocks__/axios.ts",
    "chars": 236,
    "preview": "export const mockRequest = jest.fn((config) => config);\nexport const request = jest.fn(() => ({ data: {}, catch: jest.fn"
  },
  {
    "path": "__mocks__/bcrypt.ts",
    "chars": 54,
    "preview": "export const hash = jest.fn(() => 'hashed-password');\n"
  },
  {
    "path": "__mocks__/firebase/app.ts",
    "chars": 115,
    "preview": "export const initializeApp = jest.fn();\nexport const getApps = jest.fn(() => []);\nexport const getApp = jest.fn();\n"
  },
  {
    "path": "__mocks__/firebase/auth.ts",
    "chars": 167,
    "preview": "export const getAuth = jest.fn(() => ({\n  currentUser: {\n    uid: 'uid',\n    getIdToken: () => 'uid-id-token',\n  },\n}));"
  },
  {
    "path": "__mocks__/firebase/functions.ts",
    "chars": 100,
    "preview": "export const getFunctions = jest.fn(() => ({}));\nexport const connectFunctionsEmulator = jest.fn();\n"
  },
  {
    "path": "__mocks__/firebase-admin.ts",
    "chars": 98,
    "preview": "export const auth = jest.fn(() => ({\n  verifyIdToken: jest.fn((id) => ({\n    uid: id,\n  })),\n}));\n"
  },
  {
    "path": "__mocks__/firebase-functions/v1.ts",
    "chars": 47,
    "preview": "export const https = {\n  onCall: jest.fn(),\n};\n"
  },
  {
    "path": "__mocks__/i18next.ts",
    "chars": 119,
    "preview": "import * as i18next from '../node_modules/i18next';\n\nexport const changeLanguage = jest.fn();\n\nexport default i18next;\n"
  },
  {
    "path": "__mocks__/mongoose.ts",
    "chars": 1023,
    "preview": "import mongoose from 'mongoose';\nexport { Types, Schema, Document } from 'mongoose';\nimport Plan from '../src/shared/con"
  },
  {
    "path": "__mocks__/next/font/google.ts",
    "chars": 74,
    "preview": "export const Inter = jest.fn(() => ({ style: { fontFamily: 'inter' } }));\n"
  },
  {
    "path": "__mocks__/next/router.ts",
    "chars": 184,
    "preview": "import * as next from 'next/dist/client/router';\n\nexport const routerPushMock = jest.fn();\nexport const useRouter = jest"
  },
  {
    "path": "__mocks__/react-firebase-hooks/auth.ts",
    "chars": 213,
    "preview": "import { decodedIdTokenFixture } from '../../__tests__/shared/uiFixtures';\n\nexport const onAuthStateChanged = jest.fn(()"
  },
  {
    "path": "__mocks__/shelljs.ts",
    "chars": 40,
    "preview": "export default {\n  mkdir: jest.fn(),\n};\n"
  },
  {
    "path": "__mocks__/stripe.ts",
    "chars": 562,
    "preview": "class Stripe {\n  apiKey = '';\n  prices = {\n    list: jest.fn(() => ({ data: [{ id: 'price_id' }] })),\n  };\n  checkout = "
  },
  {
    "path": "__mocks__/uuid.ts",
    "chars": 51,
    "preview": "export const v4 = jest.fn(() => 'generated-uuid');\n"
  },
  {
    "path": "__tests__/__mocks__/data.mock.json",
    "chars": 26118,
    "preview": "{\n    \"ànì\": [\n        {\n            \"wordClass\": \"noun\",\n            \"definitions\": [\n                \"A. land; ground;"
  },
  {
    "path": "__tests__/__mocks__/documentData.ts",
    "chars": 460,
    "preview": "import mongoose from 'mongoose';\n\nconst { ObjectId } = mongoose.Types;\n\nconst wordId = new ObjectId('5f864d7401203866b65"
  },
  {
    "path": "__tests__/__mocks__/genericWords.mock.json",
    "chars": 66638,
    "preview": "{\n  \"meru\": [\n      \"aal\"\n  ],\n  \"ọria\": [\n      \"aals\",\n      \"dreggy\",\n      \"gregor\",\n      \"outreness\",\n      \"scler"
  },
  {
    "path": "__tests__/api-json.test.ts",
    "chars": 1380,
    "preview": "import isEqual from 'lodash/isEqual';\nimport { NO_PROVIDED_TERM } from '../src/shared/constants/errorMessages';\nimport {"
  },
  {
    "path": "__tests__/api-mongo.test.ts",
    "chars": 23513,
    "preview": "import mongoose from 'mongoose';\nimport { forEach, has, isEqual, uniqBy, some, every } from 'lodash';\nimport stringSimil"
  },
  {
    "path": "__tests__/developers.test.ts",
    "chars": 5646,
    "preview": "import {\n  createDeveloper,\n  getDeveloper,\n  getExample,\n  getExamples,\n  getWord,\n  getWords,\n} from './shared/command"
  },
  {
    "path": "__tests__/examples.test.ts",
    "chars": 4718,
    "preview": "import { forEach, has, isEqual } from 'lodash';\nimport { getExamples, getExample, getExamplesV2, getExampleV2 } from './"
  },
  {
    "path": "__tests__/nsibidi_characters.test.ts",
    "chars": 382,
    "preview": "import { getNsibidiCharactersV2 } from './shared/commands';\n\njest.unmock('mongoose');\n\ndescribe('MongoDB Nsibidi Charact"
  },
  {
    "path": "__tests__/parse.test.ts",
    "chars": 2968,
    "preview": "import fs from 'fs';\nimport { keys } from 'lodash';\nimport replaceAbbreviations from '../src/shared/utils/replaceAbbrevi"
  },
  {
    "path": "__tests__/shared/commands.ts",
    "chars": 4705,
    "preview": "import request from 'supertest';\nimport { Types } from 'mongoose';\nimport app from '../../src/app';\nimport {\n  API_ROUTE"
  },
  {
    "path": "__tests__/shared/constants.ts",
    "chars": 1515,
    "preview": "import mongoose from 'mongoose';\nimport Version from '../../src/shared/constants/Version';\n\nexport const LOCAL_ROUTE = '"
  },
  {
    "path": "__tests__/shared/uiFixtures.ts",
    "chars": 408,
    "preview": "import { DecodedIdToken } from 'firebase-admin/auth';\n\nexport const decodedIdTokenFixture = (data: object = {}): Decoded"
  },
  {
    "path": "__tests__/shared/utils.ts",
    "chars": 585,
    "preview": "import { forEach, difference, map } from 'lodash';\nimport { expect } from '@jest/globals';\n\nexport const expectUniqSetsO"
  },
  {
    "path": "__tests__/stripe.test.ts",
    "chars": 1595,
    "preview": "import { postCheckoutSession, postPortalSession, postWebhook } from './shared/commands';\n\njest.unmock('mongoose');\n\ndesc"
  },
  {
    "path": "commitlint.config.js",
    "chars": 70,
    "preview": "module.exports = {\n  extends: ['@commitlint/config-conventional'],\n};\n"
  },
  {
    "path": "cypress/e2e/client.cy.js",
    "chars": 4371,
    "preview": "import { v4 as uuid } from 'uuid';\n\ndescribe('Igbo API Homepage', () => {\n  beforeEach(() => {\n    cy.visit('/');\n  });\n"
  },
  {
    "path": "cypress/fixtures/example.json",
    "chars": 154,
    "preview": "{\n  \"name\": \"Using fixtures to represent data\",\n  \"email\": \"hello@cypress.io\",\n  \"body\": \"Fixtures are a great way to mo"
  },
  {
    "path": "cypress/plugins/index.js",
    "chars": 709,
    "preview": "/// <reference types=\"cypress\" />\n// ***********************************************************\n// This example plugins"
  },
  {
    "path": "cypress/support/commands.js",
    "chars": 48,
    "preview": "import '@testing-library/cypress/add-commands';\n"
  },
  {
    "path": "cypress/support/e2e.js",
    "chars": 121,
    "preview": "import { configure } from '@testing-library/cypress';\nimport './commands';\n\nconfigure({ testIdAttribute: 'data-test' });"
  },
  {
    "path": "cypress.config.js",
    "chars": 415,
    "preview": "// eslint-disable-next-line import/no-extraneous-dependencies\nconst { defineConfig } = require('cypress');\n\nmodule.expor"
  },
  {
    "path": "docker-compose.yml",
    "chars": 789,
    "preview": "version: '3.7'\nservices:\n  mongo1:\n    image: mongo:4.2\n    container_name: mongo1\n    command: [\"--replSet\", \"rs0\", \"--"
  },
  {
    "path": "env.d.ts",
    "chars": 149,
    "preview": "declare global {\n  namespace NodeJS {\n    export interface ProcessEnv {\n      NODE_ENV: 'build' | 'development' | 'produ"
  },
  {
    "path": "eslint.config.mjs",
    "chars": 800,
    "preview": "import eslint from '@eslint/js';\nimport pluginReact from 'eslint-plugin-react';\nimport globals from 'globals';\nimport ts"
  },
  {
    "path": "firebase.json",
    "chars": 887,
    "preview": "{\n  \"functions\": [\n    {\n      \"source\": \"functions\",\n      \"ignore\": [\n          \"node_modules\",\n          \".git\",\n    "
  },
  {
    "path": "functions/.gitignore",
    "chars": 56,
    "preview": "node_modules/\n\n# dotenv environment variables file\n.env*"
  },
  {
    "path": "functions/index.js",
    "chars": 238,
    "preview": "const { onRequest } = require('firebase-functions/v2/https');\nconst { api, demo } = require('./build/src/app');\n\nexports"
  },
  {
    "path": "functions/next-i18next.config.js",
    "chars": 89,
    "preview": "module.exports = {\n  i18n: {\n    defaultLocale: 'en',\n    locales: ['en', 'ig'],\n  },\n};\n"
  },
  {
    "path": "functions/next.config.js",
    "chars": 180,
    "preview": "const { i18n } = require('./next-i18next.config');\n\nmodule.exports = {\n  distDir: 'dist',\n  generateBuildId: async () =>"
  },
  {
    "path": "functions/package.json",
    "chars": 3997,
    "preview": "{\n  \"name\": \"functions\",\n  \"description\": \"Cloud Functions for Firebase\",\n  \"scripts\": {\n    \"serve\": \"firebase emulator"
  },
  {
    "path": "functions/postcss.config.js",
    "chars": 204,
    "preview": "// If you want to use other PostCSS plugins, see the following:\n// https://tailwindcss.com/docs/using-with-preprocessors"
  },
  {
    "path": "functions/tailwind.config.js",
    "chars": 319,
    "preview": "module.exports = {\n  future: {\n    removeDeprecatedGapUtilities: true,\n    purgeLayersByDefault: true,\n  },\n  purge: [\n "
  },
  {
    "path": "jest.backend.config.ts",
    "chars": 489,
    "preview": "// Backend Jest Config\nexport default {\n  displayName: 'igbo_api',\n  testMatch: ['**/__tests__/*.ts'],\n  testPathIgnoreP"
  },
  {
    "path": "jest.backend.database.config.ts",
    "chars": 197,
    "preview": "import jestBackendConfig from './jest.backend.config';\n\n// Backend + Database Jest Config\nexport default {\n  ...jestBack"
  },
  {
    "path": "jest.frontend.config.ts",
    "chars": 555,
    "preview": "// Frontend Jest Config\nexport default {\n  displayName: 'igbo_api',\n  testMatch: ['./**/__tests__/**/*.test.tsx'],\n  tes"
  },
  {
    "path": "migrate-mongo-config.js",
    "chars": 399,
    "preview": "const config = {\n  mongodb: {\n    url: process.env.MONGO_URI || 'mongodb://0.0.0.0:27017',\n    databaseName: process.env"
  },
  {
    "path": "migrations/20201106045436-add-suggestion-properties.js",
    "chars": 653,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['wordsuggestions', 'examplesuggestions', 'genericwords'];\n "
  },
  {
    "path": "migrations/20201108164925-add-exampleForWordSuggestion-field.js",
    "chars": 483,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['examplesuggestions'];\n    return collections.map((collecti"
  },
  {
    "path": "migrations/20201109083748-remove-examples-from-words.js",
    "chars": 429,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words'];\n    return collections.map((collection) => (\n    "
  },
  {
    "path": "migrations/20201118192335-add-merged-by.js",
    "chars": 527,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['wordsuggestions', 'examplesuggestions', 'genericwords'];\n "
  },
  {
    "path": "migrations/20201121195224-add-updated-on-for-words-and-examples.js",
    "chars": 577,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'examples', 'wordsuggestions', 'examplesuggestions"
  },
  {
    "path": "migrations/20201206042142-add-accented-field.js",
    "chars": 489,
    "preview": "module.exports = {\n  async up(db) {\n    return [\n      db.collection('words').updateMany({}, [{\n        $set: { accented"
  },
  {
    "path": "migrations/20201213020925-uid-fields-on-suggestions.js",
    "chars": 929,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['wordsuggestions', 'examplesuggestions', 'genericwords'];\n "
  },
  {
    "path": "migrations/20210225022115-create-dialects.js",
    "chars": 923,
    "preview": "const dialectKeys = [\n  'NSA',\n  'UMU',\n  'ANI',\n  'OKA',\n  'AFI',\n  'MBA',\n  'EGB',\n  'OHU',\n  'ORL',\n  'NGW',\n  'OWE',"
  },
  {
    "path": "migrations/20210225235148-update-variations-to-array.js",
    "chars": 923,
    "preview": "const dialectKeys = [\n  'NSA',\n  'UMU',\n  'ANI',\n  'OKA',\n  'AFI',\n  'MBA',\n  'EGB',\n  'OHU',\n  'ORL',\n  'NGW',\n  'OWE',"
  },
  {
    "path": "migrations/20210306224633-add-dialects-for-word-suggestions-and-generic-words.js",
    "chars": 975,
    "preview": "const dialectKeys = [\n  'NSA',\n  'UMU',\n  'ANI',\n  'OKA',\n  'AFI',\n  'MBA',\n  'EGB',\n  'OHU',\n  'ORL',\n  'NGW',\n  'OWE',"
  },
  {
    "path": "migrations/20210325194345-add-central-igbo.js",
    "chars": 512,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'wordsuggestions', 'genericwords'];\n    return col"
  },
  {
    "path": "migrations/20210331134705-remove-developer-origin.js",
    "chars": 293,
    "preview": "module.exports = {\n  async up(db) {\n    return [\n      db.collection('developers').updateMany({}, {\n        $unset: { ho"
  },
  {
    "path": "migrations/20210426171953-remove-normalized-field.js",
    "chars": 433,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words'];\n    return collections.map((collection) => (\n    "
  },
  {
    "path": "migrations/20210814210437-pre-populate-dialects.js",
    "chars": 1221,
    "preview": "const dialectKeys = [\n  'NSA',\n  'UMU',\n  'ANI',\n  'OKA',\n  'AFI',\n  'MBA',\n  'EGB',\n  'OHU',\n  'ORL',\n  'NGW',\n  'OWE',"
  },
  {
    "path": "migrations/20210820170937-merge-accented-and-word.js",
    "chars": 1773,
    "preview": "const dialectKeys = [\n  'NSA',\n  'UMU',\n  'ANI',\n  'OKA',\n  'AFI',\n  'MBA',\n  'EGB',\n  'OHU',\n  'ORL',\n  'NGW',\n  'OWE',"
  },
  {
    "path": "migrations/20210820175620-merge-accented-and-example.js",
    "chars": 925,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['examples', 'exampleSuggestions'];\n    const igboAccentedMi"
  },
  {
    "path": "migrations/20210822145619-change-central-to-standard.js",
    "chars": 608,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'wordsuggestions'];\n    return collections.map((co"
  },
  {
    "path": "migrations/20210831163032-add-is-complete-word.js",
    "chars": 470,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'wordsuggestions'];\n    return collections.map((co"
  },
  {
    "path": "migrations/20210903175644-remove-is-complete-word.js",
    "chars": 470,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'wordsuggestions'];\n    return collections.map((co"
  },
  {
    "path": "migrations/20211030133331-add-active-and-passive-verbs.js",
    "chars": 847,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'wordsuggetions', 'genericwords'];\n    return coll"
  },
  {
    "path": "migrations/20211121214701-add-nyms.js",
    "chars": 689,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'wordsuggestions', 'genericwords'];\n    return col"
  },
  {
    "path": "migrations/20211218192401-add-isComplete.js",
    "chars": 2140,
    "preview": "/* eslint-disable max-len */\nconst wordsPipeline = [\n  {\n    $lookup: {\n      from: 'examples',\n      localField: '_id',"
  },
  {
    "path": "migrations/20220107155512-add-nsibidi.js",
    "chars": 497,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'wordsuggestions', 'genericwords'];\n    return col"
  },
  {
    "path": "migrations/20220125175808-restructure-dialects.js",
    "chars": 3554,
    "preview": "const wordsMigrationPipeline = [\n  {\n    $match: {\n      word: {\n        $exists: true,\n      },\n    },\n  },\n  {\n    $se"
  },
  {
    "path": "migrations/20220208140327-example-pronunciations.js",
    "chars": 489,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['examples', 'examplesuggestions'];\n    return collections.m"
  },
  {
    "path": "migrations/20220216030851-remove-verb-prefixes.js",
    "chars": 1918,
    "preview": "const wordsMigrationPipeline = [\n  {\n    $match: {\n      word: {\n        $regex: '^-',\n        $options: 'i',\n      },\n "
  },
  {
    "path": "migrations/20220301211505-convert-unix-to-iso.js",
    "chars": 2034,
    "preview": "const updatedOnConversion = [\n  {\n    $set: {\n      updatedAt: {\n        $function: {\n          body: `function(updatedO"
  },
  {
    "path": "migrations/20220308132126-add-is-accented.js",
    "chars": 564,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'wordsuggestions'];\n    return collections.map((co"
  },
  {
    "path": "migrations/20220406005107-add-tenses.js",
    "chars": 9250,
    "preview": "/* eslint-disable */\nconst addTenses = [\n  {\n    $set: {\n      tenses: {\n        $function: {\n          body: `function("
  },
  {
    "path": "migrations/20220423222134-add-attributes.js",
    "chars": 1059,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'wordsuggestions'];\n    return collections.map(asy"
  },
  {
    "path": "migrations/20220425130741-extend-example-sentences-with-style-and-meaning.js",
    "chars": 586,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['examples', 'examplesuggestions'];\n    return collections.m"
  },
  {
    "path": "migrations/20220808024209-add-borrowed-term-field.js",
    "chars": 887,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'wordsuggestions'];\n    return collections.map(asy"
  },
  {
    "path": "migrations/20220808033804-add-tags.js",
    "chars": 568,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'wordsuggestions', 'genericwords'];\n    return col"
  },
  {
    "path": "migrations/20220808042906-replace-nyms-for-related-terms.js",
    "chars": 805,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'wordsuggestions', 'genericwords'];\n    return col"
  },
  {
    "path": "migrations/20221014123241-add-is-stem.js",
    "chars": 492,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'wordsuggestions'];\n    return collections.map((co"
  },
  {
    "path": "migrations/20221030034746-restructure-definitions.js",
    "chars": 1846,
    "preview": "// eslint-disable-next-line\n// https://stackoverflow.com/questions/70831908/mongodb-generates-same-objectid-with-new-obj"
  },
  {
    "path": "migrations/20221030054330-connect-example-associated-definitions.js",
    "chars": 1431,
    "preview": "const associatedDefinitionsSchemasMigrationPipeline = [\n  {\n    $match: {\n      'associatedWords.0': {\n        $exists: "
  },
  {
    "path": "migrations/20221107022314-resturcture-dialects-as-arrays.js",
    "chars": 2158,
    "preview": "const dialectsAsArraysPipeline = [\n  {\n    $match: {\n      dialects: {\n        $exists: true,\n      },\n    },\n  }, {\n   "
  },
  {
    "path": "migrations/20221124200346-expand-headword.js",
    "chars": 603,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'wordsuggestions'];\n    return collections.map((co"
  },
  {
    "path": "migrations/20221207003231-nominal-modifier.js",
    "chars": 2155,
    "preview": "/* eslint-disable max-len */\nconst nominalModifierMigrationPipeline = [\n  {\n    $match: {\n      'definitions.wordClass':"
  },
  {
    "path": "migrations/20221217204603-definitions-with-nsibidi.js",
    "chars": 810,
    "preview": "/* eslint-disable max-len */\nconst definitionsWithNsibidiMigrationPipeline = [\n  {\n    $set: { 'definitions.nsibidi': '$"
  },
  {
    "path": "migrations/20230112035359-add-is-common.js",
    "chars": 496,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'wordsuggestions'];\n    return collections.map((co"
  },
  {
    "path": "migrations/20230118013604-convert-stems-to-object-id.js",
    "chars": 1792,
    "preview": "const stemsToObjectIdMigrationPipeline = [\n  {\n    $match: {\n      'stems.0': {\n        $exists: true,\n        $type: 's"
  },
  {
    "path": "migrations/20230201191800-convert-medial-to-active.js",
    "chars": 662,
    "preview": "const medialToActivePipeline = [\n  {\n    $match: {\n      'definitions.0.wordClass': 'MV',\n    },\n  },\n];\n\nmodule.exports"
  },
  {
    "path": "migrations/20230201193438-add-present-passive-to-verbs.js",
    "chars": 1469,
    "preview": "const medialToActivePipeline = [\n  {\n    $match: {\n      $or: [\n        { 'definitions.0.wordClass': 'AV' },\n        { '"
  },
  {
    "path": "migrations/20230314160556-convert-frequency-to-number.js",
    "chars": 721,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['words', 'wordsuggestions'];\n    return collections.map((co"
  },
  {
    "path": "migrations/20230409220217-convert-igbo-definitions-to-include-nsibidi.js",
    "chars": 2219,
    "preview": "const igboDefinitionsToIncludeNsibidiPipeline = [\n  {\n    $match: {\n      'definitions.igboDefinitions.0': {\n        $ex"
  },
  {
    "path": "migrations/20230522011130-pronunciation-to-pronunciations.js",
    "chars": 1120,
    "preview": "const pronunciationsMigrationPipeline = [\n  {\n    $set: {\n      pronunciations: [\n        {\n          audio: '$pronuncia"
  },
  {
    "path": "migrations/20230526231511-example-suggestions-approvals-denials-review.js",
    "chars": 1550,
    "preview": "const examplePronunciationsMigrationPipeline = [\n  {\n    $addFields: {\n      pronunciations: {\n        $function: {\n    "
  },
  {
    "path": "migrations/20230607004329-trim-headword-and-tenses-whitespace-fix.js",
    "chars": 2327,
    "preview": "const trimPipeline = [\n  {\n    $project: {\n      word: {\n        $trim: {\n          input: '$word',\n        },\n      },\n"
  },
  {
    "path": "migrations/20240908000598-create-default-igbo-api-project.js",
    "chars": 515,
    "preview": "const { Types } = require('mongoose');\n\nmodule.exports = {\n  async up(db) {\n    await db.collection('projects').insertOn"
  },
  {
    "path": "migrations/20240908000599-change-source-to-origin.js",
    "chars": 779,
    "preview": "const examplesMigrationPipeline = [\n  {\n    $addFields: {\n      origin: '$source',\n    },\n  },\n  {\n    $unset: 'source',"
  },
  {
    "path": "migrations/20240908000600-generalize-examples.js",
    "chars": 1043,
    "preview": "const examplesMigrationPipeline = [\n  {\n    $addFields: {\n      source: {\n        language: 'ibo',\n        text: '$igbo'"
  },
  {
    "path": "migrations/20240908162526-assign-projectid-to-each-collection.js",
    "chars": 1164,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = [\n      'corpus',\n      'corpussuggestions',\n      'examples"
  },
  {
    "path": "migrations/20240913215339-move-example-pronunciations-to-translations.js",
    "chars": 1385,
    "preview": "const addPronunciationsToSourceAndTranslationsPipeline = [\n  {\n    $addFields: {\n      'source.pronunciations': '$pronun"
  },
  {
    "path": "migrations/20240928023848-add-languages-to-corpus.js",
    "chars": 525,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['corpus', 'corpussuggestions'];\n    return collections.map("
  },
  {
    "path": "migrations/20240928024053-add-types-to-projecs.js",
    "chars": 502,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['projects'];\n    return collections.map((collection) =>\n   "
  },
  {
    "path": "migrations/20241116014146-add-bit-rate-audio-pronunciation.js",
    "chars": 496,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['audiopronunciations'];\n    return collections.map((collect"
  },
  {
    "path": "migrations/20241203060241-insert-owner-firebase-id-on-project.js",
    "chars": 1264,
    "preview": "const determineOwnerUserProjectPermission = (projectId) => [\n  {\n    $match: {\n      projectId,\n      role: 'admin',\n   "
  },
  {
    "path": "migrations/20241203060300-connect-paywall-to-project.js",
    "chars": 1781,
    "preview": "const getAllExamples = (projectId) => [\n  {\n    $match: {\n      projectId,\n    },\n  },\n];\n\nconst getAllExampleSuggestion"
  },
  {
    "path": "migrations/20241206235108-remove-crowdsourcing.js",
    "chars": 356,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['wordsuggestions', 'examplesuggestions'];\n    await Promise"
  },
  {
    "path": "migrations/20250212184340-add-viewableSectionIds-to-example-suggestions.js",
    "chars": 338,
    "preview": "module.exports = {\n  async up(db) {\n    const collections = ['examplesuggestions'];\n    await Promise.all(\n      collect"
  },
  {
    "path": "migrations/20250417110353-migrate-igbo-speech-example-suggestions.js",
    "chars": 1040,
    "preview": "const { Types } = require('../node_modules/mongoose');\nmodule.exports = {\n  async up(db) {\n    const collections = ['exa"
  },
  {
    "path": "next-env.d.ts",
    "chars": 201,
    "preview": "/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\n\n// NOTE: This file should not be edite"
  },
  {
    "path": "next-i18next.config.js",
    "chars": 89,
    "preview": "module.exports = {\n  i18n: {\n    defaultLocale: 'en',\n    locales: ['en', 'ig'],\n  },\n};\n"
  },
  {
    "path": "next.config.js",
    "chars": 277,
    "preview": "const { i18n } = require('./next-i18next.config');\n\nmodule.exports = {\n  distDir: 'dist',\n  generateBuildId: async () =>"
  },
  {
    "path": "package.json",
    "chars": 9779,
    "preview": "{\n  \"name\": \"igbo-api\",\n  \"version\": \"1.64.2\",\n  \"description\": \"Igbo Dictionary API contains Igbo words, definitions, a"
  },
  {
    "path": "postcss.config.js",
    "chars": 204,
    "preview": "// If you want to use other PostCSS plugins, see the following:\n// https://tailwindcss.com/docs/using-with-preprocessors"
  },
  {
    "path": "public/.hosting",
    "chars": 32,
    "preview": "Empty file for Firebase Hosting\n"
  },
  {
    "path": "script.js",
    "chars": 344,
    "preview": "const fs = require('fs');\nconst dataset = require('./igbo-api-dataset.json');\n\nconst dialects = dataset.flatMap((word) ="
  },
  {
    "path": "src/APIs/FlagsAPI.ts",
    "chars": 1886,
    "preview": "import { compact, assign, omit } from 'lodash';\nimport { OutgoingLegacyWord, OutgoingWord } from '../types/word';\nimport"
  },
  {
    "path": "src/APIs/RedisAPI.ts",
    "chars": 3179,
    "preview": "import assign from 'lodash/assign';\nimport { REDIS_CACHE_EXPIRATION } from '../config';\nimport minimizeWords from '../co"
  },
  {
    "path": "src/APIs/__tests__/FlagsAPI.test.ts",
    "chars": 4533,
    "preview": "import {\n  dialectFixture,\n  outgoingExampleFixture,\n  outgoingWordFixture,\n} from '../../__tests__/shared/fixtures';\nim"
  },
  {
    "path": "src/__data__/assetStub.ts",
    "chars": 41,
    "preview": "const asset = '';\n\nexport default asset;\n"
  },
  {
    "path": "src/__tests__/Card/Card.test.tsx",
    "chars": 502,
    "preview": "import React from 'react';\nimport { render } from '@testing-library/react';\nimport TestContext from '../components/TestC"
  },
  {
    "path": "src/__tests__/Demo/Demo.test.tsx",
    "chars": 1424,
    "preview": "import { render } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport React from "
  },
  {
    "path": "src/__tests__/FadeIn/FadeIn.test.tsx",
    "chars": 476,
    "preview": "import React from 'react';\nimport { render } from '@testing-library/react';\nimport TestContext from '../components/TestC"
  },
  {
    "path": "src/__tests__/Input/Input.test.tsx",
    "chars": 689,
    "preview": "import React from 'react';\nimport { render } from '@testing-library/react';\nimport TestContext from '../components/TestC"
  },
  {
    "path": "src/__tests__/Statistics/Stat.test.tsx",
    "chars": 871,
    "preview": "import React from 'react';\nimport { render } from '@testing-library/react';\nimport TestContext from '../components/TestC"
  },
  {
    "path": "src/__tests__/Statistics/Statistics.test.tsx",
    "chars": 1089,
    "preview": "import React from 'react';\nimport { render } from '@testing-library/react';\nimport TestContext from '../components/TestC"
  },
  {
    "path": "src/__tests__/components/TestContext.tsx",
    "chars": 1463,
    "preview": "import { ChakraProvider } from '@chakra-ui/react';\nimport { configure } from '@testing-library/react';\nimport React, { R"
  },
  {
    "path": "src/__tests__/shared/fixtures.ts",
    "chars": 4824,
    "preview": "import { capitalize } from 'lodash';\nimport { WordDialect } from '../../types/word';\nimport { NextFunction, Request, Res"
  },
  {
    "path": "src/__tests__/shared/script.ts",
    "chars": 36,
    "preview": "import '@testing-library/jest-dom';\n"
  },
  {
    "path": "src/app.ts",
    "chars": 1603,
    "preview": "import compression from 'compression';\nimport cors from 'cors';\nimport express from 'express';\nimport morgan from 'morga"
  },
  {
    "path": "src/config.ts",
    "chars": 6276,
    "preview": "/* eslint-disable max-len */\nimport { defineBoolean, defineInt, defineString } from 'firebase-functions/params';\nimport "
  },
  {
    "path": "src/controllers/__tests__/developers.test.ts",
    "chars": 2493,
    "preview": "import {\n  requestFixture,\n  responseFixture,\n  nextFunctionFixture,\n} from '../../__tests__/shared/fixtures';\nimport {\n"
  },
  {
    "path": "src/controllers/__tests__/examples.test.ts",
    "chars": 1030,
    "preview": "import { incomingExampleFixture } from '../../__tests__/shared/fixtures';\nimport LanguageEnum from '../../shared/constan"
  },
  {
    "path": "src/controllers/__tests__/speechToText.test.ts",
    "chars": 4060,
    "preview": "import axios from 'axios';\nimport {\n  nextFunctionFixture,\n  requestFixture,\n  responseFixture,\n} from '../../__tests__/"
  },
  {
    "path": "src/controllers/__tests__/stripe.test.ts",
    "chars": 734,
    "preview": "jest.mock('stripe');\nimport { requestFixture, responseFixture } from '../../__tests__/shared/fixtures';\nimport { postChe"
  },
  {
    "path": "src/controllers/__tests__/translation.test.ts",
    "chars": 3983,
    "preview": "import axios from 'axios';\nimport {\n  requestFixture,\n  responseFixture,\n  nextFunctionFixture,\n} from '../../__tests__/"
  },
  {
    "path": "src/controllers/developers.ts",
    "chars": 4609,
    "preview": "import { hash } from 'bcrypt';\nimport { v4 as uuid } from 'uuid';\nimport { Document, FilterQuery, Types } from 'mongoose"
  },
  {
    "path": "src/controllers/email.ts",
    "chars": 1981,
    "preview": "import omit from 'lodash/omit';\nimport { MailDataRequired } from '@sendgrid/mail';\nimport map from 'lodash/map';\nimport "
  },
  {
    "path": "src/controllers/examples.ts",
    "chars": 4997,
    "preview": "import { assign, omit } from 'lodash';\nimport { Connection, PipelineStage } from 'mongoose';\nimport { RedisClientType } "
  },
  {
    "path": "src/controllers/nsibidi.ts",
    "chars": 1995,
    "preview": "import mongoose, { Connection } from 'mongoose';\nimport { handleQueries, packageResponse } from './utils';\nimport { Midd"
  },
  {
    "path": "src/controllers/speechToText.ts",
    "chars": 2204,
    "preview": "import axios from 'axios';\nimport { MAIN_KEY, SPEECH_TO_TEXT_API } from '../config';\nimport Endpoint from '../shared/con"
  },
  {
    "path": "src/controllers/stats.ts",
    "chars": 2303,
    "preview": "import { statSchema } from '../models/Stat';\nimport { developerSchema } from '../models/Developer';\nimport { searchForAl"
  },
  {
    "path": "src/controllers/stripe/__mocks__/webhooks.ts",
    "chars": 299,
    "preview": "export const handleCustomerSubscriptionCreated = jest.fn();\nexport const handleCustomerSubscriptionDeleted = jest.fn();\n"
  },
  {
    "path": "src/controllers/stripe/__tests__/index.test.ts",
    "chars": 2690,
    "preview": "import { postCheckoutSession, postPortalSession, postWebhook } from '..';\nimport {\n  nextFunctionFixture,\n  requestFixtu"
  },
  {
    "path": "src/controllers/stripe/index.ts",
    "chars": 2514,
    "preview": "import { API_ROUTE } from '../../config';\nimport Plan from '../../shared/constants/Plan';\nimport {\n  handleCustomerSubsc"
  },
  {
    "path": "src/controllers/stripe/webhooks.ts",
    "chars": 2096,
    "preview": "import Stripe from 'stripe';\nimport { putDeveloperHelper } from '../developers';\nimport AccountStatus from '../../shared"
  },
  {
    "path": "src/controllers/translation.ts",
    "chars": 3568,
    "preview": "import axios from 'axios';\nimport { MiddleWare } from '../types';\nimport { ENGLIGH_TO_IGBO_API, IGBO_TO_ENGLISH_API, MAI"
  },
  {
    "path": "src/controllers/types.ts",
    "chars": 562,
    "preview": "import { Document } from 'mongoose';\nimport { OutgoingExample, OutgoingLegacyExample, OutgoingWord, OutgoingLegacyWord }"
  },
  {
    "path": "src/controllers/utils/__mocks__/fetchBase64Data.ts",
    "chars": 50,
    "preview": "export const fetchBase64Data = jest.fn(() => '');\n"
  },
  {
    "path": "src/controllers/utils/__tests__/minimizeVerbsAndSuffixes.test.ts",
    "chars": 1503,
    "preview": "import Version from '../../../shared/constants/Version';\nimport WordClass from '../../../shared/constants/WordClass';\nim"
  },
  {
    "path": "src/controllers/utils/__tests__/parseAWS.test.ts",
    "chars": 905,
    "preview": "import { parseAWSIdFromKey, parseAWSIdFromUri } from '../parseAWS';\n\ndescribe('parseAWS', () => {\n  it('parses out audio"
  },
  {
    "path": "src/controllers/utils/__tests__/queries.test.ts",
    "chars": 963,
    "preview": "import createRegExp from '../../../shared/utils/createRegExp';\nimport { searchExamplesRegexQuery } from '../queries';\nim"
  },
  {
    "path": "src/controllers/utils/buildDocs.ts",
    "chars": 8137,
    "preview": "import { Aggregate, Model as ModelType, PipelineStage } from 'mongoose';\nimport { assign, flatten, flow, omit } from 'lo"
  },
  {
    "path": "src/controllers/utils/convertToSkipAndLimit.ts",
    "chars": 1110,
    "preview": "const DEFAULT_RESPONSE_LIMIT = 10;\nconst MAX_RESPONSE_LIMIT = 25;\n\n/* Validates the provided range */\nconst isValidRange"
  },
  {
    "path": "src/controllers/utils/fetchBase64Data.ts",
    "chars": 356,
    "preview": "/**\n * Fetches the audio from the url and returns its base64 string\n * @param url\n * @returns base64 string of audio\n */"
  },
  {
    "path": "src/controllers/utils/index.ts",
    "chars": 5210,
    "preview": "import { Response } from 'express';\nimport ExampleStyles from '../../shared/constants/ExampleStyles';\nimport Version fro"
  },
  {
    "path": "src/controllers/utils/minimizeVerbsAndSuffixes.ts",
    "chars": 1365,
    "preview": "import { assign, pick } from 'lodash';\nimport Version from '../../shared/constants/Version';\nimport WordClassEnum from '"
  }
]

// ... and 241 more files (download for full content)

About this extraction

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

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

Copied to clipboard!