lore-engine
Advanced tools
Comparing version 1.0.31 to 1.0.32
@@ -0,0 +0,0 @@ { |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ [![view on npm](http://img.shields.io/npm/v/example.svg)](https://www.npmjs.org/package/example) |
@@ -0,0 +0,0 @@ (function () { |
@@ -0,0 +0,0 @@ (function () { |
@@ -0,0 +0,0 @@ (function() { |
@@ -0,0 +0,0 @@ (function() { |
@@ -0,0 +0,0 @@ (function() { |
@@ -0,0 +0,0 @@ var fs = require('fs'); |
@@ -0,0 +0,0 @@ { |
{ | ||
"name": "lore-engine", | ||
"version": "1.0.31", | ||
"version": "1.0.32", | ||
"description": "A WebGL based 3D data visualization engine.", | ||
@@ -40,2 +40,2 @@ "main": "./app.js", | ||
"private": false | ||
} | ||
} |
@@ -0,0 +0,0 @@ ![Lore](https://github.com/reymond-group/lore/blob/master/logo.png?raw=true) |
@@ -0,0 +0,0 @@ const CameraBase = require('./CameraBase'); |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
//@ts-check | ||
const Vector3f = require('../Math/Vector3f'); | ||
/** | ||
* An abstract class representing the base for controls implementations. | ||
* | ||
const Vector3f = require("../Math/Vector3f"); | ||
/** | ||
* An abstract class representing the base for controls implementations. | ||
* | ||
* @property {Renderer} renderer A Lore Renderer instance. | ||
@@ -16,3 +16,2 @@ * @property {CameraBase} camera A Lore CameraBase extending object. | ||
class ControlsBase { | ||
/** | ||
@@ -24,3 +23,7 @@ * Creates an instance of ControlsBase. | ||
*/ | ||
constructor(renderer, lookAt = new Vector3f(0.0, 0.0, 0.0), enableVR = false) { | ||
constructor( | ||
renderer, | ||
lookAt = new Vector3f(0.0, 0.0, 0.0), | ||
enableVR = false | ||
) { | ||
this.renderer = renderer; | ||
@@ -33,3 +36,3 @@ this.camera = renderer.camera; | ||
this.renderer.setMaxFps(this.lowFps); | ||
this.touchMode = 'drag'; | ||
this.touchMode = "drag"; | ||
this.lookAt = lookAt; | ||
@@ -46,6 +49,2 @@ | ||
}, | ||
position: { | ||
x: 0.0, | ||
y: 0.0 | ||
}, | ||
state: { | ||
@@ -60,3 +59,5 @@ left: false, | ||
}, | ||
touches: 0 | ||
touches: 0, | ||
pointerCache: [], | ||
pinchDiff: 0 | ||
}; | ||
@@ -73,28 +74,71 @@ | ||
let that = this; | ||
this.canvas.addEventListener('mousemove', function (e) { | ||
if (that.mouse.previousPosition.x !== null && that.mouse.state.left || | ||
// Set the touch action of the canvas | ||
this.canvas.style.touchAction = 'none'; | ||
this.canvas.addEventListener("pointermove", function(e) { | ||
// Find this event in the cache and update its record with this event | ||
for (var i = 0; i < that.mouse.pointerCache.length; i++) { | ||
if (e.pointerId == that.mouse.pointerCache[i].pointerId) { | ||
that.mouse.pointerCache[i] = e; | ||
break; | ||
} | ||
} | ||
// Get the current average / center of mass pointer location | ||
let pointerLoc = that.getPointerLocation(); | ||
// Handle touch gestures and mouse events | ||
// If there are two pointer events, it has to be touch | ||
if (that.mouse.pointerCache.length === 2) { | ||
var diff = Math.pow(that.mouse.pointerCache[1].clientX - that.mouse.pointerCache[0].clientX, 2) + | ||
Math.pow(that.mouse.pointerCache[1].clientY - that.mouse.pointerCache[0].clientY, 2); | ||
if (that.mouse.pinchDiff > 0) { | ||
if (diff > that.mouse.pinchDiff) { | ||
that.raiseEvent("touch", { | ||
e: { x: -1, y: -1, speed: 0.5 }, | ||
source: "pinch" | ||
}); | ||
} | ||
else if (diff < that.mouse.pinchDiff) { | ||
that.raiseEvent("touch", { | ||
e: { x: 1, y: 1, speed: 0.5 }, | ||
source: "pinch" | ||
}); | ||
} | ||
} | ||
that.mouse.pinchDiff = diff; | ||
} else if (that.mouse.previousPosition.x !== null && that.mouse.pointerCache.length === 3) { | ||
that.mouse.delta.x = pointerLoc[0] - that.mouse.previousPosition.x; | ||
that.mouse.delta.y = pointerLoc[1] - that.mouse.previousPosition.y; | ||
that.raiseEvent("mousedrag", { | ||
e: that.mouse.delta, | ||
source: "right" | ||
}); | ||
} else if ( | ||
that.mouse.previousPosition.x !== null && (that.mouse.state.left || | ||
that.mouse.state.middle || | ||
that.mouse.state.right) { | ||
that.mouse.delta.x = e.pageX - that.mouse.previousPosition.x; | ||
that.mouse.delta.y = e.pageY - that.mouse.previousPosition.y; | ||
that.mouse.state.right) | ||
) { | ||
that.mouse.delta.x = pointerLoc[0] - that.mouse.previousPosition.x; | ||
that.mouse.delta.y = pointerLoc[1] - that.mouse.previousPosition.y; | ||
that.mouse.position.x += 0.01 * that.mouse.delta.x; | ||
that.mouse.position.y += 0.01 * that.mouse.delta.y; | ||
// Give priority to left, then middle, then right | ||
if (that.mouse.state.left) { | ||
that.raiseEvent('mousedrag', { | ||
that.raiseEvent("mousedrag", { | ||
e: that.mouse.delta, | ||
source: 'left' | ||
source: "left" | ||
}); | ||
} else if (that.mouse.state.middle) { | ||
that.raiseEvent('mousedrag', { | ||
that.raiseEvent("mousedrag", { | ||
e: that.mouse.delta, | ||
source: 'middle' | ||
source: "middle" | ||
}); | ||
} else if (that.mouse.state.right) { | ||
that.raiseEvent('mousedrag', { | ||
that.raiseEvent("mousedrag", { | ||
e: that.mouse.delta, | ||
source: 'right' | ||
source: "right" | ||
}); | ||
@@ -107,99 +151,20 @@ } | ||
let s = that.renderer.devicePixelRatio; | ||
that.mouse.normalizedPosition.x = ((e.clientX - rect.left * s) / that.canvas.width * s) * 2 - 1; | ||
that.mouse.normalizedPosition.y = -((e.clientY - rect.top * s) / that.canvas.height * s) * 2 + 1; | ||
that.mouse.normalizedPosition.x = | ||
((e.clientX - rect.left * s) / that.canvas.width) * s * 2 - 1; | ||
that.mouse.normalizedPosition.y = | ||
-(((e.clientY - rect.top * s) / that.canvas.height) * s) * 2 + 1; | ||
that.raiseEvent('mousemove', { | ||
that.raiseEvent("mousemove", { | ||
e: that | ||
}); | ||
that.mouse.previousPosition.x = e.pageX; | ||
that.mouse.previousPosition.y = e.pageY; | ||
that.mouse.previousPosition.x = pointerLoc[0]; | ||
that.mouse.previousPosition.y = pointerLoc[1]; | ||
}); | ||
this.canvas.addEventListener('touchstart', function (e) { | ||
that.mouse.touches++; | ||
let touch = e.touches[0]; | ||
e.preventDefault(); | ||
let wheelevent = "mousewheel"; | ||
if (navigator.userAgent.toLowerCase().indexOf("firefox") > -1) | ||
wheelevent = "DOMMouseScroll"; | ||
that.mouse.touched = true; | ||
that.renderer.setMaxFps(that.highFps); | ||
// This is for selecting stuff when touching but not moving | ||
// Set normalized mouse position | ||
let rect = that.canvas.getBoundingClientRect(); | ||
that.mouse.normalizedPosition.x = ((touch.clientX - rect.left) / that.canvas.width) * 2 - 1; | ||
that.mouse.normalizedPosition.y = -((touch.clientY - rect.top) / that.canvas.height) * 2 + 1; | ||
if (that.touchMode !== 'drag') { | ||
that.raiseEvent('mousemove', { | ||
e: that | ||
}); | ||
} | ||
that.raiseEvent('mousedown', { | ||
e: that, | ||
source: 'touch' | ||
}); | ||
}); | ||
this.canvas.addEventListener('touchend', function (e) { | ||
that.mouse.touches--; | ||
e.preventDefault(); | ||
that.mouse.touched = false; | ||
// Reset the previous position and delta of the mouse | ||
that.mouse.previousPosition.x = null; | ||
that.mouse.previousPosition.y = null; | ||
that.renderer.setMaxFps(that.lowFps); | ||
that.raiseEvent('mouseup', { | ||
e: that, | ||
source: 'touch' | ||
}); | ||
}); | ||
this.canvas.addEventListener('touchmove', function (e) { | ||
let touch = e.touches[0]; | ||
let source = 'left'; | ||
if (that.mouse.touches == 2) source = 'right'; | ||
e.preventDefault(); | ||
if (that.mouse.previousPosition.x !== null && that.mouse.touched) { | ||
that.mouse.delta.x = touch.pageX - that.mouse.previousPosition.x; | ||
that.mouse.delta.y = touch.pageY - that.mouse.previousPosition.y; | ||
that.mouse.position.x += 0.01 * that.mouse.delta.x; | ||
that.mouse.position.y += 0.01 * that.mouse.delta.y; | ||
if (that.touchMode === 'drag') | ||
that.raiseEvent('mousedrag', { | ||
e: that.mouse.delta, | ||
source: source | ||
}); | ||
} | ||
// Set normalized mouse position | ||
let rect = that.canvas.getBoundingClientRect(); | ||
that.mouse.normalizedPosition.x = ((touch.clientX - rect.left) / that.canvas.width) * 2 - 1; | ||
that.mouse.normalizedPosition.y = -((touch.clientY - rect.top) / that.canvas.height) * 2 + 1; | ||
if (that.touchMode !== 'drag') | ||
that.raiseEvent('mousemove', { | ||
e: that | ||
}); | ||
that.mouse.previousPosition.x = touch.pageX; | ||
that.mouse.previousPosition.y = touch.pageY; | ||
}); | ||
let wheelevent = 'mousewheel'; | ||
if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) wheelevent = 'DOMMouseScroll'; | ||
this.canvas.addEventListener(wheelevent, function (e) { | ||
this.canvas.addEventListener(wheelevent, function(e) { | ||
if (that.isInIframe() && !e.ctrlKey) { | ||
@@ -211,4 +176,4 @@ return; | ||
let delta = 'wheelDelta' in e ? e.wheelDelta : -40 * e.detail; | ||
that.raiseEvent('mousewheel', { | ||
let delta = "wheelDelta" in e ? e.wheelDelta : -40 * e.detail; | ||
that.raiseEvent("mousewheel", { | ||
e: delta | ||
@@ -218,3 +183,3 @@ }); | ||
this.canvas.addEventListener('keydown', function (e) { | ||
this.canvas.addEventListener("keydown", function(e) { | ||
if (e.which == 16) { | ||
@@ -228,8 +193,8 @@ that.keyboard.shift = true; | ||
that.raiseEvent('keydown', { | ||
that.raiseEvent("keydown", { | ||
e: e.which | ||
}) | ||
}); | ||
}); | ||
this.canvas.addEventListener('keyup', function (e) { | ||
this.canvas.addEventListener("keyup", function(e) { | ||
if (e.which == 16) { | ||
@@ -243,3 +208,3 @@ that.keyboard.shift = false; | ||
that.raiseEvent('keyup', { | ||
that.raiseEvent("keyup", { | ||
e: e.which | ||
@@ -249,5 +214,6 @@ }); | ||
this.canvas.addEventListener('mousedown', function (e) { | ||
this.canvas.addEventListener("pointerdown", function(e) { | ||
let btn = e.button; | ||
let source = 'left'; | ||
let source = "left"; | ||
that.mouse.pointerCache.push(e); | ||
@@ -259,6 +225,6 @@ // Only handle single button events | ||
that.mouse.state.middle = true; | ||
source = 'middle'; | ||
source = "middle"; | ||
} else if (btn == 2) { | ||
that.mouse.state.right = true; | ||
source = 'right'; | ||
source = "right"; | ||
} | ||
@@ -268,3 +234,3 @@ | ||
that.raiseEvent('mousedown', { | ||
that.raiseEvent("mousedown", { | ||
e: that, | ||
@@ -275,7 +241,7 @@ source: source | ||
this.canvas.addEventListener('click', function (e) { | ||
this.canvas.addEventListener("click", function(e) { | ||
let btn = e.button; | ||
let source = 'left'; | ||
let source = "left"; | ||
that.raiseEvent('click', { | ||
that.raiseEvent("click", { | ||
e: that, | ||
@@ -286,7 +252,7 @@ source: source | ||
this.canvas.addEventListener('dblclick', function (e) { | ||
this.canvas.addEventListener("dblclick", function(e) { | ||
let btn = e.button; | ||
let source = 'left'; | ||
let source = "left"; | ||
that.raiseEvent('dblclick', { | ||
that.raiseEvent("dblclick", { | ||
e: that, | ||
@@ -297,5 +263,8 @@ source: source | ||
this.canvas.addEventListener('mouseup', function (e) { | ||
// This function is added to multiple pointer events | ||
let pointerUpEvent = function(e) { | ||
let btn = e.button; | ||
let source = 'left'; | ||
let source = "left"; | ||
that.removeEvent(e); | ||
that.mouse.pinchDiff = 0; | ||
@@ -307,6 +276,6 @@ // Only handle single button events | ||
that.mouse.state.middle = false; | ||
source = 'middle'; | ||
source = "middle"; | ||
} else if (btn == 2) { | ||
that.mouse.state.right = false; | ||
source = 'right'; | ||
source = "right"; | ||
} | ||
@@ -317,12 +286,2 @@ | ||
that.mouse.previousPosition.y = null; | ||
that.renderer.setMaxFps(that.lowFps); | ||
that.raiseEvent('mouseup', { | ||
e: that, | ||
source: source | ||
}); | ||
}); | ||
this.canvas.addEventListener('mouseleave', function (e) { | ||
that.mouse.state.left = false; | ||
@@ -332,14 +291,21 @@ that.mouse.state.middle = false; | ||
that.mouse.previousPosition.x = null; | ||
that.mouse.previousPosition.y = null; | ||
that.renderer.setMaxFps(that.lowFps); | ||
that.raiseEvent('mouseleave', { | ||
that.raiseEvent("mouseup", { | ||
e: that, | ||
source: that.canvas | ||
source: source | ||
}); | ||
}; | ||
this.canvas.addEventListener("pointerup", function(e) { | ||
pointerUpEvent(e); | ||
}); | ||
this.canvas.addEventListener("pointercancel", function(e) { | ||
pointerUpEvent(e); | ||
}); | ||
this.canvas.addEventListener("pointerleave", function(e) { | ||
pointerUpEvent(e); | ||
}); | ||
} | ||
@@ -368,3 +334,3 @@ | ||
* Adds an event listener to this controls instance. | ||
* | ||
* | ||
* @param {String} eventName The name of the event that is to be listened for. | ||
@@ -383,3 +349,3 @@ * @param {Function} callback A callback function to be called on the event being fired. | ||
* Remove an event listener from this controls instance. | ||
* | ||
* | ||
* @param {String} eventName The name of the event that is to be listened for. | ||
@@ -402,3 +368,3 @@ * @param {Function} callback A callback function to be called on the event being fired. | ||
* Raises an event. | ||
* | ||
* | ||
* @param {String} eventName The name of the event to be raised. | ||
@@ -417,3 +383,3 @@ * @param {*} [data={}] The data to be supplied to the callback function. | ||
* Returns the current look at vector associated with this controls. | ||
* | ||
* | ||
* @returns {Vector3f} The current look at vector. | ||
@@ -427,3 +393,3 @@ */ | ||
* Sets the lookat vector, which is the center of the orbital camera sphere. | ||
* | ||
* | ||
* @param {Vector3f} lookAt The lookat vector. | ||
@@ -442,3 +408,3 @@ * @returns {ControlsBase} Returns itself. | ||
* Update the camera (on mouse move, touch drag, mousewheel scroll, ...). | ||
* | ||
* | ||
* @param {*} [e=null] A mouse or touch events data. | ||
@@ -454,3 +420,3 @@ * @param {String} [source=null] The source of the input ('left', 'middle', 'right', 'wheel', ...). | ||
* Checks whether the script is being run in an IFrame. | ||
* | ||
* | ||
* @returns {Boolean} Returns whether the script is run in an IFrame. | ||
@@ -465,4 +431,39 @@ */ | ||
} | ||
/** | ||
* Removes a pointer event from the event cache. | ||
* | ||
* @param {PointerEvent} e The pointer event | ||
*/ | ||
removeEvent(e) { | ||
for (var i = 0; i < this.mouse.pointerCache.length; i++) { | ||
if (this.mouse.pointerCache[i].pointerId == e.pointerId) { | ||
this.mouse.pointerCache.splice(i, 1); | ||
break; | ||
} | ||
} | ||
} | ||
/** | ||
* Get the position of the pointer (e.g. the mouse). In case of multi- | ||
* touch, the center of mass is returned. | ||
* | ||
* @returns {Number[]} The pointer position | ||
*/ | ||
getPointerLocation() { | ||
let x = 0; | ||
let y = 0; | ||
let n = this.mouse.pointerCache.length; | ||
if (n === 0) return [null, null]; | ||
for (var i = 0; i < n; i++) { | ||
x += this.mouse.pointerCache[i].pageX; | ||
y += this.mouse.pointerCache[i].pageY; | ||
} | ||
return [x, y]; | ||
} | ||
} | ||
module.exports = ControlsBase; | ||
module.exports = ControlsBase; |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ const ControlsBase = require('./ControlsBase'); |
@@ -53,2 +53,6 @@ //@ts-check | ||
this.addEventListener('touch', function (e) { | ||
that.update(e.e, e.source); | ||
}); | ||
this.addEventListener('mousewheel', function (e) { | ||
@@ -130,3 +134,3 @@ that.update({ | ||
this._dPan.components[2] = r[2] * -x + u[2] * y; | ||
} else if (source == 'middle' || source == 'wheel') { | ||
} else if (source == 'middle' || source == 'wheel' || source == 'pinch') { | ||
if (e.y > 0) { | ||
@@ -133,0 +137,0 @@ // Zoom Out |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ const Attribute = require('./Attribute'); |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -14,3 +14,3 @@ //@ts-check | ||
class Shader { | ||
constructor(name, glVersion, uniforms, vertexShader, fragmentShader) { | ||
constructor(name, glVersion, uniforms, vertexShader, fragmentShader, fallback = 'default') { | ||
this.name = name; | ||
@@ -21,2 +21,3 @@ this.uniforms = uniforms || {}; | ||
this.glVersion = glVersion; | ||
this.fallback = fallback; | ||
this.gl = null; | ||
@@ -23,0 +24,0 @@ this.program = null; |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ const FilterBase = require('./FilterBase'); |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -25,2 +25,11 @@ //@ts-check | ||
super(); | ||
// Check whether the shader requires WebGL 2.0, if it does and the | ||
// machine doesn't support it, go to callback. | ||
if (Shaders[shaderName].glVersion === 2 && !this.renderer.webgl2) { | ||
console.warn('Switching from ' + shaderName + ' to fallback shader ' + | ||
Shaders[shaderName].fallback + ' due to missing WebGL2 support.'); | ||
shaderName = Shaders[shaderName].fallback; | ||
} | ||
this.renderer = renderer; | ||
@@ -27,0 +36,0 @@ this.shader = Shaders[shaderName].clone(); |
@@ -0,0 +0,0 @@ const AABBHelper = require('./AABBHelper'); |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ const CsvFileReader = require('./CsvFileReader'); |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ const Core = require('./Core'); |
@@ -0,0 +0,0 @@ const Matrix3f = require('./Matrix3f'); |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ const Shader = require('../Core/Shader') |
@@ -0,0 +0,0 @@ const Shader = require('../Core/Shader') |
@@ -0,0 +0,0 @@ const Shader = require('../Core/Shader') |
@@ -0,0 +0,0 @@ const Shader = require('../Core/Shader') |
@@ -0,0 +0,0 @@ const Shader = require('../Core/Shader') |
@@ -0,0 +0,0 @@ const Shader = require('../Core/Shader') |
@@ -0,0 +0,0 @@ var circle = require('./Circle'); |
@@ -54,2 +54,2 @@ const Shader = require('../Core/Shader') | ||
'}' | ||
]); | ||
], 'circle'); |
@@ -0,0 +0,0 @@ const Shader = require('../Core/Shader') |
@@ -0,0 +0,0 @@ const Shader = require('../Core/Shader') |
@@ -0,0 +0,0 @@ const Shader = require('../Core/Shader') |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ const AABB = require('./AABB'); |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ //@ts-check |
@@ -0,0 +0,0 @@ const Utils = require('./Utils'); |
@@ -0,0 +0,0 @@ //@ts-check |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
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 too big to display
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
43966139
20800
188