🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

oxlint-plugin-complexity

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

oxlint-plugin-complexity - npm Package Compare versions

Comparing version
2.0.3
to
2.1.0
+20
dist/diff-parser.d.ts
export interface DiffHunk {
newStart: number;
newCount: number;
}
export interface DiffFile {
/** Path in the old version, null for new files */
oldPath: string | null;
/** Path in the new version, null for deleted files */
newPath: string | null;
hunks: DiffHunk[];
/** 1-based line numbers of added lines in the new file */
addedLines: number[];
/** 1-based line numbers in the new file where deletions occurred */
deletedLines: number[];
}
/**
* Parse unified diff output (e.g. from `git diff`) into structured file and line data.
*/
export declare function parseDiff(diff: string): DiffFile[];
//# sourceMappingURL=diff-parser.d.ts.map
{"version":3,"file":"diff-parser.d.ts","sourceRoot":"","sources":["../src/diff-parser.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,kDAAkD;IAClD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,sDAAsD;IACtD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,0DAA0D;IAC1D,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,oEAAoE;IACpE,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAOD;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CAgClD"}
import { parsePatch } from 'diff';
function stripPrefix(path) {
if (!path || path === '/dev/null')
return null;
return path.replace(/^[ab]\//, '');
}
/**
* Parse unified diff output (e.g. from `git diff`) into structured file and line data.
*/
export function parseDiff(diff) {
const patches = parsePatch(diff);
return patches.map((patch) => {
const addedLines = [];
const deletedLines = [];
const hunks = [];
for (const hunk of patch.hunks) {
hunks.push({ newStart: hunk.newStart, newCount: hunk.newLines });
let newLine = hunk.newStart;
for (const line of hunk.lines) {
if (line.startsWith('+')) {
addedLines.push(newLine);
newLine++;
}
else if (line.startsWith('-')) {
deletedLines.push(newLine);
}
else {
newLine++;
}
}
}
return {
oldPath: stripPrefix(patch.oldFileName),
newPath: stripPrefix(patch.newFileName),
hunks,
addedLines,
deletedLines,
};
});
}
//# sourceMappingURL=diff-parser.js.map
{"version":3,"file":"diff-parser.js","sourceRoot":"","sources":["../src/diff-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAmBlC,SAAS,WAAW,CAAC,IAAwB;IAC3C,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IAC/C,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAEjC,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAC3B,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,MAAM,YAAY,GAAa,EAAE,CAAC;QAClC,MAAM,KAAK,GAAe,EAAE,CAAC;QAE7B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YAEjE,IAAI,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC;YAC5B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC9B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACzB,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBACzB,OAAO,EAAE,CAAC;gBACZ,CAAC;qBAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBAChC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC7B,CAAC;qBAAM,CAAC;oBACN,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO;YACL,OAAO,EAAE,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC;YACvC,OAAO,EAAE,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC;YACvC,KAAK;YACL,UAAU;YACV,YAAY;SACb,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
import { type FunctionComplexityResult } from './standalone.js';
export type DiffIncludeMode = 'additions' | 'deletions' | 'both';
export interface DiffAnalysisOptions {
/** Which changes to analyze: additions (default), deletions, or both */
include?: DiffIncludeMode;
/** Custom file reader. Defaults to fs.readFileSync(path, 'utf-8') */
readFile?: (path: string) => string;
}
export interface DiffFileResult {
path: string;
changedLines: number[];
functions: FunctionComplexityResult[];
}
export interface DiffAnalysisResult {
files: DiffFileResult[];
}
/**
* Analyze complexity of functions touched by a unified diff.
*
* Parses the diff, reads each changed file, runs complexity analysis,
* and returns results filtered to only functions whose line range
* overlaps with the changed lines.
*
* @param diff - Unified diff string (e.g. output of `git diff`)
* @param options - Analysis options
*/
export declare function analyzeDiffComplexity(diff: string, options?: DiffAnalysisOptions): DiffAnalysisResult;
//# sourceMappingURL=diff.d.ts.map
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AACA,OAAO,EAAyB,KAAK,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAGvF,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,WAAW,GAAG,MAAM,CAAC;AAEjE,MAAM,WAAW,mBAAmB;IAClC,wEAAwE;IACxE,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACrC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,wBAAwB,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAqDD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,mBAAmB,GAC5B,kBAAkB,CAapB"}
import { readFileSync } from 'node:fs';
import { analyzeFileComplexity } from './standalone.js';
import { parseDiff } from './diff-parser.js';
function getChangedLines(addedLines, deletedLines, include) {
switch (include) {
case 'additions':
return addedLines;
case 'deletions':
return deletedLines;
case 'both':
return [...addedLines, ...deletedLines];
}
}
function hasOverlap(startLine, endLine, lines) {
for (const line of lines) {
if (line >= startLine && line <= endLine)
return true;
}
return false;
}
function analyzeChangedFile(diffFile, include, readFile) {
if (!diffFile.newPath)
return null;
const path = diffFile.newPath;
const changedLines = getChangedLines(diffFile.addedLines, diffFile.deletedLines, include);
if (changedLines.length === 0)
return null;
const changedLineSet = new Set(changedLines);
let source;
try {
source = readFile(path);
}
catch {
return null;
}
const analysis = analyzeFileComplexity(source, path);
const touchedFunctions = analysis.functions.filter((fn) => hasOverlap(fn.startLine, fn.endLine, changedLineSet));
if (touchedFunctions.length === 0)
return null;
return { path, changedLines, functions: touchedFunctions };
}
/**
* Analyze complexity of functions touched by a unified diff.
*
* Parses the diff, reads each changed file, runs complexity analysis,
* and returns results filtered to only functions whose line range
* overlaps with the changed lines.
*
* @param diff - Unified diff string (e.g. output of `git diff`)
* @param options - Analysis options
*/
export function analyzeDiffComplexity(diff, options) {
const include = options?.include ?? 'additions';
const readFile = options?.readFile ?? ((path) => readFileSync(path, 'utf-8'));
const diffFiles = parseDiff(diff);
const results = [];
for (const diffFile of diffFiles) {
const result = analyzeChangedFile(diffFile, include, readFile);
if (result)
results.push(result);
}
return { files: results };
}
//# sourceMappingURL=diff.js.map
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,qBAAqB,EAAiC,MAAM,iBAAiB,CAAC;AACvF,OAAO,EAAE,SAAS,EAAiB,MAAM,kBAAkB,CAAC;AAqB5D,SAAS,eAAe,CACtB,UAAoB,EACpB,YAAsB,EACtB,OAAwB;IAExB,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,WAAW;YACd,OAAO,UAAU,CAAC;QACpB,KAAK,WAAW;YACd,OAAO,YAAY,CAAC;QACtB,KAAK,MAAM;YACT,OAAO,CAAC,GAAG,UAAU,EAAE,GAAG,YAAY,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,SAAiB,EAAE,OAAe,EAAE,KAAkB;IACxE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,IAAI,SAAS,IAAI,IAAI,IAAI,OAAO;YAAE,OAAO,IAAI,CAAC;IACxD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,kBAAkB,CACzB,QAAkB,EAClB,OAAwB,EACxB,QAAkC;IAElC,IAAI,CAAC,QAAQ,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC;IAE9B,MAAM,YAAY,GAAG,eAAe,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAC1F,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAE3C,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;IAE7C,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACrD,MAAM,gBAAgB,GAAG,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CACxD,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,OAAO,EAAE,cAAc,CAAC,CACrD,CAAC;IAEF,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC;AAC7D,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CACnC,IAAY,EACZ,OAA6B;IAE7B,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,WAAW,CAAC;IAChD,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAEtF,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,OAAO,GAAqB,EAAE,CAAC;IAErC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,kBAAkB,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC/D,IAAI,MAAM;YAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC5B,CAAC"}
import type { ESTreeNode, ComplexityPoint } from './types.js';
export interface FunctionComplexityResult {
name: string;
startLine: number;
endLine: number;
cyclomatic: number;
cognitive: number;
cyclomaticPoints: ComplexityPoint[];
cognitivePoints: ComplexityPoint[];
}
export interface FileAnalysisResult {
filename: string;
functions: FunctionComplexityResult[];
}
export declare function createLineOffsetTable(code: string): number[];
export declare function offsetToLineCol(offset: number, lineOffsets: number[]): {
line: number;
column: number;
};
export declare function walkAndDispatch(ast: ESTreeNode, code: string, visitor: Record<string, ((node: ESTreeNode) => void) | undefined>): void;
/**
* Analyze a source file for function complexity without the oxlint runtime.
*
* Parses the code with oxc-parser, runs the combined cyclomatic + cognitive
* complexity visitor, and returns results for every function in the file.
*/
export declare function analyzeFileComplexity(code: string, filename: string): FileAnalysisResult;
//# sourceMappingURL=standalone.d.ts.map
{"version":3,"file":"standalone.d.ts","sourceRoot":"","sources":["../src/standalone.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAgB,eAAe,EAAW,MAAM,YAAY,CAAC;AAErF,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,eAAe,EAAE,eAAe,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,wBAAwB,EAAE,CAAC;CACvC;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ5D;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EAAE,GACpB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAOlC;AAqBD,wBAAgB,eAAe,CAC7B,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC,GAChE,IAAI,CAmCN;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAmCxF"}
import { parseSync } from 'oxc-parser';
import { walk } from 'estree-walker';
import { createCombinedComplexityVisitor, } from './combined-visitor.js';
import { getFunctionName } from './utils.js';
export function createLineOffsetTable(code) {
const lineOffsets = [0];
for (let i = 0; i < code.length; i++) {
if (code[i] === '\n') {
lineOffsets.push(i + 1);
}
}
return lineOffsets;
}
export function offsetToLineCol(offset, lineOffsets) {
for (let i = lineOffsets.length - 1; i >= 0; i--) {
if (offset >= lineOffsets[i]) {
return { line: i + 1, column: offset - lineOffsets[i] };
}
}
return { line: 1, column: offset };
}
function createStandaloneContext(code) {
return {
sourceCode: {
text: code,
getText: (node) => {
const n = node;
if (n && typeof n.start === 'number' && typeof n.end === 'number') {
return code.slice(n.start, n.end);
}
return '';
},
scopeManager: null,
getScope: () => null,
},
options: [],
report: () => { },
};
}
export function walkAndDispatch(ast, code, visitor) {
const lineOffsets = createLineOffsetTable(code);
walk(ast, {
enter(node, parent) {
const esNode = node;
const nodeWithOffsets = node;
if (typeof nodeWithOffsets.start === 'number' && typeof nodeWithOffsets.end === 'number') {
const startLoc = offsetToLineCol(nodeWithOffsets.start, lineOffsets);
const endLoc = offsetToLineCol(nodeWithOffsets.end, lineOffsets);
Object.defineProperty(esNode, 'loc', {
value: { start: startLoc, end: endLoc },
writable: true,
enumerable: false,
configurable: true,
});
}
Object.defineProperty(esNode, 'parent', {
value: parent,
writable: true,
enumerable: false,
configurable: true,
});
visitor[esNode.type]?.(esNode);
visitor['*']?.(esNode);
},
leave(node) {
const esNode = node;
visitor[`${esNode.type}:exit`]?.(esNode);
visitor['*:exit']?.(esNode);
},
});
}
/**
* Analyze a source file for function complexity without the oxlint runtime.
*
* Parses the code with oxc-parser, runs the combined cyclomatic + cognitive
* complexity visitor, and returns results for every function in the file.
*/
export function analyzeFileComplexity(code, filename) {
const { program, errors } = parseSync(filename, code);
if (errors.length > 0) {
throw new Error(`Parse errors in "${filename}": ${errors.map((e) => e.message).join(', ')}`);
}
const functions = [];
let functionIndex = 0;
const context = createStandaloneContext(code);
const onComplexityCalculated = (result, node) => {
const funcNode = node;
const name = getFunctionName(funcNode, funcNode.parent);
const displayName = name === '<arrow>' || name === '<anonymous>' ? `anonymous_${functionIndex + 1}` : name;
functionIndex++;
const loc = node.loc;
functions.push({
name: displayName,
startLine: loc?.start.line ?? 0,
endLine: loc?.end.line ?? 0,
cyclomatic: result.cyclomatic,
cognitive: result.cognitive,
cyclomaticPoints: result.cyclomaticPoints,
cognitivePoints: result.cognitivePoints,
});
};
const visitor = createCombinedComplexityVisitor(context, onComplexityCalculated);
walkAndDispatch(program, code, visitor);
return { filename, functions };
}
//# sourceMappingURL=standalone.js.map
{"version":3,"file":"standalone.js","sourceRoot":"","sources":["../src/standalone.ts"],"names":[],"mappings":"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"}
+27
-4
{
"name": "oxlint-plugin-complexity",
"version": "2.0.3",
"version": "2.1.0",
"description": "Cyclomatic and cognitive complexity rules for oxlint",

@@ -35,2 +35,10 @@ "keywords": [

"types": "./dist/index.d.ts"
},
"./standalone": {
"import": "./dist/standalone.js",
"types": "./dist/standalone.d.ts"
},
"./diff": {
"import": "./dist/diff.js",
"types": "./dist/diff.d.ts"
}

@@ -42,7 +50,8 @@ },

"devDependencies": {
"@oxlint/plugins": "^1.48.0",
"@types/node": "^22.19.5",
"diff": "^8.0.4",
"estree-walker": "^3.0.3",
"husky": "^9.1.7",
"oxc-parser": "^0.120.0",
"@oxlint/plugins": "^1.48.0",
"oxc-parser": "^0.123.0",
"oxlint": "^1.48.0",

@@ -55,4 +64,18 @@ "prettier": "3.8.1",

"peerDependencies": {
"@oxlint/plugins": ">=1.43.0"
"@oxlint/plugins": ">=1.43.0",
"diff": ">=5.0.0",
"estree-walker": ">=3.0.0",
"oxc-parser": ">=0.60.0"
},
"peerDependenciesMeta": {
"diff": {
"optional": true
},
"estree-walker": {
"optional": true
},
"oxc-parser": {
"optional": true
}
},
"engines": {

@@ -59,0 +82,0 @@ "node": ">=20.0.0"

@@ -160,4 +160,62 @@ # oxlint-plugin-complexity

---
## Standalone Library Usage
You can use this package as a standalone library to analyze complexity programmatically - no oxlint runtime needed.
```bash
npm install oxlint-plugin-complexity oxc-parser estree-walker diff
```
### Analyzing a file
```typescript
import { analyzeFileComplexity } from 'oxlint-plugin-complexity/standalone';
const code = `
function processOrder(order, config) {
if (order.items.length === 0) {
return null;
}
for (const item of order.items) {
if (item.quantity > config.maxQuantity) {
if (config.strict) {
throw new Error('Over limit');
}
}
}
return order;
}
`;
const result = analyzeFileComplexity(code, 'order.ts');
for (const fn of result.functions) {
console.log(`${fn.name} (lines ${fn.startLine}-${fn.endLine})`);
console.log(` Cyclomatic: ${fn.cyclomatic}`);
console.log(` Cognitive: ${fn.cognitive}`);
}
```
Each function result includes `cyclomaticPoints` and `cognitivePoints` arrays with per-construct breakdowns (line, column, complexity contribution, and message).
### Git Diff Analysis
Analyze only the functions touched by a diff - useful for CI gates, pre-commit hooks, and code review tools.
```typescript
import { analyzeDiffComplexity } from 'oxlint-plugin-complexity/diff';
import { execFileSync } from 'node:child_process';
const diff = execFileSync('git', ['diff', 'HEAD~1']).toString();
const result = analyzeDiffComplexity(diff);
for (const file of result.files) {
for (const fn of file.functions) {
if (fn.cognitive > 15) {
console.log(`${file.path}:${fn.startLine} ${fn.name} - cognitive: ${fn.cognitive}`);
}
}
}
```
## Migration from v0.x

@@ -182,4 +240,2 @@

---
## Attribution

@@ -186,0 +242,0 @@