{"id":16677503,"url":"https://github.com/foresterre/yare","last_synced_at":"2025-10-25T02:45:05.296Z","repository":{"id":54557007,"uuid":"325527234","full_name":"foresterre/yare","owner":"foresterre","description":"🛶 Lean parametrized testing library for Rust","archived":false,"fork":false,"pushed_at":"2024-12-10T22:28:58.000Z","size":100,"stargazers_count":24,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-10-04T07:29:46.923Z","etag":null,"topics":["crate","hacktoberfest","library","macros","parameterised","parameterised-tests","parameterized","parameterized-tests","parametrized","parametrized-tests","rust","rust-lang","test","testing","unit-test","unit-testing"],"latest_commit_sha":null,"homepage":"https://docs.rs/yare","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/foresterre.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE-APACHE","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},"funding":{"github":["foresterre"],"buy_me_a_coffee":"foresterre","thanks_dev":"u/gh/foresterre"}},"created_at":"2020-12-30T10:59:20.000Z","updated_at":"2025-08-30T00:34:21.000Z","dependencies_parsed_at":"2023-12-27T00:22:39.423Z","dependency_job_id":"848fc47a-f81d-4fa8-a461-46efac410ca5","html_url":"https://github.com/foresterre/yare","commit_stats":{"total_commits":32,"total_committers":3,"mean_commits":"10.666666666666666","dds":0.09375,"last_synced_commit":"90dac038d094544d59996454ee96a160c2993765"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/foresterre/yare","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foresterre%2Fyare","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foresterre%2Fyare/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foresterre%2Fyare/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foresterre%2Fyare/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/foresterre","download_url":"https://codeload.github.com/foresterre/yare/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foresterre%2Fyare/sbom","scorecard":{"id":406858,"data":{"date":"2025-08-11","repo":{"name":"github.com/foresterre/yare","commit":"ed4d041f148c9bd9bde7aa6866f70c96197414b5"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.8,"checks":[{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Code-Review","score":0,"reason":"Found 0/12 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/fmt.yml:1","Warn: no topLevel permission defined: .github/workflows/licenses_and_advisories.yml:1","Warn: no topLevel permission defined: .github/workflows/linter.yml:1","Warn: no topLevel permission defined: .github/workflows/msrv.yml:1","Warn: no topLevel permission defined: .github/workflows/test.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/fmt.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/foresterre/yare/fmt.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/fmt.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/foresterre/yare/fmt.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/licenses_and_advisories.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/foresterre/yare/licenses_and_advisories.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/licenses_and_advisories.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/foresterre/yare/licenses_and_advisories.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/linter.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/foresterre/yare/linter.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/linter.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/foresterre/yare/linter.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/linter.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/foresterre/yare/linter.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/msrv.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/foresterre/yare/msrv.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/msrv.yml:30: update your workflow using https://app.stepsecurity.io/secureworkflow/foresterre/yare/msrv.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:39: update your workflow using https://app.stepsecurity.io/secureworkflow/foresterre/yare/test.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/test.yml:42: update your workflow using https://app.stepsecurity.io/secureworkflow/foresterre/yare/test.yml/main?enable=pin","Info:   0 out of   5 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   6 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE-APACHE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE-APACHE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 29 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-18T21:30:44.004Z","repository_id":54557007,"created_at":"2025-08-18T21:30:44.004Z","updated_at":"2025-08-18T21:30:44.004Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280897410,"owners_count":26409957,"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-10-25T02:00:06.499Z","response_time":81,"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":["crate","hacktoberfest","library","macros","parameterised","parameterised-tests","parameterized","parameterized-tests","parametrized","parametrized-tests","rust","rust-lang","test","testing","unit-test","unit-testing"],"created_at":"2024-10-12T13:26:38.394Z","updated_at":"2025-10-25T02:45:05.242Z","avatar_url":"https://github.com/foresterre.png","language":"Rust","funding_links":["https://github.com/sponsors/foresterre","https://buymeacoffee.com/foresterre","https://thanks.dev/u/gh/foresterre"],"categories":[],"sub_categories":[],"readme":"# Yare ⛵\n\nA lean procedural macro based _parameterized testing library_. Run a test case with many different inputs.\nPatameterized test cases are defined using the 'parameterized' attribute instead of a default 'test' attribute.\n\n**Features**\n\n- **Parameterized Testing:** Specify different inputs to test multiple scenarios with a single test definition.\n- **Be flexible:** Arguments provided to parameterized test cases are expressions. \n- **Works out of the box:** Works with any Rust version out of the box. No custom test harness necessary.\n- **Concise yet comprehensive:** Minimalstic doesn't need to mean 'featureless'.    \n- **Familiar syntax:** Maintains code readability with familiar Rustic syntax.\n- **Promotes :** Each test case has a user defined name which can be referred back to, and can be used to run\n  individual test cases.\n- **Battle tested:** Used for years in tests of\n  the [cargo-msrv](https://crates.io/crates/cargo-msrv), [bisector](https://crates.io/crates/bisector)\n  and [rust-releases](https://crates.io/crates/rust-releases) crates (amongst others).\n\n## Table of contents\n\n* [Introduction](#yare-)\n* [Examples](#examples-back-to-top)\n* [Arguments are expressions](#arguments-are-expressions-back-to-top)\n* [Custom test macro (e.g. tokio::test)](#custom-test-macro-eg-tokiotest-back-to-top)\n* [Return types](#return-types-back-to-top)\n* [Function qualifiers](#function-qualifiers-back-to-top)\n* [Global #[parameterized(...)] import](#globally-importing-parameterized-back-to-top)\n* [Alternatives](#alternatives-back-to-top)\n* [License](#license-back-to-top)\n\n## Examples \u003csup\u003e(\u003ca href=\"#yare-\"\u003eback to top\u003c/a\u003e)\u003c/sup\u003e\n\n**A first example**\n\n```rust\nfn add5\u003cT: Into\u003cu32\u003e\u003e(component: T) -\u003e u32 {\n    component.into() + 5\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use yare::parameterized;\n\n    #[parameterized(\n      zero_plus_five = { 0, 5 },\n      one_plus_five = { 1, 6 },\n      two_plus_five = { 2, 7 },\n    )]\n    fn test_add5(input: u16, expected: u32) {\n        assert_eq!(add5(input), expected);\n    }\n}\n```\n\n**An example with values**\n\n```rust\nenum Fruit {\n    Apple,\n    Bramble(BrambleFruit),\n    Pear,\n}\n\ntrait NameOf {\n    fn name_of(\u0026self) -\u003e \u0026str;\n}\n\nimpl NameOf for Fruit {\n    fn name_of(\u0026self) -\u003e \u0026str {\n        match self {\n            Fruit::Apple =\u003e \"apple\",\n            Fruit::Bramble(fruit) =\u003e fruit.name_of(),\n            Fruit::Pear =\u003e \"pear\",\n        }\n    }\n}\n\nenum BrambleFruit {\n    Blackberry,\n}\n\nimpl NameOf for BrambleFruit {\n    fn name_of(\u0026self) -\u003e \u0026str {\n        match self {\n            BrambleFruit::Blackberry =\u003e \"blackberry\",\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use yare::parameterized;\n\n    #[parameterized(\n      apple = { Fruit::Apple, \"apple\" },\n      pear = { Fruit::Pear, \"pear\" },\n      blackberry = { Fruit::Bramble(BrambleFruit::Blackberry), \"blackberry\" },\n    )]\n    fn a_fruity_test(fruit: Fruit, name: \u0026str) {\n        assert_eq!(fruit.name_of(), name)\n    }\n}\n```\n\n\u003cbr\u003e\n\n## Arguments are expressions \u003csup\u003e(\u003ca href=\"#yare-\"\u003eback to top\u003c/a\u003e)\u003c/sup\u003e\n\nWhile the arguments above were simple values, any expression can be used as argument in a test case.\n\n**Example**\n\nIn the example below, we [roll](https://github.com/foresterre/yare/blob/main/src/tests/dice.rs) the dice 3 times, to generate a seed for later roll_dice function calls.\nThe first argument `seed1` is a _function call_ to roll_dice. This randomness function is seeded with value `0`.\nThe second argument `seed2` is a _block expression_. In the expression the roll_dice function is called twice.\nThe test itself takes the maximum of `seed1` and `seed2`, rolls the die 1000 times, and checks that all values\nare valid for a d6 die.\n\n```rust\nuse std::sync::atomic::{AtomicU32, Ordering};\nuse yare::parameterized;\n\n#[parameterized(\n  // A complex input for the sake of showing that inputs are expressions...\n  seeding_randomness_with_two_dice_rolls = \n  {\n    roll_dice(\u0026AtomicU32::new(0)),                              // \u003c- This is an expression (a function call)\n    {                                                           // \u003c- This is also an expression (a block expression)\n      let from_half = roll_dice( \u0026AtomicU32::new(u32::MAX / 2));\n      let from_max = roll_dice( \u0026AtomicU32::new(u32::MAX));\n      \n      u8::min(from_half, from_max)\n    }\n  }\n)]\nfn dicey(seed1: u8, seed2: u8) {\n    // Creating a base seed in a complicated way for the sake of it.\n    let max = u8::max(seed1, seed2);\n    let seed = AtomicU32::new(u32::from(max));\n\n    let out_of_bounds_values = (0..1000)         // roll the dice 1000 times\n        .map(|_| roll_dice(\u0026seed))\n        .find(|value| !(1..=6).contains(value)); // check that the outputs of the dice are just 1, 2, 3, 4, 5 or 6. \n\n    assert!(out_of_bounds_values.is_none());\n}\n```\n\n## Custom test macro (e.g. tokio::test) \u003csup\u003e(\u003ca href=\"#yare-\"\u003eback to top\u003c/a\u003e)\u003c/sup\u003e\n\nBy default, the code generation step of the `parameterized` attribute will generate test cases marked with a `#[test]`\nattribute. For example, the `add5` test from the [examples](#examples-back-to-top) would generate something like:\n\n```rust\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use yare::parameterized;\n\n    // Approximate generated code from add5 example:\n    #[cfg(test)]\n    mod add5 {\n        use super::*;\n\n        #[test]\n        fn zero_plus_five() {\n            let input: u16 = 0;\n            let expected: u32 = 5;\n            assert_eq!(add5(input), expected);\n        }\n\n        #[test]\n        fn one_plus_five() {\n            let input: u16 = 1;\n            let expected: u32 = 6;\n            assert_eq!(add5(input), expected);\n        }\n\n        #[test]\n        fn two_plus_five() {\n            let input: u16 = 2;\n            let expected: u32 = 7;\n            assert_eq!(add5(input), expected);\n        }\n    }\n}\n```\n\nHowever, sometimes a different test macro is desired. An example is when writing tests for projects which depend on tokio.\nFor this, you may want to use `#[tokio::test]` (it also requires the test function to also have the `async` qualifier).\n\nIn Yare, it is possible to specify a custom test macro. To do so, you may add the `#[test_macro(...)]` attribute _after_\na `#[parameterized]` attribute.\n\n**Custom test macro example: tokio::test**\n\n```rust,ignore\nuse yare::parameterized;\n\n#[parameterized(\n    zero_wait = { 0, 0 },\n    show_paused = { 500, 0 },\n)]\n#[test_macro(tokio::test(start_paused = true))]\nasync fn test(wait: u64, time_elapsed: u128) {\n    let start = std::time::Instant::now();\n    tokio::time::sleep(tokio::time::Duration::from_millis(wait)).await;\n\n    assert_eq!(start.elapsed().as_millis(), time_elapsed);\n}\n```\n\nGotchas:\n\n* The `#[test_macro(...)]` must always be specified after a `#[parameterized(...)]` attribute.\n* Only one `#[test_macro(...)]` attribute per parameterized test function is allowed.\n* While you can rename the parameterized attribute using import aliassing (\n  e.g. `use yare::parameterized as pm`), the `test_macro` attribute cannot be renamed,\n  since it's not actually defined as a separate macro.\n  Instead, the `parameterized` macro parses this attribute as well.\n\n## Return types \u003csup\u003e(\u003ca href=\"#yare-\"\u003eback to top\u003c/a\u003e)\u003c/sup\u003e\n\nYare supports specifying a return type for a parameterized test function.\n\nNote that the underlying test attribute must also have support for return types.\nBy default, Yare generates individual test cases decorated with the\nfamiliar [test](https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute)\nattribute, which is included with any Rust distribution by default.\n\n**Example**\n\n```rust\nuse yare::parameterized;\n\n#[parameterized(\n  ok = { Ok(0) },\n  // err = {  Err(\"noes!\".to_string()) }, \u003c-- enabling this would result in a failed test, since the error code will not be an `ErrorCode::Success`. See the `Termination` trait for more.\n)]\nfn test(value: Result\u003cu32, String\u003e) -\u003e Result\u003c(), String\u003e {\n    let v = value?;\n\n    assert_eq!(v.unwrap(), 0);\n}\n\n```\n\n## Function qualifiers \u003csup\u003e(\u003ca href=\"#yare-\"\u003eback to top\u003c/a\u003e)\u003c/sup\u003e\n\nYare supports the following function qualifiers: `const`, `async`, `unsafe` and `extern`.\nThis is particularly useful if you use `#[parameterized(...)]` with a custom test macro such as `tokio::test`, instead\nof the built-in test macro.\n\n**Example**\n\n```rust\nuse yare::parameterized;\n\n#[parameterized(\n  purple = { \u0026 [128, 0, 128] },\n  orange = { \u0026 [255, 127, 0] },\n)]\nconst extern \"C\" fn has_reds(streamed_color: \u0026[u8]) {\n    assert!(streamed_color.first().is_some());\n}\n```\n\n## Globally importing parameterized \u003csup\u003e(\u003ca href=\"#yare-\"\u003eback to top\u003c/a\u003e)\u003c/sup\u003e\n\nIf you prefer not to import this library (with `use yare::parameterized;`) in every test module, you can put\nthe following snippet at the top of your crate root:\n\n```rust\n#[cfg(test)]\n#[macro_use]\nextern crate yare;\n```\n\n## Alternatives \u003csup\u003e(\u003ca href=\"#yare-\"\u003eback to top\u003c/a\u003e)\u003c/sup\u003e\n\nIf Yare is not quite what you're looking for, there are some alternatives:\n- [Parameterized](https://github.com/foresterre/parameterized): Attribute based macro with syntax inspired by JUnit (disclaimer: I authored this one too)\n- [Rstest](https://github.com/la10736/rstest)\n- [Test-case](https://github.com/frondeus/test-case)\n\n## License \u003csup\u003e(\u003ca href=\"#yare-\"\u003eback to top\u003c/a\u003e)\u003c/sup\u003e\n\nLicensed under either of \u003ca href=\"LICENSE-APACHE\"\u003eApache License, Version\n2.0\u003c/a\u003e or \u003ca href=\"LICENSE-MIT\"\u003eMIT license\u003c/a\u003e at your option.\n\n\u003cbr\u003e\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in this crate by you, as defined in the Apache-2.0 license, shall\nbe dual licensed as above, without any additional terms or conditions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fforesterre%2Fyare","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fforesterre%2Fyare","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fforesterre%2Fyare/lists"}