@coana-tech/cli 14.12.153 → 14.12.155
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.mjs +18 -2
- package/package.json +1 -1
- package/reachability-analyzers-cli.mjs +5 -2
- package/repos/coana-tech/goana/bin/goana-darwin-amd64.gz +0 -0
- package/repos/coana-tech/goana/bin/goana-darwin-arm64.gz +0 -0
- package/repos/coana-tech/goana/bin/goana-linux-amd64.gz +0 -0
- package/repos/coana-tech/goana/bin/goana-linux-arm64.gz +0 -0
- package/repos/coana-tech/javap-service/javap-service.jar +0 -0
- package/repos/coana-tech/jelly-private/dist/bundle/jelly.js +70 -28
package/cli.mjs
CHANGED
|
@@ -234634,6 +234634,7 @@ function isShortestPath(root3, vulnPath) {
|
|
|
234634
234634
|
|
|
234635
234635
|
// ../web-compat-utils/src/analysis-error-keys.ts
|
|
234636
234636
|
var CLI_ANALYSIS_ERROR_MESSAGE = "Sharing log due to analysis error";
|
|
234637
|
+
var ANALYSIS_LOW_CONFIDENCE_MESSAGE = "Analysis had low confidence in result";
|
|
234637
234638
|
|
|
234638
234639
|
// ../web-compat-utils/src/pluralize.ts
|
|
234639
234640
|
function pluralize(count, word) {
|
|
@@ -235720,6 +235721,10 @@ var ERROR_CATEGORY_MESSAGES = {
|
|
|
235720
235721
|
"Check https://docs.socket.dev/docs/reachability-analysis#reachability-ecosystem-support for more details"
|
|
235721
235722
|
]
|
|
235722
235723
|
},
|
|
235724
|
+
lowConfidence: {
|
|
235725
|
+
title,
|
|
235726
|
+
details: [TIER2_FALLBACK_MESSAGE, "The analysis produced only a partial result, which is of insufficient quality to accurately determine the reachability of this advisory."]
|
|
235727
|
+
},
|
|
235723
235728
|
general: {
|
|
235724
235729
|
title,
|
|
235725
235730
|
details: [TIER2_FALLBACK_MESSAGE, "Check the logs for more details on the specific error"]
|
|
@@ -235781,7 +235786,9 @@ function displayWorkspaceDiagnosticsSummaryInternal(diagnosticsEntries, vulns) {
|
|
|
235781
235786
|
failedToInstallPackages.add(packageInstallMatch[1]);
|
|
235782
235787
|
}
|
|
235783
235788
|
let category = "general";
|
|
235784
|
-
if (errorMessageLower.includes(
|
|
235789
|
+
if (errorMessageLower.includes(ANALYSIS_LOW_CONFIDENCE_MESSAGE.toLowerCase())) {
|
|
235790
|
+
category = "lowConfidence";
|
|
235791
|
+
} else if (errorMessageLower.includes("install") || errorMessageLower.includes("npm") || errorMessageLower.includes("pip") || errorMessageLower.includes("dependency")) {
|
|
235785
235792
|
category = "install";
|
|
235786
235793
|
} else if (errorMessageLower.includes("timeout") || errorMessageLower.includes("timed out")) {
|
|
235787
235794
|
category = "timeout";
|
|
@@ -250895,7 +250902,7 @@ async function onlineScan(dependencyTree, apiKey, timeout) {
|
|
|
250895
250902
|
}
|
|
250896
250903
|
|
|
250897
250904
|
// dist/version.js
|
|
250898
|
-
var version3 = "14.12.
|
|
250905
|
+
var version3 = "14.12.155";
|
|
250899
250906
|
|
|
250900
250907
|
// dist/cli-core.js
|
|
250901
250908
|
var { mapValues, omit, partition, pickBy: pickBy2 } = import_lodash15.default;
|
|
@@ -251167,6 +251174,15 @@ var CliCore = class {
|
|
|
251167
251174
|
}
|
|
251168
251175
|
this.sendProgress("RUN_ON_SUBPROJECT", false, this.rootWorkingDirectory);
|
|
251169
251176
|
}
|
|
251177
|
+
for (const vuln of vulnsWithResults) {
|
|
251178
|
+
if (vuln.codeAwareScanResult.type === "success" && vuln.codeAwareScanResult.lowConfidence === true && vuln.codeAwareScanResult.detectedOccurrences?.stacks?.length === 0) {
|
|
251179
|
+
vuln.codeAwareScanResult = {
|
|
251180
|
+
type: "analysisError",
|
|
251181
|
+
message: ANALYSIS_LOW_CONFIDENCE_MESSAGE
|
|
251182
|
+
};
|
|
251183
|
+
vuln.reachability = "UNKNOWN";
|
|
251184
|
+
}
|
|
251185
|
+
}
|
|
251170
251186
|
displayResultsSummary(vulnsWithResults, allWorkspaceTimings);
|
|
251171
251187
|
displayWorkspaceDiagnosticsSummary(allWorkspaceDiagnostics, vulnsWithResults);
|
|
251172
251188
|
await this.shareLogIfAnalysisError(vulnsWithResults);
|
package/package.json
CHANGED
|
@@ -110825,7 +110825,7 @@ async function runJellyAnalysis(mainProjectRoot, projectRoot, jellyOptions, reac
|
|
|
110825
110825
|
}
|
|
110826
110826
|
);
|
|
110827
110827
|
if (reachabilityAnalysisOptions.printLogFile)
|
|
110828
|
-
logger.info("JS analysis log file:",
|
|
110828
|
+
logger.info("JS analysis log file:", logFile);
|
|
110829
110829
|
const analysisDiagnostics = JSON.parse(await readFile8(diagnosticsFile, "utf-8"));
|
|
110830
110830
|
const callStacks = JSON.parse(await readFile8(callStackFile, "utf-8"));
|
|
110831
110831
|
const matches = {};
|
|
@@ -110952,12 +110952,14 @@ var JSCodeAwareVulnerabilityScanner = class _JSCodeAwareVulnerabilityScanner {
|
|
|
110952
110952
|
analysisOptionsFromHeuristic.approx = process.env.JELLY_APPROX === "true" || experiment === "JELLY_APPROX";
|
|
110953
110953
|
const analysisRes = await runJellyAnalysis(this.mainProjectDir, this.projectDir, analysisOptionsFromHeuristic, this.options, timeoutInSeconds, vulnerabilities, experiment, telemetryHandler, analyzerTelemetryHandler);
|
|
110954
110954
|
const { analysisDiagnostics: diagnostics, matches } = analysisRes;
|
|
110955
|
+
const lowConfidence = diagnostics.round < 2 && (diagnostics.timeout || diagnostics.aborted);
|
|
110955
110956
|
return {
|
|
110956
110957
|
type: "success",
|
|
110957
110958
|
diagnostics,
|
|
110958
110959
|
terminatedEarly: diagnostics.aborted || diagnostics.timeout || diagnostics.lowmemory,
|
|
110959
110960
|
reachedDependencies: diagnostics.packages > 0,
|
|
110960
110961
|
affectedPurls: analysisRes.affectedPurls,
|
|
110962
|
+
lowConfidence,
|
|
110961
110963
|
computeDetectedOccurrences: ({ url: url2 }) => this.transformSourceLocations(matches[url2] ?? { analysisLevel: "function-level", affectedPackages: [], stacks: [] })
|
|
110962
110964
|
};
|
|
110963
110965
|
} catch (e) {
|
|
@@ -113078,7 +113080,8 @@ function augmentVulnsWithDetectedOccurrences(vulns, codeAwareScanner, heuristic,
|
|
|
113078
113080
|
terminatedEarly: result.terminatedEarly,
|
|
113079
113081
|
heuristicName: heuristic.name,
|
|
113080
113082
|
affectedPurls: result.affectedPurls,
|
|
113081
|
-
detectedOccurrences
|
|
113083
|
+
detectedOccurrences,
|
|
113084
|
+
lowConfidence: result.lowConfidence
|
|
113082
113085
|
};
|
|
113083
113086
|
}
|
|
113084
113087
|
logger.debug("Done augmenting with detected occurrences");
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1485,6 +1485,44 @@ var require_constraintvarproducer = __commonJS({
|
|
|
1485
1485
|
}
|
|
1486
1486
|
});
|
|
1487
1487
|
|
|
1488
|
+
// lib/misc/large-array.js
|
|
1489
|
+
var require_large_array = __commonJS({
|
|
1490
|
+
"lib/misc/large-array.js"(exports) {
|
|
1491
|
+
"use strict";
|
|
1492
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1493
|
+
exports.LargeArray = void 0;
|
|
1494
|
+
var MAX_CHUNK_SIZE = 1 << 25;
|
|
1495
|
+
var LargeArray = class {
|
|
1496
|
+
static {
|
|
1497
|
+
__name(this, "LargeArray");
|
|
1498
|
+
}
|
|
1499
|
+
chunks = [[]];
|
|
1500
|
+
_size = 0;
|
|
1501
|
+
get length() {
|
|
1502
|
+
return this._size;
|
|
1503
|
+
}
|
|
1504
|
+
set length(_value) {
|
|
1505
|
+
this.chunks.length = 0;
|
|
1506
|
+
this.chunks.push([]);
|
|
1507
|
+
this._size = 0;
|
|
1508
|
+
}
|
|
1509
|
+
push(value) {
|
|
1510
|
+
const chunk = this.chunks[this.chunks.length - 1];
|
|
1511
|
+
if (chunk.length >= MAX_CHUNK_SIZE)
|
|
1512
|
+
this.chunks.push([value]);
|
|
1513
|
+
else
|
|
1514
|
+
chunk.push(value);
|
|
1515
|
+
this._size++;
|
|
1516
|
+
}
|
|
1517
|
+
*[Symbol.iterator]() {
|
|
1518
|
+
for (const chunk of this.chunks)
|
|
1519
|
+
yield* chunk;
|
|
1520
|
+
}
|
|
1521
|
+
};
|
|
1522
|
+
exports.LargeArray = LargeArray;
|
|
1523
|
+
}
|
|
1524
|
+
});
|
|
1525
|
+
|
|
1488
1526
|
// lib/analysis/fragmentstate.js
|
|
1489
1527
|
var require_fragmentstate = __commonJS({
|
|
1490
1528
|
"lib/analysis/fragmentstate.js"(exports) {
|
|
@@ -1505,6 +1543,7 @@ var require_fragmentstate = __commonJS({
|
|
|
1505
1543
|
var constraintvarproducer_1 = require_constraintvarproducer();
|
|
1506
1544
|
var asthelpers_1 = require_asthelpers();
|
|
1507
1545
|
var files_1 = require_files();
|
|
1546
|
+
var large_array_1 = require_large_array();
|
|
1508
1547
|
var FragmentState = class _FragmentState {
|
|
1509
1548
|
static {
|
|
1510
1549
|
__name(this, "FragmentState");
|
|
@@ -1526,8 +1565,8 @@ var require_fragmentstate = __commonJS({
|
|
|
1526
1565
|
externalCallbacksProcessed = /* @__PURE__ */ new Set();
|
|
1527
1566
|
arrayEntriesListeners = /* @__PURE__ */ new Map();
|
|
1528
1567
|
objectPropertiesListeners = /* @__PURE__ */ new Map();
|
|
1529
|
-
postponedListenerCalls =
|
|
1530
|
-
postponedListenerCalls2 =
|
|
1568
|
+
postponedListenerCalls = new large_array_1.LargeArray();
|
|
1569
|
+
postponedListenerCalls2 = new large_array_1.LargeArray();
|
|
1531
1570
|
nodesWithNewEdges = /* @__PURE__ */ new Set();
|
|
1532
1571
|
prevNumEdges = 0;
|
|
1533
1572
|
requireGraph = /* @__PURE__ */ new Map();
|
|
@@ -2144,6 +2183,7 @@ var require_diagnostics = __commonJS({
|
|
|
2144
2183
|
wave = 0;
|
|
2145
2184
|
round = 0;
|
|
2146
2185
|
analyzerRounds = 0;
|
|
2186
|
+
propagationRounds = 0;
|
|
2147
2187
|
listenerNotificationRounds = 0;
|
|
2148
2188
|
lastPrintDiagnosticsTime = 0;
|
|
2149
2189
|
lastTelemetryTime = 0;
|
|
@@ -2636,7 +2676,9 @@ var require_solver = __commonJS({
|
|
|
2636
2676
|
vars: f.getNumberOfVarsWithTokens(),
|
|
2637
2677
|
tokens: f.numberOfTokens,
|
|
2638
2678
|
subsetEdges: f.numberOfSubsetEdges,
|
|
2639
|
-
|
|
2679
|
+
analyzerRounds: d.analyzerRounds,
|
|
2680
|
+
propagationRounds: d.propagationRounds,
|
|
2681
|
+
indirectionRound: d.round,
|
|
2640
2682
|
wave: d.wave,
|
|
2641
2683
|
propagations: d.propagations,
|
|
2642
2684
|
unprocessedVars: this.unprocessedTokens.size,
|
|
@@ -3076,7 +3118,8 @@ var require_solver = __commonJS({
|
|
|
3076
3118
|
this.phase = phase;
|
|
3077
3119
|
if (logger_1.default.isDebugEnabled())
|
|
3078
3120
|
logger_1.default.debug("Processing constraints until fixpoint...");
|
|
3079
|
-
const f = this
|
|
3121
|
+
const { fragmentState: f, diagnostics: d } = this;
|
|
3122
|
+
d.propagationRounds++;
|
|
3080
3123
|
f.a.timeoutTimer.checkTimeout();
|
|
3081
3124
|
(0, memory_1.checkMemoryLow)();
|
|
3082
3125
|
await this.checkAbort();
|
|
@@ -3084,14 +3127,14 @@ var require_solver = __commonJS({
|
|
|
3084
3127
|
logger_1.default.verbose(`Propagating (tokens: ${this.unprocessedTokens.size}, non-bounded: ${f.postponedListenerCalls.length}, bounded: ${f.postponedListenerCalls2.length})`);
|
|
3085
3128
|
let wave = 1, round = 1;
|
|
3086
3129
|
while (this.unprocessedTokens.size > 0 || f.postponedListenerCalls.length > 0 || f.postponedListenerCalls2.length > 0) {
|
|
3087
|
-
|
|
3088
|
-
|
|
3130
|
+
d.wave = wave;
|
|
3131
|
+
d.round = round;
|
|
3089
3132
|
if (logger_1.default.isVerboseEnabled())
|
|
3090
3133
|
logger_1.default.verbose(`Fixpoint wave: ${wave} (call edges: ${f.numberOfCallToFunctionEdges}, vars: ${f.getNumberOfVarsWithTokens()}, tokens: ${f.numberOfTokens}, subsets: ${f.numberOfSubsetEdges})`);
|
|
3091
3134
|
if (options_1.options.maxWaves !== void 0 && wave > options_1.options.maxWaves) {
|
|
3092
3135
|
f.warn("Fixpoint wave limit reached, aborting propagation");
|
|
3093
|
-
|
|
3094
|
-
|
|
3136
|
+
d.waveLimitReached++;
|
|
3137
|
+
d.unprocessedTokensSize = 0;
|
|
3095
3138
|
this.unprocessedTokens.clear();
|
|
3096
3139
|
f.nodesWithNewEdges.clear();
|
|
3097
3140
|
f.postponedListenerCalls.length = 0;
|
|
@@ -3111,43 +3154,43 @@ var require_solver = __commonJS({
|
|
|
3111
3154
|
for (const [v, rep] of repmap)
|
|
3112
3155
|
this.redirect(v, rep);
|
|
3113
3156
|
f.prevNumEdges = f.numberOfSubsetEdges;
|
|
3114
|
-
|
|
3115
|
-
|
|
3157
|
+
d.totalCycleEliminationTime += timer1.elapsed();
|
|
3158
|
+
d.totalCycleEliminationRuns++;
|
|
3116
3159
|
if (logger_1.default.isVerboseEnabled())
|
|
3117
3160
|
logger_1.default.verbose(`Cycle detection roots: ${nodes.size} roots, edges: ${edgesBefore} -> ${f.numberOfSubsetEdges} (${(0, timer_1.nanoToMs)(timer1.elapsed())})`);
|
|
3118
3161
|
const timer2 = new timer_1.default();
|
|
3119
3162
|
if (logger_1.default.isVerboseEnabled())
|
|
3120
|
-
logger_1.default.verbose(`Processing ${
|
|
3163
|
+
logger_1.default.verbose(`Processing ${d.unprocessedTokensSize} new token${d.unprocessedTokensSize !== 1 ? "s" : ""}`);
|
|
3121
3164
|
for (let i = reps.length - 1; i >= 0; i--) {
|
|
3122
3165
|
const v = reps[i];
|
|
3123
3166
|
this.processTokens(v);
|
|
3124
3167
|
await this.checkAbort(true);
|
|
3125
3168
|
}
|
|
3126
|
-
|
|
3169
|
+
d.totalPropagationTime += timer2.elapsed();
|
|
3127
3170
|
f.nodesWithNewEdges.clear();
|
|
3128
3171
|
}
|
|
3129
3172
|
const timer3 = new timer_1.default();
|
|
3130
3173
|
for (const v of this.unprocessedTokens.keys())
|
|
3131
3174
|
this.processTokens(v);
|
|
3132
|
-
|
|
3175
|
+
d.totalPropagationTime += timer3.elapsed();
|
|
3133
3176
|
} else {
|
|
3134
3177
|
if (logger_1.default.isVerboseEnabled())
|
|
3135
|
-
logger_1.default.verbose(`Processing ${
|
|
3178
|
+
logger_1.default.verbose(`Processing ${d.unprocessedTokensSize} new token${d.unprocessedTokensSize !== 1 ? "s" : ""}`);
|
|
3136
3179
|
const timer = new timer_1.default();
|
|
3137
3180
|
for (const v of this.unprocessedTokens.keys()) {
|
|
3138
3181
|
this.processTokens(v);
|
|
3139
3182
|
await this.checkAbort(true);
|
|
3140
3183
|
}
|
|
3141
|
-
|
|
3184
|
+
d.totalPropagationTime += timer.elapsed();
|
|
3142
3185
|
}
|
|
3143
3186
|
}
|
|
3144
|
-
if (this.unprocessedTokens.size !== 0 ||
|
|
3145
|
-
assert_1.default.fail(`worklist non-empty: unprocessedTokens.size: ${this.unprocessedTokens.size}, unprocessedTokensSize: ${
|
|
3187
|
+
if (this.unprocessedTokens.size !== 0 || d.unprocessedTokensSize !== this.unprocessedTokens.size)
|
|
3188
|
+
assert_1.default.fail(`worklist non-empty: unprocessedTokens.size: ${this.unprocessedTokens.size}, unprocessedTokensSize: ${d.unprocessedTokensSize}`);
|
|
3146
3189
|
if (f.postponedListenerCalls.length > 0) {
|
|
3147
3190
|
if (logger_1.default.isVerboseEnabled())
|
|
3148
3191
|
logger_1.default.verbose(`Processing non-bounded listener calls: ${f.postponedListenerCalls.length}`);
|
|
3149
3192
|
const timer = new timer_1.default();
|
|
3150
|
-
|
|
3193
|
+
d.listenerNotificationRounds++;
|
|
3151
3194
|
for (const [fun, arg] of f.postponedListenerCalls) {
|
|
3152
3195
|
fun(arg);
|
|
3153
3196
|
if (++this.postponedListenersProcessed % 100 === 0) {
|
|
@@ -3157,11 +3200,11 @@ var require_solver = __commonJS({
|
|
|
3157
3200
|
}
|
|
3158
3201
|
}
|
|
3159
3202
|
f.postponedListenerCalls.length = this.postponedListenersProcessed = 0;
|
|
3160
|
-
|
|
3203
|
+
d.totalListenerCallTime += timer.elapsed();
|
|
3161
3204
|
} else if (f.postponedListenerCalls2.length > 0) {
|
|
3162
3205
|
if (options_1.options.maxIndirections !== void 0 && round > options_1.options.maxIndirections) {
|
|
3163
|
-
|
|
3164
|
-
|
|
3206
|
+
d.indirectionsLimitReached++;
|
|
3207
|
+
d.unprocessedTokensSize = 0;
|
|
3165
3208
|
this.unprocessedTokens.clear();
|
|
3166
3209
|
f.nodesWithNewEdges.clear();
|
|
3167
3210
|
f.postponedListenerCalls.length = 0;
|
|
@@ -3170,7 +3213,7 @@ var require_solver = __commonJS({
|
|
|
3170
3213
|
if (logger_1.default.isVerboseEnabled())
|
|
3171
3214
|
logger_1.default.verbose(`Processing bounded listener calls: ${f.postponedListenerCalls2.length}`);
|
|
3172
3215
|
const timer = new timer_1.default();
|
|
3173
|
-
|
|
3216
|
+
d.listenerNotificationRounds++;
|
|
3174
3217
|
const calls = Array.from(f.postponedListenerCalls2);
|
|
3175
3218
|
f.postponedListenerCalls2.length = this.postponedListenersProcessed = 0;
|
|
3176
3219
|
for (const [fun, args] of calls) {
|
|
@@ -3181,7 +3224,7 @@ var require_solver = __commonJS({
|
|
|
3181
3224
|
this.printDiagnostics();
|
|
3182
3225
|
}
|
|
3183
3226
|
}
|
|
3184
|
-
|
|
3227
|
+
d.totalListenerCallTime += timer.elapsed();
|
|
3185
3228
|
if (logger_1.default.isVerboseEnabled() || options_1.options.diagnostics && options_1.options.printProgress)
|
|
3186
3229
|
logger_1.default.info(`${logger_1.isTTY ? logger_1.GREY : ""}Round ${round} completed after ${(0, timer_1.nanoToMs)(this.timer.elapsed())} (call edges: ${f.numberOfCallToFunctionEdges}, vars: ${f.getNumberOfVarsWithTokens()}, tokens: ${f.numberOfTokens}, subsets: ${f.numberOfSubsetEdges})${logger_1.isTTY ? logger_1.RESET : ""}`);
|
|
3187
3230
|
round++;
|
|
@@ -3193,8 +3236,8 @@ var require_solver = __commonJS({
|
|
|
3193
3236
|
}
|
|
3194
3237
|
if (logger_1.default.isVerboseEnabled() || options_1.options.diagnostics && options_1.options.printProgress)
|
|
3195
3238
|
logger_1.default.info(`${logger_1.isTTY ? logger_1.GREY : ""}${phase} completed after ${(0, timer_1.nanoToMs)(this.timer.elapsed())} (call edges: ${f.numberOfCallToFunctionEdges}, vars: ${f.getNumberOfVarsWithTokens()}, tokens: ${f.numberOfTokens}, subsets: ${f.numberOfSubsetEdges})${logger_1.isTTY ? logger_1.RESET : ""}`);
|
|
3196
|
-
if (
|
|
3197
|
-
assert_1.default.fail(`unprocessedTokensSize non-zero after propagate: ${
|
|
3239
|
+
if (d.unprocessedTokensSize !== 0)
|
|
3240
|
+
assert_1.default.fail(`unprocessedTokensSize non-zero after propagate: ${d.unprocessedTokensSize}`);
|
|
3198
3241
|
}
|
|
3199
3242
|
async checkAbort(throttle = false) {
|
|
3200
3243
|
if (this.abort) {
|
|
@@ -5318,8 +5361,7 @@ var require_analyzer = __commonJS({
|
|
|
5318
5361
|
var memory_1 = require_memory();
|
|
5319
5362
|
var telemetry_emitter_1 = require_telemetry_emitter();
|
|
5320
5363
|
async function analyzeFiles(files, solver) {
|
|
5321
|
-
const a = solver
|
|
5322
|
-
const d = solver.diagnostics;
|
|
5364
|
+
const { globalState: a, diagnostics: d } = solver;
|
|
5323
5365
|
const timer = new timer_1.default();
|
|
5324
5366
|
(0, options_1.resolveBaseDir)();
|
|
5325
5367
|
telemetry_emitter_1.telemetryEmitter.phaseStarted("analysis", { fileCount: files.length });
|
|
@@ -5567,7 +5609,7 @@ var require_analyzer = __commonJS({
|
|
|
5567
5609
|
if (a.approx) {
|
|
5568
5610
|
a.approx.stop();
|
|
5569
5611
|
if (options_1.options.approx && (options_1.options.diagnostics || options_1.options.diagnosticsJson))
|
|
5570
|
-
|
|
5612
|
+
d.approx = a.approx.getDiagnostics();
|
|
5571
5613
|
}
|
|
5572
5614
|
}
|
|
5573
5615
|
if (d.aborted)
|