@dra2020/district-analytics 14.1.0 → 14.1.3

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.
@@ -46,6 +46,7 @@ exports.AnalyticsSession = void 0;
46
46
  const baseclient_1 = __webpack_require__(/*! @dra2020/baseclient */ "@dra2020/baseclient");
47
47
  // import * as DT from '@dra2020/dra-types';
48
48
  const Score = __importStar(__webpack_require__(/*! @dra2020/dra-score */ "@dra2020/dra-score"));
49
+ const dra_analytics_1 = __webpack_require__(/*! @dra2020/dra-analytics */ "@dra2020/dra-analytics");
49
50
  const preprocess_1 = __webpack_require__(/*! ./preprocess */ "./src/preprocess.ts");
50
51
  const analyze_1 = __webpack_require__(/*! ./analyze */ "./src/analyze.ts");
51
52
  const score_1 = __webpack_require__(/*! ./score */ "./src/score.ts");
@@ -53,6 +54,7 @@ const results_1 = __webpack_require__(/*! ./results */ "./src/results.ts");
53
54
  const results_2 = __webpack_require__(/*! ./results */ "./src/results.ts");
54
55
  const minority_1 = __webpack_require__(/*! ./minority */ "./src/minority.ts");
55
56
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
57
+ const M = __importStar(__webpack_require__(/*! ./minority */ "./src/minority.ts"));
56
58
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
57
59
  // import * as S from './settings';
58
60
  class AnalyticsSession {
@@ -106,9 +108,61 @@ class AnalyticsSession {
106
108
  return false;
107
109
  (0, preprocess_1.doPreprocessData)(this, bLog);
108
110
  (0, analyze_1.doAnalyzeDistricts)(this, bLog);
111
+ // This does a little stuff that didn't get factored out into dra-score and then dra-analytics
109
112
  (0, analyze_1.doAnalyzePlan)(this, bLog);
113
+ // THE MAIN ANALYTICS ARE NEXT
114
+ // Even though we don't save the profile (as I thought we would),
115
+ // we allow it to be exported, so keep generating it, and use it
116
+ // to gather the inputs to new analytics (as well as the legacy).
110
117
  this._profile = (0, score_1.profilePlan)(this, bLog);
111
- this._scorecard = (0, score_1.scorePlan)(this, this._profile, bLog, overridesJSON);
118
+ let legacyScorecard = {};
119
+ let legacyScorecardAlt = {};
120
+ let newScorecard = {};
121
+ // LEGACY - Run legacy analytics
122
+ if (this.config.legacyanalytics) {
123
+ if (bLog)
124
+ console.log("Running legacy analytics ...");
125
+ legacyScorecard = (0, score_1.scorePlan)(this, this._profile, bLog, overridesJSON);
126
+ }
127
+ // Construct a new/alternate scorecard
128
+ if (this.config.newanalytics) {
129
+ if (bLog)
130
+ console.log("Running new analytics ...");
131
+ newScorecard = (0, score_1.computeMetrics)(this._profile, this.getGoodShapes(), bLog); // w/o ratings
132
+ newScorecard = (0, score_1.rateKeyDimensions)(newScorecard, this._profile, bLog); // w/ ratings
133
+ legacyScorecardAlt = (0, score_1.thunkScorecard)(newScorecard, bLog);
134
+ // Add minority notes
135
+ legacyScorecardAlt.minority.details['majorityMinority'] = M.getMajorityMinority(this);
136
+ legacyScorecardAlt.minority.details['vraPreclearance'] = M.getVRASection5(this);
137
+ // Compare the new & legacy scorecards
138
+ (0, score_1.compareScorecards)(legacyScorecardAlt, legacyScorecard, bLog);
139
+ }
140
+ // Use the new scorecard, after creating it
141
+ this._scorecard = (this.config.newanalytics) ? legacyScorecardAlt : legacyScorecard;
142
+ // Post-scorecard housekeeping - copied from scorePlan()
143
+ if (this.config.newanalytics) {
144
+ // Before returning, create a dummy population deviation test, for
145
+ // doHasEqualPopulations() to use later.This is preserving the old calling sequence.
146
+ let test = this.getTest(4 /* PopulationDeviation */);
147
+ // Get the raw population deviation
148
+ const popDev = this._scorecard.populationDeviation.raw;
149
+ // Populate the test entry
150
+ test['score'] = popDev;
151
+ test['details'] = { 'maxDeviation': this._scorecard.populationDeviation.notes['maxDeviation'] };
152
+ // Populate the N+1 summary "district" in district.statistics
153
+ let totalPop = this.districts.table.totalPop;
154
+ let popDevPct = this.districts.table.popDevPct;
155
+ let totalVAP = this.districts.table.totalVAP;
156
+ const summaryRow = this.districts.numberOfRows() - 1;
157
+ totalPop[summaryRow] = this._profile.population.targetSize;
158
+ popDevPct[summaryRow] = popDev;
159
+ totalVAP[summaryRow] = Math.round(totalVAP[summaryRow] / this._profile.nDistricts);
160
+ // Added w/ new scorecard
161
+ // Use 'roughly' equal population from dra-analytics
162
+ let test2 = this.getTest(3 /* EqualPopulation */);
163
+ test2['score'] = newScorecard.populationDeviation.roughlyEqual;
164
+ }
165
+ // END main analytics
112
166
  (0, results_1.doAnalyzePostProcessing)(this, bLog);
113
167
  }
114
168
  catch (e) {
@@ -118,6 +172,29 @@ class AnalyticsSession {
118
172
  }
119
173
  return true;
120
174
  }
175
+ getGoodShapes() {
176
+ const rawShapes = this.districts.getDistrictShapes();
177
+ // Filter the real shapes & throw everything else away
178
+ let goodShapes = {};
179
+ goodShapes['type'] = "FeatureCollection";
180
+ goodShapes['features'] = [];
181
+ for (let i = 0; i < rawShapes.features.length; i++) {
182
+ const shape = rawShapes.features[i];
183
+ if (isAShape(shape)) {
184
+ const d = baseclient_1.Poly.polyDescribe(shape);
185
+ let f = {
186
+ type: 'Feature',
187
+ properties: { districtID: `${i + 1}` },
188
+ geometry: {
189
+ type: (d.npoly > 1) ? 'MultiPolygon' : 'Polygon',
190
+ coordinates: shape.geometry.coordinates
191
+ }
192
+ };
193
+ goodShapes.features.push(f);
194
+ }
195
+ }
196
+ return goodShapes;
197
+ }
121
198
  // 11-03-2020 - Added for racially polarized voting analysis
122
199
  // NOTE - This assumes that analyzePlan() has been run!
123
200
  analyzeRacialPolarization(districtID, groups, bLog = false) {
@@ -190,15 +267,29 @@ class AnalyticsSession {
190
267
  // Return a pointer to the the test entry for this test
191
268
  return this.tests[testID];
192
269
  }
270
+ // LEGACY - Threshold defined in dra-analytics for new analytics
193
271
  // NOTE - Not sure why this has to be up here ...
194
272
  populationDeviationThreshold() {
195
- // NOTE - This assumes the plan has been profiled
196
- const scorer = new Score.Scorer();
197
- const threshold = scorer.populationDeviationThreshold(this.legislativeDistricts); // TODO - 2020
273
+ let threshold;
274
+ if (this.config.legacyanalytics && !this.config.newanalytics) {
275
+ // NOTE - This assumes the plan has been profiled
276
+ const scorer = new Score.Scorer();
277
+ threshold = scorer.populationDeviationThreshold(this.legislativeDistricts); // TODO - 2020
278
+ }
279
+ else {
280
+ threshold = dra_analytics_1.Rate.popdevThreshold(this.legislativeDistricts);
281
+ }
198
282
  return threshold;
199
283
  }
200
284
  }
201
285
  exports.AnalyticsSession = AnalyticsSession;
286
+ function isAShape(poly) {
287
+ if (poly == null)
288
+ return false;
289
+ if (baseclient_1.Poly.polyNull(poly))
290
+ return false;
291
+ return poly.geometry && poly.geometry.coordinates && !U.isArrayEmpty(poly.geometry.coordinates);
292
+ }
202
293
 
203
294
 
204
295
  /***/ }),
