Comparing version 1.0.1 to 1.0.2
@@ -8,4 +8,2 @@ //// ____ _ _ | ||
//// | ||
/*global define FantasyLand inspectf*/ | ||
(function(global, f){ | ||
@@ -20,8 +18,8 @@ | ||
else if(typeof define === 'function' && define.amd){ | ||
define(['fantasy-land', 'inspect-x', 'inspect-f'], f); | ||
else if(typeof global.define === 'function' && global.define.amd){ | ||
global.define(['fantasy-land', 'inspect-f'], f); | ||
} | ||
else{ | ||
global.Fluture = f(FantasyLand, inspectf); | ||
global.Fluture = f(global.FantasyLand, global.inspectf); | ||
} | ||
@@ -28,0 +26,0 @@ |
{ | ||
"name": "fluture", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"description": "A mathematically correct alternative to Promises for asynchronous control flow", | ||
@@ -9,3 +9,3 @@ "main": "fluture.js", | ||
"check-security": "nsp check", | ||
"check-version": "node scripts/check-version 5.0.0", | ||
"check-version": "node scripts/check-version 4.0.0", | ||
"clean": "rimraf npm-debug.log coverage", | ||
@@ -16,2 +16,3 @@ "lint": "eslint fluture.js test", | ||
"setup": "npm run post-merge && cp scripts/hooks/* .git/hooks && git config push.followTags true", | ||
"toc": "node scripts/toc.js", | ||
"test": "npm run check-version && npm run clean && npm run lint && npm run test:unit && npm run test:coverage", | ||
@@ -29,3 +30,3 @@ "test:opt": "node --allow-natives-syntax --trace-opt --trace-deopt --trace-inlining scripts/test-opt", | ||
"engines": { | ||
"node": "^5.0.0" | ||
"node": "^4.0.0" | ||
}, | ||
@@ -65,2 +66,3 @@ "files": [ | ||
"lazy-either": "^1.0.3", | ||
"markdown-toc": "^0.12.6", | ||
"mocha": "^2.3.3", | ||
@@ -67,0 +69,0 @@ "nsp": "^2.2.0", |
447
README.md
@@ -8,3 +8,3 @@ # Fluture | ||
[![Build Status](https://travis-ci.org/Avaq/Fluture.svg?branch=master)](https://travis-ci.org/Avaq/Fluture) | ||
[![Code Coverage](https://codecov.io/github/Avaq/Fluture/coverage.svg?branch=master)](https://codecov.io/github/Avaq/Fluture/fluture.js?branch=master) | ||
[![Code Coverage](https://codecov.io/gh/Avaq/Fluture/branch/master/graph/badge.svg)](https://codecov.io/gh/Avaq/Fluture) | ||
@@ -16,16 +16,42 @@ Futures are containers which represent some eventual value as a result of an | ||
> `npm install --save fluture` <sup>Requires a node 5.0.0 compatible environment | ||
like modern browsers, transpilers or Node 5+</sup> | ||
> `npm install --save fluture` <sup>Requires a node 4.0.0 compatible environment | ||
like modern browsers, transpilers or Node 4+</sup> | ||
## Table of contents | ||
- [Table of contents](#table-of-contents) | ||
- [Usage](#usage) | ||
- [Motivation and Features](#motivation-and-features) | ||
- [Documentation](#documentation) | ||
- [Type signatures](#type-signatures) | ||
- [Creation](#creation) | ||
- [Method API](#method-api) | ||
- [Dispatcher API](#dispatcher-api) | ||
- [Utility functions](#utility-functions) | ||
- [Futurization](#futurization) | ||
1. [Type signatures](#type-signatures) | ||
1. [Creating Futures](#creating-futures) | ||
* [Future](#future) | ||
* [of](#of) | ||
* [reject](#reject) | ||
* [after](#after) | ||
* [cast](#cast) | ||
* [try](#try) | ||
* [encase](#encase) | ||
* [node](#node) | ||
1. [Consuming Futures](#consuming-futures) | ||
* [fork](#fork) | ||
* [value](#value) | ||
* [promise](#promise) | ||
1. [Transforming Futures](#transforming-futures) | ||
* [map](#map) | ||
* [mapRej](#maprej) | ||
* [bimap](#bimap) | ||
* [chain](#chain) | ||
* [chainRej](#chainrej) | ||
* [ap](#ap) | ||
* [fold](#fold) | ||
1. [Parallelism](#parallelism) | ||
* [race](#race) | ||
* [or](#or) | ||
* [parallel](#parallel) | ||
1. [Utility functions](#utility-functions) | ||
* [isFuture](#isfuture) | ||
* [isForkable](#isforkable) | ||
* [do](#do) | ||
1. [Futurization](#futurization) | ||
- [Benchmarks](#benchmarks) | ||
@@ -36,4 +62,2 @@ - [The name](#the-name) | ||
Using the low level, high performance [method API](#method-api): | ||
```js | ||
@@ -50,17 +74,2 @@ const Future = require('fluture'); | ||
Or use the high level, fully curried, [functional dispatch API](#dispatcher-api) | ||
for function composition using composers like [`S.pipe`][2]: | ||
```js | ||
const {node, chain, encase, map, fork} = require('fluture'); | ||
const program = S.pipe([ | ||
file => node(fs.readFile.bind(fs, file, 'utf8')), | ||
chain(encase(JSON.parse)), | ||
map(x => x.name), | ||
fork(console.error, console.log) | ||
]); | ||
program('package.json') | ||
//> "fluture" | ||
``` | ||
## Motivation and Features | ||
@@ -72,5 +81,3 @@ | ||
* Plenty of async control utilites like | ||
[Future.parallel](#parallel--positiveinteger---future-a-b---future-a-b) and | ||
[Future#race](#race--future-a-b--future-a-b---future-a-b). | ||
* Plenty of async control utilites like [Future.parallel](#parallel) and [Future#race](#race). | ||
* High performance. | ||
@@ -100,5 +107,6 @@ | ||
### Creation | ||
### Creating Futures | ||
#### `Future :: ((a -> Void), (b -> Void) -> Void) -> Future a b` | ||
#### Future | ||
##### `Future :: ((a -> Void), (b -> Void) -> Void) -> Future a b` | ||
@@ -124,3 +132,4 @@ The Future constructor. Creates a new instance of Future by taking a single | ||
#### `of :: a -> Future _ a` | ||
#### of | ||
##### `.of :: a -> Future _ a` | ||
@@ -140,3 +149,4 @@ Creates a Future which immediately resolves with the given value. This function | ||
#### `reject :: a -> Future a _` | ||
#### reject | ||
##### `.reject :: a -> Future a _` | ||
@@ -146,3 +156,4 @@ Creates a Future which immediately rejects with the given value. Just like `of` | ||
#### `after :: Number -> b -> Future a b` | ||
#### after | ||
##### `.after :: Number -> b -> Future a b` | ||
@@ -157,3 +168,4 @@ Creates a Future which resolves with the given value after n milliseconds. | ||
#### `cast :: Forkable a b -> Future a b` | ||
#### cast | ||
##### `.cast :: Forkable a b -> Future a b` | ||
@@ -167,3 +179,4 @@ Cast any [Forkable](#type-signatures) to a [Future](#type-signatures). | ||
#### `try :: (Void -> !a | b) -> Future a b` | ||
#### try | ||
##### `.try :: (Void -> !a | b) -> Future a b` | ||
@@ -182,3 +195,6 @@ Creates a Future which resolves with the result of calling the given function, | ||
#### `encase :: (a -> !e | r) -> a -> Future e r` | ||
#### encase | ||
##### `.encase :: (a -> !e | r) -> a -> Future e r` | ||
##### `.encase2 :: (a, b -> !e | r) -> a -> b -> Future e r` | ||
##### `.encase3 :: (a, b, c -> !e | r) -> a -> b -> c -> Future e r` | ||
@@ -195,12 +211,5 @@ Creates a Future which resolves with the result of calling the given function | ||
#### `encase2 :: (a, b -> !e | r) -> a -> b -> Future e r` | ||
#### node | ||
##### `.node :: ((a, b -> Void) -> Void) -> Future a b` | ||
Binary version of `Future.encase`. | ||
#### `encase3 :: (a, b, c -> !e | r) -> a -> b -> c -> Future e r` | ||
Ternary version of `Future.encase`. | ||
#### `node :: ((a, b -> Void) -> Void) -> Future a b` | ||
Creates a Future which rejects with the first argument given to the function, | ||
@@ -219,50 +228,8 @@ or resolves with the second if the first is not present. | ||
#### `parallel :: PositiveInteger -> Array (Future a b) -> Future a (Array b)` | ||
### Consuming Futures | ||
Creates a Future which when forked runs all Futures in the given `array` in | ||
parallel, ensuring no more than `limit` Futures are running at once. | ||
#### fork | ||
##### `#fork :: Future a b ~> (a -> Void), (b -> Void) -> Void` | ||
##### `.fork :: (a -> Void) -> (b -> Void) -> Future a b -> Void` | ||
```js | ||
const tenFutures = Array.from(Array(10).keys()).map(Future.after(20)); | ||
//Runs all Futures in sequence: | ||
Future.parallel(1, tenFutures).fork(console.error, console.log); | ||
//after about 200ms: | ||
//> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | ||
//Runs upto five Futures in parallel: | ||
Future.parallel(5, tenFutures).fork(console.error, console.log); | ||
//after about 40ms: | ||
//> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | ||
//Runs all Futures in parallel: | ||
Future.parallel(Infinity, tenFutures).fork(console.error, console.log); | ||
//after about 20ms: | ||
//> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | ||
``` | ||
If you want to settle all Futures, even if some may fail, you can use this in | ||
combination with [fold](#fold--future-a-b--a---c-b---c---future-_-c): | ||
```js | ||
const fourInstableFutures = Array.from(Array(4).keys()).map( | ||
i => Future( | ||
(rej, res) => setTimeout( | ||
() => Math.random() > 0.8 ? rej('failed') : res(i), | ||
20 | ||
) | ||
) | ||
); | ||
const stabalizedFutures = fourInstableFutures.map(Future.fold(S.Left, S.Right)) | ||
Future.parallel(2, stabalizedFutures).fork(console.error, console.log); | ||
//after about 40ms: | ||
//> [ Right(0), Left("failed"), Right(2), Right(3) ] | ||
``` | ||
### Method API | ||
#### `fork :: Future a b ~> (a -> Void), (b -> Void) -> Void` | ||
Execute the Future by calling the `fork` function that was passed to it at | ||
@@ -285,6 +252,44 @@ [construction](#creation) with the `reject` and `resolve` callbacks. Futures are | ||
//> "Oh no! It broke!" | ||
const consoleFork = Future.fork(console.error, console.log); | ||
consoleFork(Future.of('Hello')); | ||
//> "Hello" | ||
``` | ||
#### `map :: Future a b ~> (b -> c) -> Future a c` | ||
#### value | ||
##### `#value :: Future a b ~> (b -> Void) -> Void` | ||
##### `.value :: (b -> Void) -> Future a b -> Void` | ||
Extracts the value from a resolved Future by forking it. Only use this function | ||
if you are sure the Future is going to be resolved, for example; after using | ||
`.fold()`. If the Future rejects and `value` was used, an (likely uncatchable) | ||
`Error` will be thrown. | ||
```js | ||
Future.reject(new Error('It broke')) | ||
.fold(S.Left, S.Right) | ||
.value(console.log) | ||
//> Left([Error: It broke]) | ||
``` | ||
#### promise | ||
##### `#promise :: Future a b ~> Promise b a` | ||
##### `.promise :: Future a b -> Promise b a` | ||
An alternative way to `fork` the Future. This eagerly forks the Future and | ||
returns a Promise of the result. This is useful if some API wants you to give it | ||
a Promise. It's the only method which forks the Future without a forced way to | ||
handle the rejection branch, which means it's considered dangerous to use. | ||
```js | ||
Future.of('Hello').promise().then(console.log); | ||
//> "Hello" | ||
``` | ||
### Transforming Futures | ||
#### map | ||
##### `#map :: Future a b ~> (b -> c) -> Future a c` | ||
##### `.map :: Functor m => (a -> b) -> m a -> m b` | ||
Transforms the resolution value inside the Future, and returns a new Future with | ||
@@ -304,3 +309,5 @@ the transformed value. This is like doing `promise.then(x => x + 1)`, except | ||
#### `mapRej :: Future a b ~> (a -> c) -> Future c b` | ||
#### mapRej | ||
##### `#mapRej :: Future a b ~> (a -> c) -> Future c b` | ||
##### `.mapRej :: (a -> b) -> Future a c -> Future b c` | ||
@@ -318,3 +325,5 @@ Map over the **rejection** reason of the Future. This is like `map`, but for the | ||
#### `bimap :: Future a b ~> (a -> c) -> (b -> d) -> Future c d` | ||
#### bimap | ||
##### `#bimap :: Future a b ~> (a -> c) -> (b -> d) -> Future c d` | ||
##### `.bimap :: Bifunctor m => (a -> b) -> (c -> d) -> m a c -> m b d` | ||
@@ -336,3 +345,5 @@ Maps the left function over the rejection value, or the right function over the | ||
#### `chain :: Future a b ~> (b -> Future a c) -> Future a c` | ||
#### chain | ||
##### `#chain :: Future a b ~> (b -> Future a c) -> Future a c` | ||
##### `.chain :: Chain m => (a -> m b) -> m a -> m b` | ||
@@ -352,3 +363,5 @@ Allows the creation of a new Future based on the resolution value. This is like | ||
#### `chainRej :: Future a b ~> (a -> Future a c) -> Future a c` | ||
#### chainRej | ||
##### `#chainRej :: Future a b ~> (a -> Future a c) -> Future a c` | ||
##### `.chainRej :: (a -> Future a c) -> Future a b -> Future a c` | ||
@@ -367,3 +380,5 @@ Chain over the **rejection** reason of the Future. This is like `chain`, but for | ||
#### `ap :: Future a (b -> c) ~> Future a b -> Future a c` | ||
#### ap | ||
##### `#ap :: Future a (b -> c) ~> Future a b -> Future a c` | ||
##### `.ap :: Apply m => m (a -> b) -> m a -> m b` | ||
@@ -383,39 +398,6 @@ Apply the resolution value, which is expected to be a function (as in | ||
#### `race :: Future a b ~> Future a b -> Future a b` | ||
#### fold | ||
##### `#fold :: Future a b ~> (a -> c), (b -> c) -> Future _ c` | ||
##### `.fold :: (a -> c) -> (b -> c) -> Future a b -> Future _ c` | ||
Race two Futures against each other. Creates a new Future which resolves or | ||
rejects with the resolution or rejection value of the first Future to settle. | ||
```js | ||
Future.after(100, 'hello') | ||
.race(Future.after(50, 'bye')) | ||
.fork(console.error, console.log) | ||
//> "bye" | ||
``` | ||
#### `or :: Future a b ~> Future a b -> Future a b` | ||
Logical or for Futures. | ||
Returns a new Future which either resolves with the first resolution value, or | ||
rejects with the last rejection value once and if both Futures reject. | ||
This behaves analogues to how JavaScript's or operator does, except both | ||
Futures run simultaneously, so it is *not* short-circuited. That means that | ||
if the second has side-effects, they will run even if the first resolves. | ||
```js | ||
//An asynchronous version of: | ||
//const result = planA() || planB(); | ||
const result = planA().or(planB()); | ||
``` | ||
In the example, assume both plans return Futures. Both plans are executed in | ||
parallel. If `planA` resolves, the returned Future will resolve with its value. | ||
If `planA` fails there is always `planB`. If both plans fail then the returned | ||
Future will also reject using the rejection reason of `planB`. | ||
#### `fold :: Future a b ~> (a -> c), (b -> c) -> Future _ c` | ||
Applies the left function to the rejection value, or the right function to the | ||
@@ -440,94 +422,17 @@ resolution value, depending on which is present, and resolves with the result. | ||
#### `cache :: Future a b -> Future a b` | ||
### Parallelism | ||
Returns a Future which caches the resolution value of the given Future so that | ||
whenever it's forked, it can load the value from cache rather than reexecuting | ||
the chain. | ||
#### race | ||
##### `#race :: Future a b ~> Future a b -> Future a b` | ||
##### `.race :: Future a b -> Future a b -> Future a b` | ||
```js | ||
const eventualPackage = Future.cache( | ||
Future.node(done => { | ||
console.log('Reading some big data'); | ||
fs.readFile('package.json', 'utf8', done) | ||
}) | ||
); | ||
Race two Futures against each other. Creates a new Future which resolves or | ||
rejects with the resolution or rejection value of the first Future to settle. | ||
eventualPackage.fork(console.error, console.log); | ||
//> "Reading some big data" | ||
//> "{...}" | ||
eventualPackage.fork(console.error, console.log); | ||
//> "{...}" | ||
``` | ||
#### `value :: Future a b ~> (b -> Void) -> Void` | ||
Extracts the value from a resolved Future by forking it. Only use this function | ||
if you are sure the Future is going to be resolved, for example; after using | ||
`.fold()`. If the Future rejects and `value` was used, an (likely uncatchable) | ||
`Error` will be thrown. | ||
```js | ||
Future.reject(new Error('It broke')) | ||
.fold(S.Left, S.Right) | ||
.value(console.log) | ||
//> Left([Error: It broke]) | ||
``` | ||
Future.after(100, 'hello') | ||
.race(Future.after(50, 'bye')) | ||
.fork(console.error, console.log) | ||
//> "bye" | ||
#### `promise :: Future a b ~> Promise b a` | ||
An alternative way to `fork` the Future. This eagerly forks the Future and | ||
returns a Promise of the result. This is useful if some API wants you to give it | ||
a Promise. It's the only method which forks the Future without a forced way to | ||
handle the rejection branch, which means it's considered dangerous to use. | ||
```js | ||
Future.of('Hello').promise().then(console.log); | ||
//> "Hello" | ||
``` | ||
### Dispatcher API | ||
#### `fork :: (a -> Void) -> (b -> Void) -> Future a b -> Void` | ||
Dispatches the first and second arguments to the `fork` method of the third argument. | ||
```js | ||
const consoleFork = fork(console.error, console.log); | ||
consoleFork(of('Hello')); | ||
//> "Hello" | ||
``` | ||
#### `map :: Functor m => (a -> b) -> m a -> m b` | ||
Dispatches the first argument to the `map` method of the second argument. | ||
Has the same effect as [`R.map`][3]. | ||
#### `mapRej :: (a -> b) -> Future a c -> Future b c` | ||
Dispatches the first argument to the `mapRej` method of the second argument. | ||
#### `bimap :: Bifunctor m => (a -> b) -> (c -> d) -> m a c -> m b d` | ||
Dispatches the first two arguments to the `bimap` method of the third argument. | ||
#### `chain :: Chain m => (a -> m b) -> m a -> m b` | ||
Dispatches the first argument to the `chain` method of the second argument. | ||
Has the same effect as [`R.chain`][4]. | ||
#### `chainRej :: (a -> Future a c) -> Future a b -> Future a c` | ||
Dispatches the first argument to the `chainRej` method of the second argument. | ||
#### `ap :: Apply m => m (a -> b) -> m a -> m b` | ||
Dispatches the second argument to the `ap` method of the first argument. | ||
Has the same effect as [`R.ap`][5]. | ||
#### `race :: Future a b -> Future a b -> Future a b` | ||
Dispatches the first argument to the `race` method of the second argument. | ||
```js | ||
const first = futures => futures.reduce(race); | ||
@@ -540,10 +445,23 @@ first([ | ||
.fork(console.error, console.log) | ||
//> [Error nope] | ||
//! "nope" | ||
``` | ||
#### `or :: Future a b -> Future a b -> Future a b` | ||
#### or | ||
##### `#or :: Future a b ~> Future a b -> Future a b` | ||
##### `.or :: Future a b -> Future a b -> Future a b` | ||
Dispatches the first argument to the `or` method of the second argument. | ||
Logical or for Futures. | ||
Returns a new Future which either resolves with the first resolution value, or | ||
rejects with the last rejection value once and if both Futures reject. | ||
This behaves analogues to how JavaScript's or operator does, except both | ||
Futures run simultaneously, so it is *not* short-circuited. That means that | ||
if the second has side-effects, they will run even if the first resolves. | ||
```js | ||
//An asynchronous version of: | ||
//const result = planA() || planB(); | ||
const result = planA().or(planB()); | ||
const program = S.pipe([ | ||
@@ -554,3 +472,2 @@ reject, | ||
]); | ||
program('first chance') | ||
@@ -560,17 +477,50 @@ > "second chance" | ||
#### `fold :: (a -> c) -> (b -> c) -> Future a b -> Future _ c` | ||
In the example, assume both plans return Futures. Both plans are executed in | ||
parallel. If `planA` resolves, the returned Future will resolve with its value. | ||
If `planA` fails there is always `planB`. If both plans fail then the returned | ||
Future will also reject using the rejection reason of `planB`. | ||
Dispatches the first and second arguments to the `fold` method of the third argument. | ||
#### parallel | ||
##### `.parallel :: PositiveInteger -> Array (Future a b) -> Future a (Array b)` | ||
#### `value :: (b -> Void) -> Future a b -> Void` | ||
Creates a Future which when forked runs all Futures in the given `array` in | ||
parallel, ensuring no more than `limit` Futures are running at once. | ||
Dispatches the first argument to the `value` method of the second argument. | ||
```js | ||
const tenFutures = Array.from(Array(10).keys()).map(Future.after(20)); | ||
#### `promise :: Future a b -> Promise b a` | ||
//Runs all Futures in sequence: | ||
Future.parallel(1, tenFutures).fork(console.error, console.log); | ||
//after about 200ms: | ||
//> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | ||
Dispatches to the `promise` method. | ||
//Runs upto five Futures in parallel: | ||
Future.parallel(5, tenFutures).fork(console.error, console.log); | ||
//after about 40ms: | ||
//> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | ||
//Runs all Futures in parallel: | ||
Future.parallel(Infinity, tenFutures).fork(console.error, console.log); | ||
//after about 20ms: | ||
//> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | ||
``` | ||
If you want to settle all Futures, even if some may fail, you can use this in | ||
combination with [fold](#fold): | ||
```js | ||
Future.promise(Future.after(300, 'Hello')).then(console.log); | ||
//> "Hello" | ||
const fourInstableFutures = Array.from(Array(4).keys()).map( | ||
i => Future( | ||
(rej, res) => setTimeout( | ||
() => Math.random() > 0.8 ? rej('failed') : res(i), | ||
20 | ||
) | ||
) | ||
); | ||
const stabalizedFutures = fourInstableFutures.map(Future.fold(S.Left, S.Right)) | ||
Future.parallel(2, stabalizedFutures).fork(console.error, console.log); | ||
//after about 40ms: | ||
//> [ Right(0), Left("failed"), Right(2), Right(3) ] | ||
``` | ||
@@ -580,3 +530,4 @@ | ||
#### `isFuture :: a -> Boolean` | ||
#### isFuture | ||
##### `.isFuture :: a -> Boolean` | ||
@@ -600,8 +551,32 @@ Returns true for [Futures](#type-signatures) and false for everything else. This | ||
#### `isForkable :: a -> Boolean` | ||
#### isForkable | ||
##### `.isForkable :: a -> Boolean` | ||
Returns true for [Forkables](#type-signatures) and false for everything else. | ||
#### `do :: (() -> Iterator) -> Future a b` | ||
##### `.cache :: Future a b -> Future a b` | ||
Returns a Future which caches the resolution value of the given Future so that | ||
whenever it's forked, it can load the value from cache rather than reexecuting | ||
the chain. | ||
```js | ||
const eventualPackage = Future.cache( | ||
Future.node(done => { | ||
console.log('Reading some big data'); | ||
fs.readFile('package.json', 'utf8', done) | ||
}) | ||
); | ||
eventualPackage.fork(console.error, console.log); | ||
//> "Reading some big data" | ||
//> "{...}" | ||
eventualPackage.fork(console.error, console.log); | ||
//> "{...}" | ||
``` | ||
#### do | ||
##### `.do :: (() -> Iterator) -> Future a b` | ||
A specialized version of [fantasy-do][19] which works only for Futures, but has | ||
@@ -608,0 +583,0 @@ the advantage of type-checking and not having to pass `Future.of`. Another |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
44957
16
635
633