huge election predictor overhaul

This commit is contained in:
Elijah R 2024-06-04 00:43:42 -04:00
parent cc9fb21fbc
commit ccc2b6e205
9 changed files with 1424 additions and 425 deletions

View file

@ -0,0 +1,630 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="600"
height="500"
version="1.1"
id="svg2"
sodipodi:docname="ElectoralCollege1789.svg"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview2"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:zoom="1.569697"
inkscape:cx="304.51737"
inkscape:cy="259.92277"
inkscape:window-width="1920"
inkscape:window-height="1018"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="text"
showguides="true"
showgrid="false" />
<metadata
id="metadata1">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>2024 US presidential election results</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<title
id="title1">2024 US presidential election results</title>
<defs
id="defs1">
<style
type="text/css"
id="style1">.state{fill:#C0C0C0;}
<!-- #F07763 for Rep; below for Dem -->
<!-- #HI, #DC {fill: #698DC5;} -->
</style>
</defs>
<g
id="outlines"
class="state"
transform="translate(-301.83139,-26.775509)">
<path
id="CT"
d="m 626.76329,181.89053 3.6,-3.2 1.9,-2.1 0.8,0.6 2.7,-1.5 5.2,-1.1 7,-3.5 -0.6,-4.2 -0.8,-4.4 -1.6,-6 -4.3,1.1 -21.8,4.7 0.6,3.1 1.5,7.3 v 8.3 l -0.9,2.1 1.7,2.2 z" />
<path
id="DE"
d="m 609.16329,238.19053 -1,0.5 -3.6,-2.4 -1.8,-4.7 -1.9,-3.6 -2.3,-1 -2.1,-3.6 0.5,-2 0.5,-2.3 0.1,-1.1 -0.6,0.1 -1.7,1 -2,1.7 -0.2,0.3 1.4,4.1 2.3,5.6 3.7,16.1 5,-0.3 6,-1.1 z" />
<path
id="IL"
d="m 393.46329,205.29053 -0.8,-2.6 -1.3,-3.7 -1.6,-1.8 -1.5,-2.6 -0.4,-5.5 -15.9,1.8 -17.4,1 h -12.3 l 0.2,2.1 2.2,0.9 1.1,1.4 0.4,1.4 3.9,3.4 0.7,2.4 -0.7,3.3 -1.7,3.7 -0.8,2.7 -2.4,1.9 -1.9,0.6 -5.2,1.3 -1.3,4.1 0.6,1.1 1.9,1.8 -0.2,4.3 -2.1,1.6 -0.5,1.3 v 2.8 l -1.8,0.6 -1.4,1.2 -0.4,1.2 0.4,2 -1.6,1.3 -0.9,2.8 0.3,3.9 2.3,7 7,7.6 5.7,3.7 v 4.4 l 0.7,1.2 6.6,0.6 2.7,1.4 -0.7,3.5 -2.2,6.2 -0.8,3 2,3.7 6.4,5.3 4.8,0.8 2.2,5.1 2,3.4 -0.9,2.8 1.5,3.8 1.7,2.1 1.6,-0.3 1,-2.2 2.4,-1.7 2.8,-1 6.1,2.5 0.5,-0.2 v -1.1 l -1.2,-2.7 0.4,-2.8 2.4,-1.6 3.4,-1.2 -0.5,-1.3 -0.8,-2 1.2,-1.3 1,-2.7 v -4 l 0.4,-4.9 2.5,-3 1.8,-3.8 2.5,-4 -0.5,-5.3 -1.8,-3.2 -0.3,-3.3 0.8,-5.3 -0.7,-7.2 -1.1,-15.8 -1.4,-15.3 -0.9,-11.7 z"
style="fill:#666666" />
<path
id="IN"
d="m 397.66329,207.09053 1.5,1 1.1,-0.3 2.1,-1.9 2.5,-1.8 14.3,-1.1 18.4,-1.8 1.6,15.5 4.9,42.6 -0.6,2.9 1.3,1.6 0.2,1.3 -2.3,1.6 -3.6,1.7 -3.2,0.4 -0.5,4.8 -4.7,3.6 -2.9,4 0.2,2.4 -0.5,1.4 h -3.5 l -1.4,-1.7 -5.2,3 0.2,3.1 -0.9,0.2 -0.5,-0.9 -2.4,-1.7 -3.6,1.5 -1.4,2.9 -1.2,-0.6 -1.6,-1.8 -4.4,0.5 -5.7,1 -4.24558,1.3 0.11261,-2.54369 0.56893,-4.53107 1.34275,-4.0825 2.25047,-3.9 2.53107,-3.52429 -0.83785,-5.29321 -0.78644,-3.15631 -0.75047,-3.14369 0.91262,-5.35631 -0.30584,-6.98738 -1.12524,-12.88155 -2.5,-30.1 z"
style="fill:#666666"
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccc" />
<path
id="MA"
d="m 666.26326,27.88981 -1.80078,1.800781 -4,2.900391 v 1 l -0.79883,0.798828 -2.70117,-0.59961 -1.29883,-2.298828 V 30.38981 l -1.30078,-0.199219 h -1.29883 l -2.10156,4.199219 -2.89844,8.90039 -1.80078,4.800782 0.19922,4.798828 0.20117,1.5 -0.80078,2.701172 -0.79883,1 v 6 l 1.89844,2.40039 -1.5,4 -2.59961,4.699219 -0.79883,5.5 V 83.2902 l -1.5,-0.40039 -1.30078,0.169922 11.69922,37.431638 0.20117,2.5 4,1.09961 0.5,3.09961 2.19922,0.90039 1.09961,-6.30078 0.20117,-4.40039 1.5,-1.29883 -1,-3.20117 3.09961,-3.59961 1.59961,1.5 1.30078,-0.5 5.29883,-3.09961 0.30078,-2.90039 2.90039,-0.5 1.59961,-2.59961 -0.19922,-1.599608 -0.30078,-3.09961 0.80078,-1.300781 -0.30078,-1.099609 -1.30078,-1.5 2.10156,-1.300782 1.79883,3.201172 1.5,-0.300781 0.30078,1.300781 v 1.59961 l 1.90039,0.199218 0.5,-2.699218 0.5,-0.59961 -1.60156,-1.5 1,-1.5 2.40039,-1.5 1,-1.5 1.80078,-0.201172 c 0,10e-7 0.4,2.09961 1,2.09961 h 1.29883 l 4.80078,-5.5 3.40039,-3.09961 1.90039,-0.599609 2.09961,-4.699219 v -1.90039 l -2.30078,-3.701172 -1.90039,-2.09961 -2.79883,0.5 0.5,1.09961 -0.20117,0.5 h -0.79883 l -2.90039,-2.298828 -0.19922,-4.800782 -0.80078,-1.90039 h -6 l -9.09961,-29.898438 -1.90039,-1 -6,-2.40039 z m 20.90039,61.800781 -2,0.699219 -1.40039,2.201172 1.80078,1.90039 c 0,0 1.29883,0.09883 1.29883,-0.201172 0,-0.299999 0.20117,-1.999999 0.20117,-2 l 0.89844,-0.798828 z m -8.59961,7.300781 -1.5,1.5 1.79883,2.898438 1.70117,-0.89844 -0.60156,-2.400388 z m -22.40039,36.999998 -3.70117,1.79883 -1.79883,2.90039 -18.30078,4.69922 -13.79883,2.5 -0.60156,10.60156 0.70117,4.89844 22,-4.79883 11.19922,-2.80078 2,1.59961 3.40039,4.30078 2.90039,4.69922 2.09961,-0.89844 -0.5,-2.30078 0.80078,-1.5 2.89844,-1.5 0.80078,3.09961 -0.5,1.80078 -2.40039,1.5 v 1 l 1.90039,-1.5 3.90039,-4.5 3.90039,-1.90039 4.19922,-1.5 -0.30078,-2.40039 -1,-2.90039 -1.89844,-2.39844 -1.80078,-0.80078 -2.09961,0.19922 -0.5,0.5 1,1.30078 1.5,-0.80078 2.09961,1.60156 0.80078,2.69922 -1.80078,1.80078 -2.30078,1 -3.59961,-0.5 -3.90039,-6 -2.29883,-2.60156 h -1.80078 l -1.09961,0.80078 -1.90039,-2.59961 0.30078,-1.5 2.40039,-5.20117 z m 21.29883,28.5 -0.5,1.69922 -2.19922,0.69922 -0.5,0.60156 3.90039,-0.10156 1.29883,-0.5 -1,-2.29883 z m -9.79883,0.59961 -2.30078,2.59961 1.09961,0.90039 2.20117,-1 2.40039,-1 -1.80078,-1.5 z" />
<path
id="MD"
d="m 609.56329,255.09053 1.7,-3.8 0.5,-4.8 -6.3,1.1 -5.8,0.3 -3.8,-16.8 -2.3,-5.5 -1.5,-4.6 -22.2,4.3 -37.6,7.6 2,10.4 4.8,-4.9 2.5,-0.7 1.4,-1.5 1.8,-2.7 1.6,0.7 2.6,-0.2 2.6,-2.1 2,-1.5 2.1,-0.6 1.5,1.1 2.7,1.4 1.9,1.8 1.3,1.4 4.8,1.6 -0.6,2.9 5.8,2.1 2.1,-2.6 3.7,2.5 -2.1,3.3 -0.7,3.3 -1.8,2.6 v 2.1 l 0.3,0.8 2,1.3 3.4,1.1 4.3,-0.1 3.1,1 2.1,0.3 1,-2.1 -1.5,-2.1 v -1.8 l -2.4,-2.1 -2.1,-5.5 1.3,-5.3 -0.2,-2.1 -1.3,-1.3 c 0,0 1.5,-1.6 1.5,-2.3 0,-0.6 0.5,-2.1 0.5,-2.1 l 1.9,-1.3 1.9,-1.6 0.5,1 -1.5,1.6 -1.3,3.7 0.3,1.1 1.8,0.3 0.5,5.5 -2.1,1 0.3,3.6 0.5,-0.2 1.1,-1.9 1.6,1.8 -1.6,1.3 -0.3,3.4 2.6,3.4 3.9,0.5 1.6,-0.8 3.2,4.2 1,0.4 z m -14.5,0.2 1.1,2.5 0.2,1.8 1.1,1.9 c 0,0 0.9,-0.9 0.9,-1.2 0,-0.3 -0.7,-3.1 -0.7,-3.1 l -0.7,-2.3 z" />
<path
id="MI"
d="m 419.37591,203.0604 19.60678,-0.66119 -0.4194,0.14274 9.9,-1.55631 12.33786,-1.53107 -0.23786,-2.06404 0.2,-1.5 2.1,-3.7 2,-1.7 -0.2,-5.1 1.6,-1.6 1.1,-0.3 0.2,-3.6 1.5,-3 1.1,0.6 0.2,0.6 0.8,0.2 1.9,-1 -0.4,-9.1 -3.2,-8.2 -2.3,-9.1 -2.4,-3.2 -2.6,-1.8 -1.6,1.1 -3.9,1.8 -1.9,5 -2.7,3.7 -1.1,0.6 -1.5,-0.6 c 0,0 -2.6,-1.5 -2.4,-2.1 0.2,-0.6 0.5,-5 0.5,-5 l 3.4,-1.3 0.8,-3.4 0.6,-2.6 2.4,-1.6 -0.3,-10 -1.6,-2.3 -1.3,-0.8 -0.8,-2.1 0.8,-0.8 1.6,0.3 0.2,-1.6 -2.6,-2.2 -1.3,-2.6 h -2.6 l -4.5,-1.5 -5.5,-3.4 h -2.7 l -0.6,0.6 -1,-0.5 -3.1,-2.3 -2.9,1.8 -2.9,2.3 0.3,3.6 1,0.3 2.1,0.5 0.5,0.8 -2.6,0.8 -2.6,0.3 -1.5,1.8 -0.3,2.1 0.3,1.6 0.3,5.5 -3.6,2.1 -0.6,-0.2 v -4.2 l 1.3,-2.4 0.6,-2.4 -0.8,-0.8 -1.9,0.8 -1,4.2 -2.7,1.1 -1.8,1.9 -0.2,1 0.6,0.8 -0.6,2.6 -2.3,0.5 v 1.1 l 0.8,2.4 -1.1,6.1 -1.6,4 0.6,4.7 0.5,1.1 -0.8,2.4 -0.3,0.8 -0.3,2.7 3.6,6 2.9,6.5 1.5,4.8 -0.8,4.7 -1,6 -2.4,5.2 -0.3,2.7 -3.2,4.16987 z m -34.52748,-72.35501 -1.7778,-1.02036 -1.64074,-9.6833 -3.7,-1.5389 -0.82403,-2.37964 -12.3611,-1.76476 -2.64074,-1.73707 -8.25926,-2.2 -8.59633,-1.4778 -3.34257,-6.0167 1.25743,-1.29633 2.7,-0.8 3.6,-2.299998 v -1 l 0.6,-0.6 6,-1 2.4,-1.9 4.4,-2.1 0.2,-1.3 1.9,-2.9 1.8,-0.8 1.3,-1.8 2.3,-2.3 4.4,-2.4 4.7,-0.5 1.1,1.1 -0.3,1 -3.7,1 -1.5,3.1 -2.3,0.8 -0.5,2.4 -2.4,3.2 -0.3,2.6 0.8,0.5 1,-1.1 3.6,-2.9 1.3,1.3 h 2.3 l 3.2,1 1.5,1.1 1.5,3.1 2.7,2.699998 3.9,-0.2 1.5,-0.999998 1.6,1.299998 1.6,0.5 1.3,-0.8 h 1.1 l 1.6,-0.999998 4,-3.6 3.4,-1.1 6.6,-0.3 4.5,-1.9 2.6,-1.3 1.5,0.2 v 5.7 l 0.5,0.3 2.9,0.8 1.9,-0.5 6.1,-1.6 1.1,-1.1 1.5,0.5 v 6.999998 l 3.2,3.1 1.3,0.6 1.3,1 -1.3,0.3 -0.8,-0.3 -3.7,-0.5 -2.1,0.6 -2.3,-0.2 -3.2,1.5 h -1.8 l -5.8,-1.3 -5.2,0.2 -1.9,2.6 -7,0.6 -2.4,0.8 -1.1,3.1 -1.3,1.1 -0.5,-0.2 -1.5,-1.6 -4.5,2.4 h -0.6 l -1.1,-1.6 -0.8,0.2 -1.9,4.4 -1,4 -3.60824,7.85022 z m -28.48514,-57.614858 1.8,-2.1 2.2,-0.8 5.4,-3.9 2.3,-0.6 0.5,0.5 -5.1,5.1 -3.3,1.9 -2.1,0.9 z m 86.2,32.099998 0.6,2.5 3.2,0.2 1.3,-1.2 c 0,0 -0.1,-1.5 -0.4,-1.6 -0.3,-0.2 -1.6,-1.9 -1.6,-1.9 l -2.2,0.2 -1.6,0.2 -0.3,1.1 z"
style="fill:#666666"
sodipodi:nodetypes="cccccccccccccccccccccccccccccsccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" />
<path
id="NC"
d="m 561.46329,348.69053 -12.7,-7.7 -3.1,-0.8 -16.6,2.1 -1.6,-3 -2.8,-2.2 -16.7,0.5 -7.4,0.9 -9.2,4.5 -6.8,2.7 -6.5,1.2 -17.22902,1.96309 1.78927,-4.77571 1.81262,-3.43975 2.36214,1.66499 1.15048,-5.15142 4.01262,-1.59906 c 1.29998,-0.49999 -7.91012,-0.16486 3.67476,-1.95047 l 4.04953,-3.36214 4.51261,-2.63786 0.92524,-3.2 5.22618,-3.8 1.43202,-0.43589 1.79614,0.28449 2.14661,-2.69905 2.9388,-0.4 1.58643,0.18738 1.01168,-3.43691 2.83785,-1.72429 0.27476,-1.57476 -0.0126,-3.72524 6.20189,0.21262 38.5,-5.6 57.5,-12.3 2,4.8 3.6,6.5 2.4,2.4 0.6,2.3 -2.4,0.2 0.8,0.6 -0.3,4.2 -2.6,1.3 -0.6,2.1 -1.3,2.9 -3.7,1.6 -2.4,-0.3 -1.5,-0.2 -1.6,-1.3 0.3,1.3 v 1 h 1.9 l 0.8,1.3 -1.9,6.3 h 4.2 l 0.6,1.6 2.3,-2.3 1.3,-0.5 -1.9,3.6 -3.1,4.8 h -1.30001 l -1.1,-0.5 -2.7,0.6 -5.2,2.4 -6.5,5.3 -3.4,4.7 -1.9,6.5 -0.5,2.4 -4.7,0.5 -5.1,1.5 z m 49.3,-26.2 2.6,-2.5 3.2,-2.6 1.5,-0.6 0.2,-2 -0.6,-6.1 -1.5,-2.3 -0.6,-1.9 0.7,-0.2 2.7,5.5 0.4,4.4 -0.2,3.4 -3.4,1.5 -2.8,2.4 -1.1,1.2 z"
style="fill:#c0c0c0;fill-opacity:1"
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" />
<path
id="NH"
d="m 656.46329,132.29053 1.1,-3.2 -2.7,-1.2 -0.5,-3.1 -4.1,-1.1 -0.3,-3 -11.7,-37.479998 -0.7,0.08 -0.6,1.6 -0.6,-0.5 -1,-1 -1.5,1.9 -0.2,2.29 0.5,8.41 1.9,2.8 v 4.299998 l -3.9,4.8 -2.4,0.9 v 0.7 l 1.1,1.9 v 8.6 l -0.8,9.2 -0.2,4.7 1,1.4 -0.2,4.7 -0.5,1.5 1,1.1 5.1,-1.2 13.8,-3.5 1.7,-2.9 4,-1.9 z" />
<path
id="NJ"
d="m 598.46329,219.29053 0.1,-1.5 2.7,-1.3 1.7,-2.8 1.7,-2.4 3.3,-3.2 v -1.2 l -6.1,-4.1 -1,-2.7 -2.7,-0.3 -0.1,-0.9 -0.7,-2.2 2.2,-1.1 0.2,-2.9 -1.3,-1.3 0.2,-1.2 1.9,-3.1 v -3.1 l 2.5,-3.1 5.6,2.5 6.4,1.9 2.5,1.2 0.1,1.8 -0.5,2.7 0.4,4.5 -2.1,1.9 -1.1,1 0.5,0.5 2.7,-0.3 1.1,-0.8 1.6,3.4 0.2,9.4 0.6,1.1 -1.1,5.5 -3.1,6.5 -2.7,4 -0.8,4.8 -2.1,2.4 h -0.8 l -0.3,-2.7 0.8,-1 -0.2,-1.5 -4,-0.6 -4.8,-2.3 -3.2,-2.9 -1,-2 z" />
<path
id="NY"
d="m 618.16329,190.99053 0.5,-2.7 -0.2,-2.4 -3,-1.5 -6.5,-2 -6,-2.6 -0.6,-0.4 -2.7,-0.3 -2,-1.5 -2.1,-5.9 -3.3,-0.5 -2.4,-2.4 -38.4,8.1 -31.6,6 -0.5,-6.5 1.6,-1.2 1.3,-1.1 1,-1.6 1.8,-1.1 1.9,-1.8 0.5,-1.6 2.1,-2.7 1.1,-1 -0.2,-1 -1.3,-3.1 -1.8,-0.2 -1.9,-6.1 2.9,-1.8 4.4,-1.5 4,-1.3 3.2,-0.5 6.3,-0.2 1.9,1.3 1.6,0.2 2.1,-1.3 2.6,-1.1 5.2,-0.5 2.1,-1.8 1.8,-3.2 1.6,-1.9 h 2.1 l 1.9,-1.1 0.2,-2.3 -1.5,-2.1 -0.3,-1.5 1.1,-2.1 v -1.5 h -1.8 l -1.8,-0.8 -0.8,-1.1 -0.2,-2.6 5.8,-5.5 0.6,-0.8 1.5,-2.9 2.9,-4.5 2.7,-3.7 2.1,-2.4 2.4,-1.8 3.1,-1.2 5.5,-1.3 3.2,0.2 4.5,-1.499998 7.4,-2.2 0.7,4.899998 2.4,6.5 0.8,5 -1,4.2 2.6,4.5 0.8,2 -0.9,3.2 3.7,1.7 2.7,10.2 v 5.8 l -0.6,10.9 0.8,5.4 0.7,3.6 1.5,7.3 v 8.1 l -1.1,2.3 2.1,2.7 0.5,0.9 -1.9,1.8 0.3,1.3 1.3,-0.3 1.5,-1.3 2.3,-2.6 1.1,-0.6 1.6,0.6 2.3,0.2 7.9,-3.9 2.9,-2.7 1.3,-1.5 4.2,1.6 -3.4,3.6 -3.9,2.9 -7.1,5.3 -2.6,1 -5.8,1.9 -4,1.1 -1,-0.4 z"
style="fill:#000000" />
<path
id="OH"
d="m 437.3808,202.30315 1.19321,15.5 4.91262,41.38154 5.47666,-0.59416 2.3,-0.8 3.6,1.8 1.7,4.2 5.4,0.1 1.8,2 h 1.7 l 2.4,-1.4 3.1,0.5 1.5,1.3 1.8,-2 2.3,-1.4 2.4,-0.4 0.6,2.7 1.6,1 2.6,2 0.8,0.2 2,-0.1 1.2,-0.6 v -2.1 l 1.7,-1.5 0.1,-4.8 1.1,-4.2 1.9,-1.3 1,0.7 1,1.1 0.7,0.2 0.4,-0.4 -0.9,-2.7 v -2.2 l 1.1,-1.4 2.5,-3.6 1.3,-1.5 2.2,0.5 2.1,-1.5 3,-3.3 2.2,-3.7 0.2,-5.4 0.5,-5 v -4.6 l -1.2,-3.2 1.2,-1.8 1.3,-1.2 -0.6,-2.8 -4.3,-25.6 -6.2,3.7 -3.9,2.3 -3.4,3.7 -4,3.9 -3.2,0.8 -2.9,0.5 -5.5,2.6 -2.1,0.2 -3.4,-3.1 -5.2,0.6 -2.6,-1.5 -2.2,-1.3 z"
style="fill:#666666"
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" />
<path
id="PA"
d="m 511.36329,183.19053 1.3,-0.5 5.7,-5.5 0.7,6.9 33.5,-6.5 36.9,-7.8 2.3,2.3 3.1,0.4 2,5.6 2.4,1.9 2.8,0.4 0.1,0.1 -2.6,3.2 v 3.1 l -1.9,3.1 -0.2,1.9 1.3,1.3 -0.2,1.9 -2.4,1.1 1,3.4 0.2,1.1 2.8,0.3 0.9,2.5 5.9,3.9 v 0.4 l -3.1,3 -1.5,2.2 -1.7,2.8 -2.7,1.2 -1.4,0.3 -2.1,1.3 -1.6,1.4 -22.4,4.3 -38.7,7.8 -11.3,1.4 -3.9,0.7 -5.1,-22.4 -4.3,-25.9 z" />
<path
id="RI"
d="m 648.36329,166.69053 -0.8,-4.4 -1.6,-6 5.7,-1.5 1.5,1.3 3.4,4.3 2.8,4.4 -2.8,1.4 -1.3,-0.2 -1.1,1.8 -2.4,1.9 -2.8,1.1 z" />
<path
id="SC"
d="m 533.76329,404.59053 -2.1,-1 -1.9,-5.6 -2.5,-2.3 -2.5,-0.5 -1.5,-4.6 -3,-6.5 -4.2,-1.8 -1.9,-1.8 -1.2,-2.6 -2.4,-2 -2.3,-1.3 -2.2,-2.9 -3.2,-2.4 -4.4,-1.7 -0.4,-1.4 -2.3,-2.8 -0.5,-1.5 -3.8,-5.4 -3.4,0.1 -3.9,-2.5 -1.2,-1.2 -0.2,-1.4 0.6,-1.6 2.7,-1.3 -0.8,-2 6.4,-2.7 9.2,-4.5 7.1,-0.9 16.4,-0.5 2.3,1.9 1.8,3.5 4.6,-0.8 12.6,-1.5 2.7,0.8 12.5,7.4 10.1,8.3 -5.3,5.4 -2.6,6.1 -0.5,6.3 -1.6,0.8 -1.1,2.7 -2.4,0.6 -2.1,3.6 -2.7,2.7 -2.3,3.4 -1.6,0.8 -3.6,3.4 -2.9,0.2 1,3.2 -5,5.3 -2.3,1.6 z"
/>
<path
id="TN"
d="m 445.56329,350.59053 -13.1,1.2 -23.3,2.2 -37.6,2.7 -11.8,0.4 0.9,-0.6 0.9,-4.5 -1.2,-3.6 3.9,-2.3 0.4,-2.5 1.2,-4.3 3,-9.5 0.5,-5.6 0.3,-0.2 12.3,-0.2 13.6,-0.8 0.1,-3.9 3.5,-0.1 30.4,-3.3 54,-5.2 10.3,-1.5 7.6,-0.2 2.4,-1.9 1.3,0.3 -0.1,3.3 -0.4,1.6 -2.4,2.2 -1.6,3.6 -2,-0.4 -2.4,0.9 -2.2,3.3 -1.4,-0.2 -0.8,-1.2 -1.1,0.4 -4.3,4 -0.8,3.1 -4.2,2.2 -4.3,3.6 -3.8,1.5 -4.4,2.8 -0.6,3.6 -2.5,0.5 -2,1.7 -0.2,4.8 z"
style="fill:#c0c0c0;fill-opacity:1" />
<path
id="VT"
d="m 607.46329,102.29053 2.4,6.5 0.8,5.3 -1,3.9 2.5,4.4 0.9,2.3 -0.7,2.6 3.3,1.5 2.9,10.8 v 5.3 l 11.5,-2.1 -1,-1.1 0.6,-1.9 0.2,-4.3 -1,-1.4 0.2,-4.7 0.8,-9.3 v -8.5 l -1.1,-1.8 v -1.6 l 2.8,-1.1 3.5,-4.4 v -3.599998 l -1.9,-2.7 -0.3,-5.79 -26.1,6.79 z"
style="fill:#000000" />
<path
id="WI"
d="m 316.16329,100.89053 2.9,0.5 2.9,-0.6 7.4,-3.199998 2.9,-1.9 2.1,-0.8 1.9,1.5 -1.1,1.1 -1.9,3.099998 -0.6,1.9 1,0.6 1.8,-1 1.1,-0.2 2.7,0.8 0.6,1.1 1.1,0.2 0.6,-1.1 4,5.3 8.2,1.2 8.2,2.2 2.6,1.1 12.3,2.6 1.6,2.3 3.6,1.2 1.7,10.2 1.6,1.4 1.5,0.9 -1.1,2.3 -1.8,1.6 -2.1,4.7 -1.3,2.4 0.2,1.8 1.5,0.3 1.1,-1.9 1.5,-0.8 0.8,-2.3 1.9,-1.8 2.7,-4 4.2,-6.3 0.8,-0.5 0.3,1 -0.2,2.3 -2.9,6.8 -2.7,5.7 -0.5,3.2 -0.6,2.6 0.8,1.3 -0.2,2.7 -1.9,2.4 -0.5,1.8 0.6,3.6 0.6,3.4 -1.5,2.6 -0.8,2.9 -1,3.1 1.1,2.4 0.6,6.1 1.6,4.5 -0.0874,4.46404 -16.01262,1.68738 -17.5,0.88738 -12.58738,0.0563 -0.8126,-2.7951 -2.9,-0.4 -2.6,-1.3 -2.3,-3.7 -0.3,-3.6 2,-2.9 -0.5,-1.4 -2.1,-2.2 -0.8,-3.3 -0.6,-6.8 -2.1,-2.5 -7,-4.5 -3.8,-5.4 -3.4,-1 -2.2,-2.8 h -3.2 l -2.9,-3.3 -0.5,-6.5 0.1,-3.8 1.5,-3.1 -0.8,-3.2 -2.5,-2.8 1.8,-5.4 5.2,-3.8 1.6,-1.9 -0.2,-8.1 0.2,-2.8 2.4,-2.8 z"
style="fill:#666666"
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" />
<path
id="VA"
d="m 512.08093,215.61215 -1.2832,1.29297 -0.96875,1.45507 1.13085,3.07227 v 4.6875 l -0.48437,5.01172 -0.32422,5.65625 -2.26367,3.88086 -3.07031,3.39453 -2.26367,1.61719 -2.10157,-0.48438 -1.29297,1.45508 -2.26562,3.39453 -0.96875,1.29297 v 2.42578 l 1.13086,1.77734 -0.48438,1.61719 -1.77734,0.96875 -0.48438,-1.77734 -1.29492,-1.13086 -1.29297,0.64453 -0.96875,3.88086 -0.16211,5.01172 -1.61718,1.45508 -0.16211,2.74804 -1.9375,0.8086 -2.1836,0.0801 -1.05078,0.10157 -0.006,-0.22461 -2.42187,-2.21485 -1.77735,-0.96875 -0.64648,-2.75 h -1.61719 l -1.77734,1.29297 -2.74805,2.58594 -1.29297,-1.45508 -3.07031,-0.48437 -2.42578,1.45507 -2.10156,-0.1621 -1.7793,-1.7793 -5.81836,-0.32227 -1.61719,-4.36523 -2.91015,-1.61719 -2.42383,0.80859 -4.12305,0.24219 -0.5664,2.1836 1.45507,1.45507 0.32422,1.93946 -2.74804,1.93945 -3.88086,1.77734 -2.74805,0.32422 -0.48438,4.52539 -4.6875,3.88086 -2.91015,3.55664 0.32226,2.26368 -0.80859,2.10156 h -4.6875 l -1.13281,-1.61719 -1.13086,0.80859 -2.91016,1.61719 0.16211,3.39453 -2.10351,0.48438 -0.8086,-1.13086 -1.93945,-1.61719 -2.91016,1.45508 -1.77734,3.23242 -1.77735,-0.80859 -1.45507,-1.93946 -3.55664,0.48633 -5.82032,0.96875 -2.99023,1.69727 -1.05078,3.3125 -1.13281,0.81055 0.64648,1.9375 0.80859,1.77929 -1.61523,0.64649 -2.58789,0.64648 -1.93945,1.45508 -0.32227,2.26172 1.29297,2.42578 -0.16211,2.26367 -1.13086,0.32422 -3.55664,-1.29492 -2.74805,-1.29297 -2.10156,0.64648 -2.26367,1.7793 -0.80274,1.9043 1.60547,2.53906 -0.91406,1.82812 -0.22852,3.20118 -2.05859,1.14453 -2.17969,1.76172 -1.91211,0.22265 10.42969,-0.20508 6.95117,-0.64648 8.17969,-0.14453 0.22852,-4.2207 3.86718,0.0273 4.6211,-0.51367 15.75976,-1.77735 51.86914,-4.89843 3.51953,-0.38477 0.29297,-0.17578 1.74024,-0.0586 8.92578,-0.95118 8.38281,-0.97851 7.33789,-0.22071 2.58594,-1.92773 6.67969,0.375 37.42578,-5.27734 58.17578,-12.57617 -3.61328,-6.00977 -5.80078,1.68555 -1.57227,-1.49414 2.55274,-1.38086 -0.49024,-2.52344 -1.77344,-1.78516 v -0.002 l -0.12109,-1.41016 -2.28125,-1.54492 -0.0879,-1.61523 2.69336,0.0957 0.22266,-1.38477 -1.23047,-0.79101 0.48047,-1.92969 v -0.002 l -1.375,-1.10156 0.43945,-4.68946 v -0.002 l -0.86914,-1.19922 -3.18945,-0.40234 -2.15235,-2.08789 -4.85547,-0.94141 -2.94922,-0.96875 -4.625,-1.0918 -1.60546,-1.63086 -0.14063,-2.40429 0.50586,-1.7461 1.26367,-1.32617 0.86914,-3.68164 -1.29297,-1.79297 -1.88867,-0.67578 -0.21094,-0.30859 -2.15429,-0.53711 -1.43555,-0.51367 -2.47656,-0.60157 -0.0274,-0.0137 -0.006,-2.97851 -3.54687,-1.31641 c 0,0 -0.50769,-0.31367 -0.72266,-0.44727 l 0.006,-0.16992 -1.375,-1.29297 -1.9375,-1.77734 h -0.002 l -2.22852,-1.11524 -1.30273,-1.01757 -1.84766,0.48633 -2.00586,1.45312 -2.58593,2.10156 -2.91016,0.32227 -1.17969,-0.64453 -1.77929,2.58593 -1.45508,1.45508 -2.53711,0.61524 -2.26367,3.07031 -3.56055,2.75 -1.08203,-6.90625 -1.11328,-4.94531 -11.30078,1.55078 -4.63086,0.75195 z m 98.07812,40.30664 -6.45312,2.55078 0.14453,1.94726 -0.76758,3.09766 -1.58789,4.18359 -0.44531,5.44922 1.4707,4.64063 2.16406,-1.91602 1.82813,-4.97851 -0.46289,-3.39063 0.41797,-4.58594 2.91992,-3.77929 0.77148,-3.2168 z"
/>
<path
id="GA"
d="m 484.35742,346.5561 -5.82031,0.9707 -6.95117,0.8086 -6.79102,0.48437 -4.84961,0.8086 -8.40624,1.13281 -8.56836,0.88867 -1.11329,0.43359 0.0137,-0.21093 -8.92188,0.66211 -27.80469,2.58593 -7.75781,0.3711 v 0.0293 l -1.08008,0.0156 -4.58007,0.22852 -24.0879,1.93945 -8.67578,0.0781 -0.10547,3.41211 -2.74414,1.14258 -2.74414,5.25977 0.6875,1.37109 v 2.51562 l -2.74414,0.91407 -3.6582,5.25781 0.6875,2.05859 -2.97266,2.74219 -0.91406,6.17383 -0.45703,1.82812 1.37109,2.0586 -1.37109,1.37305 1.37109,2.9707 0.40039,4.34375 -1.37304,2.6582 0.28711,5.34375 2.05664,4.57227 -0.22852,1.83007 2.28516,1.82813 -0.68555,3.20117 h -1.14453 l 0.91406,2.0586 -5.25781,9.14453 -3.42969,6.17383 -0.68555,8.00195 0.45704,1.59961 24.23437,-0.68555 10.30859,-0.66406 26.16407,-2.64063 13.27539,-1.07812 10.41211,-1.40625 25.54297,-2.91016 6.78906,-0.64648 h 6.30469 l -0.006,-0.0137 0.86523,0.64843 2.58594,3.88086 1.45508,1.45508 7.92187,0.16016 10.81836,-0.64649 21.51367,-1.29297 5.44336,-0.67382 4.57813,0.0273 0.16211,2.9082 2.58593,0.81055 0.32422,-4.36524 -1.61718,-4.52734 1.13085,-1.61523 5.82032,0.80859 4.97851,0.31641 -0.77539,-6.29883 2.26367,-10.02149 1.45508,-4.20312 -0.48437,-2.58594 3.33398,-6.24414 -0.51172,-1.35156 -1.91211,0.70312 -2.58789,-1.29297 -0.64453,-2.10156 -1.29297,-3.55664 -2.26562,-2.10351 -2.58594,-0.64453 -1.61523,-4.85157 -2.92579,-6.33398 -4.20312,-1.93945 -2.10156,-1.94141 -1.29492,-2.58594 -2.10157,-1.93945 -2.26367,-1.29297 -2.26367,-2.9082 -3.07031,-2.26563 -4.52539,-1.77734 -0.48633,-1.45508 -2.42383,-2.91016 -0.48633,-1.45312 -3.39453,-4.9082 -3.39453,0.16015 -4.13086,-3.04297 -1.29297,-1.29297 -0.32422,-1.77929 0.81055,-1.93946 2.35156,-1.23437 -1.13281,-1.22656 z"
/>
</g>
<text
id="PAn-6"
x="286.39993"
y="116.41373"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan87-6"
x="286.39993"
y="116.41373"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:13.3333px;font-family:'Helvetica Neue';-inkscape-font-specification:'Helvetica Neue Bold';text-align:center;text-anchor:middle;fill:#ffffff">NY</tspan><tspan
sodipodi:role="line"
id="tspan88-3"
x="286.39993"
y="133.1395"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:13.3333px;font-family:'Helvetica Neue';-inkscape-font-specification:'Helvetica Neue Bold';text-align:center;text-anchor:middle;fill:#ffffff">0</tspan></text>
<g
id="text"
font-family="'Helvetica Neue'"
font-weight="bold"
transform="translate(-527.0681,-35.784978)">
<g
font-size="28px"
id="g1">
<text
id="AKn"
x="121.59544"
y="493.18863"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan41"
x="121.59544"
y="493.18863"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff" /></text>
<text
id="HIn"
x="281.26047"
y="554.18866"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan20"
x="281.26047"
y="554.18866"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1" /></text>
<text
id="WAn"
x="117.53755"
y="49.386745"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan39"
x="117.53755"
y="49.386745"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff" /></text>
<text
id="AZn"
x="188.30663"
y="358.99054"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan28"
x="188.30663"
y="358.99054"
style="font-size:13.3333px;fill:#ffffff" /></text>
<text
id="UTn"
x="219.70537"
y="251.48579"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan26"
x="219.70537"
y="251.48579"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff" /></text>
<text
id="IDn"
x="194.15645"
y="151.80695"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
x="194.15645"
y="151.80695"
id="tspan22"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1" /></text>
<text
id="MTn"
x="279.21573"
y="85.347488"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan16"
x="279.21573"
y="85.347488"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff" /></text>
<text
id="WYn"
x="298.39981"
y="182.08109"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
x="298.39981"
y="182.08109"
id="tspan19"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff" /></text>
<text
id="COn"
x="319.78827"
y="270.08292"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan24"
x="319.78827"
y="270.08292"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1" /></text>
<text
id="NMn"
x="302.97266"
y="369.28769"
style="font-size:16px"><tspan
sodipodi:role="line"
x="302.97266"
y="369.28769"
id="tspan31"
style="font-size:16px;text-align:center;text-anchor:middle;fill:#ffffff" /></text>
<text
id="TXn"
x="415.85614"
y="451.69336"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan2"
x="415.85614"
y="451.69336"
style="font-size:13.3333px;fill:#ffffff;fill-opacity:1" /></text>
<text
id="OKn"
x="461.73621"
y="358.28769"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1"><tspan
sodipodi:role="line"
id="tspan6"
x="461.73621"
y="358.28769" /></text>
<text
id="NEn"
x="414.12476"
y="221.48842"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan10"
x="414.12476"
y="221.48842"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1" /></text>
<text
id="SDn"
x="415.85419"
y="157.25868"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan12"
x="415.85419"
y="157.25868"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1" /></text>
<text
id="NDn"
x="417.25748"
y="91.851349"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan14"
x="417.25748"
y="91.851349"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1" /></text>
<text
id="ARn"
x="547.24762"
y="374.0896"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan52"
x="547.24762"
y="374.0896"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1" /></text>
<text
id="MSn"
x="597.98846"
y="417.18863"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan48"
x="597.98846"
y="417.18863"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1" /></text>
<text
id="ALn"
x="650.66272"
y="409.38675"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan58"
x="650.66272"
y="409.38675"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1" /></text>
<text
id="GAn"
x="714.30121"
y="407.73816"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan50"
x="714.30121"
y="407.73816"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1" /></text>
<text
id="FLn"
x="763.43597"
y="504.54953"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan56"
x="763.43597"
y="504.54953"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#f8f8f8;fill-opacity:1" /></text>
<text
id="SCn"
x="759.23254"
y="347.11545"><tspan
sodipodi:role="line"
x="759.23254"
y="347.11545"
id="tspan61"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1" /></text>
<text
id="NCn"
x="781.7052"
y="328.48581"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan68"
x="781.7052"
y="328.48581"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1" /></text>
<text
id="TNn"
x="659.12402"
y="401.87637"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan65"
x="659.12402"
y="401.87637"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1">GA</tspan><tspan
sodipodi:role="line"
id="tspan66"
x="659.12402"
y="418.543"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1">5</tspan></text>
<text
id="TNn-3"
x="754.21326"
y="368.78839"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan65-5"
x="754.21326"
y="368.78839"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1">SC</tspan><tspan
sodipodi:role="line"
id="tspan66-5"
x="754.21326"
y="385.45502"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1">7</tspan></text>
<text
id="KYn"
x="756.65363"
y="277.30893"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan69"
x="756.65363"
y="277.30893"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff">VA</tspan><tspan
sodipodi:role="line"
id="tspan70"
x="756.65363"
y="293.97556"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff">10</tspan></text>
<text
id="VAn"
x="771.05426"
y="282.73816"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan86"
x="771.05426"
y="282.73816"
style="font-size:13.3333px;fill:#ffffff" /></text>
<text
id="PAn"
x="779.22137"
y="210.08958"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan87"
x="779.22137"
y="210.08958"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff">PA</tspan><tspan
sodipodi:role="line"
id="tspan88"
x="779.22137"
y="226.75621"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff">10</tspan></text>
<text
id="MEn"
x="891.53564"
y="78.833321"
style="font-size:13.3333px"><tspan
sodipodi:role="line"
id="tspan62"
x="891.53564"
y="78.833321"
style="font-size:13.3333px;text-align:center;text-anchor:middle;fill:#ffffff" /></text>
<text
id="MEn-9"
x="885.10718"
y="80.869125"
style="font-size:14.7521px;stroke-width:0.52686"><tspan
sodipodi:role="line"
id="tspan4"
x="885.10718"
y="80.869125"
style="fill:#ffffff;stroke-width:0.52686" /><tspan
sodipodi:role="line"
id="tspan5"
x="885.10718"
y="99.30925"
style="fill:#ffffff;stroke-width:0.52686" /></text>
<text
id="MEn-9-7"
x="877.93567"
y="111.5111"
style="font-size:14.7521px;stroke-width:0.52686"><tspan
sodipodi:role="line"
id="tspan4-0"
x="877.93567"
y="111.5111"
style="fill:#ffffff;stroke-width:0.52686" /><tspan
sodipodi:role="line"
id="tspan5-9"
x="877.93567"
y="129.95123"
style="fill:#ffffff;stroke-width:0.52686" /></text>
<text
id="MEn-9-0"
x="463.3028"
y="239.15771"
style="font-size:14.7521px;stroke-width:0.52686"><tspan
sodipodi:role="line"
id="tspan4-6"
x="463.3028"
y="239.15771"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.52686" /><tspan
sodipodi:role="line"
id="tspan5-2"
x="463.3028"
y="257.59784"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.52686" /></text>
<text
id="DemL"
x="855"
y="425" />
<text
id="RepL"
x="855"
y="458" />
</g>
<g
font-size="22px"
id="g2">
<text
id="NHn"
x="817.56848"
y="56.648579"
style="font-size:16px"><tspan
style="font-size:16px;fill:#ffffff"
id="tspan92">NH 5</tspan></text>
<text
id="MAn"
x="905.17847"
y="169.01566"
style="font-size:13.3333px"><tspan
style="font-size:13.3333px;fill:#ffffff"
id="tspan94">MA 10</tspan></text>
<text
id="RIn"
x="925"
y="199"
style="font-size:16px"><tspan
style="font-size:16px;fill:#ffffff"
id="tspan95" /></text>
<text
id="CTn"
x="918"
y="228"
style="font-size:16px"><tspan
style="fill:#ffffff"
id="tspan96">CT 7</tspan></text>
<text
id="NJn"
x="898"
y="260"
style="font-size:16px"><tspan
style="fill:#ffffff"
id="tspan97">NJ 6</tspan></text>
<text
id="DEn"
x="891"
y="284"
style="font-size:16px"><tspan
style="font-size:16px;fill:#ffffff"
id="tspan98">DE 3</tspan></text>
<text
id="MDn"
x="883"
y="305"
style="font-size:16px"><tspan
style="font-size:16px;fill:#ffffff"
id="tspan99">MD 6</tspan></text>
<text
id="DCn"
x="864"
y="327"
style="font-size:16px"><tspan
style="font-size:16px;fill:#ffffff"
id="tspan100" /></text>
</g>
</g>
<path
d="m 304.45211,224.13438 c 36.981,39.184 39.104,40.251 39.104,40.251"
stroke-width="1.5242"
stroke="#000000"
fill="none"
id="path5643"
style="fill:#ffffff;stroke-linecap:round" />
<path
d="m 309.80711,214.28538 c 51,26 51,26 51,26"
stroke-width="1.5"
stroke="#000000"
fill="none"
id="path8572"
style="fill:#ffffff;stroke-linecap:round" />
<path
d="m 317.80711,194.28538 c 50,22 50,22 50,22"
stroke-width="1.5"
stroke="#000000"
fill="none"
id="path9543"
style="fill:#ffffff;stroke-linecap:round" />
<path
d="m 361.80711,117.28538 c 34,3 34,3 34,3"
stroke-width="1.5"
stroke="#000000"
fill="none"
id="path11485"
style="fill:#ffffff;stroke-linecap:round" />
<path
d="m 338.80711,148.28538 c 50,33 51,33 51,33"
stroke-width="1.5"
stroke="#000000"
fill="none"
id="path13435"
style="fill:#ffffff;stroke-linecap:round" />
<path
d="m 330.04111,55.519381 c -13.469,-29.469 -13.469,-29.469 -13.469,-29.469"
stroke-width="1.5"
stroke="#000000"
fill="none"
id="path14422"
style="fill:#ffffff;stroke-linecap:round" />
<path
d="m 395.64811,120.12638 c -22.682,-40.682003 -22.682,-40.682003 -22.682,-40.682003"
stroke-width="2.2871"
stroke="#000000"
fill="none"
id="path9642"
style="fill:#ffffff;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none" />
<!--
<rect id="Dem" x="828" y="406" height="19" width="19" fill="#698DC5" stroke="#000000" stroke-width="0.8"/>
<rect id="Rep" x="828" y="439" height="19" width="19" fill="#F07763" stroke="#000000" stroke-width="0.8"/>
-->
</svg>

After

Width:  |  Height:  |  Size: 36 KiB

View file

@ -1,4 +1,5 @@
import {ApplicationCommandOptionType} from "discord.js"; import {ApplicationCommandOptionType} from "discord.js";
import Elections from "./elections/elections.js";
const commands = [ const commands = [
{ {
name: 'poll', name: 'poll',
@ -6,33 +7,54 @@ const commands = [
}, },
{ {
name: 'simulate', name: 'simulate',
description: "Simulate the 2024 United States Presidential Election", description: "Simulate an election",
options: [ options: [
{ {
name: 'bias', name: 'election',
description: 'Adds a bias to a certain candidate. Use a positive number for Biden bias, negative for Trump bias', description: 'The election to simulate',
type: ApplicationCommandOptionType.Number, type: ApplicationCommandOptionType.SubcommandGroup,
options: Object.keys(Elections).map(e => {
return {
name: e,
description: Elections[e].title,
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: 'add_candidate',
description: 'Add a candidate to the election',
type: ApplicationCommandOptionType.String,
},
{
name: 'with_party',
description: 'The party of the candidate to add',
type: ApplicationCommandOptionType.String,
},
{
name: 'with_color',
description: 'Hex color of the candidate to add',
type: ApplicationCommandOptionType.String
},
{
name: 'with_odds',
description: 'The odds of the candidate to win in any state',
type: ApplicationCommandOptionType.Number
},
...Elections[e].candidates.flatMap(c => [
{
name: c.party.toLowerCase().replace(/ /g, "_") + "_candidate",
description: `The candidate to simulate for the ${c.party} party (Default: ${c.name})`,
type: ApplicationCommandOptionType.String
},
{
name: c.party.toLowerCase().replace(/ /g, "_") + "_bias",
description: `The bias toward the ${c.party} party (Default: 0)`,
type: ApplicationCommandOptionType.Number
}
])
],
};
})
}, },
{
name: 'type',
description: 'The type of election to simulate. Valid options are senate and presidential (default: presidential)',
type: ApplicationCommandOptionType.String,
},
{
name: 'year',
description: 'The year to set the simulation to (default: 2024)',
type: ApplicationCommandOptionType.Number,
},
{
name: 'gopcandidate',
description: 'The GOP candidate to simulate (default: Donald Trump)',
type: ApplicationCommandOptionType.String,
},
{
name: 'demcandidate',
description: 'The Democratic candidate to simulate (default: Joe Biden)',
type: ApplicationCommandOptionType.String,
}
], ],
} }
]; ];