@@ -238,7 +329,8 @@ const dra_analytics_1 = __webpack_require__(/*! @dra2020/dra-analytics */ "@dra2
238
329
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
239
330
  const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"));
240
331
  const compact_1 = __webpack_require__(/*! ./compact */ "./src/compact.ts");
241
- const political_1 = __webpack_require__(/*! ./political */ "./src/political.ts");
332
+ const dra_analytics_2 = __webpack_require__(/*! @dra2020/dra-analytics */ "@dra2020/dra-analytics");
333
+ // import { fptpWin } from './political'
242
334
  // DEBUG COUNTERS
243
335
  let nMissingDataset = 0;
244
336
  let nMissingProperty = 0;
@@ -472,7 +564,7 @@ class Districts {
472
564
  demPct = demVotes / totVotes;
473
565
  repPct = repVotes / totVotes;
474
566
  othPct = othVotes / totVotes;
475
- DemSeat = (0, political_1.fptpWin)(demPct);
567
+ DemSeat = dra_analytics_2.Partisan.fptpWin(demPct);
476
568
  }
477
569
  // Total minority VAP
478
570
  let minorityPop = totalVAP - whitePop;
@@ -1442,6 +1534,7 @@ function isAShape(poly) {
1442
1534
  return poly.geometry && poly.geometry.coordinates && !U.isArrayEmpty(poly.geometry.coordinates);
1443
1535
  }
1444
1536
  // SCORE KIWYSI COMPACTNESS
1537
+ // LEGACY
1445
1538
  function scoreKIWYSICompactness(s, bLog = false) {
1446
1539
  const rawShapes = s.districts.getDistrictShapes();
1447
1540
  // Filter the real shapes & throw everything else away
@@ -1521,17 +1614,20 @@ function doHasEqualPopulations(s, bLog = false) {
1521
1614
  let popDevTest = s.getTest(4 /* PopulationDeviation */);
1522
1615
  const popDevPct = popDevTest['score'];
1523
1616
  const popDevNormalized = popDevTest['normalizedScore'];
1524
- // 09-19-2020 - Added to catch edge case of only one non-empty district
1525
- const p = s._profile;
1526
- const totPopByDistrict = p.population.byDistrict.filter(x => x > 0);
1527
- const bTwoOrMoreDistricts = (totPopByDistrict.length > 1) ? true : false;
1528
- // Populate the test entry
1529
- if (bTwoOrMoreDistricts && (popDevNormalized > 0)) {
1530
- test['score'] = true;
1531
- }
1532
- else {
1533
- test['score'] = false;
1534
- }
1617
+ // LEGACY - Has 'roughly' equal populations is calculated in dra-analytics
1618
+ if (s.config.legacyanalytics && !s.config.newanalytics) {
1619
+ // 09-19-2020 - Added to catch edge case of only one non-empty district
1620
+ const p = s._profile;
1621
+ const totPopByDistrict = p.population.byDistrict.filter(x => x > 0);
1622
+ const bTwoOrMoreDistricts = (totPopByDistrict.length > 1) ? true : false;
1623
+ // Populate the test entry
1624
+ if (bTwoOrMoreDistricts && (popDevNormalized > 0)) {
1625
+ test['score'] = true;
1626
+ }
1627
+ else {
1628
+ test['score'] = false;
1629
+ }
1630
+ } // end
1535
1631
  test['details']['deviation'] = popDevPct;
1536
1632
  test['details']['thresholds'] = popDevTest['details']['scale'];
1537
1633
  // Populate the N+1 summary "district" in district.statistics
@@ -1566,7 +1662,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
1566
1662
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
1567
1663
  };
1568
1664
  Object.defineProperty(exports, "__esModule", ({ value: true }));
1569
- exports.uncertaintyOfMembership = exports.effectiveSplits = exports.isAntimajoritarian = exports.ratePartisanBias = exports.inferSelectedMinority = exports.fieldForFeature = exports.geoIDForFeature = void 0;
1665
+ exports.uncertaintyOfMembership = exports.effectiveSplits = exports.avgSVError = exports.isAntimajoritarian = exports.ratePartisanBias = exports.estSeatProbability = exports.inferSelectedMinority = exports.fieldForFeature = exports.geoIDForFeature = void 0;
1570
1666
  __exportStar(__webpack_require__(/*! ./_api */ "./src/_api.ts"), exports);
1571
1667
  var _data_1 = __webpack_require__(/*! ./_data */ "./src/_data.ts");
1572
1668
  Object.defineProperty(exports, "geoIDForFeature", ({ enumerable: true, get: function () { return _data_1.geoIDForFeature; } }));
@@ -1577,8 +1673,10 @@ __exportStar(__webpack_require__(/*! ./types */ "./src/types.ts"), exports);
1577
1673
  __exportStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"), exports);
1578
1674
  // Re-export RPV types and COI splitting functions
1579
1675
  const dra_analytics_1 = __webpack_require__(/*! @dra2020/dra-analytics */ "@dra2020/dra-analytics");
1676
+ exports.estSeatProbability = dra_analytics_1.Partisan.estSeatProbability;
1580
1677
  exports.ratePartisanBias = dra_analytics_1.Rate.ratePartisanBias;
1581
1678
  exports.isAntimajoritarian = dra_analytics_1.Rate.isAntimajoritarian;
1679
+ exports.avgSVError = dra_analytics_1.Rate.avgSVError;
1582
1680
  exports.effectiveSplits = dra_analytics_1.Splitting.effectiveSplits;
1583
1681
  exports.uncertaintyOfMembership = dra_analytics_1.Splitting.uncertaintyOfMembership;
1584
1682
 
@@ -1641,28 +1739,6 @@ exports.doAnalyzeRacialPolarization = doAnalyzeRacialPolarization;
1641
1739
  // 11-18-2020 - Moved RPV to racial-voting package.
1642
1740
 
1643
1741
 
1644
- /***/ }),
1645
-
1646
- /***/ "./src/political.ts":
1647
- /*!**************************!*\
1648
- !*** ./src/political.ts ***!
1649
- \**************************/
1650
- /***/ ((__unused_webpack_module, exports) => {
1651
-
1652
-
1653
- //
1654
- // FAIR/PROPORTIONAL
1655
- //
1656
- Object.defineProperty(exports, "__esModule", ({ value: true }));
1657
- exports.fptpWin = void 0;
1658
- function fptpWin(demPct) {
1659
- // Vote shares should be fractions in the range [0.0 – 1.0]
1660
- //assert((demPct <= 1.0) && (demPct >= 0.0));
1661
- return ((demPct > 0.5) ? 1 : 0);
1662
- }
1663
- exports.fptpWin = fptpWin;
1664
-
1665
-
1666
1742
  /***/ }),
