Comparing version
{ | ||
"name": "verto", | ||
"version": "0.0.2", | ||
"version": "0.1.0", | ||
"license": "MPL 1.1", | ||
"devDependencies": { | ||
@@ -5,0 +6,0 @@ "grunt": "~0.4.5", |
@@ -103,19 +103,7 @@ /* | ||
this.constraints = { | ||
offerToReceiveAudio: this.options.useSpeak === "none" ? false : true, | ||
offerToReceiveVideo: this.options.useVideo ? true : false, | ||
}; | ||
if (moz) { | ||
this.constraints = { | ||
offerToReceiveAudio: this.options.useSpeak === "none" ? false : true, | ||
offerToReceiveVideo: this.options.useVideo ? true : false, | ||
}; | ||
} else { | ||
this.constraints = { | ||
optional: [{ | ||
'DtlsSrtpKeyAgreement': 'true' | ||
}],mandatory: { | ||
OfferToReceiveAudio: this.options.useSpeak === "none" ? false : true, | ||
OfferToReceiveVideo: this.options.useVideo ? true : false, | ||
} | ||
}; | ||
} | ||
if (self.options.useVideo) { | ||
@@ -137,15 +125,7 @@ self.options.useVideo.style.display = 'none'; | ||
self.options.localVideo = local; | ||
if (moz) { | ||
self.constraints.offerToReceiveVideo = true; | ||
} else { | ||
self.constraints.mandatory.OfferToReceiveVideo = true; | ||
} | ||
self.constraints.offerToReceiveVideo = true; | ||
} else { | ||
self.options.useVideo = null; | ||
self.options.localVideo = null; | ||
if (moz) { | ||
self.constraints.offerToReceiveVideo = false; | ||
} else { | ||
self.constraints.mandatory.OfferToReceiveVideo = false; | ||
} | ||
self.constraints.offerToReceiveVideo = false; | ||
} | ||
@@ -198,14 +178,5 @@ | ||
function setCompat() { | ||
$.FSRTC.moz = !!navigator.mozGetUserMedia; | ||
//navigator.getUserMedia || (navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia); | ||
if (!navigator.getUserMedia) { | ||
navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia; | ||
} | ||
} | ||
function checkCompat() { | ||
if (!navigator.getUserMedia) { | ||
alert('This application cannot function in this browser.'); | ||
return false; | ||
} | ||
return true; | ||
@@ -264,5 +235,21 @@ } | ||
FSRTCattachMediaStream = function(element, stream) { | ||
if (typeof element.srcObject !== 'undefined') { | ||
element.srcObject = stream; | ||
} else { | ||
console.error('Error attaching stream to element.'); | ||
} | ||
} | ||
function onRemoteStream(self, stream) { | ||
if (self.options.useVideo) { | ||
self.options.useVideo.style.display = 'block'; | ||
// Hacks for Mobile Safari | ||
var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0; | ||
if (iOS) { | ||
self.options.useVideo.setAttribute("playsinline", true); | ||
self.options.useVideo.setAttribute("controls", true); | ||
} | ||
} | ||
@@ -273,13 +260,7 @@ | ||
if (typeof element.srcObject !== 'undefined') { | ||
element.srcObject = stream; | ||
} else if (typeof element.mozSrcObject !== 'undefined') { | ||
element.mozSrcObject = stream; | ||
} else if (typeof element.src !== 'undefined') { | ||
element.src = URL.createObjectURL(stream); | ||
} else { | ||
console.error('Error attaching stream to element.'); | ||
} | ||
FSRTCattachMediaStream(element, stream); | ||
self.options.useAudio.play(); | ||
//self.options.useAudio.play(); | ||
self.remoteStream = stream; | ||
@@ -314,7 +295,3 @@ } | ||
self.options.useVideo.style.display = 'none'; | ||
if (moz) { | ||
self.options.useVideo['mozSrcObject'] = null; | ||
} else { | ||
self.options.useVideo['src'] = ''; | ||
} | ||
self.options.useVideo['src'] = ''; | ||
} | ||
@@ -328,3 +305,3 @@ | ||
var tracks = self.localStream.getTracks(); | ||
console.error(tracks); | ||
console.log(tracks); | ||
tracks.forEach(function(track, index){ | ||
@@ -341,7 +318,3 @@ console.log(track); | ||
self.options.localVideo.style.display = 'none'; | ||
if (moz) { | ||
self.options.localVideo['mozSrcObject'] = null; | ||
} else { | ||
self.options.localVideo['src'] = ''; | ||
} | ||
self.options.localVideo['src'] = ''; | ||
} | ||
@@ -355,3 +328,3 @@ | ||
var tracks = self.options.localVideoStream.getTracks(); | ||
console.error(tracks); | ||
console.log(tracks); | ||
tracks.forEach(function(track, index){ | ||
@@ -378,2 +351,5 @@ console.log(track); | ||
var self = this; | ||
if (!self.localStream) { | ||
return false; | ||
} | ||
var audioTracks = self.localStream.getAudioTracks(); | ||
@@ -408,2 +384,5 @@ | ||
var self = this; | ||
if (!self.localStream) { | ||
return false; | ||
} | ||
var videoTracks = self.localStream.getVideoTracks(); | ||
@@ -440,3 +419,3 @@ | ||
self.peer = RTCPeerConnection({ | ||
self.peer = FSRTCPeerConnection({ | ||
type: self.type, | ||
@@ -464,6 +443,7 @@ attachStream: self.localStream, | ||
sdp: self.remoteSDP | ||
} | ||
}, | ||
turnServer: self.options.turnServer | ||
}); | ||
onStreamSuccess(self); | ||
onStreamSuccess(self, stream); | ||
} | ||
@@ -484,6 +464,3 @@ | ||
audio: false, | ||
video: { | ||
mandatory: self.options.videoParams, | ||
optional: [] | ||
}, | ||
video: { deviceId: params.useCamera }, | ||
}, | ||
@@ -518,31 +495,16 @@ localVideo: self.options.localVideo, | ||
} else if (obj.options.videoParams && obj.options.screenShare) {//obj.options.videoParams.chromeMediaSource == 'desktop') { | ||
//obj.options.videoParams = { | ||
// chromeMediaSource: 'screen', | ||
// maxWidth:screen.width, | ||
// maxHeight:screen.height | ||
// chromeMediaSourceId = sourceId; | ||
// }; | ||
console.error("SCREEN SHARE"); | ||
console.error("SCREEN SHARE", obj.options.videoParams); | ||
audio = false; | ||
} else { | ||
audio = { | ||
mandatory: {}, | ||
optional: [] | ||
}; | ||
if (obj.options.audioParams) { | ||
audio = obj.options.audioParams; | ||
} | ||
if (obj.options.useMic !== "any") { | ||
audio.optional = [{sourceId: obj.options.useMic}] | ||
//audio.optional = [{sourceId: obj.options.useMic}]; | ||
audio.deviceId = {exact: obj.options.useMic}; | ||
} | ||
if (obj.options.audioParams) { | ||
for (var key in obj.options.audioParams) { | ||
var con = {}; | ||
con[key] = obj.options.audioParams[key]; | ||
audio.optional.push(con); | ||
} | ||
} | ||
} | ||
@@ -554,9 +516,6 @@ | ||
audio: false, | ||
video: { | ||
mandatory: obj.options.videoParams, | ||
optional: [] | ||
}, | ||
video: { deviceId: obj.options.useCamera }, | ||
}, | ||
localVideo: obj.options.localVideo, | ||
onsuccess: function(e) {self.options.localVideoStream = e; console.log("local video ready");}, | ||
onsuccess: function(e) {obj.options.localVideoStream = e; console.log("local video ready");}, | ||
onerror: function(e) {console.error("local video error!");} | ||
@@ -568,29 +527,65 @@ }); | ||
var bestFrameRate = obj.options.videoParams.vertoBestFrameRate; | ||
var minFrameRate = obj.options.videoParams.minFrameRate || 15; | ||
delete obj.options.videoParams.vertoBestFrameRate; | ||
video = { | ||
mandatory: obj.options.videoParams, | ||
optional: [] | ||
} | ||
var useVideo = obj.options.useVideo; | ||
if (obj.options.screenShare) { | ||
if (!obj.options.useCamera && !!navigator.mozGetUserMedia) { | ||
//This is an issue, only FireFox needs to ask this additional question if its screen or window we need a better way | ||
var dowin = window.confirm("Do you want to share an application window? If not you can share an entire screen."); | ||
if (useVideo && obj.options.useCamera && obj.options.useCamera !== "none") { | ||
if (!video.optional) { | ||
video.optional = []; | ||
video = { | ||
width: {min: obj.options.videoParams.minWidth, max: obj.options.videoParams.maxWidth}, | ||
height: {min: obj.options.videoParams.minHeight, max: obj.options.videoParams.maxHeight}, | ||
mediaSource: dowin ? "window" : "screen" | ||
} | ||
} else { | ||
var opt = []; | ||
if (obj.options.useCamera) { | ||
opt.push({sourceId: obj.options.useCamera}); | ||
} | ||
if (bestFrameRate) { | ||
opt.push({minFrameRate: bestFrameRate}); | ||
opt.push({maxFrameRate: bestFrameRate}); | ||
} | ||
video = { | ||
mandatory: obj.options.videoParams, | ||
optional: opt | ||
}; | ||
} | ||
} else { | ||
if (obj.options.useCamera !== "any") { | ||
video.optional.push({sourceId: obj.options.useCamera}); | ||
} | ||
video = { | ||
//mandatory: obj.options.videoParams, | ||
width: {min: obj.options.videoParams.minWidth, max: obj.options.videoParams.maxWidth}, | ||
height: {min: obj.options.videoParams.minHeight, max: obj.options.videoParams.maxHeight} | ||
}; | ||
var useVideo = obj.options.useVideo; | ||
if (bestFrameRate) { | ||
video.optional.push({minFrameRate: bestFrameRate}); | ||
video.optional.push({maxFrameRate: bestFrameRate}); | ||
if (useVideo && obj.options.useCamera && obj.options.useCamera !== "none") { | ||
//if (!video.optional) { | ||
//video.optional = []; | ||
//} | ||
if (obj.options.useCamera !== "any") { | ||
//video.optional.push({sourceId: obj.options.useCamera}); | ||
video.deviceId = obj.options.useCamera; | ||
} | ||
if (bestFrameRate) { | ||
//video.optional.push({minFrameRate: bestFrameRate}); | ||
//video.optional.push({maxFrameRate: bestFrameRate}); | ||
video.frameRate = {ideal: bestFrameRate, min: minFrameRate, max: 30}; | ||
} | ||
} else { | ||
console.log("Camera Disabled"); | ||
video = false; | ||
useVideo = false; | ||
} | ||
} else { | ||
console.log("Camera Disabled"); | ||
video = false; | ||
useVideo = false; | ||
} | ||
@@ -617,10 +612,8 @@ | ||
if (screen) { | ||
if (moz) { | ||
self.constraints.OfferToReceiveVideo = false; | ||
} else { | ||
self.constraints.mandatory.OfferToReceiveVideo = false; | ||
} | ||
self.constraints.offerToReceiveVideo = false; | ||
self.constraints.offerToReceiveAudio = false; | ||
self.constraints.offerToSendAudio = false; | ||
} | ||
self.peer = RTCPeerConnection({ | ||
self.peer = FSRTCPeerConnection({ | ||
type: self.type, | ||
@@ -648,2 +641,3 @@ attachStream: self.localStream, | ||
iceServers: self.options.iceServers, | ||
turnServer: self.options.turnServer | ||
}); | ||
@@ -668,3 +662,3 @@ | ||
audio: mediaParams.audio, | ||
video: mediaParams.video | ||
video: mediaParams.video | ||
}, | ||
@@ -675,2 +669,3 @@ video: mediaParams.useVideo, | ||
}); | ||
} else { | ||
@@ -695,54 +690,24 @@ onSuccess(null); | ||
// Documentation - https://github.com/muaz-khan/WebRTC-Experiment/tree/master/RTCPeerConnection | ||
window.moz = !!navigator.mozGetUserMedia; | ||
function RTCPeerConnection(options) { | ||
function FSRTCPeerConnection(options) { | ||
var gathering = false, done = false; | ||
var config = {}; | ||
var default_ice = [{ urls: ['stun:stun.l.google.com:19302'] }]; | ||
var w = window, | ||
PeerConnection = w.mozRTCPeerConnection || w.webkitRTCPeerConnection, | ||
SessionDescription = w.mozRTCSessionDescription || w.RTCSessionDescription, | ||
IceCandidate = w.mozRTCIceCandidate || w.RTCIceCandidate; | ||
var STUN = { | ||
url: !moz ? 'stun:stun.l.google.com:19302' : 'stun:23.21.150.121' | ||
}; | ||
if (self.options.turnServer) { | ||
default_ice.push(self.options.turnServer) | ||
} | ||
var iceServers = null; | ||
if (options.iceServers) { | ||
var tmp = options.iceServers; | ||
if (typeof(tmp) === "boolean") { | ||
tmp = null; | ||
} | ||
if (tmp && !(typeof(tmp) == "object" && tmp.constructor === Array)) { | ||
console.warn("iceServers must be an array, reverting to default ice servers"); | ||
tmp = null; | ||
} | ||
iceServers = { | ||
iceServers: tmp || [STUN] | ||
}; | ||
if (!moz && !tmp) { | ||
iceServers.iceServers = [STUN]; | ||
} | ||
if (typeof(options.iceServers) === "boolean") { | ||
config.iceServers = default_ice; | ||
} else { | ||
config.iceServers = options.iceServers; | ||
} | ||
} | ||
var optional = { | ||
optional: [] | ||
}; | ||
config.bundlePolicy = "max-compat"; | ||
if (!moz) { | ||
optional.optional = [{ | ||
DtlsSrtpKeyAgreement: true | ||
}, | ||
{ | ||
RtpDataChannels: options.onChannelMessage ? true : false | ||
}]; | ||
} | ||
var peer = new window.RTCPeerConnection(config); | ||
var peer = new PeerConnection(iceServers, optional); | ||
openOffererChannel(); | ||
@@ -761,30 +726,6 @@ var x = 0; | ||
if (options.type == "offer") { | ||
if ((!moz || (!options.sentICESDP && peer.localDescription.sdp.match(/a=candidate/)) && !x && options.onICESDP)) { | ||
options.onICESDP(peer.localDescription); | ||
//x = 1; | ||
/* | ||
x = 1; | ||
peer.createOffer(function(sessionDescription) { | ||
sessionDescription.sdp = serializeSdp(sessionDescription.sdp); | ||
peer.setLocalDescription(sessionDescription); | ||
if (options.onICESDP) { | ||
options.onICESDP(sessionDescription); | ||
} | ||
}, onSdpError, constraints); | ||
*/ | ||
} | ||
options.onICESDP(peer.localDescription); | ||
} else { | ||
if (!x && options.onICESDP) { | ||
options.onICESDP(peer.localDescription); | ||
//x = 1; | ||
/* | ||
x = 1; | ||
peer.createAnswer(function(sessionDescription) { | ||
sessionDescription.sdp = serializeSdp(sessionDescription.sdp); | ||
peer.setLocalDescription(sessionDescription); | ||
if (options.onICESDP) { | ||
options.onICESDP(sessionDescription); | ||
} | ||
}, onSdpError, constraints); | ||
*/ | ||
} | ||
@@ -837,3 +778,3 @@ } | ||
// onRemoteStreamEnded(MediaStream) | ||
remoteMediaStream.onended = function() { | ||
remoteMediaStream.oninactive = function () { | ||
if (options.onRemoteStreamEnded) options.onRemoteStreamEnded(remoteMediaStream); | ||
@@ -848,6 +789,6 @@ }; | ||
var constraints = options.constraints || { | ||
offerToReceiveAudio: true, | ||
offerToReceiveVideo: true | ||
}; | ||
//var constraints = options.constraints || { | ||
// offerToReceiveAudio: true, | ||
//offerToReceiveVideo: true | ||
//}; | ||
@@ -862,9 +803,4 @@ // onOfferSDP(RTCSessionDescription) | ||
options.onOfferSDP(sessionDescription); | ||
/* old mozilla behaviour the SDP was already great right away */ | ||
if (moz && options.onICESDP && sessionDescription.sdp.match(/a=candidate/)) { | ||
options.onICESDP(sessionDescription); | ||
options.sentICESDP = 1; | ||
} | ||
}, | ||
onSdpError, constraints); | ||
onSdpError, options.constraints); | ||
} | ||
@@ -877,3 +813,3 @@ | ||
//options.offerSDP.sdp = addStereo(options.offerSDP.sdp); | ||
peer.setRemoteDescription(new SessionDescription(options.offerSDP), onSdpSuccess, onSdpError); | ||
peer.setRemoteDescription(new window.RTCSessionDescription(options.offerSDP), onSdpSuccess, onSdpError); | ||
peer.createAnswer(function(sessionDescription) { | ||
@@ -886,7 +822,7 @@ sessionDescription.sdp = serializeSdp(sessionDescription.sdp); | ||
}, | ||
onSdpError, constraints); | ||
onSdpError); | ||
} | ||
// if Mozilla Firefox & DataChannel; offer/answer will be created later | ||
if ((options.onChannelMessage && !moz) || !options.onChannelMessage) { | ||
if ((options.onChannelMessage) || !options.onChannelMessage) { | ||
createOffer(); | ||
@@ -930,5 +866,2 @@ createAnswer(); | ||
function serializeSdp(sdp) { | ||
//if (!moz) sdp = setBandwidth(sdp); | ||
//sdp = getInteropSDP(sdp); | ||
//console.debug(sdp); | ||
return sdp; | ||
@@ -941,25 +874,14 @@ } | ||
function openOffererChannel() { | ||
if (!options.onChannelMessage || (moz && !options.onOfferSDP)) return; | ||
if (!options.onChannelMessage) return; | ||
_openOffererChannel(); | ||
if (!moz) return; | ||
navigator.mozGetUserMedia({ | ||
audio: true, | ||
fake: true | ||
}, | ||
function(stream) { | ||
peer.addStream(stream); | ||
createOffer(); | ||
}, | ||
useless); | ||
return; | ||
} | ||
function _openOffererChannel() { | ||
channel = peer.createDataChannel(options.channel || 'RTCDataChannel', moz ? {} : { | ||
channel = peer.createDataChannel(options.channel || 'RTCDataChannel', { | ||
reliable: false | ||
}); | ||
if (moz) channel.binaryType = 'blob'; | ||
setChannelEvents(); | ||
@@ -988,4 +910,2 @@ } | ||
if (options.onAnswerSDP && moz && options.onChannelMessage) openAnswererChannel(); | ||
function openAnswererChannel() { | ||
@@ -998,12 +918,3 @@ peer.ondatachannel = function(event) { | ||
if (!moz) return; | ||
navigator.mozGetUserMedia({ | ||
audio: true, | ||
fake: true | ||
}, | ||
function(stream) { | ||
peer.addStream(stream); | ||
createAnswer(); | ||
}, | ||
useless); | ||
return; | ||
} | ||
@@ -1028,6 +939,6 @@ | ||
peer.setRemoteDescription(new SessionDescription(sdp), cbSuccess ? cbSuccess : onSdpSuccess, cbError ? cbError : onSdpError); | ||
peer.setRemoteDescription(new window.RTCSessionDescription(sdp), cbSuccess ? cbSuccess : onSdpSuccess, cbError ? cbError : onSdpError); | ||
}, | ||
addICE: function(candidate) { | ||
peer.addIceCandidate(new IceCandidate({ | ||
peer.addIceCandidate(new window.RTCIceCandidate({ | ||
sdpMLineIndex: candidate.sdpMLineIndex, | ||
@@ -1062,4 +973,4 @@ candidate: candidate.candidate | ||
var video_constraints = { | ||
mandatory: {}, | ||
optional: [] | ||
//mandatory: {}, | ||
//optional: [] | ||
}; | ||
@@ -1070,3 +981,3 @@ | ||
media; | ||
n.getMedia = n.webkitGetUserMedia || n.mozGetUserMedia; | ||
n.getMedia = n.getUserMedia; | ||
n.getMedia(options.constraints || { | ||
@@ -1082,11 +993,4 @@ audio: true, | ||
function streaming(stream) { | ||
//var video = options.video; | ||
//var localVideo = options.localVideo; | ||
//if (video) { | ||
// video[moz ? 'mozSrcObject' : 'src'] = moz ? stream : window.webkitURL.createObjectURL(stream); | ||
//video.play(); | ||
//} | ||
if (options.localVideo) { | ||
options.localVideo[moz ? 'mozSrcObject' : 'src'] = moz ? stream : window.webkitURL.createObjectURL(stream); | ||
options.localVideo['srcObject'] = stream; | ||
options.localVideo.style.display = 'block'; | ||
@@ -1119,3 +1023,3 @@ } | ||
for (var i in $.FSRTC.validRes) { | ||
if ($.FSRTC.validRes[i][0] > w && $.FSRTC.validRes[i][1] > h) { | ||
if ($.FSRTC.validRes[i][0] >= w && $.FSRTC.validRes[i][1] >= h) { | ||
w = $.FSRTC.validRes[i][0]; | ||
@@ -1129,3 +1033,3 @@ h = $.FSRTC.validRes[i][1]; | ||
var resList = [[320, 180], [320, 240], [640, 360], [640, 480], [1280, 720], [1920, 1080]]; | ||
var resList = [[160, 120], [320, 180], [320, 240], [640, 360], [640, 480], [1280, 720], [1920, 1080]]; | ||
var resI = 0; | ||
@@ -1149,8 +1053,9 @@ var ttl = 0; | ||
var video = { | ||
mandatory: {}, | ||
optional: [] | ||
//mandatory: {}, | ||
//optional: [] | ||
} | ||
//FIXME | ||
if (cam) { | ||
video.optional = [{sourceId: cam}]; | ||
//video.optional = [{sourceId: cam}]; | ||
video.deviceId = {exact: cam}; | ||
} | ||
@@ -1162,7 +1067,9 @@ | ||
video.mandatory = { | ||
"minWidth": w, | ||
"minHeight": h, | ||
"maxWidth": w, | ||
"maxHeight": h | ||
video = { | ||
width: {exact: w}, | ||
height: {exact: h} | ||
//"minWidth": w, | ||
//"minHeight": h, | ||
//"maxWidth": w, | ||
//"maxHeight": h | ||
}; | ||
@@ -1178,3 +1085,3 @@ | ||
console.info(w + "x" + h + " supported."); $.FSRTC.validRes.push([w, h]); checkRes(cam, func);}, | ||
onerror: function(e) {console.error( w + "x" + h + " not supported."); checkRes(cam, func);} | ||
onerror: function(e) {console.warn( w + "x" + h + " not supported."); checkRes(cam, func);} | ||
}); | ||
@@ -1214,2 +1121,3 @@ } | ||
onsuccess: function(e) { | ||
e.getTracks().forEach(function(track) {track.stop();}); | ||
@@ -1216,0 +1124,0 @@ |
@@ -325,2 +325,6 @@ /* | ||
if (self.ws_cnt > 10 && self.options.wsFallbackURL) { | ||
self.options.socketUrl = self.options.wsFallbackURL; | ||
} | ||
console.error("Websocket Lost " + self.ws_cnt + " sleep: " + self.ws_sleep + "msec"); | ||
@@ -363,2 +367,7 @@ | ||
$.JsonRpcClient.prototype.stopRetrying = function() { | ||
if (self.to) | ||
clearTimeout(self.to); | ||
} | ||
$.JsonRpcClient.prototype._getSocket = function(onmessage_cb) { | ||
@@ -365,0 +374,0 @@ // If there is no ws url set, we don't have a socket. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Copyleft License
License(Experimental) Copyleft license information was found.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
Non-permissive License
License(Experimental) A license not known to be considered permissive was found.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Copyleft License
License(Experimental) Copyleft license information was found.
Found 1 instance in 1 package
Non-permissive License
License(Experimental) A license not known to be considered permissive was found.
Found 1 instance in 1 package
317439
110.5%10
11.11%8224
112.89%3
50%5
400%