19
src/election.ts Normal file
View file

@ -0,0 +1,19 @@
export default interface Election {
title : string,
shortname : string,
description : string,
svg: string,
candidates : {
name : string,
party : string,
color : string
}[],
states : {
[key : string] : {
electoralVotes : number,
odds : {
[key : string] : number
}
}
}
}

214
src/elections/1864.ts Normal file
View file

@ -0,0 +1,214 @@
import { readFile } from "node:fs/promises";
import Election from "../election.js";
const Presidential_1864 = {
title: "1864 United States Presidential Election Simulator",
shortname: "1864",
description: "The CalubViem Press has rewritten history and called the 1864 United States Presidential Election for $WINNER!",
svg: await readFile("assets/ElectoralCollege1864.svg", "utf-8"),
candidates: [
{
name: "Abraham Lincoln",
party: "National Union",
color: "#BF1D29",
},
{
name: "George B. McClellan",
party: "Democratic",
color: "#1C408C",
},
],
states: {
"CA": {
electoralVotes: 5,
odds: {
"National Union": 0.7,
"Democratic": 0.3,
}
},
"CT": {
electoralVotes: 6,
odds: {
"National Union": 0.6,
"Democratic": 0.4,
}
},
"DE": {
electoralVotes: 3,
odds: {
"National Union": 0.5,
"Democratic": 0.5,
}
},
"IA": {
electoralVotes: 8,
odds: {
"National Union": 0.95,
"Democratic": 0.05,
}
},
"IL": {
electoralVotes: 16,
odds: {
"National Union": 0.8,
"Democratic": 0.2,
}
},
"IN": {
electoralVotes: 13,
odds: {
"National Union": 0.6,
"Democratic": 0.4,
}
},
"KS": {
electoralVotes: 3,
odds: {
"National Union": 1,
"Democratic": 0,
}
},
"KY": {
electoralVotes: 11,
odds: {
"National Union": 0.2,
"Democratic": 0.8,
}
},
"LA": {
electoralVotes: 7,
odds: {
"National Union": 0.2,
"Democratic": 0.8,
}
},
"MA": {
electoralVotes: 12,
odds: {
"National Union": 1,
"Democratic": 0,
}
},
"MD": {
electoralVotes: 7,
odds: {
"National Union": 0.7,
"Democratic": 0.3,
}
},
"ME": {
electoralVotes: 7,
odds: {
"National Union": 0.9,
"Democratic": 0.1,
}
},
"MI": {
electoralVotes: 8,
odds: {
"National Union": 0.7,
"Democratic": 0.3,
}
},
"MN": {
electoralVotes: 4,
odds: {
"National Union": 0.8,
"Democratic": 0.2,
}
},
"MO": {
electoralVotes: 11,
odds: {
"National Union": 0.99,
"Democratic": 0.01,
}
},
"NH": {
electoralVotes: 5,
odds: {
"National Union": 0.6,
"Democratic": 0.4,
}
},
"NV": {
electoralVotes: 2,
odds: {
"National Union": 0.9,
"Democratic": 0.1,
}
},
"NJ": {
electoralVotes: 7,
odds: {
"National Union": 0.4,
"Democratic": 0.6,
}
},
"NY": {
electoralVotes: 33,
odds: {
"National Union": 0.55,
"Democratic": 0.45,
}
},
"OH": {
electoralVotes: 21,
odds: {
"National Union": 0.7,
"Democratic": 0.3,
}
},
"OR": {
electoralVotes: 3,
odds: {
"National Union": 0.7,
"Democratic": 0.3,
}
},
"PA": {
electoralVotes: 26,
odds: {
"National Union": 0.6,
"Democratic": 0.4,
}
},
"RI": {
electoralVotes: 4,
odds: {
"National Union": 0.95,
"Democratic": 0.05,
}
},
"TN": {
electoralVotes: 10,
odds: {
"National Union": 1,
"Democratic": 0,
}
},
"VT": {
electoralVotes: 5,
odds: {
"National Union": 1,
"Democratic": 0,
}
},
"WI": {
electoralVotes: 8,
odds: {
"National Union": 0.7,
"Democratic": 0.3,
}
},
"WV": {
electoralVotes: 5,
odds: {
"National Union": 0.99,
"Democratic": 0.01,
}
},
}
}
export default Presidential_1864 as Election;