1667
1743
 
1668
1744
  /***/ "./src/preprocess.ts":
@@ -2042,6 +2118,7 @@ function doAnalyzePostProcessing(s, bLog = false) {
2042
2118
  scorecard.splitting.details['countiesWithSplits'] = simpleSplits['details']['countiesWithSplits'];
2043
2119
  // NOTE - Add split precincts in dra-client directly
2044
2120
  // Derive secondary tests
2121
+ // Note - The only secondary test is 'roughly equal population (true/false)
2045
2122
  (0, analyze_1.doDeriveSecondaryTests)(s, bLog);
2046
2123
  // Toggle the semaphore, so postprocessing isn't for both the testlog & scorecard
2047
2124
  s.bPostProcessingDone = true;
@@ -2081,11 +2158,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
2081
2158
  return result;
2082
2159
  };
2083
2160
  Object.defineProperty(exports, "__esModule", ({ value: true }));
2084
- exports.scorePlan = exports.getStatewideDemographics = exports.profilePlan = void 0;
2161
+ exports.compareScorecards = exports.thunkScorecard = exports.rateKeyDimensions = exports.computeMetrics = exports.scorePlan = exports.getStatewideDemographics = exports.profilePlan = void 0;
2085
2162
  const Score = __importStar(__webpack_require__(/*! @dra2020/dra-score */ "@dra2020/dra-score"));
2086
2163
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
2087
2164
  const M = __importStar(__webpack_require__(/*! ./minority */ "./src/minority.ts"));
2088
2165
  const C = __importStar(__webpack_require__(/*! ./compact */ "./src/compact.ts"));
2166
+ const dra_analytics_1 = __webpack_require__(/*! @dra2020/dra-analytics */ "@dra2020/dra-analytics");
2089
2167
  // PROFILE A PLAN
2090
2168
  const KEEP_DECIMALS = 6;
