@dra2020/district-analytics 14.1.1 → 14.2.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.
@@ -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.avgSVError = 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,6 +1673,7 @@ __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;
1582
1679
  exports.avgSVError = dra_analytics_1.Rate.avgSVError;
@@ -1642,28 +1739,6 @@ exports.doAnalyzeRacialPolarization = doAnalyzeRacialPolarization;
1642
1739
  // 11-18-2020 - Moved RPV to racial-voting package.
1643
1740
 
1644
1741
 
1645
- /***/ }),
1646
-
1647
- /***/ "./src/political.ts":
1648
- /*!**************************!*\
1649
- !*** ./src/political.ts ***!
1650
- \**************************/
1651
- /***/ ((__unused_webpack_module, exports) => {
1652
-
1653
-
1654
- //
1655
- // FAIR/PROPORTIONAL
1656
- //
1657
- Object.defineProperty(exports, "__esModule", ({ value: true }));
1658
- exports.fptpWin = void 0;
1659
- function fptpWin(demPct) {
1660
- // Vote shares should be fractions in the range [0.0 – 1.0]
1661
- //assert((demPct <= 1.0) && (demPct >= 0.0));
1662
- return ((demPct > 0.5) ? 1 : 0);
1663
- }
1664
- exports.fptpWin = fptpWin;
1665
-
1666
-
1667
1742
  /***/ }),
1668
1743
 
1669
1744
  /***/ "./src/preprocess.ts":
@@ -2043,6 +2118,7 @@ function doAnalyzePostProcessing(s, bLog = false) {
2043
2118
  scorecard.splitting.details['countiesWithSplits'] = simpleSplits['details']['countiesWithSplits'];
2044
2119
  // NOTE - Add split precincts in dra-client directly
2045
2120
  // Derive secondary tests
2121
+ // Note - The only secondary test is 'roughly equal population (true/false)
2046
2122
  (0, analyze_1.doDeriveSecondaryTests)(s, bLog);
2047
2123
  // Toggle the semaphore, so postprocessing isn't for both the testlog & scorecard
2048
2124
  s.bPostProcessingDone = true;
@@ -2082,11 +2158,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
2082
2158
  return result;
2083
2159
  };
2084
2160
  Object.defineProperty(exports, "__esModule", ({ value: true }));
2085
- 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;
2086
2162
  const Score = __importStar(__webpack_require__(/*! @dra2020/dra-score */ "@dra2020/dra-score"));
2087
2163
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
2088
2164
  const M = __importStar(__webpack_require__(/*! ./minority */ "./src/minority.ts"));
2089
2165
  const C = __importStar(__webpack_require__(/*! ./compact */ "./src/compact.ts"));
2166
+ const dra_analytics_1 = __webpack_require__(/*! @dra2020/dra-analytics */ "@dra2020/dra-analytics");
2090
2167
  // PROFILE A PLAN
2091
2168
  const KEEP_DECIMALS = 6;