403
src/elections/2024.ts Normal file
View file

@ -0,0 +1,403 @@
import { readFile } from "node:fs/promises";
import Election from "../election.js";
const Presidential_2024 = {
title: "2024 United States Presidential Election Simulator",
shortname: "2024",
description: "The CalubViem Press has called the 2024 United States Presidential Election for $WINNER!",
svg: await readFile("assets/ElectoralCollege2024.svg", "utf-8"),
candidates: [
{
name: "Joseph R. Biden Jr.",
party: "Democratic",
color: "#1C408C",
},
{
name: "Donald J. Trump",
party: "Republican",
color: "#BF1D29",
}
],
states: {
"AL": {
electoralVotes: 9,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"AK": {
electoralVotes: 3,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"AZ": {
electoralVotes: 11,
odds: {
"Republican": 0.5,
"Democratic": 0.5,
}
},
"AR": {
electoralVotes: 6,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"CA": {
electoralVotes: 54,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"CO": {
electoralVotes: 10,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"CT": {
electoralVotes: 7,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"DE": {
electoralVotes: 3,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"DC": {
electoralVotes: 3,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"FL": {
electoralVotes: 30,
odds: {
"Republican": 0.6,
"Democratic": 0.4,
}
},
"GA": {
electoralVotes: 16,
odds: {
"Republican": 0.5,
"Democratic": 0.5,
}
},
"HI": {
electoralVotes: 4,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"ID": {
electoralVotes: 4,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"IL": {
electoralVotes: 19,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"IN": {
electoralVotes: 11,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"IA": {
electoralVotes: 6,
odds: {
"Republican": 0.8,
"Democratic": 0.2,
}
},
"KS": {
electoralVotes: 6,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"KY": {
electoralVotes: 8,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"LA": {
electoralVotes: 8,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"ME": {
electoralVotes: 2,
odds: {
"Republican": 0.2,
"Democratic": 0.8,
}
},
"ME-01": {
electoralVotes: 1,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"ME-02": {
electoralVotes: 1,
odds: {
"Republican": 0.8,
"Democratic": 0.2,
}
},
"MD": {
electoralVotes: 10,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"MA": {
electoralVotes: 11,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"MI": {
electoralVotes: 15,
odds: {
"Republican": 0.5,
"Democratic": 0.5,
}
},
"MN": {
electoralVotes: 10,
odds: {
"Republican": 0.4,
"Democratic": 0.6,
}
},
"MS": {
electoralVotes: 6,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"MO": {
electoralVotes: 10,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"MT": {
electoralVotes: 4,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"NE": {
electoralVotes: 4,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"NE-02": {
electoralVotes: 1,
odds: {
"Republican": 0.55,
"Democratic": 0.45,
}
},
"NV": {
electoralVotes: 6,
odds: {
"Republican": 0.5,
"Democratic": 0.5,
}
},
"NH": {
electoralVotes: 4,
odds: {
"Republican": 0.4,
"Democratic": 0.6,
}
},
"NJ": {
electoralVotes: 14,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"NM": {
electoralVotes: 5,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"NY": {
electoralVotes: 28,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"NC": {
electoralVotes: 16,
odds: {
"Republican": 0.55,
"Democratic": 0.45,
}
},
"ND": {
electoralVotes: 3,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"OH": {
electoralVotes: 17,
odds: {
"Republican": 0.8,
"Democratic": 0.2,
}
},
"OK": {
electoralVotes: 7,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"OR": {
electoralVotes: 8,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"PA": {
electoralVotes: 19,
odds: {
"Republican": 0.5,
"Democratic": 0.5,
}
},
"RI": {
electoralVotes: 4,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"SC": {
electoralVotes: 9,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"SD": {
electoralVotes: 3,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"TN": {
electoralVotes: 11,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"TX": {
electoralVotes: 40,
odds: {
"Republican": 0.8,
"Democratic": 0.2,
}
},
"UT": {
electoralVotes: 6,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"VT": {
electoralVotes: 3,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"VA": {
electoralVotes: 13,
odds: {
"Republican": 0.2,
"Democratic": 0.8,
}
},
"WA": {
electoralVotes: 12,
odds: {
"Republican": 0,
"Democratic": 1,
}
},
"WV": {
electoralVotes: 4,
odds: {
"Republican": 1,
"Democratic": 0,
}
},
"WI": {
electoralVotes: 10,
odds: {
"Republican": 0.5,
"Democratic": 0.5,
}
},
"WY": {
electoralVotes: 3,
odds: {
"Republican": 1,
"Democratic": 0,
}
}
}
}
export default Presidential_2024 as Election;

View file

@ -0,0 +1,10 @@
import Election from "../election.js";
import Presidential_1864 from "./1864.js";
import Presidential_2024 from "./2024.js";
const Elections = {
"1864": Presidential_1864,
"2024": Presidential_2024
}
export default (Elections as {[key : string] : Election})

View file

@ -1,7 +1,10 @@
import {REST, Routes, Client, GatewayIntentBits, CommandInteraction, EmbedBuilder } from "discord.js"; import {REST, Routes, Client, GatewayIntentBits, CommandInteraction, EmbedBuilder, CommandInteractionOption, CommandInteractionOptionResolver } from "discord.js";
import * as fs from "node:fs"; import * as fs from "node:fs";
import commands from "./commands.js"; import commands from "./commands.js";
import {MakePrediction} from "./predictor.js"; import {MakePrediction} from "./predictor.js";
import Election from "./election.js";
import Presidential_2024 from "./elections/2024.js";
import Elections from "./elections/elections.js";
const configraw = fs.readFileSync("config.json", "utf-8"); const configraw = fs.readFileSync("config.json", "utf-8");
const config = JSON.parse(configraw); const config = JSON.parse(configraw);
@ -31,59 +34,57 @@ if (!config.token) {
await i.reply(`Biden Approval Rating\n\n${polls}`); await i.reply(`Biden Approval Rating\n\n${polls}`);
break; break;
case "simulate": case "simulate":
var simulationtype = i.options.get('type')?.value as string || "presidential"; var electionname = (i.options as CommandInteractionOptionResolver).getSubcommand();
var year = Number(i.options.get('year')?.value);
switch(simulationtype) { var election = structuredClone(Elections[electionname]);
case "presidential": for (const candidate of election.candidates) {
if (year == 1864) { var option = (i.options as CommandInteractionOptionResolver).getString(candidate.party.toLowerCase().replace(/ /g, "_") + "_candidate");
var gopcandidate = i.options.get('gopcandidate')?.value as string || "Abraham Lincoln"; if (option) {
var demcandidate = i.options.get('demcandidate')?.value as string || "George B. McClellan"; candidate.name = option;
var result = await MakePrediction(Number(i.options.get('bias')?.value), gopcandidate, demcandidate, simulationtype, Number(i.options.get('year')?.value)); }
var embed = new EmbedBuilder() var bias = (i.options as CommandInteractionOptionResolver).getNumber(candidate.party.toLowerCase().replace(/ /g, "_") + "_bias");
.setTitle("1864 United States Presidential Election Simulator") if (bias) {
.setDescription(`The CalubViem Press has rewritten history, and has called the 1864 United States Presidential Election for ${result.winner}!`) for (const state of Object.keys(election.states)) {
.addFields( election.states[state].odds[candidate.party] += bias;
{name: `${result.winner === gopcandidate ? ":white_check_mark:" : ""} ${gopcandidate}`, value: `${result.gopVotes} Electoral Votes`, inline: true},
{name: `${result.winner === demcandidate ? ":white_check_mark:" : ""} ${demcandidate}`, value: `${result.demVotes} Electoral Votes`, inline: true},
)
.setImage("attachment://election.png")
.setTimestamp();
await i.reply({embeds: [embed], files: [{attachment: result.png, name: "election.png"}]});
break;
} else {
var gopcandidate = i.options.get('gopcandidate')?.value as string || "Donald J. Trump";
var demcandidate = i.options.get('demcandidate')?.value as string || "Joseph R. Biden Jr.";
var result = await MakePrediction(Number(i.options.get('bias')?.value), gopcandidate, demcandidate, simulationtype, Number(i.options.get('year')?.value));
var embed = new EmbedBuilder()
.setTitle("2024 United States Presidential Election Simulator")
.setDescription(`The CalubViem Press has called the 2024 United States Presidential Election for ${result.winner}!`)
.addFields(
{name: `${result.winner === gopcandidate ? ":white_check_mark:" : ""} ${gopcandidate}`, value: `${result.gopVotes} Electoral Votes`, inline: true},
{name: `${result.winner === demcandidate ? ":white_check_mark:" : ""} ${demcandidate}`, value: `${result.demVotes} Electoral Votes`, inline: true},
)
.setImage("attachment://election.png")
.setTimestamp();
await i.reply({embeds: [embed], files: [{attachment: result.png, name: "election.png"}]});
break;
} }
case "senate": }
var gopcandidate = i.options.get('gopcandidate')?.value as string || "Republicans";
var demcandidate = i.options.get('demcandidate')?.value as string || "Democrats";
var result = await MakePrediction(Number(i.options.get('bias')?.value), gopcandidate, demcandidate, simulationtype, 0);
var embed = new EmbedBuilder()
.setTitle("2024 United States Senate Simulator")
.setDescription(`The CalubViem Press has called the 2024 United States Senate for ${result.winner}!`)
.addFields(
{name: `${result.winner === gopcandidate ? ":white_check_mark:" : ""} ${gopcandidate}`, value: `${result.gopVotes} seats`, inline: true},
{name: `${result.winner === demcandidate ? ":white_check_mark:" : ""} ${demcandidate}`, value: `${result.demVotes} seats`, inline: true},
)
.setImage("attachment://election.png")
.setTimestamp();
await i.reply({embeds: [embed], files: [{attachment: result.png, name: "election.png"}]});
break;
} }
var newcandidate = (i.options as CommandInteractionOptionResolver).getString("add_candidate");
if (newcandidate) {
var party = (i.options as CommandInteractionOptionResolver).getString("with_party") || "Independent";
var color = (i.options as CommandInteractionOptionResolver).getString("with_color") || "#bfab22";
var odds = (i.options as CommandInteractionOptionResolver).getNumber("with_odds") || 0.33;
if (!/^#[0-9A-Fa-f]{3,6}$/.test(color)) {
await i.reply("Please provide a valid hex color code");
return;
}
if (election.candidates.some(c => c.party === party || c.name === newcandidate)) {
await i.reply("A candidate with that name or party already exists");
return
}
election.candidates.push({
name: newcandidate,
party: party,
color: color
});
for (const state of Object.keys(election.states))
election.states[state].odds[party] = odds;
}
var result = await MakePrediction(election);
var embed = new EmbedBuilder()
.setTitle(election.title)
.setDescription(election.description.replace("$WINNER", result.winner))
.addFields(result.candidates.map(c => {
return {
name: `${(result.winner === c.name ? ":white_check_mark:" : "")} ${c.name} (${c.party})`,
value: `${c.votes} Electoral Votes`,
inline: true
}
}))
.setImage("attachment://election.png")
.setTimestamp();
await i.reply({embeds: [embed], files: [{attachment: result.png, name: "election.png"}]});
} }
} }
}); });

View file

@ -1,236 +0,0 @@
const GOP_WIN_ODDS = {
// Data from https://www.insideelections.com/ratings/president
// Toss-up
"AZ": 0.5,
"GA": 0.5,
"MI": 0.5,
"NV": 0.5,
"PA": 0.5,
"WI": 0.5,
// Lean D
"MN": 0.4,
"NH": 0.4,
// Likely D
"ME": 0.2,
"VA": 0.2,
// Solid D
"CA": 0,
"CO": 0,
"CT": 0,
"DC": 0,
"DE": 0,
"HI": 0,
"IL": 0,
"MA": 0,
"MD": 0,
"NJ": 0,
"NM": 0,
"NY": 0,
"OR": 0,
"RI": 0,
"VT": 0,
"WA": 0,
"ME-01": 0,
// Tilt R
"NC": 0.55,
"NE-02": 0.55,
// Lean R
"FL": 0.6,
// Likely R
"IA": 0.8,
"OH": 0.8,
"TX": 0.8,
"ME-02": 0.8,
// Solid R
"AK": 1,
"AL": 1,
"AR": 1,
"ID": 1,
"IN": 1,
"KS": 1,
"KY": 1,
"LA": 1,
"MO": 1,
"MS": 1,
"MT": 1,
"NE": 1,
"ND": 1,
"OK": 1,
"SC": 1,
"SD": 1,
"TN": 1,
"UT": 1,
"WV": 1,
"WY": 1
};
const GOP_WIN_ODDS_1864 = {
// Solid R
"TN": 1,
"KS": 1,
"VT": 1,
"MA": 1,
// Likely R
"MO": 0.99,
"WV": 0.99,
"IA": 0.95,
"RI": 0.95,
"NV": 0.9,
"ME": 0.9,
"IL": 0.8,
"MN": 0.8,
"CA": 0.7,
"OH": 0.7,
"WI": 0.7,
"MD": 0.7,
"OR": 0.7,
"MI": 0.7,
"IN": 0.6,
"NH": 0.6,
"PA": 0.6,
"CT": 0.6,
"NY": 0.55,
"DE": 0.5,
// Likely D
"NJ": 0.4,
"KY": 0.2,
"LA": 0.2
};
const GOP_WIN_ODDS_SENATE = {
// Data from https://www.insideelections.com/ratings/senate
// Toss-up
"MT": 0.5,
"OH": 0.5,
// Tilt D
"AZ": 0.4,
"MI": 0.4,
"NV": 0.4,
"PA": 0.4,
// Lean D
"WI": 0.3,
// Likely D
"MD": 0.2,
// Solid D
"CA": 0,
"CT": 0,
"DE": 0,
"HI": 0,
"MA": 0,
"ME": 0,
"MN": 0,
"NJ": 0,
"NM": 0,
"NY": 0,
"RI": 0,
"VA": 0,
"VT": 0,
"WA": 0,
// Likely R
"TX": 0.8,
// Solid R
"FL": 1,
"IN": 1,
"MO": 1,
"MS": 1,
"ND": 1,
"NE": 1,
"NE-02": 1,
"TN": 1,
"UT": 1,
"WV": 1,
"WY": 1
}
const ELECTORAL_COLLEGE = {
"AL": 9,
"AK": 3,
"AZ": 11,
"AR": 6,
"CA": 54,
"CO": 10,
"CT": 7,
"DE": 3,
"DC": 3,
"FL": 30,
"GA": 16,
"HI": 4,
"ID": 4,
"IL": 19,
"IN": 11,
"IA": 6,
"KS": 6,
"KY": 8,
"LA": 8,
"ME": 2,
"ME-01": 1,
"ME-02": 1,
"MD": 10,
"MA": 11,
"MI": 15,
"MN": 10,
"MS": 6,
"MO": 10,
"MT": 4,
"NE": 4,
"NE-02": 1,
"NV": 6,
"NH": 4,
"NJ": 14,
"NM": 5,
"NY": 28,
"NC": 16,
"ND": 3,
"OH": 17,
"OK": 7,
"OR": 8,
"PA": 19,
"RI": 4,
"SC": 9,
"SD": 3,
"TN": 11,
"TX": 40,
"UT": 6,
"VT": 3,
"VA": 13,
"WA": 12,
"WV": 4,
"WI": 10,
"WY": 3
};
const ELECTORAL_COLLEGE_1864 = {
"CA": 5,
"CT": 6,
"DE": 3,
"IA": 8,
"IL": 16,
"IN": 13,
"KS": 3,
"KY": 11,
"LA": 7,
"MA": 12,
"MD": 7,
"ME": 7,
"MI": 8,
"MN": 4,
"MO": 11,
"NH": 5,
"NV": 2,
"NJ": 7,
"NY": 33,
"OH": 21,
"OR": 3,
"PA": 26,
"RI": 4,
"TN": 10,
"VT": 5,
"WI": 8,
"WV": 5
};
export const ElectoralCollege = ELECTORAL_COLLEGE;
export const ElectoralCollege1864 = ELECTORAL_COLLEGE_1864;
export const GOPWinOddsSenate = GOP_WIN_ODDS_SENATE;
export const GOPWinOdds1864 = GOP_WIN_ODDS_1864;
export const GOPWinOdds = GOP_WIN_ODDS;

View file

@ -1,134 +1,70 @@
import { ElectoralCollege, ElectoralCollege1864, GOPWinOdds, GOPWinOdds1864, GOPWinOddsSenate } from "./numbers.js";
import { createSVGWindow } from 'svgdom' import { createSVGWindow } from 'svgdom'
import { SVG, registerWindow } from '@svgdotjs/svg.js' import { SVG, registerWindow } from '@svgdotjs/svg.js'
import * as fs from "node:fs/promises";
import sharp from "sharp"; import sharp from "sharp";
import crypto from "crypto"; import crypto from "crypto";
import Election from "./election.js";
const BASE_SVG = await fs.readFile("assets/ElectoralCollege2024.svg", "utf-8"); export function MakePrediction(election : Election) : Promise<Prediction> {
const BASE_SVG_1864 = await fs.readFile("assets/ElectoralCollege1864.svg", "utf-8"); return new Promise(async res => {
const BASE_SVG_SENATE = await fs.readFile("assets/SenateMap2024.svg", "utf-8"); const window = createSVGWindow();
registerWindow(window, window.document);
var draw = SVG(window.document.documentElement);
draw.svg(election.svg);
var pred = {} as any;
pred.candidates = [];
for (var candidate of election.candidates) {
pred.candidates.push({
name: candidate.name,
party: candidate.party,
votes: 0,
});
}
export function MakePrediction(bias : number, gopcandidate : string, demcandidate : string, simulationtype : string, year : number) : Promise<Prediction> { for (const state of Object.keys(election.states)) {
return new Promise(async res => { var winner = await weightedRand(election.states[state].odds);
if (Number.isNaN(bias)) bias = 0; pred.candidates.find((c : any) => c.party === winner).votes += election.states[state].electoralVotes;
const window = createSVGWindow(); // @ts-ignore
registerWindow(window, window.document); draw.find(`#${state}`).fill(election.candidates.find((c : any) => c.party === winner).color);
var election = {} as any; }
var gopVotes = 0;
var demVotes = 0; var s = sharp(Buffer.from(draw.svg()));
var png = await s.png().toBuffer();
pred.winner = pred.candidates.sort((a : any, b : any) => b.votes - a.votes)[0].name;
pred.svg = draw.svg();
pred.png = png;
res(pred);
switch (simulationtype) { });
case "presidential":
if(year == 1864) {
var draw = SVG(window.document.documentElement);
draw.svg(BASE_SVG_1864);
for (const state of Object.keys(ElectoralCollege1864)) {
if ((GOPWinOdds1864 as any)[state] >= bias + await betterRandom()) {
election[state] = "R";
gopVotes += (ElectoralCollege1864 as any)[state];
// @ts-ignore
draw.find(`#${state}`).fill("#BF1D29");
}
else {
election[state] = "D";
demVotes += (ElectoralCollege1864 as any)[state];
// @ts-ignore
draw.find(`#${state}`).fill("#1C408C");
}
};
var s = sharp(Buffer.from(draw.svg()));
var png = await s.png().toBuffer();
res({
gopVotes,
demVotes,
gopCandidate: gopcandidate,
demCandidate: demcandidate,
winner: gopVotes > demVotes ? gopcandidate : demcandidate,
svg: draw.svg(),
png,
});
break;
} else {
var draw = SVG(window.document.documentElement);
draw.svg(BASE_SVG);
for (const state of Object.keys(ElectoralCollege)) {
if ((GOPWinOdds as any)[state] >= bias + await betterRandom()) {
election[state] = "R";
gopVotes += (ElectoralCollege as any)[state];
// @ts-ignore
draw.find(`#${state}`).fill("#BF1D29");
}
else {
election[state] = "D";
demVotes += (ElectoralCollege as any)[state];
// @ts-ignore
draw.find(`#${state}`).fill("#1C408C");
}
};
var s = sharp(Buffer.from(draw.svg()));
var png = await s.png().toBuffer();
res({
gopVotes,
demVotes,
gopCandidate: gopcandidate,
demCandidate: demcandidate,
winner: gopVotes > demVotes ? gopcandidate : demcandidate,
svg: draw.svg(),
png,
});
break;
}
case "senate":
var draw = SVG(window.document.documentElement);
draw.svg(BASE_SVG_SENATE);
let senatestates = ["AZ", "CA", "CT", "DE", "FL", "HI", "IN", "MA", "MD", "ME", "MI", "MN",
"MO", "MS", "MT", "ND", "NE", "NE-02", "NJ", "NM", "NV", "NY", "OH", "PA", "RI", "TN", "TX",
"UT", "VA", "VT", "WA", "WI", "WV", "WY"];
for await (const state of senatestates) {
if ((GOPWinOddsSenate as any)[state] >= bias + await betterRandom()) {
election[state] = "R";
gopVotes += 1;
// @ts-ignore
draw.find(`#${state}`).fill("#BF1D29");
} else {
election[state] = "D";
demVotes += 1;
// @ts-ignore
draw.find(`#${state}`).fill("#1C408C");
}
}
var s = sharp(Buffer.from(draw.svg()));
var png = await s.png().toBuffer();
res({
gopVotes,
demVotes,
gopCandidate: gopcandidate,
demCandidate: demcandidate,
winner: gopVotes > demVotes ? gopcandidate : demcandidate,
svg: draw.svg(),
png,
});
break;
}
});
} }
export interface Prediction { export interface Prediction {
gopVotes: number, candidates : {
demVotes: number, name : string,
gopCandidate: string, party : string,
demCandidate: string, votes : string,
}[],
winner: string, winner: string,
svg: string, svg: string,
png: Buffer, png: Buffer,
} }
export function betterRandom() : Promise<number> { export function betterRandom(min : number, max : number) : Promise<number> {
return new Promise(res => { return new Promise(res => {
crypto.randomBytes(4, (err, buf) => { crypto.randomBytes(4, (err, buf) => {
res(buf.readUInt32BE(0) / 0x100000000); if (err) throw err;
const random = buf.readUInt32LE(0) / 0x100000000;
res(Math.floor(min + random * (max - min)));
}); });
}); });
}
// https://stackoverflow.com/a/8435261
export async function weightedRand(spec : { [key : string] : number }) : Promise<string> {
var i, j, table = [];
for (i in spec) {
for (j = 0; j < spec[i] * 10; j++) {
table.push(i);
}
}
return table[await betterRandom(0, table.length)];
} }