2091
2169
  function profilePlan(s, bLog = false) {
@@ -2197,26 +2275,30 @@ function getStatewideDemographics(s, bLog = false) {
2197
2275
  return demographics;
2198
2276
  }
2199
2277
  exports.getStatewideDemographics = getStatewideDemographics;
2200
- // SCORE A PLAN
2278
+ // SCORE A PLAN - Legacy using dra-score
2279
+ // LEGACY
2201
2280
  function scorePlan(s, p, bLog = false, overridesJSON) {
2202
2281
  let scorer = new Score.Scorer();
2203
2282
  const scorecard = scorer.score(p, overridesJSON);
2204
- // Before returning, create a dummy population deviation test, for
2205
- // doHasEqualPopulations() to use later.This is preserving the old calling sequence.
2206
- let test = s.getTest(4 /* PopulationDeviation */);
2207
- // Get the raw population deviation
2208
- const popDev = scorecard.populationDeviation.raw;
2209
- // Populate the test entry
2210
- test['score'] = popDev;
2211
- test['details'] = { 'maxDeviation': scorecard.populationDeviation.notes['maxDeviation'] };
2212
- // Populate the N+1 summary "district" in district.statistics
2213
- let totalPop = s.districts.table.totalPop;
2214
- let popDevPct = s.districts.table.popDevPct;
2215
- let totalVAP = s.districts.table.totalVAP;
2216
- const summaryRow = s.districts.numberOfRows() - 1;
2217
- totalPop[summaryRow] = p.population.targetSize;
2218
- popDevPct[summaryRow] = popDev;
2219
- totalVAP[summaryRow] = Math.round(totalVAP[summaryRow] / p.nDistricts);
2283
+ // LEGACY POST-SCORECARD HOUSEKEEPING
2284
+ if (s.config.legacyanalytics && !s.config.newanalytics) {
2285
+ // Before returning, create a dummy population deviation test, for
2286
+ // doHasEqualPopulations() to use later.This is preserving the old calling sequence.
2287
+ let test = s.getTest(4 /* PopulationDeviation */);
2288
+ // Get the raw population deviation
2289
+ const popDev = scorecard.populationDeviation.raw;
2290
+ // Populate the test entry
2291
+ test['score'] = popDev;
2292
+ test['details'] = { 'maxDeviation': scorecard.populationDeviation.notes['maxDeviation'] };
2293
+ // Populate the N+1 summary "district" in district.statistics
2294
+ let totalPop = s.districts.table.totalPop;
2295
+ let popDevPct = s.districts.table.popDevPct;
2296
+ let totalVAP = s.districts.table.totalVAP;
2297
+ const summaryRow = s.districts.numberOfRows() - 1;
2298
+ totalPop[summaryRow] = p.population.targetSize;
2299
+ popDevPct[summaryRow] = popDev;
2300
+ totalVAP[summaryRow] = Math.round(totalVAP[summaryRow] / p.nDistricts);
2301
+ } // end
2220
2302
  // Add minority notes
2221
2303
  scorecard.minority.details['majorityMinority'] = M.getMajorityMinority(s);
2222
2304
  scorecard.minority.details['vraPreclearance'] = M.getVRASection5(s);
@@ -2241,6 +2323,432 @@ function scorePlan(s, p, bLog = false, overridesJSON) {
2241
2323
  return scorecard;
2242
2324
  }
2243
2325
  exports.scorePlan = scorePlan;
2326
+ // SCORE A PLAN - New using dra-analytics
2327
+ function computeMetrics(p, districtShapes, bLog = false) {
2328
+ if (bLog)
2329
+ console.log("Computing metrics ...");
2330
+ const bLegislative = p.bStateLeg;
2331
+ // Calculate bias & responsiveness metrics ...
2332
+ const byDistrictVf = p.partisanship.byDistrict;
2333
+ const statewideVf = p.partisanship.statewide;
2334
+ let _pS = dra_analytics_1.Partisan.makePartisanScorecard(statewideVf, byDistrictVf, bLog);
2335
+ // Calculate minority representation metrics ...
2336
+ const statewideDemos = p.demographics.statewide;
2337
+ const byDistrictDemos = p.demographics.byDistrict;
2338
+ let _mS = dra_analytics_1.Minority.makeMinorityScorecard(statewideDemos, byDistrictDemos, bLog);
2339
+ // Calculate compactness metrics ...
2340
+ let _cS = dra_analytics_1.Compactness.makeCompactnessScorecard(districtShapes, bLog);
2341
+ // Calculate county-district splitting metrics ...
2342
+ const CxD = p.counties;
2343
+ const _sS = dra_analytics_1.Splitting.makeSplittingScorecard(CxD, bLog);
2344
+ // Calculate population deviation-related metrics ...
2345
+ const totPopByDistrict = p.population.byDistrict;
2346
+ const targetSize = p.population.targetSize;
2347
+ const _pdS = dra_analytics_1.Equal.makePopulationScorecard(totPopByDistrict, targetSize, bLegislative, bLog);
2348
+ const details = {};
2349
+ // Assemble the pieces into new scorecard
2350
+ const scorecard = {
2351
+ partisan: _pS,
2352
+ minority: _mS,
2353
+ compactness: _cS,
2354
+ splitting: _sS,
2355
+ populationDeviation: _pdS,
2356
+ details: details,
2357
+ scratchpad: {} // Hack to pass legacy values between processing steps
2358
+ };
2359
+ return scorecard;
2360
+ }
2361
+ exports.computeMetrics = computeMetrics;
2362
+ function rateKeyDimensions(scorecard, p, bLog = false) {
2363
+ if (bLog)
2364
+ console.log("Rating key dimensions ...");
2365
+ const bLegislative = p.bStateLeg;
2366
+ // Rate proportionality
2367
+ const statewideVf = p.partisanship.statewide;
2368
+ const Sf = scorecard.partisan.bias.estSf;
2369
+ scorecard.partisan.bias.score = dra_analytics_1.Rate.rateProportionality(scorecard.partisan.bias.deviation, statewideVf, Sf);
2370
+ // Rate competititveness
2371
+ scorecard.partisan.responsiveness.score = dra_analytics_1.Rate.rateCompetitiveness(scorecard.partisan.responsiveness.cDf);
2372
+ // Rate minority representation
2373
+ const rawOd = scorecard.minority.opportunityDistricts;
2374
+ const pOd = scorecard.minority.proportionalOpportunities;
2375
+ const rawCd = scorecard.minority.coalitionDistricts;
2376
+ const pCd = scorecard.minority.proportionalCoalitions;
2377
+ scorecard.minority.score = dra_analytics_1.Rate.rateMinorityRepresentation(rawOd, pOd, rawCd, pCd);
2378
+ // Rate compactness
2379
+ const avgReock = scorecard.compactness.avgReock;
2380
+ const avgPolsby = scorecard.compactness.avgPolsby;
2381
+ const reockRating = dra_analytics_1.Rate.rateReock(avgReock);
2382
+ const polsbyRating = dra_analytics_1.Rate.ratePolsby(avgPolsby);
2383
+ scorecard.compactness.score = dra_analytics_1.Rate.rateCompactness(reockRating, polsbyRating);
2384
+ // Rate county- & district-splitting
2385
+ const rawCountySplitting = scorecard.splitting.county;
2386
+ const rawDistrictSplitting = scorecard.splitting.district;
2387
+ const nCounties = p.nCounties;
2388
+ const nDistricts = p.nDistricts;
2389
+ const countyRating = dra_analytics_1.Rate.rateCountySplitting(rawCountySplitting, nCounties, nDistricts, bLegislative);
2390
+ const districtRating = dra_analytics_1.Rate.rateDistrictSplitting(rawDistrictSplitting, bLegislative);
2391
+ const unadjusted = dra_analytics_1.Rate.rateSplitting(countyRating, districtRating);
2392
+ scorecard.splitting.score = dra_analytics_1.Rate.adjustSplittingRating(unadjusted, rawCountySplitting, rawDistrictSplitting);
2393
+ // Rate population deviation
2394
+ const rawDeviation = scorecard.populationDeviation.deviation;
2395
+ scorecard.populationDeviation.score = dra_analytics_1.Rate.ratePopulationDeviation(rawDeviation, bLegislative);
2396
+ // Squirrel away normalized compactness & splitting ratings for the legacy scorecard
2397
+ const keep = {
2398
+ reockScore: reockRating,
2399
+ polsbyScore: polsbyRating,
2400
+ countyScore: countyRating,
2401
+ districtScore: districtRating
2402
+ };
2403
+ scorecard.scratchpad = keep;
2404
+ return scorecard;
2405
+ }
2406
+ exports.rateKeyDimensions = rateKeyDimensions;
2407
+ function thunkScorecard(newScorecard, bLog = false) {
2408
+ if (bLog)
2409
+ console.log("Thunking new scorecard into legacy structure ...");
2410
+ const scratchpad = newScorecard.scratchpad;
2411
+ // Partisan scorecard
2412
+ const pS = U.deepCopy(newScorecard.partisan);
2413
+ // Minority scorecard
2414
+ const mS = U.deepCopy(newScorecard.minority);
2415
+ // Compactness scorecard
2416
+ const reockM = {
2417
+ raw: newScorecard.compactness.avgReock,
2418
+ normalized: scratchpad.reockScore,
2419
+ notes: {}
2420
+ };
2421
+ const polsbyM = {
2422
+ raw: newScorecard.compactness.avgPolsby,
2423
+ normalized: scratchpad.polsbyScore,
2424
+ notes: {}
2425
+ };
2426
+ let cS = {
2427
+ score: newScorecard.compactness.score,
2428
+ reock: reockM,
2429
+ polsby: polsbyM,
2430
+ details: U.deepCopy(newScorecard.compactness.details)
2431
+ };
2432
+ // Relocate byDistrict compactness #'s
2433
+ cS.details.byDistrict = U.deepCopy(newScorecard.compactness.byDistrict);
2434
+ // Add KIWYSI compactness score
2435
+ cS.details['kiwysi'] = newScorecard.compactness.avgKWIWYSI;
2436
+ // Splitting scorecard
2437
+ const countyM = {
2438
+ raw: newScorecard.splitting.county,
2439
+ normalized: scratchpad.countyScore,
2440
+ notes: {}
2441
+ };
2442
+ const districtM = {
2443
+ raw: newScorecard.splitting.district,
2444
+ normalized: scratchpad.districtScore,
2445
+ notes: {}
2446
+ };
2447
+ const sS = {
2448
+ score: newScorecard.splitting.score,
2449
+ county: countyM,
2450
+ district: districtM,
2451
+ details: U.deepCopy(newScorecard.splitting.details)
2452
+ };
2453
+ // Population (equality) scorecard
2454
+ const pdM = {
2455
+ raw: newScorecard.populationDeviation.deviation,
2456
+ normalized: newScorecard.populationDeviation.score,
2457
+ notes: newScorecard.populationDeviation.notes
2458
+ };
2459
+ const pdS = pdM;
2460
+ const scorecard = {
2461
+ partisan: pS,
2462
+ minority: mS,
2463
+ compactness: cS,
2464
+ splitting: sS,
2465
+ populationDeviation: pdS,
2466
+ details: newScorecard.details
2467
+ };
2468
+ return scorecard;
2469
+ }
2470
+ exports.thunkScorecard = thunkScorecard;
2471
+ function compareScorecards(altLegacyScorecard, legacyScorecard, bLog = false) {
2472
+ if (bLog)
2473
+ console.log("Comparing new & legacy scorecards ...");
2474
+ // A pretty loose tolerance, because we're not trimming values in the new analytics
2475
+ const DECIMAL_PLACES = 2;
2476
+ const DEFAULT_TOLERANCE = toleranceFn(DECIMAL_PLACES);
2477
+ // COMPARE PARTISAN SCORECARD
2478
+ // Compare BIAS section
2479
+ matchFloats("bestS", altLegacyScorecard.partisan.bias.bestS, legacyScorecard.partisan.bias.bestS, DEFAULT_TOLERANCE);
2480
+ matchFloats("bestSf", altLegacyScorecard.partisan.bias.bestSf, legacyScorecard.partisan.bias.bestSf, DEFAULT_TOLERANCE);
2481
+ matchFloats("estS", altLegacyScorecard.partisan.bias.estS, legacyScorecard.partisan.bias.estS, DEFAULT_TOLERANCE);
2482
+ matchFloats("estSf", altLegacyScorecard.partisan.bias.estSf, legacyScorecard.partisan.bias.estSf, DEFAULT_TOLERANCE);
2483
+ matchFloats("deviation", altLegacyScorecard.partisan.bias.deviation, legacyScorecard.partisan.bias.deviation, DEFAULT_TOLERANCE);
2484
+ matchInts("proportionality/score", altLegacyScorecard.partisan.bias.score, legacyScorecard.partisan.bias.score);
2485
+ matchFloats("tOf", altLegacyScorecard.partisan.bias.tOf, legacyScorecard.partisan.bias.tOf, DEFAULT_TOLERANCE);
2486
+ matchFloats("fptpS", altLegacyScorecard.partisan.bias.fptpS, legacyScorecard.partisan.bias.fptpS, DEFAULT_TOLERANCE);
2487
+ matchFloats("bS50", altLegacyScorecard.partisan.bias.bS50, legacyScorecard.partisan.bias.bS50, DEFAULT_TOLERANCE);
2488
+ matchFloats("deviation", altLegacyScorecard.partisan.bias.deviation, legacyScorecard.partisan.bias.deviation, DEFAULT_TOLERANCE);
2489
+ matchUndefinableFloats("decl", altLegacyScorecard.partisan.bias.decl, legacyScorecard.partisan.bias.decl, toleranceFn(1));
2490
+ let rvPointsAlt = altLegacyScorecard.partisan.bias.rvPoints;
2491
+ let rvPoints = legacyScorecard.partisan.bias.rvPoints;
2492
+ if (matchUndefinedness("rvPoints", rvPointsAlt, rvPoints)) {
2493
+ rvPointsAlt = rvPointsAlt;
2494
+ rvPoints = rvPoints;
2495
+ matchFloats("rvPoints/Sb", rvPointsAlt.Sb, rvPoints.Sb, DEFAULT_TOLERANCE);
2496
+ matchFloats("rvPoints/Ra", rvPointsAlt.Ra, rvPoints.Ra, DEFAULT_TOLERANCE);
2497
+ matchFloats("rvPoints/Rb", rvPointsAlt.Rb, rvPoints.Rb, DEFAULT_TOLERANCE);
2498
+ matchFloats("rvPoints/Va", rvPointsAlt.Va, rvPoints.Va, DEFAULT_TOLERANCE);
2499
+ matchFloats("rvPoints/Vb", rvPointsAlt.Vb, rvPoints.Vb, DEFAULT_TOLERANCE);
2500
+ }
2501
+ matchFloats("gSym", altLegacyScorecard.partisan.bias.gSym, legacyScorecard.partisan.bias.gSym, DEFAULT_TOLERANCE);
2502
+ matchUndefinableFloats("gamma", altLegacyScorecard.partisan.bias.gamma, legacyScorecard.partisan.bias.gamma, DEFAULT_TOLERANCE);
2503
+ matchFloats("eG", altLegacyScorecard.partisan.bias.eG, legacyScorecard.partisan.bias.eG, DEFAULT_TOLERANCE);
2504
+ matchUndefinableFloats("bSV", altLegacyScorecard.partisan.bias.bSV, legacyScorecard.partisan.bias.bSV, DEFAULT_TOLERANCE);
2505
+ matchFloats("prop", altLegacyScorecard.partisan.bias.prop, legacyScorecard.partisan.bias.prop, DEFAULT_TOLERANCE);
2506
+ matchFloats("mMs", altLegacyScorecard.partisan.bias.mMs, legacyScorecard.partisan.bias.mMs, DEFAULT_TOLERANCE);
2507
+ matchFloats("mMd", altLegacyScorecard.partisan.bias.mMd, legacyScorecard.partisan.bias.mMd, DEFAULT_TOLERANCE);
2508
+ matchUndefinableFloats("lO", altLegacyScorecard.partisan.bias.lO, legacyScorecard.partisan.bias.lO, DEFAULT_TOLERANCE);
2509
+ // Compare Impact section
2510
+ matchFloats("unearnedS", altLegacyScorecard.partisan.impact.unearnedS, legacyScorecard.partisan.impact.unearnedS, DEFAULT_TOLERANCE);
2511
+ // Note - We don't use the impact score, so we don't compute it in the new scorecard.
2512
+ // matchInts("impact/score", altLegacyScorecard.partisan.impact.score as number, legacyScorecard.partisan.impact.score);
2513
+ // Compare Responsiveness section
2514
+ matchUndefinableFloats("bigR", altLegacyScorecard.partisan.responsiveness.bigR, legacyScorecard.partisan.responsiveness.bigR, DEFAULT_TOLERANCE);
2515
+ matchUndefinableFloats("littleR", altLegacyScorecard.partisan.responsiveness.littleR, legacyScorecard.partisan.responsiveness.littleR, DEFAULT_TOLERANCE);
2516
+ matchUndefinableFloats("mIR", altLegacyScorecard.partisan.responsiveness.mIR, legacyScorecard.partisan.responsiveness.mIR, DEFAULT_TOLERANCE);
2517
+ matchFloats("rD", altLegacyScorecard.partisan.responsiveness.rD, legacyScorecard.partisan.responsiveness.rD, DEFAULT_TOLERANCE);
2518
+ matchFloats("rDf", altLegacyScorecard.partisan.responsiveness.rDf, legacyScorecard.partisan.responsiveness.rDf, DEFAULT_TOLERANCE);
2519
+ matchFloats("cSimple", altLegacyScorecard.partisan.responsiveness.cSimple, legacyScorecard.partisan.responsiveness.cSimple, DEFAULT_TOLERANCE);
2520
+ matchFloats("cD", altLegacyScorecard.partisan.responsiveness.cD, legacyScorecard.partisan.responsiveness.cD, DEFAULT_TOLERANCE);
2521
+ matchFloats("cDf", altLegacyScorecard.partisan.responsiveness.cDf, legacyScorecard.partisan.responsiveness.cDf, DEFAULT_TOLERANCE);
2522
+ matchInts("competitiveness/score", altLegacyScorecard.partisan.responsiveness.score, legacyScorecard.partisan.responsiveness.score);
2523
+ matchPointArrays("dSVpoints", altLegacyScorecard.partisan.dSVpoints, legacyScorecard.partisan.dSVpoints, DEFAULT_TOLERANCE);
2524
+ matchPointArrays("rSVpoints", altLegacyScorecard.partisan.rSVpoints, legacyScorecard.partisan.rSVpoints, DEFAULT_TOLERANCE);
2525
+ matchUndefinableFloats("averageDVf", altLegacyScorecard.partisan.averageDVf, legacyScorecard.partisan.averageDVf, DEFAULT_TOLERANCE);
2526
+ matchUndefinableFloats("averageRVf", altLegacyScorecard.partisan.averageRVf, legacyScorecard.partisan.averageRVf, DEFAULT_TOLERANCE);
2527
+ matchDicts("partisan/details", altLegacyScorecard.partisan.details, legacyScorecard.partisan.details);
2528
+ // COMPARE MINORITY SCORECARD
2529
+ matchObjectsAndArrays("pivotByDemographic", altLegacyScorecard.minority.pivotByDemographic, legacyScorecard.minority.pivotByDemographic);
2530
+ matchFloats("opportunityDistricts", altLegacyScorecard.minority.opportunityDistricts, legacyScorecard.minority.opportunityDistricts, DEFAULT_TOLERANCE);
2531
+ matchFloats("coalitionDistricts", altLegacyScorecard.minority.coalitionDistricts, legacyScorecard.minority.coalitionDistricts, DEFAULT_TOLERANCE);
2532
+ matchInts("minority/score", altLegacyScorecard.minority.score, legacyScorecard.minority.score);
2533
+ matchDicts("minority/details", altLegacyScorecard.minority.details, legacyScorecard.minority.details);
2534
+ // COMPARE COMPACTNESS SCORECARD
2535
+ matchFloats("reock", altLegacyScorecard.compactness.reock.raw, legacyScorecard.compactness.reock.raw, DEFAULT_TOLERANCE);
2536
+ matchInts("reock/normalized", altLegacyScorecard.compactness.reock.normalized, legacyScorecard.compactness.reock.normalized);
2537
+ matchFloats("polsby", altLegacyScorecard.compactness.polsby.raw, legacyScorecard.compactness.polsby.raw, DEFAULT_TOLERANCE);
2538
+ matchInts("polsby/normalized", altLegacyScorecard.compactness.polsby.normalized, legacyScorecard.compactness.polsby.normalized);
2539
+ matchInts("compactness/score", altLegacyScorecard.compactness.score, legacyScorecard.compactness.score);
2540
+ // Compare 'byDistrict' results separately
2541
+ const _altCompactnessByDistrict = dra_analytics_1.Utils.deepCopy(altLegacyScorecard.compactness.details['byDistrict']);
2542
+ const _CompactnessByDistrict = dra_analytics_1.Utils.deepCopy(legacyScorecard.compactness.details['byDistrict']);
2543
+ const _altCompactnessDetails = dra_analytics_1.Utils.deepCopy(altLegacyScorecard.compactness.details);
2544
+ const _CompactnessDetails = dra_analytics_1.Utils.deepCopy(legacyScorecard.compactness.details);
2545
+ delete _altCompactnessDetails['byDistrict'];
2546
+ delete _CompactnessDetails['byDistrict'];
2547
+ matchDicts("compactness/details", _altCompactnessDetails, _CompactnessDetails);
2548
+ matchCompactnessByDistrict("compactness/byDistrict", _altCompactnessByDistrict, _CompactnessByDistrict, DEFAULT_TOLERANCE);
2549
+ // COMPARE SPLITTING SCORECARD
2550
+ matchFloats("county", altLegacyScorecard.splitting.county.raw, legacyScorecard.splitting.county.raw, DEFAULT_TOLERANCE);
2551
+ matchInts("county/normalized", altLegacyScorecard.splitting.county.normalized, legacyScorecard.splitting.county.normalized);
2552
+ matchFloats("district", altLegacyScorecard.splitting.district.raw, legacyScorecard.splitting.district.raw, DEFAULT_TOLERANCE);
2553
+ matchInts("district/normalized", altLegacyScorecard.splitting.district.normalized, legacyScorecard.splitting.district.normalized);
2554
+ matchInts("splitting/score", altLegacyScorecard.splitting.score, legacyScorecard.splitting.score);
2555
+ matchDicts("splitting/details", altLegacyScorecard.splitting.details, legacyScorecard.splitting.details);
2556
+ // COMPARE POPULATION SCORECARD
2557
+ matchFloats("popdev", altLegacyScorecard.populationDeviation.raw, legacyScorecard.populationDeviation.raw, DEFAULT_TOLERANCE);
2558
+ matchInts("popdev/score", altLegacyScorecard.populationDeviation.normalized, legacyScorecard.populationDeviation.normalized);
2559
+ matchDicts("popdev/notes", altLegacyScorecard.populationDeviation.notes, legacyScorecard.populationDeviation.notes);
2560
+ matchDicts("details", altLegacyScorecard.details, legacyScorecard.details);
2561
+ }
2562
+ exports.compareScorecards = compareScorecards;
2563
+ // Matching helpers
2564
+ function matchFloats(property, received, good, tolerance) {
2565
+ if (dra_analytics_1.Utils.areRoughlyEqual(received, good, tolerance)) {
2566
+ return true;
2567
+ }
2568
+ else {
2569
+ console.log(`${property} does not match: ${good} expected. Received ${received}.`);
2570
+ return false;
2571
+ }
2572
+ }
2573
+ function toleranceFn(places) {
2574
+ return 0.5 / Math.pow(10, places);
2575
+ }
2576
+ function matchInts(property, received, good) {
2577
+ if (received == good) {
2578
+ return true;
2579
+ }
2580
+ else {
2581
+ console.log(`${property} does not match: ${good} expected. Received ${received}.`);
2582
+ return false;
2583
+ }
2584
+ }
2585
+ function matchUndefinableFloats(property, received, good, tolerance) {
2586
+ if ((received === undefined) && (good === undefined))
2587
+ return true;
2588
+ if ((received === undefined) || (good === undefined)) {
2589
+ console.log(`${property} does not match: ${good} expected. Received ${received}.`);
2590
+ return false;
2591
+ }
2592
+ return matchFloats(property, received, good, tolerance);
2593
+ }
2594
+ // https://stackoverflow.com/questions/13142968/deep-comparison-of-objects-arrays
2595
+ function matchObjectsAndArrays(property, received, good) {
2596
+ if ((received === undefined) && (good === undefined))
2597
+ return true; // Both undefined
2598
+ if ((received === undefined) || (good === undefined)) { // One undefined but not the other
2599
+ console.log(`${property} does not match: ${good} expected. Received ${received}.`);
2600
+ return false;
2601
+ }
2602
+ if ((Object.keys(received).length === 0) && (Object.keys(good).length === 0))
2603
+ return true; // Both empty
2604
+ if (JSON.stringify(received) === JSON.stringify(good))
2605
+ return true; // Contents match
2606
+ console.log(`${property} objects or arrays do not match.`); // Contents don't match
2607
+ return false;
2608
+ }
2609
+ function matchDicts(property, received, good) {
2610
+ if ((Object.keys(received).length === 0) && (Object.keys(good).length === 0))
2611
+ return true; // Both empty
2612
+ const receivedStr = JSON.stringify(received);
2613
+ const goodStr = JSON.stringify(good);
2614
+ if (receivedStr === goodStr)
2615
+ return true; // Contents match
2616
+ console.log(`${property} does not match: ${goodStr} expected. Received ${receivedStr}.`); // Contents don't match
2617
+ return false;
2618
+ }
2619
+ function matchUndefinedness(property, received, good) {
2620
+ if ((received === undefined) && (good === undefined))
2621
+ return true;
2622
+ if ((received === undefined) || (good === undefined))
2623
+ return false;
2624
+ return true;
2625
+ }
2626
+ function matchPointArrays(property, received, good, tolerance) {
2627
+ if (received.length != good.length) {
2628
+ console.log(`${property} does not match: Different number of points.`);
2629
+ return false;
2630
+ }
2631
+ for (var i = 0; i < received.length; i++) {
2632
+ const vLabel = property + '/' + i.toString() + '/' + 'v';
2633
+ const sLabel = property + '/' + i.toString() + '/' + 's';
2634
+ if (!matchFloats(vLabel, received[i].v, good[i].v, tolerance))
2635
+ return false;
2636
+ if (!matchFloats(sLabel, received[i].s, good[i].s, tolerance))
2637
+ return false;
2638
+ }
2639
+ return true;
2640
+ }
2641
+ function matchCompactnessByDistrict(property, received, good, tolerance) {
2642
+ if (received.length != good.length) {
2643
+ console.log(`${property} does not match: Different number of districts.`);
2644
+ return false;
2645
+ }
2646
+ let bMismatched = false;
2647
+ for (var i = 0; i < received.length; i++) {
2648
+ const rawReock = property + '/' + i.toString() + '/' + 'rawReock';
2649
+ if (!matchFloats(rawReock, received[i].rawReock, good[i].rawReock, tolerance))
2650
+ bMismatched = true;
2651
+ const normalizedReock = property + '/' + i.toString() + '/' + 'normalizedReock';
2652
+ if (!matchInts(normalizedReock, received[i].normalizedReock, good[i].normalizedReock))
2653
+ bMismatched = true;
2654
+ const rawPolsby = property + '/' + i.toString() + '/' + 'rawPolsby';
2655
+ if (!matchFloats(rawPolsby, received[i].rawPolsby, good[i].rawPolsby, tolerance))
2656
+ bMismatched = true;
2657
+ // 09-17-21 - By-district Polsby–Popper ratings from dra-score in production are wrong!
2658
+ // const normalizedPolsby: string = property + '/' + i.toString() + '/' + 'normalizedPolsby';
2659
+ // if (!matchInts(normalizedPolsby, received[i].normalizedPolsby, good[i].normalizedPolsby)) bMismatched = true;
2660
+ const kiwysiScore = property + '/' + i.toString() + '/' + 'kiwysiScore';
2661
+ if (!matchInts(kiwysiScore, received[i].kiwysiScore, good[i].kiwysiScore))
2662
+ bMismatched = true;
2663
+ }
2664
+ if (bMismatched = true)
2665
+ return false;
2666
+ return true;
2667
+ }
2668
+ // Not used, after all
2669
+ /* Modeled after David Sielaff's Jest extension 'toBeArrayWithValuesCloseTo'
2670
+
2671
+ function matchFloatArrays(property: string, received: Array<any>, expected: Array<any>, tolerance: number): boolean
2672
+ {
2673
+ // Note - Not sure what this check was for ...
2674
+ // if (expected.length == 0) {
2675
+ // return {
2676
+ // message: () => `expected arrays of same size`,
2677
+ // pass: received.length == 0
2678
+ // }
2679
+ // }
2680
+
2681
+ if (typeof expected[0] === "number")
2682
+ {
2683
+ if (typeof received[0] === "number") return matchArrays1d(property, received, expected, tolerance);
2684
+
2685
+ console.log(`${property} does not match: array doesn't contain numbers.`);
2686
+ return false;
2687
+ }
2688
+
2689
+ // Note - Ditto
2690
+ // if (expected[0].length == 0) {
2691
+ // return {
2692
+ // message: () => `expected arrays of same size`,
2693
+ // pass: received[0].length == 0
2694
+ // }
2695
+ // }
2696
+
2697
+ if (expected[0] instanceof Array && typeof expected[0][0] === "number")
2698
+ {
2699
+ if (received[0] instanceof Array && typeof received[0][0] === "number") return matchArrays2d(property, received, expected, tolerance);
2700
+
2701
+ console.log(`${property} does not match: arrays don't have the same dimensionality and content.`);
2702
+ return false;
2703
+ }
2704
+
2705
+ console.log(`${property}: Expected 1d or 2d arrays.`);
2706
+ return false;
2707
+ }
2708
+
2709
+ function matchArrays1d(property: string, received: number[], expected: number[], tolerance: number): boolean
2710
+ {
2711
+ if (received.length != expected.length)
2712
+ {
2713
+ console.log(`${property} does not match: arrays have different lengths.`);
2714
+ return false;
2715
+ }
2716
+
2717
+ for (var index = 0; index < received.length; index++)
2718
+ {
2719
+ const cell: string = property + '/' + index.toString();
2720
+ if (!matchFloats(cell, received[index], expected[index], tolerance)) return false;
2721
+ }
2722
+
2723
+ return true;
2724
+ }
2725
+
2726
+ function matchArrays2d(property: string, received: number[][], expected: number[][], tolerance: number): boolean
2727
+ {
2728
+ if (received.length != expected.length)
2729
+ {
2730
+ console.log(`${property} does not match: arrays have different lengths.`);
2731
+ return false;
2732
+ }
2733
+
2734
+ for (var index = 0; index < received.length; index++)
2735
+ {
2736
+ if (received[index].length != expected[index].length)
2737
+ {
2738
+ console.log(`${property} does not match: arrays have different lengths.`);
2739
+ return false;
2740
+ }
2741
+
2742
+ for (var inner = 0; inner < received[index].length; inner++)
2743
+ {
2744
+ const cell: string = property + '/' + index.toString() + '/' + inner.toString();
2745
+ if (!matchFloats(cell, received[index][inner], expected[index][inner], tolerance)) return false;
2746
+ }
2747
+ }
2748
+
2749
+ return true;
2750
+ }
2751
+ */
2244
2752
 
2245
2753
 
2246
2754
  /***/ }),
