{"id":18507651,"url":"https://github.com/mihaiconstantin/parabar","last_synced_at":"2025-08-17T10:08:20.738Z","repository":{"id":66462790,"uuid":"564265909","full_name":"mihaiconstantin/parabar","owner":"mihaiconstantin","description":"An `R` package for parallelizing tasks, tracking their progress, and displaying accurate progress bars.","archived":false,"fork":false,"pushed_at":"2024-12-16T23:14:43.000Z","size":16284,"stargazers_count":21,"open_issues_count":5,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-09T20:44:15.996Z","etag":null,"topics":["parallel-computing","progress-bar","r"],"latest_commit_sha":null,"homepage":"https://parabar.mihaiconstantin.com","language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mihaiconstantin.png","metadata":{"files":{"readme":"README.md","changelog":"NEWS.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-10T10:53:45.000Z","updated_at":"2025-04-05T20:32:44.000Z","dependencies_parsed_at":null,"dependency_job_id":"6db1553c-8214-431c-a8c0-f773be3d8920","html_url":"https://github.com/mihaiconstantin/parabar","commit_stats":{"total_commits":509,"total_committers":1,"mean_commits":509.0,"dds":0.0,"last_synced_commit":"344297dabd6017c25f52ece32398336e9b10e2fe"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/mihaiconstantin/parabar","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mihaiconstantin%2Fparabar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mihaiconstantin%2Fparabar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mihaiconstantin%2Fparabar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mihaiconstantin%2Fparabar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mihaiconstantin","download_url":"https://codeload.github.com/mihaiconstantin/parabar/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mihaiconstantin%2Fparabar/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270832601,"owners_count":24653578,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-17T02:00:09.016Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["parallel-computing","progress-bar","r"],"created_at":"2024-11-06T15:10:57.826Z","updated_at":"2025-08-17T10:08:20.712Z","avatar_url":"https://github.com/mihaiconstantin.png","language":"R","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://parabar.mihaiconstantin.com\"\u003e\n        \u003cimg width=\"180px\" src=\"man/figures/logo.png\" alt=\"parabar logo\"/\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003e\n    Progress Bar for Parallel Tasks\n    \u003cbr\u003e\n    \u003csub\u003e...and more\u003c/sub\u003e\n\u003c/h1\u003e\n\n\u003c!-- badges: start --\u003e\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://www.repostatus.org/#active\"\u003e\u003cimg src=\"https://www.repostatus.org/badges/latest/active.svg\" alt=\"Repository status\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/mihaiconstantin/parabar/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/mihaiconstantin/parabar?display_name=tag\u0026sort=semver\" alt=\"GitHub version\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://cran.r-project.org/package=parabar \"\u003e\u003cimg src=\"https://www.r-pkg.org/badges/version/parabar\" alt=\"CRAN version\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://www.r-pkg.org/pkg/parabar\"\u003e\u003cimg src=\"https://cranlogs.r-pkg.org/badges/grand-total/parabar\" alt=\"CRAN RStudio mirror downloads\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://app.codecov.io/gh/mihaiconstantin/parabar\"\u003e\u003cimg src=\"https://codecov.io/gh/mihaiconstantin/parabar/branch/main/graph/badge.svg?token=1NZWRKQH1T\" alt=\"Code coverage\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/mihaiconstantin/parabar/actions\"\u003e\u003cimg src=\"https://github.com/mihaiconstantin/parabar/workflows/R-CMD-check/badge.svg\" alt=\"R-CMD-check\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://cran.r-project.org/web/checks/check_results_parabar.html\"\u003e\u003cimg src=\"https://badges.cranchecks.info/worst/parabar.svg\" alt=\"CRAN checks\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://parabar.mihaiconstantin.com\"\u003e\u003cimg src=\"https://img.shields.io/badge/docs-website-brightgreen\" alt=\"Documentation website\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://raw.githubusercontent.com/mihaiconstantin/parabar/main/inst/design/parabar-design.drawio.svg\"\u003e\u003cimg src=\"https://img.shields.io/badge/design-diagram-brightgreen\" alt=\"Software design diagram\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003c!-- badges: end --\u003e\n\n[`parabar`](https://parabar.mihaiconstantin.com) is a package designed to\nprovide a simple interface for executing tasks in parallel, while also providing\nfunctionality for tracking and displaying the progress of the tasks.\n\nThis package is aimed at two audiences: (1) end-users who want to execute a task\nin parallel in an interactive `R` session and track the execution progress, and\n(2) `R` package developers who want to use\n[`parabar`](https://parabar.mihaiconstantin.com) as a solution for parallel\nprocessing in their packages.\n\n## Installation\n\nYou can install `parabar` directly from `CRAN` using the following command:\n\n```r\n# Install the package from `CRAN`.\ninstall.packages(\"parabar\")\n\n# Load the package.\nlibrary(parabar)\n```\n\nAlternatively, you can also install the latest development version from `GitHub`\nvia:\n\n```r\n# Install the package from `GitHub`.\nremotes::install_github(\"mihaiconstantin/parabar\")\n\n# Load the package.\nlibrary(parabar)\n```\n\n## Usage\nBelow you can find a few examples of how to use\n[`parabar`](https://parabar.mihaiconstantin.com) in your `R` scripts, both for\nend-users, and for developers. All examples below assume that you have already\ninstalled and loaded the package.\n\n### Users\nIn general, the usage of [`parabar`](https://parabar.mihaiconstantin.com)\nconsists of the following steps:\n\n1. Start a backend for parallel processing.\n2. Execute a task in parallel.\n3. Stop the backend.\n\nOptionally, you can also configure the progress bar if the backend created\nsupports progress tracking, or perform additional operations on the backend.\n\n#### Synchronous Backend\nThe simplest, and perhaps least interesting, way to use\n[`parabar`](https://parabar.mihaiconstantin.com) is by requesting a synchronous\nbackend.\n\n```r\n# Start a synchronous backend.\nbackend \u003c- start_backend(cores = 4, cluster_type = \"psock\", backend_type = \"sync\")\n\n# Run a task in parallel.\nresults \u003c- par_sapply(backend, 1:1000, function(x) {\n    # Sleep a bit.\n    Sys.sleep(0.01)\n\n    # Compute and return.\n    x + 1\n})\n```\n\nAt this point you will notice the following warning message:\n\n```txt\nWarning message:\nProgress tracking not supported for backend of type 'SyncBackend'.\n```\n\nThe reason for this is because progress tracking only works for asynchronous\nbackends, and [`parabar`](https://parabar.mihaiconstantin.com) enables progress\ntracking by default at load time. We can disable this by option to get rid of\nthe warning message.\n\n```r\n# Disable progress tracking.\nset_option(\"progress_track\", FALSE)\n```\n\nWe can verify that the warning message is gone by running the task again,\nreusing the backend we created earlier.\n\n```r\n# Run a task in parallel.\nresults \u003c- par_sapply(backend, 1:1000, function(x) {\n    # Sleep a bit.\n    Sys.sleep(0.01)\n\n    # Compute and return.\n    x + 1\n})\n```\n\nWhen we are done with this backend, we can stop it to free up the resources.\n\n```r\n# Stop the backend.\nstop_backend(backend)\n```\n\n#### Asynchronous Backend\nThe more interesting way to use [`parabar`](https://parabar.mihaiconstantin.com)\nis by requesting an asynchronous backend. This is the default backend type, and\nhighlights the strengths of the package.\n\nFirst, let's ensure progress tracking is enabled (i.e., we disabled it above).\n\n```r\n# Enable progress tracking.\nset_option(\"progress_track\", TRUE)\n```\n\nNow, we can proceed with creating the backend and running the task.\n\n```r\n# Start an asynchronous backend.\nbackend \u003c- start_backend(cores = 4, cluster_type = \"psock\", backend_type = \"async\")\n\n# Run a task in parallel.\nresults \u003c- par_sapply(backend, 1:1000, function(x) {\n    # Sleep a bit.\n    Sys.sleep(0.01)\n\n    # Compute and return.\n    x + 1\n})\n```\n\nAt this point, we can see that the progress bar is displayed, and that the\nprogress is tracked. The progress bar is updated in real-time, after each task\nexecution, e.g.:\n\n```txt\n \u003e completed 928 out of 1000 tasks [ 93%] [ 3s]\n```\n\nWe can also configure the progress bar. For example, suppose we want to display\nan actual progress bar.\n\n```r\n# Change the progress bar options.\nconfigure_bar(type = \"modern\", format = \"[:bar] :percent\")\n\n# Run a task in parallel.\nresults \u003c- par_sapply(backend, 1:1000, function(x) {\n    # Sleep a bit.\n    Sys.sleep(0.01)\n\n    # Compute and return.\n    x + 1\n})\n```\n\nThe progress bar will now look like this:\n\n```txt\n[====================\u003e-------------------------------------------------]  30%\n```\n\nBy default, [`parabar`](https://parabar.mihaiconstantin.com) uses the\n[`progress`](https://cran.r-project.org/package=progress) package to display the\nprogress bar. However, we can easily swap it with another progress bar engine.\nFor example, suppose we want to use the built-in\n[`utils::txtProgressBar`](https://stat.ethz.ch/R-manual/R-devel/library/utils/html/txtProgressBar.html).\n\n```r\n# Change to and adjust the style of the `basic` progress bar.\nconfigure_bar(type = \"basic\", style = 3)\n\n# Run a task in parallel.\nresults \u003c- par_sapply(backend, 1:1000, function(x) {\n    # Sleep a bit.\n    Sys.sleep(0.01)\n\n    # Compute and return.\n    x + 1\n})\n```\n\nCheck out `?configure_bar` for more information on the possible ways of\nconfiguring the progress bar.\n\nWe can also disable the progress bar for asynchronous backends altogether, by\nadjusting the package options.\n\n```r\n# Disable progress tracking.\nset_option(\"progress_track\", FALSE)\n\n# Run a task in parallel.\nresults \u003c- par_sapply(backend, 1:1000, function(x) {\n    # Sleep a bit.\n    Sys.sleep(0.01)\n\n    # Compute and return.\n    x + 1\n})\n```\n\nWe can stop the backend when we are done.\n\n```r\n# Stop the backend.\nstop_backend(backend)\n```\n\n#### No Backend\nFinally, we can also the `?par_sapply` function without a backend, which will\nresort to running the task sequentially by means of\n[`utils::sapply`](https://stat.ethz.ch/R-manual/R-devel/library/base/html/lapply.html).\n\n\n```r\n# Run the task sequentially using the `base::sapply`.\nresults \u003c- par_sapply(backend = NULL, 1:300, function(x) {\n    # Sleep a bit.\n    Sys.sleep(0.01)\n\n    # Compute and return.\n    x + 1\n})\n```\n\n#### Additional Operations\nAs indicated above, the general workflow consists of starting a backend,\nexecuting a task in parallel, and stopping the backend. However, there are\nadditional operations that can be performed on a backend (i.e., see\n_**Developers**_ section). The table below lists all available operations that\ncan be performed on a backend.\n\n| Operation                                                                                                                    | Description                                   |\n| :--------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------- |\n| \u003ccode\u003e\u003ca href=\"https://parabar.mihaiconstantin.com/reference/start_backend.html\"\u003estart_backend(backend)\u003c/a\u003e\u003c/code\u003e           | Start a backend.                              |\n| \u003ccode\u003e\u003ca href=\"https://parabar.mihaiconstantin.com/reference/stop_backend.html\"\u003estop_backend(backend)\u003c/a\u003e\u003c/code\u003e             | Stop a backend.                               |\n| \u003ccode\u003e\u003ca href=\"https://parabar.mihaiconstantin.com/reference/clear.html\"\u003eclear(backend)\u003c/a\u003e\u003c/code\u003e                           | Remove all objects from a backend.            |\n| \u003ccode\u003e\u003ca href=\"https://parabar.mihaiconstantin.com/reference/peek.html\"\u003epeek(backend)\u003c/a\u003e\u003c/code\u003e                             | List the names of the variables on a backend. |\n| \u003ccode\u003e\u003ca href=\"https://parabar.mihaiconstantin.com/reference/export.html\"\u003eexport(backend, variables, environment)\u003c/a\u003e\u003c/code\u003e | Export objects to a backend.                  |\n| \u003ccode\u003e\u003ca href=\"https://parabar.mihaiconstantin.com/reference/evaluate.html\"\u003eevaluate(backend, expression)\u003c/a\u003e\u003c/code\u003e         | Evaluate expressions on a backend.            |\n| \u003ccode\u003e\u003ca href=\"https://parabar.mihaiconstantin.com/reference/par_sapply.html\"\u003epar_sapply(backend, x, fun)\u003c/a\u003e\u003c/code\u003e         | Run tasks in parallel on a backend.           |\n| \u003ccode\u003e\u003ca href=\"https://parabar.mihaiconstantin.com/reference/par_lapply.html\"\u003epar_lapply(backend, x, fun)\u003c/a\u003e\u003c/code\u003e         | Run tasks in parallel on a backend.           |\n| \u003ccode\u003e\u003ca href=\"https://parabar.mihaiconstantin.com/reference/par_apply.html\"\u003epar_apply(backend, x, margin, fun)\u003c/a\u003e\u003c/code\u003e   | Run tasks in parallel on a backend.           |\n\nCheck the documentation corresponding to each operation for more information and\nexamples.\n\n### Developers\n[`parabar`](https://parabar.mihaiconstantin.com) provides a rich API for\ndevelopers who want to use the package in their own projects.\n\nFrom a high-level perspective, the package consists of **`backends`** and\n**`contexts`** in which these backends are employed for executing tasks in\nparallel.\n\n#### Backends\nA **`backend`** represents a set of operations, defined by the `?BackendService`\ninterface. Backends can be synchronous (i.e., `?SyncBackend`) or asynchronous\n(i.e., `?AsyncBackend`). The former will block the execution of the current `R`\nsession until the parallel task is completed, while the latter will return\nimmediately and the task will be executed in a background `R` session.\n\nThe `?BackendService` interface defines the following operations:\n\n- `start`: Start the backend.\n- `stop`: Stop the backend.\n- `clear`: Remove all objects from the backend.\n- `peek`: Show the variables names available on the backend.\n- `export`: Export variables from a given environment to the backend.\n- `evaluate`: Evaluate an arbitrary expression on the backend.\n- `sapply`: Run a task on the backend.\n- `lapply`: Run a task on the backend.\n- `apply`: Run a task on the backend.\n- `get_output`: Get the output of the task execution.\n\nCheck out the documentation for `BackendService` for more information on each\nmethod.\n\n#### Contexts\nA **`context`** represents the specific conditions in which a backend object\noperates. The default context class (i.e., `?Context`) simply forwards the call\nto the corresponding backend method. However, a more complex context can augment\nthe operation before forwarding the call to the backend. One example of a\ncomplex context is the `?ProgressTrackingContext` class. This class extends the\nregular `?Context` class and decorates, e.g., the backend `sapply` operation to\nlog the progress after each task execution and display a progress bar.\n\n#### Main Classes\nThe following are the main classes provided by\n[`parabar`](https://parabar.mihaiconstantin.com):\n\n- `BackendService`: Interface for backend operations.\n- `SyncBackend`: Synchronous backend extending the abstract `Backend` class and\n  implementing the `BackendService` interface.\n- `AsyncBackend`: Asynchronous backend extending the abstract `Backend` class\n  and implementing the `BackendService` interface.\n- `Specification`: Backend specification used when starting a backend.\n- `BackendFactory`: Factory for creating `Backend` objects.\n- `Context`: Default context for executing backend operations without\n  interference.\n- `ProgressTrackingContext`: Context for decorating the `sapply` operation to\n  track and display the progress.\n- `ContextFactory`: Factory for creating `Context` objects.\n- `UserApiConsumer`: Wrapper around the developer `API`.\n\nAdditionally, [`parabar`](https://parabar.mihaiconstantin.com) also provides\nseveral classes for creating and updating different progress bars, namely:\n\n- `BasicBar`: A simple, but robust, bar created via\n  [`utils::txtProgressBar`](https://stat.ethz.ch/R-manual/R-devel/library/utils/html/txtProgressBar.html)\n  extending the `Bar` abstract class.\n- `ModernBar`: A modern bar created via\n  [`progress::progress_bar`](https://cran.r-project.org/package=progress)\n  extending the `Bar` abstract class.\n- `BarFactory`: Factory for creating `Bar` objects.\n\n#### Examples\nBelow there is an example of how to use the package\n[`R6`](https://adv-r.hadley.nz/r6.html) class API.\n\nWe start by creating a `?Specification` object instructing the `?Backend` object\nhow to create a cluster via the built-in function\n[`parallel::makeCluster`](https://stat.ethz.ch/R-manual/R-devel/library/parallel/html/makeCluster.html).\n\n```r\n# Create a specification object.\nspecification \u003c- Specification$new()\nspecification$set_cores(4)\nspecification$set_type(\"psock\")\n```\n\nWe proceed by obtaining an asynchronous backend instance from the\n`?BackendFactory` and starting the backend using the `?Specification` instance\nabove.\n\n```r\n# Create a backend factory.\nbackend_factory \u003c- BackendFactory$new()\n\n# Get an asynchronous backend instance.\nbackend \u003c- backend_factory$get(\"async\")\n\n# Start the backend.\nbackend$start(specification)\n```\n\nFinally, we can run a task in parallel by calling, e.g., the `sapply` method on\nthe `backend` instance.\n\n```r\n# Run a task in parallel.\nbackend$sapply(1:1000, function(x) {\n    # Sleep a bit.\n    Sys.sleep(0.01)\n\n    # Compute and return.\n    x + 1\n})\n```\n\nAt this point, the task was deployed in a background `R` session, and the caller\nprocess is free to do other things.\n\nCalling `backend$get_output` immediately after the `backend$sapply` call will\nthrow an error, indicating that the task is still running, i.e.:\n\n```txt\nError: A task is currently running.\n```\n\nWe can, however, block the caller process and wait for the task to complete\nbefore fetching the results.\n\n```r\nresults \u003c- backend$get_output(wait = TRUE)\n```\n\nWe can now introduce the `context` concept to decorate the `backend` instance\nand, in this example, track the progress of the task. First, we obtain an\n`?Context` instance from the `?ContextFactory`. Furthermore, since we are using\nan asynchronous backend, we can request a context that facilitates\nprogress-tracking.\n\n```r\n# Create a context factory.\ncontext_factory \u003c- ContextFactory$new()\n\n# Get a progress-tracking context.\ncontext \u003c- context_factory$get(\"progress\")\n\n# Register the backend with the context.\ncontext$set_backend(backend)\n```\n\nThe `?Context` class (i.e., and it's subclasses) implements the\n`?BackendService` interface, which means that we can use it to execute backend\noperations.\n\nSince we are using the `?ProgressTrackingContext` context, we also need to\nregister a `?Bar` instance with the context. First, let's obtain a `?Bar`\ninstance from the `?BarFactory`.\n\n```r\n# Create a bar factory.\nbar_factory \u003c- BarFactory$new()\n\n# Get a `modern` bar (i.e., via `progress::progress_bar`).\nbar \u003c- bar_factory$get(\"modern\")\n```\n\nWe can now register the `bar` instance with the `context` instance.\n\n```r\n# Register the `bar` with the `context`.\ncontext$set_bar(bar)\n```\n\nWe may also configure the `bar`, or change its appearance. For instance, it may\nbe a good idea is to show the progress bar right away.\n\n```r\n# Configure the `bar`.\ncontext$configure_bar(\n    show_after = 0,\n    format = \" \u003e completed :current out of :total tasks [:percent] [:elapsed]\"\n)\n```\n\nAt this point, the `backend$sapply` operation is decorated with progress\ntracking. Finally, we can run the task in parallel and enjoy our progress bar\nusing the `context` instance.\n\n```r\n# Run a task in parallel with progress tracking.\ncontext$sapply(1:1000, function(x) {\n    # Sleep a bit.\n    Sys.sleep(0.01)\n\n    # Compute and return.\n    x + 1\n})\n```\n\nAll there is left to do is to fetch the results and stop the backend.\n\n```r\n# Get the results.\nresults \u003c- context$get_output()\n\n# Stop the backend.\ncontext$stop()\n```\n\n#### Design\nCheck out the UML diagram below for a quick overview of the package design.\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://raw.githubusercontent.com/mihaiconstantin/parabar/main/inst/design/parabar-design.drawio.svg\"\u003e\n        \u003cimg src=\"man/figures/parabar-design.png\" alt=\"parabar Software Design\"/\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n**_Note._** For the sake of clarity, the diagram only displays the `sapply`\noperation for running tasks in parallel. However, other operations are supported\nas well (i.e., see table in the section *Additional Operations*).\n\n## Contributing\n- Any contributions are welcome and greatly appreciated. Please open a [pull\n  request](https://github.com/mihaiconstantin/parabar/pulls) on `GitHub`.\n- To report bugs, or request new features, please open an\n  [issue](https://github.com/mihaiconstantin/parabar/issues) on `GitHub`.\n\n## License\n- The package source code in this repository is licensed under the [MIT\n  license](https://opensource.org/license/mit).\n- \u003cp class=\"license-cc\" xmlns:cc=\"https://creativecommons.org/ns#\" xmlns:dct=\"https://purl.org/dc/terms/\"\u003e\u003ca property=\"dct:title\" rel=\"cc:attributionURL\" href=\"https://parabar.mihaiconstantin.com\"\u003eThe documentation, vignettes, and other website materials\u003c/a\u003e by \u003ca rel=\"cc:attributionURL dct:creator\" property=\"cc:attributionName\" href=\"https://mihaiconstantin.com\"\u003eMihai Constantin\u003c/a\u003e are licensed under \u003ca href=\"https://creativecommons.org/licenses/by/4.0/?ref=chooser-v1\" target=\"_blank\" rel=\"license noopener noreferrer\" style=\"display:inline-block;\"\u003eCC BY 4.0 \u003cimg style=\"height:22px!important\" src=\"https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1\"\u003e \u003cimg style=\"height:22px!important\" src=\"https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1\"\u003e\u003c/a\u003e.\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmihaiconstantin%2Fparabar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmihaiconstantin%2Fparabar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmihaiconstantin%2Fparabar/lists"}