Comparing version 0.5.8 to 0.5.9
@@ -63,3 +63,2 @@ 'use strict'; | ||
// Defaults | ||
var _defaultRandomGenerator = new _Random2.default(); | ||
var _defaultDelegate = _CollectionDelegate2.default; | ||
@@ -70,6 +69,6 @@ var _defaultCursorClass = _CursorObservable2.default; | ||
var _defaultIdGenerator = function _defaultIdGenerator(modelName) { | ||
var nextSeed = _defaultRandomGenerator.hexString(20); | ||
var nextSeed = _Random2.default.default().hexString(20); | ||
var sequenceSeed = [nextSeed, '/collection/' + modelName]; | ||
return { | ||
value: _Random2.default.createWithSeed.apply(null, sequenceSeed).id(17), | ||
value: _Random2.default.createWithSeeds.apply(null, sequenceSeed).id(17), | ||
seed: nextSeed | ||
@@ -76,0 +75,0 @@ }; |
@@ -146,2 +146,4 @@ 'use strict'; | ||
if (_this2._observers === 0) { | ||
_this2._latestResult = null; | ||
_this2._latestIds = null; | ||
_this2.emit('stopped'); | ||
@@ -148,0 +150,0 @@ } |
@@ -8,5 +8,28 @@ 'use strict'; | ||
}); | ||
exports._getBrowserSeeds = _getBrowserSeeds; | ||
var _try2 = require('fast.js/function/try'); | ||
var _try3 = _interopRequireDefault(_try2); | ||
var _invariant = require('invariant'); | ||
var _invariant2 = _interopRequireDefault(_invariant); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
// Intarnals | ||
var _defaultRandomGenerator = undefined; | ||
var RANDOM_GENERATOR_TYPE = { | ||
NODE_CRYPTO: 'NODE_CRYPTO', | ||
BROWSER_CRYPTO: 'BROWSER_CRYPTO', | ||
ALEA: 'ALEA' | ||
}; | ||
var UNMISTAKABLE_CHARS = '23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz'; | ||
var BASE64_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + '0123456789-_'; | ||
// see http://baagoe.org/en/wiki/Better_random_numbers_for_javascript | ||
@@ -85,27 +108,34 @@ // for a full discussion and Alea implementation. | ||
var UNMISTAKABLE_CHARS = '23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz'; | ||
var BASE64_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + '0123456789-_'; | ||
/** | ||
* Create seeds array for a browser based on window sizes, | ||
* Date and some random number. | ||
* @return {Arrat} | ||
*/ | ||
function _getBrowserSeeds() { | ||
var height = typeof window !== 'undefined' && window.innerHeight || typeof document !== 'undefined' && document.documentElement && document.documentElement.clientHeight || typeof document !== 'undefined' && document.body && document.body.clientHeight || 1; | ||
var Random = exports.Random = (function () { | ||
function Random() { | ||
_classCallCheck(this, Random); | ||
var width = typeof window !== 'undefined' && window.innerWidth || typeof document !== 'undefined' && document.documentElement && document.documentElement.clientWidth || typeof document !== 'undefined' && document.body && document.body.clientWidth || 1; | ||
// Get first argumnts with this method | ||
// because ngInject tries to inject any | ||
// service from a declared consturcor | ||
var seedArray = arguments[0]; | ||
var agent = typeof navigator !== 'undefined' && navigator.userAgent || ''; | ||
return [new Date(), height, width, agent, Math.random()]; | ||
} | ||
// Get default seed in the browser | ||
if (seedArray === undefined && !(typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues)) { | ||
var height = typeof window !== 'undefined' && window.innerHeight || typeof document !== 'undefined' && document.documentElement && document.documentElement.clientHeight || typeof document !== 'undefined' && document.body && document.body.clientHeight || 1; | ||
/** | ||
* Random string generator copied from Meteor | ||
* with minor modifications and refactoring. | ||
*/ | ||
var width = typeof window !== 'undefined' && window.innerWidth || typeof document !== 'undefined' && document.documentElement && document.documentElement.clientWidth || typeof document !== 'undefined' && document.body && document.body.clientWidth || 1; | ||
var Random = (function () { | ||
function Random(type) { | ||
var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
var agent = typeof navigator !== 'undefined' && navigator.userAgent || ''; | ||
seedArray = [new Date(), height, width, agent, Math.random()]; | ||
} | ||
_classCallCheck(this, Random); | ||
// Use Alea then seed provided | ||
if (seedArray !== undefined) { | ||
this.alea = Alea.apply(null, seedArray); | ||
this.type = type; | ||
(0, _invariant2.default)(RANDOM_GENERATOR_TYPE[type], 'Random(...): no generator type %s', type); | ||
if (type === RANDOM_GENERATOR_TYPE.ALEA) { | ||
(0, _invariant2.default)(options.seeds, 'Random(...): seed is not provided for ALEA seeded generator'); | ||
this.alea = Alea.apply(null, options.seeds); | ||
} | ||
@@ -117,12 +147,14 @@ } | ||
value: function fraction() { | ||
var self = this; | ||
if (self.alea) { | ||
return self.alea(); | ||
} else if (typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues) { | ||
var array = new Uint32Array(1); | ||
window.crypto.getRandomValues(array); | ||
return array[0] * 2.3283064365386963e-10; // 2^-32 | ||
} else { | ||
throw new Error('No random generator available'); | ||
} | ||
if (this.type === RANDOM_GENERATOR_TYPE.ALEA) { | ||
return this.alea(); | ||
} else if (this.type === RANDOM_GENERATOR_TYPE.NODE_CRYPTO) { | ||
var numerator = parseInt(this.hexString(8), 16); | ||
return numerator * 2.3283064365386963e-10; // 2^-32 | ||
} else if (this.type === RANDOM_GENERATOR_TYPE.BROWSER_CRYPTO) { | ||
var array = new Uint32Array(1); | ||
window.crypto.getRandomValues(array); | ||
return array[0] * 2.3283064365386963e-10; // 2^-32 | ||
} else { | ||
throw new Error('Unknown random generator type: ' + this.type); | ||
} | ||
} | ||
@@ -132,10 +164,28 @@ }, { | ||
value: function hexString(digits) { | ||
var self = this; | ||
var hexDigits = []; | ||
if (this.type === RANDOM_GENERATOR_TYPE.NODE_CRYPTO) { | ||
var _ret = (function () { | ||
var nodeCrypto = require('crypto'); | ||
var numBytes = Math.ceil(digits / 2); | ||
for (var i = 0; i < digits; ++i) { | ||
hexDigits.push(self.choice('0123456789abcdef')); | ||
// Try to get cryptographically strong randomness. Fall back to | ||
// non-cryptographically strong if not available. | ||
var bytes = (0, _try3.default)(function () { | ||
return nodeCrypto.randomBytes(numBytes); | ||
}); | ||
if (bytes instanceof Error) { | ||
bytes = nodeCrypto.pseudoRandomBytes(numBytes); | ||
} | ||
var result = bytes.toString('hex'); | ||
// If the number of digits is odd, we'll have generated an extra 4 bits | ||
// of randomness, so we need to trim the last digit. | ||
return { | ||
v: result.substring(0, digits) | ||
}; | ||
})(); | ||
if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v; | ||
} else { | ||
return this._randomString(digits, '0123456789abcdef'); | ||
} | ||
return hexDigits.join(''); | ||
} | ||
@@ -145,6 +195,5 @@ }, { | ||
value: function _randomString(charsCount, alphabet) { | ||
var self = this; | ||
var digits = []; | ||
for (var i = 0; i < charsCount; i++) { | ||
digits[i] = self.choice(alphabet); | ||
digits[i] = this.choice(alphabet); | ||
} | ||
@@ -156,3 +205,2 @@ return digits.join(''); | ||
value: function id(charsCount) { | ||
var self = this; | ||
// 17 characters is around 96 bits of entropy, which is the amount of | ||
@@ -163,4 +211,3 @@ // state in the Alea PRNG. | ||
} | ||
return self._randomString(charsCount, UNMISTAKABLE_CHARS); | ||
return this._randomString(charsCount, UNMISTAKABLE_CHARS); | ||
} | ||
@@ -170,3 +217,2 @@ }, { | ||
value: function secret(charsCount) { | ||
var self = this; | ||
// Default to 256 bits of entropy, or 43 characters at 6 bits per | ||
@@ -177,3 +223,3 @@ // character. | ||
} | ||
return self._randomString(charsCount, BASE64_CHARS); | ||
return this._randomString(charsCount, BASE64_CHARS); | ||
} | ||
@@ -191,9 +237,24 @@ }, { | ||
}], [{ | ||
key: 'createWithSeed', | ||
value: function createWithSeed() { | ||
if (arguments.length === 0) { | ||
throw new Error('No seeds were provided'); | ||
key: 'default', | ||
value: function _default() { | ||
if (!_defaultRandomGenerator) { | ||
if (typeof window !== 'undefined') { | ||
if (window.crypto && window.crypto.getRandomValues) { | ||
return new Random(RANDOM_GENERATOR_TYPE.BROWSER_CRYPTO); | ||
} else { | ||
return new Random(RANDOM_GENERATOR_TYPE.ALEA, { seeds: _getBrowserSeeds() }); | ||
} | ||
} else { | ||
return new Random(RANDOM_GENERATOR_TYPE.NODE_CRYPTO); | ||
} | ||
} | ||
return new Random(arguments); | ||
return _defaultRandomGenerator; | ||
} | ||
}, { | ||
key: 'createWithSeeds', | ||
value: function createWithSeeds() { | ||
(0, _invariant2.default)(arguments.length, 'Random.createWithSeeds(...): no seeds were provided'); | ||
return new Random(RANDOM_GENERATOR_TYPE.ALEA, { seeds: arguments }); | ||
} | ||
}]); | ||
@@ -204,2 +265,3 @@ | ||
exports.default = Random; | ||
exports.default = Random; |
@@ -94,3 +94,5 @@ 'use strict'; | ||
return b.bundle() | ||
return b | ||
.exclude('crypto') | ||
.bundle() | ||
.pipe(source(config.browser.bundleName)) | ||
@@ -97,0 +99,0 @@ .pipe(buffer()) |
@@ -15,3 +15,2 @@ import _map from 'fast.js/map'; | ||
// Defaults | ||
const _defaultRandomGenerator = new Random(); | ||
let _defaultDelegate = CollectionDelegate; | ||
@@ -22,6 +21,6 @@ let _defaultCursorClass = CursorObservable; | ||
let _defaultIdGenerator = function(modelName) { | ||
const nextSeed = _defaultRandomGenerator.hexString(20); | ||
const nextSeed = Random.default().hexString(20); | ||
const sequenceSeed = [nextSeed, `/collection/${modelName}`]; | ||
return { | ||
value: Random.createWithSeed.apply(null, sequenceSeed).id(17), | ||
value: Random.createWithSeeds.apply(null, sequenceSeed).id(17), | ||
seed: nextSeed, | ||
@@ -28,0 +27,0 @@ }; |
@@ -102,2 +102,4 @@ import _bind from 'fast.js/function/bind'; | ||
if (this._observers === 0) { | ||
this._latestResult = null; | ||
this._latestIds = null; | ||
this.emit('stopped'); | ||
@@ -104,0 +106,0 @@ } |
@@ -0,4 +1,19 @@ | ||
import _try from 'fast.js/function/try'; | ||
import invariant from 'invariant'; | ||
// Intarnals | ||
let _defaultRandomGenerator; | ||
const RANDOM_GENERATOR_TYPE = { | ||
NODE_CRYPTO: 'NODE_CRYPTO', | ||
BROWSER_CRYPTO: 'BROWSER_CRYPTO', | ||
ALEA: 'ALEA', | ||
}; | ||
const UNMISTAKABLE_CHARS = '23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz'; | ||
const BASE64_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + | ||
'0123456789-_'; | ||
// see http://baagoe.org/en/wiki/Better_random_numbers_for_javascript | ||
// for a full discussion and Alea implementation. | ||
var Alea = function() { | ||
const Alea = function() { | ||
function Mash() { | ||
@@ -76,58 +91,65 @@ var n = 0xefc8249d; | ||
/** | ||
* Create seeds array for a browser based on window sizes, | ||
* Date and some random number. | ||
* @return {Arrat} | ||
*/ | ||
export function _getBrowserSeeds() { | ||
var height = (typeof window !== 'undefined' && window.innerHeight) || | ||
(typeof document !== 'undefined' | ||
&& document.documentElement | ||
&& document.documentElement.clientHeight) || | ||
(typeof document !== 'undefined' | ||
&& document.body | ||
&& document.body.clientHeight) || | ||
1; | ||
var UNMISTAKABLE_CHARS = '23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz'; | ||
var BASE64_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + | ||
'0123456789-_'; | ||
var width = (typeof window !== 'undefined' && window.innerWidth) || | ||
(typeof document !== 'undefined' | ||
&& document.documentElement | ||
&& document.documentElement.clientWidth) || | ||
(typeof document !== 'undefined' | ||
&& document.body | ||
&& document.body.clientWidth) || | ||
1; | ||
var agent = (typeof navigator !== 'undefined' && navigator.userAgent) || ''; | ||
return [new Date(), height, width, agent, Math.random()]; | ||
} | ||
export class Random { | ||
constructor() { | ||
// Get first argumnts with this method | ||
// because ngInject tries to inject any | ||
// service from a declared consturcor | ||
var seedArray = arguments[0]; | ||
/** | ||
* Random string generator copied from Meteor | ||
* with minor modifications and refactoring. | ||
*/ | ||
export default class Random { | ||
constructor(type, options = {}) { | ||
this.type = type; | ||
// Get default seed in the browser | ||
if (seedArray === undefined && | ||
!(typeof window !== 'undefined' && | ||
window.crypto && window.crypto.getRandomValues)) { | ||
var height = (typeof window !== 'undefined' && window.innerHeight) || | ||
(typeof document !== 'undefined' | ||
&& document.documentElement | ||
&& document.documentElement.clientHeight) || | ||
(typeof document !== 'undefined' | ||
&& document.body | ||
&& document.body.clientHeight) || | ||
1; | ||
invariant( | ||
RANDOM_GENERATOR_TYPE[type], | ||
'Random(...): no generator type %s', | ||
type | ||
); | ||
var width = (typeof window !== 'undefined' && window.innerWidth) || | ||
(typeof document !== 'undefined' | ||
&& document.documentElement | ||
&& document.documentElement.clientWidth) || | ||
(typeof document !== 'undefined' | ||
&& document.body | ||
&& document.body.clientWidth) || | ||
1; | ||
var agent = (typeof navigator !== 'undefined' && navigator.userAgent) || ''; | ||
seedArray = [new Date(), height, width, agent, Math.random()]; | ||
if (type === RANDOM_GENERATOR_TYPE.ALEA) { | ||
invariant( | ||
options.seeds, | ||
'Random(...): seed is not provided for ALEA seeded generator' | ||
); | ||
this.alea = Alea.apply(null, options.seeds); | ||
} | ||
// Use Alea then seed provided | ||
if (seedArray !== undefined) { | ||
this.alea = Alea.apply(null, seedArray); | ||
} | ||
} | ||
fraction() { | ||
var self = this; | ||
if (self.alea) { | ||
return self.alea(); | ||
} else if (typeof window !== 'undefined' && window.crypto && | ||
window.crypto.getRandomValues) { | ||
var array = new Uint32Array(1); | ||
if (this.type === RANDOM_GENERATOR_TYPE.ALEA) { | ||
return this.alea(); | ||
} else if (this.type === RANDOM_GENERATOR_TYPE.NODE_CRYPTO) { | ||
const numerator = parseInt(this.hexString(8), 16); | ||
return numerator * 2.3283064365386963e-10; // 2^-32 | ||
} else if (this.type === RANDOM_GENERATOR_TYPE.BROWSER_CRYPTO) { | ||
const array = new Uint32Array(1); | ||
window.crypto.getRandomValues(array); | ||
return array[0] * 2.3283064365386963e-10; // 2^-32 | ||
} else { | ||
throw new Error('No random generator available'); | ||
throw new Error('Unknown random generator type: ' + this.type); | ||
} | ||
@@ -137,17 +159,26 @@ } | ||
hexString(digits) { | ||
var self = this; | ||
var hexDigits = []; | ||
if (this.type === RANDOM_GENERATOR_TYPE.NODE_CRYPTO) { | ||
const nodeCrypto = require('crypto'); | ||
const numBytes = Math.ceil(digits / 2); | ||
for (var i = 0; i < digits; ++i) { | ||
hexDigits.push(self.choice('0123456789abcdef')); | ||
// Try to get cryptographically strong randomness. Fall back to | ||
// non-cryptographically strong if not available. | ||
let bytes = _try(() => nodeCrypto.randomBytes(numBytes)); | ||
if (bytes instanceof Error) { | ||
bytes = nodeCrypto.pseudoRandomBytes(numBytes); | ||
} | ||
const result = bytes.toString('hex'); | ||
// If the number of digits is odd, we'll have generated an extra 4 bits | ||
// of randomness, so we need to trim the last digit. | ||
return result.substring(0, digits); | ||
} else { | ||
return this._randomString(digits, '0123456789abcdef'); | ||
} | ||
return hexDigits.join(''); | ||
} | ||
_randomString(charsCount, alphabet) { | ||
var self = this; | ||
var digits = []; | ||
for (var i = 0; i < charsCount; i++) { | ||
digits[i] = self.choice(alphabet); | ||
const digits = []; | ||
for (let i = 0; i < charsCount; i++) { | ||
digits[i] = this.choice(alphabet); | ||
} | ||
@@ -158,3 +189,2 @@ return digits.join(''); | ||
id(charsCount) { | ||
var self = this; | ||
// 17 characters is around 96 bits of entropy, which is the amount of | ||
@@ -165,8 +195,6 @@ // state in the Alea PRNG. | ||
} | ||
return self._randomString(charsCount, UNMISTAKABLE_CHARS); | ||
return this._randomString(charsCount, UNMISTAKABLE_CHARS); | ||
} | ||
secret(charsCount) { | ||
var self = this; | ||
// Default to 256 bits of entropy, or 43 characters at 6 bits per | ||
@@ -177,7 +205,7 @@ // character. | ||
} | ||
return self._randomString(charsCount, BASE64_CHARS); | ||
return this._randomString(charsCount, BASE64_CHARS); | ||
} | ||
choice(arrayOrString) { | ||
var index = Math.floor(this.fraction() * arrayOrString.length); | ||
const index = Math.floor(this.fraction() * arrayOrString.length); | ||
if (typeof arrayOrString === 'string') { | ||
@@ -190,10 +218,33 @@ return arrayOrString.substr(index, 1); | ||
static createWithSeed() { | ||
if (arguments.length === 0) { | ||
throw new Error('No seeds were provided'); | ||
static default() { | ||
if (!_defaultRandomGenerator) { | ||
if (typeof window !== 'undefined') { | ||
if (window.crypto && window.crypto.getRandomValues) { | ||
return new Random(RANDOM_GENERATOR_TYPE.BROWSER_CRYPTO); | ||
} else { | ||
return new Random( | ||
RANDOM_GENERATOR_TYPE.ALEA, | ||
{ seeds: _getBrowserSeeds() } | ||
); | ||
} | ||
} else { | ||
return new Random(RANDOM_GENERATOR_TYPE.NODE_CRYPTO); | ||
} | ||
} | ||
return new Random(arguments); | ||
return _defaultRandomGenerator; | ||
} | ||
static createWithSeeds() { | ||
invariant( | ||
arguments.length, | ||
'Random.createWithSeeds(...): no seeds were provided' | ||
); | ||
return new Random( | ||
RANDOM_GENERATOR_TYPE.ALEA, | ||
{ seeds: arguments } | ||
); | ||
} | ||
} | ||
export default Random; |
{ | ||
"name": "marsdb", | ||
"version": "0.5.8", | ||
"version": "0.5.9", | ||
"author": { | ||
@@ -5,0 +5,0 @@ "name": "Artem Artemev", |
@@ -13,3 +13,3 @@ <div style="text-align:center"><img src="https://static.studytime.me/marsdb.png" /></div> | ||
MarsDB is a lightweight client-side database. | ||
It's based on a Meteor’s **minimongo** matching/modifying implementation. It's carefully written on **ES6**, have a **Promise based** interface and may be backed with any storage implementation ([see storages](https://github.com/c58/marsdb#storage-implementations)). It's also supports **observable** cursors. | ||
It's based on a Meteor’s **minimongo** matching/modifying implementation. It's carefully written on **ES6**, have a **Promise based** interface and may be backed with any storage implementation ([see plugins](https://github.com/c58/marsdb#plugins)). It's also supports **observable** cursors. | ||
@@ -24,2 +24,3 @@ MarsDB supports any kind of find/update/remove operations that Meteor’s minimongo does. So, go to the Meteor docs for supported query/modifier operations. | ||
* **Carefully written on ES6** | ||
* **Very very flexible** – just take a look to the [plugins section](https://github.com/c58/marsdb#plugins) | ||
* **Supports many of MongoDB query/modify operations** – thanks to a Meteor’s minimongo | ||
@@ -36,15 +37,12 @@ * **Flexible pipeline** – map, reduce, custom sorting function, filtering. All with a sexy JS interface (no ugly mongo’s aggregation language) | ||
## Storage implementations | ||
## Plugins | ||
* In-memory (built-in default) | ||
* [LocalForage](https://github.com/c58/marsdb-localforage) – fastest in-browser storage (InexedDB, WebSQL and fallback to localStorage) | ||
* [LocalStorage](https://github.com/c58/marsdb-localstorage) – not recommended, better prefer LocalForage | ||
* [LevelUP](https://github.com/c58/marsdb-levelup) – lightweight server-less Node.js storage | ||
* [MongoDB](https://github.com/c58/marsdb-mongo) – use MarsDB as a sugar upon MongoDB | ||
* In-memory storage (built-in default) | ||
* [LocalForage storage](https://github.com/c58/marsdb-localforage) – fastest in-browser storage (InexedDB, WebSQL and fallback to localStorage) | ||
* [LocalStorage storage](https://github.com/c58/marsdb-localstorage) – not recommended, better prefer LocalForage | ||
* [LevelUP storage](https://github.com/c58/marsdb-levelup) – lightweight server-less Node.js storage | ||
* [MongoDB wrapper](https://github.com/c58/marsdb-mongo) – use MarsDB for comfortable work with MongoDB | ||
* [Validation via Mongoose](https://github.com/c58/marsdb-validation) – validate objects with Mongoose | ||
* **Meteor compatible** [Client](https://github.com/c58/marsdb-sync-client) / [Server](https://github.com/c58/marsdb-sync-server) synchronizer | ||
## Client-Server | ||
* **Meteor compatible** [Client](https://github.com/c58/marsdb-sync-client) / [Server](https://github.com/c58/marsdb-sync-server) | ||
* REST (pull-request if you need it ;)) | ||
## Examples | ||
@@ -51,0 +49,0 @@ |
@@ -458,6 +458,5 @@ import Collection from '../../lib/Collection'; | ||
db2 = new Collection('another'); | ||
const rand = new Random(); | ||
return Promise.all(_.times(30, function (i) { | ||
return db2.insert({ | ||
something: rand.id(), | ||
something: Random.default().id(), | ||
anything: { | ||
@@ -464,0 +463,0 @@ foo: "bar", |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
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
906428
79
21151
203