@@ -2256,24 +2764,27 @@ exports.scorePlan = scorePlan;
2256
2764
  // GLOBAL CONSTANTS
2257
2765
  //
2258
2766
  Object.defineProperty(exports, "__esModule", ({ value: true }));
2259
- exports.DISTRICT_SPLITTING_WEIGHT = exports.COUNTY_SPLITTING_WEIGHT = exports.EQUAL_TOLERANCE = exports.OUT_OF_STATE = exports.NUMBER_OF_ITEMS_TO_REPORT = exports.NOT_ASSIGNED = exports.NORMALIZED_RANGE = exports.PRECISION = void 0;
2767
+ exports.OUT_OF_STATE = exports.NUMBER_OF_ITEMS_TO_REPORT = exports.NOT_ASSIGNED = exports.PRECISION = void 0;
2260
2768
  // Keep four decimal places for fractions [0–1], i.e.,
2261
2769
  // keep two decimal places for %'s [0–100].
2262
2770
  exports.PRECISION = 4;
2771
+ // LEGACY - Not used
2263
2772
  // Normalized scores [0-100]
2264
- exports.NORMALIZED_RANGE = 100;
2773
+ // export const NORMALIZED_RANGE: number = 100;
2265
2774
  // The dummy district ID for features not assigned districts yet
