aerospike
Advanced tools
Comparing version 2.0.0 to 2.0.1
@@ -45,3 +45,3 @@ # Aerospike Node.js Client API | ||
* {@link LargeList} - The LargeList class provides an interface to the | ||
(Aerospike LDT feature)[http://www.aerospike.com/docs/guide/ldt_guide.html). | ||
[Aerospike LDT feature](http://www.aerospike.com/docs/guide/ldt_guide.html). | ||
* {@link Job} - The Job class is used to query the status of long running | ||
@@ -48,0 +48,0 @@ background jobs. |
@@ -1,5 +0,23 @@ | ||
v2.0.0 / 2016-04-18 | ||
v2.0.1 / 2016-04-27 | ||
=================== | ||
* **Improvements** | ||
* Optimize callback handler performance. [#119](https://github.com/aerospike/aerospike-client-nodejs/issues/119) | ||
* Removed some unused async C++ helper functions; minor code cleanup | ||
* **Fixes** | ||
* Ensure callbacks are always called asynchronously, even for param errors | ||
raised by the client itself. [#120](https://github.com/aerospike/aerospike-client-nodejs/issues/120) | ||
* **Tests** | ||
* Complete tests for writing bins with specific data types | ||
* Extend query/scan performance tests | ||
* **Documentation** | ||
* Minor JSDoc documentation fixes | ||
v2.0.0 / 2016-04-19 | ||
=================== | ||
* **Documentation** | ||
* Added overview page for API docs | ||
@@ -32,4 +50,2 @@ * Added "Getting Started" tutorial to API docs | ||
* **Fixes** | ||
* Ensure callbacks are always called asynchronously, even for param errors | ||
raised by the client itself. | ||
* Fix possible memory corruption parsing UDF module or function names. | ||
@@ -36,0 +52,0 @@ |
@@ -69,3 +69,8 @@ // ***************************************************************************** | ||
Client.DefaultCallbackHandler = function (callback, err) { | ||
// The callback functions for the client commands take a variable number of | ||
// arguments. Since use of the arguments variable can prevent V8 from | ||
// optimizing the function we declare the max. number of arguments statically. | ||
// See // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments | ||
// for more information. | ||
Client.DefaultCallbackHandler = function (callback, err, arg1, arg2, arg3) { | ||
if (!callback) return | ||
@@ -76,12 +81,9 @@ if (err && err.code !== as.status.AEROSPIKE_OK) { | ||
} else { | ||
var args = Array.prototype.slice.call(arguments, 2) | ||
args.unshift(null) | ||
callback.apply(undefined, args) | ||
callback(null, arg1, arg2, arg3) | ||
} | ||
} | ||
Client.LegacyCallbackHandler = function (callback, err) { | ||
Client.LegacyCallbackHandler = function (callback, err, arg1, arg2, arg3) { | ||
if (!callback) return | ||
var args = Array.prototype.slice.call(arguments, 1) | ||
callback.apply(undefined, args) | ||
callback(err, arg1, arg2, arg3) | ||
} | ||
@@ -88,0 +90,0 @@ |
@@ -269,3 +269,3 @@ // ***************************************************************************** | ||
/** | ||
* @function geoContainsGeoJSONPoint | ||
* @function geoContainsPoint | ||
* @static | ||
@@ -272,0 +272,0 @@ * |
{ | ||
"name": "aerospike", | ||
"version": "2.0.0", | ||
"version": "2.0.1", | ||
"description": "Aerospike Client Library", | ||
@@ -29,3 +29,4 @@ "tags": [ | ||
"test": "standard && ./scripts/shuffle_tests", | ||
"apidocs": "jsdoc -c jsdoc.json" | ||
"apidocs": "jsdoc -c jsdoc.json", | ||
"preversion": "npm test" | ||
}, | ||
@@ -32,0 +33,0 @@ "dependencies": { |
@@ -1,10 +0,13 @@ | ||
[![Build Status](https://travis-ci.org/aerospike/aerospike-client-nodejs.svg?branch=master)](https://travis-ci.org/aerospike/aerospike-client-nodejs) | ||
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/) | ||
[![npm](https://img.shields.io/npm/v/aerospike.svg)](https://www.npmjs.com/package/aerospik://www.npmjs.com/package/aerospike) | ||
# Aerospike Node.js Client [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![downloads][downloads-image]][downloads-url] | ||
# Aerospike Node.js Client | ||
[travis-image]: https://travis-ci.org/aerospike/aerospike-client-nodejs.svg?branch=master | ||
[travis-url]: https://travis-ci.org/aerospike/aerospike-client-nodejs | ||
[npm-image]: https://img.shields.io/npm/v/aerospike.svg | ||
[npm-url]: https://www.npmjs.com/package/aerospike | ||
[downloads-image]: https://img.shields.io/npm/dm/aerospike.svg | ||
[downloads-url]: http://npm-stat.com/charts.html?package=aerospike | ||
An Aerospike add-on module for Node.js. | ||
This module is compatible with Node.js v0.10.x, v0.12.x, io.js, v4.x, v5.x and supports the following operating systems: | ||
This module is compatible with Node.js v0.12.x, io.js, v4.x, v5.x and supports the following operating systems: | ||
CentOS/RHEL 6.x, Debian 6+, Ubuntu 12.04+, Fedora 20+, Korora 22+, Linuxmint and Mac OS X. | ||
@@ -11,0 +14,0 @@ |
@@ -62,8 +62,9 @@ // ***************************************************************************** | ||
it('it passes through the non-error callback parameters', function (done) { | ||
var resultIn = 'result value' | ||
var cb = function (errOut, resultOut) { | ||
expect(resultOut).to.eql(resultIn) | ||
var cb = function (errOut, arg1, arg2, arg3) { | ||
expect(arg1).to.equal('one') | ||
expect(arg2).to.equal(2) | ||
expect(arg3).to.equal('three') | ||
done() | ||
} | ||
callbackHandler(cb, errIn, resultIn) | ||
callbackHandler(cb, errIn, 'one', 2, 'three') | ||
}) | ||
@@ -111,8 +112,9 @@ }) | ||
it('it passes through the non-error callback parameters', function (done) { | ||
var resultIn = 'result value' | ||
var cb = function (errOut, resultOut) { | ||
expect(resultOut).to.eql(resultIn) | ||
var cb = function (errOut, arg1, arg2, arg3) { | ||
expect(arg1).to.equal('one') | ||
expect(arg2).to.equal(2) | ||
expect(arg3).to.equal('three') | ||
done() | ||
} | ||
callbackHandler(cb, errIn, resultIn) | ||
callbackHandler(cb, errIn, 'one', 2, 'three') | ||
}) | ||
@@ -119,0 +121,0 @@ }) |
@@ -25,3 +25,6 @@ // ***************************************************************************** | ||
var creator = function (record, err) { | ||
if (err) throw err | ||
if (err) { | ||
console.error('ERROR: %s [%d] in %s at %s:%d\n%s', err.message, err.code, err.func, err.file, err.line, err.stack) | ||
throw err | ||
} | ||
if (record) { | ||
@@ -53,3 +56,3 @@ callback(record.key, record. bins, record.meta) | ||
function put (n, keygen, recgen, metagen, callback) { | ||
var policy = { exists: Aerospike.policy.exists.CREATE_OR_REPLACE } | ||
var policy = { exists: Aerospike.policy.exists.CREATE_OR_REPLACE, timeout: 1000 } | ||
var generator = { | ||
@@ -56,0 +59,0 @@ key: keygen, |
130
test/put.js
@@ -17,3 +17,3 @@ // ***************************************************************************** | ||
/* global expect, describe, it */ | ||
/* global expect, describe, it, context */ | ||
@@ -30,2 +30,3 @@ const Aerospike = require('../lib/aerospike') | ||
const Double = Aerospike.Double | ||
const GeoJSON = Aerospike.GeoJSON | ||
@@ -147,83 +148,74 @@ describe('client.put()', function () { | ||
it('shoule write an array, map type of bin and read', function (done) { | ||
// generators | ||
var kgen = keygen.string(helper.namespace, helper.set, {prefix: 'test/put/'}) | ||
var mgen = metagen.constant({ttl: 1000}) | ||
var rgen = recgen.record({list: valgen.array(), map: valgen.map()}) | ||
context('bins with various data types', function () { | ||
var meta = { ttl: 600 } | ||
var policy = { exists: Aerospike.policy.exists.CREATE_OR_REPLACE } | ||
// values | ||
var key = kgen() | ||
var meta = mgen(key) | ||
var record = rgen(key, meta) | ||
// write the record and then check | ||
client.put(key, record, meta, function (err, key) { | ||
expect(err).not.to.be.ok() | ||
client.get(key, function (err, record1, metadata, key) { | ||
if (err) { throw new Error(err.message) } | ||
expect(record1).to.eql(record) | ||
client.remove(key, function (err, key) { | ||
if (err) { throw new Error(err.message) } | ||
done() | ||
function putGetVerify (record, expected, done) { | ||
var key = keygen.string(helper.namespace, helper.set, {prefix: 'test/put/'})() | ||
client.put(key, record, meta, policy, function (err) { | ||
if (err) throw err | ||
client.get(key, function (err, record) { | ||
if (err) throw err | ||
expect(record).to.eql(expected) | ||
client.remove(key, done) | ||
}) | ||
}) | ||
}) | ||
}) | ||
it('shoule write a bin with double value', function (done) { | ||
// generators | ||
var kgen = keygen.string(helper.namespace, helper.set, {prefix: 'test/put/'}) | ||
var mgen = metagen.constant({ttl: 1000}) | ||
// values | ||
var key = kgen() | ||
var meta = mgen(key) | ||
var record = { | ||
val: 123.45, | ||
dval: new Double(456.00) | ||
} | ||
// write the record and then check | ||
client.put(key, record, meta, function (err, key) { | ||
expect(err).to.not.be.ok() | ||
it('writes bin with string values and reads it back', function (done) { | ||
var record = { string: 'hello world' } | ||
var expected = { string: 'hello world' } | ||
putGetVerify(record, expected, done) | ||
}) | ||
client.get(key, function (err, record1, metadata, key) { | ||
if (err) { throw new Error(err.message) } | ||
expect(record1.val).to.equal(record.val) | ||
expect(record1.dval).to.equal(record.dval.value()) | ||
it('writes bin with integer values and reads it back', function (done) { | ||
var record = { low: Number.MIN_SAFE_INTEGER, high: Number.MAX_SAFE_INTEGER } | ||
var expected = { low: -9007199254740991, high: 9007199254740991 } | ||
putGetVerify(record, expected, done) | ||
}) | ||
client.remove(key, function (err, key) { | ||
if (err) { throw new Error(err.message) } | ||
done() | ||
}) | ||
}) | ||
it('writes bin with Buffer value and reads it back', function (done) { | ||
var record = { buffer: new Buffer([0x61, 0x65, 0x72, 0x6f, 0x73, 0x70, 0x69, 0x6b, 0x65]) } | ||
var expected = { buffer: new Buffer([0x61, 0x65, 0x72, 0x6f, 0x73, 0x70, 0x69, 0x6b, 0x65]) } | ||
putGetVerify(record, expected, done) | ||
}) | ||
}) | ||
it('should write an array of map and array, map of array and map, then read', function (done) { | ||
// generators | ||
var kgen = keygen.string(helper.namespace, helper.set, {prefix: 'test/put/'}) | ||
var mgen = metagen.constant({ttl: 1000}) | ||
var rgen = recgen.record({list_of_list: valgen.array_of_array(), map_of_list: valgen.map_of_map()}) | ||
it('writes bin with float value as double and reads it back', function (done) { | ||
var record = { double: 3.141592653589793 } | ||
var expected = { double: 3.141592653589793 } | ||
putGetVerify(record, expected, done) | ||
}) | ||
// values | ||
var key = kgen() | ||
var meta = mgen(key) | ||
var record = rgen(key, meta) | ||
it('writes bin with Double value as double and reads it back', function (done) { | ||
var record = { double: new Double(3.141592653589793) } | ||
var expected = { double: 3.141592653589793 } | ||
putGetVerify(record, expected, done) | ||
}) | ||
// write the record and then check | ||
client.put(key, record, meta, function (err, key) { | ||
expect(err).not.to.be.ok() | ||
it('writes bin with GeoJSON value and reads it back as string', function (done) { | ||
var record = { geo: new GeoJSON.Point(103.8, 1.283) } | ||
var expected = { geo: '{"type":"Point","coordinates":[103.8,1.283]}' } | ||
putGetVerify(record, expected, done) | ||
}) | ||
client.get(key, function (err, record1, metadata, key) { | ||
if (err) { throw new Error(err.message) } | ||
expect(record1).to.eql(record) | ||
it('writes bin with array value as list and reads it back', function (done) { | ||
var record = { list: [ 1, 'foo', 1.23, new Double(3.14), new Buffer('bar'), | ||
GeoJSON.Point(103.8, 1.283), [1, 2, 3], { a: 1, b: 2 } ] | ||
} | ||
var expected = { list: [ 1, 'foo', 1.23, 3.14, new Buffer('bar'), | ||
'{"type":"Point","coordinates":[103.8,1.283]}', [1, 2, 3], { a: 1, b: 2 } ] | ||
} | ||
putGetVerify(record, expected, done) | ||
}) | ||
client.remove(key, function (err, key) { | ||
if (err) { throw new Error(err.message) } | ||
done() | ||
}) | ||
}) | ||
it('writes bin with object value as map and reads it back', function (done) { | ||
var record = { map: { a: 1, b: 'foo', c: 1.23, d: new Double(3.14), | ||
e: new Buffer('bar'), f: GeoJSON.Point(103.8, 1.283), g: [1, 2, 3], | ||
h: { a: 1, b: 2 } } | ||
} | ||
var expected = { map: { a: 1, b: 'foo', c: 1.23, d: 3.14, | ||
e: new Buffer('bar'), f: '{"type":"Point","coordinates":[103.8,1.283]}', | ||
g: [1, 2, 3], h: { a: 1, b: 2 } } | ||
} | ||
putGetVerify(record, expected, done) | ||
}) | ||
@@ -230,0 +222,0 @@ }) |
@@ -178,2 +178,15 @@ // ***************************************************************************** | ||
describe('query.foreach()', function () { | ||
it('should raise client errors asynchronously', function (done) { | ||
var query = client.query('test') | ||
var invalidPolicy = {timeout: 'not a valid timeout'} | ||
var stream = query.foreach(invalidPolicy) | ||
// if error is raised synchronously we will never reach here | ||
stream.on('error', function (error) { | ||
expect(error.code).to.equal(Aerospike.status.AEROSPIKE_ERR_PARAM) | ||
done() | ||
}) | ||
}) | ||
}) | ||
context('filter predicates', function () { | ||
@@ -180,0 +193,0 @@ describe('filter.equal()', function () { |
@@ -40,8 +40,10 @@ // ***************************************************************************** | ||
// Generates records with ~ 1k record size each | ||
function generate (ns, set, numberOfRecords, done) { | ||
// Generates records with specific record size | ||
function generate (ns, set, numberOfRecords, recordSize, done) { | ||
var numBinsPerRecord = recordSize[0] | ||
var sizePerBin = recordSize[1] | ||
var kgen = keygen.string(ns, set, {length: {min: 20, max: 20}}) | ||
var bins = { id: valgen.integer({random: false, min: 0}) } | ||
for (var i = 0; i < 8; i++) { | ||
bins['b' + i] = valgen.bytes({length: {min: 128, max: 128}}) // 8 x 128 bytes ≈ 1k/record | ||
for (var i = 0; i < numBinsPerRecord; i++) { | ||
bins['b' + i] = valgen.bytes({length: {min: sizePerBin, max: sizePerBin}}) | ||
} | ||
@@ -48,0 +50,0 @@ var rgen = recgen.record(bins) |
@@ -23,2 +23,6 @@ // ***************************************************************************** | ||
const fs = require('fs') | ||
const mega = 1024 * 1024 // bytes in a MB | ||
describe('client.query()', function () { | ||
@@ -29,4 +33,34 @@ this.enableTimeouts(false) | ||
var idxKey = new Aerospike.Key(helper.namespace, helper.set, 'queryPerfData') | ||
var numberOfRecords = 1e6 // 1 Mio. records at 1kb ≈ 1 GB total data size | ||
var recordSize = [8, 128] // 8 x 128 bytes ≈ 1 kb / record | ||
var numberOfRecords = 1e6 // 1 Mio. records at 1 kb ≈ 1 GB total data size | ||
// Execute query using given onData handler to process each scanned record | ||
function executeQuery (onData, done) { | ||
var query = client.query(helper.namespace, testSet) | ||
query.where(Aerospike.filter.range('id', 0, numberOfRecords)) | ||
var stream = query.foreach() | ||
var received = 0 | ||
var timer = perfdata.interval(10000, function (ms) { | ||
var throughput = Math.round(1000 * received / ms) | ||
var memUsage = process.memoryUsage() | ||
var rss = Math.round(memUsage.rss / mega) | ||
var heapUsed = Math.round(memUsage.heapUsed / mega) | ||
var heapTotal = Math.round(memUsage.heapTotal / mega) | ||
console.log('%d ms: %d records received (%d rps; mem: %d MB, heap: %d / %d MB)', | ||
ms, received, throughput, rss, heapUsed, heapTotal) | ||
}) | ||
stream.on('error', function (err) { throw err }) | ||
stream.on('data', function (record) { received++ }) | ||
stream.on('end', function () { | ||
timer.call() | ||
timer.clear() | ||
expect(received).to.be(numberOfRecords) | ||
done() | ||
}) | ||
stream.on('data', onData) | ||
} | ||
// Create test data | ||
before(function (done) { | ||
@@ -40,3 +74,3 @@ client.get(idxKey, function (err, record) { | ||
console.time('generating performance test data') | ||
perfdata.generate(helper.namespace, testSet, numberOfRecords, function (recordsGenerated) { | ||
perfdata.generate(helper.namespace, testSet, numberOfRecords, recordSize, function (recordsGenerated) { | ||
console.timeEnd('generating performance test data') | ||
@@ -58,3 +92,2 @@ numberOfRecords = recordsGenerated // might be slightly less due to duplciate keys | ||
console.timeEnd('creating secondary index') | ||
job.info(function (err, info) { if (!err) console.info(info) }) | ||
client.put(idxKey, {norec: numberOfRecords, set: testSet}, done) | ||
@@ -75,28 +108,27 @@ }) | ||
// run query test both with and without busy loop in data handler | ||
;[false, true].forEach(function (busyLoop) { | ||
it('query a million records - ' + (busyLoop ? 'with' : 'without') + ' busy loop', function (done) { | ||
var query = client.query(helper.namespace, testSet) | ||
query.where(Aerospike.filter.range('id', 0, numberOfRecords)) | ||
var stream = query.foreach() | ||
var received = 0 | ||
// Test definitions | ||
it('queries ' + numberOfRecords + ' records with noop', function (done) { | ||
var noop = function () {} | ||
executeQuery(noop, done) | ||
}) | ||
var timer = perfdata.interval(2000, function (ms) { | ||
var throughput = Math.round(1000 * received / ms) | ||
console.log('%d ms: %d records received (%d records / second)', ms, received, throughput) | ||
}) | ||
it('queries ' + numberOfRecords + ' records with busy loop', function (done) { | ||
var busy = function () { | ||
for (var x = 0; x < 1e5; x++) {} // busy loop | ||
} | ||
executeQuery(busy, done) | ||
}) | ||
stream.on('error', function (err) { throw err }) | ||
stream.on('data', function (record) { | ||
received++ | ||
if (busyLoop) for (var x = 0; x < 1e5; x++) {} // busy loop | ||
}) | ||
stream.on('end', function () { | ||
timer.call() | ||
timer.clear() | ||
expect(received).to.be(numberOfRecords) | ||
done() | ||
}) | ||
it('queries ' + numberOfRecords + ' records with file IO', function (done) { | ||
var file = 'query-stress-test.log' | ||
var stream = fs.createWriteStream(file) | ||
stream.on('error', function (err) { throw err }) | ||
var fileAppend = function (record) { | ||
stream.write(JSON.stringify(record) + '\n') | ||
} | ||
executeQuery(fileAppend, function () { | ||
stream.end() | ||
fs.unlink(file, done) | ||
}) | ||
}) | ||
}) |
@@ -23,2 +23,6 @@ // ***************************************************************************** | ||
const fs = require('fs') | ||
const mega = 1024 * 1024 // bytes in a MB | ||
describe('client.scan()', function () { | ||
@@ -29,4 +33,35 @@ this.enableTimeouts(false) | ||
var idxKey = new Aerospike.Key(helper.namespace, helper.set, 'scanPerfData') | ||
var numberOfRecords = 1e6 // 1 Mio. records at 1kb ≈ 1 GB total data size | ||
var recordSize = [8, 128] // 8 x 128 bytes ≈ 1 kb / record | ||
var numberOfRecords = 1e6 // 1 Mio. records at 1 kb ≈ 1 GB total data size | ||
// Execute scan using given onData handler to process each scanned record | ||
function executeScan (onData, done) { | ||
var scan = client.scan(helper.namespace, testSet) | ||
scan.priority = Aerospike.scanPriority.HIGH | ||
scan.concurrent = true | ||
var stream = scan.foreach() | ||
var received = 0 | ||
var timer = perfdata.interval(10000, function (ms) { | ||
var throughput = Math.round(1000 * received / ms) | ||
var memUsage = process.memoryUsage() | ||
var rss = Math.round(memUsage.rss / mega) | ||
var heapUsed = Math.round(memUsage.heapUsed / mega) | ||
var heapTotal = Math.round(memUsage.heapTotal / mega) | ||
console.log('%d ms: %d records scanned (%d rps; mem: %d MB, heap: %d / %d MB)', | ||
ms, received, throughput, rss, heapUsed, heapTotal) | ||
}) | ||
stream.on('error', function (err) { throw err }) | ||
stream.on('data', function (record) { received++ }) | ||
stream.on('end', function () { | ||
timer.call() | ||
timer.clear() | ||
expect(received).to.be(numberOfRecords) | ||
done() | ||
}) | ||
stream.on('data', onData) | ||
} | ||
// Create test data | ||
before(function (done) { | ||
@@ -40,3 +75,3 @@ client.get(idxKey, function (err, record) { | ||
console.time('generating performance test data') | ||
perfdata.generate(helper.namespace, testSet, numberOfRecords, function (recordsGenerated) { | ||
perfdata.generate(helper.namespace, testSet, numberOfRecords, recordSize, function (recordsGenerated) { | ||
console.timeEnd('generating performance test data') | ||
@@ -56,29 +91,27 @@ numberOfRecords = recordsGenerated // might be slightly less due to duplciate keys | ||
// run scan test both with and without busy loop in data handler | ||
;[false, true].forEach(function (busyLoop) { | ||
it('scan a million records - ' + (busyLoop ? 'with' : 'without') + ' busy loop', function (done) { | ||
var scan = client.scan(helper.namespace, testSet) | ||
scan.priority = Aerospike.scanPriority.HIGH | ||
scan.concurrent = true | ||
var stream = scan.foreach() | ||
var received = 0 | ||
// Test definitions | ||
it('scans ' + numberOfRecords + ' records with noop', function (done) { | ||
var noop = function () {} | ||
executeScan(noop, done) | ||
}) | ||
var timer = perfdata.interval(2000, function (ms) { | ||
var throughput = Math.round(1000 * received / ms) | ||
console.log('%d ms: %d records scanned (%d records / second)', ms, received, throughput) | ||
}) | ||
it('scans ' + numberOfRecords + ' records with busy loop', function (done) { | ||
var busy = function () { | ||
for (var x = 0; x < 1e5; x++) {} // busy loop | ||
} | ||
executeScan(busy, done) | ||
}) | ||
stream.on('error', function (err) { throw err }) | ||
stream.on('data', function (record) { | ||
received++ | ||
if (busyLoop) for (var x = 0; x < 1e5; x++) {} // busy loop | ||
}) | ||
stream.on('end', function () { | ||
timer.call() | ||
timer.clear() | ||
expect(received).to.be(numberOfRecords) | ||
done() | ||
}) | ||
it('scans ' + numberOfRecords + ' records with file IO', function (done) { | ||
var file = 'scan-stress-test.log' | ||
var stream = fs.createWriteStream(file) | ||
stream.on('error', function (err) { throw err }) | ||
var fileAppend = function (record) { | ||
stream.write(JSON.stringify(record) + '\n') | ||
} | ||
executeScan(fileAppend, function () { | ||
stream.end() | ||
fs.unlink(file, done) | ||
}) | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
1072571
16632
428
191
73