2092
2169
  function profilePlan(s, bLog = false) {
@@ -2198,26 +2275,30 @@ function getStatewideDemographics(s, bLog = false) {
2198
2275
  return demographics;
2199
2276
  }
2200
2277
  exports.getStatewideDemographics = getStatewideDemographics;
2201
- // SCORE A PLAN
2278
+ // SCORE A PLAN - Legacy using dra-score
2279
+ // LEGACY
2202
2280
  function scorePlan(s, p, bLog = false, overridesJSON) {
2203
2281
  let scorer = new Score.Scorer();
2204
2282
  const scorecard = scorer.score(p, overridesJSON);
2205
- // Before returning, create a dummy population deviation test, for
2206
- // doHasEqualPopulations() to use later.This is preserving the old calling sequence.
2207
- let test = s.getTest(4 /* PopulationDeviation */);
2208
- // Get the raw population deviation
2209
- const popDev = scorecard.populationDeviation.raw;
2210
- // Populate the test entry
2211
- test['score'] = popDev;
2212
- test['details'] = { 'maxDeviation': scorecard.populationDeviation.notes['maxDeviation'] };
2213
- // Populate the N+1 summary "district" in district.statistics
2214
- let totalPop = s.districts.table.totalPop;
2215
- let popDevPct = s.districts.table.popDevPct;
2216
- let totalVAP = s.districts.table.totalVAP;
2217
- const summaryRow = s.districts.numberOfRows() - 1;
2218
- totalPop[summaryRow] = p.population.targetSize;
2219
- popDevPct[summaryRow] = popDev;
2220
- 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
2221
2302
  // Add minority notes
2222
2303
  scorecard.minority.details['majorityMinority'] = M.getMajorityMinority(s);
2223
2304
  scorecard.minority.details['vraPreclearance'] = M.getVRASection5(s);
@@ -2232,6 +2313,9 @@ function scorePlan(s, p, bLog = false, overridesJSON) {
2232
2313
  const nDistricts = byDistrict.length;
2233
2314
  for (let districtID = 1; districtID <= nDistricts; districtID++) {
2234
2315
  byDistrict[districtID - 1].kiwysiScore = kiwysiScores[districtID - 1];
2316
+ // 09-17-21 - Fix the normalized Polsby–Popper score!
2317
+ const rawPolsby = byDistrict[districtID - 1].rawPolsby;
2318
+ byDistrict[districtID - 1].normalizedPolsby = dra_analytics_1.Rate.ratePolsby(rawPolsby);
2235
2319
  }
2236
2320
  }
2237
2321
  catch (e) {
@@ -2242,6 +2326,434 @@ function scorePlan(s, p, bLog = false, overridesJSON) {
2242
2326
  return scorecard;
2243
2327
  }
2244
2328
  exports.scorePlan = scorePlan;
2329
+ // SCORE A PLAN - New using dra-analytics
2330
+ function computeMetrics(p, districtShapes, bLog = false) {
2331
+ if (bLog)
2332
+ console.log("Computing metrics ...");
2333
+ const bLegislative = p.bStateLeg;
2334
+ // Calculate bias & responsiveness metrics ...
2335
+ const byDistrictVf = p.partisanship.byDistrict;
2336
+ const statewideVf = p.partisanship.statewide;
2337
+ let _pS = dra_analytics_1.Partisan.makePartisanScorecard(statewideVf, byDistrictVf, bLog);
2338
+ // Calculate minority representation metrics ...
2339
+ const statewideDemos = p.demographics.statewide;
2340
+ const byDistrictDemos = p.demographics.byDistrict;
2341
+ let _mS = dra_analytics_1.Minority.makeMinorityScorecard(statewideDemos, byDistrictDemos, bLog);
2342
+ // Calculate compactness metrics ...
2343
+ let _cS = dra_analytics_1.Compactness.makeCompactnessScorecard(districtShapes, bLog);
2344
+ // Calculate county-district splitting metrics ...
2345
+ const CxD = p.counties;
2346
+ const _sS = dra_analytics_1.Splitting.makeSplittingScorecard(CxD, bLog);
2347
+ // Calculate population deviation-related metrics ...
2348
+ const totPopByDistrict = p.population.byDistrict;
2349
+ const targetSize = p.population.targetSize;
2350
+ const _pdS = dra_analytics_1.Equal.makePopulationScorecard(totPopByDistrict, targetSize, bLegislative, bLog);
2351
+ const details = {};
2352
+ // Assemble the pieces into new scorecard
2353
+ const scorecard = {
2354
+ partisan: _pS,
2355
+ minority: _mS,
2356
+ compactness: _cS,
2357
+ splitting: _sS,
2358
+ populationDeviation: _pdS,
2359
+ details: details,
2360
+ scratchpad: {} // Hack to pass legacy values between processing steps
2361
+ };
2362
+ return scorecard;
2363
+ }
2364
+ exports.computeMetrics = computeMetrics;
2365
+ function rateKeyDimensions(scorecard, p, bLog = false) {
2366
+ if (bLog)
2367
+ console.log("Rating key dimensions ...");
2368
+ const bLegislative = p.bStateLeg;
2369
+ // Rate proportionality
2370
+ const statewideVf = p.partisanship.statewide;
2371
+ const Sf = scorecard.partisan.bias.estSf;
2372
+ scorecard.partisan.bias.score = dra_analytics_1.Rate.rateProportionality(scorecard.partisan.bias.deviation, statewideVf, Sf);
2373
+ // Rate competititveness
2374
+ scorecard.partisan.responsiveness.score = dra_analytics_1.Rate.rateCompetitiveness(scorecard.partisan.responsiveness.cDf);
2375
+ // Rate minority representation
2376
+ const rawOd = scorecard.minority.opportunityDistricts;
2377
+ const pOd = scorecard.minority.proportionalOpportunities;
2378
+ const rawCd = scorecard.minority.coalitionDistricts;
2379
+ const pCd = scorecard.minority.proportionalCoalitions;
2380
+ scorecard.minority.score = dra_analytics_1.Rate.rateMinorityRepresentation(rawOd, pOd, rawCd, pCd);
2381
+ // Rate compactness
2382
+ const avgReock = scorecard.compactness.avgReock;
2383
+ const avgPolsby = scorecard.compactness.avgPolsby;
2384
+ const reockRating = dra_analytics_1.Rate.rateReock(avgReock);
2385
+ const polsbyRating = dra_analytics_1.Rate.ratePolsby(avgPolsby);
2386
+ scorecard.compactness.score = dra_analytics_1.Rate.rateCompactness(reockRating, polsbyRating);
2387
+ // Rate county- & district-splitting
2388
+ const rawCountySplitting = scorecard.splitting.county;
2389
+ const rawDistrictSplitting = scorecard.splitting.district;
2390
+ const nCounties = p.nCounties;
2391
+ const nDistricts = p.nDistricts;
2392
+ const countyRating = dra_analytics_1.Rate.rateCountySplitting(rawCountySplitting, nCounties, nDistricts, bLegislative);
2393
+ const districtRating = dra_analytics_1.Rate.rateDistrictSplitting(rawDistrictSplitting, bLegislative);
2394
+ const unadjusted = dra_analytics_1.Rate.rateSplitting(countyRating, districtRating);
2395
+ scorecard.splitting.score = dra_analytics_1.Rate.adjustSplittingRating(unadjusted, rawCountySplitting, rawDistrictSplitting);
2396
+ // Rate population deviation
2397
+ const rawDeviation = scorecard.populationDeviation.deviation;
2398
+ scorecard.populationDeviation.score = dra_analytics_1.Rate.ratePopulationDeviation(rawDeviation, bLegislative);
2399
+ // Squirrel away normalized compactness & splitting ratings for the legacy scorecard
2400
+ const keep = {
2401
+ reockScore: reockRating,
2402
+ polsbyScore: polsbyRating,
2403
+ countyScore: countyRating,
2404
+ districtScore: districtRating
2405
+ };
2406
+ scorecard.scratchpad = keep;
2407
+ return scorecard;
2408
+ }
2409
+ exports.rateKeyDimensions = rateKeyDimensions;
2410
+ function thunkScorecard(newScorecard, bLog = false) {
2411
+ if (bLog)
2412
+ console.log("Thunking new scorecard into legacy structure ...");
2413
+ const scratchpad = newScorecard.scratchpad;
2414
+ // Partisan scorecard
2415
+ const pS = U.deepCopy(newScorecard.partisan);
2416
+ // Minority scorecard
2417
+ const mS = U.deepCopy(newScorecard.minority);
2418
+ // Compactness scorecard
2419
+ const reockM = {
2420
+ raw: newScorecard.compactness.avgReock,
2421
+ normalized: scratchpad.reockScore,
2422
+ notes: {}
2423
+ };
2424
+ const polsbyM = {
2425
+ raw: newScorecard.compactness.avgPolsby,
2426
+ normalized: scratchpad.polsbyScore,
2427
+ notes: {}
2428
+ };
2429
+ let cS = {
2430
+ score: newScorecard.compactness.score,
2431
+ reock: reockM,
2432
+ polsby: polsbyM,
2433
+ details: U.deepCopy(newScorecard.compactness.details)
2434
+ };
2435
+ // Relocate byDistrict compactness #'s
2436
+ cS.details.byDistrict = U.deepCopy(newScorecard.compactness.byDistrict);
2437
+ // Add KIWYSI compactness score
2438
+ cS.details['kiwysi'] = newScorecard.compactness.avgKWIWYSI;
2439
+ // Splitting scorecard
2440
+ const countyM = {
2441
+ raw: newScorecard.splitting.county,
2442
+ normalized: scratchpad.countyScore,
2443
+ notes: {}
2444
+ };
2445
+ const districtM = {
2446
+ raw: newScorecard.splitting.district,
2447
+ normalized: scratchpad.districtScore,
2448
+ notes: {}
2449
+ };
2450
+ const sS = {
2451
+ score: newScorecard.splitting.score,
2452
+ county: countyM,
2453
+ district: districtM,
2454
+ details: U.deepCopy(newScorecard.splitting.details)
2455
+ };
2456
+ // Population (equality) scorecard
2457
+ const pdM = {
2458
+ raw: newScorecard.populationDeviation.deviation,
2459
+ normalized: newScorecard.populationDeviation.score,
2460
+ notes: newScorecard.populationDeviation.notes
2461
+ };
2462
+ const pdS = pdM;
2463
+ const scorecard = {
2464
+ partisan: pS,
2465
+ minority: mS,
2466
+ compactness: cS,
2467
+ splitting: sS,
2468
+ populationDeviation: pdS,
2469
+ details: newScorecard.details
2470
+ };
2471
+ return scorecard;
2472
+ }
2473
+ exports.thunkScorecard = thunkScorecard;
2474
+ function compareScorecards(altLegacyScorecard, legacyScorecard, bLog = false) {
2475
+ if (bLog)
2476
+ console.log("Comparing new & legacy scorecards ...");
2477
+ // A pretty loose tolerance, because we're not trimming values in the new analytics
2478
+ const DECIMAL_PLACES = 2;
2479
+ const DEFAULT_TOLERANCE = toleranceFn(DECIMAL_PLACES);
2480
+ // COMPARE PARTISAN SCORECARD
2481
+ // Compare BIAS section
2482
+ matchFloats("bestS", altLegacyScorecard.partisan.bias.bestS, legacyScorecard.partisan.bias.bestS, DEFAULT_TOLERANCE);
2483
+ matchFloats("bestSf", altLegacyScorecard.partisan.bias.bestSf, legacyScorecard.partisan.bias.bestSf, DEFAULT_TOLERANCE);
2484
+ matchFloats("estS", altLegacyScorecard.partisan.bias.estS, legacyScorecard.partisan.bias.estS, DEFAULT_TOLERANCE);
2485
+ matchFloats("estSf", altLegacyScorecard.partisan.bias.estSf, legacyScorecard.partisan.bias.estSf, DEFAULT_TOLERANCE);
2486
+ matchFloats("deviation", altLegacyScorecard.partisan.bias.deviation, legacyScorecard.partisan.bias.deviation, DEFAULT_TOLERANCE);
2487
+ matchInts("proportionality/score", altLegacyScorecard.partisan.bias.score, legacyScorecard.partisan.bias.score);
2488
+ matchFloats("tOf", altLegacyScorecard.partisan.bias.tOf, legacyScorecard.partisan.bias.tOf, DEFAULT_TOLERANCE);
2489
+ matchFloats("fptpS", altLegacyScorecard.partisan.bias.fptpS, legacyScorecard.partisan.bias.fptpS, DEFAULT_TOLERANCE);
2490
+ matchFloats("bS50", altLegacyScorecard.partisan.bias.bS50, legacyScorecard.partisan.bias.bS50, DEFAULT_TOLERANCE);
2491
+ matchFloats("deviation", altLegacyScorecard.partisan.bias.deviation, legacyScorecard.partisan.bias.deviation, DEFAULT_TOLERANCE);
2492
+ matchUndefinableFloats("decl", altLegacyScorecard.partisan.bias.decl, legacyScorecard.partisan.bias.decl, toleranceFn(1));
2493
+ let rvPointsAlt = altLegacyScorecard.partisan.bias.rvPoints;
2494
+ let rvPoints = legacyScorecard.partisan.bias.rvPoints;
2495
+ if (matchUndefinedness("rvPoints", rvPointsAlt, rvPoints)) {
2496
+ rvPointsAlt = rvPointsAlt;
2497
+ rvPoints = rvPoints;
2498
+ matchFloats("rvPoints/Sb", rvPointsAlt.Sb, rvPoints.Sb, DEFAULT_TOLERANCE);
2499
+ matchFloats("rvPoints/Ra", rvPointsAlt.Ra, rvPoints.Ra, DEFAULT_TOLERANCE);
2500
+ matchFloats("rvPoints/Rb", rvPointsAlt.Rb, rvPoints.Rb, DEFAULT_TOLERANCE);
2501
+ matchFloats("rvPoints/Va", rvPointsAlt.Va, rvPoints.Va, DEFAULT_TOLERANCE);
2502
+ matchFloats("rvPoints/Vb", rvPointsAlt.Vb, rvPoints.Vb, DEFAULT_TOLERANCE);
2503
+ }
2504
+ matchFloats("gSym", altLegacyScorecard.partisan.bias.gSym, legacyScorecard.partisan.bias.gSym, DEFAULT_TOLERANCE);
2505
+ matchUndefinableFloats("gamma", altLegacyScorecard.partisan.bias.gamma, legacyScorecard.partisan.bias.gamma, DEFAULT_TOLERANCE);
2506
+ matchFloats("eG", altLegacyScorecard.partisan.bias.eG, legacyScorecard.partisan.bias.eG, DEFAULT_TOLERANCE);
2507
+ matchUndefinableFloats("bSV", altLegacyScorecard.partisan.bias.bSV, legacyScorecard.partisan.bias.bSV, DEFAULT_TOLERANCE);
2508
+ matchFloats("prop", altLegacyScorecard.partisan.bias.prop, legacyScorecard.partisan.bias.prop, DEFAULT_TOLERANCE);
2509
+ matchFloats("mMs", altLegacyScorecard.partisan.bias.mMs, legacyScorecard.partisan.bias.mMs, DEFAULT_TOLERANCE);
2510
+ matchFloats("mMd", altLegacyScorecard.partisan.bias.mMd, legacyScorecard.partisan.bias.mMd, DEFAULT_TOLERANCE);
2511
+ matchUndefinableFloats("lO", altLegacyScorecard.partisan.bias.lO, legacyScorecard.partisan.bias.lO, DEFAULT_TOLERANCE);
2512
+ // Compare Impact section
2513
+ matchFloats("unearnedS", altLegacyScorecard.partisan.impact.unearnedS, legacyScorecard.partisan.impact.unearnedS, DEFAULT_TOLERANCE);
2514
+ // Note - We don't use the impact score, so we don't compute it in the new scorecard.
2515
+ // matchInts("impact/score", altLegacyScorecard.partisan.impact.score as number, legacyScorecard.partisan.impact.score);
2516
+ // Compare Responsiveness section
2517
+ matchUndefinableFloats("bigR", altLegacyScorecard.partisan.responsiveness.bigR, legacyScorecard.partisan.responsiveness.bigR, DEFAULT_TOLERANCE);
2518
+ matchUndefinableFloats("littleR", altLegacyScorecard.partisan.responsiveness.littleR, legacyScorecard.partisan.responsiveness.littleR, DEFAULT_TOLERANCE);
2519
+ matchUndefinableFloats("mIR", altLegacyScorecard.partisan.responsiveness.mIR, legacyScorecard.partisan.responsiveness.mIR, DEFAULT_TOLERANCE);
2520
+ matchFloats("rD", altLegacyScorecard.partisan.responsiveness.rD, legacyScorecard.partisan.responsiveness.rD, DEFAULT_TOLERANCE);
2521
+ matchFloats("rDf", altLegacyScorecard.partisan.responsiveness.rDf, legacyScorecard.partisan.responsiveness.rDf, DEFAULT_TOLERANCE);
2522
+ matchFloats("cSimple", altLegacyScorecard.partisan.responsiveness.cSimple, legacyScorecard.partisan.responsiveness.cSimple, DEFAULT_TOLERANCE);
2523
+ matchFloats("cD", altLegacyScorecard.partisan.responsiveness.cD, legacyScorecard.partisan.responsiveness.cD, DEFAULT_TOLERANCE);
2524
+ matchFloats("cDf", altLegacyScorecard.partisan.responsiveness.cDf, legacyScorecard.partisan.responsiveness.cDf, DEFAULT_TOLERANCE);
2525
+ matchInts("competitiveness/score", altLegacyScorecard.partisan.responsiveness.score, legacyScorecard.partisan.responsiveness.score);
2526
+ matchPointArrays("dSVpoints", altLegacyScorecard.partisan.dSVpoints, legacyScorecard.partisan.dSVpoints, DEFAULT_TOLERANCE);
2527
+ matchPointArrays("rSVpoints", altLegacyScorecard.partisan.rSVpoints, legacyScorecard.partisan.rSVpoints, DEFAULT_TOLERANCE);
2528
+ matchUndefinableFloats("averageDVf", altLegacyScorecard.partisan.averageDVf, legacyScorecard.partisan.averageDVf, DEFAULT_TOLERANCE);
2529
+ matchUndefinableFloats("averageRVf", altLegacyScorecard.partisan.averageRVf, legacyScorecard.partisan.averageRVf, DEFAULT_TOLERANCE);
2530
+ matchDicts("partisan/details", altLegacyScorecard.partisan.details, legacyScorecard.partisan.details);
2531
+ // COMPARE MINORITY SCORECARD
2532
+ matchObjectsAndArrays("pivotByDemographic", altLegacyScorecard.minority.pivotByDemographic, legacyScorecard.minority.pivotByDemographic);
2533
+ matchFloats("opportunityDistricts", altLegacyScorecard.minority.opportunityDistricts, legacyScorecard.minority.opportunityDistricts, DEFAULT_TOLERANCE);
2534
+ matchFloats("coalitionDistricts", altLegacyScorecard.minority.coalitionDistricts, legacyScorecard.minority.coalitionDistricts, DEFAULT_TOLERANCE);
2535
+ matchInts("minority/score", altLegacyScorecard.minority.score, legacyScorecard.minority.score);
2536
+ matchDicts("minority/details", altLegacyScorecard.minority.details, legacyScorecard.minority.details);
2537
+ // COMPARE COMPACTNESS SCORECARD
2538
+ matchFloats("reock", altLegacyScorecard.compactness.reock.raw, legacyScorecard.compactness.reock.raw, DEFAULT_TOLERANCE);
2539
+ matchInts("reock/normalized", altLegacyScorecard.compactness.reock.normalized, legacyScorecard.compactness.reock.normalized);
2540
+ matchFloats("polsby", altLegacyScorecard.compactness.polsby.raw, legacyScorecard.compactness.polsby.raw, DEFAULT_TOLERANCE);
2541
+ matchInts("polsby/normalized", altLegacyScorecard.compactness.polsby.normalized, legacyScorecard.compactness.polsby.normalized);
2542
+ matchInts("compactness/score", altLegacyScorecard.compactness.score, legacyScorecard.compactness.score);
2543
+ // Compare 'byDistrict' results separately
2544
+ const _altCompactnessByDistrict = dra_analytics_1.Utils.deepCopy(altLegacyScorecard.compactness.details['byDistrict']);
2545
+ const _CompactnessByDistrict = dra_analytics_1.Utils.deepCopy(legacyScorecard.compactness.details['byDistrict']);
2546
+ const _altCompactnessDetails = dra_analytics_1.Utils.deepCopy(altLegacyScorecard.compactness.details);
2547
+ const _CompactnessDetails = dra_analytics_1.Utils.deepCopy(legacyScorecard.compactness.details);
2548
+ delete _altCompactnessDetails['byDistrict'];
2549
+ delete _CompactnessDetails['byDistrict'];
2550
+ matchDicts("compactness/details", _altCompactnessDetails, _CompactnessDetails);
2551
+ matchCompactnessByDistrict("compactness/byDistrict", _altCompactnessByDistrict, _CompactnessByDistrict, DEFAULT_TOLERANCE);
2552
+ // COMPARE SPLITTING SCORECARD
2553
+ matchFloats("county", altLegacyScorecard.splitting.county.raw, legacyScorecard.splitting.county.raw, DEFAULT_TOLERANCE);
2554
+ matchInts("county/normalized", altLegacyScorecard.splitting.county.normalized, legacyScorecard.splitting.county.normalized);
2555
+ matchFloats("district", altLegacyScorecard.splitting.district.raw, legacyScorecard.splitting.district.raw, DEFAULT_TOLERANCE);
2556
+ matchInts("district/normalized", altLegacyScorecard.splitting.district.normalized, legacyScorecard.splitting.district.normalized);
2557
+ matchInts("splitting/score", altLegacyScorecard.splitting.score, legacyScorecard.splitting.score);
2558
+ matchDicts("splitting/details", altLegacyScorecard.splitting.details, legacyScorecard.splitting.details);
2559
+ // COMPARE POPULATION SCORECARD
2560
+ matchFloats("popdev", altLegacyScorecard.populationDeviation.raw, legacyScorecard.populationDeviation.raw, DEFAULT_TOLERANCE);
2561
+ matchInts("popdev/score", altLegacyScorecard.populationDeviation.normalized, legacyScorecard.populationDeviation.normalized);
2562
+ matchDicts("popdev/notes", altLegacyScorecard.populationDeviation.notes, legacyScorecard.populationDeviation.notes);
2563
+ matchDicts("details", altLegacyScorecard.details, legacyScorecard.details);
2564
+ }
2565
+ exports.compareScorecards = compareScorecards;
2566
+ // Matching helpers
2567
+ function matchFloats(property, received, good, tolerance) {
2568
+ if (dra_analytics_1.Utils.areRoughlyEqual(received, good, tolerance)) {
2569
+ return true;
2570
+ }
2571
+ else {
2572
+ console.log(`${property} does not match: ${good} expected. Received ${received}.`);
2573
+ return false;
2574
+ }
2575
+ }
2576
+ function toleranceFn(places) {
2577
+ return 0.5 / Math.pow(10, places);
2578
+ }
2579
+ function matchInts(property, received, good) {
2580
+ if (received == good) {
2581
+ return true;
2582
+ }
2583
+ else {
2584
+ console.log(`${property} does not match: ${good} expected. Received ${received}.`);
2585
+ return false;
2586
+ }
2587
+ }
2588
+ function matchUndefinableFloats(property, received, good, tolerance) {
2589
+ if ((received === undefined) && (good === undefined))
2590
+ return true;
2591
+ if ((received === undefined) || (good === undefined)) {
2592
+ console.log(`${property} does not match: ${good} expected. Received ${received}.`);
2593
+ return false;
2594
+ }
2595
+ return matchFloats(property, received, good, tolerance);
2596
+ }
2597
+ // https://stackoverflow.com/questions/13142968/deep-comparison-of-objects-arrays
2598
+ function matchObjectsAndArrays(property, received, good) {
2599
+ if ((received === undefined) && (good === undefined))
2600
+ return true; // Both undefined
2601
+ if ((received === undefined) || (good === undefined)) { // One undefined but not the other
2602
+ console.log(`${property} does not match: ${good} expected. Received ${received}.`);
2603
+ return false;
2604
+ }
2605
+ if ((Object.keys(received).length === 0) && (Object.keys(good).length === 0))
2606
+ return true; // Both empty
2607
+ if (JSON.stringify(received) === JSON.stringify(good))
2608
+ return true; // Contents match
2609
+ console.log(`${property} objects or arrays do not match.`); // Contents don't match
2610
+ return false;
2611
+ }
2612
+ function matchDicts(property, received, good) {
2613
+ if ((Object.keys(received).length === 0) && (Object.keys(good).length === 0))
2614
+ return true; // Both empty
2615
+ const receivedStr = JSON.stringify(received);
2616
+ const goodStr = JSON.stringify(good);
2617
+ if (receivedStr === goodStr)
2618
+ return true; // Contents match
2619
+ console.log(`${property} does not match: ${goodStr} expected. Received ${receivedStr}.`); // Contents don't match
2620
+ return false;
2621
+ }
2622
+ function matchUndefinedness(property, received, good) {
2623
+ if ((received === undefined) && (good === undefined))
2624
+ return true;
2625
+ if ((received === undefined) || (good === undefined))
2626
+ return false;
2627
+ return true;
2628
+ }
2629
+ function matchPointArrays(property, received, good, tolerance) {
2630
+ if (received.length != good.length) {
2631
+ console.log(`${property} does not match: Different number of points.`);
2632
+ return false;
2633
+ }
2634
+ for (var i = 0; i < received.length; i++) {
2635
+ const vLabel = property + '/' + i.toString() + '/' + 'v';
2636
+ const sLabel = property + '/' + i.toString() + '/' + 's';
2637
+ if (!matchFloats(vLabel, received[i].v, good[i].v, tolerance))
2638
+ return false;
2639
+ if (!matchFloats(sLabel, received[i].s, good[i].s, tolerance))
2640
+ return false;
2641
+ }
2642
+ return true;
2643
+ }
2644
+ function matchCompactnessByDistrict(property, received, good, tolerance) {
2645
+ if (received.length != good.length) {
2646
+ console.log(`${property} does not match: Different number of districts.`);
2647
+ return false;
2648
+ }
2649
+ let bMismatched = false;
2650
+ for (var i = 0; i < received.length; i++) {
2651
+ const rawReock = property + '/' + i.toString() + '/' + 'rawReock';
2652
+ if (!matchFloats(rawReock, received[i].rawReock, good[i].rawReock, tolerance))
2653
+ bMismatched = true;
2654
+ const normalizedReock = property + '/' + i.toString() + '/' + 'normalizedReock';
2655
+ if (!matchInts(normalizedReock, received[i].normalizedReock, good[i].normalizedReock))
2656
+ bMismatched = true;
2657
+ const rawPolsby = property + '/' + i.toString() + '/' + 'rawPolsby';
2658
+ if (!matchFloats(rawPolsby, received[i].rawPolsby, good[i].rawPolsby, tolerance))
2659
+ bMismatched = true;
2660
+ // TODO
2661
+ // 09-17-21 - By-district Polsby–Popper ratings from dra-score in production are wrong!
2662
+ const normalizedPolsby = property + '/' + i.toString() + '/' + 'normalizedPolsby';
2663
+ if (!matchInts(normalizedPolsby, received[i].normalizedPolsby, good[i].normalizedPolsby))
2664
+ bMismatched = true;
2665
+ const kiwysiScore = property + '/' + i.toString() + '/' + 'kiwysiScore';
2666
+ if (!matchInts(kiwysiScore, received[i].kiwysiScore, good[i].kiwysiScore))
2667
+ bMismatched = true;
2668
+ }
2669
+ if (bMismatched = true)
2670
+ return false;
2671
+ return true;
2672
+ }
2673
+ // Not used, after all
2674
+ /* Modeled after David Sielaff's Jest extension 'toBeArrayWithValuesCloseTo'
2675
+
2676
+ function matchFloatArrays(property: string, received: Array<any>, expected: Array<any>, tolerance: number): boolean
2677
+ {
2678
+ // Note - Not sure what this check was for ...
2679
+ // if (expected.length == 0) {
2680
+ // return {
2681
+ // message: () => `expected arrays of same size`,
2682
+ // pass: received.length == 0
2683
+ // }
2684
+ // }
2685
+
2686
+ if (typeof expected[0] === "number")
2687
+ {
2688
+ if (typeof received[0] === "number") return matchArrays1d(property, received, expected, tolerance);
2689
+
2690
+ console.log(`${property} does not match: array doesn't contain numbers.`);
2691
+ return false;
2692
+ }
2693
+
2694
+ // Note - Ditto
2695
+ // if (expected[0].length == 0) {
2696
+ // return {
2697
+ // message: () => `expected arrays of same size`,
2698
+ // pass: received[0].length == 0
2699
+ // }
2700
+ // }
2701
+
2702
+ if (expected[0] instanceof Array && typeof expected[0][0] === "number")
2703
+ {
2704
+ if (received[0] instanceof Array && typeof received[0][0] === "number") return matchArrays2d(property, received, expected, tolerance);
2705
+
2706
+ console.log(`${property} does not match: arrays don't have the same dimensionality and content.`);
2707
+ return false;
2708
+ }
2709
+
2710
+ console.log(`${property}: Expected 1d or 2d arrays.`);
2711
+ return false;
2712
+ }
2713
+
2714
+ function matchArrays1d(property: string, received: number[], expected: number[], tolerance: number): boolean
2715
+ {
2716
+ if (received.length != expected.length)
2717
+ {
2718
+ console.log(`${property} does not match: arrays have different lengths.`);
2719
+ return false;
2720
+ }
2721
+
2722
+ for (var index = 0; index < received.length; index++)
2723
+ {
2724
+ const cell: string = property + '/' + index.toString();
2725
+ if (!matchFloats(cell, received[index], expected[index], tolerance)) return false;
2726
+ }
2727
+
2728
+ return true;
2729
+ }
2730
+
2731
+ function matchArrays2d(property: string, received: number[][], expected: number[][], tolerance: number): boolean
2732
+ {
2733
+ if (received.length != expected.length)
2734
+ {
2735
+ console.log(`${property} does not match: arrays have different lengths.`);
2736
+ return false;
2737
+ }
2738
+
2739
+ for (var index = 0; index < received.length; index++)
2740
+ {
2741
+ if (received[index].length != expected[index].length)
2742
+ {
2743
+ console.log(`${property} does not match: arrays have different lengths.`);
2744
+ return false;
2745
+ }
2746
+
2747
+ for (var inner = 0; inner < received[index].length; inner++)
2748
+ {
2749
+ const cell: string = property + '/' + index.toString() + '/' + inner.toString();
2750
+ if (!matchFloats(cell, received[index][inner], expected[index][inner], tolerance)) return false;
2751
+ }
2752
+ }
2753
+
2754
+ return true;
2755
+ }
2756
+ */
2245
2757
 
2246
2758
 
2247
2759
  /***/ }),
@@ -2257,24 +2769,27 @@ exports.scorePlan = scorePlan;
2257
2769
  // GLOBAL CONSTANTS
2258
2770
  //
2259
2771
  Object.defineProperty(exports, "__esModule", ({ value: true }));
2260
- 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;
2772
+ exports.OUT_OF_STATE = exports.NUMBER_OF_ITEMS_TO_REPORT = exports.NOT_ASSIGNED = exports.PRECISION = void 0;
2261
2773
  // Keep four decimal places for fractions [0–1], i.e.,
2262
2774
  // keep two decimal places for %'s [0–100].
2263
2775
  exports.PRECISION = 4;
2776
+ // LEGACY - Not used
2264
2777
  // Normalized scores [0-100]
2265
- exports.NORMALIZED_RANGE = 100;
2778
+ // export const NORMALIZED_RANGE: number = 100;
2266
2779
  // The dummy district ID for features not assigned districts yet
2267
2780
  exports.NOT_ASSIGNED = 0;
2268
2781
  // # of items to report as problematic (e.g., features, districts, etc.)
2269
2782
  exports.NUMBER_OF_ITEMS_TO_REPORT = 10;
2270
2783
  // The virtual geoID for "neighbors" in other states
2271
2784
  exports.OUT_OF_STATE = "OUT_OF_STATE";
2785
+ // LEGACY - Not used
2272
2786
  // "Roughly equal" = average census block size / 2
2273
- const AVERAGE_BLOCK_SIZE = 30;
2274
- exports.EQUAL_TOLERANCE = AVERAGE_BLOCK_SIZE / 2;
2787
+ // const AVERAGE_BLOCK_SIZE = 30;
2788
+ // export const EQUAL_TOLERANCE: number = AVERAGE_BLOCK_SIZE / 2;
2789
+ // LEGACY - Not used
2275
2790
  // County & district splitting weights
2276
- exports.COUNTY_SPLITTING_WEIGHT = 0.8;
2277
- exports.DISTRICT_SPLITTING_WEIGHT = 1.0 - exports.COUNTY_SPLITTING_WEIGHT;
2791
+ // export const COUNTY_SPLITTING_WEIGHT = 0.8;
2792
+ // export const DISTRICT_SPLITTING_WEIGHT = 1.0 - COUNTY_SPLITTING_WEIGHT;
2278
2793
  // 2020
2279
2794
  // export const SHAPES = "2010 VTD shapes";
2280
2795
 
@@ -2285,16 +2800,13 @@ exports.DISTRICT_SPLITTING_WEIGHT = 1.0 - exports.COUNTY_SPLITTING_WEIGHT;
2285
2800
  /*!**********************!*\
2286
2801
  !*** ./src/types.ts ***!
2287
2802
  \**********************/
2288
- /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
2803
+ /***/ ((__unused_webpack_module, exports) => {
2289
2804
 
2290
2805
 
2291
2806
  //
2292
2807
  // TYPE DEFINITIONS
2293
2808
  //
2294
2809
  Object.defineProperty(exports, "__esModule", ({ value: true }));
2295
- exports.estSeatProbability = void 0;
2296
- var dra_score_1 = __webpack_require__(/*! @dra2020/dra-score */ "@dra2020/dra-score");
2297
- Object.defineProperty(exports, "estSeatProbability", ({ enumerable: true, get: function () { return dra_score_1.estSeatProbability; } }));
2298
2810
  // END
2299
2811
 
2300
2812
 
@@ -2330,21 +2842,23 @@ var __importStar = (this && this.__importStar) || function (mod) {
2330
2842
  return result;
2331
2843
  };
2332
2844
  Object.defineProperty(exports, "__esModule", ({ value: true }));
2333
- 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;
2845
+ 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;
2334
2846
  const DT = __importStar(__webpack_require__(/*! @dra2020/dra-types */ "@dra2020/dra-types"));
2335
2847
  const _data_1 = __webpack_require__(/*! ./_data */ "./src/_data.ts");
2336
2848
  const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"));
2337
2849
  // PLAN HELPERS
2850
+ // LEGACY - Not used
2338
2851
  // Is a "neighbor" in state?
2339
- function isInState(geoID) {
2340
- return geoID != S.OUT_OF_STATE;
2341
- }
2342
- exports.isInState = isInState;
2852
+ // export function isInState(geoID: string): boolean
2853
+ // {
2854
+ // return geoID != S.OUT_OF_STATE;
2855
+ // }
2856
+ // LEGACY - Not used
2343
2857
  // Is a "neighbor" out of state?
2344
- function isOutOfState(geoID) {
2345
- return geoID == S.OUT_OF_STATE;
2346
- }
2347
- exports.isOutOfState = isOutOfState;
2858
+ // export function isOutOfState(geoID: string): boolean
2859
+ // {
2860
+ // return geoID == S.OUT_OF_STATE;
2861
+ // }
2348
2862
  // Get the districtID to which a geoID is assigned
2349
2863
  function getDistrict(plan, geoID) {
2350
2864
  // All geoIDs in a state *should be* assigned to a district (including the