2266
2775
  exports.NOT_ASSIGNED = 0;
2267
2776
  // # of items to report as problematic (e.g., features, districts, etc.)
2268
2777
  exports.NUMBER_OF_ITEMS_TO_REPORT = 10;
2269
2778
  // The virtual geoID for "neighbors" in other states
2270
2779
  exports.OUT_OF_STATE = "OUT_OF_STATE";
2780
+ // LEGACY - Not used
2271
2781
  // "Roughly equal" = average census block size / 2
2272
- const AVERAGE_BLOCK_SIZE = 30;
2273
- exports.EQUAL_TOLERANCE = AVERAGE_BLOCK_SIZE / 2;
2782
+ // const AVERAGE_BLOCK_SIZE = 30;
2783
+ // export const EQUAL_TOLERANCE: number = AVERAGE_BLOCK_SIZE / 2;
2784
+ // LEGACY - Not used
2274
2785
  // County & district splitting weights
2275
- exports.COUNTY_SPLITTING_WEIGHT = 0.8;
2276
- exports.DISTRICT_SPLITTING_WEIGHT = 1.0 - exports.COUNTY_SPLITTING_WEIGHT;
2786
+ // export const COUNTY_SPLITTING_WEIGHT = 0.8;
2787
+ // export const DISTRICT_SPLITTING_WEIGHT = 1.0 - COUNTY_SPLITTING_WEIGHT;
2277
2788
  // 2020
