@dra2020/district-analytics 3.0.1 → 3.1.0

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/dist/cli.js CHANGED
@@ -86,10 +86,10 @@
86
86
  /************************************************************************/
87
87
  /******/ ({
88
88
 
89
- /***/ "./node_modules/@dra2020/dra-score/dist/dra-score.bundle.js":
90
- /*!******************************************************************!*\
91
- !*** ./node_modules/@dra2020/dra-score/dist/dra-score.bundle.js ***!
92
- \******************************************************************/
89
+ /***/ "../dra-score/dist/dra-score.bundle.js":
90
+ /*!*********************************************!*\
91
+ !*** ../dra-score/dist/dra-score.bundle.js ***!
92
+ \*********************************************/
93
93
  /*! no static exports found */
94
94
  /***/ (function(module, exports, __webpack_require__) {
95
95
 
@@ -89814,7 +89814,11 @@ function doPopulationDeviation(e, targetSize, bLegislative, bLog = false) {
89814
89814
  // Round the raw value to the desired level of precision
89815
89815
  const popDev = U.trim((max - min) / targetSize);
89816
89816
  const score = scorePopulationDeviation(popDev, bLegislative);
89817
- const notes = { 'maxDeviation': max - min };
89817
+ const threshold = bLegislative ? S.POPDEV_WORST_LD : S.POPDEV_WORST;
89818
+ const notes = {
89819
+ 'maxDeviation': max - min,
89820
+ 'threshold': threshold
89821
+ };
89818
89822
  // Populate the measurement
89819
89823
  const m = {
89820
89824
  raw: popDev,
@@ -90349,7 +90353,7 @@ const cohesive_1 = __webpack_require__(/*! ./cohesive */ "./src/cohesive.ts");
90349
90353
  const equal_1 = __webpack_require__(/*! ./equal */ "./src/equal.ts");
90350
90354
  const fair_1 = __webpack_require__(/*! ./fair */ "./src/fair.ts");
90351
90355
  // TODO - Score opportunity for minority representation
90352
- function scorePlan(p) {
90356
+ function scorePlan(p, overridesJSON = undefined) {
90353
90357
  // BEST subcategories - compactness, splitting, population deviation
90354
90358
  // Compactness
90355
90359
  const reockM = compact_1.doReock(p.compactnessProfile.GeometryByDistrict);
@@ -90636,10 +90640,10 @@ module.exports = JSON.parse("{\"score\":5,\"best\":{\"BestScore\":18,\"compactne
90636
90640
 
90637
90641
  /***/ }),
90638
90642
 
90639
- /***/ "./node_modules/@dra2020/poly/dist/poly.js":
90640
- /*!*************************************************!*\
90641
- !*** ./node_modules/@dra2020/poly/dist/poly.js ***!
90642
- \*************************************************/
90643
+ /***/ "./node_modules/@dra2020/dra-types/dist/dra-types.js":
90644
+ /*!***********************************************************!*\
90645
+ !*** ./node_modules/@dra2020/dra-types/dist/dra-types.js ***!
90646
+ \***********************************************************/
90643
90647
  /*! no static exports found */
90644
90648
  /***/ (function(module, exports, __webpack_require__) {
90645
90649
 
@@ -90749,334 +90753,2145 @@ function __export(m) {
90749
90753
  for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
90750
90754
  }
90751
90755
  Object.defineProperty(exports, "__esModule", { value: true });
90752
- __export(__webpack_require__(/*! ./poly */ "./lib/poly.ts"));
90753
- __export(__webpack_require__(/*! ./union */ "./lib/union.ts"));
90756
+ __export(__webpack_require__(/*! ./dra-types */ "./lib/dra-types.ts"));
90754
90757
 
90755
90758
 
90756
90759
  /***/ }),
90757
90760
 
90758
- /***/ "./lib/poly.ts":
90759
- /*!*********************!*\
90760
- !*** ./lib/poly.ts ***!
90761
- \*********************/
90761
+ /***/ "./lib/dra-types.ts":
90762
+ /*!**************************!*\
90763
+ !*** ./lib/dra-types.ts ***!
90764
+ \**************************/
90762
90765
  /*! no static exports found */
90763
90766
  /***/ (function(module, exports, __webpack_require__) {
90764
90767
 
90765
90768
  "use strict";
90766
90769
 
90767
90770
  Object.defineProperty(exports, "__esModule", { value: true });
90771
+ // Public libraries
90772
+ const Hash = __webpack_require__(/*! object-hash */ "object-hash");
90768
90773
  const Util = __webpack_require__(/*! @dra2020/util */ "@dra2020/util");
90769
- // Internal utilities
90770
- exports.EARTH_RADIUS = 6371000; // Radius of earth in meters
90771
- const DefaultOptions = {};
90772
- // Return geographic polygon area in meters^2
90773
- function polySimpleArea(p, options) {
90774
- if (options === undefined)
90775
- options = DefaultOptions;
90776
- let p1;
90777
- let p2;
90778
- let p3;
90779
- let dx;
90780
- let l;
90781
- let m;
90782
- let u;
90783
- let i;
90784
- let total = 0;
90785
- let n = p.length;
90786
- if (n > 2) {
90787
- for (i = 0; i < n; i++) {
90788
- if (i === n - 2) {
90789
- l = n - 2;
90790
- m = n - 1;
90791
- u = 0;
90792
- }
90793
- else if (i === n - 1) {
90794
- l = n - 1;
90795
- m = 0;
90796
- u = 1;
90797
- }
90798
- else {
90799
- l = i;
90800
- m = i + 1;
90801
- u = i + 2;
90802
- }
90803
- p1 = p[l];
90804
- p2 = p[m];
90805
- p3 = p[u];
90806
- dx = (Util.deg2rad(p3[0]) - Util.deg2rad(p1[0]));
90807
- dx *= Math.sin(Util.deg2rad(p2[1]));
90808
- total += dx;
90809
- }
90810
- total *= exports.EARTH_RADIUS * exports.EARTH_RADIUS / 2;
90811
- }
90812
- return Math.abs(total);
90813
- }
90814
- // Allow bare polygon coordinates array or GeoJSON feature.
90815
- // Normalize to multipolygon points array.
90816
- function polyNormalize(poly, options) {
90817
- if (options === undefined)
90818
- options = DefaultOptions;
90819
- // Convert a GeoJSON polygon or multipolygon to the raw list of points
90820
- if (poly && poly.geometry && poly.geometry.coordinates)
90821
- poly = poly.geometry.coordinates;
90822
- // This is really an invalid specification but used internally to represent null polygon
90823
- if (poly && poly.length == 0)
90824
- return null;
90825
- if (Util.depthof(poly) == 4)
90826
- poly = [poly];
90827
- return poly;
90774
+ // Canonical hashing of splitblock data
90775
+ function hash(o) {
90776
+ return Hash(o, { respectType: false,
90777
+ unorderedArrays: true,
90778
+ unorderedObjects: true,
90779
+ excludeKeys: (k) => (k === 'id' || k === 'chunk')
90780
+ });
90828
90781
  }
90829
- exports.polyNormalize = polyNormalize;
90830
- // Area of geographic polygon
90831
- function polyArea(poly, options) {
90832
- if (options === undefined)
90833
- options = DefaultOptions;
90834
- poly = polyNormalize(poly, options);
90835
- let a = 0;
90836
- // MultiPolygon is a set of polygons
90837
- for (let i = 0; poly && i < poly.length; i++) {
90838
- // Single polygon is exterior ring with interior holes. Holes are subtracted.
90839
- let p = poly[i];
90840
- for (let j = 0; j < p.length; j++) {
90841
- let sp = p[j];
90842
- a += polySimpleArea(sp, options) * (j == 0 ? 1 : -1);
90782
+ function vgeoidToGeoid(vgeoid) {
90783
+ let re = /vfeature_([^_]*)_.*/;
90784
+ let a = re.exec(vgeoid);
90785
+ if (a == null || a.length != 2)
90786
+ return '';
90787
+ else
90788
+ return a[1];
90789
+ }
90790
+ exports.vgeoidToGeoid = vgeoidToGeoid;
90791
+ function vgeoidToChunk(vgeoid) {
90792
+ // vgeoid is string of form: "vfeature_[geoid]_[chunkid]_[hash]"
90793
+ // the contents are chunked into a file of form "vfeature_chunk_[chunkid]"
90794
+ // So extract the chunk ID and download that.
90795
+ let re = /vfeature_([^_]*)_([^_*])_(.*)/;
90796
+ let a = re.exec(vgeoid);
90797
+ if (a && a.length == 4)
90798
+ vgeoid = `vfeature_chunk_${a[2]}`;
90799
+ else
90800
+ vgeoid = null;
90801
+ return vgeoid;
90802
+ }
90803
+ exports.vgeoidToChunk = vgeoidToChunk;
90804
+ function vgeoidToHash(vgeoid) {
90805
+ // vgeoid is string of form: "vfeature_[geoid]_[chunkid]_[hash]"
90806
+ let re = /vfeature_([^_]*)_([^_*])_(.*)/;
90807
+ let a = re.exec(vgeoid);
90808
+ if (a && a.length == 4)
90809
+ vgeoid = a[3];
90810
+ else
90811
+ vgeoid = null;
90812
+ return vgeoid;
90813
+ }
90814
+ exports.vgeoidToHash = vgeoidToHash;
90815
+ function isVfeature(geoid) {
90816
+ return geoid.indexOf('vfeature') === 0;
90817
+ }
90818
+ exports.isVfeature = isVfeature;
90819
+ function splitToCacheKey(s) {
90820
+ if (s.id === undefined)
90821
+ s.id = hash(s);
90822
+ if (s.chunk === undefined)
90823
+ s.chunk = "0";
90824
+ return `_${s.state}_${s.datasource}_vfeature_${s.geoid}_${s.chunk}_${s.id}.geojson`;
90825
+ }
90826
+ exports.splitToCacheKey = splitToCacheKey;
90827
+ function splitToChunkKey(s) {
90828
+ if (s.chunk === undefined)
90829
+ s.chunk = "0";
90830
+ return `_${s.state}_${s.datasource}_vfeature_chunk_${s.chunk}.geojson`;
90831
+ }
90832
+ exports.splitToChunkKey = splitToChunkKey;
90833
+ function splitToPrefix(s) {
90834
+ if (s.blocks === undefined) {
90835
+ let re = /_([^_]*)_(.*)_vfeature.*\.geojson$/;
90836
+ let a = re.exec(s.id);
90837
+ if (a && a.length == 3)
90838
+ return `_${a[1]}_${a[2]}`;
90839
+ return s.id;
90840
+ }
90841
+ return `_${s.state}_${s.datasource}`;
90842
+ }
90843
+ exports.splitToPrefix = splitToPrefix;
90844
+ function cacheKeysToChunkHash(keys) {
90845
+ return hash(keys);
90846
+ }
90847
+ exports.cacheKeysToChunkHash = cacheKeysToChunkHash;
90848
+ let reNumeric = /^(\D*)(\d*)(\D*)$/;
90849
+ let reDistrictNumber = /^\d+$/;
90850
+ let reDistrictNumeric = /^\d/;
90851
+ // Normalize any numeric part to have no padded leading zeros
90852
+ function canonicalDistrictID(districtID) {
90853
+ let a = reNumeric.exec(districtID);
90854
+ if (a && a.length == 4) {
90855
+ if (a[2].length > 0)
90856
+ a[2] = String(Number(a[2]));
90857
+ districtID = `${a[1]}${a[2]}${a[3]}`;
90858
+ }
90859
+ return districtID;
90860
+ }
90861
+ exports.canonicalDistrictID = canonicalDistrictID;
90862
+ // Normalize any numeric part to have four digits with padded leading zeros
90863
+ function canonicalSortingDistrictID(districtID) {
90864
+ let a = reNumeric.exec(districtID);
90865
+ if (a && a.length == 4) {
90866
+ let s = a[2];
90867
+ if (s.length > 0) {
90868
+ switch (s.length) {
90869
+ case 1:
90870
+ s = `000${s}`;
90871
+ break;
90872
+ case 2:
90873
+ s = `00${s}`;
90874
+ break;
90875
+ case 3:
90876
+ s = `0${s}`;
90877
+ break;
90878
+ }
90879
+ a[2] = s;
90843
90880
  }
90881
+ districtID = `${a[1]}${a[2]}${a[3]}`;
90844
90882
  }
90845
- return a;
90846
- }
90847
- exports.polyArea = polyArea;
90848
- // Return distance in meters given two lat/lon points
90849
- function haversine(x1, y1, x2, y2, options) {
90850
- let dLat = Util.deg2rad(y2 - y1);
90851
- let dLon = Util.deg2rad(x2 - x1);
90852
- let c;
90853
- // Short circuit for using simple cartesian algorithm instead of haversine
90854
- if (options.noLatitudeCorrection)
90855
- c = Math.sqrt((dLat * dLat) + (dLon * dLon));
90856
- else {
90857
- let lat1 = Util.deg2rad(y1);
90858
- let lat2 = Util.deg2rad(y2);
90859
- let a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
90860
- Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
90861
- c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
90862
- }
90863
- return exports.EARTH_RADIUS * c;
90883
+ return districtID;
90864
90884
  }
90865
- // Perimeter of geographic polygon in meters
90866
- function polyPerimeter(poly, options) {
90867
- if (options === undefined)
90868
- options = DefaultOptions;
90869
- poly = polyNormalize(poly, options);
90870
- let perimeter = 0;
90871
- for (let i = 0; poly && i < poly.length; i++) {
90872
- // Ignore holes so only look at first polyline
90873
- let p = poly[i][0];
90874
- for (let j = 0; j < p.length - 1; j++)
90875
- perimeter += haversine(p[j][0], p[j][1], p[j + 1][0], p[j + 1][1], options);
90876
- if (p.length > 2 && (p[0][0] != p[p.length - 1][0] || p[0][1] != p[p.length - 1][1]))
90877
- perimeter += haversine(p[0][0], p[0][1], p[p.length - 1][0], p[p.length - 1][1], options);
90885
+ exports.canonicalSortingDistrictID = canonicalSortingDistrictID;
90886
+ // Return numeric part of districtID (or -1 if there is none)
90887
+ function canonicalNumericFromDistrictID(districtID) {
90888
+ let a = reNumeric.exec(districtID);
90889
+ if (a && a.length == 4) {
90890
+ let s = a[2];
90891
+ if (s.length > 0)
90892
+ return Number(s);
90878
90893
  }
90879
- return perimeter;
90894
+ return -1;
90880
90895
  }
90881
- exports.polyPerimeter = polyPerimeter;
90882
- class Point {
90883
- constructor(x, y) {
90884
- this.x = x;
90885
- this.y = y;
90896
+ exports.canonicalNumericFromDistrictID = canonicalNumericFromDistrictID;
90897
+ function canonicalDistrictIDFromNumber(districtID, n) {
90898
+ let a = reNumeric.exec(districtID);
90899
+ if (a && a.length == 4) {
90900
+ a[2] = String(n);
90901
+ districtID = `${a[1]}${a[2]}${a[3]}`;
90886
90902
  }
90903
+ else
90904
+ districtID = String(n);
90905
+ return districtID;
90887
90906
  }
90888
- class Circle {
90889
- constructor(x, y, r) {
90890
- this.x = x;
90891
- this.y = y;
90892
- this.r = r;
90907
+ exports.canonicalDistrictIDFromNumber = canonicalDistrictIDFromNumber;
90908
+ function canonicalDistrictIDOrdering(order) {
90909
+ let keys = Object.keys(order);
90910
+ let i;
90911
+ let a = [];
90912
+ let template = undefined;
90913
+ keys = keys.map((s) => canonicalSortingDistrictID(s));
90914
+ keys.sort();
90915
+ order = {};
90916
+ for (i = 0; i < keys.length; i++)
90917
+ order[canonicalDistrictID(keys[i])] = i + 1;
90918
+ // Remove water districts
90919
+ if (order['ZZZ'])
90920
+ delete order['ZZZ'];
90921
+ if (order['ZZ'])
90922
+ delete order['ZZ'];
90923
+ return order;
90924
+ }
90925
+ exports.canonicalDistrictIDOrdering = canonicalDistrictIDOrdering;
90926
+ let reArray = [
90927
+ /^(\d\d[^\s,"']*)[\s]*,[\s]*([^\s'"]+)[\s]*$/,
90928
+ /^["'](\d\d[^"']*)["'][\s]*,[\s]*["']([^"']*)["'][\s]*$/,
90929
+ /^(\d\d[^\s,]*)[\s]*,[\s]*["']([^"']*)["'][\s]*$/,
90930
+ /^["'](\d\d[^"']*)["'][\s]*,[\s]*([^\s]+)[\s]*$/,
90931
+ ];
90932
+ function parseCSVLine(line) {
90933
+ if (line == null || line == '')
90934
+ return null;
90935
+ for (let i = 0; i < reArray.length; i++) {
90936
+ let a = reArray[i].exec(line);
90937
+ if (a && a.length === 3)
90938
+ return { geoid: a[1], districtID: a[2] };
90893
90939
  }
90940
+ return null;
90894
90941
  }
90895
- exports.Circle = Circle;
90896
- //
90897
- // Returns the smallest circle that encloses the given polygon.
90898
- // Runs in expected O(n) time, randomized.
90899
- // Note: If 0 points are given, null is returned.
90900
- // If 1 point is given, a circle of radius 0 is returned.
90901
- //
90902
- function polyToCircle(poly, options) {
90903
- if (options === undefined)
90904
- options = DefaultOptions;
90905
- return makeCircle(polyToExteriorPoints(poly));
90942
+ exports.parseCSVLine = parseCSVLine;
90943
+ function blockmapToState(blockMap) {
90944
+ for (var id in blockMap)
90945
+ if (blockMap.hasOwnProperty(id))
90946
+ return geoidToState(id);
90947
+ return null;
90906
90948
  }
90907
- exports.polyToCircle = polyToCircle;
90949
+ exports.blockmapToState = blockmapToState;
90950
+ // blockToVTD:
90951
+ // Take BlockMapping (simple map of GEOID to districtID) and a per-state map of block-level GEOID to VTD
90952
+ // and return the output mapping of VTD to districtID, as well a data structure that describes any VTD's
90953
+ // that need to be split between districtIDs. Also returns the DistrictOrder structure that defines the
90954
+ // districtIDs that were used by the file.
90908
90955
  //
90909
- // Returns the circle whose perimeter is equal to the perimeter of the bounding perimeter
90910
- // of the polygon. Use binary search to find an approximation.
90956
+ // The state (as specified by the first two digits of the GEOID) is also determined. If the GEOID's do
90957
+ // not all specify the same state, the mapping is considered invalid and the outValid flag is set to false.
90911
90958
  //
90912
- function polyToPolsbyPopperCircle(poly, options) {
90913
- if (options === undefined)
90914
- options = DefaultOptions;
90915
- let c = polyToCircle(poly, options);
90916
- if (c == null)
90917
- return c;
90918
- let p = polyPerimeter(poly, options);
90919
- c.r = (p / (2 * Math.PI)) / 111139;
90920
- return c;
90921
- }
90922
- exports.polyToPolsbyPopperCircle = polyToPolsbyPopperCircle;
90923
- function makeCircle(points) {
90924
- if (points == null)
90925
- return null;
90926
- // Clone list to preserve the caller's data, do Durstenfeld shuffle
90927
- let shuffled = points.slice();
90928
- for (let i = points.length - 1; i >= 0; i--) {
90929
- let j = Math.floor(Math.random() * (i + 1));
90930
- j = Math.max(Math.min(j, i), 0);
90931
- const temp = shuffled[i];
90932
- shuffled[i] = shuffled[j];
90933
- shuffled[j] = temp;
90934
- }
90935
- // Progressively add points to circle or recompute circle
90936
- let c = null;
90937
- shuffled.forEach((p, i) => {
90938
- if (c === null || !isInCircle(c, p))
90939
- c = makeCircleOnePoint(shuffled.slice(0, i + 1), p);
90940
- });
90941
- return c;
90942
- }
90943
- // One boundary point known
90944
- function makeCircleOnePoint(points, p) {
90945
- let c = new Circle(p.x, p.y, 0);
90946
- points.forEach((q, i) => {
90947
- if (!isInCircle(c, q)) {
90948
- if (c.r == 0)
90949
- c = makeDiameter(p, q);
90959
+ function blockmapToVTDmap(blockMap, stateMap) {
90960
+ let res = {
90961
+ inBlockMap: blockMap,
90962
+ inStateMap: stateMap,
90963
+ outValid: true,
90964
+ outState: null,
90965
+ outMap: {},
90966
+ outOrder: {},
90967
+ outDistrictToSplit: {}
90968
+ };
90969
+ let bmGather = {};
90970
+ let revMap = {};
90971
+ let id;
90972
+ if (stateMap)
90973
+ for (id in stateMap)
90974
+ if (stateMap.hasOwnProperty(id))
90975
+ revMap[stateMap[id]] = null;
90976
+ // First aggregate into features across all the blocks
90977
+ for (id in blockMap)
90978
+ if (blockMap.hasOwnProperty(id)) {
90979
+ let state = geoidToState(id);
90980
+ if (res.outState == null)
90981
+ res.outState = state;
90982
+ else if (res.outState !== state) {
90983
+ res.outValid = false;
90984
+ break;
90985
+ }
90986
+ let districtID = canonicalDistrictID(blockMap[id]);
90987
+ // Just ignore ZZZ (water) blocks
90988
+ if (districtID === 'ZZZ')
90989
+ continue;
90990
+ let n = id.length;
90991
+ let geoid;
90992
+ // Simple test for block id (vs. voting district or block group) id
90993
+ if (n >= 15) {
90994
+ if (stateMap && stateMap[id] !== undefined)
90995
+ geoid = stateMap[id];
90996
+ else {
90997
+ geoid = id.substr(0, 12); // heuristic for mapping blockID to blockgroupID
90998
+ if (revMap[geoid] === undefined) {
90999
+ res.outValid = false;
91000
+ break;
91001
+ }
91002
+ }
91003
+ }
90950
91004
  else
90951
- c = makeCircleTwoPoints(points.slice(0, i + 1), p, q);
91005
+ geoid = id;
91006
+ if (res.outOrder[districtID] === undefined)
91007
+ res.outOrder[districtID] = 0;
91008
+ let districtToBlocks = bmGather[geoid];
91009
+ if (districtToBlocks === undefined)
91010
+ bmGather[geoid] = { [districtID]: { [id]: true } };
91011
+ else {
91012
+ let thisDistrict = districtToBlocks[districtID];
91013
+ if (thisDistrict === undefined) {
91014
+ thisDistrict = {};
91015
+ districtToBlocks[districtID] = thisDistrict;
91016
+ }
91017
+ thisDistrict[id] = true;
91018
+ }
90952
91019
  }
90953
- });
90954
- return c;
90955
- }
90956
- // Two boundary points known
90957
- function makeCircleTwoPoints(points, p, q) {
90958
- const circ = makeDiameter(p, q);
90959
- let left = null;
90960
- let right = null;
90961
- // For each point not in the two-point circle
90962
- for (const r of points) {
90963
- if (isInCircle(circ, r))
90964
- continue;
90965
- // Form a circumcircle and classify it on left or right side
90966
- const cross = crossProduct(p.x, p.y, q.x, q.y, r.x, r.y);
90967
- const c = makeCircumcircle(p, q, r);
90968
- if (c === null)
90969
- continue;
90970
- else if (cross > 0 && (left === null || crossProduct(p.x, p.y, q.x, q.y, c.x, c.y) > crossProduct(p.x, p.y, q.x, q.y, left.x, left.y)))
90971
- left = c;
90972
- else if (cross < 0 && (right === null || crossProduct(p.x, p.y, q.x, q.y, c.x, c.y) < crossProduct(p.x, p.y, q.x, q.y, right.x, right.y)))
90973
- right = c;
90974
- }
90975
- // Select which circle to return
90976
- if (left === null && right === null)
90977
- return circ;
90978
- else if (left === null && right !== null)
90979
- return right;
90980
- else if (left !== null && right === null)
90981
- return left;
90982
- else if (left !== null && right !== null)
90983
- return left.r <= right.r ? left : right;
90984
- else
90985
- throw "Assertion error";
90986
- }
90987
- function makeDiameter(a, b) {
90988
- const cx = (a.x + b.x) / 2;
90989
- const cy = (a.y + b.y) / 2;
90990
- const r0 = Util.distance(cx, cy, a.x, a.y);
90991
- const r1 = Util.distance(cx, cy, b.x, b.y);
90992
- return new Circle(cx, cy, Math.max(r0, r1));
91020
+ // Now determine actual mapping of blocks to features, looking for split features
91021
+ for (let geoid in bmGather)
91022
+ if (bmGather.hasOwnProperty(geoid)) {
91023
+ let districtToBlocks = bmGather[geoid];
91024
+ if (Util.countKeys(districtToBlocks) == 1) {
91025
+ res.outMap[geoid] = Util.nthKey(districtToBlocks);
91026
+ }
91027
+ else {
91028
+ for (let districtID in districtToBlocks)
91029
+ if (districtToBlocks.hasOwnProperty(districtID)) {
91030
+ let split = { state: '', datasource: '', geoid: geoid, blocks: Object.keys(districtToBlocks[districtID]) };
91031
+ let splits = res.outDistrictToSplit[districtID];
91032
+ if (splits === undefined) {
91033
+ splits = [];
91034
+ res.outDistrictToSplit[districtID] = splits;
91035
+ }
91036
+ splits.push(split);
91037
+ }
91038
+ }
91039
+ }
91040
+ res.outOrder = canonicalDistrictIDOrdering(res.outOrder);
91041
+ return res;
90993
91042
  }
90994
- function makeCircumcircle(a, b, c) {
90995
- // Mathematical algorithm from Wikipedia: Circumscribed circle
90996
- const ox = (Math.min(a.x, b.x, c.x) + Math.max(a.x, b.x, c.x)) / 2;
90997
- const oy = (Math.min(a.y, b.y, c.y) + Math.max(a.y, b.y, c.y)) / 2;
90998
- const ax = a.x - ox;
90999
- const ay = a.y - oy;
91000
- const bx = b.x - ox;
91001
- const by = b.y - oy;
91002
- const cx = c.x - ox;
91003
- const cy = c.y - oy;
91004
- const d = (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by)) * 2;
91005
- if (d == 0)
91043
+ exports.blockmapToVTDmap = blockmapToVTDmap;
91044
+ exports.GEOIDToState = {
91045
+ '01': 'AL',
91046
+ '02': 'AK',
91047
+ '04': 'AZ',
91048
+ '05': 'AR',
91049
+ '06': 'CA',
91050
+ '08': 'CO',
91051
+ '09': 'CT',
91052
+ '10': 'DE',
91053
+ '12': 'FL',
91054
+ '13': 'GA',
91055
+ '15': 'HI',
91056
+ '16': 'ID',
91057
+ '17': 'IL',
91058
+ '18': 'IN',
91059
+ '19': 'IA',
91060
+ '20': 'KS',
91061
+ '21': 'KY',
91062
+ '22': 'LA',
91063
+ '23': 'ME',
91064
+ '24': 'MD',
91065
+ '25': 'MA',
91066
+ '26': 'MI',
91067
+ '27': 'MN',
91068
+ '28': 'MS',
91069
+ '29': 'MO',
91070
+ '30': 'MT',
91071
+ '31': 'NE',
91072
+ '32': 'NV',
91073
+ '33': 'NH',
91074
+ '34': 'NJ',
91075
+ '35': 'NM',
91076
+ '36': 'NY',
91077
+ '37': 'NC',
91078
+ '38': 'ND',
91079
+ '39': 'OH',
91080
+ '40': 'OK',
91081
+ '41': 'OR',
91082
+ '42': 'PA',
91083
+ '44': 'RI',
91084
+ '45': 'SC',
91085
+ '46': 'SD',
91086
+ '47': 'TN',
91087
+ '48': 'TX',
91088
+ '49': 'UT',
91089
+ '50': 'VT',
91090
+ '51': 'VA',
91091
+ '53': 'WA',
91092
+ '54': 'WV',
91093
+ '55': 'WI',
91094
+ '56': 'WY',
91095
+ };
91096
+ exports.StateToGEOID = {
91097
+ 'AL': '01',
91098
+ 'AK': '02',
91099
+ 'AZ': '04',
91100
+ 'AR': '05',
91101
+ 'CA': '06',
91102
+ 'CO': '08',
91103
+ 'CT': '09',
91104
+ 'DE': '10',
91105
+ 'FL': '12',
91106
+ 'GA': '13',
91107
+ 'HI': '15',
91108
+ 'ID': '16',
91109
+ 'IL': '17',
91110
+ 'IN': '18',
91111
+ 'IA': '19',
91112
+ 'KS': '20',
91113
+ 'KY': '21',
91114
+ 'LA': '22',
91115
+ 'ME': '23',
91116
+ 'MD': '24',
91117
+ 'MA': '25',
91118
+ 'MI': '26',
91119
+ 'MN': '27',
91120
+ 'MS': '28',
91121
+ 'MO': '29',
91122
+ 'MT': '30',
91123
+ 'NE': '31',
91124
+ 'NV': '32',
91125
+ 'NH': '33',
91126
+ 'NJ': '34',
91127
+ 'NM': '35',
91128
+ 'NY': '36',
91129
+ 'NC': '37',
91130
+ 'ND': '38',
91131
+ 'OH': '39',
91132
+ 'OK': '40',
91133
+ 'OR': '41',
91134
+ 'PA': '42',
91135
+ 'RI': '44',
91136
+ 'SC': '45',
91137
+ 'SD': '46',
91138
+ 'TN': '47',
91139
+ 'TX': '48',
91140
+ 'UT': '49',
91141
+ 'VT': '50',
91142
+ 'VA': '51',
91143
+ 'WA': '53',
91144
+ 'WV': '54',
91145
+ 'WI': '55',
91146
+ 'WY': '56',
91147
+ };
91148
+ function geoidToState(geoid) {
91149
+ let re = /^(..).*$/;
91150
+ let a = re.exec(geoid);
91151
+ if (a == null || a.length != 2)
91006
91152
  return null;
91007
- const x = ox + ((ax * ax + ay * ay) * (by - cy) + (bx * bx + by * by) * (cy - ay) + (cx * cx + cy * cy) * (ay - by)) / d;
91008
- const y = oy + ((ax * ax + ay * ay) * (cx - bx) + (bx * bx + by * by) * (ax - cx) + (cx * cx + cy * cy) * (bx - ax)) / d;
91009
- const ra = Util.distance(x, y, a.x, a.y);
91010
- const rb = Util.distance(x, y, b.x, b.y);
91011
- const rc = Util.distance(x, y, c.x, c.y);
91012
- return new Circle(x, y, Math.max(ra, rb, rc));
91013
- }
91014
- /* Simple mathematical functions */
91015
- const MULTIPLICATIVE_EPSILON = 1 + 1e-14;
91016
- function isInCircle(c, p) {
91017
- return c !== null && Util.distance(p.x, p.y, c.x, c.y) <= c.r * MULTIPLICATIVE_EPSILON;
91153
+ return exports.GEOIDToState[a[1]];
91018
91154
  }
91019
- // Returns twice the signed area of the triangle defined by (x0, y0), (x1, y1), (x2, y2).
91020
- function crossProduct(x0, y0, x1, y1, x2, y2) {
91021
- return (x1 - x0) * (y2 - y0) - (y1 - y0) * (x2 - x0);
91155
+ exports.geoidToState = geoidToState;
91156
+
91157
+
91158
+ /***/ }),
91159
+
91160
+ /***/ "@dra2020/util":
91161
+ /*!********************************!*\
91162
+ !*** external "@dra2020/util" ***!
91163
+ \********************************/
91164
+ /*! no static exports found */
91165
+ /***/ (function(module, exports) {
91166
+
91167
+ module.exports = __webpack_require__(/*! @dra2020/util */ "./node_modules/@dra2020/dra-types/node_modules/@dra2020/util/dist/util.js");
91168
+
91169
+ /***/ }),
91170
+
91171
+ /***/ "object-hash":
91172
+ /*!******************************!*\
91173
+ !*** external "object-hash" ***!
91174
+ \******************************/
91175
+ /*! no static exports found */
91176
+ /***/ (function(module, exports) {
91177
+
91178
+ module.exports = __webpack_require__(/*! object-hash */ "./node_modules/@dra2020/dra-types/node_modules/object-hash/index.js");
91179
+
91180
+ /***/ })
91181
+
91182
+ /******/ });
91183
+ });
91184
+
91185
+
91186
+ /***/ }),
91187
+
91188
+ /***/ "./node_modules/@dra2020/dra-types/node_modules/@dra2020/util/dist/util.js":
91189
+ /*!*********************************************************************************!*\
91190
+ !*** ./node_modules/@dra2020/dra-types/node_modules/@dra2020/util/dist/util.js ***!
91191
+ \*********************************************************************************/
91192
+ /*! no static exports found */
91193
+ /***/ (function(module, exports, __webpack_require__) {
91194
+
91195
+ (function webpackUniversalModuleDefinition(root, factory) {
91196
+ if(true)
91197
+ module.exports = factory();
91198
+ else {}
91199
+ })(global, function() {
91200
+ return /******/ (function(modules) { // webpackBootstrap
91201
+ /******/ // The module cache
91202
+ /******/ var installedModules = {};
91203
+ /******/
91204
+ /******/ // The require function
91205
+ /******/ function __webpack_require__(moduleId) {
91206
+ /******/
91207
+ /******/ // Check if module is in cache
91208
+ /******/ if(installedModules[moduleId]) {
91209
+ /******/ return installedModules[moduleId].exports;
91210
+ /******/ }
91211
+ /******/ // Create a new module (and put it into the cache)
91212
+ /******/ var module = installedModules[moduleId] = {
91213
+ /******/ i: moduleId,
91214
+ /******/ l: false,
91215
+ /******/ exports: {}
91216
+ /******/ };
91217
+ /******/
91218
+ /******/ // Execute the module function
91219
+ /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
91220
+ /******/
91221
+ /******/ // Flag the module as loaded
91222
+ /******/ module.l = true;
91223
+ /******/
91224
+ /******/ // Return the exports of the module
91225
+ /******/ return module.exports;
91226
+ /******/ }
91227
+ /******/
91228
+ /******/
91229
+ /******/ // expose the modules object (__webpack_modules__)
91230
+ /******/ __webpack_require__.m = modules;
91231
+ /******/
91232
+ /******/ // expose the module cache
91233
+ /******/ __webpack_require__.c = installedModules;
91234
+ /******/
91235
+ /******/ // define getter function for harmony exports
91236
+ /******/ __webpack_require__.d = function(exports, name, getter) {
91237
+ /******/ if(!__webpack_require__.o(exports, name)) {
91238
+ /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
91239
+ /******/ }
91240
+ /******/ };
91241
+ /******/
91242
+ /******/ // define __esModule on exports
91243
+ /******/ __webpack_require__.r = function(exports) {
91244
+ /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
91245
+ /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
91246
+ /******/ }
91247
+ /******/ Object.defineProperty(exports, '__esModule', { value: true });
91248
+ /******/ };
91249
+ /******/
91250
+ /******/ // create a fake namespace object
91251
+ /******/ // mode & 1: value is a module id, require it
91252
+ /******/ // mode & 2: merge all properties of value into the ns
91253
+ /******/ // mode & 4: return value when already ns object
91254
+ /******/ // mode & 8|1: behave like require
91255
+ /******/ __webpack_require__.t = function(value, mode) {
91256
+ /******/ if(mode & 1) value = __webpack_require__(value);
91257
+ /******/ if(mode & 8) return value;
91258
+ /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
91259
+ /******/ var ns = Object.create(null);
91260
+ /******/ __webpack_require__.r(ns);
91261
+ /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
91262
+ /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
91263
+ /******/ return ns;
91264
+ /******/ };
91265
+ /******/
91266
+ /******/ // getDefaultExport function for compatibility with non-harmony modules
91267
+ /******/ __webpack_require__.n = function(module) {
91268
+ /******/ var getter = module && module.__esModule ?
91269
+ /******/ function getDefault() { return module['default']; } :
91270
+ /******/ function getModuleExports() { return module; };
91271
+ /******/ __webpack_require__.d(getter, 'a', getter);
91272
+ /******/ return getter;
91273
+ /******/ };
91274
+ /******/
91275
+ /******/ // Object.prototype.hasOwnProperty.call
91276
+ /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
91277
+ /******/
91278
+ /******/ // __webpack_public_path__
91279
+ /******/ __webpack_require__.p = "";
91280
+ /******/
91281
+ /******/
91282
+ /******/ // Load entry module and return exports
91283
+ /******/ return __webpack_require__(__webpack_require__.s = "./lib/all.ts");
91284
+ /******/ })
91285
+ /************************************************************************/
91286
+ /******/ ({
91287
+
91288
+ /***/ "./lib/all.ts":
91289
+ /*!********************!*\
91290
+ !*** ./lib/all.ts ***!
91291
+ \********************/
91292
+ /*! no static exports found */
91293
+ /***/ (function(module, exports, __webpack_require__) {
91294
+
91295
+ "use strict";
91296
+
91297
+ function __export(m) {
91298
+ for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
91022
91299
  }
91023
- // cache x,y circle offsets for one quadrant indexed by number of segments
91024
- let circleOffsets = {};
91025
- function getCircleOffsets(n) {
91026
- if (circleOffsets[n] === undefined) {
91027
- let a = [];
91028
- let incr = (Math.PI / 2) / n;
91029
- let theta = 0;
91030
- let i, j;
91031
- // Compute NE quadrant
91032
- for (i = 0; i < n; i++, theta += incr) {
91033
- a.push(Math.sin(theta));
91034
- a.push(Math.cos(theta));
91035
- }
91036
- // Add top of circle
91037
- a.push(0);
91038
- a.push(1);
91039
- // Now flip X and replicate to NW quadrant
91040
- for (i = 0; i < n; i++) {
91041
- j = (n - i) * 2;
91042
- a.push(-a[j - 1]);
91043
- a.push(a[j - 2]);
91044
- }
91045
- // Now flip X and Y and replicate to SW quadrant
91046
- for (i = 0; i < n; i++) {
91047
- j = (n - i) * 2;
91048
- a.push(-a[j - 1]);
91049
- a.push(-a[j - 2]);
91300
+ Object.defineProperty(exports, "__esModule", { value: true });
91301
+ __export(__webpack_require__(/*! ./util */ "./lib/util.ts"));
91302
+ __export(__webpack_require__(/*! ./countedhash */ "./lib/countedhash.ts"));
91303
+ __export(__webpack_require__(/*! ./indexedarray */ "./lib/indexedarray.ts"));
91304
+
91305
+
91306
+ /***/ }),
91307
+
91308
+ /***/ "./lib/countedhash.ts":
91309
+ /*!****************************!*\
91310
+ !*** ./lib/countedhash.ts ***!
91311
+ \****************************/
91312
+ /*! no static exports found */
91313
+ /***/ (function(module, exports, __webpack_require__) {
91314
+
91315
+ "use strict";
91316
+
91317
+ Object.defineProperty(exports, "__esModule", { value: true });
91318
+ class CountedHash {
91319
+ constructor() {
91320
+ this.n = 0;
91321
+ this.val = {};
91322
+ }
91323
+ get length() { return this.n; }
91324
+ test(id) {
91325
+ return id != '' && this.val[id] !== undefined;
91326
+ }
91327
+ set(id) {
91328
+ if (id != '' && !this.test(id)) {
91329
+ this.n++;
91330
+ this.val[id] = true;
91050
91331
  }
91051
- // Add bottom of circle
91052
- a.push(0);
91053
- a.push(-1);
91054
- // Now flip Y and replicate to SE quadrant
91055
- for (i = 0; i < n; i++) {
91056
- j = (n - i) * 2;
91057
- a.push(a[j - 1]);
91058
- a.push(-a[j - 2]);
91332
+ }
91333
+ clear(id) {
91334
+ if (this.test(id)) {
91335
+ this.n--;
91336
+ delete this.val[id];
91059
91337
  }
91060
- // Duplicate final point per GeoJSON spec
91061
- a.push(a[0]);
91062
- a.push(a[1]);
91063
- circleOffsets[n] = a;
91064
91338
  }
91065
- return circleOffsets[n];
91066
- }
91067
- // Note that this is essentially an inversion of polyToCircle which computes a mathematical
91068
- // circle given the point values, ignoring latitude correction. This inversion also
91069
- // ignores that correction which means when plotted on a 2D map looks circular but the edge of
91070
- // the circle is not a fixed distance (in physical units, e.g. meters) from the center.
91071
- //
91072
- function polyFromCircle(c, nSegments, options) {
91073
- if (options === undefined)
91074
- options = DefaultOptions;
91075
- if (c === null || c.r == 0)
91076
- return null;
91077
- if (!nSegments || nSegments < 8)
91078
- nSegments = 8;
91079
- let poly = [];
91339
+ empty() {
91340
+ this.n = 0;
91341
+ this.val = {};
91342
+ }
91343
+ asArray() {
91344
+ let a = [];
91345
+ this.forEach(id => { a.push(id); });
91346
+ return a;
91347
+ }
91348
+ asString() {
91349
+ for (var id in this.val)
91350
+ if (this.val.hasOwnProperty(id))
91351
+ return id;
91352
+ return '';
91353
+ }
91354
+ forEach(f) {
91355
+ for (var id in this.val)
91356
+ if (this.val.hasOwnProperty(id))
91357
+ f(id);
91358
+ }
91359
+ }
91360
+ exports.CountedHash = CountedHash;
91361
+
91362
+
91363
+ /***/ }),
91364
+
91365
+ /***/ "./lib/indexedarray.ts":
91366
+ /*!*****************************!*\
91367
+ !*** ./lib/indexedarray.ts ***!
91368
+ \*****************************/
91369
+ /*! no static exports found */
91370
+ /***/ (function(module, exports, __webpack_require__) {
91371
+
91372
+ "use strict";
91373
+
91374
+ Object.defineProperty(exports, "__esModule", { value: true });
91375
+ class IndexedArray {
91376
+ constructor() {
91377
+ this.o = {};
91378
+ this.a = null;
91379
+ }
91380
+ ensure() {
91381
+ if (this.a === null) {
91382
+ this.a = [];
91383
+ for (let p in this.o)
91384
+ if (this.o.hasOwnProperty(p))
91385
+ this.a.push(p);
91386
+ this.a.sort((a, b) => { a = a.toUpperCase(); b = b.toUpperCase(); return a < b ? -1 : (a > b ? 1 : 0); });
91387
+ }
91388
+ }
91389
+ asArray() {
91390
+ this.ensure();
91391
+ return this.a;
91392
+ }
91393
+ get length() { this.ensure(); return this.a.length; }
91394
+ test(s) {
91395
+ return !!s && this.o[s] !== undefined;
91396
+ }
91397
+ set(s) {
91398
+ if (!!s && !this.test(s)) {
91399
+ this.o[s] = true;
91400
+ this.a = null;
91401
+ }
91402
+ }
91403
+ setAll(a) {
91404
+ if (a && a.length)
91405
+ for (let i = 0; i < a.length; i++)
91406
+ this.set(a[i]);
91407
+ }
91408
+ clear(s) {
91409
+ if (this.test(s)) {
91410
+ delete this.o[s];
91411
+ this.a = null;
91412
+ }
91413
+ }
91414
+ at(i) {
91415
+ this.ensure();
91416
+ if (i < 0 || i >= this.a.length)
91417
+ return undefined;
91418
+ return this.a[i];
91419
+ }
91420
+ empty() {
91421
+ this.o = {};
91422
+ this.a = null;
91423
+ }
91424
+ forEach(f) {
91425
+ for (var s in this.o)
91426
+ if (this.o.hasOwnProperty(s))
91427
+ f(s);
91428
+ }
91429
+ }
91430
+ exports.IndexedArray = IndexedArray;
91431
+
91432
+
91433
+ /***/ }),
91434
+
91435
+ /***/ "./lib/util.ts":
91436
+ /*!*********************!*\
91437
+ !*** ./lib/util.ts ***!
91438
+ \*********************/
91439
+ /*! no static exports found */
91440
+ /***/ (function(module, exports, __webpack_require__) {
91441
+
91442
+ "use strict";
91443
+
91444
+ Object.defineProperty(exports, "__esModule", { value: true });
91445
+ function Now() { return (new Date()).toJSON(); }
91446
+ exports.Now = Now;
91447
+ class Elapsed {
91448
+ constructor(bStart = true) {
91449
+ this.tStart = undefined;
91450
+ this.tDur = undefined;
91451
+ if (bStart)
91452
+ this.start();
91453
+ }
91454
+ start() {
91455
+ if (process && process.hrtime)
91456
+ this.tStart = process.hrtime();
91457
+ else
91458
+ this.tStart = performance.now();
91459
+ if (this.tDur)
91460
+ this.tDur = undefined;
91461
+ }
91462
+ end() {
91463
+ if (this.tStart === undefined)
91464
+ this.start();
91465
+ if (process && process.hrtime)
91466
+ this.tDur = process.hrtime(this.tStart);
91467
+ else
91468
+ this.tDur = performance.now() - this.tStart;
91469
+ }
91470
+ ms() {
91471
+ if (this.tDur === undefined)
91472
+ this.end();
91473
+ if (process && process.hrtime)
91474
+ return Math.round((this.tDur[0] * 1000) + (this.tDur[1] / 1000000));
91475
+ else
91476
+ return this.tDur;
91477
+ }
91478
+ nano() {
91479
+ if (this.tDur === undefined)
91480
+ this.end();
91481
+ if (process && process.hrtime)
91482
+ return (this.tDur[0] * 1000000000) + this.tDur[1];
91483
+ else
91484
+ return this.tDur * 1000000;
91485
+ }
91486
+ }
91487
+ exports.Elapsed = Elapsed;
91488
+ class Deadline {
91489
+ constructor(msDelta) {
91490
+ this.msDelta = msDelta;
91491
+ this.elapsed = new Elapsed();
91492
+ }
91493
+ done() {
91494
+ this.elapsed.end();
91495
+ return this.elapsed.ms() > this.msDelta;
91496
+ }
91497
+ }
91498
+ exports.Deadline = Deadline;
91499
+ function createGuid() {
91500
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
91501
+ var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
91502
+ return v.toString(16);
91503
+ });
91504
+ }
91505
+ exports.createGuid = createGuid;
91506
+ function _sizeof(a, loops) {
91507
+ if (a === null || a === undefined)
91508
+ return 0;
91509
+ switch (typeof a) {
91510
+ default: return 0;
91511
+ case 'number': return 8;
91512
+ case 'boolean': return 4;
91513
+ case 'string': return a.length * 2;
91514
+ case 'object':
91515
+ {
91516
+ if (loops.has(a))
91517
+ return 0;
91518
+ else
91519
+ loops.set(a, true);
91520
+ let t = 0;
91521
+ if (Array.isArray(a)) {
91522
+ for (let i = 0; i < a.length; i++)
91523
+ t += _sizeof(a[i], loops);
91524
+ t += 8; // length
91525
+ }
91526
+ else if (Buffer.isBuffer(a)) {
91527
+ t = a.length;
91528
+ }
91529
+ else if (a.hasOwnProperty === undefined)
91530
+ return t;
91531
+ else {
91532
+ for (var key in a)
91533
+ if (a.hasOwnProperty && a.hasOwnProperty(key)) {
91534
+ t += _sizeof(key, loops); // this is a good estimate of download size, but poor estimate of internal size
91535
+ // because of JS object templating vs. naive hashtables
91536
+ t += _sizeof(a[key], loops);
91537
+ }
91538
+ }
91539
+ return t;
91540
+ }
91541
+ }
91542
+ }
91543
+ function sizeof(a) {
91544
+ let loops = new WeakMap();
91545
+ let n = _sizeof(a, loops);
91546
+ return n;
91547
+ }
91548
+ exports.sizeof = sizeof;
91549
+ function depthof(a) {
91550
+ if (a === null || a === undefined)
91551
+ return 1;
91552
+ switch (typeof a) {
91553
+ default: return 1;
91554
+ case 'number': return 1;
91555
+ case 'boolean': return 1;
91556
+ case 'string': return 1;
91557
+ case 'object':
91558
+ {
91559
+ let d = 0;
91560
+ if (Array.isArray(a))
91561
+ return a.length > 0 ? (1 + depthof(a[0])) : 2; // still return 2 for empty array
91562
+ else if (Buffer.isBuffer(a))
91563
+ return 2;
91564
+ else if (a.hasOwnProperty === undefined)
91565
+ return 1;
91566
+ else {
91567
+ for (var key in a)
91568
+ if (a.hasOwnProperty(key))
91569
+ return 1 + depthof(a[key]);
91570
+ return 2; // or 2 for empty object
91571
+ }
91572
+ }
91573
+ }
91574
+ }
91575
+ exports.depthof = depthof;
91576
+ function isEmpty(o) {
91577
+ if (o === null || o === undefined)
91578
+ return true;
91579
+ for (var p in o)
91580
+ if (o.hasOwnProperty(p))
91581
+ return false;
91582
+ return true;
91583
+ }
91584
+ exports.isEmpty = isEmpty;
91585
+ function countKeys(o) {
91586
+ if (o === undefined || typeof o !== 'object')
91587
+ return -1;
91588
+ let count = 0;
91589
+ for (let p in o)
91590
+ if (o.hasOwnProperty(p))
91591
+ count++;
91592
+ return count;
91593
+ }
91594
+ exports.countKeys = countKeys;
91595
+ function nthProperty(o, n = 0) {
91596
+ for (let p in o)
91597
+ if (o.hasOwnProperty(p)) {
91598
+ if (n <= 0)
91599
+ return o[p];
91600
+ n--;
91601
+ }
91602
+ return undefined;
91603
+ }
91604
+ exports.nthProperty = nthProperty;
91605
+ function nthKey(o, n = 0) {
91606
+ for (let p in o)
91607
+ if (o.hasOwnProperty(p)) {
91608
+ if (n <= 0)
91609
+ return p;
91610
+ n--;
91611
+ }
91612
+ return undefined;
91613
+ }
91614
+ exports.nthKey = nthKey;
91615
+ function partialEqual(o, subset) {
91616
+ for (let p in subset)
91617
+ if (subset.hasOwnProperty(p))
91618
+ if (o[p] !== subset[p])
91619
+ return false;
91620
+ return true;
91621
+ }
91622
+ exports.partialEqual = partialEqual;
91623
+ function deepEqual(o1, o2, options) {
91624
+ if (typeof o1 !== typeof o2)
91625
+ return false;
91626
+ if (typeof o1 !== 'object')
91627
+ return o1 === o2;
91628
+ // Special case array
91629
+ if (Array.isArray(o1)) {
91630
+ if (!Array.isArray(o2))
91631
+ return false;
91632
+ if (o1.length != o2.length)
91633
+ return false;
91634
+ if (options && options.unorderedArrays) {
91635
+ o1 = o1.sort();
91636
+ o2 = o2.sort();
91637
+ }
91638
+ for (let i = 0; i < o1.length; i++)
91639
+ if (!deepEqual(o1[i], o2[i], options))
91640
+ return false;
91641
+ return true;
91642
+ }
91643
+ // Special case object
91644
+ if (o1.hasOwnProperty === undefined || o2.hasOwnProperty === undefined)
91645
+ return o1 === o2;
91646
+ for (let p in o1)
91647
+ if (o1.hasOwnProperty(p)) {
91648
+ if (options && options.omitKey[p])
91649
+ continue;
91650
+ if (o2[p] === undefined)
91651
+ return false;
91652
+ if (!deepEqual(o1[p], o2[p], options))
91653
+ return false;
91654
+ }
91655
+ // If any properties in o2 aren't in o1, not equal
91656
+ for (let p in o2)
91657
+ if (o2.hasOwnProperty(p)) {
91658
+ if (options && options.omitKey[p])
91659
+ continue;
91660
+ if (o1[p] === undefined)
91661
+ return false;
91662
+ }
91663
+ return true;
91664
+ }
91665
+ exports.deepEqual = deepEqual;
91666
+ const Months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
91667
+ function prettyDate(d) {
91668
+ if (d == null)
91669
+ return 'unknown';
91670
+ let mmm = Months[d.getMonth()];
91671
+ let dd = d.getDate();
91672
+ let yyyy = d.getFullYear();
91673
+ let hh = d.getHours();
91674
+ let m = d.getMinutes();
91675
+ let mm = m < 10 ? `0${m}` : String(m);
91676
+ let ampm = hh >= 12 ? 'PM' : 'AM';
91677
+ if (hh > 12)
91678
+ hh -= 12;
91679
+ return `${mmm} ${dd}, ${yyyy} at ${hh}:${mm} ${ampm}`;
91680
+ }
91681
+ exports.prettyDate = prettyDate;
91682
+ function relativeDate(d) {
91683
+ if (d == null)
91684
+ return 'unknown';
91685
+ let now = new Date();
91686
+ let yyyyNow = now.getFullYear();
91687
+ let mmmNow = Months[now.getMonth()];
91688
+ let ddNow = now.getDate();
91689
+ let mmm = Months[d.getMonth()];
91690
+ let dd = d.getDate();
91691
+ let yyyy = d.getFullYear();
91692
+ let hh = d.getHours();
91693
+ let m = d.getMinutes();
91694
+ let mm = m < 10 ? `0${m}` : String(m);
91695
+ let ampm = hh >= 12 ? 'PM' : 'AM';
91696
+ if (hh > 12)
91697
+ hh -= 12;
91698
+ if (yyyyNow === yyyy && mmmNow === mmm && ddNow === dd)
91699
+ return `Today at ${hh}:${mm} ${ampm}`;
91700
+ else if (yyyyNow === yyyy)
91701
+ return `${mmm} ${dd}`;
91702
+ else
91703
+ return `${mmm} ${dd}, ${yyyy}`;
91704
+ }
91705
+ exports.relativeDate = relativeDate;
91706
+ const OneMinute = 1000 * 60;
91707
+ const OneHour = OneMinute * 60;
91708
+ const OneDay = OneHour * 24;
91709
+ function recentDate(d) {
91710
+ if (d == null)
91711
+ return 'u';
91712
+ let now = new Date();
91713
+ let msNow = now.getTime();
91714
+ let msThen = d.getTime();
91715
+ let msDelta = msNow - msThen;
91716
+ // Within the hour, display in minutes
91717
+ if (msDelta < OneHour)
91718
+ return `${Math.round(msDelta / OneMinute) + 1}m`;
91719
+ // Within the day, display in hours
91720
+ else if (msDelta < OneDay)
91721
+ return `${Math.round(msDelta / OneHour) + 1}h`;
91722
+ // Otherwise, display using relativeDate
91723
+ else
91724
+ return relativeDate(d);
91725
+ }
91726
+ exports.recentDate = recentDate;
91727
+ function textToHtml(sText) {
91728
+ let lines = sText.split('\n');
91729
+ let aHtml = [];
91730
+ let inTable = false;
91731
+ aHtml.push('<body>');
91732
+ for (let i = 0; i < lines.length; i++) {
91733
+ let line = lines[i];
91734
+ let isRow = line.indexOf('|') === 0;
91735
+ if (inTable && !isRow) {
91736
+ aHtml.push('</tbody></table>');
91737
+ inTable = false;
91738
+ }
91739
+ if (isRow && !inTable) {
91740
+ inTable = true;
91741
+ aHtml.push('<table border="1" cellspacing="0" cellpadding="2"><tbody>');
91742
+ }
91743
+ if (isRow) {
91744
+ let cells = line.split('|');
91745
+ if (cells.length > 2) {
91746
+ aHtml.push('<tr>');
91747
+ for (let j = 1; j < cells.length - 1; j++)
91748
+ aHtml.push(`<td>${cells[j]}</td>`);
91749
+ aHtml.push('</tr>');
91750
+ }
91751
+ }
91752
+ else
91753
+ aHtml.push(`<div>${line}&nbsp;</div>`);
91754
+ }
91755
+ if (inTable)
91756
+ aHtml.push('</tbody></table>');
91757
+ aHtml.push('</body>');
91758
+ return aHtml.join('');
91759
+ }
91760
+ exports.textToHtml = textToHtml;
91761
+ function shallowCopy(src) {
91762
+ if (src === null || src === undefined)
91763
+ return src;
91764
+ switch (typeof src) {
91765
+ case 'boolean':
91766
+ case 'number':
91767
+ case 'string':
91768
+ case 'symbol':
91769
+ case 'function':
91770
+ default:
91771
+ return src;
91772
+ case 'object':
91773
+ if (Array.isArray(src))
91774
+ return src.slice();
91775
+ else {
91776
+ let copy = {};
91777
+ for (var p in src)
91778
+ if (src.hasOwnProperty(p))
91779
+ copy[p] = src[p];
91780
+ return copy;
91781
+ }
91782
+ }
91783
+ }
91784
+ exports.shallowCopy = shallowCopy;
91785
+ function shallowAssign(o1, o2) {
91786
+ if (o1 === null || o1 === undefined)
91787
+ o1 = {};
91788
+ if (o2 === null || o2 === undefined)
91789
+ return o1;
91790
+ if (typeof o2 !== 'object' || typeof o1 !== 'object')
91791
+ return o1;
91792
+ for (var p in o2)
91793
+ if (o2.hasOwnProperty(p))
91794
+ o1[p] = o2[p];
91795
+ return o1;
91796
+ }
91797
+ exports.shallowAssign = shallowAssign;
91798
+ function shallowDelete(o1, o2) {
91799
+ if (o1 == null || o2 == null)
91800
+ return o1;
91801
+ if (typeof o2 !== 'object' || typeof o1 !== 'object')
91802
+ return o1;
91803
+ for (var p in o2)
91804
+ if (o2.hasOwnProperty(p))
91805
+ delete o1[p];
91806
+ return o1;
91807
+ }
91808
+ exports.shallowDelete = shallowDelete;
91809
+ function shallowAssignImmutable(o1, o2) {
91810
+ if (o1 === null || o1 === undefined)
91811
+ o1 = {};
91812
+ if (o2 === null || o2 === undefined)
91813
+ return o1;
91814
+ if (typeof o2 !== 'object' || typeof o1 !== 'object')
91815
+ return o1;
91816
+ // First determine whether o2 changes any properties, if it has, make new instance
91817
+ let oNew = o1;
91818
+ for (let p in o2)
91819
+ if (o2.hasOwnProperty(p)) {
91820
+ if (o1[p] != o2[p]) {
91821
+ oNew = shallowCopy(o1);
91822
+ break;
91823
+ }
91824
+ }
91825
+ if (oNew !== o1)
91826
+ shallowAssign(oNew, o2);
91827
+ return oNew;
91828
+ }
91829
+ exports.shallowAssignImmutable = shallowAssignImmutable;
91830
+ function shallowEqual(o1, o2) {
91831
+ if (o1 === undefined || o2 === undefined || typeof o1 !== 'object' || typeof o2 !== 'object')
91832
+ return o1 === o2;
91833
+ if (Array.isArray(o1) && Array.isArray(o2)) {
91834
+ if (o1.length != o2.length)
91835
+ return false;
91836
+ for (let i = 0; i < o1.length; i++)
91837
+ if (o1[i] !== o2[i])
91838
+ return false;
91839
+ return true;
91840
+ }
91841
+ else {
91842
+ let p;
91843
+ for (p in o1)
91844
+ if (o1.hasOwnProperty(p))
91845
+ if (o1[p] !== o2[p])
91846
+ return false;
91847
+ for (p in o2)
91848
+ if (o2.hasOwnProperty(p))
91849
+ if (o1[p] === undefined)
91850
+ return false;
91851
+ return true;
91852
+ }
91853
+ }
91854
+ exports.shallowEqual = shallowEqual;
91855
+ function deepCopy(src) {
91856
+ // Beware typeof oddities
91857
+ if (src === null || src === undefined)
91858
+ return src;
91859
+ if (typeof src === 'object') {
91860
+ if (Array.isArray(src)) {
91861
+ let dst = [];
91862
+ for (let i = 0; i < src.length; i++)
91863
+ dst.push(deepCopy(src[i]));
91864
+ return dst;
91865
+ }
91866
+ else {
91867
+ if (src.hasOwnProperty === undefined)
91868
+ return src;
91869
+ let dst = {};
91870
+ for (var p in src)
91871
+ if (src.hasOwnProperty(p))
91872
+ dst[p] = deepCopy(src[p]);
91873
+ return dst;
91874
+ }
91875
+ }
91876
+ else
91877
+ return src;
91878
+ }
91879
+ exports.deepCopy = deepCopy;
91880
+ function deepAccum(accum, o) {
91881
+ if (accum == null)
91882
+ accum = {};
91883
+ if (o == null)
91884
+ return accum;
91885
+ for (let p in o)
91886
+ if (o.hasOwnProperty(p)) {
91887
+ let vs = o[p];
91888
+ let vd = accum[p];
91889
+ if (typeof vs === 'number') {
91890
+ if (vd !== undefined && typeof vd !== 'number')
91891
+ throw 'deepAccum: unexpected type mismatch';
91892
+ accum[p] = (vd === undefined ? 0 : vd) + vs;
91893
+ }
91894
+ else if (typeof vs === 'object') {
91895
+ if (vd === undefined) {
91896
+ vd = {};
91897
+ accum[p] = vd;
91898
+ }
91899
+ else if (typeof vd !== 'object')
91900
+ throw 'deepAccum: unexpected type mismatch';
91901
+ deepAccum(vd, vs);
91902
+ }
91903
+ }
91904
+ }
91905
+ exports.deepAccum = deepAccum;
91906
+ function precisionRound(n, p) {
91907
+ let f = Math.pow(10, p);
91908
+ return Math.round(n * f) / f;
91909
+ }
91910
+ exports.precisionRound = precisionRound;
91911
+ function percentString(num, den, precision = 0) {
91912
+ if (den == 0)
91913
+ return '(-)';
91914
+ let p = precisionRound((num / den) * 100, precision);
91915
+ return String(p) + '%';
91916
+ }
91917
+ exports.percentString = percentString;
91918
+ function hash(s) {
91919
+ let hash = 5381;
91920
+ let i = s.length;
91921
+ while (i)
91922
+ hash = (hash * 33) ^ s.charCodeAt(--i);
91923
+ /* JavaScript does bitwise operations (like XOR, above) on 32-bit signed
91924
+ * integers. Since we want the results to be always positive, convert the
91925
+ * signed int to an unsigned by doing an unsigned bitshift. */
91926
+ return hash >>> 0;
91927
+ }
91928
+ exports.hash = hash;
91929
+ function hashObject(o) {
91930
+ return hash(o ? JSON.stringify(o) : '');
91931
+ }
91932
+ exports.hashObject = hashObject;
91933
+ const HexTable = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
91934
+ function toHex(n) {
91935
+ if (n < 0 || n > 255)
91936
+ throw ('only 0 to 255 supported now');
91937
+ n = Math.floor(n);
91938
+ return HexTable[n >> 4] + HexTable[n & 15];
91939
+ }
91940
+ exports.toHex = toHex;
91941
+ function toRGBA(color, alpha) {
91942
+ let r;
91943
+ let g;
91944
+ let b;
91945
+ switch (color) {
91946
+ case 'white':
91947
+ r = 255;
91948
+ g = 255;
91949
+ b = 255;
91950
+ break;
91951
+ case 'black':
91952
+ r = 0;
91953
+ g = 0;
91954
+ b = 0;
91955
+ break;
91956
+ default:
91957
+ r = parseInt(color.substr(1, 2), 16);
91958
+ g = parseInt(color.substr(3, 2), 16);
91959
+ b = parseInt(color.substr(5, 2), 16);
91960
+ break;
91961
+ }
91962
+ return `rgba(${String(r)}, ${String(g)}, ${String(b)}, ${String(alpha)})`;
91963
+ }
91964
+ exports.toRGBA = toRGBA;
91965
+ function toRGBAIntensity(color, intensity, alpha) {
91966
+ // for now assume color is black
91967
+ let g = precisionRound(255 * intensity, 0);
91968
+ return `rgba(${String(g)}, ${String(g)}, ${String(g)}, ${String(alpha)})`;
91969
+ }
91970
+ exports.toRGBAIntensity = toRGBAIntensity;
91971
+ // Geo functions
91972
+ function distance(x0, y0, x1, y1) {
91973
+ return Math.hypot(x0 - x1, y0 - y1);
91974
+ }
91975
+ exports.distance = distance;
91976
+ function deg2rad(num) { return num * Math.PI / 180; }
91977
+ exports.deg2rad = deg2rad;
91978
+ function rad2deg(num) { return num / Math.PI * 180; }
91979
+ exports.rad2deg = rad2deg;
91980
+ // Restricts lon to range [-180..180]
91981
+ function wrapLon(lon) {
91982
+ let worlds = Math.floor((lon + 180) / 360);
91983
+ return lon - (worlds * 360);
91984
+ }
91985
+ exports.wrapLon = wrapLon;
91986
+
91987
+
91988
+ /***/ })
91989
+
91990
+ /******/ });
91991
+ });
91992
+
91993
+
91994
+ /***/ }),
91995
+
91996
+ /***/ "./node_modules/@dra2020/dra-types/node_modules/object-hash/index.js":
91997
+ /*!***************************************************************************!*\
91998
+ !*** ./node_modules/@dra2020/dra-types/node_modules/object-hash/index.js ***!
91999
+ \***************************************************************************/
92000
+ /*! no static exports found */
92001
+ /***/ (function(module, exports, __webpack_require__) {
92002
+
92003
+ "use strict";
92004
+
92005
+
92006
+ var crypto = __webpack_require__(/*! crypto */ "crypto");
92007
+
92008
+ /**
92009
+ * Exported function
92010
+ *
92011
+ * Options:
92012
+ *
92013
+ * - `algorithm` hash algo to be used by this instance: *'sha1', 'md5'
92014
+ * - `excludeValues` {true|*false} hash object keys, values ignored
92015
+ * - `encoding` hash encoding, supports 'buffer', '*hex', 'binary', 'base64'
92016
+ * - `ignoreUnknown` {true|*false} ignore unknown object types
92017
+ * - `replacer` optional function that replaces values before hashing
92018
+ * - `respectFunctionProperties` {*true|false} consider function properties when hashing
92019
+ * - `respectFunctionNames` {*true|false} consider 'name' property of functions for hashing
92020
+ * - `respectType` {*true|false} Respect special properties (prototype, constructor)
92021
+ * when hashing to distinguish between types
92022
+ * - `unorderedArrays` {true|*false} Sort all arrays before hashing
92023
+ * - `unorderedSets` {*true|false} Sort `Set` and `Map` instances before hashing
92024
+ * * = default
92025
+ *
92026
+ * @param {object} object value to hash
92027
+ * @param {object} options hashing options
92028
+ * @return {string} hash value
92029
+ * @api public
92030
+ */
92031
+ exports = module.exports = objectHash;
92032
+
92033
+ function objectHash(object, options){
92034
+ options = applyDefaults(object, options);
92035
+
92036
+ return hash(object, options);
92037
+ }
92038
+
92039
+ /**
92040
+ * Exported sugar methods
92041
+ *
92042
+ * @param {object} object value to hash
92043
+ * @return {string} hash value
92044
+ * @api public
92045
+ */
92046
+ exports.sha1 = function(object){
92047
+ return objectHash(object);
92048
+ };
92049
+ exports.keys = function(object){
92050
+ return objectHash(object, {excludeValues: true, algorithm: 'sha1', encoding: 'hex'});
92051
+ };
92052
+ exports.MD5 = function(object){
92053
+ return objectHash(object, {algorithm: 'md5', encoding: 'hex'});
92054
+ };
92055
+ exports.keysMD5 = function(object){
92056
+ return objectHash(object, {algorithm: 'md5', encoding: 'hex', excludeValues: true});
92057
+ };
92058
+
92059
+ // Internals
92060
+ var hashes = crypto.getHashes ? crypto.getHashes().slice() : ['sha1', 'md5'];
92061
+ hashes.push('passthrough');
92062
+ var encodings = ['buffer', 'hex', 'binary', 'base64'];
92063
+
92064
+ function applyDefaults(object, sourceOptions){
92065
+ sourceOptions = sourceOptions || {};
92066
+
92067
+ // create a copy rather than mutating
92068
+ var options = {};
92069
+ options.algorithm = sourceOptions.algorithm || 'sha1';
92070
+ options.encoding = sourceOptions.encoding || 'hex';
92071
+ options.excludeValues = sourceOptions.excludeValues ? true : false;
92072
+ options.algorithm = options.algorithm.toLowerCase();
92073
+ options.encoding = options.encoding.toLowerCase();
92074
+ options.ignoreUnknown = sourceOptions.ignoreUnknown !== true ? false : true; // default to false
92075
+ options.respectType = sourceOptions.respectType === false ? false : true; // default to true
92076
+ options.respectFunctionNames = sourceOptions.respectFunctionNames === false ? false : true;
92077
+ options.respectFunctionProperties = sourceOptions.respectFunctionProperties === false ? false : true;
92078
+ options.unorderedArrays = sourceOptions.unorderedArrays !== true ? false : true; // default to false
92079
+ options.unorderedSets = sourceOptions.unorderedSets === false ? false : true; // default to false
92080
+ options.unorderedObjects = sourceOptions.unorderedObjects === false ? false : true; // default to true
92081
+ options.replacer = sourceOptions.replacer || undefined;
92082
+ options.excludeKeys = sourceOptions.excludeKeys || undefined;
92083
+
92084
+ if(typeof object === 'undefined') {
92085
+ throw new Error('Object argument required.');
92086
+ }
92087
+
92088
+ // if there is a case-insensitive match in the hashes list, accept it
92089
+ // (i.e. SHA256 for sha256)
92090
+ for (var i = 0; i < hashes.length; ++i) {
92091
+ if (hashes[i].toLowerCase() === options.algorithm.toLowerCase()) {
92092
+ options.algorithm = hashes[i];
92093
+ }
92094
+ }
92095
+
92096
+ if(hashes.indexOf(options.algorithm) === -1){
92097
+ throw new Error('Algorithm "' + options.algorithm + '" not supported. ' +
92098
+ 'supported values: ' + hashes.join(', '));
92099
+ }
92100
+
92101
+ if(encodings.indexOf(options.encoding) === -1 &&
92102
+ options.algorithm !== 'passthrough'){
92103
+ throw new Error('Encoding "' + options.encoding + '" not supported. ' +
92104
+ 'supported values: ' + encodings.join(', '));
92105
+ }
92106
+
92107
+ return options;
92108
+ }
92109
+
92110
+ /** Check if the given function is a native function */
92111
+ function isNativeFunction(f) {
92112
+ if ((typeof f) !== 'function') {
92113
+ return false;
92114
+ }
92115
+ var exp = /^function\s+\w*\s*\(\s*\)\s*{\s+\[native code\]\s+}$/i;
92116
+ return exp.exec(Function.prototype.toString.call(f)) != null;
92117
+ }
92118
+
92119
+ function hash(object, options) {
92120
+ var hashingStream;
92121
+
92122
+ if (options.algorithm !== 'passthrough') {
92123
+ hashingStream = crypto.createHash(options.algorithm);
92124
+ } else {
92125
+ hashingStream = new PassThrough();
92126
+ }
92127
+
92128
+ if (typeof hashingStream.write === 'undefined') {
92129
+ hashingStream.write = hashingStream.update;
92130
+ hashingStream.end = hashingStream.update;
92131
+ }
92132
+
92133
+ var hasher = typeHasher(options, hashingStream);
92134
+ hasher.dispatch(object);
92135
+ if (!hashingStream.update) {
92136
+ hashingStream.end('');
92137
+ }
92138
+
92139
+ if (hashingStream.digest) {
92140
+ return hashingStream.digest(options.encoding === 'buffer' ? undefined : options.encoding);
92141
+ }
92142
+
92143
+ var buf = hashingStream.read();
92144
+ if (options.encoding === 'buffer') {
92145
+ return buf;
92146
+ }
92147
+
92148
+ return buf.toString(options.encoding);
92149
+ }
92150
+
92151
+ /**
92152
+ * Expose streaming API
92153
+ *
92154
+ * @param {object} object Value to serialize
92155
+ * @param {object} options Options, as for hash()
92156
+ * @param {object} stream A stream to write the serializiation to
92157
+ * @api public
92158
+ */
92159
+ exports.writeToStream = function(object, options, stream) {
92160
+ if (typeof stream === 'undefined') {
92161
+ stream = options;
92162
+ options = {};
92163
+ }
92164
+
92165
+ options = applyDefaults(object, options);
92166
+
92167
+ return typeHasher(options, stream).dispatch(object);
92168
+ };
92169
+
92170
+ function typeHasher(options, writeTo, context){
92171
+ context = context || [];
92172
+ var write = function(str) {
92173
+ if (writeTo.update) {
92174
+ return writeTo.update(str, 'utf8');
92175
+ } else {
92176
+ return writeTo.write(str, 'utf8');
92177
+ }
92178
+ };
92179
+
92180
+ return {
92181
+ dispatch: function(value){
92182
+ if (options.replacer) {
92183
+ value = options.replacer(value);
92184
+ }
92185
+
92186
+ var type = typeof value;
92187
+ if (value === null) {
92188
+ type = 'null';
92189
+ }
92190
+
92191
+ //console.log("[DEBUG] Dispatch: ", value, "->", type, " -> ", "_" + type);
92192
+
92193
+ return this['_' + type](value);
92194
+ },
92195
+ _object: function(object) {
92196
+ var pattern = (/\[object (.*)\]/i);
92197
+ var objString = Object.prototype.toString.call(object);
92198
+ var objType = pattern.exec(objString);
92199
+ if (!objType) { // object type did not match [object ...]
92200
+ objType = 'unknown:[' + objString + ']';
92201
+ } else {
92202
+ objType = objType[1]; // take only the class name
92203
+ }
92204
+
92205
+ objType = objType.toLowerCase();
92206
+
92207
+ var objectNumber = null;
92208
+
92209
+ if ((objectNumber = context.indexOf(object)) >= 0) {
92210
+ return this.dispatch('[CIRCULAR:' + objectNumber + ']');
92211
+ } else {
92212
+ context.push(object);
92213
+ }
92214
+
92215
+ if (typeof Buffer !== 'undefined' && Buffer.isBuffer && Buffer.isBuffer(object)) {
92216
+ write('buffer:');
92217
+ return write(object);
92218
+ }
92219
+
92220
+ if(objType !== 'object' && objType !== 'function') {
92221
+ if(this['_' + objType]) {
92222
+ this['_' + objType](object);
92223
+ } else if (options.ignoreUnknown) {
92224
+ return write('[' + objType + ']');
92225
+ } else {
92226
+ throw new Error('Unknown object type "' + objType + '"');
92227
+ }
92228
+ }else{
92229
+ var keys = Object.keys(object);
92230
+ if (options.unorderedObjects) {
92231
+ keys = keys.sort();
92232
+ }
92233
+ // Make sure to incorporate special properties, so
92234
+ // Types with different prototypes will produce
92235
+ // a different hash and objects derived from
92236
+ // different functions (`new Foo`, `new Bar`) will
92237
+ // produce different hashes.
92238
+ // We never do this for native functions since some
92239
+ // seem to break because of that.
92240
+ if (options.respectType !== false && !isNativeFunction(object)) {
92241
+ keys.splice(0, 0, 'prototype', '__proto__', 'constructor');
92242
+ }
92243
+
92244
+ if (options.excludeKeys) {
92245
+ keys = keys.filter(function(key) { return !options.excludeKeys(key); });
92246
+ }
92247
+
92248
+ write('object:' + keys.length + ':');
92249
+ var self = this;
92250
+ return keys.forEach(function(key){
92251
+ self.dispatch(key);
92252
+ write(':');
92253
+ if(!options.excludeValues) {
92254
+ self.dispatch(object[key]);
92255
+ }
92256
+ write(',');
92257
+ });
92258
+ }
92259
+ },
92260
+ _array: function(arr, unordered){
92261
+ unordered = typeof unordered !== 'undefined' ? unordered :
92262
+ options.unorderedArrays !== false; // default to options.unorderedArrays
92263
+
92264
+ var self = this;
92265
+ write('array:' + arr.length + ':');
92266
+ if (!unordered || arr.length <= 1) {
92267
+ return arr.forEach(function(entry) {
92268
+ return self.dispatch(entry);
92269
+ });
92270
+ }
92271
+
92272
+ // the unordered case is a little more complicated:
92273
+ // since there is no canonical ordering on objects,
92274
+ // i.e. {a:1} < {a:2} and {a:1} > {a:2} are both false,
92275
+ // we first serialize each entry using a PassThrough stream
92276
+ // before sorting.
92277
+ // also: we can’t use the same context array for all entries
92278
+ // since the order of hashing should *not* matter. instead,
92279
+ // we keep track of the additions to a copy of the context array
92280
+ // and add all of them to the global context array when we’re done
92281
+ var contextAdditions = [];
92282
+ var entries = arr.map(function(entry) {
92283
+ var strm = new PassThrough();
92284
+ var localContext = context.slice(); // make copy
92285
+ var hasher = typeHasher(options, strm, localContext);
92286
+ hasher.dispatch(entry);
92287
+ // take only what was added to localContext and append it to contextAdditions
92288
+ contextAdditions = contextAdditions.concat(localContext.slice(context.length));
92289
+ return strm.read().toString();
92290
+ });
92291
+ context = context.concat(contextAdditions);
92292
+ entries.sort();
92293
+ return this._array(entries, false);
92294
+ },
92295
+ _date: function(date){
92296
+ return write('date:' + date.toJSON());
92297
+ },
92298
+ _symbol: function(sym){
92299
+ return write('symbol:' + sym.toString());
92300
+ },
92301
+ _error: function(err){
92302
+ return write('error:' + err.toString());
92303
+ },
92304
+ _boolean: function(bool){
92305
+ return write('bool:' + bool.toString());
92306
+ },
92307
+ _string: function(string){
92308
+ write('string:' + string.length + ':');
92309
+ write(string.toString());
92310
+ },
92311
+ _function: function(fn){
92312
+ write('fn:');
92313
+ if (isNativeFunction(fn)) {
92314
+ this.dispatch('[native]');
92315
+ } else {
92316
+ this.dispatch(fn.toString());
92317
+ }
92318
+
92319
+ if (options.respectFunctionNames !== false) {
92320
+ // Make sure we can still distinguish native functions
92321
+ // by their name, otherwise String and Function will
92322
+ // have the same hash
92323
+ this.dispatch("function-name:" + String(fn.name));
92324
+ }
92325
+
92326
+ if (options.respectFunctionProperties) {
92327
+ this._object(fn);
92328
+ }
92329
+ },
92330
+ _number: function(number){
92331
+ return write('number:' + number.toString());
92332
+ },
92333
+ _xml: function(xml){
92334
+ return write('xml:' + xml.toString());
92335
+ },
92336
+ _null: function() {
92337
+ return write('Null');
92338
+ },
92339
+ _undefined: function() {
92340
+ return write('Undefined');
92341
+ },
92342
+ _regexp: function(regex){
92343
+ return write('regex:' + regex.toString());
92344
+ },
92345
+ _uint8array: function(arr){
92346
+ write('uint8array:');
92347
+ return this.dispatch(Array.prototype.slice.call(arr));
92348
+ },
92349
+ _uint8clampedarray: function(arr){
92350
+ write('uint8clampedarray:');
92351
+ return this.dispatch(Array.prototype.slice.call(arr));
92352
+ },
92353
+ _int8array: function(arr){
92354
+ write('uint8array:');
92355
+ return this.dispatch(Array.prototype.slice.call(arr));
92356
+ },
92357
+ _uint16array: function(arr){
92358
+ write('uint16array:');
92359
+ return this.dispatch(Array.prototype.slice.call(arr));
92360
+ },
92361
+ _int16array: function(arr){
92362
+ write('uint16array:');
92363
+ return this.dispatch(Array.prototype.slice.call(arr));
92364
+ },
92365
+ _uint32array: function(arr){
92366
+ write('uint32array:');
92367
+ return this.dispatch(Array.prototype.slice.call(arr));
92368
+ },
92369
+ _int32array: function(arr){
92370
+ write('uint32array:');
92371
+ return this.dispatch(Array.prototype.slice.call(arr));
92372
+ },
92373
+ _float32array: function(arr){
92374
+ write('float32array:');
92375
+ return this.dispatch(Array.prototype.slice.call(arr));
92376
+ },
92377
+ _float64array: function(arr){
92378
+ write('float64array:');
92379
+ return this.dispatch(Array.prototype.slice.call(arr));
92380
+ },
92381
+ _arraybuffer: function(arr){
92382
+ write('arraybuffer:');
92383
+ return this.dispatch(new Uint8Array(arr));
92384
+ },
92385
+ _url: function(url) {
92386
+ return write('url:' + url.toString(), 'utf8');
92387
+ },
92388
+ _map: function(map) {
92389
+ write('map:');
92390
+ var arr = Array.from(map);
92391
+ return this._array(arr, options.unorderedSets !== false);
92392
+ },
92393
+ _set: function(set) {
92394
+ write('set:');
92395
+ var arr = Array.from(set);
92396
+ return this._array(arr, options.unorderedSets !== false);
92397
+ },
92398
+ _blob: function() {
92399
+ if (options.ignoreUnknown) {
92400
+ return write('[blob]');
92401
+ }
92402
+
92403
+ throw Error('Hashing Blob objects is currently not supported\n' +
92404
+ '(see https://github.com/puleos/object-hash/issues/26)\n' +
92405
+ 'Use "options.replacer" or "options.ignoreUnknown"\n');
92406
+ },
92407
+ _domwindow: function() { return write('domwindow'); },
92408
+ /* Node.js standard native objects */
92409
+ _process: function() { return write('process'); },
92410
+ _timer: function() { return write('timer'); },
92411
+ _pipe: function() { return write('pipe'); },
92412
+ _tcp: function() { return write('tcp'); },
92413
+ _udp: function() { return write('udp'); },
92414
+ _tty: function() { return write('tty'); },
92415
+ _statwatcher: function() { return write('statwatcher'); },
92416
+ _securecontext: function() { return write('securecontext'); },
92417
+ _connection: function() { return write('connection'); },
92418
+ _zlib: function() { return write('zlib'); },
92419
+ _context: function() { return write('context'); },
92420
+ _nodescript: function() { return write('nodescript'); },
92421
+ _httpparser: function() { return write('httpparser'); },
92422
+ _dataview: function() { return write('dataview'); },
92423
+ _signal: function() { return write('signal'); },
92424
+ _fsevent: function() { return write('fsevent'); },
92425
+ _tlswrap: function() { return write('tlswrap'); }
92426
+ };
92427
+ }
92428
+
92429
+ // Mini-implementation of stream.PassThrough
92430
+ // We are far from having need for the full implementation, and we can
92431
+ // make assumptions like "many writes, then only one final read"
92432
+ // and we can ignore encoding specifics
92433
+ function PassThrough() {
92434
+ return {
92435
+ buf: '',
92436
+
92437
+ write: function(b) {
92438
+ this.buf += b;
92439
+ },
92440
+
92441
+ end: function(b) {
92442
+ this.buf += b;
92443
+ },
92444
+
92445
+ read: function() {
92446
+ return this.buf;
92447
+ }
92448
+ };
92449
+ }
92450
+
92451
+
92452
+ /***/ }),
92453
+
92454
+ /***/ "./node_modules/@dra2020/poly/dist/poly.js":
92455
+ /*!*************************************************!*\
92456
+ !*** ./node_modules/@dra2020/poly/dist/poly.js ***!
92457
+ \*************************************************/
92458
+ /*! no static exports found */
92459
+ /***/ (function(module, exports, __webpack_require__) {
92460
+
92461
+ (function webpackUniversalModuleDefinition(root, factory) {
92462
+ if(true)
92463
+ module.exports = factory();
92464
+ else {}
92465
+ })(global, function() {
92466
+ return /******/ (function(modules) { // webpackBootstrap
92467
+ /******/ // The module cache
92468
+ /******/ var installedModules = {};
92469
+ /******/
92470
+ /******/ // The require function
92471
+ /******/ function __webpack_require__(moduleId) {
92472
+ /******/
92473
+ /******/ // Check if module is in cache
92474
+ /******/ if(installedModules[moduleId]) {
92475
+ /******/ return installedModules[moduleId].exports;
92476
+ /******/ }
92477
+ /******/ // Create a new module (and put it into the cache)
92478
+ /******/ var module = installedModules[moduleId] = {
92479
+ /******/ i: moduleId,
92480
+ /******/ l: false,
92481
+ /******/ exports: {}
92482
+ /******/ };
92483
+ /******/
92484
+ /******/ // Execute the module function
92485
+ /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
92486
+ /******/
92487
+ /******/ // Flag the module as loaded
92488
+ /******/ module.l = true;
92489
+ /******/
92490
+ /******/ // Return the exports of the module
92491
+ /******/ return module.exports;
92492
+ /******/ }
92493
+ /******/
92494
+ /******/
92495
+ /******/ // expose the modules object (__webpack_modules__)
92496
+ /******/ __webpack_require__.m = modules;
92497
+ /******/
92498
+ /******/ // expose the module cache
92499
+ /******/ __webpack_require__.c = installedModules;
92500
+ /******/
92501
+ /******/ // define getter function for harmony exports
92502
+ /******/ __webpack_require__.d = function(exports, name, getter) {
92503
+ /******/ if(!__webpack_require__.o(exports, name)) {
92504
+ /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
92505
+ /******/ }
92506
+ /******/ };
92507
+ /******/
92508
+ /******/ // define __esModule on exports
92509
+ /******/ __webpack_require__.r = function(exports) {
92510
+ /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
92511
+ /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
92512
+ /******/ }
92513
+ /******/ Object.defineProperty(exports, '__esModule', { value: true });
92514
+ /******/ };
92515
+ /******/
92516
+ /******/ // create a fake namespace object
92517
+ /******/ // mode & 1: value is a module id, require it
92518
+ /******/ // mode & 2: merge all properties of value into the ns
92519
+ /******/ // mode & 4: return value when already ns object
92520
+ /******/ // mode & 8|1: behave like require
92521
+ /******/ __webpack_require__.t = function(value, mode) {
92522
+ /******/ if(mode & 1) value = __webpack_require__(value);
92523
+ /******/ if(mode & 8) return value;
92524
+ /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
92525
+ /******/ var ns = Object.create(null);
92526
+ /******/ __webpack_require__.r(ns);
92527
+ /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
92528
+ /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
92529
+ /******/ return ns;
92530
+ /******/ };
92531
+ /******/
92532
+ /******/ // getDefaultExport function for compatibility with non-harmony modules
92533
+ /******/ __webpack_require__.n = function(module) {
92534
+ /******/ var getter = module && module.__esModule ?
92535
+ /******/ function getDefault() { return module['default']; } :
92536
+ /******/ function getModuleExports() { return module; };
92537
+ /******/ __webpack_require__.d(getter, 'a', getter);
92538
+ /******/ return getter;
92539
+ /******/ };
92540
+ /******/
92541
+ /******/ // Object.prototype.hasOwnProperty.call
92542
+ /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
92543
+ /******/
92544
+ /******/ // __webpack_public_path__
92545
+ /******/ __webpack_require__.p = "";
92546
+ /******/
92547
+ /******/
92548
+ /******/ // Load entry module and return exports
92549
+ /******/ return __webpack_require__(__webpack_require__.s = "./lib/all.ts");
92550
+ /******/ })
92551
+ /************************************************************************/
92552
+ /******/ ({
92553
+
92554
+ /***/ "./lib/all.ts":
92555
+ /*!********************!*\
92556
+ !*** ./lib/all.ts ***!
92557
+ \********************/
92558
+ /*! no static exports found */
92559
+ /***/ (function(module, exports, __webpack_require__) {
92560
+
92561
+ "use strict";
92562
+
92563
+ function __export(m) {
92564
+ for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
92565
+ }
92566
+ Object.defineProperty(exports, "__esModule", { value: true });
92567
+ __export(__webpack_require__(/*! ./poly */ "./lib/poly.ts"));
92568
+ __export(__webpack_require__(/*! ./union */ "./lib/union.ts"));
92569
+
92570
+
92571
+ /***/ }),
92572
+
92573
+ /***/ "./lib/poly.ts":
92574
+ /*!*********************!*\
92575
+ !*** ./lib/poly.ts ***!
92576
+ \*********************/
92577
+ /*! no static exports found */
92578
+ /***/ (function(module, exports, __webpack_require__) {
92579
+
92580
+ "use strict";
92581
+
92582
+ Object.defineProperty(exports, "__esModule", { value: true });
92583
+ const Util = __webpack_require__(/*! @dra2020/util */ "@dra2020/util");
92584
+ // Internal utilities
92585
+ exports.EARTH_RADIUS = 6371000; // Radius of earth in meters
92586
+ const DefaultOptions = {};
92587
+ // Return geographic polygon area in meters^2
92588
+ function polySimpleArea(p, options) {
92589
+ if (options === undefined)
92590
+ options = DefaultOptions;
92591
+ let p1;
92592
+ let p2;
92593
+ let p3;
92594
+ let dx;
92595
+ let l;
92596
+ let m;
92597
+ let u;
92598
+ let i;
92599
+ let total = 0;
92600
+ let n = p.length;
92601
+ if (n > 2) {
92602
+ for (i = 0; i < n; i++) {
92603
+ if (i === n - 2) {
92604
+ l = n - 2;
92605
+ m = n - 1;
92606
+ u = 0;
92607
+ }
92608
+ else if (i === n - 1) {
92609
+ l = n - 1;
92610
+ m = 0;
92611
+ u = 1;
92612
+ }
92613
+ else {
92614
+ l = i;
92615
+ m = i + 1;
92616
+ u = i + 2;
92617
+ }
92618
+ p1 = p[l];
92619
+ p2 = p[m];
92620
+ p3 = p[u];
92621
+ dx = (Util.deg2rad(p3[0]) - Util.deg2rad(p1[0]));
92622
+ dx *= Math.sin(Util.deg2rad(p2[1]));
92623
+ total += dx;
92624
+ }
92625
+ total *= exports.EARTH_RADIUS * exports.EARTH_RADIUS / 2;
92626
+ }
92627
+ return Math.abs(total);
92628
+ }
92629
+ // Allow bare polygon coordinates array or GeoJSON feature.
92630
+ // Normalize to multipolygon points array.
92631
+ function polyNormalize(poly, options) {
92632
+ if (options === undefined)
92633
+ options = DefaultOptions;
92634
+ // Convert a GeoJSON polygon or multipolygon to the raw list of points
92635
+ if (poly && poly.geometry && poly.geometry.coordinates)
92636
+ poly = poly.geometry.coordinates;
92637
+ // This is really an invalid specification but used internally to represent null polygon
92638
+ if (poly && poly.length == 0)
92639
+ return null;
92640
+ if (Util.depthof(poly) == 4)
92641
+ poly = [poly];
92642
+ return poly;
92643
+ }
92644
+ exports.polyNormalize = polyNormalize;
92645
+ // Area of geographic polygon
92646
+ function polyArea(poly, options) {
92647
+ if (options === undefined)
92648
+ options = DefaultOptions;
92649
+ poly = polyNormalize(poly, options);
92650
+ let a = 0;
92651
+ // MultiPolygon is a set of polygons
92652
+ for (let i = 0; poly && i < poly.length; i++) {
92653
+ // Single polygon is exterior ring with interior holes. Holes are subtracted.
92654
+ let p = poly[i];
92655
+ for (let j = 0; j < p.length; j++) {
92656
+ let sp = p[j];
92657
+ a += polySimpleArea(sp, options) * (j == 0 ? 1 : -1);
92658
+ }
92659
+ }
92660
+ return a;
92661
+ }
92662
+ exports.polyArea = polyArea;
92663
+ // Return distance in meters given two lat/lon points
92664
+ function haversine(x1, y1, x2, y2, options) {
92665
+ let dLat = Util.deg2rad(y2 - y1);
92666
+ let dLon = Util.deg2rad(x2 - x1);
92667
+ let c;
92668
+ // Short circuit for using simple cartesian algorithm instead of haversine
92669
+ if (options.noLatitudeCorrection)
92670
+ c = Math.sqrt((dLat * dLat) + (dLon * dLon));
92671
+ else {
92672
+ let lat1 = Util.deg2rad(y1);
92673
+ let lat2 = Util.deg2rad(y2);
92674
+ let a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
92675
+ Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
92676
+ c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
92677
+ }
92678
+ return exports.EARTH_RADIUS * c;
92679
+ }
92680
+ // Perimeter of geographic polygon in meters
92681
+ function polyPerimeter(poly, options) {
92682
+ if (options === undefined)
92683
+ options = DefaultOptions;
92684
+ poly = polyNormalize(poly, options);
92685
+ let perimeter = 0;
92686
+ for (let i = 0; poly && i < poly.length; i++) {
92687
+ // Ignore holes so only look at first polyline
92688
+ let p = poly[i][0];
92689
+ for (let j = 0; j < p.length - 1; j++)
92690
+ perimeter += haversine(p[j][0], p[j][1], p[j + 1][0], p[j + 1][1], options);
92691
+ if (p.length > 2 && (p[0][0] != p[p.length - 1][0] || p[0][1] != p[p.length - 1][1]))
92692
+ perimeter += haversine(p[0][0], p[0][1], p[p.length - 1][0], p[p.length - 1][1], options);
92693
+ }
92694
+ return perimeter;
92695
+ }
92696
+ exports.polyPerimeter = polyPerimeter;
92697
+ class Point {
92698
+ constructor(x, y) {
92699
+ this.x = x;
92700
+ this.y = y;
92701
+ }
92702
+ }
92703
+ class Circle {
92704
+ constructor(x, y, r) {
92705
+ this.x = x;
92706
+ this.y = y;
92707
+ this.r = r;
92708
+ }
92709
+ }
92710
+ exports.Circle = Circle;
92711
+ //
92712
+ // Returns the smallest circle that encloses the given polygon.
92713
+ // Runs in expected O(n) time, randomized.
92714
+ // Note: If 0 points are given, null is returned.
92715
+ // If 1 point is given, a circle of radius 0 is returned.
92716
+ //
92717
+ function polyToCircle(poly, options) {
92718
+ if (options === undefined)
92719
+ options = DefaultOptions;
92720
+ return makeCircle(polyToExteriorPoints(poly));
92721
+ }
92722
+ exports.polyToCircle = polyToCircle;
92723
+ //
92724
+ // Returns the circle whose perimeter is equal to the perimeter of the bounding perimeter
92725
+ // of the polygon. Use binary search to find an approximation.
92726
+ //
92727
+ function polyToPolsbyPopperCircle(poly, options) {
92728
+ if (options === undefined)
92729
+ options = DefaultOptions;
92730
+ let c = polyToCircle(poly, options);
92731
+ if (c == null)
92732
+ return c;
92733
+ let p = polyPerimeter(poly, options);
92734
+ c.r = (p / (2 * Math.PI)) / 111139;
92735
+ return c;
92736
+ }
92737
+ exports.polyToPolsbyPopperCircle = polyToPolsbyPopperCircle;
92738
+ function makeCircle(points) {
92739
+ if (points == null)
92740
+ return null;
92741
+ // Clone list to preserve the caller's data, do Durstenfeld shuffle
92742
+ let shuffled = points.slice();
92743
+ for (let i = points.length - 1; i >= 0; i--) {
92744
+ let j = Math.floor(Math.random() * (i + 1));
92745
+ j = Math.max(Math.min(j, i), 0);
92746
+ const temp = shuffled[i];
92747
+ shuffled[i] = shuffled[j];
92748
+ shuffled[j] = temp;
92749
+ }
92750
+ // Progressively add points to circle or recompute circle
92751
+ let c = null;
92752
+ shuffled.forEach((p, i) => {
92753
+ if (c === null || !isInCircle(c, p))
92754
+ c = makeCircleOnePoint(shuffled.slice(0, i + 1), p);
92755
+ });
92756
+ return c;
92757
+ }
92758
+ // One boundary point known
92759
+ function makeCircleOnePoint(points, p) {
92760
+ let c = new Circle(p.x, p.y, 0);
92761
+ points.forEach((q, i) => {
92762
+ if (!isInCircle(c, q)) {
92763
+ if (c.r == 0)
92764
+ c = makeDiameter(p, q);
92765
+ else
92766
+ c = makeCircleTwoPoints(points.slice(0, i + 1), p, q);
92767
+ }
92768
+ });
92769
+ return c;
92770
+ }
92771
+ // Two boundary points known
92772
+ function makeCircleTwoPoints(points, p, q) {
92773
+ const circ = makeDiameter(p, q);
92774
+ let left = null;
92775
+ let right = null;
92776
+ // For each point not in the two-point circle
92777
+ for (const r of points) {
92778
+ if (isInCircle(circ, r))
92779
+ continue;
92780
+ // Form a circumcircle and classify it on left or right side
92781
+ const cross = crossProduct(p.x, p.y, q.x, q.y, r.x, r.y);
92782
+ const c = makeCircumcircle(p, q, r);
92783
+ if (c === null)
92784
+ continue;
92785
+ else if (cross > 0 && (left === null || crossProduct(p.x, p.y, q.x, q.y, c.x, c.y) > crossProduct(p.x, p.y, q.x, q.y, left.x, left.y)))
92786
+ left = c;
92787
+ else if (cross < 0 && (right === null || crossProduct(p.x, p.y, q.x, q.y, c.x, c.y) < crossProduct(p.x, p.y, q.x, q.y, right.x, right.y)))
92788
+ right = c;
92789
+ }
92790
+ // Select which circle to return
92791
+ if (left === null && right === null)
92792
+ return circ;
92793
+ else if (left === null && right !== null)
92794
+ return right;
92795
+ else if (left !== null && right === null)
92796
+ return left;
92797
+ else if (left !== null && right !== null)
92798
+ return left.r <= right.r ? left : right;
92799
+ else
92800
+ throw "Assertion error";
92801
+ }
92802
+ function makeDiameter(a, b) {
92803
+ const cx = (a.x + b.x) / 2;
92804
+ const cy = (a.y + b.y) / 2;
92805
+ const r0 = Util.distance(cx, cy, a.x, a.y);
92806
+ const r1 = Util.distance(cx, cy, b.x, b.y);
92807
+ return new Circle(cx, cy, Math.max(r0, r1));
92808
+ }
92809
+ function makeCircumcircle(a, b, c) {
92810
+ // Mathematical algorithm from Wikipedia: Circumscribed circle
92811
+ const ox = (Math.min(a.x, b.x, c.x) + Math.max(a.x, b.x, c.x)) / 2;
92812
+ const oy = (Math.min(a.y, b.y, c.y) + Math.max(a.y, b.y, c.y)) / 2;
92813
+ const ax = a.x - ox;
92814
+ const ay = a.y - oy;
92815
+ const bx = b.x - ox;
92816
+ const by = b.y - oy;
92817
+ const cx = c.x - ox;
92818
+ const cy = c.y - oy;
92819
+ const d = (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by)) * 2;
92820
+ if (d == 0)
92821
+ return null;
92822
+ const x = ox + ((ax * ax + ay * ay) * (by - cy) + (bx * bx + by * by) * (cy - ay) + (cx * cx + cy * cy) * (ay - by)) / d;
92823
+ const y = oy + ((ax * ax + ay * ay) * (cx - bx) + (bx * bx + by * by) * (ax - cx) + (cx * cx + cy * cy) * (bx - ax)) / d;
92824
+ const ra = Util.distance(x, y, a.x, a.y);
92825
+ const rb = Util.distance(x, y, b.x, b.y);
92826
+ const rc = Util.distance(x, y, c.x, c.y);
92827
+ return new Circle(x, y, Math.max(ra, rb, rc));
92828
+ }
92829
+ /* Simple mathematical functions */
92830
+ const MULTIPLICATIVE_EPSILON = 1 + 1e-14;
92831
+ function isInCircle(c, p) {
92832
+ return c !== null && Util.distance(p.x, p.y, c.x, c.y) <= c.r * MULTIPLICATIVE_EPSILON;
92833
+ }
92834
+ // Returns twice the signed area of the triangle defined by (x0, y0), (x1, y1), (x2, y2).
92835
+ function crossProduct(x0, y0, x1, y1, x2, y2) {
92836
+ return (x1 - x0) * (y2 - y0) - (y1 - y0) * (x2 - x0);
92837
+ }
92838
+ // cache x,y circle offsets for one quadrant indexed by number of segments
92839
+ let circleOffsets = {};
92840
+ function getCircleOffsets(n) {
92841
+ if (circleOffsets[n] === undefined) {
92842
+ let a = [];
92843
+ let incr = (Math.PI / 2) / n;
92844
+ let theta = 0;
92845
+ let i, j;
92846
+ // Compute NE quadrant
92847
+ for (i = 0; i < n; i++, theta += incr) {
92848
+ a.push(Math.sin(theta));
92849
+ a.push(Math.cos(theta));
92850
+ }
92851
+ // Add top of circle
92852
+ a.push(0);
92853
+ a.push(1);
92854
+ // Now flip X and replicate to NW quadrant
92855
+ for (i = 0; i < n; i++) {
92856
+ j = (n - i) * 2;
92857
+ a.push(-a[j - 1]);
92858
+ a.push(a[j - 2]);
92859
+ }
92860
+ // Now flip X and Y and replicate to SW quadrant
92861
+ for (i = 0; i < n; i++) {
92862
+ j = (n - i) * 2;
92863
+ a.push(-a[j - 1]);
92864
+ a.push(-a[j - 2]);
92865
+ }
92866
+ // Add bottom of circle
92867
+ a.push(0);
92868
+ a.push(-1);
92869
+ // Now flip Y and replicate to SE quadrant
92870
+ for (i = 0; i < n; i++) {
92871
+ j = (n - i) * 2;
92872
+ a.push(a[j - 1]);
92873
+ a.push(-a[j - 2]);
92874
+ }
92875
+ // Duplicate final point per GeoJSON spec
92876
+ a.push(a[0]);
92877
+ a.push(a[1]);
92878
+ circleOffsets[n] = a;
92879
+ }
92880
+ return circleOffsets[n];
92881
+ }
92882
+ // Note that this is essentially an inversion of polyToCircle which computes a mathematical
92883
+ // circle given the point values, ignoring latitude correction. This inversion also
92884
+ // ignores that correction which means when plotted on a 2D map looks circular but the edge of
92885
+ // the circle is not a fixed distance (in physical units, e.g. meters) from the center.
92886
+ //
92887
+ function polyFromCircle(c, nSegments, options) {
92888
+ if (options === undefined)
92889
+ options = DefaultOptions;
92890
+ if (c === null || c.r == 0)
92891
+ return null;
92892
+ if (!nSegments || nSegments < 8)
92893
+ nSegments = 8;
92894
+ let poly = [];
91080
92895
  let offsets = getCircleOffsets(nSegments);
91081
92896
  const n = offsets.length;
91082
92897
  for (let i = 0; i < n; i += 2)
@@ -98606,6 +100421,7 @@ const analyze_1 = __webpack_require__(/*! ./analyze */ "./src/analyze.ts");
98606
100421
  const score_1 = __webpack_require__(/*! ./score */ "./src/score.ts");
98607
100422
  const results_1 = __webpack_require__(/*! ./results */ "./src/results.ts");
98608
100423
  const results_2 = __webpack_require__(/*! ./results */ "./src/results.ts");
100424
+ const geofeature_1 = __webpack_require__(/*! ./geofeature */ "./src/geofeature.ts");
98609
100425
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
98610
100426
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
98611
100427
  class AnalyticsSession {
@@ -98625,46 +100441,39 @@ class AnalyticsSession {
98625
100441
  this.features = new D.Features(this, SessionRequest['data'], this.config['datasets']);
98626
100442
  this.plan = new D.Plan(this, SessionRequest['plan']);
98627
100443
  this.districts = new D.Districts(this, SessionRequest['districtShapes']);
98628
- // TODO - Confirming that the graph includes OUT_OF_STATE neighbors
98629
- // if (U.keyExists(S.OUT_OF_STATE, this.graph._graph)) {
98630
- // console.log("Contiguity graph includes out-of-state neighbors.");
98631
- // }
98632
- // else {
98633
- // console.log("Contiguity graph does NOT include out-of-state neighbors.");
98634
- // }
98635
- // NOTE: I've pulled these out of the individual analytics to here. Eventually,
98636
- // we could want them to passed into an analytics session as data, along with
98637
- // everything else. For now, this keeps branching out of the main code.
98638
- results_1.doConfigureScales(this);
100444
+ // TODO - SCORE: Toggle
100445
+ if (this.useLegacy()) {
100446
+ // NOTE: I've pulled these out of the individual analytics to here. Eventually,
100447
+ // we could want them to passed into an analytics session as data, along with
100448
+ // everything else. For now, this keeps branching out of the main code.
100449
+ results_1.doConfigureScales(this);
100450
+ }
98639
100451
  }
98640
100452
  processConfig(config) {
98641
100453
  // NOTE - Session settings are required:
98642
100454
  // - Analytics suites can be defaulted to all with [], but
98643
100455
  // - Dataset keys must be explicitly specified with 'dataset'
98644
- // TODO - DASHBOARD: Remove this mechanism. Always run everything.
98645
- let defaultSuites = [0 /* Legal */, 1 /* Fair */, 2 /* Best */];
98646
- // If the config passed in has no suites = [], use the default suites
98647
- if (U.isArrayEmpty(config['suites'])) {
98648
- config['suites'] = defaultSuites;
98649
- }
100456
+ config['suites'] = [0 /* Legal */, 1 /* Fair */, 2 /* Best */];
98650
100457
  // Default the Census & redistricting cycle to 2010
98651
100458
  if (!(U.keyExists('cycle', config)))
98652
100459
  config['cycle'] = 2010;
98653
100460
  return config;
98654
100461
  }
100462
+ useLegacy() {
100463
+ return (U.keyExists('useScore', this.config) && (this.config['useScore'])) ? false : true;
100464
+ }
98655
100465
  // Using the the data in the analytics session, calculate all the
98656
100466
  // analytics & validations, saving/updating the individual test results.
98657
- analyzePlan(bLog = false) {
100467
+ analyzePlan(bLog = false, overridesJSON = undefined) {
98658
100468
  try {
98659
100469
  preprocess_1.doPreprocessData(this, bLog);
98660
100470
  analyze_1.doAnalyzeDistricts(this, bLog);
98661
- analyze_1.doAnalyzePlan(this, bLog);
98662
100471
  // TODO - SCORE
100472
+ analyze_1.doAnalyzePlan(this, bLog);
98663
100473
  this._profile = score_1.profilePlan(this, bLog);
98664
- // this._profile = Score.sampleProfile;
98665
100474
  this._scorecard = score_1.scorePlan(this._profile, bLog);
98666
- // TODO - SCORE
98667
100475
  results_1.doAnalyzePostProcessing(this, bLog);
100476
+ //
98668
100477
  }
98669
100478
  catch (_a) {
98670
100479
  console.log("Exception caught by analyzePlan()");
@@ -98684,13 +100493,6 @@ class AnalyticsSession {
98684
100493
  getPlanScorecard(bLog = false) {
98685
100494
  return this._scorecard;
98686
100495
  }
98687
- /* TODO - SCORE
98688
- // NOTE - This assumes that analyzePlan() has been run!
98689
- getPlanAnalytics(bLog: boolean = false): PlanAnalytics
98690
- {
98691
- return preparePlanAnalytics(this, bLog);
98692
- }
98693
- */
98694
100496
  // TODO - SCORE
98695
100497
  // NOTE - This assumes that analyzePlan() has been run!
98696
100498
  getRequirementsChecklist(bLog = false) {
@@ -98699,19 +100501,82 @@ class AnalyticsSession {
98699
100501
  // NOTE - This assumes that analyzePlan() has been run!
98700
100502
  getDiscontiguousDistrictFeatures(bLog = false) {
98701
100503
  // Get the (possibly empty) list of discontiguous district IDs
98702
- let contiguousTest = this.getTest(1 /* Contiguous */);
98703
- let discontiguousDistrictIDs = contiguousTest['details']['discontiguousDistricts'] || [];
100504
+ const contiguousTest = this.getTest(1 /* Contiguous */);
100505
+ const discontiguousDistrictIDs = contiguousTest['details']['discontiguousDistricts'] || [];
98704
100506
  // Convert them into a (possibly empty) list of features
98705
100507
  let discontiguousDistrictFeatures = { type: 'FeatureCollection', features: [] };
98706
100508
  if (!(U.isArrayEmpty(discontiguousDistrictIDs))) {
98707
100509
  for (let id of discontiguousDistrictIDs) {
98708
100510
  let poly = this.districts.getDistrictShapeByID(id);
98709
- if (poly)
98710
- discontiguousDistrictFeatures.features.push(poly);
100511
+ if (poly) {
100512
+ // If a district has a shape & it is not contiguous, by definition,
100513
+ // it will be a Multipolygon, i.e., it will have multiple pieces, some
100514
+ // possibly embedded w/in other districts. Get & add all the pieces.
100515
+ const districtParts = geofeature_1.polyParts(poly);
100516
+ discontiguousDistrictFeatures.features.push(...districtParts.features);
100517
+ // discontiguousDistrictFeatures.features.push(poly);
100518
+ }
98711
100519
  }
98712
100520
  }
98713
100521
  return discontiguousDistrictFeatures;
98714
100522
  }
100523
+ // Comments clipped from dra-client geodistrict.ts.
100524
+ // Discontiguous polygons are:
100525
+ // 1. All polygons in a multi-polygon; and
100526
+ // 2. All holes in a otherwise cohesive polygon.
100527
+ // Note that all non-cohesive features are always simple polygons.
100528
+ /*
100529
+ let i: number, j: number;
100530
+ let nPoly: number = 0;
100531
+ for (i = 0;nPoly == 0 && i < this.cacheDistricts.features.length;i++)
100532
+ {
100533
+ let f = this.cacheDistricts.features[i];
100534
+
100535
+ if (f.geometry.type === 'MultiPolygon')
100536
+ nPoly += f.geometry.coordinates.length;
100537
+ else if (f.geometry.type === 'Polygon' && f.geometry.coordinates.length)
100538
+ nPoly += (f.geometry.coordinates.length - 1);
100539
+ }
100540
+ if (nPoly)
100541
+ {
100542
+ this.cacheNoncohesive = {type: 'FeatureCollection', features: []};
100543
+ let af: any = this.cacheNoncohesive.features;
100544
+ let oUnique: any = {};
100545
+
100546
+ // First add discontiguous polygons
100547
+ for (i = 0;i < this.cacheDistricts.features.length;i++)
100548
+ {
100549
+ let f = this.cacheDistricts.features[i];
100550
+
100551
+ if (f.geometry.type === 'MultiPolygon')
100552
+ {
100553
+ // Push all non-contiguous polygons
100554
+ for (j = 0;j < f.geometry.coordinates.length;j++)
100555
+ {
100556
+ let p: any = f.geometry.coordinates[j];
100557
+ oUnique[Hash.qhash(p[0])] = true;
100558
+ af.push({type: 'Feature', properties: {id: `${af.length + 1}`}, geometry: {type: 'Polygon', coordinates: p}});
100559
+ }
100560
+ }
100561
+ }
100562
+
100563
+ // Now add unique holes
100564
+ for (i = 0;i < this.cacheDistricts.features.length;i++)
100565
+ {
100566
+ let f = this.cacheDistricts.features[i];
100567
+
100568
+ if (f.geometry.type === 'Polygon')
100569
+ {
100570
+ // Push all holes from this polygon
100571
+ for (j = 1;j < f.geometry.coordinates.length;j++)
100572
+ {
100573
+ let p: any = f.geometry.coordinates[j];
100574
+ if (oUnique[Hash.qhash(p)] === undefined)
100575
+ af.push({type: 'Feature', properties: {id: `${af.length + 1}`}, geometry: {type: 'Polygon', coordinates: [p]}});
100576
+ }
100577
+ }
100578
+ }
100579
+ } */
98715
100580
  // HELPERS USED INTERNALLY
98716
100581
  // Get an individual test, so you can drive UI with the results.
98717
100582
  getTest(testID) {
@@ -98727,9 +100592,17 @@ class AnalyticsSession {
98727
100592
  // Return a pointer to the the test entry for this test
98728
100593
  return this.tests[testID];
98729
100594
  }
98730
- // NOTE - Not sure why this has to be up here.
100595
+ // NOTE - Not sure why this has to be up here ...
98731
100596
  populationDeviationThreshold() {
98732
- return 1 - this.testScales[4 /* PopulationDeviation */]['scale'][0];
100597
+ // TODO - SCORE: Toggle
100598
+ // const bLegacy = this._bLegacy; DELETE
100599
+ if (this.useLegacy()) {
100600
+ return 1 - this.testScales[4 /* PopulationDeviation */]['scale'][0];
100601
+ }
100602
+ else {
100603
+ const scorecard = this._scorecard;
100604
+ return scorecard.best.populationDeviation.notes['threshold'];
100605
+ }
98733
100606
  }
98734
100607
  }
98735
100608
  exports.AnalyticsSession = AnalyticsSession;
@@ -98905,7 +100778,7 @@ class Districts {
98905
100778
  let outerThis = this;
98906
100779
  // Default the pop dev % for the dummy Unassigned district to 0%.
98907
100780
  // Default the pop dev % for real (1–N) but empty districts to 100%.
98908
- // TODO - SCORE
100781
+ // TODO - SCORE: Why did I mark this?
98909
100782
  let popDevPct = (i > 0) ? (targetSize / targetSize) : 0 / targetSize;
98910
100783
  // Get the geoIDs assigned to the district
98911
100784
  // Guard against empty districts
@@ -98932,7 +100805,6 @@ class Districts {
98932
100805
  // NOTE - SPLITTING
98933
100806
  // Total population by counties w/in a district,
98934
100807
  // except the dummy unassigned district 0
98935
- // TODO - VFEATURE
98936
100808
  if (i > 0)
98937
100809
  countySplits[outerThis.getCountyIndex(geoID)] += featurePop;
98938
100810
  // Democratic and Republican vote totals
@@ -99106,10 +100978,7 @@ class Districts {
99106
100978
  compact_1.extractDistrictProperties(this._session, bLog);
99107
100979
  }
99108
100980
  getCountyIndex(geoID) {
99109
- // TODO - VFEATURE
99110
100981
  let countyFIPS = U.parseGeoID(geoID)['county'];
99111
- // let countyGeoID = U.parseGeoID(geoID)['county'] as string;
99112
- // let countyFIPS = U.getFIPSFromCountyGeoID(countyGeoID);
99113
100982
  let countyIndex = this._session.counties.indexFromFIPS(countyFIPS);
99114
100983
  return countyIndex;
99115
100984
  }
@@ -99358,6 +101227,8 @@ exports.doAnalyzeDistricts = doAnalyzeDistricts;
99358
101227
  // NOTE - I could make this table-driven, but I'm thinking that the explicit
99359
101228
  // calls might make chunking for aync easier.
99360
101229
  function doAnalyzePlan(s, bLog = false) {
101230
+ // TODO - SCORE: Toggle
101231
+ // const bLegacy = s._bLegacy;
99361
101232
  // TODO - Remove this mechanism. Always run all tests
99362
101233
  // Get the requested suites, and only execute those tests
99363
101234
  let requestedSuites = s.config['suites'];
@@ -99404,6 +101275,8 @@ exports.doAnalyzePlan = doAnalyzePlan;
99404
101275
  // NOTE - Should this be conditionalized on the test suites requested?
99405
101276
  // Those are encapsulated in reports.ts right now, so not doing that.
99406
101277
  function doDeriveSecondaryTests(s, bLog = false) {
101278
+ // TODO - SCORE: Toggle
101279
+ // const bLegacy = s._bLegacy;
99407
101280
  s.tests[3 /* EqualPopulation */] = equal_1.doHasEqualPopulations(s, bLog);
99408
101281
  }
99409
101282
  exports.doDeriveSecondaryTests = doDeriveSecondaryTests;
@@ -99987,6 +101860,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
99987
101860
  Object.defineProperty(exports, "__esModule", { value: true });
99988
101861
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
99989
101862
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
101863
+ // TODO - SCORE: Delete
99990
101864
  function doPopulationDeviation(s, bLog = false) {
99991
101865
  let test = s.getTest(4 /* PopulationDeviation */);
99992
101866
  let targetSize = s.state.totalPop / s.state.nDistricts;
@@ -100022,6 +101896,13 @@ exports.doPopulationDeviation = doPopulationDeviation;
100022
101896
  // NOTE - This validity check is *derived* and depends on population deviation %
100023
101897
  // being computed (above) and normalized in test log & scorecard generation.
100024
101898
  function doHasEqualPopulations(s, bLog = false) {
101899
+ // TODO - SCORE: Toggle
101900
+ // const bLegacy = s._bLegacy;
101901
+ const scorecard = s._scorecard;
101902
+ const popDevNormalizedNEW = scorecard.best.populationDeviation.normalized;
101903
+ const bScore = (popDevNormalizedNEW > 0) ? true : false;
101904
+ // TODO - Get scales
101905
+ // TODO - Flow through to RequirementsChecklist
100025
101906
  let test = s.getTest(3 /* EqualPopulation */);
100026
101907
  // Get the normalized population deviation %
100027
101908
  let popDevTest = s.getTest(4 /* PopulationDeviation */);
@@ -100036,6 +101917,7 @@ function doHasEqualPopulations(s, bLog = false) {
100036
101917
  }
100037
101918
  test['details']['deviation'] = popDevPct;
100038
101919
  test['details']['thresholds'] = popDevTest['details']['scale'];
101920
+ console.log("Equal population =", test['score'], bScore);
100039
101921
  // Populate the N+1 summary "district" in district.statistics
100040
101922
  let bEqualPop = s.districts.statistics[D.DistrictField.bEqualPop];
100041
101923
  let summaryRow = s.districts.numberOfRows() - 1;
@@ -100068,6 +101950,23 @@ var __importStar = (this && this.__importStar) || function (mod) {
100068
101950
  };
100069
101951
  Object.defineProperty(exports, "__esModule", { value: true });
100070
101952
  const Poly = __importStar(__webpack_require__(/*! @dra2020/poly */ "./node_modules/@dra2020/poly/dist/poly.js"));
101953
+ // HELPER
101954
+ function polyParts(poly) {
101955
+ let parts = { type: 'FeatureCollection', features: [] };
101956
+ let af = parts.features;
101957
+ if (poly.geometry.type === 'MultiPolygon') {
101958
+ // Push all non-contiguous polygons
101959
+ for (let j = 0; j < poly.geometry.coordinates.length; j++) {
101960
+ let onePoly = poly.geometry.coordinates[j];
101961
+ af.push({ type: 'Feature', properties: { id: `${af.length + 1}` }, geometry: { type: 'Polygon', coordinates: onePoly } });
101962
+ }
101963
+ }
101964
+ else {
101965
+ parts.features.push(poly);
101966
+ }
101967
+ return parts;
101968
+ }
101969
+ exports.polyParts = polyParts;
100071
101970
  // CARTESIAN SHIMS OVER 'POLY' FUNCTIONS
100072
101971
  // TODO - POLY: Confirm Cartesian calculations
100073
101972
  function gfArea(poly) {
@@ -100369,10 +102268,7 @@ function doPreprocessCensus(s, bLog = false) {
100369
102268
  // Sum total population across the state
100370
102269
  s.state.totalPop += value;
100371
102270
  // Get the county FIPS code for the feature
100372
- // TODO - VFEATURE
100373
102271
  let countyFIPS = U.parseGeoID(geoID)['county'];
100374
- // let county = U.parseGeoID(geoID)['county'] as string;
100375
- // let countyFIPS = U.getFIPSFromCountyGeoID(county);
100376
102272
  // If a subtotal for the county doesn't exist, initialize one
100377
102273
  if (!(U.keyExists(countyFIPS, totalByCounty))) {
100378
102274
  totalByCounty[countyFIPS] = 0;
@@ -100390,8 +102286,8 @@ function doPreprocessCensus(s, bLog = false) {
100390
102286
  let fipsCodes = U.getObjectKeys(totalByCounty);
100391
102287
  // Sort the results
100392
102288
  fipsCodes = fipsCodes.sort();
100393
- // TODO - SCORE: This was added for SPLITTING
100394
- // Add a dummy county, for county-district splitting analysis
102289
+ // NOTE - This was added for the legacy SPLITTING implementation.
102290
+ // Add a dummy county, for county-district splitting analysis.
100395
102291
  fipsCodes.unshift('000');
100396
102292
  // Create the ID-ordinal map
100397
102293
  for (let i in fipsCodes) {
@@ -100481,6 +102377,7 @@ const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
100481
102377
  const analyze_1 = __webpack_require__(/*! ./analyze */ "./src/analyze.ts");
100482
102378
  const state_reqs_json_1 = __importDefault(__webpack_require__(/*! ../static/state-reqs.json */ "./static/state-reqs.json"));
100483
102379
  // Example
102380
+ // TODO - DELETE?
100484
102381
  let sampleRequirements = {
100485
102382
  score: 2 /* Red */,
100486
102383
  metrics: {
@@ -100504,6 +102401,7 @@ let sampleRequirements = {
100504
102401
  stateReqs: "https://www.brennancenter.org/sites/default/files/publications/2019_06_50States_FINALsinglepages_20.pdf"
100505
102402
  }
100506
102403
  };
102404
+ // TODO - DELETE
100507
102405
  let sampleCompactness = {
100508
102406
  score: 60,
100509
102407
  metrics: {
@@ -100516,6 +102414,7 @@ let sampleCompactness = {
100516
102414
  },
100517
102415
  resources: {}
100518
102416
  };
102417
+ // TODO - DELETE
100519
102418
  let sampleSplitting = {
100520
102419
  score: 73,
100521
102420
  metrics: {
@@ -100533,7 +102432,7 @@ let sampleSplitting = {
100533
102432
  datasets: {},
100534
102433
  resources: {}
100535
102434
  };
100536
- // TODO - PARTISAN: This category is still being fleshed out.
102435
+ // TODO - DELETE
100537
102436
  let samplePartisan = {
100538
102437
  score: 100,
100539
102438
  metrics: {
@@ -100548,7 +102447,7 @@ let samplePartisan = {
100548
102447
  planScore: "https://planscore.org/plan.html?20180219T202039.596761160Z"
100549
102448
  }
100550
102449
  };
100551
- // TODO - SCORE: Add a minority report
102450
+ // TODO - DELETE
100552
102451
  let sampleMinority = {
100553
102452
  score: null,
100554
102453
  metrics: {
@@ -100575,6 +102474,7 @@ let sampleMinority = {
100575
102474
  },
100576
102475
  resources: {}
100577
102476
  };
102477
+ // TODO - DELETE
100578
102478
  exports.samplePlanAnalytics = {
100579
102479
  requirements: sampleRequirements,
100580
102480
  compactness: sampleCompactness,
@@ -100583,232 +102483,6 @@ exports.samplePlanAnalytics = {
100583
102483
  partisan: samplePartisan,
100584
102484
  minority: sampleMinority
100585
102485
  };
100586
- /* TODO - SCORE
100587
- export function preparePlanAnalytics(s: AnalyticsSession, bLog: boolean = false): PlanAnalytics
100588
- {
100589
- if (!(s.bPostProcessingDone))
100590
- {
100591
- doAnalyzePostProcessing(s);
100592
- }
100593
-
100594
- // REQUIREMENTS CATEGORY
100595
- let paRequirements: RequirementsCategory;
100596
-
100597
- {
100598
- let completeTest = s.getTest(T.Test.Complete) as T.TestEntry;
100599
- let contiguousTest = s.getTest(T.Test.Contiguous) as T.TestEntry;
100600
- let freeOfHolesTest = s.getTest(T.Test.FreeOfHoles) as T.TestEntry;
100601
- let equalPopulationTest = s.getTest(T.Test.EqualPopulation) as T.TestEntry;
100602
-
100603
- // Combine individual checks into an overall score
100604
-
100605
- // TODO - DASHBOARD: Until we add three-state support top to bottom in
100606
- // requirements/validations, map booleans to tri-states here.
100607
- let completeMetric = U.mapBooleanToTriState(completeTest['score'] as boolean);
100608
- let contiguousMetric = U.mapBooleanToTriState(contiguousTest['score'] as boolean);
100609
- let freeOfHolesMetric = U.mapBooleanToTriState(freeOfHolesTest['score'] as boolean);
100610
- let equalPopulationMetric = U.mapBooleanToTriState(equalPopulationTest['score'] as boolean);
100611
-
100612
- let reqScore: T.TriState = T.TriState.Green;
100613
- let checks = [completeMetric, contiguousMetric, freeOfHolesMetric, equalPopulationMetric];
100614
- if (checks.includes(T.TriState.Yellow)) reqScore = T.TriState.Yellow;
100615
- if (checks.includes(T.TriState.Red)) reqScore = T.TriState.Red;
100616
-
100617
- // Get values to support details entries
100618
- let unassignedFeaturesDetail = U.deepCopy(completeTest['details']['unassignedFeatures']) || [];
100619
- let emptyDistrictsDetail = U.deepCopy(completeTest['details']['emptyDistricts']) || [];
100620
- let discontiguousDistrictsDetail = U.deepCopy(contiguousTest['details']['discontiguousDistricts']) || [];
100621
- let embeddedDistrictsDetail = U.deepCopy(freeOfHolesTest['details']['embeddedDistricts']) || [];
100622
-
100623
- let populationDeviationDetail = U.deepCopy(equalPopulationTest['details']['deviation']);
100624
- let deviationThresholdDetail = U.trim(s.populationDeviationThreshold());
100625
-
100626
- let xx: string = s.state.xx;
100627
- // TODO - JSON: Is there a better / easier way to work with the variable?
100628
- let stateReqsDict: T.Dict = allStateReqs;
100629
- let reqLinkToStateReqs: string = stateReqsDict[xx];
100630
-
100631
- // Populate the category
100632
- paRequirements = {
100633
- score: reqScore,
100634
- metrics: {
100635
- complete: completeMetric,
100636
- contiguous: contiguousMetric,
100637
- freeOfHoles: freeOfHolesMetric,
100638
- equalPopulation: equalPopulationMetric
100639
- },
100640
- details: {
100641
- unassignedFeatures: unassignedFeaturesDetail,
100642
- emptyDistricts: emptyDistrictsDetail,
100643
- discontiguousDistricts: discontiguousDistrictsDetail,
100644
- embeddedDistricts: embeddedDistrictsDetail,
100645
- populationDeviation: populationDeviationDetail,
100646
- deviationThreshold: deviationThresholdDetail
100647
- },
100648
- datasets: {
100649
- census: U.deepCopy(s.config['descriptions']['CENSUS']),
100650
- },
100651
- resources: {
100652
- stateReqs: reqLinkToStateReqs
100653
- }
100654
- }
100655
- }
100656
-
100657
- // COMPACTNESS CATEGORY
100658
- let paCompactness: CompactnessCategory;
100659
- {
100660
- let reockWeight = 0.5;
100661
- let polsbyWeight = 1.0 - reockWeight;
100662
-
100663
- let reockTest = s.getTest(T.Test.Reock) as T.TestEntry;
100664
- let polsbyTest = s.getTest(T.Test.PolsbyPopper) as T.TestEntry;
100665
-
100666
- let normalizedReock = reockTest['normalizedScore'] as number;
100667
- let normalizedPolsby = reockTest['normalizedScore'] as number;
100668
- let compactnessScore = U.trim((reockWeight * normalizedReock) + (polsbyWeight * normalizedPolsby), 0);
100669
-
100670
- let reockMetric = U.deepCopy(reockTest['score'] as number);
100671
- let polsbyMetric = U.deepCopy(polsbyTest['score'] as number);
100672
-
100673
- // Populate the category
100674
- paCompactness = {
100675
- score: compactnessScore,
100676
- metrics: {
100677
- reock: reockMetric,
100678
- polsby: polsbyMetric
100679
- },
100680
- details: {
100681
- // None at this time
100682
- },
100683
- datasets: {
100684
- // NOTE - DATASETS
100685
- shapes: U.deepCopy(s.config['descriptions']['SHAPES'])
100686
- // shapes: "2010 VTD shapes"
100687
- },
100688
- resources: {
100689
- // None at this time
100690
- }
100691
- }
100692
- }
100693
-
100694
- // SPLITTING CATEGORY
100695
-
100696
- let paSplitting: SplittingCategory
100697
-
100698
- {
100699
- let unexpectedCountySplittingTest = s.getTest(T.Test.UnexpectedCountySplits) as T.TestEntry;
100700
- let VTDSplitsTest = s.getTest(T.Test.VTDSplits) as T.TestEntry;
100701
- let countySplittingTest = s.getTest(T.Test.CountySplitting) as T.TestEntry;
100702
- let districtSplittingTest = s.getTest(T.Test.DistrictSplitting) as T.TestEntry;
100703
-
100704
- let unexpectedAffectedMetric = U.deepCopy(unexpectedCountySplittingTest['score']);
100705
- let countiesSplitUnexpectedlyDetail = U.deepCopy(unexpectedCountySplittingTest['details']['countiesSplitUnexpectedly']);
100706
-
100707
- let nVTDSplitsMetric = U.deepCopy(VTDSplitsTest['score']);
100708
- let splitVTDsDetail = U.deepCopy(VTDSplitsTest['details']['splitVTDs']);
100709
-
100710
- let SqEnt_DCreducedMetric = U.deepCopy(countySplittingTest['score']);
100711
- let SqEnt_CDreducedMetric = U.deepCopy(districtSplittingTest['score']);
100712
-
100713
- let countySplittingNormalized = countySplittingTest['normalizedScore'] as number;
100714
- let districtSplittingNormalized = districtSplittingTest['normalizedScore'] as number;
100715
- let splittingScore = U.trim((S.COUNTY_SPLITTING_WEIGHT * countySplittingNormalized) +
100716
- + (S.DISTRICT_SPLITTING_WEIGHT * districtSplittingNormalized), 0);
100717
-
100718
- paSplitting = {
100719
- score: splittingScore,
100720
- metrics: {
100721
- sqEnt_DCreduced: SqEnt_DCreducedMetric,
100722
- sqEnt_CDreduced: SqEnt_CDreducedMetric
100723
- // NOTE - The un-reduced raw values
100724
- // sqEnt_DC : SqEnt_DCMetric,
100725
- // sqEnt_CD : SqEnt_CDMetric
100726
- },
100727
- details: {
100728
- countiesSplitUnexpectedly: countiesSplitUnexpectedlyDetail,
100729
- unexpectedAffected: unexpectedAffectedMetric,
100730
- nSplitVTDs: nVTDSplitsMetric,
100731
- splitVTDs: splitVTDsDetail
100732
- },
100733
- datasets: {
100734
- // None at this time
100735
- },
100736
- resources: {
100737
- // None at this time
100738
- }
100739
- }
100740
- }
100741
-
100742
- // PARTISAN CATEGORY
100743
- //
100744
- // TODO - PARTISAN: This category is still being fleshed out. Just an example below.
100745
- let paPartisan: PartisanCategory;
100746
-
100747
- {
100748
- paPartisan = {
100749
- score: 100,
100750
- metrics: {
100751
- partisanBias: 0.15,
100752
- responsiveness: 2.0
100753
- },
100754
- details: {},
100755
- datasets: {
100756
- election: "2016 Presidential, US Senate, Governor, and AG election results"
100757
- },
100758
- resources: {
100759
- planScore: "https://planscore.org/plan.html?20180219T202039.596761160Z"
100760
- }
100761
- }
100762
- }
100763
-
100764
- // MINORITY CATEGORY
100765
- //
100766
- // TODO - MINORITY: This category is still being fleshed out. Just an example below.
100767
- let paMinority: MinorityCategory;
100768
-
100769
- {
100770
- paMinority = {
100771
- score: null,
100772
- metrics: {
100773
- nBlack37to50: 1,
100774
- nBlackMajority: 12,
100775
- nHispanic37to50: 0,
100776
- nHispanicMajority: 0,
100777
- nPacific37to50: 0,
100778
- nPacificMajority: 0,
100779
- nAsian37to50: 0,
100780
- nAsianMajority: 0,
100781
- nNative37to50: 0,
100782
- nNativeMajority: 0,
100783
- nMinority37to50: 0,
100784
- nMinorityMajority: 0,
100785
-
100786
- averageDVoteShare: 0.90
100787
- },
100788
- details: {
100789
- vap: true,
100790
- comboCategories: true
100791
- },
100792
- datasets: {
100793
- vap: "2010 Voting Age Population"
100794
- },
100795
- resources: {}
100796
- }
100797
- }
100798
-
100799
- // PLAN ANALYTICS
100800
- let pa: PlanAnalytics = {
100801
- requirements: paRequirements,
100802
- compactness: paCompactness,
100803
- // TODO - Not implemented yet
100804
- splitting: paSplitting,
100805
- partisan: paPartisan,
100806
- minority: paMinority
100807
- }
100808
-
100809
- return pa;
100810
- }
100811
- */
100812
102486
  function prepareRequirementsChecklist(s, bLog = false) {
100813
102487
  if (!(s.bPostProcessingDone)) {
100814
102488
  doAnalyzePostProcessing(s);
@@ -100816,34 +102490,38 @@ function prepareRequirementsChecklist(s, bLog = false) {
100816
102490
  // REQUIREMENTS CATEGORY
100817
102491
  let paRequirements;
100818
102492
  {
100819
- let completeTest = s.getTest(0 /* Complete */);
100820
- let contiguousTest = s.getTest(1 /* Contiguous */);
100821
- let freeOfHolesTest = s.getTest(2 /* FreeOfHoles */);
100822
- let equalPopulationTest = s.getTest(3 /* EqualPopulation */);
102493
+ const completeTest = s.getTest(0 /* Complete */);
102494
+ const contiguousTest = s.getTest(1 /* Contiguous */);
102495
+ const freeOfHolesTest = s.getTest(2 /* FreeOfHoles */);
102496
+ const equalPopulationTest = s.getTest(3 /* EqualPopulation */);
100823
102497
  // Combine individual checks into an overall score
100824
- // TODO - DASHBOARD: Until we add three-state support top to bottom in
102498
+ // NOTE - Until we add three-state support top to bottom in
100825
102499
  // requirements/validations, map booleans to tri-states here.
100826
- let completeMetric = U.mapBooleanToTriState(completeTest['score']);
100827
- let contiguousMetric = U.mapBooleanToTriState(contiguousTest['score']);
100828
- let freeOfHolesMetric = U.mapBooleanToTriState(freeOfHolesTest['score']);
100829
- let equalPopulationMetric = U.mapBooleanToTriState(equalPopulationTest['score']);
102500
+ const completeMetric = U.mapBooleanToTriState(completeTest['score']);
102501
+ const contiguousMetric = U.mapBooleanToTriState(contiguousTest['score']);
102502
+ const freeOfHolesMetric = U.mapBooleanToTriState(freeOfHolesTest['score']);
102503
+ const equalPopulationMetric = U.mapBooleanToTriState(equalPopulationTest['score']);
100830
102504
  let reqScore = 0 /* Green */;
100831
- let checks = [completeMetric, contiguousMetric, freeOfHolesMetric, equalPopulationMetric];
102505
+ const checks = [completeMetric, contiguousMetric, freeOfHolesMetric, equalPopulationMetric];
100832
102506
  if (checks.includes(1 /* Yellow */))
100833
102507
  reqScore = 1 /* Yellow */;
100834
102508
  if (checks.includes(2 /* Red */))
100835
102509
  reqScore = 2 /* Red */;
100836
102510
  // Get values to support details entries
100837
- let unassignedFeaturesDetail = U.deepCopy(completeTest['details']['unassignedFeatures']) || [];
100838
- let emptyDistrictsDetail = U.deepCopy(completeTest['details']['emptyDistricts']) || [];
100839
- let discontiguousDistrictsDetail = U.deepCopy(contiguousTest['details']['discontiguousDistricts']) || [];
100840
- let embeddedDistrictsDetail = U.deepCopy(freeOfHolesTest['details']['embeddedDistricts']) || [];
100841
- let populationDeviationDetail = U.deepCopy(equalPopulationTest['details']['deviation']);
100842
- let deviationThresholdDetail = U.trim(s.populationDeviationThreshold());
100843
- let xx = s.state.xx;
102511
+ const unassignedFeaturesDetail = U.deepCopy(completeTest['details']['unassignedFeatures']) || [];
102512
+ const emptyDistrictsDetail = U.deepCopy(completeTest['details']['emptyDistricts']) || [];
102513
+ const discontiguousDistrictsDetail = U.deepCopy(contiguousTest['details']['discontiguousDistricts']) || [];
102514
+ const embeddedDistrictsDetail = U.deepCopy(freeOfHolesTest['details']['embeddedDistricts']) || [];
102515
+ const scorecard = s._scorecard;
102516
+ const deviationThreshold = scorecard.best.populationDeviation.notes['threshold'];
102517
+ // TODO - SCORE: Toggle
102518
+ const populationDeviationDetail = U.deepCopy(equalPopulationTest['details']['deviation']);
102519
+ const deviationThresholdDetail = U.trim(s.populationDeviationThreshold());
102520
+ console.log("Population deviation thresholds =", deviationThresholdDetail, deviationThreshold);
102521
+ const xx = s.state.xx;
100844
102522
  // TODO - JSON: Is there a better / easier way to work with the variable?
100845
- let stateReqsDict = state_reqs_json_1.default;
100846
- let reqLinkToStateReqs = stateReqsDict[xx];
102523
+ const stateReqsDict = state_reqs_json_1.default;
102524
+ const reqLinkToStateReqs = stateReqsDict[xx];
100847
102525
  // Populate the category
100848
102526
  paRequirements = {
100849
102527
  score: reqScore,
@@ -101106,6 +102784,8 @@ exports.doConfigureScales = doConfigureScales;
101106
102784
  // Postprocess analytics - Normalize numeric results and derive secondary tests.
101107
102785
  // Do this after analytics have been run and before preparing a test log or scorecard.
101108
102786
  function doAnalyzePostProcessing(s, bLog = false) {
102787
+ // TODO - SCORE: Toggle
102788
+ // const bLegacy = s._bLegacy;
101109
102789
  // Normalize the raw scores for all the numerics tests
101110
102790
  let testResults = U.getNumericObjectKeys(testDefns);
101111
102791
  for (let testID of testResults) {
@@ -101149,7 +102829,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
101149
102829
  return result;
101150
102830
  };
101151
102831
  Object.defineProperty(exports, "__esModule", { value: true });
101152
- const Score = __importStar(__webpack_require__(/*! @dra2020/dra-score */ "./node_modules/@dra2020/dra-score/dist/dra-score.bundle.js"));
102832
+ const Score = __importStar(__webpack_require__(/*! @dra2020/dra-score */ "../dra-score/dist/dra-score.bundle.js"));
101153
102833
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
101154
102834
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
101155
102835
  // PROFILE A PLAN
@@ -101201,13 +102881,11 @@ function makeNakedCxD(s, bLog = false) {
101201
102881
  let CxD = [];
101202
102882
  // Remove the unassigned & total dummy "districts"
101203
102883
  for (let districtID = 1; districtID <= s.state.nDistricts; districtID++) {
101204
- // TODO - SCORE: OH has an extra county!?!
101205
102884
  const splits = U.deepCopy(adornedCxD[districtID].slice(1));
101206
102885
  CxD.push(splits);
101207
102886
  }
101208
102887
  return CxD;
101209
102888
  }
101210
- // TODO - SCORE: Convert dict of geo props to array by district index
101211
102889
  function makeArrayOfGeoProps(s, bLog = false) {
101212
102890
  let geometryByDistrict = [];
101213
102891
  for (let districtID = 1; districtID <= s.state.nDistricts; districtID++) {
@@ -101305,6 +102983,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
101305
102983
  return result;
101306
102984
  };
101307
102985
  Object.defineProperty(exports, "__esModule", { value: true });
102986
+ const DT = __importStar(__webpack_require__(/*! @dra2020/dra-types */ "./node_modules/@dra2020/dra-types/dist/dra-types.js"));
101308
102987
  const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"));
101309
102988
  // PLAN HELPERS
101310
102989
  // Is a "neighbor" in state?
@@ -101332,7 +103011,6 @@ function getDistrict(plan, geoID) {
101332
103011
  }
101333
103012
  exports.getDistrict = getDistrict;
101334
103013
  // WORKING WITH GEOIDS
101335
- // TODO - VFEATURE
101336
103014
  function parseGeoID(geoID) {
101337
103015
  let bVfeature = false;
101338
103016
  // Rewrite vfeature GEOIDs to enable lexical parsing of higher-level parts
@@ -101340,12 +103018,7 @@ function parseGeoID(geoID) {
101340
103018
  // Example: vfeature_39153153ASV_0_28e0bc2c8163e5982e1da2d61e2388a8325c575e
101341
103019
  if (geoID.indexOf('vfeature') >= 0) {
101342
103020
  bVfeature = true;
101343
- // Strip off leading 'vfeature_'
101344
- let parentGeoID = geoID.slice(9);
101345
- // Strip off trailing goo
101346
- const uPos = parentGeoID.indexOf('_');
101347
- parentGeoID = parentGeoID.slice(0, uPos);
101348
- geoID = parentGeoID;
103021
+ geoID = DT.vgeoidToGeoid(geoID);
101349
103022
  }
101350
103023
  const parts = {
101351
103024
  vfeature: bVfeature,
@@ -101353,29 +103026,9 @@ function parseGeoID(geoID) {
101353
103026
  county: geoID.substring(2, 5),
101354
103027
  rest: geoID.slice(5)
101355
103028
  };
101356
- // let l: number = geoID.length;
101357
- // if (l >= 11)
101358
- // {
101359
- // parts['tract'] = geoID.substring(0, 11);
101360
- // }
101361
- // if (l >= 12)
101362
- // {
101363
- // parts['bg'] = geoID.substring(0, 12);
101364
- // }
101365
- // if (l == 15)
101366
- // {
101367
- // parts['block'] = geoID;
101368
- // }
101369
103029
  return parts;
101370
103030
  }
101371
103031
  exports.parseGeoID = parseGeoID;
101372
- // TODO - VFEATURE
101373
- // export function getFIPSFromCountyGeoID(geoID: string): string
101374
- // {
101375
- // const fips = geoID.substring(2, 5);
101376
- // if (isNaN(Number(fips))) console.log("Non-numeric GEOID =", geoID);
101377
- // return fips;
101378
- // }
101379
103032
  function isWaterOnly(geoID) {
101380
103033
  let waterOnlySignature = 'ZZZZZZ';
101381
103034
  if (geoID.indexOf(waterOnlySignature) >= 0)
@@ -102276,113 +103929,6 @@ function formatNumber(n) {
102276
103929
  let p = S.PRECISION;
102277
103930
  return n.toLocaleString('en-US', { minimumFractionDigits: p, maximumFractionDigits: p });
102278
103931
  }
102279
- /* TODO - SCORE: DELETE
102280
- function echoPlanAnalytics(pa: PlanAnalytics): void
102281
- {
102282
- console.log("Plan Analytics:");
102283
- console.log("");
102284
-
102285
- console.log("Requirements:");
102286
- console.log("* Score:", pa.requirements.score);
102287
- console.log("* Metrics:");
102288
- console.log(" - Complete:", pa.requirements.metrics.complete);
102289
- console.log(" - Contiguous:", pa.requirements.metrics.contiguous);
102290
- console.log(" - Free of holes:", pa.requirements.metrics.freeOfHoles);
102291
- console.log(" - Equal population:", pa.requirements.metrics.equalPopulation);
102292
- console.log("* Details:");
102293
- console.log(" - Empty districts:", prepareListItems(pa.requirements.details.emptyDistricts));
102294
- console.log(" - Unassigned features:", prepareListItems(pa.requirements.details.unassignedFeatures));
102295
- console.log(" - Population deviation:", pa.requirements.details.populationDeviation);
102296
- console.log(" - Deviation threshold:", pa.requirements.details.deviationThreshold);
102297
- console.log(" - Discontiguous districts:", prepareListItems(pa.requirements.details.discontiguousDistricts));
102298
- console.log(" - Embedded districts:", prepareListItems(pa.requirements.details.embeddedDistricts));
102299
- console.log("* Datasets:");
102300
- console.log("- Shapes:", pa.requirements.datasets.shapes);
102301
- console.log("- Census:", pa.requirements.datasets.census);
102302
- console.log("- VAP:", pa.requirements.datasets.vap);
102303
- console.log("- Election:", pa.requirements.datasets.election);
102304
- console.log("* Resources:");
102305
- console.log("- State requirements:", pa.requirements.resources.stateReqs);
102306
- console.log("");
102307
-
102308
- console.log("Compactness:");
102309
- console.log("* Score:", pa.compactness.score);
102310
- console.log("* Metrics:");
102311
- console.log(" - Reock:", pa.compactness.metrics.reock);
102312
- console.log(" - Polsby-Popper:", pa.compactness.metrics.polsby);
102313
- console.log("* Details:");
102314
- console.log(" - N/A");
102315
- console.log("* Datasets:");
102316
- console.log("- Shapes:", pa.compactness.datasets.shapes);
102317
- console.log("- Census:", pa.compactness.datasets.census);
102318
- console.log("- VAP:", pa.compactness.datasets.vap);
102319
- console.log("- Election:", pa.compactness.datasets.election);
102320
- console.log("* Resources:");
102321
- console.log("- N/A");
102322
- console.log("");
102323
-
102324
- console.log("Splitting:");
102325
- console.log("* Score:", pa.splitting.score);
102326
- console.log("* Metrics:");
102327
- console.log(" - sqEnt_DCreduced:", pa.splitting.metrics.sqEnt_DCreduced);
102328
- console.log(" - sqEnt_CDreduced:", pa.splitting.metrics.sqEnt_CDreduced);
102329
- console.log("* Details:");
102330
- console.log(" - countiesSplitUnexpectedly:", prepareListItems(pa.splitting.details.countiesSplitUnexpectedly));
102331
- console.log(" - unexpectedAffected:", pa.splitting.details.unexpectedAffected);
102332
- console.log(" - splitVTDs:", pa.splitting.details.splitVTDs);
102333
- console.log("* Datasets:");
102334
- console.log("- Shapes:", pa.splitting.datasets.shapes);
102335
- console.log("- Census:", pa.splitting.datasets.census);
102336
- console.log("- VAP:", pa.splitting.datasets.vap);
102337
- console.log("- Election:", pa.splitting.datasets.election);
102338
- console.log("* Resources:");
102339
- console.log("- N/A");
102340
- console.log("");
102341
-
102342
- console.log("Partisan:");
102343
- console.log("* Score:", pa.partisan.score);
102344
- console.log("* Metrics:");
102345
- console.log(" - sqEnt_DCreduced:", pa.partisan.metrics.partisanBias);
102346
- console.log(" - sqEnt_CDreduced:", pa.partisan.metrics.responsiveness);
102347
- console.log("* Details:");
102348
- console.log(" - N/A");
102349
- console.log("* Datasets:");
102350
- console.log("- Shapes:", pa.partisan.datasets.shapes);
102351
- console.log("- Census:", pa.partisan.datasets.census);
102352
- console.log("- VAP:", pa.partisan.datasets.vap);
102353
- console.log("- Election:", pa.partisan.datasets.election);
102354
- console.log("* Resources:");
102355
- console.log(" - Plan Score:", pa.partisan.resources.planScore);
102356
- console.log("");
102357
-
102358
- console.log("Minority:");
102359
- console.log("* Score:", pa.minority.score);
102360
- console.log("* Metrics:");
102361
- console.log(" - nBlack37to50:", pa.minority.metrics.nBlack37to50);
102362
- console.log(" - nBlackMajority:", pa.minority.metrics.nBlackMajority);
102363
- console.log(" - nHispanic37to50:", pa.minority.metrics.nHispanic37to50);
102364
- console.log(" - nHispanicMajority:", pa.minority.metrics.nHispanicMajority);
102365
- console.log(" - nPacific37to50:", pa.minority.metrics.nPacific37to50);
102366
- console.log(" - nPacificMajority:", pa.minority.metrics.nPacificMajority);
102367
- console.log(" - nAsian37to50:", pa.minority.metrics.nAsian37to50);
102368
- console.log(" - nAsianMajority:", pa.minority.metrics.nAsianMajority);
102369
- console.log(" - nNative37to50:", pa.minority.metrics.nNative37to50);
102370
- console.log(" - nNativeMajority:", pa.minority.metrics.nNativeMajority);
102371
- console.log(" - nMinority37to50:", pa.minority.metrics.nMinority37to50);
102372
- console.log(" - nMinorityMajority:", pa.minority.metrics.nMinorityMajority);
102373
- console.log("* Details:");
102374
- console.log(" - VAP:", pa.minority.details.vap);
102375
- console.log(" - comboCategoroes:", pa.minority.details.comboCategories);
102376
- console.log("* Datasets:");
102377
- console.log("- Shapes:", pa.minority.datasets.shapes);
102378
- console.log("- Census:", pa.minority.datasets.census);
102379
- console.log("- VAP:", pa.minority.datasets.vap);
102380
- console.log("- Election:", pa.minority.datasets.election);
102381
- console.log("* Resources:");
102382
- console.log("- N/A");
102383
- console.log("");
102384
- }
102385
- */
102386
103932
  function echoDistrictStatistics(ds) {
102387
103933
  console.log("District Statistics:");
102388
103934
  for (let row of ds.table) {
@@ -102493,6 +104039,17 @@ module.exports = require("assert");
102493
104039
 
102494
104040
  /***/ }),
102495
104041
 
104042
+ /***/ "crypto":
104043
+ /*!*************************!*\
104044
+ !*** external "crypto" ***!
104045
+ \*************************/
104046
+ /*! no static exports found */
104047
+ /***/ (function(module, exports) {
104048
+
104049
+ module.exports = require("crypto");
104050
+
104051
+ /***/ }),
104052
+
102496
104053
  /***/ "fs":
102497
104054
  /*!*********************!*\
102498
104055
  !*** external "fs" ***!