mapshaper 0.6.42 → 0.6.44
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/bin/mapshaper-gui +9 -2
- package/mapshaper.js +159 -58
- package/package.json +1 -1
- package/www/mapshaper-gui.js +18 -6
- package/www/mapshaper.js +159 -58
package/bin/mapshaper-gui
CHANGED
|
@@ -61,7 +61,10 @@ function startServer(port) {
|
|
|
61
61
|
http.createServer(function(request, response) {
|
|
62
62
|
var uri = url.parse(request.url).pathname;
|
|
63
63
|
clearTimeout(timeout);
|
|
64
|
-
if (uri
|
|
64
|
+
if (uri.includes('..')) {
|
|
65
|
+
// block attempts to load files outside webroot
|
|
66
|
+
serve404(response);
|
|
67
|
+
} else if (uri == '/close') {
|
|
65
68
|
// end process when page closes, unless page is immediately refreshed
|
|
66
69
|
timeout = setTimeout(function() {
|
|
67
70
|
process.exit(0);
|
|
@@ -116,10 +119,14 @@ function serveError(text, code, response) {
|
|
|
116
119
|
response.end();
|
|
117
120
|
}
|
|
118
121
|
|
|
122
|
+
function serve404(response) {
|
|
123
|
+
serveError("404 Not Found\n", 404, response);
|
|
124
|
+
}
|
|
125
|
+
|
|
119
126
|
function serveFile(filename, response) {
|
|
120
127
|
fs.readFile(filename, function(err, content) {
|
|
121
128
|
if (err) {
|
|
122
|
-
|
|
129
|
+
serve404(response);
|
|
123
130
|
} else {
|
|
124
131
|
serveContent(content, response, getMimeType(filename));
|
|
125
132
|
}
|
package/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.6.
|
|
3
|
+
var VERSION = "0.6.44";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
get default () { return utils; },
|
|
9
9
|
get getUniqueName () { return getUniqueName; },
|
|
10
10
|
get isFunction () { return isFunction; },
|
|
11
|
+
get isPromise () { return isPromise; },
|
|
11
12
|
get isObject () { return isObject; },
|
|
12
13
|
get clamp () { return clamp; },
|
|
13
14
|
get isArray () { return isArray; },
|
|
@@ -147,6 +148,10 @@
|
|
|
147
148
|
return typeof obj == 'function';
|
|
148
149
|
}
|
|
149
150
|
|
|
151
|
+
function isPromise(arg) {
|
|
152
|
+
return arg ? isFunction(arg.then) : false;
|
|
153
|
+
}
|
|
154
|
+
|
|
150
155
|
function isObject(obj) {
|
|
151
156
|
return obj === Object(obj); // via underscore
|
|
152
157
|
}
|
|
@@ -12488,7 +12493,6 @@
|
|
|
12488
12493
|
return +n.toPrecision(d);
|
|
12489
12494
|
}
|
|
12490
12495
|
|
|
12491
|
-
|
|
12492
12496
|
function roundToDigits(n, d) {
|
|
12493
12497
|
return +n.toFixed(d); // string conversion makes this slow
|
|
12494
12498
|
}
|
|
@@ -12552,6 +12556,37 @@
|
|
|
12552
12556
|
});
|
|
12553
12557
|
}
|
|
12554
12558
|
|
|
12559
|
+
const fround2 = (function() {
|
|
12560
|
+
var arr = new Float32Array(1);
|
|
12561
|
+
return function(x) {
|
|
12562
|
+
arr[0] = x;
|
|
12563
|
+
return arr[0];
|
|
12564
|
+
};
|
|
12565
|
+
})();
|
|
12566
|
+
|
|
12567
|
+
// This function rounds towards 0 (i.e. floor). TODO: round properly
|
|
12568
|
+
// @bits: number of bits to round
|
|
12569
|
+
// performance: about 3x slower than Math.fround()
|
|
12570
|
+
function getBinaryRoundingFunction(bits) {
|
|
12571
|
+
// double: sign (1) exponent (11) fraction (52)
|
|
12572
|
+
// single: sign (1) exponent (8) fraction (23)
|
|
12573
|
+
if ((bits >= 1 && bits <= 32) === false) {
|
|
12574
|
+
error('Invalid bits argument:', bits);
|
|
12575
|
+
}
|
|
12576
|
+
var isLE = require('os').endianness() == 'LE';
|
|
12577
|
+
var fp = new Float64Array(1);
|
|
12578
|
+
var leastBits = new Uint32Array(fp.buffer, isLE ? 0 : 4, 1);
|
|
12579
|
+
var mask = 2 ** 32 - 2 ** bits; // e.g. bits = 4 -> 0b11110000
|
|
12580
|
+
return function(x) {
|
|
12581
|
+
fp[0] = x;
|
|
12582
|
+
leastBits[0] = leastBits[0] & mask;
|
|
12583
|
+
return fp[0];
|
|
12584
|
+
};
|
|
12585
|
+
}
|
|
12586
|
+
|
|
12587
|
+
// "round to even" on the 23rd bit of the mantissa
|
|
12588
|
+
const fround = Math.fround || fround2;
|
|
12589
|
+
|
|
12555
12590
|
function setCoordinatePrecision(dataset, precision) {
|
|
12556
12591
|
var round = getRoundingFunction(precision);
|
|
12557
12592
|
// var dissolvePolygon, nodes;
|
|
@@ -12586,6 +12621,9 @@
|
|
|
12586
12621
|
getRoundedCoordString: getRoundedCoordString,
|
|
12587
12622
|
getRoundedCoords: getRoundedCoords,
|
|
12588
12623
|
roundPoints: roundPoints,
|
|
12624
|
+
fround2: fround2,
|
|
12625
|
+
getBinaryRoundingFunction: getBinaryRoundingFunction,
|
|
12626
|
+
fround: fround,
|
|
12589
12627
|
setCoordinatePrecision: setCoordinatePrecision
|
|
12590
12628
|
});
|
|
12591
12629
|
|
|
@@ -16438,19 +16476,41 @@
|
|
|
16438
16476
|
buildPolygonMosaic: buildPolygonMosaic
|
|
16439
16477
|
});
|
|
16440
16478
|
|
|
16479
|
+
// Map non-negative integers to non-negative integer ids
|
|
16480
|
+
function IdLookupIndex(n) {
|
|
16481
|
+
var index = new Uint32Array(n);
|
|
16482
|
+
|
|
16483
|
+
this.setId = function(id, val) {
|
|
16484
|
+
if (id >= 0 && val >= 0 && val < n - 1) {
|
|
16485
|
+
index[id] = val + 1;
|
|
16486
|
+
} else {
|
|
16487
|
+
error('Invalid value');
|
|
16488
|
+
}
|
|
16489
|
+
};
|
|
16490
|
+
|
|
16491
|
+
this.hasId = function(id) {
|
|
16492
|
+
return this.getId(id) > -1;
|
|
16493
|
+
};
|
|
16494
|
+
|
|
16495
|
+
this.getId = function(id) {
|
|
16496
|
+
if (id >= 0 && id < n) {
|
|
16497
|
+
return index[id] - 1;
|
|
16498
|
+
} else {
|
|
16499
|
+
return -1;
|
|
16500
|
+
// error('Invalid index');
|
|
16501
|
+
}
|
|
16502
|
+
};
|
|
16503
|
+
}
|
|
16504
|
+
|
|
16505
|
+
|
|
16441
16506
|
// Map positive or negative integer ids to non-negative integer ids
|
|
16442
|
-
function
|
|
16507
|
+
function ArcLookupIndex(n) {
|
|
16443
16508
|
var fwdIndex = new Int32Array(n);
|
|
16444
16509
|
var revIndex = new Int32Array(n);
|
|
16445
|
-
var index = this;
|
|
16446
|
-
var setList = [];
|
|
16447
16510
|
utils.initializeArray(fwdIndex, -1);
|
|
16448
16511
|
utils.initializeArray(revIndex, -1);
|
|
16449
16512
|
|
|
16450
16513
|
this.setId = function(id, val) {
|
|
16451
|
-
if (clearable && !index.hasId(id)) {
|
|
16452
|
-
setList.push(id);
|
|
16453
|
-
}
|
|
16454
16514
|
if (id < 0) {
|
|
16455
16515
|
revIndex[~id] = val;
|
|
16456
16516
|
} else {
|
|
@@ -16458,25 +16518,8 @@
|
|
|
16458
16518
|
}
|
|
16459
16519
|
};
|
|
16460
16520
|
|
|
16461
|
-
this.clear = function() {
|
|
16462
|
-
if (!clearable) {
|
|
16463
|
-
error('Index is not clearable');
|
|
16464
|
-
}
|
|
16465
|
-
setList.forEach(function(id) {
|
|
16466
|
-
index.setId(id, -1);
|
|
16467
|
-
});
|
|
16468
|
-
setList = [];
|
|
16469
|
-
};
|
|
16470
|
-
|
|
16471
|
-
this.clearId = function(id) {
|
|
16472
|
-
if (!index.hasId(id)) {
|
|
16473
|
-
error('Tried to clear an unset id');
|
|
16474
|
-
}
|
|
16475
|
-
index.setId(id, -1);
|
|
16476
|
-
};
|
|
16477
|
-
|
|
16478
16521
|
this.hasId = function(id) {
|
|
16479
|
-
var val =
|
|
16522
|
+
var val = this.getId(id);
|
|
16480
16523
|
return val > -1;
|
|
16481
16524
|
};
|
|
16482
16525
|
|
|
@@ -16489,6 +16532,36 @@
|
|
|
16489
16532
|
};
|
|
16490
16533
|
}
|
|
16491
16534
|
|
|
16535
|
+
// Support clearing the index (for efficient reuse)
|
|
16536
|
+
function ClearableArcLookupIndex(n) {
|
|
16537
|
+
var setList = [];
|
|
16538
|
+
var idx = new ArcLookupIndex(n);
|
|
16539
|
+
var _setId = idx.setId;
|
|
16540
|
+
|
|
16541
|
+
idx.setId = function(id, val) {
|
|
16542
|
+
if (!idx.hasId(id)) {
|
|
16543
|
+
setList.push(id);
|
|
16544
|
+
}
|
|
16545
|
+
_setId(id, val);
|
|
16546
|
+
};
|
|
16547
|
+
|
|
16548
|
+
idx.clear = function() {
|
|
16549
|
+
setList.forEach(function(id) {
|
|
16550
|
+
_setId(id, -1);
|
|
16551
|
+
});
|
|
16552
|
+
setList = [];
|
|
16553
|
+
};
|
|
16554
|
+
|
|
16555
|
+
this.clearId = function(id) {
|
|
16556
|
+
if (!idx.hasId(id)) {
|
|
16557
|
+
error('Tried to clear an unset id');
|
|
16558
|
+
}
|
|
16559
|
+
_setId(id, -1);
|
|
16560
|
+
};
|
|
16561
|
+
|
|
16562
|
+
return idx;
|
|
16563
|
+
}
|
|
16564
|
+
|
|
16492
16565
|
// Associate mosaic tiles with shapes (i.e. identify the groups of tiles that
|
|
16493
16566
|
// belong to each shape)
|
|
16494
16567
|
//
|
|
@@ -16740,7 +16813,7 @@
|
|
|
16740
16813
|
// Supports looking up a shape id using an arc id.
|
|
16741
16814
|
function ShapeArcIndex(shapes, arcs) {
|
|
16742
16815
|
var n = arcs.size();
|
|
16743
|
-
var index = new
|
|
16816
|
+
var index = new ArcLookupIndex(n);
|
|
16744
16817
|
var shapeId;
|
|
16745
16818
|
shapes.forEach(onShape);
|
|
16746
16819
|
|
|
@@ -16892,7 +16965,7 @@
|
|
|
16892
16965
|
var arcs = dataset.arcs;
|
|
16893
16966
|
var filter = getArcPresenceTest(lyr.shapes, arcs);
|
|
16894
16967
|
var nodes = new NodeCollection(arcs, filter);
|
|
16895
|
-
var arcIndex = new
|
|
16968
|
+
var arcIndex = new ClearableArcLookupIndex(arcs.size());
|
|
16896
16969
|
lyr.shapes = lyr.shapes.map(function(shp, i) {
|
|
16897
16970
|
if (!shp) return null;
|
|
16898
16971
|
// split parts at nodes (where multiple arcs intersect)
|
|
@@ -18378,7 +18451,8 @@
|
|
|
18378
18451
|
// null values indicate the lack of a function for parsing/identifying this property
|
|
18379
18452
|
// (in which case a heuristic is used for distinguishing a string literal from an expression)
|
|
18380
18453
|
var stylePropertyTypes = {
|
|
18381
|
-
css: null,
|
|
18454
|
+
// css: null,
|
|
18455
|
+
css: 'inlinecss',
|
|
18382
18456
|
class: 'classname',
|
|
18383
18457
|
dx: 'measure',
|
|
18384
18458
|
dy: 'measure',
|
|
@@ -18565,6 +18639,8 @@
|
|
|
18565
18639
|
val = isPattern(strVal) ? strVal : null;
|
|
18566
18640
|
} else if (type == 'boolean') {
|
|
18567
18641
|
val = parseBoolean(strVal);
|
|
18642
|
+
} else if (type == 'inlinecss') {
|
|
18643
|
+
val = strVal; // TODO: validate
|
|
18568
18644
|
}
|
|
18569
18645
|
// else {
|
|
18570
18646
|
// // unknown type -- assume literal value
|
|
@@ -24662,9 +24738,9 @@ ${svg}
|
|
|
24662
24738
|
.option('class', {
|
|
24663
24739
|
describe: 'name of CSS class or classes (space-separated)'
|
|
24664
24740
|
})
|
|
24665
|
-
|
|
24666
|
-
|
|
24667
|
-
|
|
24741
|
+
.option('css', {
|
|
24742
|
+
describe: 'inline css style'
|
|
24743
|
+
})
|
|
24668
24744
|
.option('fill', {
|
|
24669
24745
|
describe: 'fill color; examples: #eee pink rgba(0, 0, 0, 0.2)'
|
|
24670
24746
|
})
|
|
@@ -38262,7 +38338,7 @@ ${svg}
|
|
|
38262
38338
|
// polygon layer, @clipData). This avoids performing unnecessary intersection
|
|
38263
38339
|
// tests on each line segment.
|
|
38264
38340
|
var layers = dataset.layers.filter(function(lyr) {
|
|
38265
|
-
return !layerIsFullyEnclosed(lyr, dataset, clipData);
|
|
38341
|
+
return layerHasGeometry(lyr) && !layerIsFullyEnclosed(lyr, dataset, clipData);
|
|
38266
38342
|
});
|
|
38267
38343
|
if (layers.length > 0) {
|
|
38268
38344
|
clipLayersInPlace(layers, clipData, dataset, 'clip');
|
|
@@ -41240,21 +41316,24 @@ ${svg}
|
|
|
41240
41316
|
parseConsoleCommands: parseConsoleCommands
|
|
41241
41317
|
});
|
|
41242
41318
|
|
|
41243
|
-
cmd.run = function(job, targets, opts
|
|
41319
|
+
cmd.run = async function(job, targets, opts) {
|
|
41244
41320
|
var commandStr, commands;
|
|
41245
41321
|
if (!opts.expression) {
|
|
41246
41322
|
stop("Missing expression parameter");
|
|
41247
41323
|
}
|
|
41248
41324
|
commandStr = runGlobalExpression(opts.expression, targets);
|
|
41325
|
+
// Support async functions as expressions
|
|
41326
|
+
if (utils.isPromise(commandStr)) {
|
|
41327
|
+
commandStr = await commandStr;
|
|
41328
|
+
}
|
|
41249
41329
|
if (commandStr) {
|
|
41250
41330
|
message(`command: [${commandStr}]`);
|
|
41251
41331
|
commands = parseCommands(commandStr);
|
|
41252
|
-
runParsedCommands(commands, job
|
|
41253
|
-
} else {
|
|
41254
|
-
cb(null);
|
|
41332
|
+
await utils.promisify(runParsedCommands)(commands, job);
|
|
41255
41333
|
}
|
|
41256
41334
|
};
|
|
41257
41335
|
|
|
41336
|
+
// This could return a Promise or a value or nothing
|
|
41258
41337
|
function runGlobalExpression(expression, targets) {
|
|
41259
41338
|
var ctx = getBaseContext();
|
|
41260
41339
|
var output, targetData;
|
|
@@ -42381,6 +42460,7 @@ ${svg}
|
|
|
42381
42460
|
shapes = lyr0.shapes,
|
|
42382
42461
|
index = {},
|
|
42383
42462
|
splitLayers = [],
|
|
42463
|
+
n = getFeatureCount(lyr0),
|
|
42384
42464
|
namer;
|
|
42385
42465
|
|
|
42386
42466
|
if (opts.ids) {
|
|
@@ -42389,11 +42469,18 @@ ${svg}
|
|
|
42389
42469
|
namer = getSplitNameFunction(lyr0, expression);
|
|
42390
42470
|
}
|
|
42391
42471
|
|
|
42472
|
+
// // halt if split field is missing
|
|
42392
42473
|
// if (splitField) {
|
|
42393
42474
|
// internal.requireDataField(lyr0, splitField);
|
|
42394
42475
|
// }
|
|
42395
42476
|
|
|
42396
|
-
|
|
42477
|
+
// if input layer is empty, return original layer
|
|
42478
|
+
// TODO: consider halting
|
|
42479
|
+
if (n === 0) {
|
|
42480
|
+
return [lyr0];
|
|
42481
|
+
}
|
|
42482
|
+
|
|
42483
|
+
utils.repeat(n, function(i) {
|
|
42397
42484
|
var name = namer(i),
|
|
42398
42485
|
lyr;
|
|
42399
42486
|
|
|
@@ -42416,6 +42503,7 @@ ${svg}
|
|
|
42416
42503
|
lyr.data.getRecords().push(properties[i]);
|
|
42417
42504
|
}
|
|
42418
42505
|
});
|
|
42506
|
+
|
|
42419
42507
|
return splitLayers;
|
|
42420
42508
|
};
|
|
42421
42509
|
|
|
@@ -42426,26 +42514,34 @@ ${svg}
|
|
|
42426
42514
|
};
|
|
42427
42515
|
}
|
|
42428
42516
|
|
|
42429
|
-
function
|
|
42430
|
-
// if not splitting on an expression and layer is unnamed, name split-apart layers
|
|
42431
|
-
// like: split-1, split-2, ...
|
|
42432
|
-
return function(i) {
|
|
42433
|
-
return (lyr && lyr.name || 'split') + '-' + (i + 1);
|
|
42434
|
-
};
|
|
42435
|
-
}
|
|
42436
|
-
|
|
42437
|
-
function getSplitNameFunction(lyr, exp) {
|
|
42517
|
+
function getSplitNameFunction(lyr, arg) {
|
|
42438
42518
|
var compiled;
|
|
42439
|
-
if (!
|
|
42519
|
+
if (!arg) {
|
|
42520
|
+
// if not splitting on an expression and layer is unnamed, name split-apart layers
|
|
42521
|
+
// like: split-1, split-2, ...
|
|
42522
|
+
return function(i) {
|
|
42523
|
+
return (lyr && lyr.name || 'split') + '-' + (i + 1);
|
|
42524
|
+
};
|
|
42525
|
+
}
|
|
42526
|
+
if (lyr.data && lyr.data.fieldExists(arg)) {
|
|
42527
|
+
// Argument is a field name
|
|
42528
|
+
return function(i) {
|
|
42529
|
+
var rec = lyr.data.getRecords()[i];
|
|
42530
|
+
return rec ? valueToLayerName(rec[arg]) : '';
|
|
42531
|
+
};
|
|
42532
|
+
}
|
|
42533
|
+
// Assume: argument is an expression
|
|
42440
42534
|
lyr = {name: lyr.name, data: lyr.data}; // remove shape info
|
|
42441
|
-
compiled = compileValueExpression(
|
|
42535
|
+
compiled = compileValueExpression(arg, lyr, null);
|
|
42442
42536
|
return function(i) {
|
|
42443
42537
|
var val = compiled(i);
|
|
42444
|
-
return
|
|
42445
|
-
// return val || val === 0 ? String(val) : '';
|
|
42538
|
+
return valueToLayerName(val);
|
|
42446
42539
|
};
|
|
42447
42540
|
}
|
|
42448
42541
|
|
|
42542
|
+
function valueToLayerName(val) {
|
|
42543
|
+
return String(val);
|
|
42544
|
+
}
|
|
42449
42545
|
|
|
42450
42546
|
// internal.getSplitKey = function(i, field, properties) {
|
|
42451
42547
|
// var rec = field && properties ? properties[i] : null;
|
|
@@ -42481,6 +42577,9 @@ ${svg}
|
|
|
42481
42577
|
|
|
42482
42578
|
cmd.svgStyle = function(lyr, dataset, opts) {
|
|
42483
42579
|
var filter;
|
|
42580
|
+
if (getFeatureCount(lyr) === 0) {
|
|
42581
|
+
return;
|
|
42582
|
+
}
|
|
42484
42583
|
if (!lyr.data) {
|
|
42485
42584
|
initDataTable(lyr);
|
|
42486
42585
|
}
|
|
@@ -43786,7 +43885,7 @@ ${svg}
|
|
|
43786
43885
|
});
|
|
43787
43886
|
|
|
43788
43887
|
} else if (name == 'run') {
|
|
43789
|
-
await
|
|
43888
|
+
await cmd.run(job, targets, opts);
|
|
43790
43889
|
|
|
43791
43890
|
} else if (name == 'scalebar') {
|
|
43792
43891
|
cmd.scalebar(job.catalog, opts);
|
|
@@ -43809,7 +43908,7 @@ ${svg}
|
|
|
43809
43908
|
|
|
43810
43909
|
} else if (name == 'snap') {
|
|
43811
43910
|
// cmd.snap(targetDataset, opts);
|
|
43812
|
-
applyCommandToEachTarget(targets, opts);
|
|
43911
|
+
applyCommandToEachTarget(cmd.snap, targets, opts);
|
|
43813
43912
|
|
|
43814
43913
|
} else if (name == 'sort') {
|
|
43815
43914
|
applyCommandToEachLayer(cmd.sortFeatures, targetLayers, arcs, opts);
|
|
@@ -44063,6 +44162,13 @@ ${svg}
|
|
|
44063
44162
|
}
|
|
44064
44163
|
});
|
|
44065
44164
|
|
|
44165
|
+
var lastCmd = commands[commands.length - 1];
|
|
44166
|
+
if (!runningInBrowser() && lastCmd.name == 'o') {
|
|
44167
|
+
// in CLI, set 'final' flag on final -o command, so the export function knows
|
|
44168
|
+
// that it can modify the output dataset in-place instead of making a copy.
|
|
44169
|
+
lastCmd.options.final = true;
|
|
44170
|
+
}
|
|
44171
|
+
|
|
44066
44172
|
var batches = divideImportCommand(commands);
|
|
44067
44173
|
utils.reduceAsync(batches, null, nextGroup, done);
|
|
44068
44174
|
|
|
@@ -44131,11 +44237,6 @@ ${svg}
|
|
|
44131
44237
|
// @done: function([error], [job])
|
|
44132
44238
|
//
|
|
44133
44239
|
function runParsedCommands(commands, job, done) {
|
|
44134
|
-
if (!runningInBrowser() && commands[commands.length-1].name == 'o') {
|
|
44135
|
-
// in CLI, set 'final' flag on final -o command, so the export function knows
|
|
44136
|
-
// that it can modify the output dataset in-place instead of making a copy.
|
|
44137
|
-
commands[commands.length-1].options.final = true;
|
|
44138
|
-
}
|
|
44139
44240
|
if (!job) job = new Job();
|
|
44140
44241
|
commands = readAndRemoveSettings(job, commands);
|
|
44141
44242
|
if (!runningInBrowser()) {
|
package/package.json
CHANGED
package/www/mapshaper-gui.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
get default () { return utils; },
|
|
6
6
|
get getUniqueName () { return getUniqueName; },
|
|
7
7
|
get isFunction () { return isFunction; },
|
|
8
|
+
get isPromise () { return isPromise; },
|
|
8
9
|
get isObject () { return isObject; },
|
|
9
10
|
get clamp () { return clamp; },
|
|
10
11
|
get isArray () { return isArray; },
|
|
@@ -2157,11 +2158,18 @@
|
|
|
2157
2158
|
}
|
|
2158
2159
|
|
|
2159
2160
|
function downloadNextFile(memo, item, next) {
|
|
2160
|
-
var
|
|
2161
|
-
fetch(item.url).then(resp =>
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2161
|
+
var err;
|
|
2162
|
+
fetch(item.url).then(resp => {
|
|
2163
|
+
if (resp.status != 200) {
|
|
2164
|
+
// e.g. 404 because a URL listed in the GUI query string does not exist
|
|
2165
|
+
throw Error();
|
|
2166
|
+
}
|
|
2167
|
+
return resp.blob();
|
|
2168
|
+
}).then(blob => {
|
|
2169
|
+
if (blob) {
|
|
2170
|
+
blob.name = item.basename;
|
|
2171
|
+
memo.push(blob);
|
|
2172
|
+
}
|
|
2165
2173
|
}).catch(e => {
|
|
2166
2174
|
err = "Error loading " + item.name + ". Possible causes include: wrong URL, no network connection, server not configured for cross-domain sharing (CORS).";
|
|
2167
2175
|
}).finally(() => {
|
|
@@ -5209,6 +5217,10 @@
|
|
|
5209
5217
|
return typeof obj == 'function';
|
|
5210
5218
|
}
|
|
5211
5219
|
|
|
5220
|
+
function isPromise(arg) {
|
|
5221
|
+
return arg ? isFunction(arg.then) : false;
|
|
5222
|
+
}
|
|
5223
|
+
|
|
5212
5224
|
function isObject(obj) {
|
|
5213
5225
|
return obj === Object(obj); // via underscore
|
|
5214
5226
|
}
|
|
@@ -8112,7 +8124,7 @@
|
|
|
8112
8124
|
el.addClass('option-menu');
|
|
8113
8125
|
var html = `<input type="text" class="field-name text-input" placeholder="field name"><br>
|
|
8114
8126
|
<input type="text" class="field-value text-input" placeholder="value"><br>
|
|
8115
|
-
<div class="btn dialog-btn">Apply</div> <span class="inline-checkbox"><input type="checkbox" class="all" />assign value to all records</span>`;
|
|
8127
|
+
<div tabindex="0" class="btn dialog-btn">Apply</div> <span class="inline-checkbox"><input type="checkbox" class="all" />assign value to all records</span>`;
|
|
8116
8128
|
el.html(html);
|
|
8117
8129
|
|
|
8118
8130
|
var name = el.findChild('.field-name');
|
package/www/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.6.
|
|
3
|
+
var VERSION = "0.6.44";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
get default () { return utils; },
|
|
9
9
|
get getUniqueName () { return getUniqueName; },
|
|
10
10
|
get isFunction () { return isFunction; },
|
|
11
|
+
get isPromise () { return isPromise; },
|
|
11
12
|
get isObject () { return isObject; },
|
|
12
13
|
get clamp () { return clamp; },
|
|
13
14
|
get isArray () { return isArray; },
|
|
@@ -147,6 +148,10 @@
|
|
|
147
148
|
return typeof obj == 'function';
|
|
148
149
|
}
|
|
149
150
|
|
|
151
|
+
function isPromise(arg) {
|
|
152
|
+
return arg ? isFunction(arg.then) : false;
|
|
153
|
+
}
|
|
154
|
+
|
|
150
155
|
function isObject(obj) {
|
|
151
156
|
return obj === Object(obj); // via underscore
|
|
152
157
|
}
|
|
@@ -12488,7 +12493,6 @@
|
|
|
12488
12493
|
return +n.toPrecision(d);
|
|
12489
12494
|
}
|
|
12490
12495
|
|
|
12491
|
-
|
|
12492
12496
|
function roundToDigits(n, d) {
|
|
12493
12497
|
return +n.toFixed(d); // string conversion makes this slow
|
|
12494
12498
|
}
|
|
@@ -12552,6 +12556,37 @@
|
|
|
12552
12556
|
});
|
|
12553
12557
|
}
|
|
12554
12558
|
|
|
12559
|
+
const fround2 = (function() {
|
|
12560
|
+
var arr = new Float32Array(1);
|
|
12561
|
+
return function(x) {
|
|
12562
|
+
arr[0] = x;
|
|
12563
|
+
return arr[0];
|
|
12564
|
+
};
|
|
12565
|
+
})();
|
|
12566
|
+
|
|
12567
|
+
// This function rounds towards 0 (i.e. floor). TODO: round properly
|
|
12568
|
+
// @bits: number of bits to round
|
|
12569
|
+
// performance: about 3x slower than Math.fround()
|
|
12570
|
+
function getBinaryRoundingFunction(bits) {
|
|
12571
|
+
// double: sign (1) exponent (11) fraction (52)
|
|
12572
|
+
// single: sign (1) exponent (8) fraction (23)
|
|
12573
|
+
if ((bits >= 1 && bits <= 32) === false) {
|
|
12574
|
+
error('Invalid bits argument:', bits);
|
|
12575
|
+
}
|
|
12576
|
+
var isLE = require('os').endianness() == 'LE';
|
|
12577
|
+
var fp = new Float64Array(1);
|
|
12578
|
+
var leastBits = new Uint32Array(fp.buffer, isLE ? 0 : 4, 1);
|
|
12579
|
+
var mask = 2 ** 32 - 2 ** bits; // e.g. bits = 4 -> 0b11110000
|
|
12580
|
+
return function(x) {
|
|
12581
|
+
fp[0] = x;
|
|
12582
|
+
leastBits[0] = leastBits[0] & mask;
|
|
12583
|
+
return fp[0];
|
|
12584
|
+
};
|
|
12585
|
+
}
|
|
12586
|
+
|
|
12587
|
+
// "round to even" on the 23rd bit of the mantissa
|
|
12588
|
+
const fround = Math.fround || fround2;
|
|
12589
|
+
|
|
12555
12590
|
function setCoordinatePrecision(dataset, precision) {
|
|
12556
12591
|
var round = getRoundingFunction(precision);
|
|
12557
12592
|
// var dissolvePolygon, nodes;
|
|
@@ -12586,6 +12621,9 @@
|
|
|
12586
12621
|
getRoundedCoordString: getRoundedCoordString,
|
|
12587
12622
|
getRoundedCoords: getRoundedCoords,
|
|
12588
12623
|
roundPoints: roundPoints,
|
|
12624
|
+
fround2: fround2,
|
|
12625
|
+
getBinaryRoundingFunction: getBinaryRoundingFunction,
|
|
12626
|
+
fround: fround,
|
|
12589
12627
|
setCoordinatePrecision: setCoordinatePrecision
|
|
12590
12628
|
});
|
|
12591
12629
|
|
|
@@ -16438,19 +16476,41 @@
|
|
|
16438
16476
|
buildPolygonMosaic: buildPolygonMosaic
|
|
16439
16477
|
});
|
|
16440
16478
|
|
|
16479
|
+
// Map non-negative integers to non-negative integer ids
|
|
16480
|
+
function IdLookupIndex(n) {
|
|
16481
|
+
var index = new Uint32Array(n);
|
|
16482
|
+
|
|
16483
|
+
this.setId = function(id, val) {
|
|
16484
|
+
if (id >= 0 && val >= 0 && val < n - 1) {
|
|
16485
|
+
index[id] = val + 1;
|
|
16486
|
+
} else {
|
|
16487
|
+
error('Invalid value');
|
|
16488
|
+
}
|
|
16489
|
+
};
|
|
16490
|
+
|
|
16491
|
+
this.hasId = function(id) {
|
|
16492
|
+
return this.getId(id) > -1;
|
|
16493
|
+
};
|
|
16494
|
+
|
|
16495
|
+
this.getId = function(id) {
|
|
16496
|
+
if (id >= 0 && id < n) {
|
|
16497
|
+
return index[id] - 1;
|
|
16498
|
+
} else {
|
|
16499
|
+
return -1;
|
|
16500
|
+
// error('Invalid index');
|
|
16501
|
+
}
|
|
16502
|
+
};
|
|
16503
|
+
}
|
|
16504
|
+
|
|
16505
|
+
|
|
16441
16506
|
// Map positive or negative integer ids to non-negative integer ids
|
|
16442
|
-
function
|
|
16507
|
+
function ArcLookupIndex(n) {
|
|
16443
16508
|
var fwdIndex = new Int32Array(n);
|
|
16444
16509
|
var revIndex = new Int32Array(n);
|
|
16445
|
-
var index = this;
|
|
16446
|
-
var setList = [];
|
|
16447
16510
|
utils.initializeArray(fwdIndex, -1);
|
|
16448
16511
|
utils.initializeArray(revIndex, -1);
|
|
16449
16512
|
|
|
16450
16513
|
this.setId = function(id, val) {
|
|
16451
|
-
if (clearable && !index.hasId(id)) {
|
|
16452
|
-
setList.push(id);
|
|
16453
|
-
}
|
|
16454
16514
|
if (id < 0) {
|
|
16455
16515
|
revIndex[~id] = val;
|
|
16456
16516
|
} else {
|
|
@@ -16458,25 +16518,8 @@
|
|
|
16458
16518
|
}
|
|
16459
16519
|
};
|
|
16460
16520
|
|
|
16461
|
-
this.clear = function() {
|
|
16462
|
-
if (!clearable) {
|
|
16463
|
-
error('Index is not clearable');
|
|
16464
|
-
}
|
|
16465
|
-
setList.forEach(function(id) {
|
|
16466
|
-
index.setId(id, -1);
|
|
16467
|
-
});
|
|
16468
|
-
setList = [];
|
|
16469
|
-
};
|
|
16470
|
-
|
|
16471
|
-
this.clearId = function(id) {
|
|
16472
|
-
if (!index.hasId(id)) {
|
|
16473
|
-
error('Tried to clear an unset id');
|
|
16474
|
-
}
|
|
16475
|
-
index.setId(id, -1);
|
|
16476
|
-
};
|
|
16477
|
-
|
|
16478
16521
|
this.hasId = function(id) {
|
|
16479
|
-
var val =
|
|
16522
|
+
var val = this.getId(id);
|
|
16480
16523
|
return val > -1;
|
|
16481
16524
|
};
|
|
16482
16525
|
|
|
@@ -16489,6 +16532,36 @@
|
|
|
16489
16532
|
};
|
|
16490
16533
|
}
|
|
16491
16534
|
|
|
16535
|
+
// Support clearing the index (for efficient reuse)
|
|
16536
|
+
function ClearableArcLookupIndex(n) {
|
|
16537
|
+
var setList = [];
|
|
16538
|
+
var idx = new ArcLookupIndex(n);
|
|
16539
|
+
var _setId = idx.setId;
|
|
16540
|
+
|
|
16541
|
+
idx.setId = function(id, val) {
|
|
16542
|
+
if (!idx.hasId(id)) {
|
|
16543
|
+
setList.push(id);
|
|
16544
|
+
}
|
|
16545
|
+
_setId(id, val);
|
|
16546
|
+
};
|
|
16547
|
+
|
|
16548
|
+
idx.clear = function() {
|
|
16549
|
+
setList.forEach(function(id) {
|
|
16550
|
+
_setId(id, -1);
|
|
16551
|
+
});
|
|
16552
|
+
setList = [];
|
|
16553
|
+
};
|
|
16554
|
+
|
|
16555
|
+
this.clearId = function(id) {
|
|
16556
|
+
if (!idx.hasId(id)) {
|
|
16557
|
+
error('Tried to clear an unset id');
|
|
16558
|
+
}
|
|
16559
|
+
_setId(id, -1);
|
|
16560
|
+
};
|
|
16561
|
+
|
|
16562
|
+
return idx;
|
|
16563
|
+
}
|
|
16564
|
+
|
|
16492
16565
|
// Associate mosaic tiles with shapes (i.e. identify the groups of tiles that
|
|
16493
16566
|
// belong to each shape)
|
|
16494
16567
|
//
|
|
@@ -16740,7 +16813,7 @@
|
|
|
16740
16813
|
// Supports looking up a shape id using an arc id.
|
|
16741
16814
|
function ShapeArcIndex(shapes, arcs) {
|
|
16742
16815
|
var n = arcs.size();
|
|
16743
|
-
var index = new
|
|
16816
|
+
var index = new ArcLookupIndex(n);
|
|
16744
16817
|
var shapeId;
|
|
16745
16818
|
shapes.forEach(onShape);
|
|
16746
16819
|
|
|
@@ -16892,7 +16965,7 @@
|
|
|
16892
16965
|
var arcs = dataset.arcs;
|
|
16893
16966
|
var filter = getArcPresenceTest(lyr.shapes, arcs);
|
|
16894
16967
|
var nodes = new NodeCollection(arcs, filter);
|
|
16895
|
-
var arcIndex = new
|
|
16968
|
+
var arcIndex = new ClearableArcLookupIndex(arcs.size());
|
|
16896
16969
|
lyr.shapes = lyr.shapes.map(function(shp, i) {
|
|
16897
16970
|
if (!shp) return null;
|
|
16898
16971
|
// split parts at nodes (where multiple arcs intersect)
|
|
@@ -18378,7 +18451,8 @@
|
|
|
18378
18451
|
// null values indicate the lack of a function for parsing/identifying this property
|
|
18379
18452
|
// (in which case a heuristic is used for distinguishing a string literal from an expression)
|
|
18380
18453
|
var stylePropertyTypes = {
|
|
18381
|
-
css: null,
|
|
18454
|
+
// css: null,
|
|
18455
|
+
css: 'inlinecss',
|
|
18382
18456
|
class: 'classname',
|
|
18383
18457
|
dx: 'measure',
|
|
18384
18458
|
dy: 'measure',
|
|
@@ -18565,6 +18639,8 @@
|
|
|
18565
18639
|
val = isPattern(strVal) ? strVal : null;
|
|
18566
18640
|
} else if (type == 'boolean') {
|
|
18567
18641
|
val = parseBoolean(strVal);
|
|
18642
|
+
} else if (type == 'inlinecss') {
|
|
18643
|
+
val = strVal; // TODO: validate
|
|
18568
18644
|
}
|
|
18569
18645
|
// else {
|
|
18570
18646
|
// // unknown type -- assume literal value
|
|
@@ -24662,9 +24738,9 @@ ${svg}
|
|
|
24662
24738
|
.option('class', {
|
|
24663
24739
|
describe: 'name of CSS class or classes (space-separated)'
|
|
24664
24740
|
})
|
|
24665
|
-
|
|
24666
|
-
|
|
24667
|
-
|
|
24741
|
+
.option('css', {
|
|
24742
|
+
describe: 'inline css style'
|
|
24743
|
+
})
|
|
24668
24744
|
.option('fill', {
|
|
24669
24745
|
describe: 'fill color; examples: #eee pink rgba(0, 0, 0, 0.2)'
|
|
24670
24746
|
})
|
|
@@ -38262,7 +38338,7 @@ ${svg}
|
|
|
38262
38338
|
// polygon layer, @clipData). This avoids performing unnecessary intersection
|
|
38263
38339
|
// tests on each line segment.
|
|
38264
38340
|
var layers = dataset.layers.filter(function(lyr) {
|
|
38265
|
-
return !layerIsFullyEnclosed(lyr, dataset, clipData);
|
|
38341
|
+
return layerHasGeometry(lyr) && !layerIsFullyEnclosed(lyr, dataset, clipData);
|
|
38266
38342
|
});
|
|
38267
38343
|
if (layers.length > 0) {
|
|
38268
38344
|
clipLayersInPlace(layers, clipData, dataset, 'clip');
|
|
@@ -41240,21 +41316,24 @@ ${svg}
|
|
|
41240
41316
|
parseConsoleCommands: parseConsoleCommands
|
|
41241
41317
|
});
|
|
41242
41318
|
|
|
41243
|
-
cmd.run = function(job, targets, opts
|
|
41319
|
+
cmd.run = async function(job, targets, opts) {
|
|
41244
41320
|
var commandStr, commands;
|
|
41245
41321
|
if (!opts.expression) {
|
|
41246
41322
|
stop("Missing expression parameter");
|
|
41247
41323
|
}
|
|
41248
41324
|
commandStr = runGlobalExpression(opts.expression, targets);
|
|
41325
|
+
// Support async functions as expressions
|
|
41326
|
+
if (utils.isPromise(commandStr)) {
|
|
41327
|
+
commandStr = await commandStr;
|
|
41328
|
+
}
|
|
41249
41329
|
if (commandStr) {
|
|
41250
41330
|
message(`command: [${commandStr}]`);
|
|
41251
41331
|
commands = parseCommands(commandStr);
|
|
41252
|
-
runParsedCommands(commands, job
|
|
41253
|
-
} else {
|
|
41254
|
-
cb(null);
|
|
41332
|
+
await utils.promisify(runParsedCommands)(commands, job);
|
|
41255
41333
|
}
|
|
41256
41334
|
};
|
|
41257
41335
|
|
|
41336
|
+
// This could return a Promise or a value or nothing
|
|
41258
41337
|
function runGlobalExpression(expression, targets) {
|
|
41259
41338
|
var ctx = getBaseContext();
|
|
41260
41339
|
var output, targetData;
|
|
@@ -42381,6 +42460,7 @@ ${svg}
|
|
|
42381
42460
|
shapes = lyr0.shapes,
|
|
42382
42461
|
index = {},
|
|
42383
42462
|
splitLayers = [],
|
|
42463
|
+
n = getFeatureCount(lyr0),
|
|
42384
42464
|
namer;
|
|
42385
42465
|
|
|
42386
42466
|
if (opts.ids) {
|
|
@@ -42389,11 +42469,18 @@ ${svg}
|
|
|
42389
42469
|
namer = getSplitNameFunction(lyr0, expression);
|
|
42390
42470
|
}
|
|
42391
42471
|
|
|
42472
|
+
// // halt if split field is missing
|
|
42392
42473
|
// if (splitField) {
|
|
42393
42474
|
// internal.requireDataField(lyr0, splitField);
|
|
42394
42475
|
// }
|
|
42395
42476
|
|
|
42396
|
-
|
|
42477
|
+
// if input layer is empty, return original layer
|
|
42478
|
+
// TODO: consider halting
|
|
42479
|
+
if (n === 0) {
|
|
42480
|
+
return [lyr0];
|
|
42481
|
+
}
|
|
42482
|
+
|
|
42483
|
+
utils.repeat(n, function(i) {
|
|
42397
42484
|
var name = namer(i),
|
|
42398
42485
|
lyr;
|
|
42399
42486
|
|
|
@@ -42416,6 +42503,7 @@ ${svg}
|
|
|
42416
42503
|
lyr.data.getRecords().push(properties[i]);
|
|
42417
42504
|
}
|
|
42418
42505
|
});
|
|
42506
|
+
|
|
42419
42507
|
return splitLayers;
|
|
42420
42508
|
};
|
|
42421
42509
|
|
|
@@ -42426,26 +42514,34 @@ ${svg}
|
|
|
42426
42514
|
};
|
|
42427
42515
|
}
|
|
42428
42516
|
|
|
42429
|
-
function
|
|
42430
|
-
// if not splitting on an expression and layer is unnamed, name split-apart layers
|
|
42431
|
-
// like: split-1, split-2, ...
|
|
42432
|
-
return function(i) {
|
|
42433
|
-
return (lyr && lyr.name || 'split') + '-' + (i + 1);
|
|
42434
|
-
};
|
|
42435
|
-
}
|
|
42436
|
-
|
|
42437
|
-
function getSplitNameFunction(lyr, exp) {
|
|
42517
|
+
function getSplitNameFunction(lyr, arg) {
|
|
42438
42518
|
var compiled;
|
|
42439
|
-
if (!
|
|
42519
|
+
if (!arg) {
|
|
42520
|
+
// if not splitting on an expression and layer is unnamed, name split-apart layers
|
|
42521
|
+
// like: split-1, split-2, ...
|
|
42522
|
+
return function(i) {
|
|
42523
|
+
return (lyr && lyr.name || 'split') + '-' + (i + 1);
|
|
42524
|
+
};
|
|
42525
|
+
}
|
|
42526
|
+
if (lyr.data && lyr.data.fieldExists(arg)) {
|
|
42527
|
+
// Argument is a field name
|
|
42528
|
+
return function(i) {
|
|
42529
|
+
var rec = lyr.data.getRecords()[i];
|
|
42530
|
+
return rec ? valueToLayerName(rec[arg]) : '';
|
|
42531
|
+
};
|
|
42532
|
+
}
|
|
42533
|
+
// Assume: argument is an expression
|
|
42440
42534
|
lyr = {name: lyr.name, data: lyr.data}; // remove shape info
|
|
42441
|
-
compiled = compileValueExpression(
|
|
42535
|
+
compiled = compileValueExpression(arg, lyr, null);
|
|
42442
42536
|
return function(i) {
|
|
42443
42537
|
var val = compiled(i);
|
|
42444
|
-
return
|
|
42445
|
-
// return val || val === 0 ? String(val) : '';
|
|
42538
|
+
return valueToLayerName(val);
|
|
42446
42539
|
};
|
|
42447
42540
|
}
|
|
42448
42541
|
|
|
42542
|
+
function valueToLayerName(val) {
|
|
42543
|
+
return String(val);
|
|
42544
|
+
}
|
|
42449
42545
|
|
|
42450
42546
|
// internal.getSplitKey = function(i, field, properties) {
|
|
42451
42547
|
// var rec = field && properties ? properties[i] : null;
|
|
@@ -42481,6 +42577,9 @@ ${svg}
|
|
|
42481
42577
|
|
|
42482
42578
|
cmd.svgStyle = function(lyr, dataset, opts) {
|
|
42483
42579
|
var filter;
|
|
42580
|
+
if (getFeatureCount(lyr) === 0) {
|
|
42581
|
+
return;
|
|
42582
|
+
}
|
|
42484
42583
|
if (!lyr.data) {
|
|
42485
42584
|
initDataTable(lyr);
|
|
42486
42585
|
}
|
|
@@ -43786,7 +43885,7 @@ ${svg}
|
|
|
43786
43885
|
});
|
|
43787
43886
|
|
|
43788
43887
|
} else if (name == 'run') {
|
|
43789
|
-
await
|
|
43888
|
+
await cmd.run(job, targets, opts);
|
|
43790
43889
|
|
|
43791
43890
|
} else if (name == 'scalebar') {
|
|
43792
43891
|
cmd.scalebar(job.catalog, opts);
|
|
@@ -43809,7 +43908,7 @@ ${svg}
|
|
|
43809
43908
|
|
|
43810
43909
|
} else if (name == 'snap') {
|
|
43811
43910
|
// cmd.snap(targetDataset, opts);
|
|
43812
|
-
applyCommandToEachTarget(targets, opts);
|
|
43911
|
+
applyCommandToEachTarget(cmd.snap, targets, opts);
|
|
43813
43912
|
|
|
43814
43913
|
} else if (name == 'sort') {
|
|
43815
43914
|
applyCommandToEachLayer(cmd.sortFeatures, targetLayers, arcs, opts);
|
|
@@ -44063,6 +44162,13 @@ ${svg}
|
|
|
44063
44162
|
}
|
|
44064
44163
|
});
|
|
44065
44164
|
|
|
44165
|
+
var lastCmd = commands[commands.length - 1];
|
|
44166
|
+
if (!runningInBrowser() && lastCmd.name == 'o') {
|
|
44167
|
+
// in CLI, set 'final' flag on final -o command, so the export function knows
|
|
44168
|
+
// that it can modify the output dataset in-place instead of making a copy.
|
|
44169
|
+
lastCmd.options.final = true;
|
|
44170
|
+
}
|
|
44171
|
+
|
|
44066
44172
|
var batches = divideImportCommand(commands);
|
|
44067
44173
|
utils.reduceAsync(batches, null, nextGroup, done);
|
|
44068
44174
|
|
|
@@ -44131,11 +44237,6 @@ ${svg}
|
|
|
44131
44237
|
// @done: function([error], [job])
|
|
44132
44238
|
//
|
|
44133
44239
|
function runParsedCommands(commands, job, done) {
|
|
44134
|
-
if (!runningInBrowser() && commands[commands.length-1].name == 'o') {
|
|
44135
|
-
// in CLI, set 'final' flag on final -o command, so the export function knows
|
|
44136
|
-
// that it can modify the output dataset in-place instead of making a copy.
|
|
44137
|
-
commands[commands.length-1].options.final = true;
|
|
44138
|
-
}
|
|
44139
44240
|
if (!job) job = new Job();
|
|
44140
44241
|
commands = readAndRemoveSettings(job, commands);
|
|
44141
44242
|
if (!runningInBrowser()) {
|