2278
2789
  // export const SHAPES = "2010 VTD shapes";
2279
2790
 
@@ -2284,16 +2795,13 @@ exports.DISTRICT_SPLITTING_WEIGHT = 1.0 - exports.COUNTY_SPLITTING_WEIGHT;
2284
2795
  /*!**********************!*\
2285
2796
  !*** ./src/types.ts ***!
2286
2797
  \**********************/
2287
- /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
2798
+ /***/ ((__unused_webpack_module, exports) => {
2288
2799
 
2289
2800
 
2290
2801
  //
2291
2802
  // TYPE DEFINITIONS
2292
2803
  //
2293
2804
  Object.defineProperty(exports, "__esModule", ({ value: true }));
2294
- exports.estSeatProbability = void 0;
2295
- var dra_score_1 = __webpack_require__(/*! @dra2020/dra-score */ "@dra2020/dra-score");
2296
- Object.defineProperty(exports, "estSeatProbability", ({ enumerable: true, get: function () { return dra_score_1.estSeatProbability; } }));
2297
2805
  // END
2298
2806
 
2299
2807
 
@@ -2329,21 +2837,23 @@ var __importStar = (this && this.__importStar) || function (mod) {
2329
2837
  return result;
2330
2838
  };
2331
2839
  Object.defineProperty(exports, "__esModule", ({ value: true }));
2332
- exports.depthof = exports.deepCopy = exports.shallowCopy = exports.countEnumValues = exports.objectContains = exports.arrayContains = exports.getSelectObjectKeys = exports.getNumericObjectKeys = exports.getObjectKeys = exports.isArrayEmpty = exports.isSetEmpty = exports.isObjectEmpty = exports.keyExists = exports.andArray = exports.initArray = exports.maxArray = exports.minArray = exports.avgArray = exports.sumArray = exports.trim = exports.isUninhabited = exports.isWaterOnly = exports.parseGeoID = exports.getDistrict = exports.isOutOfState = exports.isInState = void 0;
2840
+ exports.depthof = exports.deepCopy = exports.shallowCopy = exports.countEnumValues = exports.objectContains = exports.arrayContains = exports.getSelectObjectKeys = exports.getNumericObjectKeys = exports.getObjectKeys = exports.isArrayEmpty = exports.isSetEmpty = exports.isObjectEmpty = exports.keyExists = exports.andArray = exports.initArray = exports.maxArray = exports.minArray = exports.avgArray = exports.sumArray = exports.trim = exports.isUninhabited = exports.isWaterOnly = exports.parseGeoID = exports.getDistrict = void 0;
2333
2841
  const DT = __importStar(__webpack_require__(/*! @dra2020/dra-types */ "@dra2020/dra-types"));
2334
2842
  const _data_1 = __webpack_require__(/*! ./_data */ "./src/_data.ts");
2335
2843
  const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"));
2336
2844
  // PLAN HELPERS
2845
+ // LEGACY - Not used
2337
2846
  // Is a "neighbor" in state?
2338
- function isInState(geoID) {
2339
- return geoID != S.OUT_OF_STATE;
2340
- }
2341
- exports.isInState = isInState;
2847
+ // export function isInState(geoID: string): boolean
2848
+ // {
2849
+ // return geoID != S.OUT_OF_STATE;
2850
+ // }
2851
+ // LEGACY - Not used
2342
2852
  // Is a "neighbor" out of state?
2343
- function isOutOfState(geoID) {
2344
- return geoID == S.OUT_OF_STATE;
2345
- }
2346
- exports.isOutOfState = isOutOfState;
2853
+ // export function isOutOfState(geoID: string): boolean
2854
+ // {
2855
+ // return geoID == S.OUT_OF_STATE;
2856
+ // }
2347
2857
  // Get the districtID to which a geoID is assigned
2348
2858
  function getDistrict(plan, geoID) {
2349
2859
  // All geoIDs in a state *should be* assigned to a district (including the