diff --git a/_blog/a-standard-ci-cd-pipeline-for-python-projects.md b/_blog/a-standard-ci-cd-pipeline-for-python-projects.md deleted file mode 100644 index d9c40bac..00000000 --- a/_blog/a-standard-ci-cd-pipeline-for-python-projects.md +++ /dev/null @@ -1,312 +0,0 @@ ---- -title: A Standard & Complete CI/CD Pipeline for Most Python Projects -date: 2021-01-21 -slug: a-standard-ci-cd-pipeline-for-python-projects -description: - Optimize your Python project's CI/CD with a comprehensive GitHub Actions - workflow. Learn how to automate linting, testing, coverage reports, and more - without any hassle. Build upon this minimalistic setup for further - customization and improvements. -coverImage: - url: https://ik.imagekit.io/jarmos/learn-cicd-practices-for-python.png?updatedAt=1685086095424 - alt: | - Learn to utilise GitHub Actions to create a robust CI/CD pipeline for - your Python projects. -summary: | - Optimize your Python project's CI/CD with a comprehensive GitHub Actions - workflow. Learn how to automate linting, testing, coverage reports, and more - without any hassle. Build upon this minimalistic setup for further - customization and improvements. ---- - -# A Standard and Complete CI/CD Pipeline for Python Projects - -![Learn to create robust CI/CD pipelines for your Python projects](https://ik.imagekit.io/jarmos/learn-cicd-practices-for-python.png?updatedAt=1685086095424) - -Have you ever spent ages tinkering with CI/CD tools rather than work on writing -code for your Python project? I sure did! There were times -[Poetry](https://python-poetry.com) couldn't install dependencies due to virtual -environments issues. Or other times, the dependencies wouldn't just cache for -some other reasons. - -On top of it, some CI/CD tools are difficult to debug due to obscure error -messages. Hence, I'm sharing this GitHub Actions workflow which I use with most -of my Python projects. It works right out-of-the-box without any tinkering & -sets you on the right path to publishing your project. The workflow is very -minimal yet doesn't compromise on some of the most major CI/CD principles -required for maintaining optimal coding standards. Keeping it minimal also -means, you're free to build upon it for further changes & improvements. - -That said, here're what you get with this workflow, out-of-the-box without any -changes: - -- Linting & code formatting with `pylint`, `Black` & `isort` on all PRs & pushes - to the remote repository. -- Running integrated test suites for catching any breaking changes before - merging the PR. -- Caching dependencies for faster workflow execution times. -- Uploading coverage reports to [CodeCov](https://www.codecov.org) for following - coverage reports. - -So, as you can see, the workflow doesn't do much but ensure the bare minimum -CI/CD principles are taken care of. And, best of all, you can build upon it as -you'll soon see. - -## About the Workflow - -Python's package management scene isn't praiseworthy. And coupled with those -packaging issues, due to virtualenv requirements, setting up CI/CD tools are -quite complicated as well (on GitHub Actions at least). So, I scourged through -the Internet to come up with the most optimal CI/CD setup for Python projects. -While Poetry, out-of-the-box is a great CLI tool for local development, it -doesn't work well with CI/CD platforms. With Poetry, you can manage local -virtualenvs as easily as publishing your project on PyPi right from your -terminal! - -But that's manual labour and as developers we commit often & push to remote -repositories on regular intervals. Repeated manual tasks are subject to mistakes -thus increasing the chances of a bug or breaking changes creeping into the -project. I wanted to resolve this issue without spending too much time setting -up CI/CD tools. The goal was to make the setup as simple & as minimal as -possible, yet it should qualify to meet the modern standards of CI/CD -principles. - -In other words, the setup should be able to perform linting and/or formatting -tasks, run the test suites, generate coverage reports & upload the report to -CodeCov. And those were the tasks, the setup **should have at the minimum**. -Hence, the principles of minimalism were kept in mind. - -I also assume most projects are hosted on GitHub repositories so the setup works -**ONLY** with [GitHub Actions](https://features.github.com/actions). And in case -you're looking to use other CI/CD platforms like -[Travis CI](https://www.travis-ci.com)/[CircleCI](https://circleci.com), then -you might want to look elsewhere. - -That said, you can copy the code snippets shared below in an aptly named -`.yml` under the `.github` directory of your project. For -example, I usually name the file like `test_suite.yml`. GitHub can identify your -workflow files from there automatically. Once you push your commits to the -remote repository, the workflow should initiate then. You can access it at -`https://github.com///actions?query=workflow%3A%22Test+Suite%22`. - -That said, here's the code snippet for the CI/CD pipeline. Feel free to -copy+paste it. 😉 - -```yml -name: Test Suite - -on: [pull_request, push] - -jobs: - linter: - runs-on: ubuntu-latest - steps: - - name: Check out repository - uses: actions/checkout@v3.5.2 - - - name: Set up python - uses: actions/setup-python@v4.6.1 - - - name: Load cache (if exists) - uses: actions/cache@v3.3.1 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip - restore-keys: ${{ runner.os }}-pip - - - name: Install Black, Pylint & iSort - run: python -m pip install black pylint isort - - - name: Run linters - run: | - pylint alokka - black . - isort . - - test: - needs: linter - strategy: - fail-fast: true - matrix: - os: ["ubuntu-latest", "macos-latest", "windows-latest"] - python-version: ["3.8", "3.9", "3.10", "3.11"] - defaults: - run: - shell: bash - runs-on: ${{ matrix.os }} - steps: - - name: Checkout Repository - uses: actions/checkout@v3.5.2 - - - name: Set up Python v${{matrix.python-version }} - uses: actions/setup-python@v4.6.1 - with: - python-version: ${{ matrix.python-version}} - - - name: Install Poetry - uses: snok/install-poetry@v1.3.3 - with: - virtualenvs-create: true - virtualenvs-in-project: true - - - name: Load Cached Virtualenv - id: cached-pip-wheels - uses: actions/cache@v3.3.1 - with: - path: ~/.cache - key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} - - - name: Install Dependencies - run: poetry install --no-interaction --no-root -vvv - - - name: Run Tests - run: | - source $VENV - pytest -vvv --cov-report xml --cov=./ - - - name: Upload Coverage - uses: codecov/codecov-action@v3.1.4 - with: - token: ${{ secrets.CODECOV_TOKEN }} - file: coverage.xml - fail_ci_if_error: true -``` - -## Brief Overview of What the Workflow Does - -If you're impatient like me & would like to skim through the article, here's -what you should know: - -- The workflow executes on PR & push events. As in when someone makes a PR, the - `Test Suite` workflow will run. The same happens when you push you local - commits to the remote repository. -- The workflow consists of two jobs: `linter` & `test`. The latter of which is - dependent on the former. So if `linter` fails, execution of `test` will be - skipped. -- `linter` runs on an Ubuntu VM & installs `pylint`, `Black` & `isort` for - linting & formatting the code. They're also cached for decreasing the - execution times. -- `test` runs on a MacOS, an Ubuntu & a Windows VM with Python versions - `3.8`, - `3.9`, `3.10` and `3.11` respectively. Do note, these runs happen in parallel - irrespective of each other's execution state. -- The `test` job will also cache & install the virtualenv stored under the - `.venv` directory. And then run the test suites with PyTest which generates a - `coverage.xml` report to be uploaded to CodeCov. - -So, as you can see, even if the workflow is kept as minimal as possible, it -still accomplishes a lot of tasks. In fact, most of these tasks are -indispensable for maitaining the minimum quality standards for your projects. - -Anyway, with a brief overview of what the workflow does, let's take a deeper -look into what each line of code was written for. The next section describes it -in as much details as possible. - -## In-depth Explanation of the Workflow - -Right at the top of the file is the `name: Test Suite` key-value pair. It -describes the name of the workflow which GitHub shows in it's web UI. The -succeeding line, `on: [pull_request, push]` pair describes the events that -should trigger the workflow. - -The `jobs:` section describes different jobs that should run in parallel (not -neccessarily, more on it later). Being a minimalist, this workflow describes two -jobs: a `linter` & a `test`. The names of the jobs are kept self-descriptive -intentionally. As mentioned in the previous section, `linter` performs linting -actions when some code is pushed to the repository or a PR is created. While the -`test` job initiates the array of tests on the code pushed or in a PR. - -That said, each job has to be assigned an operating system which is assigned -with the `runs-on:` keyword. While these jobs run in parallel, they can be made -dependent on another. Hence, they can also be stopped prior to completion if a -dependent job failed earlier for some reasons. - -Now for the interesting part. The `steps:` key describes what/which -workflow/commands to execute. So, the `linter` job executes a `git checkout` -first, then sets up an appropriate version of Python in the succeeding step. - -The next couple of steps involves caching dependencies for decreased workflow -execution time. The [actions/cache](https://github.com/actions/cache) GitHub -Action loads the dependencies if they've been cached earlier. It also identifies -the correct cache with a signed key. - -If the dependencies aren't loaded from the cache, then `pip` installs `Black`, -`pylint` & `isort` for linting purposes. - -The final step for the `linter` job is to execute the aforementioned linting & -formatting tools. `Pylint`, `Black` & `isort` has sensible defaults, hence -they're passed without any additional arguments. While you could replace -`Pylint` with `Flake8` but I feel the latter needs some configuration to make -the most out of it especially for an open-source project. - -And finally coming to the `test` job. This job mirrors the previous `linter` job -to an extent as you'll see soon enough. - -Right off the bat, using the `needs:` key, the job is said to be dependent on -the completion of the `linter` job. Thus, `test` willn't execute in parallel but -will also not execute if `linter` fails. The fast fail option is enabled with -the `fail-fast: true` pair. - -In addition to the above strategy, this job is set to run on multiple OS -platforms with multiple versions of Python. This is set with the `matrix:` key -which has `os` & `python-version` has its values. The `os` & `python-version` -values accept an array each, of the OS & the Python versions respectively. - -The next line sets the default shell for the virtual environment the workflow -should run. - -And as mentioned earlier each workflow has to assigned an OS to run on with the -`runs-on` keyword. The `runs-on` key for the `test` job accepts a variable which -will iterate through each of the values set under `matrix.os`. Thus, allowing -the workflow to run multiple instances of the ensuing steps for different OSes & -Python versions! - -The following next two steps is pretty similar to how `linter` started it's -execution process but with a caveat. Based on the values set up under -`matrix.python-version`, each OS instance will have one Python instance as well. - -Now, instead of installing `pip` as was the case in `linter`, the workflow -installs Poetry using the -`[snok/install-poetry](https://github.com/snok/install-poetry)` Action. It -configures Poetry to setup virtualenvs inside the project directory which can -then easily cached in the next step. - -The Cache action caches the whole virtualenv instead of the dependencies. Hence, -Poetry installs the dependencies only if the cached `.venv` wasn't restored. - -Following that, the `.venv` is activated & `pytest` then runs the test suite. -The arguments passed to `pytest` ensures maximum verbosity for debugging & -reporting the output in a `.xml` file format in the root directory. The -generated report then uploads the file to [CodeCov][2] using the -[`codecov/codecov-action`][12]. - -The CodeCov Action accepts an API token that you'll have to copy & pass in as a -[Secret][8] Environment Variable. The CodeCov token can be found at -`https://codecov.io/gh//` (for projects hosted on -GitHub). And finally, at the end, the CodeCov Actions is set to fail if it -errors out. - -The workflow at it's full glory isn't as minimal as it sounds. It's complexity -comes with the fact that production-grade software should be thoroughly tested & -formatted by following standards, if your project is open-source. Even then, -there's still a lot of room for further improvements & changes. And the next -section looks into how you further build upon this workflow. - -## Room for Further Improvements - -As mentioned countless other times, the pipeline is kept minimalistic with an -intention: _Keep room for further changes and/or improvements_. - -Tthere're a ton more changes/improvements that can be made as per one's -requirements. Some such improvements that I can think of over my head are: - -- Enable a `release` event wherein the package is tested, formatted, linted, - built & then uploaded to PyPi with Poetry. -- Considering scalability, the linters & code formatters can be run in parrallel - instead of the sequential runs. -- Tag & update a `CHANGELOG.md` file upon `release`. - -And many more. The possibilities are endless & only limited by the project & -individual maintainer's requirements. - -But all said & done, the code shared here should suffice for most open-sourced -Python projects on GitHub. diff --git a/_blog/blogging-with-hugo-as-an-wordpress-alternative.md b/_blog/blogging-with-hugo-as-an-wordpress-alternative.md deleted file mode 100644 index de804805..00000000 --- a/_blog/blogging-with-hugo-as-an-wordpress-alternative.md +++ /dev/null @@ -1,437 +0,0 @@ ---- -title: How to Create an Overpowered Blog With Hugo (As a Wordpress Alternative) -date: 2021-02-21 -slug: blogging-with-hugo-as-an-wordpress-alternative -description: - Create a blog with Hugo Static Site Generator as a Wordpress alternative & - with added automation plus other superpowers -coverImage: - url: https://ik.imagekit.io/jarmos/creating-hugo-blog.png?updatedAt=1685086095343 - alt: | - Learn to build a blog with Hugo as a WordPress alternative. -summary: | - Learn how to set up a blog with Hugo, a user-friendly Static Site Generator. - Hugo offers benefits like easy installation, content management, and SEO - metadata. You'll also learn how to automate tasks with GitHub Actions and use - a CMS backend like Forestry. Deploy your blog using Netlify for a global CDN. ---- - -# How to Create an Overpowered Blog With Hugo (as a Wordpress Alternative) - -![Learn to build a blog with Hugo as a WordPress alternative](https://ik.imagekit.io/jarmos/creating-hugo-blog.png?updatedAt=1685086095343) - -**Disclaimer**: This blog post suggest using Forestry as a CMS earlier but as of -May 25, 2023, Forestry is now [ TinaCMS ](https://tina.io). - -A developer without a blog is like a fisherman without their fishing rod. While -it is possible to fish with just a thread & a hook, the rod makes life much -easier for the fishermen. In that context, Dan Bader summed it up well in his -article: -[3 Reasons Why You Need a Programming Blog](https://dbader.org/blog/3-reasons-why-you-need-a-programming-blog). - -But, if you've read some of my previous articles, you would know choosing the -right tools to blog is no easy task. I wrote about such a dilemma I was in -earlier. Here's the article: -[_Medium vs Static Site Generators -- A Computer Vision Engineer's Dilemma_](https://medium.com/@jarmos/medium-vs-static-site-generators-1059c46aa59c). -Since publishing that article I had time to experiment with existing blogging -tools. And I reviewed each of them. You can read the review at -- -[_A Review of Some of the Most Popular Static Site Generators_](https://medium.com/dev-genius/a-review-of-some-of-the-most-popular-static-site-generators-e473aa5fa2f9). -And if you are uninterested in reading those articles, here is a quick TLDR - -Static Sites Generators (SSGs) did not serve my needs! - -Any way, on the flip side though, static sites provides the benefit of never -having to worry about server maintenance & security updates. Hence, they are a -much better alternative to Wordpress. Besides, websites/blog posts created using -SSGs cost almost nothing to write, host and maintain! Sure, if you are bent on -spending some cash maintaining it you are free to do so but the expenses will be -negligible to say the least! - -So, in this article, I'll show how you can set up a blog with Hugo. The blog -will have a CMS, it will update itself & some more OP super powers to add along. -But do note, having some prior programming knowledge can be a bonus point but is -not a prerequisite. You can follow along with the instructions suggested in this -article & you'll be fine. - -## Prerequisite Tools - -The star of our article is [Hugo](https://gohugo.io) and trust me when I say it, -this piece of software is without a doubt one of the easiest to use SSG -available out there. - -Besides Hugo, we'll also need a GitHub account to host the articles & other -tools as well. One of those tools include -[GitHub Actions](https://features.github.com/actions). Of the many -community-maintained GitHub Actions, we'll be using a couple of them. No blog -can be a Wordpress alternative without a Content Management System (CMS). So, to -deliver onto our CMS needs, we'll use the services from -[TinaCMS](https://tina.io). And we'll use [Netlify](https://www.netlify.com) to -deliver the generated static content. They use a global Content Delivery Network -(CDN) to deliver the content to our audiences. - -Optionally, we could use -[Google Analytics](https://analytics.google.com/analytics/web/) for tracking -needs. But if you're a privacy concerned citizen, use -[Cloudflare Web Analytics](https://www.cloudflare.com/en-gb/web-analytics) -instead. - -So, to sum up, here's the list of all the necessary tools & services we'll be -using: - -- A Github repository to host the articles, themes & other files required by the - tools we'll be using. -- A couple of GitHub Actions. - - [peaceiris/actions-hugo](https://github.com/peaceiris/actions-hugo) to set - up Hugo & generate the static content. - - [nwtgck/actions-netlify](https://github.com/nwtgck/actions-netlify) to - deploy the generated static content. -- An account on TinaCMS for managing our content in Markdown format. -- A Netlify account to deliver the static content to our audiences. -- And the optional Google Analytics account for tracking needs. - -So, that said, ensure you're set up with all the tools mentioned above & then we -can get started. - -## Using Hugo (With All Its Glory) - -As mentioned earlier, Hugo is without a doubt one of the easiest Static Site -Generators available to use. The fact that Hugo has 50K+ stargazers shows how -useful it is! So, without wasting any more time, let's dive into seeing how to -use Hugo. - -### Installing Hugo - -First things first, is to install Hugo on your local machine. Unlike other -Static Site Generators Hugo has no dependency! But generators like -[Pelican](https://getpelican.com), [Gatsby](https://www.gatsbyjs.org) and/or -[Jekyll](https://jekyllrb.com) needs a local Python/Ruby runtime or a JavaScript -environment. With Hugo, all you need is the Hugo binary & you're good to go. The -"_installation_" procedure is also pretty simple. You need to add the binary to -system `PATH` & invoke the `hugo` command from anywhere in the Terminal. Do -note, editing each Operating System's PATH is quite different. Hence, do take a -thorough look at the official [installation docs][8]. - -Now ensure you installed Hugo by running the `hugo version` command on your CLI. -If everything works fine, you should see a similar output. - -```sh - Hugo Static Site Generator v0.80.0-792EF0F4 windows/amd64 BuildDate: 2020-12-31T13:37:57Z` -``` - -### Creating Your Site - -I must say, installing Hugo while easy, it isn't the most fun part of the whole -process. So, let's get started with the fun parts. - -You can generate a skeleton site (_which we'll build upon soon_) with the -`hugo new site .` command. Notice the `.` (_dot_) at the end of the command? It -tells Hugo to generate the skeleton site in the current directory. The command -generates a simple set of files & folders. Each of them serves a specific -purpose for Hugo. Here is what the directory structure looks like after -generating them. - -```sh - . # Current (or Root) directory - ├───archetypes # Stores preconfigured frontmatter metadata. - ├───content # Stores your Markdown articles. - ├───data # Stores data for used with templates and/or shortcodes - ├───layouts # Stores custom code snippets to override the used theme(s). - ├───resources # Generated resources (for eg processed images) are stored here. - ├───static # Holds static content like CSS/JS files, images, favicons, etc. - ├───themes # This is where you download & store a Hugo theme. - └───config.yml # Config file to configure Hugo. Supports YAML, TOML & JSON formats. -``` - -There is more to what Hugo generates as a skeleton site than what I can discuss -in one blog. So without delving into the details of the directory structure, -let's keep things minimal. That way, there'll be room for further -personalization and you can start delivering content at the earliest as well. - -### Creating Content (The Actual Fun Stuff!) - -As mentioned earlier using Hugo is drop-dead easy. Yet, any given Hugo project -can be as complicated as it needs to be. But regardless, you can start writing -content right away, all you now need is; - -- Download a theme under the `themes` directory. -- Configure Hugo to generate your site with some site metadata for SEO needs in - the `config.yml` file. -- Write content in Markdown under the `content` directory. - -It's that simple! - -Hugo boasts of some 300+ beautiful -[community maintained themes](https://themes.gohugo.io). You can download a -theme to your site's `theme` directory & Hugo will use it to generate the -contents of your site. And the easiest way to install a theme is to use "_Git -Submodules_". That way you can ensure the themes are updated as & when the theme -authors pushes a commit to it's repository. Installing themes is also very easy. -Running the `git submodule add themes/ --depth=1` -command is enough. - -For SEO needs, you might also need site metadata. And Hugo takes care of it -out-of-the-box. You've to configure Hugo with a `config.yml` file. And in that -file you include the necessary details for the metadata. Hugo uses those values -to populate the metadata of your site. - -And to get a general feel of what a config.yml file looks like, here's an -example; - -```yaml -baseURL: "Your Site URL" -languageCode: "en-us" -title: "Your Website Name" -theme: "Theme Name" -paginate: 5 -enableRobotsTXT: true -params: - env: production - title: Your Website Name - description: "Description of your website." - images: ["profile-pic.jpg"] - defaultTheme: auto - GoogleAnalyticsID: G-V0ZH6RS2BM - assets: - favicon: icons/favicon.ico -menu: - main: - # Menu items like Contact, About Me pages & so on -``` - -Do note, configuring the `config.yml` isn't limited to what I mentioned here. -Based on the theme you're using, you might/mightn't have to extend on it. - -And at last, the content directory where you store the Markdown files for your -articles. You can organize your Markdown content into subdirectories for easier -maintenance & organization. For example, here's how mine looks. - -```bash -./content - ├───posts - ├ ├───article-1.md - ├ ├───article-2.md - └───about-me.md -``` - -And with that information, you can start creating content right away. - -Be sure to store all the articles in Markdown format under the content -directory. And if you're not familiar with Markdown, check out -[Markdown Guide](https://www.markdownguide.com). - -Now that you've started creating content, it's time for your audience to read -them! And the next section is about delivering the content to our audiences... - -## Deploying the Blog - -Unlike Wordpress sites, static sites don't need a hosting server. This reduces -the surface area of potential security & maintenance mishaps. But without a -server to host the content how do we deliver them to our audience? - -This is where Netlify's services come handy. They'll deliver our static content -over their global CDN. And their free tier services also come with some nifty -goodies. Some of those extra goodies include a domain, a build platform & many -more. But for reasons mentioned later, we won't use all their services. - -So, ensure you've created a GitHub repository to host your site contents & a -Netlify account to start with. You'll need to perform a one-time operation on -the Netlify dashboard to create a new site. Refer to the -[Netlify documentations](https://docs.netlify.com) to learn more about the exact -process to do so. - -Then push your fresh new site to the GitHub repository you created recently. And -that should trigger a Netlify build operation. You can now view your website at -an URL provided by Netlify which you can change to a custom domain if you wish -to do so later on. - -Now each time you write a new article or push some aesthetic changes to your -site, Netlify will trigger a build. While it works & is fine for most users, -there are certain downsides. One of them is the slow & unoptimized build timings -(_often taking over 2mins to complete the build_). And considering Netlify -provides only 300 minutes of build per month, it won't be long before you run -out of it. - -Besides, that way you're not utilizing Hugo's full potential. Which is why we'll -use some GitHub Actions instead. With it, we'll deploy our site & automate some -monotonous tasks as well! - -The next section delves deeper into why & how we can achieve such a feat. - -## Setting Up Automation & a CMS Backend - -Creating & deploying the site was easy & fun. But it doesn't last long (_saying -from personal experience_). More so, when you add the theme as a submodule. You -can expect frequent updates for it. - -But thanks to [Dependabot](https://github.com/dependabot), we can keep our -theme(s) updated at all times. - -There's also the need for a Content Management System (CMS). What good is a -Wordpress Alternative, without a CMS, right? And we should also delegate the -build process to GitHub Actions instead of Netlify. This is a more efficient way -to deploy & maintain our site. - -So that said, let's list out the remaining features we need to work on & start -working on them one-by-one. - -- Setup & configure Dependabot to keep all dependencies for our site updated. - -- Setup & use TinaCMS as the CMS backend. - -- Configure & delegate the build process to GitHub instead of Netlify. - -### Allowing Dependabot to Keep Dependencies Up-to-Date - -The Dependabot and GitHub integration came as a godsend. Because of it, keeping -project dependencies up-to-date has never been easier. And guess what? -Dependabot can take care of Git Submodules as well! Which means your themes will -stay updated as soon as its author pushes some changes to it. - -To configure Dependabot, you need a specific config file for it. This specific -file named `dependabot.yml` stays under the `.github` directory (_create it if -it doesn't exist yet_). - -And this is how it should look like: - -```yaml -version: 2 -updates: - # Update all the GitHub Actions we'll use soon - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "daily" - time: "06:00" - labels: ["github-actions", "automerge"] - - # Updates all Git Submodules (the theme in this case) - - package-ecosystem: "gitsubmodule" - directory: "/" - schedule: - interval: "daily" - time: "06:00" - labels: ["submodule", "automerge"] -``` - -With Dependabot configured, it'll now look for updates every day at 0600 Hours -UTC. And if there's any, it'll then open a PR with respective labels for GitHub -Actions & Git Submodules each. But that's pretty much the tip of the iceberg for -Dependabot configurations. You can find a more detailed configuration option in -the official docs. - -With Dependabot set up, you no longer have to worry about manual update & -maintenance tasks. - -### Setting Up TinaCMS as a CMS Backend - -No static blog can become a true _Wordpress alternative_ without a CMS. And -that's what makes Wordpress attractive to most users without any technical -prowess. And as such, some users might not be comfortable writing their content -in Markdown. For them a web-based Rich Text environment is what works best. - -Hence, we'll be using TinaCMS's backend CMS services. There are alternatives -like [Contentful](https://www.contentful.com) (_one of the most popular one_) & -[Netlify CMS][14]. But, from personal experience I found TinaCMS to be the -easiest to setup & configure. - -The things you can do with Hugo & TinaCMS is beyond the scope of this article. I -could write another full-blown article on this topic alone. So, keeping this -article rather short & act as a guide for interested readers, here's a gist of -how to set up 19. - -1. Ensure you've TinaCMS account & your site is "_added_" to their services. -2. Configure the settings of the CMS from the Admin panel. -3. Login to your site's Admin panel by navigating to `` & - start writing your content in Rich Text (_you can write in Markdown as well - if you prefer_). - -TinaCMS has a [guide][1] to set up their CMS with Hugo, do check it out as well! - -### Automation & Delegating Build Task to GitHub - -While there's nothing wrong in using Netlify to build the site, it has some -limitations. A major one being, it's slow & unoptimized build times (_it took -over 2mins for my site to build_). With Netlify's limited 300 build mins per -month, it won't take long before the free quota is used up. - -So, to make the most out of Hugo's potential, you should use GitHub Actions. -With it, you can build your site in <1 mins (_usually takes 20-40 secs on -average for mine_). - -Besides, compared to Netlify, GitHub provides 2000 build mins per month! So, -coupled with less build times & a huge build mins quota, you won't have to worry -about builds not triggering 😊. - -Also, having all tools under one roof makes maintenance much easier to handle. -So, let's peruse through what we need to do automate some of the build tasks; - -1. First thing first is to ensure you've a `netlify.toml` config file under the - root directory. The Netlify GitHub Action will use it to deploy the website - to Netlify's CDN. The file usually looks something like the following; - - ```toml - # Post Processing Settings - [build.processing] - skip_processing = false - [build.processing.css] - bundle = true - minify = true - [build.processing.js] - bundle = true - minify = true - [build.processing.html] - pretty_urls = true - [build.processing.images] - compress = true - ``` - - As is customary, the Netlify documentations has more information on this - particular configuration file, so its recommended to refer to it. - -2. To automate some more monotonous tasks, add a `build.yml` workflow file. - Place it under the `.github` directory. And add the following content to the - `build.yml` file. - - ```yaml - name: Netlify Deploy - - on: push - - jobs: - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - submodules: true - fetch-depth: 0 - - name: Setup Hugo - uses: peaceiris/actions-hugo@v2 - with: - hugo-version: "0.80.0" - - name: Generate Static Content - run: hugo --minify - - name: Deploy to Netlify - uses: nwtgck/actions-netlify@v1.1 - with: - publish-dir: "./public" - production-branch: dev - production-deploy: true - github-token: ${{ secrets.GITHUB_TOKEN }} - deploy-message: "Deployed with GitHub Actions" - enable-pull-request-comment: true - enable-commit-comment: false - enable-commit-status: true - overwrites-pull-request-comment: true - netlify-config-path: ./netlify.toml - env: - NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - timeout-minutes: 1 - ``` - - This file instructs GitHub Actions to use two workflows for deployment tasks. - It'll set up Hugo, generate the static content & deploy it to Netlify. - Further, it's triggered on every push & PR event. - -That said, I look forward to how you use Hugo to share your amazing content to -the rest of the world, so please feel free to reach out to me if needed! diff --git a/_blog/create-custom-keymaps-using-lua-for-neovim.md b/_blog/create-custom-keymaps-using-lua-for-neovim.md deleted file mode 100644 index e3ff0a3f..00000000 --- a/_blog/create-custom-keymaps-using-lua-for-neovim.md +++ /dev/null @@ -1,274 +0,0 @@ ---- -title: How to Create Custom Keymaps in Neovim With Lua -date: 2021-10-12 -slug: create-custom-keymaps-using-lua-for-neovim -description: | - Learn to create custom key bindings in Neovim using the optional inbuilt Lua - runtime. And ditch the archaic & cryptic Vimscript in Lua's favour! -coverImage: - url: https://ik.imagekit.io/jarmos/create-custom-keymaps-using-lua.png?updatedAt=1685086095483 - alt: | - Learn to create custom Neovim keymaps using the inbuilt Lua embedded - scripting environment and the native Lua API. -summary: | - Neovim's Lua runtime allows for powerful customization through custom - keybindings. Learn how to write Lua functions for key mappings and modularize - your configurations. Check out the Neovim-Lua Guide and other resources for - more information. Migrate your Vimscript configs to Lua for a better - experience. ---- - -# How to Create Custom Keymaps in Neovim Using the Embedded Lua Environment - -![Learn to create custom keymaps in Neovim using Lua](https://ik.imagekit.io/jarmos/create-custom-keymaps-using-lua.png?updatedAt=1685086095483) - -Neovim (or even Vim) is an excellent piece of software for any developers out -there. The ability to create custom keybindings & do pretty much anything is -testament to Vim's popularity. And if you've used Vim before, you should be -aware of what's possible through custom Vim keybindings as well. - -For the uninitiated, Vim's openness towards creating custom keybindings has -pretty much no competition out there. As such, only your imagination is the -limit to what you could possibly create using custom keybindings. - -Vim users are also required to have working knowledge of Vimscript (_which is a -scripting language built for Vim configuration_). It's not the most elegant -language out there & neither has it any use outside of Vim. Also for many of -you, the time investment & efforts required to pickup a redundant programming -language mightn't be productive either. Fortunately, `Neovim v0.5+` gave the -community a signficant update to play around with & that's the inbuilt Lua -runtime. - -The optional Lua runtime also backwards compatible meaning you could still try -out the optional runtime right from within Vimscript. We'll not discuss how to -write Lua code within Vimscript since it's beyond the scope of this article. But -feel free to refer to this amazing -[Neovim-Lua Guide](https://github.com/nanotee/nvim-lua-guide) on GitHub for a -quick reference. - -If that piqued your interests & you would like continue learning about how -creating custom keybinds in Neovim is a much pleasant experience, then read -ahead. The rest of the article starts with a brief intro to the optional Lua -runtime, followed by creating a Lua function for mapping the custom keybinds. -And towards the end of it all, we'll suggest further resources you might want to -take a look at to learn about Neovim's Lua runtime better. - -## Introducing the Optional Lua Runtime - -Before we proceed further into the article, let's briefly introduce the Lua -runtime in Neovim. Having some idea of it will help better understand the how's -& what's possible to create. - -That said, Neovim was released with a set of some useful features. One such -feature that makes Neovim stand out is its -[builtin API](https://neovim.io/doc/user/api.html). The programmatic access to -the API & the Lua runtime means you can let your imaginations go wild if you so -desire. - -And just so you know, like any other config files used to hack Neovim/Vim, the -Lua code also needs to be placed in the `runtimepath` (see `:h rtp` for more -info). These config files (with a `.lua` extensions) are placed inside a -directory aptly named `lua`. And Neovim will source everything inside that -directory when invoked. - -Do note, the location to the Neovim runtimepath varies depending on the choice -of your OS. So, for Linux users out there, check if your OS follows the -[XDG Base Directory](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) -specification, then the Lua files should be usually available at: -`$HOME/.config/nvim/lua`. And my fellow Windows users out there, you should -check for the Lua files at `%LOCALAPPDATA%\nvim\lua`. - -For more info on where to place the config files, check out the -["_Where to put Lua files_"](https://github.com/nanotee/nvim-lua-guide#where-to-put-lua-files) -section of the Neovim-Lua Guide on GitHub. - -With our little introduction to the optional Lua runtime taken care of, lets -check out the how to configure Neovim keybindings with Lua. In the next few -sections we'll taking a look at, writing an example Lua function followed by an -actual functional wrapper in Lua. This functional wrapper will be used to create -our custom keybindings where & whenever necessary. - -## How to Write Lua Function for the Neovim Key Bindings - -Back in the day when Neovim wasn't a thing, Vim provided the `remap` commands -(_and the `noremap` for non-recursive remaps_) for customizing & remapping -keybindings. As such it was a common scene to see `nnoremap` commands scattered -all over one's `.vimrc` file. Here's one such -[example `.vimrc`](https://github.com/jessfraz/.vim/blob/master/vimrc) file I -picked up from the Internet. The file is huge (~1200 lines of code!), is -unweidly & a totaly nightmare to maintain. - -And here's a little code snippet I picked up from the `.vimrc` file above. - -```vimscript -" Example .vimrc file with hundreds of lines of code -... -nnoremap :WhichKey ',' -nnoremap ? :WhichKey ',' -nnoremap a :cclose -nnoremap :nohlsearch -... -``` - -Fortunately for us, Neovim provides a helper function through it's builtin API. -Aptly named `vim.keymap.set()`, the users are expected to use this function -directly or by wrapping it in Lua code. The later method is recommended since -that way it's possible to adhere to standard coding practices. Using Lua code in -tandem with the Neovim API also helps in modularising the configurations. Thus -making maintenance much easier & keep your sanity intact. - -Using wrapper functions also ensures the configurations are -["**DRY**"](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) & -["**SOLID**"](https://www.digitalocean.com/community/conceptual_articles/s-o-l-i-d-the-first-five-principles-of-object-oriented-design). -Adhering to such common development standard practices means the configurations -looks clean & organized as well. - -So what does a typical Neovim configuration look like when used with Lua? -Following are some such examples: - -```lua --- Functional wrapper for mapping custom keybindings -function map(mode, lhs, rhs, opts) - local options = { noremap = true } - - if opts then - options = vim.tbl_extend("force", options, opts) - end - - vim.keymap.set(mode, lhs, rhs, options) -end - -map("n", ",", ":nohlsearch", { silent = true }) -map("n", "", ":WhichKey ','" { silent = true }) -map("n", "?", ":WhichKey ','") -map("n", "a", ":cclose") -``` - -At first glance, the Lua code might appear too verbose but it's a good thing as -you'll see soon. - -In the Lua code snippet we shared aboved, we defined a function called `map()`. -It accepts four parameters namely: - -- `mode` (as in Vim modes like `Normal`/`Insert` mode) -- `lhs` (the custom keybinds you need) -- `rhs` (the commands or existing keybinds to customise) -- `opts` (additional options like ``/``, see `:h map-arguments` - for more info on it) - -By default, the `opts` parameter of the `map()` function is assigned to a table -`{ noremap = true }`. In doing so, nested & recusive use of mappings are allowed -(refer to `:h map-commands` for more info on it). You can expand the `opts` -table further with additional `map-arguments` as you require. And at the core of -the wrapper is the `vim.keymap.set()` function which accepts the list of -parameters mentioned above. - -This function can then be reused wherever you need them. As you'll see in the -next we can modularise our Neovim configurations even further! - -## Using the Lua Functions Across the Neovim Runtime Files - -The wrapper function we used in the section above does help in customising -default Vim remappings. But defining the wrapper function & then using it right -within our `init.lua` file doesn't adhere to the DRY and/or SOLID principles at -all. To make the configs more compliant with standard dev practices, we'll use -[Lua Modules](https://www.lua.org/manual/5.1/manual.html#5.3). Using Lua Modules -ensures there's clear separation of logic in our configurations. - -And if you need a refresher on how to create Lua Modules for Neovim, refer to -the ["_Modules_"](https://github.com/nanotee/nvim-lua-guide#modules) section of -the Neovim-Lua Guide on GitHub. - -That said, create a `utils.lua` under the `lua` directory in your runtimepath. -Lua Modules are identified if they contain the following lines of code: - -```lua --- Assign an empty table to the local variable named M (it's standard to name the variable as "M") -local M = {} - --- Define your function & add it the M table -function M.do_something() - -- Your functional logic -end - --- Since the M table is scoped, it has to be returned for usage elsewhere -return M -``` - -Explaining Lua Modules are beyond the scope of this article as well, so perhaps -refer to the Lua 5.1 documentations linked above for reference. - -For our use case, the Lua Module we defined will contain the functional wrapper -for the custom keybinds. As such this is what the contents of our `utils.lua` -module will look like: - -```lua --- Our lua/utils.lua file - -local M = {} - -function M.map(mode, lhs, rhs, opts) - local options = { noremap = true } - if opts then - options = vim.tbl_extend("force", options, opts) - end - vim.keymap.set(mode, lhs, rhs, options) -end - -return M -``` - -Since Neovim sources & loads any Lua files located under the `lua` directory in -the runtimepath our `map()` function will be available to be imported anywhere -else as well. Hence, now it's possible to simply import the wrapper into your -`init.lua` file & use it for creating your remaps. Thereby you can now keep the -file clean, maintainable & fast to load. - -Here's how you could rewrite the `init.lua` file by importing the `map()` -function from the `utils` module; - -```lua --- Our example init.lua file - --- Import & assign the map() function from the utils module -local map = require("utils").map - -map("n", ",", ":nohlsearch", { silent = true }) -map("n", "", ":WhichKey ','" { silent = true }) -map("n", "?", ":WhichKey ','") -map("n", "a", ":cclose") -``` - -Now that the code is properly modularised, maintenance shouldn't be a chore & -chances of something breaking will be much lower. Further, if you wish extending -our rudimentary `map()` function is as simple making your necessary changes to -the `utils` module! - -That said, chances are, if you've been using Neovim for a while now, you're yet -to migrate your configs to Lua code. And you'll be glad to hear that the Neovim -devs went through great lengths to maintain backwards compatibility. If making -migration changes from Vimscrip to Lua code for your existing configs makes you -uneasy, then don't fret. You can even use Lua code right within Vimscript as -well! For that, refer to `:h heredocs` for more info on the topic. - -To help you figure your way around while migrating the existing configs, the -next section will suggest some useful references you could take a look at. - -## Final Words & Things to Look Forward to - -The optional Lua runtime within Neovim is a godsend & it's also one such feature -which makes Neovim particularly stand out apart from Vim. But since the features -& Neovim itself is comparatively new, resources around these features are hard -to come by. As such following are some resources you might want to take a look -at if configuring Neovim with Lua piques your interests. - -1. [A Guide to Using Lua in Neovim](https://github.com/nanotee/nvim-lua-guide) -2. [`h: lua`](https://neovim.io/doc/user/lua.html) for a comprehensive guide on - how to use Lua within Neovim. - -There is obviously a lot more that is possible with using Lua for Neovim -configuration, so in case I missed out on something, do let me know? - -And to conclude this article, what do you think of using Lua to configure -Neovim? Are you current configuration in Vimscript or Lua? And have you noticed -any difference while using either? Let me know... diff --git a/_blog/customize-windows-terminal.md b/_blog/customize-windows-terminal.md deleted file mode 100644 index 21afe1be..00000000 --- a/_blog/customize-windows-terminal.md +++ /dev/null @@ -1,362 +0,0 @@ ---- -title: "Customizing the New Windows Terminal: A Minimalist Approach" -date: 2020-12-25 -slug: customize-windows-terminal -description: Who needs Linux when you got a fully customized Windows Terminal! -coverImage: - url: https://ik.imagekit.io/jarmos/windows-terminal-customisation.png?updatedAt=1685086095311 - alt: | - Learn how to customise the new Windows Terminal using a minimalist - approach. -summary: | - Boost productivity with Windows Terminal: Customize for a minimalist approach. - Learn settings, profiles, color schemes, key bindings & more. Streamline your - coding experience on Windows. ---- - -# Customise Windows Terminal: A Minimalist Approach - -![Customise Windows Terminal with a minimalist approach](https://ik.imagekit.io/jarmos/windows-terminal-customisation.png?updatedAt=1685086095311) - -**Disclaimer**: As of May 25, 2023, I am no longer using Windows (and its -related technologies) for software development, hence I cannot guranteed the -suggestions made in this blog post will work for you! - -Heard of the new Windows Terminal (WT), Microsoft has been actively working on -recently? You might’ve if you’ve been following my updates on Twitter. I was -advocating Microsoft’s effort to make Windows a more developer-friendly platform -for quite a while now. And ever since I moved from Ubuntu to Windows for my -coding needs, I’ve come to realise how things have changed on Windows-land for -the better. - -## What is This New Windows Terminal? - -With that said, WT is a console developed & distributed by Microsoft. It -supports a wide variety of shells, the full list of which I’m not aware of. But -I’m assured it supports most of the popular ones. Hence, by popularity, Bash/ZSH -is supported through Windows Subsystem for Linux (WSL) & PowerShell 5.1 which -ships pre-packaged with Windows 10+. - -On that note, I’ve been using PowerShell 5.1 mainly because it’s there by -default & is a much easier scripting language over Bash. So, without further -ado, let’s dive into how I’ve made some very minimalist customization to WT. - -## Why Maintain a Minimalist Look? - -Windows Terminal is **VERY** customizable, as you’ll see soon enough. You can -set a background image (or a GIF) of your choice. You can add multiple panes to -a tab with each running a different shell instance, the possibilities are -infinite. But customizing to such an extent comes with a caveat, spending way -more time on customizing the Terminal to look “perfect” is time-consuming. The -time which I could spend on projects & work instead. - -Besides, there’s also the problem of cognitive overload I’ve trouble dealing -with. Thus, I follow the principles of minimalism wherever possible. Put simply, -having just enough & specific information for a task is all I need. If a need -arises, customizing the Terminal to fit those needs is still an open option. - -Anyway, enough of my justifications & let’s cut the chase. This is the -configuration I use, feel free to copy & use them. - -```json -{ - "$schema": "https://aka.ms/terminal-profiles-schema", - "actions": [ - { - "command": { - "action": "copy", - "singleLine": false - }, - "keys": "ctrl+c" - }, - { - "command": "paste", - "keys": "ctrl+v" - }, - { - "command": "find", - "keys": "ctrl+shift+f" - }, - { - "command": { - "action": "splitPane", - "split": "auto", - "splitMode": "duplicate" - }, - "keys": "alt+shift+d" - }, - { - "command": { - "action": "splitPane", - "profile": "Neovim v0.4.4", - "split": "auto" - }, - "keys": "shift+alt+2" - }, - { - "command": "closeTab", - "keys": "ctrl+w" - }, - { - "command": "closeOtherTabs", - "keys": "ctrl+t" - }, - { - "command": "closePane", - "keys": "ctrl+shift+w" - } - ], - "copyFormatting": "none", - "copyOnSelect": false, - "defaultProfile": "{574e775e-4f2a-5b96-ac1e-a2962a402336}", - "disabledProfileSources": ["Windows.Terminal.Azure", "Windows.Terminal.Wsl"], - "launchMode": "maximized", - "profiles": { - "defaults": { - "acrylicOpacity": 0.2, - "colorScheme": "Nord", - "cursorColor": "#969696", - "cursorShape": "filledBox", - "fontFace": "MesloLGL Nerd Font", - "fontSize": 11, - "padding": "20, 8, 8, 3", - "startingDirectory": "E:\\Projects", - "useAcrylic": true, - "backgroundImage": "%USERPROFILE%\\Pictures\\Saved Pictures\\312629.jpg" - }, - "list": [ - { - "commandline": "powershell.exe", - "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}", - "hidden": false, - "name": "Windows PowerShell v5.1" - }, - { - "commandline": "cmd.exe", - "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}", - "hidden": true, - "name": "Command Prompt" - }, - { - "guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}", - "hidden": false, - "name": "PowerShell v7.2", - "source": "Windows.Terminal.PowershellCore" - }, - { - "guid": "{905ee199-8709-449b-b0f1-5ac7ea8638b9}", - "commandline": "py.exe", - "icon": "%PROGRAMFILES(x86)%\\Python38-32\\python.png", - "name": "Python v3.8.5" - }, - { - "commandline": "nvim", - "guid": "{cec59ed5-e63e-4199-9e5f-d292b4ce5346}", - "icon": "C:\\Tools\\Neovim\\neovim.png", - "name": "Neovim v0.4.4" - } - ] - }, - "schemes": [ - { - "background": "#2E3440", - "black": "#3B4252", - "blue": "#81A1C1", - "brightBlack": "#4C566A", - "brightBlue": "#81A1C1", - "brightCyan": "#88C0D0", - "brightGreen": "#A3BE8C", - "brightPurple": "#B48EAD", - "brightRed": "#BF616A", - "brightWhite": "#E5E9F0", - "brightYellow": "#EBCB8B", - "cursorColor": "#FFFFFF", - "cyan": "#88C0D0", - "foreground": "#D8DEE9", - "green": "#A3BE8C", - "name": "Nord", - "purple": "#B48EAD", - "red": "#BF616A", - "selectionBackground": "#FFFFFF", - "white": "#E5E9F0", - "yellow": "#EBCB8B" - } - ], - "tabWidthMode": "equal", - "theme": "dark" -} -``` - -## My Customization & Description of the Config File - -The Windows Terminal configurations are divided into 4 distinct sections each -customizing a specific aspect of the software. - -**Global (or Default) Settings**: - -The config file begins with the Global (or “_default_”) settings. Followed by -the Profile, Colour Schemes & lastly, the key Bindings (or “_Actions_”). - -Right at the start of the file, the Global settings apply customization to the -whole software, as in how Windows Terminal behaves. In context to that, my -configuration starts Windows Terminal with PowerShell as the default profile -(more on profiles a bit later), indicated with the `defaultProfile` settings. - -Right below it & till line 12, I’ve set Windows Terminal to not copy a body of -text when selected & not even the formatting. Azure Shell & WSL profiles are -also disabled since I’ve yet to find any relevant use for them. And at last, to -ensure my eyes don’t burn & are protected, a dark theme, tab width & startup -window maximized is enabled. - -Those were the Global settings which apply to the whole of Windows Terminal as a -software. They don’t do much but help with the startup time, my eyes & -productivity. - -But here’s where things get visually interesting, customizing individual -Profiles. - -**Profiles**: - -Profiles are Windows Terminal’s way of creating & manipulating shells & other -terminal emulators. In other words, you can have a PowerShell session running -side-by-side on a tab with Bash (running on an Ubuntu-WSL). If it isn’t obvious -from the GIF on the featured image already, I’ve set up four profiles – -PowerShell, Python Repl, Git Bash & Neovim. But the configuration lists 6, how & -what’s going on? - -Be patient, soon enough you’ll figure that out as well. - -The Profile section accepts some default settings as well. And they’ll be -applied to each of the profiles stated inside the array. The default settings -specify, the starting directory when the profile is initiated, the font size, -bold fonts (so you don’t have to squint to read the texts), padding (makes the -text look nicer & works like CSS padding), the shape & colour of the cursor (to -add some oomph…). The acrylic background is enabled, making the Terminal look -transparent. And not to forget, at last, the name of the colour scheme. - -These default settings ensure uniformity across whichever shell emulator is in -use. These settings also ensure good minimalist aesthetics without being too -distracting and/or hard on the eyes. - -Line 25-64 lists the profiles, the crest of Windows Terminal we’ve been -discussing till now. There’s a lot more you could do here, so I suggest checking -out the -[official docs](https://docs.microsoft.com/en-us/windows/terminal/customize-settings/profile-settings) -first. You can build upon my configurations & yes, don’t forget to share your -creations with me (tweet them to me 😉). - -Anyway, keeping in mind a minimalist approach, Command Prompt & Azure profiles -are hidden using the `hidden: true` settings. Since Windows Terminal comes with -them by default & removing them makes the software act weird, I felt it’s best -to hide them altogether. Besides Azure Shell & Command Prompt, PowerShell is -also configured to load by default right after installation. - -And, I’ve been using PowerShell a lot lately & I assure you, it’s pretty darn -good! It’s a good scripting language which has the simplicity of Python & file -system management capabilities of Bash. So, I feel you should give it a try, -more so right now, since it’s cross-platform. Hence, PowerShell is set to -`hidden: false`, to **NOT** hide it from the UI. - -Additionally, the `guid` is set to a unique alphanumeric value, generated using -`New-Guid` in PowerShell which acts as a unique identifier for that specific -profile. `name` is set to the name of the profile which should show up on the UI -tab. Often you might’ve to use `suppressApplicationTitle: true` to not load the -application default name. For example, Git Bash loads the file path as the tab -name on the UI. - -The `commandline` & icons setting accepts the path to the binaries & the icons, -respectively. If the file path is added to PATH, then there’s no need to specify -the absolute file path. I did something similar with `nvim`. - -A great feature of Windows 10 is the concept of -[Universal Windows Platform](https://docs.microsoft.com/en-us/windows/uwp/get-started/universal-application-platform-guide) -(UWP) app which enables devs to create apps for any Windows platform. Windows -Terminal accesses those UWPs with the `source` setting. Hence, Azure Shell & WSL -are loaded as UWPs on the Terminal. - -Now with most of the theory done & dusted, it’s time to figure out how to -customize the colour scheme & the key bindings. So let’s move on to the next -section. - -**Colour Schemes**: - -Lines 65-87 lists the settings for the colour schemes. There’s not much to -discuss here except perhaps the `name` settings. It serves as an identifier for -specific colour schemes & hence, you can have a list of multiple other colour -schemes, all customized to fit your needs. - -Do note though, it’s important to name your colour schemes, as that’s what each -profile will refer to for customizing its font colours. But in my case, I’ve set -one single colour scheme for all the profiles. This way I can maintain -consistency across all the Shells. - -You can of course have more than one scheme, each referenced by specific -profiles. - -**Key Bindings**: - -As for customized key bindings, I’ve kept them to the minimal, since the default -ones serve my needs most of the time. Feel free to refer to the docs on -customizing key bindings to check & change them according to your needs. - -With that said, here’s the list of key bindings that I use: - -- `ctrl+c` for copying a selected piece of text. -- `ctrl+v` for pasting a piece of text from the clipboard. -- `ctrl+shift+f` to find texts/words on the Terminal. -- `alt+shift+d` to split the pane automatically with the most available space & - duplicating the active shell. -- `shift+alt+2` to activate the Neovim pane & size it automatically. -- `ctrl+w` to close a tab. -- `ctrl+t` to close all the other tabs except the current one. -- `ctrl+shift+w` closes the active pane. - -And that marks the end of my Windows Terminal customization configuration. That -was a lot to read for a supposed minimalist configuration. - -## How Can You Give Your Windows Terminal a Personal Touch - -My customization was meant to be minimal, pleasant on the eyes & most important, -not distracting. It’s fine if you find my customization not “good enough” for -you & thus, would like to add some more personal touches. - -To do that, I suggest, looking at the colour scheme customization first. There -are a ton of schemes available for free at -[Windows Terminal Themes](https://windowsterminalthemes.dev/) & -[Terminal Splash](https://terminalsplash.com/). Just ensure there's enough -contrast between the foreground & the font colours. Additionally, you might’ve -to experiment with the acrylic opacity as well & or the background image (or a -.gif) size, its relative position, etc, if you do add one. - -Besides the colour customizations, you could try customizing the shell prompts. -The GIF image above, showcases my custom PowerShell prompt powered by -[oh-my-posh v3](https://ohmyposh.dev/). You could customize Neovim even further -to fit your needs. - -Regardless, customizing the PowerShell prompt & setting up Neovim is a project -on its own, hence they deserve a separate blog post of their own. - -## What’re You Waiting For, Start Customizing Yours Too? - -That said, I can’t recommend using Windows Terminal enough. Heck, I would even -go as far as asking you to switch to using Windows as your everyday development -platform. The team behind the development of Windows Terminal at Microsoft are -very proactive. And their contributions are only improving the product each day. -So if you’re on Window, & haven’t used Windows Terminal yet, then do it ASAP! - -You can download the preview version to test experimental features. They’re -available both from the -[Microsoft Store](https://www.microsoft.com/en-in/p/windows-terminal-preview/9n8g5rfz9xk3?activetab=pivot:overviewtab) -or from their [GitHub Releases](https://github.com/microsoft/terminal/releases) -page. Or the non-preview version which serves your purpose. - -Once downloaded edit the config file by following the steps mentioned above. And -you’re good to go! Do let me know how you’ve customized your Terminal. Drop me a -tweet & don’t forget to share the config file for others to take inspiration -from. - -Found this article helpful? Do let me know so I can personalize the next -work-in-progress article on customizing PowerShell the prompt. I’ll also share -more details on how I set it up along with Neovim on my Windows machine. So, if -you want to read that as well, then subscribe to my newsletter or follow me on -[Twitter](https://twitter.com/Jarmosan) whichever feels more convenient. diff --git a/_blog/using-github-actions-to-deploy-a-fastapi-project-to-heroku.md b/_blog/using-github-actions-to-deploy-a-fastapi-project-to-heroku.md deleted file mode 100644 index c3f091bb..00000000 --- a/_blog/using-github-actions-to-deploy-a-fastapi-project-to-heroku.md +++ /dev/null @@ -1,379 +0,0 @@ ---- -title: Using GitHub Actions to Deploy a FastAPI Project to Heroku -date: 2021-05-05 -slug: "using-github-actions-to-deploy-a-fastapi-project-to-heroku" -description: - Heroku makes deployment a piece of cake, but compromises on quality control & - best practices. So, this article shows how to use GitHub Actions in tandem - with Heroku while maintaining best practices. -coverImage: - url: https://ik.imagekit.io/jarmos/learn-to-deploy-fastapi-project-to-heroku.png?updatedAt=1685086095459 - alt: | - Learn to deploy a Python based FastAPI project to Heroku using GitHub - Actions and more! -summary: | - Heroku makes deployment a piece of cake, but compromises on quality control & - best practices. So, this article shows how to use GitHub Actions in tandem - with Heroku while maintaining best practices. ---- - -# Using GitHub Actions to Deploy a FastAPI Project to Heroku - -![Learn to deploy FastAPI project to Heroku using GitHub Actions](https://ik.imagekit.io/jarmos/learn-to-deploy-fastapi-project-to-heroku.png?updatedAt=1685086095459) - -**DISCLAIMER**: Heroku no longer supports their free tier (see this [FAQ][6] for -more clarification) and hence I cannpt guranteed the workflow suggested in this -article will work or not for your projects. - -All my opensource projects are hosted on GitHub repositories and this is no -different for my backend Python project either. And thanks to [GitHub -Actions][1], I don't have to worry about Continuous Integration (CI) needs -either while [Heroku][2] takes care of my Continuous Deployment (CD) needs. But, -the main issue with Heroku is they do not provide a straightforward way to -deploy my projects using GitHub Actions. Instead, I am obligated to download the -[Heroku CLI][3] for all my deployment requirements! - -I am not a fan of bloating my local development machine with unnecessary crap -which I may never use again (if I do not abandon a side project that is!). And -hence I needed a way to figure out how to make use of GitHub Actions to perform -all deployment tasks for me instead. - -The idea is to commit changes on my local machine and push the latest changes to -the remote repository on GitHub. Further I usually configure GitHub Actions to -run a test suite on the lastest changes along with other tasks like code linting -& formatting. Deployment to Heroku should **ONLY** happen if all the configured -tasks pass. This is pretty standard practice & nothing fancy here. - -The caveat though, Heroku uses `git` commands to push code to Heroku's remote. -So, it's pretty much like pushing code to a GitHub repository but, with no -robust CI/CD pipelines. I could configure Heroku to deploy when the tests & -other checks pass on GitHub but it is best to stick to standard practice & -configure everything under one roof. - -On top of it, invoking `git` commands on a remote environment bring along its -own set of challenges & hence does not sound like a good idea to stick with. -Hence this article will shed some insight on the techniques I used to circumvent -this tricky situation. We'll be using GitHub Actions to configure a CI/CD -pipeline and [FastAPI][4] to build our hypothetical REST API. - -So without further adieu, let's dive in & learn how to do it. - -## Things to Know Before Deployment - -Heroku's design reflects the need for simplicity & reducing complexity. Its -users are not expected to know in-depth CI/CD concepts & practices. But as long -as the users are well-acquainted with basic `git` commands, they are good to go -with sharing their backend projects with the world. In other words, deploying a -project to Heroku is as simple as pushing your code to a remote GitHub repo and -the rest is taken care of by Heroku's infrastructure! - -You would develop your project & then push your code to the Heroku remote. It -triggers a build process which sets up a web server on their remote environments -to serve your API to the end-users. - -There is a drawback to this process though, like Heroku's lack of a robust -enough CI/CD pipeline. And because of this drawback there is no way to keep a -check on any breaking changes or bugs which can be introduced during -development. As such, we need to use GitHub Actions for our CI/CD pipeline -instead. While discussing GitHub Actions is out-of-scope of this short article, -I recommend checking out the official documentations for more in-depth -explanation on this tool. - -That said, we will be integrating the [`heroku-deploy`][5] Action to deploy the -project once the rest of the other checks pass. And the said Action is a NodeJS -wrapper around basic `git` command invocations. These invocations are exactly -like what you would use with Heroku instead. - -Further, to keep things simple & to-the-point, our FastAPI app is a single file -with no more than 8 lines of code! Besides that, Heroku also requires some extra -files for the build process to work. And these files are also pushed to the -Heroku remote as well. They’re plain-text files with information for Heroku to -parse during the build phase. You’ll find more details about them later in the -article. Additionally, the `heroku-deploy` Action also requires an API key for -authentication so, ensure you've it along with the project's name. - -With all the prerequisites ready and taken care of, let's develop the project -now. - -## Putting Everything Together - -### Our Simple FastAPI Project - -In the previous section we setup some prerequisites for developing our simple -hypothetical FastAPI project and learned a bit about GitHub Actions as well as -Heroku. So, let's write our hypothetical FastAPI project now. - -The source code is written in the `main.py` file. And is configured with routes -to return a set of JSON responses when queried. The said routes are; a `/` (_or -root_) route & a `/healthcheck` route. The latter of which has some significance -in our CI/CD pipeline as you'll see. - -The root route returns a JSON response like this; `{"message": "Hello, World!"}` -when queried. And the `/healtchcheck` route acts as the last-line-of-defense for -the REST API. But it also returns a JSON response for better user -interpretation. So, if you invoke a `cURL` command to this route, you should get -back `{“message”: “Everything, OK!”}` response back. - -We will configure our CI/CD pipeline to query the health-check route to check if -its still up and running. Failing to do so which means returning a `400` (_or -similar_) response code will invoke a roll-back. Hence, our REST API in -production will always be up & running regardless of any breaking changes or -bugs creeping in. - -That said, here's what the source code for our REST API will look like: - -```python -from fastapi import FastAPI, status - -app = FastAPI() - -@app.get('/') -def hello_world(): - ''' - The root route which returns a JSON response. - - The JSON response is delivered as: - - { - 'message': 'Hello, World!' - } - ''' - return {'message': 'Hello, World!'} - -@app.get('/healthcheck', status_code=status.HTTP_200_OK) -def perform_healthcheck(): - ''' - Simple route for the GitHub Actions to perform healthchecks on. - - More info is available at: - https://github.com/akhileshns/heroku-deploy#health-check - - It basically sends a GET request to the route & hopes to get a "200" - response code. Failing to return a 200 response code just enables - the GitHub Actions to rollback to the last version the project was - found in a "working condition". It acts as a last line of defense in - case something goes south. - - Additionally, it also returns a JSON response in the form of: - - { - 'healtcheck': 'Everything OK!' - } - ''' - return {'healthcheck': 'Everything OK!'} -``` - -### Configuring the GitHub Actions Workflow - -With our REST API built, let's configure a CI/CD pipeline for it. The pipeline -is pretty standard & is nothing fancy. On every Push and/or PR events, it will -invoke a series of tests followed by code quality checks. And if everything -passes, the workflow will invoke the deployment process as well. - -But before discussing more about our pipeline, let's learn a bit about GitHub -Actions. - -Its easy to confuse GitHub Actions as "_yet another CI/CD tool_". But, it's not. -GitHub defines it as an automation tool for all software development needs one -can think of. And, there're many preconfigured Actions provided officially by -GitHub and/or the community as well. One such Action we'll use for our use case -is the `heroku-action` Action. - -We’ll trigger our workflow on every push event. But you can configure it to -trigger on other events as well. You can find more info on the list of events -that triggers a workflow it's official documentation. - -Workflows are further configured through YAML files. And, they're stored under -the `.github/workflows` directory which is also version controlled. GitHub will -parse these YAML files for instructions on how to set up the environment. - -And here's what our workflow looks like: - -```yml -# This is the .12hub/workflows/main.yml - -name: Deploy # Name of the workflow - -# Events that trigger a workflow: -# https://docs.github.com/en/actions/reference/events-that-trigger-workflows -on: push - -jobs: - # Check out the following article for more inspiration on setting up a - # standard CI/CD pipeline for most Python projects: - # https://jarmos.netlify.app/posts/a-standard-ci-cd-pipeline-for-python-projects/ - test: - # Include your test suite here. - lint: - # Lint & format your code over here. - deploy: - # If the test & lint jobs don't pass, - # the deploy job willn't even execute - needs: [test, lint] - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - name: Deploying to Heroku - # More details available at: - # https://github.com/akhileshns/heroku-deploy - uses: akhileshns/heroku-deploy@v3.12.12 - with: - heroku_api_key: ${{ secrets.HEROKU_API_KEY }} - heroku_app_name: "" - heroku_email: "" - healthcheck: "https://.herokuapp.com/healthcheck" - rollbackonhealthcheckfailed: true -``` - -GitHub Actions workflows have to adhere to a specific syntax. And explaining the -syntax is a bit out of context of this article. So, you should refer to the -official docs for info to learn about the syntax instead. - -That said, let's understand how we can customize our workflow. - -At the top of our `main.yml` file is the name of the workflow signified with the -`name` keyword. It's followed by the `on` keyword which instructs GitHub Actions -to trigger the workflow on `push` events. - -There're way more "_on event_" keywords available to trigger workflows. So, do -take a look at the documentation & configure your pipeline according to your -needs. - -Continuing on, the `jobs` section of the workflow is pretty much the heart of -the pipeline. This is where GitHub will find instructions on which Actions to -trigger & when. For our needs, we defined 3 jobs & they'll run in parallel -unless explicitly configured not to do so. - -The jobs are configured to run on the latest version of Ubuntu. And -additionally, the `deploy` job is dependent on the other previous jobs. So, -while the `test` & `linter` jobs run in parallel, the `deploy` job will wait -till they pass. And, if they don't, the `deploy` job willn’t even execute. - -This structure of the pipeline ensures bugs are never introduced to production -hence ensuring quality standards of the source code. And if you want to know how -to set up a code quality check for Python projects, I've an article for you. -Check out -"[A Standard & Complete CI/CD Pipeline for Most Python Projects](./a-standard-ci-cd-pipeline-for-python-projects)" -to know how to set it up. - -Diving deeper into the `deploy` job, let's figure out it's exact purpose. - -Like its predecessors, the `deploy` job also runs on the latest version of -Ubuntu. Then it instructs GitHub to parse the steps for execution. Accordingly, -GitHub "_copies_" the contents of the repo in the virtual environment. Following -which the `heroku-deploy` Action is executed. - -The `heroku-deploy` Action also requires a couple of variables to function. And -these variables are provided using the `with` keyword. The said Action accepts -more variables than what we're using. So, do check out it's repo for further -configuration. - -That said, we're using the `heroku_api_key`, `heroku_app_name`, `heroku_email`, -`healthcheck` & `rollbackonhealthcheckfailed` variables. Since, the first 3 -variables accept valuable user-info, they're passed in as GitHub Secrets. The -`healtcheck` variable accepts an URL to the `/healthcheck` route. And finally, -the `rollbackonhealthcheckfailed` accepts a boolean value. - -The last variable helps us as the last-line-of-defence. Anytime an event -triggers workflow & the project deploys, a health-check will be performed. It'll -look for a `200` response code & if it fails, the workflow will revert back to a -previous working version! - -Pretty nifty if you ask me! - -But then, why do we need such complexity in the first place? - -You see, in production environments it's common to have robust CI/CD pipeline(s) -in place. These systems test your commit pushes & PR for any potential -breakages. And not to forget coding best practices & quality standards as well. - -The health-check & roll back features of the pipeline are there as a -last-line-of-defence. Since, it is possible for bugs and/or breaking changes to -pass the preliminary checks. And it could break our REST API in production. -Imagine what it would be like for your project’s users (_and they paid for using -it_)! - -But fortunate for us, you needn't worry about such a scenario ever becoming a -reality. With the health-check & roll-back features, issues will turn back north -as quickly as it turned south. So, in other words, you get a good night's sleep -without any worry. - -### About the `Procfile`, `requirements.txt` & `runtime.txt` Files - -As mentioned earlier, Heroku requires certain plain-text files during the build -process. It parses these files to set up the web-server & the dependencies for -the project. So, for our REST API project which is a Python application, -following are the files Heroku needs to parse. - -- The `Procfile` (_without a file extension_) which Heroku parses to set up a - web-server on the remote machine. So, while using `uvicorn`, the contents of - the file would be: - `uvicorn main:app --host=0.0.0.0 --port=${PORT:-5000} --workers 4`. -- The `requirements.txt` lists project dependencies. And, Heroku will parse it - to install the project's dependencies. -- The `runtime.txt` file states the specific Python version to use for our REST - API. So, if it depends on Python v3.8.10, the contents of the file would be - `python-3.8.10`. **Do note the format** & it has to be exactly similar else it - won't work. - -With these files, your build environment on Heroku should be up & running in no -time. But let's double check the directory structure before committing things to -version-control. Here's what your directory structure should look like: - -```shell -example_project/ # Root directory for our project -├─ .github/ -│ ├─ workflows/ -│ │ ├─ main.yml # Our Workflow file -├─ main.py # Our FastAPI project -├─ Procfile # Instructions for Heroku to setup 1 -├─ requirements.txt # Lists the dependencies of our project -├─ runtime.txt # List the Python version our project depends on -``` - -Now, each time you push your changes to a GitHub repository, the push event will -trigger the workflow. And if the tests & code quality checks pass, the workflow -will try to deploy the project to Heroku. On top of it, if the health-check URL -returns a `200` response code back to our workflow, the REST API goes live! - -You can then navigate to the `https://.herokuapp.com` URL to check -out our REST API. If it’s working you should see a JSON response on the screen. - -With this setup, now you’ve the best of both worlds. Simple deployment with -Heroku and robust code quality checks with GitHub Actions! And the best part of -it all, there was no need to use the Heroku on your local machine! - -## Some Potential Roadblocks - -While the techniques & code detailed out in this article works, it's not robust -enough. There're a couple of fragile areas in the `heroku-deploy` Action which -need to be taken care of. If you peruse through the source code, you’ll find -it's invoking actual `git` commands using NodeJS. - -But, NodeJS wasn't meant to invoke shell commands so expect your CI/CD pipeline -to break if using this workflow. In other words, the Action used here is more of -a workaround than anything else! I will not recommending using the methods -suggested here for production usage. - -A better solution to this problem would be to wrap an API provided by Heroku to -create an Action. And fortunate for us, appears to be some light at the other -end of this tunnel. Heroku provides an official API to interact with their build -process & other services. They named it Heroku Platform API. They even shared an -article to programmatically release code to Heroku using their Platform API. - -So, a shout-out to JavaScript developers. If you're reading this & you're -experienced developing GitHub Actions workflows, the community needs you. But -till then, this article should be a good guideline for anyone wanting to deploy -their FastAPI app to Heroku. - -There are other alternatives though. Google Serverless Infrastructure is one & -other provided by Microsoft Azure and/or Amazon Web Service. Until then cheers & -happy developing! 🥂 - -[1]: https://github.com/features/actions -[2]: https://www.heroku.com -[3]: https://devcenter.heroku.com/articles/heroku-cli -[4]: http://fastapi.tiangolo.com/ -[5]: https://github.com/akhileshns/heroku-deploy -[6]: https://help.heroku.com/RSBRUH58/removal-of-heroku-free-product-plans-faq diff --git a/_blog/vim-vs-neovim-a-comprehensive-analysis.md b/_blog/vim-vs-neovim-a-comprehensive-analysis.md deleted file mode 100644 index 05e3c99b..00000000 --- a/_blog/vim-vs-neovim-a-comprehensive-analysis.md +++ /dev/null @@ -1,309 +0,0 @@ ---- -title: Vim or Neovim? Here's Why You Should Use the Latter -date: 2021-07-15 -slug: vim-vs-neovim-a-comprehensive-analysis -description: - Confused between Vim and/or Neovim? Here are my justifications to convince you - to use Neovim instead! -coverImage: - url: https://ik.imagekit.io/jarmos/vim-vs-neovim.png?updatedAt=1685086095409 - alt: | - A comprehensive analysis between Vim and Neovim intended for interested - users who are confused about which to use. -summary: | - Choose Neovim over Vim for faster performance, cleaner code, embedded Lua - scripting, standard library, and sensible default settings. Discover the - advantages of Neovim in everyday use cases. Read more. ---- - -# Vim or Neovim? Here's Why You Should Use the Latter - -![Vim vs Neovim: A Comprehensive Analysis](https://ik.imagekit.io/jarmos/vim-vs-neovim.png?updatedAt=1685086095409) - -If you ever heard of [Vim](https://www.vim.org) before, you would know all about -its forks that have popped up in recent years! There’s -[Neovim](https://neovim.io) which is one of the most promising ones among -countless others. And as is obvious, choosing the one right one for yourself can -be a difficult task (been there & done that myself)! - -So to help you decide, this article will shed light on some of the reasons to -choose Neovim over Vim. To be more specific, we’ll look into every day use cases -while comparing the two. Analysing everyday use cases is more relevant while -comparing consumer products anyway. - -But before we dive into the real deal of the article, as usual a little bit of a -history lesson first. - -Vim itself started out as an improved clone of the now antiquated -[Vi](https://www.wikipedia.com/Vi) by Bram Moolenaar way back in the early 90s. -Moolenaar himself overlooked the development & course of actions for Vim. And -over the decades, the Vim source code has started to become archaic & difficult -to maintain. Its bloated, some of the code is unoptimized & its current set of -features (like VimScript) hasn't aged well either. - -On the contrary, Neovim was rebuilt from scratch! Redundant & decades old code -was weeded out while the maintainers prioritised having as much parity to -upstream Vim features as much as possible! And to top it of, the maintainers -added more icing to the cherry on the cake with the embedded Lua scripting -environment! There are more features which clearly makes Neovim stand out over -its predecessor and we will look at them in the rest of the article! - -## Why is Vim More Popular Than Neovim - -As mentioned earlier Vim is pretty old, as such it’s source code is archaic & -difficult to maintain. This was a primary reason for the current dev team for -Neovim to fork Vim & set off on a journey of their own. Unlike some of the -rumours floating around Neovim was not forked because “_Bram is a dictator_” & -what not. Neither was Neovim created to give more power to the community. But -the latter is definitely an unintentional outcome of the fork in a good way. - -Since, Neovim was rebuilt from the ground-up, it opened up doors to; - -1. Adding useful features like - [Language-Server Protocol](https://microsoft.github.io/language-server-protocol/) - (LSP), an embedded Lua (and LuaJIT) scripting environment & so on, more - easily. -2. Cleaner & optimized source code for easier maintainability & reduced load - times. -3. Straight-up better plugin development environment. -4. Extending core Vim capabilities through improved plugins if necessary. - -And those were only a few good outcomes of forking the Vim source code. But in -reality, the list is never-ending & chances are, as Vim matures over time, -there’ll be another reason to extend the list. - -Some other equally prominent features include: - -1. The underlying 6 for plugin devs to use for building pretty much anything. -2. The optional embedded 7 5.1 en12ronment is also a reason why 11 is so loved - by the community. If a user wishes to do, 11 can be configured with 7 rather - than 10Script. -3. An inbuilt standard library which includes useful functions like - `CheckHealth` and/or the global `10` Object. These are used to check if a - plugin has been set up correctly. Or to configure global 11 settings. -4. Comes pre-packaged with sensible default settings making the "_10 - experience_" more pleasant. - -And if it’s not ob12ous already, 11 is already miles ahead when it comes to -useful features. For example, choosing to configure 11 with either 12mScript -or 7. Or heck if you desire, you can even use both side-by-side, the choice is -all yours! - -With 10, you would be stuck with the dreaded 12mScript! While 5 capabilities are -supported through plugins, the experience isn't as smooth & out-of-the-box like -it's cousin. - -With that said, let’s take a more detailed approach to some of the most used -features mentioned above. - -## Neovim is Noticeably FASTER Than Vim - -As mentioned earlier, one of the major reasons to fork 10 was it’s archaic -source code. Since 10 has been in existence for close to three decades it's -source code is pretty bloated by now. It was hard to maintain & was much easier -to simply rebuild from scratch, so the devs did what was necessary. Owing to -that decision, the source code was cleaned & optimized. This is obvious if you -notice how faster Neovim is more performant than its predecessor. For context, -in my computer with old hardware (Intel Pentium G3220 and 4GB RAM) and 40+ -plugins, Neovim loads up in about ~40ms! - -Rebuilding Neovim also opened up many doors towards developing handy features. -One & the most killer feature of the editor is the embedded Lua scripting -environment. The devs also took other performance optimization course of action -as well. One of them included making Neovim run in an event loop. So, you can -finally bid goodbye to plugins that would hang earlier! - -Besides, the devs have also ensured backwards compatibility with VimScript. So, -if you’re a long-term Vim user who wants to try out Neovim, don’t fret, you will -be fine. You can configure Neovim to read your older `.vimrc` just fine albeit -with some trivial hacks here & there. - -But what if you’re committed to using Neovim & is ready to take the dive? Then I -would suggest migrating your current VimScript configurations to Lua code -instead. Mark my words, you’ll notice an increased performance boost at least in -the startup times for sure. To give an idea of what sorts of performance boost -I’m talking about here, I'll share my experience, my Neovim load times decreased -from 500+ ms to 237 ms. That’s a roughly ~50% improvement by simply migrating -from VimScript to Lua! - -One can only imagine how much faster it can perform if the config loading -process was optimized even further. I have achieve sub 50ms load times in my -latest configurations but thats a story for another day. - -On the flip side though, configuring through Lua is an optional feature. So, you -needn't feel obligated to "_learn yet another language_". More on it in the next -section of the article. - -## Option to Ditch VimScript & Embrace Lua - -[One of the goals](https://neovim.io/charter) of the Neovim development team is -to “_develop a first-class Lua scripting alternative to VimScript_”. Staying -true to their words, the devs haven’t enforced ditching VimScript in favour of -Lua till now. And I doubt any of us would live to see that happen in our -lifetime! - -So, if you want to continue using your previous Vim configs, you needn’t fret at -all. But what if you definitely need Lua code, for example say configuring the -builtin features like LSP and/or Tree-Sitter based syntax highlightng? For -situations like that, Vim `heredoc` will be at your rescue. You can embed Lua -code within VimScript with a syntax which looks something like this; - -```lua -lua << EOF -require'5config'.pyright.setup{ - cmd = { "pyright-langserver", "--stdio" } - filetypes = { "python" } - root_dir = function(filename) - return util.root_pattern(unpack(root_files))(filename) or util.path.dirname(filename) - end, - settings = { - python = { - analysis = { - autoSearchPaths = true, - diagnosticMode = "workspace", - useLibraryCodeForTypes = true - } - } - } -} -EOF -``` - -And you’re good to go out on your day without worrying it would break something -from your previous Vim configurations. Vim would still know how to parse those -code & make sense of it. - -Although, a bit of a personal opinion here, try not to use VimScript if you can. -Coding in Lua is a more pleasant experience and even if you had to learn it, the -language has many real-life applications outside of the Neovim environment. So, -it’s not like you would be wasting your time learning a redundant programming -language. If you do decide to start configuring Neovim with Lua, do give this -“[Guide to Using Neovim with Lua](https://github.com/nanotee/nvim-lua-guide)” a -thorough read. - -That said, Neovim’s embedded Lua environment’s usefulness takes proper shape -through its inbuilt standard library & API. If you’re either a plugin developer -or a regular Vim user, the standard library can be useful in many ways. It -packages many useful functions & commands to use for your day-to-day development -needs. - -So, in the next section, we'll take a more detailed look into it. - -## The Inbuilt Standard Library & the API is 💖 - -Second on Neovim's list of development goals is to create a suitable environment -of plugin authors. That way, the plugin authors could extend the core features -of Neovim with much ease. And the core team of devs achieved this feat by -creating the "_standard library_" accessible through the `vim.api` layer (see -`:h vim.api` for more information on this). - -The underlying API layer exposes useful functions to the user for programmatic -control over Neovim. These functions are exposed through a global namespace -called `vim`. As such, let's say we want to configure Neovim to display the -number column. Then it's as easy as writing `vim.opt.number = true` in an -`init.lua` (_or `init.vim` with some caveats_) file and you're good to go! - -Granted, a first glance on the global `vim` namespace might look confusing but -stay with me & I’ll help you make sense of it. The `vim` namespace exposes a -couple functions for everyday use. Most notable ones include the `vim.api` -function. There are a couple more of them & explaining all them is out-of-scope -for this article so its recommended you check the documentations for this as -well. - -To stay relevant to the context of this article, following are some of the most -useful functions exposed by the `vim.api` namespace: - -1. Functions for setting options like `vim.opt.some_option = value`. See the - documentations at `:h vim.opt` for more information in this context. - -2. The “_vim experience_” is incomplete without customizing personalized key - bindings. And , there’s a pretty nifty function for doing exactly that as - well! The `vim.keymap.set()` function takes four parameters. The “_mode_”, - your custom key binds, the expression/default key binds & options (_like - “silent”_) to pass to it. See `:h vim.keymap.set()` to check the details - about this functionality. - -3. Another function I found useful on a day-to-day basis is the `vim.cmd()` - function which allows me to run arbitrary Vim commands in Lua! It comes handy - when I need to invoke some Vim command but a native Lua API is not available - yet. - -4. The `vim.api.nvim_create_autocmd()` and the `vim.api.nvim_create_augroup()` - are another two Lua functions which are helpful to create autocommands using - a sane and readable syntax. - -This blog post will barely scratch the surface of what is possible using the -native Lua API. So it is strongly recommended that you check out the -documentations and/or hang out in the various online Neovim communities. - -## Sensible Default Settings for a Better First-Time Experience - -If programmatic configurations of your editor does not sound interesting to you. -Or perhaps, you tried out Neovim some time earlier & found it difficult to use? -Or maybe you didn’t want to spend a whole weekend trying to configure Neovim for -your specific needs? Well for you, my friend, there's good news. Reducing the -barrier-to-entry for first-time Vim users topped the development goals for the -Neovim devs. - -So, what does it mean for the uninitiated? - -It means, Neovim, out-of-the-box looks & feels good enough. It doesn’t need much -of any configuration & it’s usable for all your software development needs. -Granted this feature isn't as interesting as Neovim’s other “_killer features_” -like the inbuilt Lua environment or LSP/Tree-Sitter support. But it’s still an -important feature worth noting. - -When you want an editor that serves your purpose, helps you complete every-day -tasks, you wouldn’t want to spend a day (or two) configuring it, wouldn’t you? -And if you’re someone who fall into this category of people, check out the -following Neovim configuration frameworks: - -1. [LazyVim](https://github.com/LazyVim/LazyVim) -2. [Neovimulus](https://github.com/Jarmos-san/neovimulus) -3. [LunarVim](https://github.com/LunarVim/LunarVim) -4. [NvChad](https://github.com/NvChad/NvChad) -5. [AstroNvim](https://github.com/AstroNvim/AstroNvim) - -These frameworks comes with pre-configured features and you need not tinker -around them to get some bare minimum software development needs over your -weekends. And who knows, you might end up enjoying working with Neovim for the -rest of your life thanks to these frameworks?! - -## Final Words & Resources for Your Journey into Neovim-land - -And now, before I answer the question, “_Vim or Neovim: Which one to use?_”. -Here's a short summary of everything we talked about earlier: - -1. Why does Neovim exist in the first place? And how it affected the community. - -2. We now know, Neovim’s source code was cleaned, optimized & rewritten from - scratch. Hence, it’s noticeably faster than it’s older cousin Vim. - -3. Allowing Neovim to be rewritten opened up opportunities to include many - useful features like embedded Lua scripting environment, asynchronous - execution, LSP support, etc. - -4. Inclusion of a “_standard library_” which augments the optional embedded Lua - scripting environment for configurability. Sensible default configurations to - ease a first-time Neovim user’s experience. - -...and many more! The list is never-ending & what I listed up there is just the -cherry on top of the cake. These features are also what makes 11 stand out when -compared to 10. But, it shouldn’t come as a surprise if 12m supports most if not -all of 11’s features one day as well. - -That said, you should use Neovim for reasons mentioned below: - -1. You need a terminal-based editor with stable cross-platform availability. - -2. You’ve been a long-time Vim user & find certain features of the editor like - VimScript annoying & frustrating. - -3. You need modern IDE-like features like LSP out-of-the-box and/or if you need - some default configurations available without further tinkering. - -4. And finally, if you need a minimalist text editor which is modern, Neovim - should be your go-to option. - -Do you believe those were some valid reasons to try out Neovim, let me know what -you think! diff --git a/mdx-components.tsx b/mdx-components.tsx new file mode 100644 index 00000000..0c3792e9 --- /dev/null +++ b/mdx-components.tsx @@ -0,0 +1,43 @@ +/** + * The default MDX support in general is very flaky in the current version of + * Next.js. There are a few errors raised by the TypeScript language server and + * TailwindCSS transpilation is not full-proof either! It's because of the later + * that instead of using TailwindCSS utility classes I'm directly issuing inline + * style props to the custom components! + + * The custom style props are based on values directly copied from the + * TailwindCSS documentations on respective classes. + **/ +import Image from "next/image"; + +import type { MDXComponents } from "mdx/types"; + +export function useMDXComponents(components: MDXComponents): MDXComponents { + return { + h1: ({ children }) => ( +

