Comparing version 1.1.11 to 1.1.12
@@ -49,14 +49,2 @@ /** | ||
/** | ||
* Expression node. | ||
*/ | ||
export type NodeExpr = NodeName | NodeArgExpr | NodeOperation | NodeList; | ||
/** | ||
* Range node. | ||
*/ | ||
interface NodeRange { | ||
start: NodeExpr | null; | ||
stop: NodeExpr | null; | ||
stride: NodeExpr | null; | ||
} | ||
/** | ||
* Common primary node. | ||
@@ -68,2 +56,6 @@ */ | ||
/** | ||
* Expression node. | ||
*/ | ||
export type NodeExpr = NodeName | NodeArgExpr | NodeOperation | NodeList | NodeRange | NodeReturnList; | ||
/** | ||
* Reserved node. | ||
@@ -97,2 +89,11 @@ */ | ||
/** | ||
* Range node. | ||
*/ | ||
interface NodeRange extends PrimaryNode { | ||
type: 'RANGE'; | ||
start: NodeExpr | null; | ||
stop: NodeExpr | null; | ||
stride: NodeExpr | null; | ||
} | ||
/** | ||
* Operation node. | ||
@@ -127,6 +128,15 @@ */ | ||
*/ | ||
export interface NodeList { | ||
export interface NodeList extends PrimaryNode { | ||
type: 'LIST'; | ||
list: Array<NodeExpr>; | ||
} | ||
export type ReturnSelector = (length: number, index: number) => any; | ||
/** | ||
* Return list node | ||
*/ | ||
export interface NodeReturnList extends PrimaryNode { | ||
type: 'RETLIST'; | ||
selector: ReturnSelector; | ||
} | ||
/** | ||
* External parser declarations (defined in parser body) | ||
@@ -202,3 +212,2 @@ */ | ||
private readonly opTable; | ||
get opList(): string[]; | ||
/** | ||
@@ -218,3 +227,2 @@ * Parser AST (Abstract Syntax Tree) constructor methods. | ||
readonly isTensor: typeof MultiArray.isThis; | ||
readonly isRange: typeof MultiArray.isRange; | ||
readonly unparseTensor: typeof MultiArray.unparse; | ||
@@ -300,3 +308,3 @@ readonly unparseTensorML: typeof MultiArray.unparseML; | ||
*/ | ||
nodeRange(left: any, ...right: any): NodeRange; | ||
nodeRange(...args: any): NodeRange; | ||
/** | ||
@@ -336,2 +344,3 @@ * Create operator node. | ||
nodeAppendRow(matrix: any, row: any): MultiArray; | ||
nodeReturnList(selector: ReturnSelector): NodeReturnList; | ||
/** | ||
@@ -342,7 +351,7 @@ * Validate left hand side of assignment node. | ||
*/ | ||
validateAssignment(tree: any): { | ||
validateAssignment(tree: any, shallow?: boolean): { | ||
left: any; | ||
id: string; | ||
args: any[]; | ||
}; | ||
}[]; | ||
/** | ||
@@ -349,0 +358,0 @@ * Define function in baseFunctionTable. |
import { ComplexDecimal } from './complex-decimal'; | ||
/** | ||
* External reference for Evaluator. | ||
* TODO: remove this when implement multiple returns in functions. | ||
*/ | ||
export type Evaluator = any; | ||
@@ -7,12 +11,6 @@ /** | ||
export type TNameTableEntry = { | ||
args: Array<any>; | ||
args: any[]; | ||
expr: any; | ||
}; | ||
export type TNameTable = Record<string, TNameTableEntry>; | ||
export type ArrayElement = MultiArray | ComplexDecimal | any; | ||
export type dimRange = { | ||
start: number; | ||
stride: number; | ||
stop: number; | ||
}; | ||
/** | ||
@@ -66,3 +64,3 @@ * # MultiArray | ||
*/ | ||
static firstRow(row: Array<ArrayElement>): MultiArray; | ||
static firstRow(row: any[]): MultiArray; | ||
/** | ||
@@ -75,5 +73,5 @@ * Append a row of elements to a MultiArray object (for parsing | ||
*/ | ||
static appendRow(M: MultiArray, row: Array<ArrayElement>): MultiArray; | ||
static appendRow(M: MultiArray, row: any[]): MultiArray; | ||
/** | ||
* Swap two rows of a MultiArray. | ||
* Swap two rows of a MultiArray in place. | ||
* @param M | ||
@@ -91,8 +89,2 @@ * @param m | ||
/** | ||
* Check if object is MultiArray range compatible. | ||
* @param obj | ||
* @returns | ||
*/ | ||
static isRange(obj: any): boolean; | ||
/** | ||
* Unparse MultiArray. | ||
@@ -167,5 +159,6 @@ * @param tree MultiArray matrix object. | ||
/** | ||
* Expand Matrix dimensions if dimensions in `dim` is greater than dimensions of `M`. | ||
* Expand matrix dimensions if dimensions in `dim` is greater than dimensions of `M`. | ||
* If a dimension of `M` is greater than corresponding dimension in `dim` it's unchanged. | ||
* The matrix is filled with zeros. | ||
* The matrix is expanded in place. | ||
* @param M Matrix. | ||
@@ -184,6 +177,38 @@ * @param dim New dimensions. | ||
static expandRange(startNode: ComplexDecimal, stopNode: ComplexDecimal, strideNode?: ComplexDecimal | null): MultiArray; | ||
/** | ||
* Check if subscript is a integer number, convert ComplexDecimal to | ||
* number and decrement (for use in a 0 based javascript array). | ||
* @param k | ||
* @param input | ||
* @returns | ||
*/ | ||
static testIndex(k: ComplexDecimal, input?: string): number; | ||
/** | ||
* Check if subscript is a integer number, convert ComplexDecimal to | ||
* number and decrement (for use in a 0 based javascript array), then | ||
* check if it's less than bound. | ||
* @param k | ||
* @param input | ||
* @returns | ||
*/ | ||
static testIndexBound(k: ComplexDecimal, bound: number, dim: number[], input?: string): number; | ||
/** | ||
* Check if two dimensions are compatible. | ||
* @param leftDim | ||
* @param rightDim | ||
* @returns | ||
*/ | ||
static testDimension(leftDim: number[], rightDim: number[]): boolean; | ||
/** | ||
* Find first non-single dimension. | ||
* @param M | ||
* @returns | ||
*/ | ||
static firstNonSingleDimmension(M: MultiArray): number; | ||
/** | ||
* Converts a ComplexDecimal array or a single line MultiArray to an array | ||
* or number. | ||
* @param M | ||
* @returns | ||
*/ | ||
static oneRowToDim(M: ComplexDecimal[] | MultiArray): number[]; | ||
@@ -205,3 +230,3 @@ /** | ||
*/ | ||
static getItems(M: MultiArray, id: string, indexList: Array<ComplexDecimal | MultiArray>): MultiArray | ComplexDecimal; | ||
static getItems(M: MultiArray, id: string, indexList: (ComplexDecimal | MultiArray)[]): MultiArray | ComplexDecimal; | ||
/** | ||
@@ -406,8 +431,2 @@ * Matrix product. | ||
/** | ||
* Compute the adjugate (adjoint) matrix for a square matrix. | ||
* @param M | ||
* @returns | ||
*/ | ||
static adj(M: MultiArray): MultiArray; | ||
/** | ||
* Compute the minor of a matrix. | ||
@@ -426,2 +445,8 @@ * @param M Matrix. | ||
static cofactor(M: MultiArray): MultiArray; | ||
/** | ||
* Compute the adjugate (adjoint) matrix for a square matrix. | ||
* @param M | ||
* @returns | ||
*/ | ||
static adj(M: MultiArray): MultiArray; | ||
static pivot(M: MultiArray): MultiArray; | ||
@@ -428,0 +453,0 @@ /** |
{ | ||
"name": "mathjslab", | ||
"version": "1.1.11", | ||
"version": "1.1.12", | ||
"description": "MathJSLab - An interpreter with language syntax like MATLAB®/Octave. ISBN 978-65-00-82338-7", | ||
@@ -5,0 +5,0 @@ "main": "lib/mathjslab.js", |
@@ -61,16 +61,2 @@ /** | ||
/** | ||
* Expression node. | ||
*/ | ||
export type NodeExpr = NodeName | NodeArgExpr | NodeOperation | NodeList; | ||
/** | ||
* Range node. | ||
*/ | ||
interface NodeRange { | ||
start: NodeExpr | null; | ||
stop: NodeExpr | null; | ||
stride: NodeExpr | null; | ||
} | ||
/** | ||
* Common primary node. | ||
@@ -83,2 +69,7 @@ */ | ||
/** | ||
* Expression node. | ||
*/ | ||
export type NodeExpr = NodeName | NodeArgExpr | NodeOperation | NodeList | NodeRange | NodeReturnList; | ||
/** | ||
* Reserved node. | ||
@@ -115,2 +106,12 @@ */ | ||
/** | ||
* Range node. | ||
*/ | ||
interface NodeRange extends PrimaryNode { | ||
type: 'RANGE'; | ||
start: NodeExpr | null; | ||
stop: NodeExpr | null; | ||
stride: NodeExpr | null; | ||
} | ||
/** | ||
* Operation node. | ||
@@ -150,7 +151,18 @@ */ | ||
*/ | ||
export interface NodeList { | ||
export interface NodeList extends PrimaryNode { | ||
type: 'LIST'; | ||
list: Array<NodeExpr>; | ||
} | ||
export type ReturnSelector = (length: number, index: number) => any; | ||
/** | ||
* Return list node | ||
*/ | ||
export interface NodeReturnList extends PrimaryNode { | ||
type: 'RETLIST'; | ||
selector: ReturnSelector; | ||
} | ||
/** | ||
* External parser declarations (defined in parser body) | ||
@@ -322,6 +334,2 @@ */ | ||
public get opList(): string[] { | ||
return Object.keys(this.opTable); | ||
} | ||
/** | ||
@@ -342,3 +350,2 @@ * Parser AST (Abstract Syntax Tree) constructor methods. | ||
public readonly isTensor = MultiArray.isThis; | ||
public readonly isRange = MultiArray.isRange; | ||
public readonly unparseTensor = MultiArray.unparse; | ||
@@ -531,3 +538,6 @@ public readonly unparseTensorML = MultiArray.unparseML; | ||
public nodeName(nodeid: string): NodeName { | ||
return { type: 'NAME', id: nodeid.replace(/(\r\n|[\n\r])|[\ ]/gm, '') }; | ||
return { | ||
type: 'NAME', | ||
id: nodeid.replace(/(\r\n|[\n\r])|[\ ]/gm, ''), | ||
}; | ||
} | ||
@@ -542,3 +552,7 @@ | ||
public nodeCmdWList(nodename: NodeName, nodelist: NodeList): NodeCmdWList { | ||
return { type: 'CmdWList', id: nodename.id, args: nodelist ? (nodelist.list as any) : [] }; | ||
return { | ||
type: 'CmdWList', | ||
id: nodename.id, | ||
args: nodelist ? (nodelist.list as any) : [], | ||
}; | ||
} | ||
@@ -553,3 +567,7 @@ | ||
public nodeArgExpr(nodeexpr: any, nodelist?: any): NodeArgExpr { | ||
return { type: 'ARG', expr: nodeexpr, args: nodelist ? nodelist.list : [] }; | ||
return { | ||
type: 'ARG', | ||
expr: nodeexpr, | ||
args: nodelist ? nodelist.list : [], | ||
}; | ||
} | ||
@@ -563,10 +581,20 @@ | ||
*/ | ||
public nodeRange(left: any, ...right: any): NodeRange { | ||
public nodeRange(...args: any): NodeRange { | ||
/* https://www.mathworks.com/help/matlab/ref/end.html */ | ||
if (right.length === 1) { | ||
return { start: left, stop: right[0], stride: null }; | ||
} else if (right.length === 2) { | ||
return { start: left, stop: right[1], stride: right[0] }; | ||
if (args.length === 2) { | ||
return { | ||
type: 'RANGE', | ||
start: args[0], | ||
stop: args[1], | ||
stride: null, | ||
}; | ||
} else if (args.length === 3) { | ||
return { | ||
type: 'RANGE', | ||
start: args[0], | ||
stop: args[2], | ||
stride: args[1], | ||
}; | ||
} else { | ||
throw new Error('invalid range.'); | ||
throw new SyntaxError('invalid range.'); | ||
} | ||
@@ -648,5 +676,11 @@ } | ||
if (node) { | ||
return { list: [node] }; | ||
return { | ||
type: 'LIST', | ||
list: [node], | ||
}; | ||
} else { | ||
return { list: [] }; | ||
return { | ||
type: 'LIST', | ||
list: [], | ||
}; | ||
} | ||
@@ -693,2 +727,9 @@ } | ||
public nodeReturnList(selector: ReturnSelector): NodeReturnList { | ||
return { | ||
type: 'RETLIST', | ||
selector, | ||
}; | ||
} | ||
/** | ||
@@ -699,6 +740,5 @@ * Validate left hand side of assignment node. | ||
*/ | ||
public validateAssignment(tree: any): { left: any; id: string; args: any[] } { | ||
public validateAssignment(tree: any, shallow: boolean = true): { left: any; id: string; args: any[] }[] { | ||
const invalidMessageBase = 'invalid left hand side of assignment'; | ||
const invalidMessage = `${invalidMessageBase}: cannot assign to a read only value:`; | ||
let result: any; | ||
if (tree.type === 'NAME') { | ||
@@ -708,7 +748,9 @@ if (this.readonlyNameTable.includes(tree.id)) { | ||
} | ||
result = { | ||
left: tree, | ||
id: tree.id, | ||
args: [], | ||
}; | ||
return [ | ||
{ | ||
left: tree, | ||
id: tree.id, | ||
args: [], | ||
}, | ||
]; | ||
} else if (tree.type === 'ARG' && tree.expr.type === 'NAME') { | ||
@@ -718,14 +760,14 @@ if (this.readonlyNameTable.includes(tree.expr.id)) { | ||
} | ||
result = { | ||
left: tree.expr, | ||
id: tree.expr.id, | ||
args: tree.args, | ||
}; | ||
return [ | ||
{ | ||
left: tree.expr, | ||
id: tree.expr.id, | ||
args: tree.args, | ||
}, | ||
]; | ||
} else if (shallow && this.isTensor(tree) && tree.dim[0] === 1) { | ||
return tree.array[0].map((left: any) => this.validateAssignment(left, false)[0]); | ||
} else { | ||
throw new Error(`${invalidMessageBase}.`); | ||
} | ||
if (result.aliasTreeName in this.baseFunctionTable) { | ||
throw new Error(`${invalidMessage} ${result.aliasTreeName}.`); | ||
} | ||
return result; | ||
} | ||
@@ -841,26 +883,6 @@ | ||
public Evaluator(tree: any, local: boolean = false, fname: string = ''): any { | ||
if (this.debug) { | ||
console.log(`Evaluator(\ntree:${JSON.stringify(tree, null, 2)},\nlocal:${local},\nfname:${fname})`); | ||
if (this._debug) { | ||
console.log(`Evaluator(\ntree:${JSON.stringify(tree, null, 2)},\nlocal:${local},\nfname:${fname});`); | ||
} | ||
if ('list' in tree) { | ||
const result = { list: new Array(tree.list.length) }; | ||
for (let i = 0; i < tree.list.length; i++) { | ||
/* Convert undefined name, defined in word-list command, to word-list command. | ||
* (Null length word-list command) */ | ||
if ( | ||
tree.list[i].type === 'NAME' && | ||
!(local && this.localTable[fname] && this.localTable[fname][tree.list[i].id]) && | ||
!(tree.list[i].id in this.nameTable) && | ||
commandsTable.indexOf(tree.list[i].id) >= 0 | ||
) { | ||
tree.list[i].type = 'CmdWList'; | ||
tree.list[i]['args'] = []; | ||
} | ||
result.list[i] = this.Evaluator(tree.list[i], local, fname); | ||
if (typeof result.list[i].type === 'number') { | ||
this.nameTable['ans'] = { args: [], expr: result.list[i] }; | ||
} | ||
} | ||
return result; | ||
} else if (this.isNumber(tree) || this.isString(tree)) { | ||
if (this.isNumber(tree) || this.isString(tree)) { | ||
/* NUMBER or STRING */ | ||
@@ -871,9 +893,2 @@ return tree; | ||
return this.evaluateTensor(tree, this, local, fname); | ||
} else if (this.isRange(tree)) { | ||
/* RANGE */ | ||
return this.expandRange( | ||
this.Evaluator(tree.start, local, fname), | ||
this.Evaluator(tree.stop, local, fname), | ||
tree.stride ? this.Evaluator(tree.stride, local, fname) : null, | ||
); | ||
} else { | ||
@@ -934,4 +949,8 @@ switch (tree.type) { | ||
case '|=': | ||
const { left, id, args } = this.validateAssignment(tree.left); | ||
const assignment = this.validateAssignment(tree.left); | ||
const op: string = tree.type.substring(0, tree.type.length - 1); | ||
if (assignment.length > 1 && op.length > 0) { | ||
throw new Error('computed multiple assignment not allowed.'); | ||
} | ||
const { left, id, args } = assignment[0]; | ||
if (args.length === 0) { | ||
@@ -1005,2 +1024,31 @@ /* Name definition. */ | ||
} | ||
case 'LIST': | ||
const result = { | ||
type: 'LIST', | ||
list: new Array(tree.list.length), | ||
}; | ||
for (let i = 0; i < tree.list.length; i++) { | ||
/* Convert undefined name, defined in word-list command, to word-list command. | ||
* (Null length word-list command) */ | ||
if ( | ||
tree.list[i].type === 'NAME' && | ||
!(local && this.localTable[fname] && this.localTable[fname][tree.list[i].id]) && | ||
!(tree.list[i].id in this.nameTable) && | ||
commandsTable.indexOf(tree.list[i].id) >= 0 | ||
) { | ||
tree.list[i].type = 'CmdWList'; | ||
tree.list[i]['args'] = []; | ||
} | ||
result.list[i] = this.Evaluator(tree.list[i], local, fname); | ||
if (typeof result.list[i].type === 'number') { | ||
this.nameTable['ans'] = { args: [], expr: result.list[i] }; | ||
} | ||
} | ||
return result; | ||
case 'RANGE': | ||
return this.expandRange( | ||
this.Evaluator(tree.start, local, fname), | ||
this.Evaluator(tree.stop, local, fname), | ||
tree.stride ? this.Evaluator(tree.stride, local, fname) : null, | ||
); | ||
case 'ARG': | ||
@@ -1082,2 +1130,4 @@ if (typeof tree.expr === 'undefined') { | ||
} | ||
case 'RETLIST': | ||
return this.Evaluator(tree.selector(1, 1), local, fname); | ||
case 'CmdWList': | ||
@@ -1116,11 +1166,5 @@ this.commandWordListTable[tree.id].func(...tree.args.map((word: { str: string }) => word.str)); | ||
if (tree === undefined) { | ||
return ''; | ||
return '<UNDEFINED>'; | ||
} | ||
if ('list' in tree) { | ||
let list = ''; | ||
for (let i = 0; i < tree.list.length; i++) { | ||
list += this.Unparse(tree.list[i]) + '\n'; | ||
} | ||
return list; | ||
} else if (this.isNumber(tree)) { | ||
if (this.isNumber(tree)) { | ||
/* NUMBER */ | ||
@@ -1134,15 +1178,3 @@ return this.unparseNumber(tree); | ||
return this.unparseTensor(tree, this); | ||
} else if (this.isRange(tree)) { | ||
/* RANGE */ | ||
if (tree.start && tree.stop) { | ||
if (tree.stride) { | ||
return this.Unparse(tree.start) + ':' + this.Unparse(tree.stride) + ':' + this.Unparse(tree.stop); | ||
} else { | ||
return this.Unparse(tree.start) + ':' + this.Unparse(tree.stop); | ||
} | ||
} else { | ||
return ':'; | ||
} | ||
} else { | ||
let arglist: string; | ||
switch (tree.type) { | ||
@@ -1214,14 +1246,18 @@ case ':': | ||
return tree.id; | ||
case 'LIST': | ||
return tree.list.map((value: any) => this.Unparse(value)).join('\n') + '\n'; | ||
case 'RANGE': | ||
if (tree.start && tree.stop) { | ||
if (tree.stride) { | ||
return this.Unparse(tree.start) + ':' + this.Unparse(tree.stride) + ':' + this.Unparse(tree.stop); | ||
} else { | ||
return this.Unparse(tree.start) + ':' + this.Unparse(tree.stop); | ||
} | ||
} else { | ||
return ':'; | ||
} | ||
case 'ARG': | ||
arglist = ''; | ||
for (let i = 0; i < tree.args.length; i++) { | ||
arglist += this.Unparse(tree.args[i]) + ','; | ||
} | ||
return this.Unparse(tree.expr) + '(' + arglist.substring(0, arglist.length - 1) + ')'; | ||
return this.Unparse(tree.expr) + '(' + tree.args.map((value: any) => this.Unparse(value)).join(',') + ')'; | ||
case 'CmdWList': | ||
arglist = ''; | ||
for (let i = 0; i < tree.args.length; i++) { | ||
arglist += this.Unparse(tree.args[i]) + ' '; | ||
} | ||
return tree.id + arglist.substring(0, arglist.length - 1); | ||
return tree.id + ' ' + tree.args.map((arg: any) => this.Unparse(arg)).join(' '); | ||
default: | ||
@@ -1244,11 +1280,5 @@ return '<INVALID>'; | ||
if (tree === undefined) { | ||
return ''; | ||
return '<mi>undefined</mi>'; | ||
} | ||
if ('list' in tree) { | ||
let list = '<mtable>'; | ||
for (let i = 0; i < tree.list.length; i++) { | ||
list += '<mtr><mtd>' + this.unparserML(tree.list[i]) + '</mtd></mtr>'; | ||
} | ||
return list + '</mtable>'; | ||
} else if (this.isNumber(tree)) { | ||
if (this.isNumber(tree)) { | ||
/* NUMBER */ | ||
@@ -1262,15 +1292,3 @@ return this.unparseNumberML(tree); | ||
return this.unparseTensorML(tree, this); | ||
} else if (this.isRange(tree)) { | ||
/* RANGE */ | ||
if (tree.start && tree.stop) { | ||
if (tree.stride) { | ||
return this.unparserML(tree.start) + '<mo>:</mo>' + this.unparserML(tree.stride) + '<mo>:</mo>' + this.unparserML(tree.stop); | ||
} else { | ||
return this.unparserML(tree.start) + '<mo>:</mo>' + this.unparserML(tree.stop); | ||
} | ||
} else { | ||
return '<mo>:</mo>'; | ||
} | ||
} else { | ||
let arglist: string; | ||
switch (tree.type) { | ||
@@ -1350,2 +1368,14 @@ case ':': | ||
return '<mi>' + substGreek(tree.id) + '</mi>'; | ||
case 'LIST': | ||
return `<mtable>${tree.list.map((value: any) => `<mtr><mtd>${this.unparserML(value)}</mtd></mtr>`).join('')}</mtable>`; | ||
case 'RANGE': | ||
if (tree.start && tree.stop) { | ||
if (tree.stride) { | ||
return this.unparserML(tree.start) + '<mo>:</mo>' + this.unparserML(tree.stride) + '<mo>:</mo>' + this.unparserML(tree.stop); | ||
} else { | ||
return this.unparserML(tree.start) + '<mo>:</mo>' + this.unparserML(tree.stop); | ||
} | ||
} else { | ||
return '<mo>:</mo>'; | ||
} | ||
case 'ARG': | ||
@@ -1355,7 +1385,3 @@ if (tree.args.length === 0) { | ||
} else { | ||
arglist = ''; | ||
for (let i = 0; i < tree.args.length; i++) { | ||
arglist += this.unparserML(tree.args[i]) + '<mo>,</mo>'; | ||
} | ||
arglist = arglist.substring(0, arglist.length - 10); | ||
const arglist = tree.args.map((arg: any) => this.unparserML(arg)).join('<mo>,</mo>'); | ||
if (tree.expr.type === 'NAME') { | ||
@@ -1373,7 +1399,3 @@ const aliasTreeName = this.aliasName(tree.expr.id); | ||
case 'CmdWList': | ||
arglist = ' '; | ||
for (let i = 0; i < tree.args.length; i++) { | ||
arglist += this.Unparse(tree.args[i]) + ' '; | ||
} | ||
return '<mtext>' + tree.id + ' ' + arglist.substring(0, arglist.length - 1) + '</mtext>'; | ||
return '<mtext>' + tree.id + ' ' + tree.args.map((arg: any) => this.unparserML(arg)).join(' ') + '</mtext>'; | ||
default: | ||
@@ -1384,3 +1406,3 @@ return '<mi>invalid</mi>'; | ||
} catch (e) { | ||
if (this.debug) { | ||
if (this._debug) { | ||
throw e; | ||
@@ -1387,0 +1409,0 @@ } else { |
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
443642
6806