+ {children} +

+ ), + img: (props) => ( + + ), + p: ({ children }) => ( +

{children}

+ ), + ...components, + }; +} diff --git a/next.config.js b/next.config.mjs similarity index 72% rename from next.config.js rename to next.config.mjs index 840d11f0..a486dad8 100644 --- a/next.config.js +++ b/next.config.mjs @@ -1,5 +1,4 @@ -/** @type {import('next').NextConfig} */ -const path = require("path"); +import createMDX from "@next/mdx"; const securityHeaders = [ { @@ -16,10 +15,12 @@ const securityHeaders = [ }, ]; +/** @type {import('next').NextConfig} */ const nextConfig = { images: { - domains: ["flowbite.com"], + domains: ["picsum.photos", "ik.imagekit.io"], }, + pageExtensions: ["js", "jsx", "mdx", "ts", "tsx"], swcMinify: true, eslint: { ignoreDuringBuilds: true, @@ -38,4 +39,11 @@ const nextConfig = { }, }; -module.exports = nextConfig; +const withMDX = createMDX({ + options: { + remarkPlugins: [], + rehypePlugins: [], + }, +}); + +export default withMDX(nextConfig); diff --git a/package-lock.json b/package-lock.json index 58198271..bf57505c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,22 +6,40 @@ "": { "hasInstallScript": true, "dependencies": { - "gray-matter": "^4.0.3", + "@mdx-js/loader": "^3.0.0", + "@mdx-js/react": "^3.0.0", + "@next/mdx": "^14.0.1", + "@types/mdx": "^2.0.9", "next": "~13.5.6", "react": "18.2.0", "react-dom": "18.2.0", +<<<<<<< HEAD "react-icons": "^4.12.0", "react-markdown": "^9.0.1", "react-syntax-highlighter": "^15.5.0", "remark-gfm": "^4.0.0" +======= + "react-icons": "^4.11.0" +>>>>>>> 5bf2ac47e95e3d0baa4af333a963409a852c4bac }, "devDependencies": { +<<<<<<< HEAD "@commitlint/types": "^18.4.0", "@tailwindcss/typography": "^0.5.10", "@trivago/prettier-plugin-sort-imports": "^4.3.0", +<<<<<<< HEAD "@types/node": "^20.9.2", "@types/react": "^18.2.37", "@types/react-dom": "^18.2.15", +======= +======= + "@commitlint/types": "^18.1.0", + "@trivago/prettier-plugin-sort-imports": "^4.2.1", +>>>>>>> chore(deps): remove some redundant dependencies + "@types/node": "^20.8.10", + "@types/react": "^18.2.35", + "@types/react-dom": "^18.2.14", +>>>>>>> 5bf2ac47e95e3d0baa4af333a963409a852c4bac "@types/react-syntax-highlighter": "^15.5.10", "autoprefixer": "^10.4.16", "eslint": "^8.53.0", @@ -499,6 +517,7 @@ "version": "7.21.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "dev": true, "dependencies": { "regenerator-runtime": "^0.13.11" }, @@ -817,7 +836,6 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -831,7 +849,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -840,22 +857,29 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, "engines": { "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.18", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "3.1.0", "@jridgewell/sourcemap-codec": "1.4.14" @@ -864,8 +888,97 @@ "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "node_modules/@mdx-js/loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@mdx-js/loader/-/loader-3.0.0.tgz", + "integrity": "sha512-9kLv83YtgxpoXVYHaf0ygx1dmhCffo0MQCv6KtNG67jy/JlBK/2Q0dSWfuuyStP3jnZKABHfbjv8zsiT1buu6A==", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "webpack": ">=5" + } + }, + "node_modules/@mdx-js/loader/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@mdx-js/mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.0.0.tgz", + "integrity": "sha512-Icm0TBKBLYqroYbNW3BPnzMGn+7mwpQOK310aZ7+fkCtiU3aqv2cdcX+nd0Ydo3wI5Rx8bX2Z2QmGb/XcAClCw==", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-to-js": "^2.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-estree": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "periscopic": "^3.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/@types/hast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.2.tgz", + "integrity": "sha512-B5hZHgHsXvfCoO3xgNJvBnX7N8p86TqQeGKXcokW4XXi+qY4vxxPSFYofytvVmpFxzPv7oxDQzjg5Un5m2/xiw==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@mdx-js/mdx/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@mdx-js/react": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.0.tgz", + "integrity": "sha512-nDctevR9KyYFyV+m+/+S4cpzCWHqj+iHDHq3QrsWezcC+B17uZdIWgCguESUkwFhM3n/56KxWVE3V6EokrmONQ==", + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } }, "node_modules/@next/env": { "version": "13.5.6", @@ -881,6 +994,34 @@ "glob": "7.1.7" } }, + "node_modules/@next/mdx": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/mdx/-/mdx-14.0.1.tgz", + "integrity": "sha512-9hikFxx1XQOReOp5SBO1o3fGs1Z1GT1flKm1wrjFOwOTNI0M4x9CuQsUx5KJwvbt0FejCS5bsuNGXqxHchcMCQ==", + "dependencies": { + "source-map": "^0.7.0" + }, + "peerDependencies": { + "@mdx-js/loader": ">=0.15.0", + "@mdx-js/react": ">=0.15.0" + }, + "peerDependenciesMeta": { + "@mdx-js/loader": { + "optional": true + }, + "@mdx-js/react": { + "optional": true + } + } + }, + "node_modules/@next/mdx/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, "node_modules/@next/swc-darwin-arm64": { "version": "13.5.6", "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.6.tgz", @@ -1580,34 +1721,6 @@ "node": ">=10" } }, - "node_modules/@tailwindcss/typography": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.10.tgz", - "integrity": "sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw==", - "dev": true, - "dependencies": { - "lodash.castarray": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.merge": "^4.6.2", - "postcss-selector-parser": "6.0.10" - }, - "peerDependencies": { - "tailwindcss": ">=3.0.0 || insiders" - } - }, - "node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", - "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", @@ -1637,6 +1750,14 @@ } } }, + "node_modules/@types/acorn": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", + "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/@types/cacheable-request": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", @@ -1657,18 +1778,37 @@ "@types/ms": "*" } }, + "node_modules/@types/eslint": { + "version": "8.44.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.6.tgz", + "integrity": "sha512-P6bY56TVmX8y9J87jHNgQh43h6VVU+6H7oN7hgvivV81K2XY8qJZ5vqPy/HdUoVIelii2kChYVzQanlswPWVFw==", + "peer": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.6.tgz", + "integrity": "sha512-zfM4ipmxVKWdxtDaJ3MP3pBurDXOCoyjvlpE3u6Qzrmw4BPbfm4/ambIeTk/r/J0iq/+2/xp0Fmt+gFvXJY2PQ==", + "peer": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" }, - "node_modules/@types/hast": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", - "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", + "node_modules/@types/estree-jsx": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.2.tgz", + "integrity": "sha512-GNBWlGBMjiiiL5TSkvPtOteuXsiVitw5MYGY1UYlrAq0SKyczsls6sCD7TZ8fsjRsvCVxml7EbyjJezPb3DrSA==", "dependencies": { - "@types/unist": "*" + "@types/estree": "*" } }, "node_modules/@types/http-cache-semantics": { @@ -1677,6 +1817,12 @@ "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", "dev": true }, + "node_modules/@types/json-schema": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", + "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", + "peer": true + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -1700,16 +1846,27 @@ "@types/unist": "*" } }, + "node_modules/@types/mdx": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.9.tgz", + "integrity": "sha512-OKMdj17y8Cs+k1r0XFyp59ChSOwf8ODGtMQ4mnpfz5eFDk1aO41yN3pSKGuvVzmWAkFp37seubY1tzOVpwfWwg==" + }, "node_modules/@types/ms": { "version": "0.7.32", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.32.tgz", "integrity": "sha512-xPSg0jm4mqgEkNhowKgZFBNtwoEwF6gJ4Dhww+GFpm3IgtNseHQZ5IqdNwnquZEoANxyDAKDRAdVo4Z72VvD/g==" }, "node_modules/@types/node": { +<<<<<<< HEAD "version": "20.9.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.2.tgz", "integrity": "sha512-WHZXKFCEyIUJzAwh3NyyTHYSR35SevJ6mZ1nWwJafKtiQbqRTIKSRcw3Ma3acqgsent3RRDqeVwpHntMk+9irg==", "dev": true, +======= + "version": "20.8.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz", + "integrity": "sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==", +>>>>>>> 5bf2ac47e95e3d0baa4af333a963409a852c4bac "dependencies": { "undici-types": "~5.26.4" } @@ -2387,6 +2544,164 @@ "integrity": "sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw==", "dev": true }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "peer": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "peer": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "peer": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "peer": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "peer": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "peer": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "peer": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "peer": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "peer": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "peer": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "peer": true + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -2412,11 +2727,19 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "peer": true, + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -2437,7 +2760,6 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2449,6 +2771,15 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peer": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, "node_modules/ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", @@ -2716,6 +3047,14 @@ "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", "dev": true }, + "node_modules/astring": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.8.6.tgz", + "integrity": "sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==", + "bin": { + "astring": "bin/astring" + } + }, "node_modules/asynciterator.prototype": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", @@ -2969,7 +3308,6 @@ "version": "4.21.10", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -3030,6 +3368,12 @@ "node": "*" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "peer": true + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -3195,19 +3539,10 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -3326,6 +3661,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "peer": true, + "engines": { + "node": ">=6.0" + } + }, "node_modules/chromium-bidi": { "version": "0.4.33", "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.33.tgz", @@ -3567,6 +3911,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -3603,6 +3956,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "peer": true + }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -4177,8 +4536,7 @@ "node_modules/electron-to-chromium": { "version": "1.4.477", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.477.tgz", - "integrity": "sha512-shUVy6Eawp33dFBFIoYbIwLHrX0IZ857AlH9ug2o4rvbWmpaCUdBpQ5Zw39HRrfzAFm4APJE9V+E2A/WB0YqJw==", - "dev": true + "integrity": "sha512-shUVy6Eawp33dFBFIoYbIwLHrX0IZ857AlH9ug2o4rvbWmpaCUdBpQ5Zw39HRrfzAFm4APJE9V+E2A/WB0YqJw==" }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -4196,10 +4554,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", - "dev": true, + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -4338,6 +4695,12 @@ "safe-array-concat": "^1.0.1" } }, + "node_modules/es-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.1.tgz", + "integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==", + "peer": true + }, "node_modules/es-set-tostringtag": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", @@ -4382,7 +4745,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, "engines": { "node": ">=6" } @@ -4948,6 +5310,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -4972,7 +5335,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -4984,36 +5346,114 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "engines": { "node": ">=4.0" } }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", "dependencies": { "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/execa": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", - "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", - "dev": true, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", "dependencies": { - "cross-spawn": "^7.0.3", + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "peer": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", "get-stream": "^6.0.1", "human-signals": "^4.3.0", "is-stream": "^3.0.0", @@ -5035,17 +5475,6 @@ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, - "node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", @@ -5084,8 +5513,7 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-fifo": { "version": "1.3.2", @@ -5124,8 +5552,7 @@ "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -5142,18 +5569,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fault": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", - "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", - "dependencies": { - "format": "^0.2.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -5265,14 +5680,6 @@ "node": ">= 6" } }, - "node_modules/format": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", - "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", - "engines": { - "node": ">=0.4.x" - } - }, "node_modules/fraction.js": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.6.tgz", @@ -5632,40 +6039,6 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, - "node_modules/gray-matter": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", - "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", - "dependencies": { - "js-yaml": "^3.13.1", - "kind-of": "^6.0.2", - "section-matter": "^1.0.0", - "strip-bom-string": "^1.0.0" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/gray-matter/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/gray-matter/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/h3": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/h3/-/h3-1.8.2.tgz", @@ -5763,15 +6136,41 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hast-util-parse-selector": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", - "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "node_modules/hast-util-to-estree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.0.tgz", + "integrity": "sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-to-estree/node_modules/@types/hast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.2.tgz", + "integrity": "sha512-B5hZHgHsXvfCoO3xgNJvBnX7N8p86TqQeGKXcokW4XXi+qY4vxxPSFYofytvVmpFxzPv7oxDQzjg5Un5m2/xiw==", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/hast-util-to-jsx-runtime": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.2.0.tgz", @@ -5820,75 +6219,12 @@ "@types/unist": "*" } }, - "node_modules/hastscript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", - "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", - "dependencies": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^1.0.0", - "hast-util-parse-selector": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hastscript/node_modules/comma-separated-tokens": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", - "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/hastscript/node_modules/property-information": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", - "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", - "dependencies": { - "xtend": "^4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/hastscript/node_modules/space-separated-tokens": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", - "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/highlight.js": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", - "engines": { - "node": "*" - } - }, "node_modules/hookable": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", "dev": true }, - "node_modules/html-url-attributes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.0.tgz", - "integrity": "sha512-/sXbVCWayk6GDVg3ctOX6nxaVj7So40FcFAnWlWGNAB1LpYKcV5Cd10APjPjW80O7zYW2MsjBV4zZ7IZO5fVow==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/htmlparser2": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", @@ -6123,28 +6459,6 @@ "url": "https://github.com/sponsors/brc-dd" } }, - "node_modules/is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "dependencies": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -6276,15 +6590,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -6300,14 +6605,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -6374,15 +6671,6 @@ "node": ">=4" } }, - "node_modules/is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/is-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", @@ -6457,6 +6745,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -6634,6 +6930,44 @@ "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", "dev": true }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "peer": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/jiti": { "version": "1.21.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", @@ -6697,14 +7031,12 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, "peer": true }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -6764,14 +7096,6 @@ "json-buffer": "3.0.1" } }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -7129,6 +7453,15 @@ "listhen": "bin/listhen.mjs" } }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "peer": true, + "engines": { + "node": ">=6.11.5" + } + }, "node_modules/local-pkg": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", @@ -7168,18 +7501,6 @@ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "dev": true }, - "node_modules/lodash.castarray": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", - "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", - "dev": true - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -7221,19 +7542,6 @@ "node": ">=8" } }, - "node_modules/lowlight": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", - "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", - "dependencies": { - "fault": "^1.0.0", - "highlight.js": "~10.7.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/lru_map": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", @@ -7288,13 +7596,15 @@ "semver": "bin/semver.js" } }, - "node_modules/markdown-table": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", - "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "engines": { + "node": ">=16" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/marky": { @@ -7303,32 +7613,6 @@ "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==", "dev": true }, - "node_modules/mdast-util-find-and-replace": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz", - "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "escape-string-regexp": "^5.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/mdast-util-from-markdown": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz", @@ -7352,17 +7636,15 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-gfm": { + "node_modules/mdast-util-mdx": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", - "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", "dependencies": { "mdast-util-from-markdown": "^2.0.0", - "mdast-util-gfm-autolink-literal": "^2.0.0", - "mdast-util-gfm-footnote": "^2.0.0", - "mdast-util-gfm-strikethrough": "^2.0.0", - "mdast-util-gfm-table": "^2.0.0", - "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" }, "funding": { @@ -7370,73 +7652,152 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-gfm-autolink-literal": { + "node_modules/mdast-util-mdx-expression": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz", - "integrity": "sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz", + "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==", "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", - "ccount": "^2.0.0", "devlop": "^1.0.0", - "mdast-util-find-and-replace": "^3.0.0", - "micromark-util-character": "^2.0.0" + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-gfm-footnote": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", - "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", + "node_modules/mdast-util-mdx-expression/node_modules/@types/hast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.2.tgz", + "integrity": "sha512-B5hZHgHsXvfCoO3xgNJvBnX7N8p86TqQeGKXcokW4XXi+qY4vxxPSFYofytvVmpFxzPv7oxDQzjg5Un5m2/xiw==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.0.0.tgz", + "integrity": "sha512-XZuPPzQNBPAlaqsTTgRrcJnyFbSOBovSadFgbFu8SnuNgm+6Bdx1K+IWoitsmj6Lq6MNtI+ytOqwN70n//NaBA==", "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0" + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-remove-position": "^5.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "node_modules/mdast-util-mdx-jsx/node_modules/@types/hast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.2.tgz", + "integrity": "sha512-B5hZHgHsXvfCoO3xgNJvBnX7N8p86TqQeGKXcokW4XXi+qY4vxxPSFYofytvVmpFxzPv7oxDQzjg5Un5m2/xiw==", "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" + "@types/unist": "*" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/mdast-util-gfm-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", - "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "node_modules/mdast-util-mdx-jsx/node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/parse-entities": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", + "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "markdown-table": "^3.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" + "@types/unist": "^2.0.0", + "character-entities": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/mdast-util-gfm-task-list-item": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", - "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "node_modules/mdast-util-mdx-jsx/node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.9.tgz", + "integrity": "sha512-zC0iXxAv1C1ERURduJueYzkzZ2zaGyc+P2c95hgkikHPr3z8EdUZOlgEQ5X0DRmwDZn+hekycQnoeiiRVrmilQ==" + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", @@ -7447,6 +7808,14 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdast-util-mdxjs-esm/node_modules/@types/hast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.2.tgz", + "integrity": "sha512-B5hZHgHsXvfCoO3xgNJvBnX7N8p86TqQeGKXcokW4XXi+qY4vxxPSFYofytvVmpFxzPv7oxDQzjg5Un5m2/xiw==", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/mdast-util-phrasing": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.0.0.tgz", @@ -7521,8 +7890,7 @@ "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, "node_modules/merge2": { "version": "1.4.1", @@ -7606,85 +7974,57 @@ "micromark-util-types": "^2.0.0" } }, - "node_modules/micromark-extension-gfm": { + "node_modules/micromark-extension-mdx-expression": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", - "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", - "dependencies": { - "micromark-extension-gfm-autolink-literal": "^2.0.0", - "micromark-extension-gfm-footnote": "^2.0.0", - "micromark-extension-gfm-strikethrough": "^2.0.0", - "micromark-extension-gfm-table": "^2.0.0", - "micromark-extension-gfm-tagfilter": "^2.0.0", - "micromark-extension-gfm-task-list-item": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-autolink-literal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.0.0.tgz", - "integrity": "sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-footnote": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.0.0.tgz", - "integrity": "sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", + "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { + "@types/estree": "^1.0.0", "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", + "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-extension-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==", + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.0.tgz", + "integrity": "sha512-uvhhss8OGuzR4/N17L1JwvmJIpPhAd8oByMawEKx6NVdBCbesjH4t+vjEp3ZXft9DwvlKSD07fCeI44/N0Vf2w==", "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-extension-gfm-table": { + "node_modules/micromark-extension-mdx-md": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz", - "integrity": "sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" }, "funding": { @@ -7692,11 +8032,18 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-extension-gfm-tagfilter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", - "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", - "dependencies": { + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", "micromark-util-types": "^2.0.0" }, "funding": { @@ -7704,16 +8051,20 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-extension-gfm-task-list-item": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.0.1.tgz", - "integrity": "sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==", + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", "dependencies": { + "@types/estree": "^1.0.0", "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", + "micromark-core-commonmark": "^2.0.0", "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" }, "funding": { "type": "opencollective", @@ -7761,6 +8112,31 @@ "micromark-util-types": "^2.0.0" } }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.1.tgz", + "integrity": "sha512-F0ccWIUHRLRrYp5TC9ZYXmZo+p2AM13ggbsW4T0b5CRKP8KHVRB8t4pwtBgTxtjRmwrK0Irwm7vs2JOZabHZfg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, "node_modules/micromark-factory-space": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", @@ -7952,6 +8328,31 @@ } ] }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", + "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, "node_modules/micromark-util-html-tag-name": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", @@ -8103,7 +8504,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -8112,7 +8512,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -8252,6 +8651,12 @@ "node": ">= 0.6" } }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "peer": true + }, "node_modules/netmask": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", @@ -8350,8 +8755,7 @@ "node_modules/node-releases": { "version": "2.0.13", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", - "dev": true + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -8804,32 +9208,6 @@ "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", "dev": true }, - "node_modules/parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", - "dependencies": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/parse-entities/node_modules/character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -8928,6 +9306,16 @@ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, + "node_modules/periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -9245,14 +9633,6 @@ } } }, - "node_modules/prismjs": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", - "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", - "engines": { - "node": ">=6" - } - }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -9461,6 +9841,15 @@ "integrity": "sha512-pNsHDxbGORSvuSScqNJ+3Km6QAVqk8CfsCBIEoDgpqLrkD2f3QM4I7d1ozJJ172OmIcoUcerZaNWqtLkRXTV3A==", "dev": true }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "peer": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -9498,6 +9887,7 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, +<<<<<<< HEAD "node_modules/react-markdown": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.0.1.tgz", @@ -9546,6 +9936,8 @@ "react": ">= 0.14.0" } }, +======= +>>>>>>> 5bf2ac47e95e3d0baa4af333a963409a852c4bac "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -9601,32 +9993,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/refractor": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", - "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", - "dependencies": { - "hastscript": "^6.0.0", - "parse-entities": "^2.0.0", - "prismjs": "~1.27.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/prismjs": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", - "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", - "engines": { - "node": ">=6" - } - }, "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true }, "node_modules/regexp.prototype.flags": { "version": "1.5.1", @@ -9654,17 +10025,13 @@ "node": ">=8" } }, - "node_modules/remark-gfm": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", - "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", + "node_modules/remark-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.0.0.tgz", + "integrity": "sha512-O7yfjuC6ra3NHPbRVxfflafAj3LTwx3b73aBvkEFU5z4PsD6FD4vrqJAkE5iNGLz71GdjXfgRqm3SQ0h0VuE7g==", "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-gfm": "^3.0.0", - "micromark-extension-gfm": "^3.0.0", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "unified": "^11.0.0" + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" }, "funding": { "type": "opencollective", @@ -9710,20 +10077,6 @@ "@types/unist": "*" } }, - "node_modules/remark-stringify": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", - "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-to-markdown": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -9855,8 +10208,7 @@ "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/safe-regex-test": { "version": "1.0.0", @@ -9913,24 +10265,30 @@ "loose-envify": "^1.1.0" } }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/scule": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/scule/-/scule-1.1.0.tgz", "integrity": "sha512-vRUjqhyM/YWYzT+jsMk6tnl3NkY4A4soJ8uyh3O6Um+JXEQL9ozUCe7pqrxn3CSKokw0hw3nFStfskzpgYwR0g==", "dev": true }, - "node_modules/section-matter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", - "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", - "dependencies": { - "extend-shallow": "^2.0.1", - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -9946,6 +10304,15 @@ "node": ">=10" } }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "peer": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/set-function-name": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", @@ -10130,6 +10497,25 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "peer": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/space-separated-tokens": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", @@ -10153,11 +10539,6 @@ "node": ">=8.0" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" - }, "node_modules/std-env": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.5.0.tgz", @@ -10332,6 +10713,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/stringify-entities": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz", + "integrity": "sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-entities/node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -10353,14 +10756,6 @@ "node": ">=4" } }, - "node_modules/strip-bom-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/strip-final-newline": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", @@ -10578,7 +10973,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -10605,6 +10999,58 @@ "streamx": "^2.15.0" } }, + "node_modules/terser": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz", + "integrity": "sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==", + "peer": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -11064,6 +11510,31 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unist-util-stringify-position": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", @@ -11200,7 +11671,6 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", - "dev": true, "funding": [ { "type": "opencollective", @@ -11236,7 +11706,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -11334,11 +11803,57 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "dev": true }, + "node_modules/webpack": { + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", + "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", + "peer": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, "node_modules/webpack-sources": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, "engines": { "node": ">=10.13.0" } @@ -11349,6 +11864,28 @@ "integrity": "sha512-KnaMTE6EItz/f2q4Gwg5/rmeKVi79OR58NoYnwDJqCk9ywMtTGbBnBcfoBtN4QbYu0lWXvyMoH2Owxuhe4qI6Q==", "dev": true }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "peer": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -11591,14 +12128,6 @@ "node": ">=4.0" } }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "engines": { - "node": ">=0.4" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 603d835d..de0691ac 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "scripts": { "vercel-build": "next build", "prod": "next build && next start", - "dev": "next dev --turbo", + "dev": "next dev", "lint": "next lint", "format": "prettier . --check", "format:fix": "prettier . --write", @@ -12,22 +12,40 @@ "postinstall": "pre-commit install --install-hooks" }, "dependencies": { - "gray-matter": "^4.0.3", + "@mdx-js/loader": "^3.0.0", + "@mdx-js/react": "^3.0.0", + "@next/mdx": "^14.0.1", + "@types/mdx": "^2.0.9", "next": "~13.5.6", "react": "18.2.0", "react-dom": "18.2.0", +<<<<<<< HEAD "react-icons": "^4.12.0", "react-markdown": "^9.0.1", "react-syntax-highlighter": "^15.5.0", "remark-gfm": "^4.0.0" +======= + "react-icons": "^4.11.0" +>>>>>>> 5bf2ac47e95e3d0baa4af333a963409a852c4bac }, "devDependencies": { +<<<<<<< HEAD "@commitlint/types": "^18.4.0", "@tailwindcss/typography": "^0.5.10", "@trivago/prettier-plugin-sort-imports": "^4.3.0", +<<<<<<< HEAD "@types/node": "^20.9.2", "@types/react": "^18.2.37", "@types/react-dom": "^18.2.15", +======= +======= + "@commitlint/types": "^18.1.0", + "@trivago/prettier-plugin-sort-imports": "^4.2.1", +>>>>>>> chore(deps): remove some redundant dependencies + "@types/node": "^20.8.10", + "@types/react": "^18.2.35", + "@types/react-dom": "^18.2.14", +>>>>>>> 5bf2ac47e95e3d0baa4af333a963409a852c4bac "@types/react-syntax-highlighter": "^15.5.10", "autoprefixer": "^10.4.16", "eslint": "^8.53.0", diff --git a/src/app/about/page.tsx b/src/app/about/page.tsx index 82e50655..ff3428b2 100644 --- a/src/app/about/page.tsx +++ b/src/app/about/page.tsx @@ -1,19 +1,18 @@ import { Metadata } from "next"; -import Link from "next/link"; + +const pageDescription = `Somraj Saha is a Senior Software Engineer working + independently for businesses of all sorts of scale! Learn more about me in + this page and see if there is anything I might be able to help you out with`; export const metadata: Metadata = { title: "About", - description: `This is about Somraj Saha who is a Full-Stack Software Engineer and - working as an Independent Software Developer. He works with startup founders and - business owners to bring fresh ideas to production and serve paying customers.`, + description: pageDescription, alternates: { canonical: "/about", }, openGraph: { title: "About | Somraj Saha", - description: `This is about Somraj Saha who is a Full-Stack Software Engineer and - working as an Independent Software Developer. He works with startup founders and - business owners to bring fresh ideas to production and serve paying customers.`, + description: pageDescription, url: "https://jarmos.dev/about", siteName: "Somraj Saha", images: [ @@ -27,9 +26,7 @@ export const metadata: Metadata = { twitter: { card: "summary_large_image", title: "About | Somraj Saha", - description: `This is about Somraj Saha who is a Full-Stack Software Engineer and - working as an Independent Software Developer. He works with startup founders and - business owners to bring fresh ideas to production and serve paying customers.`, + description: pageDescription, creator: "@Jarmosan", images: ["https://ik.imagekit.io/jarmos/tr:w-1200,h-627/logo-og.svg"], }, @@ -46,349 +43,262 @@ export const metadata: Metadata = { }, }; -const AboutPage = () => { - return ( -
-

About Somraj Saha

-

Hi There!

-

- I am an Independent Software Engineer & I work with startup founders - & business owners from different backgrounds to build/design their - MVPs. If you do decide to work with me, here is what a typical workflow - will look like:{" "} -

-
    -
  1. - I will sit with you to understand the business problem & the - target customers of the product. During this phase I might as well - suggest some pros/cons of the approach you have in mind (if at all - needed). -
  2. -
  3. - With the initial ideation phase complete, I will design & draft - the software architecture & specification of the product which - will be later used as a source of reference for other teams - contributing to the product. -
  4. -
  5. - With the documentation for the software architecture complete, I will - then proceed towards building the MVP. I will also be hiring the first - group of engineers, developers & related roles to build & - maintain the product during this phase. -
  6. -
+const AboutPage = () => ( +
+

+ About Somraj Saha +

+ +

+ Hi there! 👋🏽Welcome to my " + + digital garden + + "! +

+ +

+ I am Somraj Saha (aka "Jarmos") and I am a Senior Software + Engineer working independently! My primary work involves helping + businesses of all scale solve some of their software engineering probalems + and contribute (or even create) opensource tools as a hobby and + recreational purposes. The website you are on right now is where I share + my knowledge, skills and thoughts as a Software Engineer. +

+ +

+ If you are curious of the technologies and/or the development tools I use + for work, here is what you should know: +

-

- That was a quick sneak peak into what a typical workflow of us working - together to build a business would sound like. So, if you want to - collaborate with me, reach out to me over{" "} - - email +

+ Programming Languages I Work With +

+ +
    +
  1. + + Python + {" "} + when dealing with scall-scale scripts, system automation and/or building + large scale backend APIs. +
  2. +
  3. + + TypeScript + {" "} + to write{" "} + + React.js + {" "} + based applications for web browsers. The developer experience thanks to + the strict static typing is something I cannot live without! +
  4. +
  5. + + Lua + {" "} + to programmatically configure a develop my personalised development + environment within{" "} + + Neovim - . You can find also find me on:{" "} -

    - + . And I am yet to come across an opportunity where I could write Lua + code outside of Neovim environment as well. +
  6. +
  7. + + Golang + {" "} + (or simply Go) is a programming language I am currently learning to + rewrite some of my CLI tools with. I choose this language because of its + easy syntax, static typing and ability to distribute executable binaries + of my projects. +
  8. +
-

- And if you want to check out my previous work/experience writing code? - Then head over to the portfolio page to - see the highlights of the projects I worked on. -

-

- That said, here are the list of technologies I work with at the moment. - Do note, the list shared below is by no means exhaustive & I'm - open to picking up other technologies as the need arises. -

-

Programming Languages I Work With

-
    -
  1. - - Python - {" "} - for small-scale scripting, system automation and/or building backend - REST APIs. I also often use Python to build CLI applications which are - not complex in functionality and design. -
  2. -
  3. - - TypeScript - {" "} - when working on{" "} - - React.js - {" "} - based projects since I enjoy working with the static-typing - capabilities the language provides. The language also helps me nip - common bugs introduced by dynamic-typing & other JavaScript - caveats right at the bud. -
  4. -
  5. - - Lua - {" "} - for scripting & configuring{" "} - - Neovim - - . Unfortunately I am yet to come across other areas of application - where I can make full use of my Lua programming skills. -
  6. -
-

Frameworks & Libraries I Use to Develop Software

-
    -
  1. - - Next.js - {" "} - is a React.js-based framework & I use it to build fast & - well-optimised websites. A quick heads up for you, the website you are - on, was built using Next.js as well! If you are interested, go ahead - & check out the{" "} - - source code - - . -
  2. -
  3. - - FastAPI - {" "} - is a Python framework for developing & building REST APIs. This is - my favourite go-to framework for backend projects because of its speed - & static-typing support which alternatives like{" "} - - Django Rest Framework - {" "} - or{" "} - - Flask - {" "} - lacks. -
  4. -
  5. - - TailwindCSS - {" "} - is a CSS framework for those who does not like the monotonic - aesthetics of other CSS frameworks like{" "} - - Bootstrap - {" "} - & so on. I use it often to develop most of my frontend projects - & not worry about the overhead of “CSS anxiety“. -
  6. -
  7. - - Chakra-UI - {" "} - is a ready-to-use React Component library & I use it when I need - to build a web project real quick! This library is best suited for - usage when the project need not require a lot of aesthetic - customisation. There are other React component libraries out there as - well & some of those which I used are:{" "} - - NextUI - - ,{" "} - - Flowbite - {" "} - &{" "} - - Radix - -
  8. -
  9. - - SASS - {" "} - is a CSS preprocesser & it has “first-class support“ - with Next.js through CSS Modules. Hence, making life much easier by - allowing me to write more modular, clean & dry CSS code for my - Next.js projects. -
  10. -
  11. - - Scikit-Learn - {" "} - is a comprehensive library providing Python API for some of the most - widely used ML algorithms. I use this library to build modern ML-based - software. -
  12. -
-

Miscellaneous Development Tools I Need Daily

-

- A Software Developer's toolkit is incomplete without their - preferred set of tools. Apart from the few programming languages & - their respective framework/libraries mentioned above, there are other - equally important tools as well. Some of these tools might not directly - affect the development or maintainance of a software product but they - help me write better software. Hence, following are the few tools I - employ on a regular basis when writing code: -

-
    -
  1. - - Ubuntu - {" "} - the Linux-based OS & my primary choice of an Operating System when - developing & deploying software to production environments. I am - reconsidering using a more configurable distro like{" "} - - EndeavourOS - {" "} - for my development needs in the future though. So, if you have used it - before or using it at the moment? Then feel free to share a review or - two about it with me. -
  2. -
  3. - - Visual Studio Code (VSCode) - {" "} - is a configurable Text Editor from Microsoft & I use it with a ton - of plugins for writing code. This particular Text Editor has - incredible support for plugins (some maintained by Microsoft - themselves) which makes other, more resource-intensive IDEs like{" "} - - PyCharm - {" "} - unattractive in my eyes. -
  4. -
  5. - - Neovim - {" "} - is the one & only preferred (more like favourite) Text Editor I - use to write code. Its a “better“ fork of{" "} - - Vim - {" "} - & I have been using it for the past{" "} - {new Date().getFullYear() - Number("2019")} years. -
  6. -
  7. - - Docker - {" "} - is the de facto containerisation tool for developing & - deploying projects to production environments. And I try to use it for - all of my projects (including some of my hobby projects as well) - whenever possible! -
  8. -
-
- ); -}; +

+ Primary Frameworks & Libraries +

+ +

+ Although I use quite a few frameworks and libraries on a daily basis but I + am only listing a few of the primary and most widely used ones here. I am + generally framework agnostic and will pick up whatever framework does the + job or is currently widely used by the community. +

+ +
    +
  1. + + Next.js + {" "} + to build websites and web applications using React.js technologies in a + more sensible manner. And a little heads up for you, the website you are + currently on is built using Next.js as well! You can check out the{" "} + + source code on GitHub + {" "} + if interested. +
  2. +
  3. + + FastAPI + {" "} + is a Python framework to build fast asynchronous backend REST APIs. This + is my primary choice of a tool to build the backend systems of any web + applications I work on. +
  4. +
  5. + + TailwindCSS + {" "} + is a CSS library for styling web applications quickly using + “utility classes” (a concept borrowed from{" "} + + Bootstrap + + ). I use it when a speedy deployment to production is of utmost + importance. +
  6. +
+ +

+ As mentioned earlier, those are not the only frameworks and libraries I + work with but the list would be too long to list all of them! +

+ +

+ Other Developer Tools I Use +

+ +

+ A Software Engineer is “a Batman without his + Batsuit/Batmobile”, hence it is very important for me to choose and + maintain a bunch of tools I would use on a day-to-day basis to write code + as well. +

+ +

+ Here are the rest of the tools which helps me write code with the list of + technologies mentioned above: +

+ +
    +
  1. + + Ubuntu + {" "} + is my current Operating System of choice but I do use{" "} + + Windows 11 + {" "} + and{" "} + + Fedora Linux + {" "} + for development at certain times. +
  2. +
  3. + + Docker + {" "} + which is the de facto containerisation tool is used in my development + workflow to run various software in a sandbox environment safely and + quickly! I cannot imagine writing and deploying code to production + without Docker containers. +
  4. +
  5. + Neovim as my preferred Text Editor which I have extensively configured + to my particular developer habits. If you want to explore how I + configure and setup a personalised development environment, check out{" "} + + the dotfiles + {" "} + on GitHub. +
  6. +
+ +

+ That said, as a Software Engineer I am always on the look out to learn and + use new technologies. And although I will try my best to keep this page + updated frequently I would not want to make it a boring read for you. If + you still want to be updated of the technologies I work with or have plans + to try out, you might want to follow me on my social media platforms! +

+
+); export default AboutPage; diff --git a/src/app/blog/[slug]/page.tsx b/src/app/blog/[slug]/page.tsx deleted file mode 100644 index f7f9f929..00000000 --- a/src/app/blog/[slug]/page.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import type { Metadata } from "next"; - -import matter from "gray-matter"; -import path from "path"; -import ReactMarkdown from "react-markdown"; -import remarkGfm from "remark-gfm"; - -export const dynamicParams = false; - -type StaticParamsType = { - params: { - slug: string; - }; -}; - -export async function generateMetadata({ - params, -}: StaticParamsType): Promise { - const blogDir = path.join(process.cwd(), "_blog"); - const content = matter.read(`${blogDir}/${params?.slug}.md`).data; - - return { - title: content.title, - description: content.description, - alternates: { - canonical: `/${content.slug}`, - }, - openGraph: { - title: `${content.title} | Somraj Saha`, - description: content.description, - url: `https://jarmos.dev/${content.slug}`, - siteName: "Somraj Saha", - images: [ - { - url: content.coverImage.url, - alt: content.coverImage.alt, - }, - ], - type: "website", - }, - twitter: { - card: "summary_large_image", - title: `${content.title} | Somraj Saha`, - description: content.description, - creator: "@Jarmosan", - images: [content.coverImage.url], - }, - appleWebApp: { - title: `${content.title} | Somraj Saha`, - statusBarStyle: "black-translucent", - startupImage: [ - "/apple-touch-icon.png", - { - url: "/apple-touch-icon.png", - media: "(device-width: 768px) and (device-height: 1024px)", - }, - ], - }, - }; -} - -function BlogPage({ params }: StaticParamsType) { - const blogDir = path.join(process.cwd(), "_blog"); - const content = matter.read(`${blogDir}/${params?.slug}.md`).content; - - return ( - <> -
- {content} -
- - ); -} - -export default BlogPage; - -// FIXME: Syntax highlighting is broken fix it some other day diff --git a/src/app/blog/another-mdx-test/page.mdx b/src/app/blog/another-mdx-test/page.mdx new file mode 100644 index 00000000..1b290f19 --- /dev/null +++ b/src/app/blog/another-mdx-test/page.mdx @@ -0,0 +1,13 @@ +# Welcome to my MDX page! + +This is some **bold** and _italics_ text. + +![](https://picsum.photos/200) + +This is a list in markdown: + +- One +- Two +- Three + +Checkout my React component: diff --git a/src/app/blog/create-custom-keymaps-using-lua-for-neovim/page.mdx b/src/app/blog/create-custom-keymaps-using-lua-for-neovim/page.mdx new file mode 100644 index 00000000..11d56a0d --- /dev/null +++ b/src/app/blog/create-custom-keymaps-using-lua-for-neovim/page.mdx @@ -0,0 +1,52 @@ +# How to Create Custom Keymaps in Neovim Using the Embedded Lua Environment + +![Create Custom Keymaps for Neovim Using Lua](https://ik.imagekit.io/jarmos/create-custom-keymaps-using-lua.png?updatedAt=1685086095483) + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam ornare at metus +ut auctor. Etiam fermentum laoreet porttitor. Vestibulum vel nibh enim. Cras +massa dolor, fermentum id ligula non, pharetra pharetra urna. Proin congue +fermentum faucibus. Suspendisse laoreet sapien non vehicula fringilla. Morbi +facilisis rhoncus odio, et vestibulum ante dignissim vitae. Aenean egestas ante +vitae erat tempor, sit amet vehicula diam efficitur. + +Donec efficitur aliquam dui, sed porta nisl hendrerit sit amet. Nam augue odio, +maximus at dolor sed, pharetra convallis diam. Vivamus ipsum nunc, feugiat id +cursus ac, semper sit amet orci. Vivamus ac accumsan nulla. Nunc ipsum libero, +feugiat et orci sit amet, interdum semper ante. Ut id diam eu tortor scelerisque +scelerisque. Proin sit amet urna ac sapien ornare rutrum molestie sed turpis. +Duis ullamcorper tellus eu ligula mollis fringilla. Donec condimentum gravida +tincidunt. Nullam vulputate enim arcu, id tincidunt felis laoreet quis. Nunc +viverra commodo porttitor. + +Fusce rutrum ultricies diam, non sodales purus mollis sed. Integer fringilla +diam nisi, vitae elementum arcu posuere ac. Morbi porta dolor in posuere +scelerisque. Ut non nunc odio. Donec lobortis lacinia lacinia. Aliquam eu nunc +in turpis venenatis euismod vel eget orci. Morbi fringilla, nunc vel sagittis +aliquet, libero purus tempor ex, a condimentum nibh ex non nisl. Proin a arcu +nec ex elementum mollis. Curabitur nec ante bibendum, imperdiet lacus quis, +dapibus tellus. Proin lacinia lectus in facilisis suscipit. + +Aliquam luctus, erat vitae malesuada fermentum, enim nibh vestibulum lorem, vel +convallis diam ex sit amet velit. Sed efficitur purus ut vehicula placerat. +Integer consectetur tempor tortor, ultricies lacinia dui porttitor eu. Donec +dictum tortor blandit neque hendrerit, non ultrices orci bibendum. Pellentesque +habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. +Phasellus vulputate pulvinar nunc in aliquam. Maecenas ut eros mi. Morbi id +purus consectetur, tincidunt libero sollicitudin, mollis felis. In hac habitasse +platea dictumst. Cras placerat, est nec ultrices iaculis, magna felis sodales +libero, at interdum lectus nisl sed velit. Proin bibendum risus eu odio +efficitur scelerisque. Maecenas quis diam ac massa sollicitudin maximus. Aenean +a hendrerit dolor. Cras efficitur, nibh in tempor dignissim, diam enim semper +velit, lobortis faucibus lacus purus a sem. Phasellus non dictum augue. + +Aenean ut lorem mauris. Duis pulvinar, dui et laoreet maximus, lacus nunc +pellentesque elit, ac condimentum magna metus id augue. Fusce consectetur felis +ac hendrerit suscipit. Proin elementum ligula ut eros viverra elementum. +Phasellus quis nisi id risus hendrerit lacinia. Curabitur condimentum fermentum +vulputate. Maecenas turpis ipsum, cursus id faucibus pretium, gravida vitae leo. +Aenean eu purus tristique, malesuada orci quis, commodo ligula. Sed lorem nibh, +pharetra sit amet lorem quis, lobortis ullamcorper velit. Cras volutpat justo +ante, eu porttitor erat vulputate et. Ut commodo, elit ut pretium auctor, quam +sem lacinia lacus, nec lobortis risus arcu facilisis diam. Curabitur metus +velit, sodales eu ultrices et, congue congue elit. Nunc rutrum pretium commodo. +Proin interdum pharetra enim, a malesuada nisi consequat ac. diff --git a/src/app/blog/layout.tsx b/src/app/blog/layout.tsx new file mode 100644 index 00000000..aa339da6 --- /dev/null +++ b/src/app/blog/layout.tsx @@ -0,0 +1,15 @@ +import { PropsWithChildren } from "react"; + +const BlogLayout = ({ children }: PropsWithChildren) => { + // The contents of all the blogs are rendered inside the "article" tag + return ( +
+ {children} +
+ ); +}; + +export default BlogLayout; diff --git a/src/app/blog/page.tsx b/src/app/blog/page.tsx index ae2fbab6..821232f8 100644 --- a/src/app/blog/page.tsx +++ b/src/app/blog/page.tsx @@ -1,8 +1,6 @@ import { Metadata } from "next"; import Link from "next/link"; -import getPosts from "@lib/get-posts"; - export const metadata: Metadata = { title: "Blog Posts", description: `Blog posts Somraj Saha has written and publised on topics like @@ -45,32 +43,56 @@ export const metadata: Metadata = { }, }; -const BlogPostsPage = async () => { - const blogs = await getPosts(); +const blogs = [ + { + slug: "test-mdx", + title: "This is a test MDX blog", + summary: "Just a simple summary of the blog", + publicationDate: "20-10-2023", + }, + { + slug: "test-mdx-simplified", + title: "This is a test MDX blog simplified", + summary: "Just a simple summary of the blog", + publicationDate: "21-10-2023", + }, + { + slug: "another-test-mdx", + title: "This is another test MDX blog", + summary: "Just another simple summary of the blog", + publicationDate: "22-10-2023", + }, +]; +const BlogPostsPage = async () => { return ( - <> -
-

Blog Posts

- {blogs.map((data) => ( -
- +
+

Blog Posts

+
+ {blogs.map((blog) => ( +
+

- {data.title} + {blog.title}

-

{data.summary}

- Published on {data.date} +

{blog.summary}

+
+ Published on {blog.publicationDate} +
))} -
- + +
); }; diff --git a/src/app/blog/test-mdx/page.mdx b/src/app/blog/test-mdx/page.mdx new file mode 100644 index 00000000..1b290f19 --- /dev/null +++ b/src/app/blog/test-mdx/page.mdx @@ -0,0 +1,13 @@ +# Welcome to my MDX page! + +This is some **bold** and _italics_ text. + +![](https://picsum.photos/200) + +This is a list in markdown: + +- One +- Two +- Three + +Checkout my React component: diff --git a/src/app/distribution-rights/page.tsx b/src/app/distribution-rights/page.tsx index 0938854b..c67e18af 100644 --- a/src/app/distribution-rights/page.tsx +++ b/src/app/distribution-rights/page.tsx @@ -44,83 +44,94 @@ export const metadata: Metadata = { const LicensePage = () => { return ( - <> -
-

Licensing & Distribution Rights

-

- The enitirety of the project you are seeing right now is made - available for public usage under an open-source license. The contents - & the source code of the website as well is made available for - public scrutiny. In other words, you are free to view, use, modify - everything related to this project as long as you adhere to certain - usage terms & conditions (T&Cs). And this page of the website - details the usage T&Cs for your reference. -

-

Usage Rights of the Source Code

-

- The{" "} - - source code - {" "} - of the project is hosted in a public GitHub repository. And hence is - licensed under the open-source MIT License. As such you can check out - the source code to: -

-
    -
  1. - Fork the repository & modify the source code for your specific - requirements. -
  2. -
  3. Take inspiration for building your own personal website.
  4. -
  5. Contribute, report and/or fix bugs for the project.
  6. -
  7. - Use the source code for commercial requirements (as long as you - provide due credits to the stakeholders). -
  8. -
-

- That said, you can read more about the licensing & usage T&Cs - in the{" "} - - LICENSE - {" "} - document. -

-

Usage Rights of the Website Content

-

- This website contains a lot of technical & literary content meant - for educating the readers on certain topics related to Computer - Science & programming. All such contents are released & made - available in the public domain as well! In other words, you as a - reader/consumer are free to use, modify & distribute the content - as long as you adhere to the T&Cs detailed in this section of the - page. -

-

- That said, the open-source license in question is the{" "} - - CC BY 4.0 - - . And you are free to use, distribute and/or modify the contents of - this website as long as you adhere to the said license. -

-
- +
+

+ Licensing & Distribution Rights +

+ +

+ The enitirety of the project you are seeing right now is made available + for public usage under an open-source license. The contents & the + source code of the website as well is made available for public + scrutiny. In other words, you are free to view, use, modify everything + related to this project as long as you adhere to certain usage terms + & conditions (T&Cs). And this page of the website details the + usage T&Cs for your reference. +

+ +

+ Usage Rights of the Source Code +

+ +

+ The{" "} + + source code + {" "} + of the project is hosted in a public GitHub repository. And hence is + licensed under the open-source MIT License. As such you can check out + the source code to: +

+ +
    +
  1. + Fork the repository & modify the source code for your specific + requirements. +
  2. +
  3. Take inspiration for building your own personal website.
  4. +
  5. Contribute, report and/or fix bugs for the project.
  6. +
  7. + Use the source code for commercial requirements (as long as you + provide due credits to the stakeholders). +
  8. +
+ +

+ That said, you can read more about the licensing & usage T&Cs in + the{" "} + + LICENSE + {" "} + document. +

+ +

+ Usage Rights of the Website Content +

+ +

+ This website contains a lot of technical & literary content meant + for educating the readers on certain topics related to Computer Science + & programming. All such contents are released & made available + in the public domain as well! In other words, you as a reader/consumer + are free to use, modify & distribute the content as long as you + adhere to the T&Cs detailed in this section of the page. +

+ +

+ That said, the open-source license in question is the{" "} + + CC BY 4.0 + + . And you are free to use, distribute and/or modify the contents of this + website as long as you adhere to the said license. +

+
); }; diff --git a/src/app/portfolio/page.tsx b/src/app/portfolio/page.tsx index 6f818b9d..6f66859b 100644 --- a/src/app/portfolio/page.tsx +++ b/src/app/portfolio/page.tsx @@ -43,7 +43,7 @@ function PortfolioPage() { return ( <>

Portfolio

diff --git a/src/app/privacy-policy/page.tsx b/src/app/privacy-policy/page.tsx index d566f21a..334b98db 100644 --- a/src/app/privacy-policy/page.tsx +++ b/src/app/privacy-policy/page.tsx @@ -39,254 +39,301 @@ export const metadata: Metadata = { }, }; -const LicensePage = () => { +const PrivacyPolicyPage = () => { return ( - <> -
-

Privacy Policy

-

- While developing & maintaining this project, our reader's - privacy concerns is of utmost importance to us. Hence, at each & - every step of developing this website, we ensured everything is - covered under the{" "} - - GDPR - {" "} - guidelines. That said, if you concerned about what sort of private - data do we collect, this section of the website contains everything - you will need to read about. -

-

Information We Collect

-
    -
  • - Contact Information: We might collect your name, - email, mobile number, phone number, street, city, state, pincode, - country and IP address. -
  • -
  • - Information You Share: We collect information & - other details like email you share with us through HTML forms & - other means of gathering user feedback like onlines questionnaires - such as those from Google Forms and/or TypeForm. -
  • -
  • - Demographic Information: We may collect demographic - information about you. These information might include your age, - your residence, country, gender, specific preferences for content - & so on. They are collected through use of third-party trackers - like Google Analytics, Cloudflare Analytics & Twitter Analytics. - We might collect this as a part of a survey also. -
  • -
  • - Other Information: If you use our website, we may - collect information about your IP address and the browser you are - using. We might look at what site you came from, duration of time - spent on our website, pages accessed or what site you visit when you - leave us. We might also collect the type of mobile device you are - using, or the version of the operating system your computer or - device is running. -
  • -
-

We Collect Information in Different Ways

-
    -
  • - We Collect Information Directly From You: We - collect information directly from you when you share your email with - us to join our private email list(s). We also collect information if - you share a feedback or ask us a question through phone or email. -
  • -
  • - We Collect Information From You Passively: We use - tracking tools like Google Analytics, Google Webmaster, Cloudlfare - Analytics, Twitter Analytics, browser cookies and web beacons for - collecting information about your usage of our website. -
  • -
  • - We Get Information About You From Third-Parties: - For example, if you use an integrated social media feature on our - websites. The third-party social media site will give us certain - information about you. This could include your name and email - address. -
  • -
-

Use of Your Personal Information

-
    -
  • - We Use the Information to Contact You: We might use - the information you provide to contact you for confirmation of a - subscription on our website or for other promotional purposes. -
  • -
  • - - We Use the Information to Respond to Your Requests or Questions - - : We might use your information to confirm your registration for an - event, a subscription, giveaways & other similar activities. -
  • -
  • - - We Use Information to Improve Our Products & Services - - : We might use your information to customize your experience with - us. This could include displaying content based upon your - preferences. -
  • -
  • - - We Use Information to Look at Site Trends & Reader Interests - - : We may use your information to make our website and products - better. We may combine information we get from you with information - about you we get from third parties. -
  • -
  • - We Use Information for Security Concerns: We may - use information to protect our company, our readers, or our - websites. -
  • -
  • - We Use Information for Marketing Purposes: We might - send you information about special promotions or offers. We might - also tell you about new features or products. These might be our own - offers or products, or third-party offers or products we think you - might find interesting. Or, for example, posts containing affiliate - links & other sponsored posts. Do note, you will be notified of - the nature of the posts when we send you one. -
  • -
  • - - We Use Information to Send You Transactional Communications - - : We might send you emails about the terms & conditions of - services between Somraj Saha & you or a subscription. -
  • -
-

We use the information as permitted by law.

-

Sharing of Information with Third-Parties

-
    -
  • - - We Will Share Information With Third Parties Who Perform Services - On Our Behalf - - : We share information with vendors who help us manage our email - list subscription process. Some vendors may be located outside of - India. -
  • -
  • - - We Will Share Information With Our Business Partners - - : : We share information with vendors who help us manage our email - list subscription process. Some vendors may be located outside of - India. -
  • -
  • - - We Will Share Information If We Think We Have to Comply With or to - Protect Ourselves - - : We will share information to respond to a court order or subpoena. - We may also share it if a government agency or investigatory body - requests. Or, we might also share information when we are - investigating potential fraud. -
  • -
  • - - We May Share Information With Any Successor to All or Part of Our - Business - - : For example, if part of our business is sold we may give our - reader list as part of that transaction. -
  • -
  • - - We May Share Your Information for Reasons Not Described in This - Policy - - : We will tell you before we do this along with a detailed - explanation for us to do so. -
  • -
-

Email Opt-Out and/or Unsubscribe from Routine Updates

-

- You can opt out of receiving our marketing emails and/or receiving - personalized contents for our private email list(s). To stop receiving - our promotional emails, please email{" "} +

+

+ Privacy Policy +

+ +

+ While developing & maintaining this project, our reader's + privacy concerns is of utmost importance to us. Hence, at each & + every step of developing this website, we ensured everything is covered + under the{" "} + + GDPR + {" "} + guidelines. That said, if you concerned about what sort of private data + do we collect, this section of the website contains everything you will + need to read about. +

+ +

+ Information We Collect +

+ +
    +
  • + Contact Information: We might collect your name, + email, mobile number, phone number, street, city, state, pincode, + country and IP address. +
  • +
  • + Information You Share: We collect information & + other details like email you share with us through HTML forms & + other means of gathering user feedback like onlines questionnaires + such as those from Google Forms and/or TypeForm. +
  • +
  • + Demographic Information: We may collect demographic + information about you. These information might include your age, your + residence, country, gender, specific preferences for content & so + on. They are collected through use of third-party trackers like Google + Analytics, Cloudflare Analytics & Twitter Analytics. We might + collect this as a part of a survey also. +
  • +
  • + Other Information: If you use our website, we may + collect information about your IP address and the browser you are + using. We might look at what site you came from, duration of time + spent on our website, pages accessed or what site you visit when you + leave us. We might also collect the type of mobile device you are + using, or the version of the operating system your computer or device + is running. +
  • +
+ +

+ We Collect Information in Different Ways +

+ +
    +
  • + We Collect Information Directly From You: We collect + information directly from you when you share your email with us to + join our private email list(s). We also collect information if you + share a feedback or ask us a question through phone or email. +
  • +
  • + We Collect Information From You Passively: We use + tracking tools like Google Analytics, Google Webmaster, Cloudlfare + Analytics, Twitter Analytics, browser cookies and web beacons for + collecting information about your usage of our website. +
  • +
  • + We Get Information About You From Third-Parties: For + example, if you use an integrated social media feature on our + websites. The third-party social media site will give us certain + information about you. This could include your name and email address. +
  • +
+ +

+ Use of Your Personal Information +

+ +
    +
  • + We Use the Information to Contact You: We might use + the information you provide to contact you for confirmation of a + subscription on our website or for other promotional purposes. +
  • +
  • + + We Use the Information to Respond to Your Requests or Questions + + : We might use your information to confirm your registration for an + event, a subscription, giveaways & other similar activities. +
  • +
  • + + We Use Information to Improve Our Products & Services + + : We might use your information to customize your experience with us. + This could include displaying content based upon your preferences. +
  • +
  • + + We Use Information to Look at Site Trends & Reader Interests + + : We may use your information to make our website and products better. + We may combine information we get from you with information about you + we get from third parties. +
  • +
  • + We Use Information for Security Concerns: We may use + information to protect our company, our readers, or our websites. +
  • +
  • + We Use Information for Marketing Purposes: We might + send you information about special promotions or offers. We might also + tell you about new features or products. These might be our own offers + or products, or third-party offers or products we think you might find + interesting. Or, for example, posts containing affiliate links & + other sponsored posts. Do note, you will be notified of the nature of + the posts when we send you one. +
  • +
  • + + We Use Information to Send You Transactional Communications + + : We might send you emails about the terms & conditions of + services between Somraj Saha & you or a subscription. +
  • +
+ +

We use the information as permitted by law.

+ +

+ Sharing of Information with Third-Parties +

+ +
    +
  • + + We Will Share Information With Third Parties Who Perform Services On + Our Behalf + + : We share information with vendors who help us manage our email list + subscription process. Some vendors may be located outside of India. +
  • +
  • + We Will Share Information With Our Business Partners: + : We share information with vendors who help us manage our email list + subscription process. Some vendors may be located outside of India. +
  • +
  • + + We Will Share Information If We Think We Have to Comply With or to + Protect Ourselves + + : We will share information to respond to a court order or subpoena. + We may also share it if a government agency or investigatory body + requests. Or, we might also share information when we are + investigating potential fraud. +
  • +
  • + + We May Share Information With Any Successor to All or Part of Our + Business + + : For example, if part of our business is sold we may give our reader + list as part of that transaction. +
  • +
  • + + We May Share Your Information for Reasons Not Described in This + Policy + + : We will tell you before we do this along with a detailed explanation + for us to do so. +
  • +
+ +

+ Email Opt-Out and/or Unsubscribe from Routine Updates +

+ +

+ You can opt out of receiving our marketing emails and/or receiving + personalized contents for our private email list(s). To stop receiving + our promotional emails, please email{" "} + + somraj.mle@gmail.com + + . It may take about ten days to process your request. +

+ +

+ But, to receive a prompt unsubsribe request, please check the last email + you received. There will be an unsubscribe option at the bottom of it. + Do note, even if you opt out of getting marketing messages, we will + still be sending you transactional messages through email about your + purchase of our goods & services. +

+ +

+ Third-Party Sites +

+ +

+ If you click on one of the links to third party websites, you may be + taken to websites we do not control. This policy does not apply to the + privacy practices of those websites. Read the privacy policy of other + websites carefully. We are not responsible for these third party sites. +

+ +

+ Grievance Complaints +

+ +

+ In accordance with{" "} + + Information Technology Act, 2000 + {" "} + and rules made there under, the name and contact details of the + individual to share your grievance complaints at the provided email + address. +

+ +
+ Somraj Saha, + + 2nd Floor, Above Ram Thakur Tubewells, Masjid Road + + Agartala, Tripura + PIN: 799001 + Phone: (+91) 7731 824 653 + + Email:{" "} - somraj.mle@gmail.com + contact@jarmos.dev - . It may take about ten days to process your request. -

-

- But, to receive a prompt unsubsribe request, please check the last - email you received. There will be an unsubscribe option at the bottom - of it. Do note, even if you opt out of getting marketing messages, we - will still be sending you transactional messages through email about - your purchase of our goods & services. -

-

Third-Party Sites

-

- If you click on one of the links to third party websites, you may be - taken to websites we do not control. This policy does not apply to the - privacy practices of those websites. Read the privacy policy of other - websites carefully. We are not responsible for these third party - sites. -

-

Grievance Complaints

-

- In accordance with{" "} - - Information Technology Act, 2000 - {" "} - and rules made there under, the name and contact details of the - individual to share your grievance complaints at the provided email - address. -

-
- Mr. Somraj Saha Calcutta Textiles, Santipara, Masjid Road Agartala, - West Tripura PIN: 799001 Phone: (+91) 7731 824 653 Email: - somraj.mle@gmail.com -
-

- If you have any questions about this Policy or other privacy concerns, - you can reach out to us over electronic mail, traditional mail, - telephone or whichever means is convenient for you. Please do so - without any hesitation. -

-

Updates to This Policy

-

- From time to time we may change our privacy practices. We will notify - you of any material changes to this policy as required by law. We will - also post an updated copy on our website which you will find on the - top of this Privacy Policy document. Please check our site - periodically for updates. -

-

Jurisdiction

-

- If you choose to visit the website, your visit and any dispute over - privacy is subject to this Policy and the website's terms of use. - In addition to the foregoing, any disputes arising under this Policy - shall be governed by the laws of India. -

-
- + + + +

+ If you have any questions about this Policy or other privacy concerns, + you can reach out to us over electronic mail, traditional mail, + telephone or whichever means is convenient for you. Please do so without + any hesitation. +

+ +

+ Updates to This Policy +

+ +

+ From time to time we may change our privacy practices. We will notify + you of any material changes to this policy as required by law. We will + also post an updated copy on our website which you will find on the top + of this Privacy Policy document. Please check our site periodically for + updates. +

+ +

+ Jurisdiction +

+ +

+ If you choose to visit the website, your visit and any dispute over + privacy is subject to this Policy and the website's terms of use. + In addition to the foregoing, any disputes arising under this Policy + shall be governed by the laws of India. +

+
); }; -export default LicensePage; +export default PrivacyPolicyPage; diff --git a/src/app/terms-and-conditions/page.tsx b/src/app/terms-and-conditions/page.tsx index b1aee3aa..dc7a79a1 100644 --- a/src/app/terms-and-conditions/page.tsx +++ b/src/app/terms-and-conditions/page.tsx @@ -42,360 +42,416 @@ export const metadata: Metadata = { const TermsAndConditionsPage = () => { return ( - <> -
-

Terms And Conditions

-

- - PLEASE READ THIS TERMS OF SERVICE AGREEMENT CAREFULLY. BY USING THIS - WEBSITE, SUBSRIBING TO OUR PRODUCTS AND/OR USING OUR SERVICES FROM - THIS WEBSITE YOU AGREE TO BE BOUND BY ALL OF THE TERMS AND - CONDITIONS OF THIS AGREEMENT. - -

-

- This Terms of Service Agreement (the "Agreement - ") governs your use of this website,{" "} - jarmos.vercel.app (the " - Website"), business name (" - Somraj Saha") offer of services and/or products - for purchase and/or subscription on this Website, or your purchase of - products and/or subscriptions available on this Website. This - Agreement includes, and incorporates by this reference, the policies - and guidelines referenced below. Somraj Saha reserves the right to - change or revise the terms and conditions of this Agreement at any - time by posting any changes or a revised Agreement on this Website. - Somraj Saha will alert you that changes or revisions have been made by - indicating on the top of this Agreement the date it was last revised. - The changes or revised Agreement will be effective immediately after - it is posted on this Website. Your use of the Website following the - posting any such changes or of a revised Agreement will constitute - your acceptance of any such changes or revisions. Somraj Saha - encourages you to review this Agreement whenever you visit the Website - to make sure that you understand the terms and conditions governing - use of the Website. This Agreement does not alter in any way the terms - or conditions of any other written agreement you may have with Somraj - Saha for other products or services. If you do not agree to this - Agreement (including any referenced policies or guidelines), please - immediately terminate your use of the Website. If you would like to - print this Agreement, please click the print button on your browser - toolbar. -

-

I. Products

-

- Terms of Offer. This Website offers for sale certain products (the - "Products"). By placing an order for - Products through this Website, you agree to the terms and conditions - set forth in this Agreement. -

- -

- Reader Solicitation: Unless you notify Somraj Saha, - while they are communicating with you, of your desire to opt out from - further direct company communications and solicitations, you are - agreeing to continue to receive further emails and solicitations from - Somraj Saha. -

-

- Opt-Out Procedure: We provide 3 easy ways to opt out - of from future solicitations. -

    -
  1. - You may use the opt out link found in any email solicitation that - you may receive. -
  2. -
  3. - You may also choose to opt out, via sending your email address to:{" "} - - somraj.mle@gmail.com - -
  4. -
-

-

- Proprietary Rights. Somraj Saha has proprietary - rights and trade secrets in the Products & Services mentioned in - this Website. You may copy, reproduce, resell or redistribute any - Products & Services manufactured and/or distributed by Somraj Saha - under the Terms & Conditions of the{" "} - - CC BY-NA 4.0 - - . -

-

- Sales Tax. If you purchase any Products and/or - Services, you will be responsible for paying any applicable sales tax - (if any). -

-

II. Website

-

- Content; Intellectual Property; Third Party Links. In addition to - making Products available, this Website also offers information and - marketing materials. This Website also offers information, both - directly and through indirect links to third-party websites, about - Information Technology (IT). Somraj Saha does not always create the - information offered on this Website; instead the information is often - gathered from other sources. To the extent that Somraj Saha does - create the content on this Website, such content is protected by - intellectual property laws of the India, foreign nations, and - international bodies. Unauthorized use of the material may violate - copyright, trademark, and/or other laws. You acknowledge that your use - of the content on this Website is for personal, noncommercial use. Any - links to third-party websites are provided solely as a convenience to - you. Somraj Saha does not endorse the contents on any such third-party - websites. Somraj Saha is not responsible for the content of or any - damage that may result from your access to or reliance on these - third-party websites. If you link to third-party websites, you do so - at your own risk. -

-

- Use of Website; Somraj Saha is not responsible for any damages - resulting from use of this website by anyone. You will not use the - Website for illegal purposes. You will (1) abide by all applicable - local, state, national, and international laws and regulations in your - use of the Website (including laws regarding intellectual property), - (2) not interfere with or disrupt the use and enjoyment of the Website - by other users, (3) not resell material on the Website, (4) not - engage, directly or indirectly, in transmission of "spam", - chain letters, junk mail or any other type of unsolicited - communication, and (5) not defame, harass, abuse, or disrupt other - users of the Website -

-

- License. By using this Website, you are granted a limited, - non-exclusive, non-transferable right to use the content and materials - on the Website in connection with your normal, noncommercial, use of - the Website under the Terms & Conditions laid down by{" "} - - CC BY-NA 4.0 - - . You may copy, reproduce, transmit, distribute, or create derivative - works of such content or information with/without express written - authorization from Somraj Saha or the applicable third party (if third - party content is at issue). -

-

- Sharing Information. By sharing your personal information, storing, or - transmitting any content with us on the Website, you hereby grant - Somraj Saha a perpetual, worldwide, non-exclusive, royalty-free, - assignable, right and license to use, copy, display, perform, create - derivative works from, distribute, have distributed, transmit and - assign such content in any form, in all media now known or hereinafter - created, anywhere in the world. You are solely responsible for your - interactions with other users of the Website and any content they - share with you. Somraj Saha is not liable for any damage or harm - resulting from any posts by or interactions between users. Somraj Saha - reserves the right, but has no obligation, to monitor interactions - between and among users of the Website and to remove any content - Somraj Saha deems objectionable, in Somraj Saha's sole - discretion. -

-

III. Disclaimer of Warranties

-

- YOUR USE OF THIS WEBSITE AND/OR PRODUCTS ARE AT YOUR SOLE RISK. THE - WEBSITE AND PRODUCTS ARE OFFERED ON AN "AS IS - " AND "AS AVAILABLE" BASIS. SOMRAJ - SAHA EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, WHETHER EXPRESS - OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - WITH RESPECT TO THE PRODUCTS OR WEBSITE CONTENT, OR ANY RELIANCE UPON - OR USE OF THE WEBSITE CONTENT OR PRODUCTS. (" - PRODUCTS" INCLUDE TRIAL PRODUCTS.) -

-

- WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, SOMRAJ SAHA MAKES NO - WARRANTY: -

-

- NO ADVICE OR INFORMATION, WHETHER ORAL OR WRITTEN, OBTAINED BY YOU - FROM THIS WEBSITE WILL CREATE ANY WARRANTY NOT EXPRESSLY STATED - HEREIN. -

-

- AS TO THE RESULTS THAT MAY BE OBTAINED FROM THE USE OF THE PRODUCTS OR - THAT DEFECTS IN PRODUCTS WILL BE CORRECTED. -

-

REGARDING ANY PRODUCTS PURCHASED OR OBTAINED THROUGH THE WEBSITE.

-

- SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES, - SO SOME OF THE ABOVE EXCLUSIONS MAY NOT APPLY TO YOU. -

-

IV. Limitation of Liability

-

- SOMRAJ SAHA ENTIRE LIABILITY, AND YOUR EXCLUSIVE REMEDY, IN LAW, IN - EQUITY, OR OTHWERWISE, WITH RESPECT TO THE WEBSITE CONTENT AND - PRODUCTS AND/OR FOR ANY BREACH OF THIS AGREEMENT IS SOLELY LIMITED TO - THE AMOUNT YOU PAID, LESS SHIPPING AND HANDLING, FOR PRODUCTS AND/OR - SERVICES PURCHASED VIA THE WEBSITE. -

-

- SOMRAJ SAHA WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH THIS AGREEMENT OR - THE PRODUCTS IN ANY MANNER, INCLUDING LIABILITIES RESULTING FROM (1) - THE USE OR THE INABILITY TO USE THE WEBSITE CONTENT OR PRODUCTS; (2) - THE COST OF PROCURING SUBSTITUTE PRODUCTS OR CONTENT; (3) ANY PRODUCTS - PURCHASED OR OBTAINED OR TRANSACTIONS ENTERED INTO THROUGH THE - WEBSITE; OR (4) ANY LOST PROFITS YOU ALLEGE. -

-

- SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OR EXCLUSION OF - LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES SO SOME OF THE ABOVE - LIMITATIONS MAY NOT APPLY TO YOU. -

-

V. Indemnification

-

- You will release, indemnify, defend and hold harmless Somraj Saha, and - any of his contractors, agents, employees, officers, directors, - shareholders, affiliates and assigns from all liabilities, claims, - damages, costs and expenses, including reasonable attorneys' fees - and expenses, of third parties relating to or arising out of (1) this - Agreement or the breach of your warranties, representations and - obligations under this Agreement; (2) the Website content or your use - of the Website content; (3) the Products or your use of the Products - (including Trial Products); (4) any intellectual property or other - proprietary right of any person or entity; (5) your violation of any - provision of this Agreement; or (6) any information or data you - supplied to Somraj Saha. When Somraj Saha is threatened with suit or - sued by a third party, Somraj Saha may seek written assurances from - you concerning your promise to indemnify Somraj Saha; your failure to - provide such assurances may be considered by Somraj Saha to be a - material breach of this Agreement. Somraj Saha will have the right to - participate in any defense by you of a third-party claim related to - your use of any of the Website content or Products, with counsel of - Somraj Saha's choice at its expense. Somraj Saha will reasonably - cooperate in any defense by you of a third-party claim at your request - and expense. You will have sole responsibility to defend Somraj Saha - against any claim, but you must receive Somraj Saha a prior written - consent regarding any related settlement. The terms of this provision - will survive any termination or cancellation of this Agreement or your - use of the Website or Products. -

-

VI. Privacy

-

- Somraj Saha believes strongly in protecting user privacy and providing - you with notice of Somraj Saha's blog's use of data. Please - refer to Somraj Saha's{" "} - Privacy Policy, incorporated by - reference herein, that is posted on the Website. -

-

VII. Agreement to be Bound

-

- By using this Website, ordering Products and/or subscribing to our - Services, you acknowledge that you have read and agree to be bound by - this Agreement and all terms and conditions on this Website. -

-

VIII. General

-

- Force Majeure. Somaraj Saha will not be deemed in default hereunder or - held responsible for any cessation, interruption or delay in the - performance of its obligations hereunder due to earthquake, flood, - fire, storm, natural disaster, act of God, war, terrorism, armed - conflict, labor strike, lockout, or boycott. -

-

- Cessation of Operation. Somraj Saha may at any time, in its sole - discretion and without advance notice to you, cease operation of the - Website and distribution of the Products. -

-

- Entire Agreement. This Agreement comprises the entire agreement - between you and Somraj Saha and supersedes any prior agreements - pertaining to the subject matter contained herein. -

-

- Effect of Waiver. The failure of Somraj Saha to exercise or enforce - any right or provision of this Agreement will not constitute a waiver - of such right or provision. If any provision of this Agreement is - found by a court of competent jurisdiction to be invalid, the parties - nevertheless agree that the court should endeavor to give effect to - the parties' intentions as reflected in the provision, and the - other provisions of this Agreement remain in full force and effect. -

-

- Governing Law;{" "} - - Supreme Court of India - - . This Website originates from the city of Agartala in Tripura, India. - This Agreement will be governed by the laws of the State of India - without regard to its conflict of law principles to the contrary. - Neither you nor Somraj Saha will commence or prosecute any suit, - proceeding or claim to enforce the provisions of this Agreement, to - recover damages for breach of or default of this Agreement, or - otherwise arising under or by reason of this Agreement, other than in - courts located in State of India. By using this Website or ordering - and/or subscribing to our Products, you consent to the jurisdiction - and venue of such courts in connection with any action, suit, - proceeding or claim arising under or by reason of this Agreement. You - hereby waive any right to trial by jury arising out of this Agreement - and any related documents. -

-

- Statute of Limitation. You agree that regardless of any statute or law - to the contrary, any claim or cause of action arising out of or - related to use of the Website or Products or this Agreement must be - filed within one (1) year after such claim or cause of action arose or - be forever barred. -

-

- Waiver of Class Action Rights. BY ENTERING INTO THIS AGREEMENT, YOU - HEREBY IRREVOCABLY WAIVE ANY RIGHT YOU MAY HAVE TO JOIN CLAIMS WITH - THOSE OF OTHER IN THE FORM OF A CLASS ACTION OR SIMILAR PROCEDURAL - DEVICE. ANY CLAIMS ARISING OUT OF, RELATING TO, OR CONNECTION WITH - THIS AGREEMENT MUST BE ASSERTED INDIVIDUALLY. -

-

- Termination. Somraj Saha reserves the right to terminate your access - to the Website if it reasonably believes, in its sole discretion, that - you have breached any of the terms and conditions of this Agreement. - Following termination, you will not be permitted to use the Website - and Somraj Saha may, in its sole discretion and without advance notice - to you, cancel any outstanding orders for Products. If your access to - the Website is terminated, Somraj Saha reserves the right to exercise - whatever means it deems necessary to prevent unauthorized access of - the Website. This Agreement will survive indefinitely unless and until - Somraj Saha chooses, in its sole discretion and without advance to - you, to terminate it. -

-

- Domestic Use. Somraj Saha makes no representation that the Website or - Products are appropriate or available for use in locations outside - India. Users who access the Website from outside India do so at their - own risk and initiative and must bear all responsibility for - compliance with any applicable local laws. -

-

- Assignment. You may not assign your rights and obligations under this - Agreement to anyone. Somraj Saha may assign its rights and obligations - under this Agreement in its sole discretion and without advance notice - to you. -

-

- BY USING THIS WEBSITE OR ORDERING PRODUCTS FROM THIS WEBSITE YOU AGREE - TO BE BOUND BY ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. -

-
- +
+

+ Terms And Conditions +

+ +

+ + PLEASE READ THIS TERMS OF SERVICE AGREEMENT CAREFULLY. BY USING THIS + WEBSITE, SUBSRIBING TO OUR PRODUCTS AND/OR USING OUR SERVICES FROM + THIS WEBSITE YOU AGREE TO BE BOUND BY ALL OF THE TERMS AND CONDITIONS + OF THIS AGREEMENT. + +

+ +

+ This Terms of Service Agreement (the "Agreement + ") governs your use of this website,{" "} + + jarmos.dev + {" "} + (the " + Website"), business name (" + Somraj Saha") offer of services and/or products + for purchase and/or subscription on this Website, or your purchase of + products and/or subscriptions available on this Website. This Agreement + includes, and incorporates by this reference, the policies and + guidelines referenced below. Somraj Saha reserves the right to change or + revise the terms and conditions of this Agreement at any time by posting + any changes or a revised Agreement on this Website. Somraj Saha will + alert you that changes or revisions have been made by indicating on the + top of this Agreement the date it was last revised. The changes or + revised Agreement will be effective immediately after it is posted on + this Website. Your use of the Website following the posting any such + changes or of a revised Agreement will constitute your acceptance of any + such changes or revisions. Somraj Saha encourages you to review this + Agreement whenever you visit the Website to make sure that you + understand the terms and conditions governing use of the Website. This + Agreement does not alter in any way the terms or conditions of any other + written agreement you may have with Somraj Saha for other products or + services. If you do not agree to this Agreement (including any + referenced policies or guidelines), please immediately terminate your + use of the Website. If you would like to print this Agreement, please + click the print button on your browser toolbar. +

+ +

I. Products

+ +

+ Terms of Offer. This Website offers for sale certain products (the + "Products"). By placing an order for Products + through this Website, you agree to the terms and conditions set forth in + this Agreement. +

+ +

+ Reader Solicitation: Unless you notify Somraj Saha, + while they are communicating with you, of your desire to opt out from + further direct company communications and solicitations, you are + agreeing to continue to receive further emails and solicitations from + Somraj Saha. +

+ +

+ Opt-Out Procedure: We provide 3 easy ways to opt out of + from future solicitations. +

    +
  1. + You may use the opt out link found in any email solicitation that + you may receive. +
  2. +
  3. + You may also choose to opt out, via sending your email address to:{" "} + + contact@jarmos.dev + +
  4. +
+

+ +

+ Proprietary Rights. Somraj Saha has proprietary rights + and trade secrets in the Products & Services mentioned in this + Website. You may copy, reproduce, resell or redistribute any Products + & Services manufactured and/or distributed by Somraj Saha under the + Terms & Conditions of the{" "} + + CC BY-NA 4.0 + + . +

+ +

+ Sales Tax. If you purchase any Products and/or + Services, you will be responsible for paying any applicable sales tax ( + if any). +

+ +

II. Website

+ +

+ Content; Intellectual Property; Third Party Links. In addition to making + Products available, this Website also offers information and marketing + materials. This Website also offers information, both directly and + through indirect links to third-party websites, about Information + Technology (IT). Somraj Saha does not always create the information + offered on this Website; instead the information is often gathered from + other sources. To the extent that Somraj Saha does create the content on + this Website, such content is protected by intellectual property laws of + the India, foreign nations, and international bodies. Unauthorized use + of the material may violate copyright, trademark, and/or other laws. You + acknowledge that your use of the content on this Website is for + personal, noncommercial use. Any links to third-party websites are + provided solely as a convenience to you. Somraj Saha does not endorse + the contents on any such third-party websites. Somraj Saha is not + responsible for the content of or any damage that may result from your + access to or reliance on these third-party websites. If you link to + third-party websites, you do so at your own risk. +

+ +

+ Use of Website; Somraj Saha is not responsible for any damages resulting + from use of this website by anyone. You will not use the Website for + illegal purposes. You will (1) abide by all applicable local, state, + national, and international laws and regulations in your use of the + Website (including laws regarding intellectual property), (2) not + interfere with or disrupt the use and enjoyment of the Website by other + users, (3) not resell material on the Website, (4) not engage, directly + or indirectly, in transmission of "spam", chain letters, junk + mail or any other type of unsolicited communication, and (5) not defame, + harass, abuse, or disrupt other users of the Website +

+ +

+ License. By using this Website, you are granted a limited, + non-exclusive, non-transferable right to use the content and materials + on the Website in connection with your normal, noncommercial, use of the + Website under the Terms & Conditions laid down by{" "} + + CC BY-NA 4.0 + + . You may copy, reproduce, transmit, distribute, or create derivative + works of such content or information with/without express written + authorization from Somraj Saha or the applicable third party (if third + party content is at issue). +

+ +

+ Sharing Information. By sharing your personal information, storing, or + transmitting any content with us on the Website, you hereby grant Somraj + Saha a perpetual, worldwide, non-exclusive, royalty-free, assignable, + right and license to use, copy, display, perform, create derivative + works from, distribute, have distributed, transmit and assign such + content in any form, in all media now known or hereinafter created, + anywhere in the world. You are solely responsible for your interactions + with other users of the Website and any content they share with you. + Somraj Saha is not liable for any damage or harm resulting from any + posts by or interactions between users. Somraj Saha reserves the right, + but has no obligation, to monitor interactions between and among users + of the Website and to remove any content Somraj Saha deems + objectionable, in Somraj Saha's sole discretion. +

+ +

+ III. Disclaimer of Warranties +

+ +

+ YOUR USE OF THIS WEBSITE AND/OR PRODUCTS ARE AT YOUR SOLE RISK. THE + WEBSITE AND PRODUCTS ARE OFFERED ON AN "AS IS + " AND "AS AVAILABLE" BASIS. SOMRAJ SAHA + EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, WHETHER EXPRESS OR + IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + WITH RESPECT TO THE PRODUCTS OR WEBSITE CONTENT, OR ANY RELIANCE UPON OR + USE OF THE WEBSITE CONTENT OR PRODUCTS. (" + PRODUCTS" INCLUDE TRIAL PRODUCTS.) +

+ +

+ WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, SOMRAJ SAHA MAKES NO + WARRANTY: +

+ +

+ NO ADVICE OR INFORMATION, WHETHER ORAL OR WRITTEN, OBTAINED BY YOU FROM + THIS WEBSITE WILL CREATE ANY WARRANTY NOT EXPRESSLY STATED HEREIN. +

+ +

+ AS TO THE RESULTS THAT MAY BE OBTAINED FROM THE USE OF THE PRODUCTS OR + THAT DEFECTS IN PRODUCTS WILL BE CORRECTED. +

+ +

REGARDING ANY PRODUCTS PURCHASED OR OBTAINED THROUGH THE WEBSITE.

+ +

+ SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES, SO + SOME OF THE ABOVE EXCLUSIONS MAY NOT APPLY TO YOU. +

+ +

+ IV. Limitation of Liability +

+ +

+ SOMRAJ SAHA ENTIRE LIABILITY, AND YOUR EXCLUSIVE REMEDY, IN LAW, IN + EQUITY, OR OTHWERWISE, WITH RESPECT TO THE WEBSITE CONTENT AND PRODUCTS + AND/OR FOR ANY BREACH OF THIS AGREEMENT IS SOLELY LIMITED TO THE AMOUNT + YOU PAID, LESS SHIPPING AND HANDLING, FOR PRODUCTS AND/OR SERVICES + PURCHASED VIA THE WEBSITE. +

+ +

+ SOMRAJ SAHA WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH THIS AGREEMENT OR + THE PRODUCTS IN ANY MANNER, INCLUDING LIABILITIES RESULTING FROM (1) THE + USE OR THE INABILITY TO USE THE WEBSITE CONTENT OR PRODUCTS; (2) THE + COST OF PROCURING SUBSTITUTE PRODUCTS OR CONTENT; (3) ANY PRODUCTS + PURCHASED OR OBTAINED OR TRANSACTIONS ENTERED INTO THROUGH THE WEBSITE; + OR (4) ANY LOST PROFITS YOU ALLEGE. +

+ +

+ SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OR EXCLUSION OF LIABILITY + FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES SO SOME OF THE ABOVE LIMITATIONS + MAY NOT APPLY TO YOU. +

+ +

+ V. Indemnification +

+ +

+ You will release, indemnify, defend and hold harmless Somraj Saha, and + any of his contractors, agents, employees, officers, directors, + shareholders, affiliates and assigns from all liabilities, claims, + damages, costs and expenses, including reasonable attorneys' fees + and expenses, of third parties relating to or arising out of (1) this + Agreement or the breach of your warranties, representations and + obligations under this Agreement; (2) the Website content or your use of + the Website content; (3) the Products or your use of the Products + (including Trial Products); (4) any intellectual property or other + proprietary right of any person or entity; (5) your violation of any + provision of this Agreement; or (6) any information or data you supplied + to Somraj Saha. When Somraj Saha is threatened with suit or sued by a + third party, Somraj Saha may seek written assurances from you concerning + your promise to indemnify Somraj Saha; your failure to provide such + assurances may be considered by Somraj Saha to be a material breach of + this Agreement. Somraj Saha will have the right to participate in any + defense by you of a third-party claim related to your use of any of the + Website content or Products, with counsel of Somraj Saha's choice + at its expense. Somraj Saha will reasonably cooperate in any defense by + you of a third-party claim at your request and expense. You will have + sole responsibility to defend Somraj Saha against any claim, but you + must receive Somraj Saha a prior written consent regarding any related + settlement. The terms of this provision will survive any termination or + cancellation of this Agreement or your use of the Website or Products. +

+ +

VI. Privacy

+ +

+ Somraj Saha believes strongly in protecting user privacy and providing + you with notice of Somraj Saha's blog's use of data. Please + refer to Somraj Saha's{" "} + + Privacy Policy + + , incorporated by reference herein, that is posted on the Website. +

+ +

+ VII. Agreement to be Bound +

+ +

+ By using this Website, ordering Products and/or subscribing to our + Services, you acknowledge that you have read and agree to be bound by + this Agreement and all terms and conditions on this Website. +

+ +

+ VIII. General +

+ +

+ Force Majeure. Somaraj Saha will not be deemed in default hereunder or + held responsible for any cessation, interruption or delay in the + performance of its obligations hereunder due to earthquake, flood, fire, + storm, natural disaster, act of God, war, terrorism, armed conflict, + labor strike, lockout, or boycott. +

+ +

+ Cessation of Operation. Somraj Saha may at any time, in its sole + discretion and without advance notice to you, cease operation of the + Website and distribution of the Products. +

+ +

+ Entire Agreement. This Agreement comprises the entire agreement between + you and Somraj Saha and supersedes any prior agreements pertaining to + the subject matter contained herein. +

+ +

+ Effect of Waiver. The failure of Somraj Saha to exercise or enforce any + right or provision of this Agreement will not constitute a waiver of + such right or provision. If any provision of this Agreement is found by + a court of competent jurisdiction to be invalid, the parties + nevertheless agree that the court should endeavor to give effect to the + parties' intentions as reflected in the provision, and the other + provisions of this Agreement remain in full force and effect. +

+ +

+ Governing Law;{" "} + + Supreme Court of India + + . This Website originates from the city of Agartala in Tripura, India. + This Agreement will be governed by the laws of the State of India + without regard to its conflict of law principles to the contrary. + Neither you nor Somraj Saha will commence or prosecute any suit, + proceeding or claim to enforce the provisions of this Agreement, to + recover damages for breach of or default of this Agreement, or otherwise + arising under or by reason of this Agreement, other than in courts + located in State of India. By using this Website or ordering and/or + subscribing to our Products, you consent to the jurisdiction and venue + of such courts in connection with any action, suit, proceeding or claim + arising under or by reason of this Agreement. You hereby waive any right + to trial by jury arising out of this Agreement and any related + documents. +

+ +

+ Statute of Limitation. You agree that regardless of any statute or law + to the contrary, any claim or cause of action arising out of or related + to use of the Website or Products or this Agreement must be filed within + one (1) year after such claim or cause of action arose or be forever + barred. +

+ +

+ Waiver of Class Action Rights. BY ENTERING INTO THIS AGREEMENT, YOU + HEREBY IRREVOCABLY WAIVE ANY RIGHT YOU MAY HAVE TO JOIN CLAIMS WITH + THOSE OF OTHER IN THE FORM OF A CLASS ACTION OR SIMILAR PROCEDURAL + DEVICE. ANY CLAIMS ARISING OUT OF, RELATING TO, OR CONNECTION WITH THIS + AGREEMENT MUST BE ASSERTED INDIVIDUALLY. +

+ +

+ Termination. Somraj Saha reserves the right to terminate your access to + the Website if it reasonably believes, in its sole discretion, that you + have breached any of the terms and conditions of this Agreement. + Following termination, you will not be permitted to use the Website and + Somraj Saha may, in its sole discretion and without advance notice to + you, cancel any outstanding orders for Products. If your access to the + Website is terminated, Somraj Saha reserves the right to exercise + whatever means it deems necessary to prevent unauthorized access of the + Website. This Agreement will survive indefinitely unless and until + Somraj Saha chooses, in its sole discretion and without advance to you, + to terminate it. +

+ +

+ Domestic Use. Somraj Saha makes no representation that the Website or + Products are appropriate or available for use in locations outside + India. Users who access the Website from outside India do so at their + own risk and initiative and must bear all responsibility for compliance + with any applicable local laws. +

+ +

+ Assignment. You may not assign your rights and obligations under this + Agreement to anyone. Somraj Saha may assign its rights and obligations + under this Agreement in its sole discretion and without advance notice + to you. +

+ +

+ BY USING THIS WEBSITE OR ORDERING PRODUCTS FROM THIS WEBSITE YOU AGREE + TO BE BOUND BY ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. +

+
); }; diff --git a/tailwind.config.js b/tailwind.config.js index 408ab029..27f5e4db 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,10 +1,15 @@ +const { fontFamily } = require("tailwindcss/defaultTheme"); + /** * @type {import('tailwindcss').Config} */ +<<<<<<< HEAD +======= +>>>>>>> 5bf2ac47e95e3d0baa4af333a963409a852c4bac module.exports = { content: ["./src/**/*.{js,ts,jsx,tsx}"], - plugins: [require("@tailwindcss/typography")], + plugins: [], theme: { extend: { colors: { @@ -27,41 +32,6 @@ module.exports = { 30: "#83F9A2", }, }, - typography: (theme) => ({ - DEFAULT: { - css: { - code: { - color: theme("colors.gray.400"), - }, - h1: { - color: theme("colors.green.30"), - fontWeight: theme("fontWeight.bold"), - fontSize: theme("fontSize.3xl"), - }, - h2: { - color: theme("colors.green.10"), - fontWeight: theme("fontWeight.semibold"), - fontSize: theme("fontSize.2xl"), - }, - a: { - color: theme("colors.white.10"), - textDecorationColor: theme("colors.gray.100"), - }, - p: { - color: theme("colors.white.20"), - }, - li: { - color: theme("colors.white.20"), - }, - strong: { - color: theme("colors.white.20"), - }, - address: { - color: theme("colors.white.20"), - }, - }, - }, - }), }, }, };