diff --git a/package-lock.json b/package-lock.json index 1444d47..801b9e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,9 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "axios": "^1.5.0", "classnames": "^2.3.2", + "fetch-jsonp": "^1.3.0", "iframe-phone": "^1.3.1", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -5717,8 +5719,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/at-least-node": { "version": "1.0.0", @@ -5789,14 +5790,33 @@ "dev": true }, "node_modules/axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", - "dev": true, + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", + "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", "dependencies": { - "follow-redirects": "^1.14.7" + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" } }, + "node_modules/axios/node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/babel-jest": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", @@ -6714,7 +6734,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -7550,7 +7569,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -9230,6 +9248,11 @@ "pend": "~1.2.0" } }, + "node_modules/fetch-jsonp": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fetch-jsonp/-/fetch-jsonp-1.3.0.tgz", + "integrity": "sha512-hxCYGvmANEmpkHpeWY8Kawfa5Z1t2csTpIClIDG/0S92eALWHRU1RnGaj86Tf5Cc0QF+afSa4SQ4pFB2rFM5QA==" + }, "node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -9378,7 +9401,6 @@ "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", - "dev": true, "funding": [ { "type": "individual", @@ -14809,7 +14831,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -14818,7 +14839,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -18681,6 +18701,15 @@ "node": ">=10.0.0" } }, + "node_modules/wait-on/node_modules/axios": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", + "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.14.7" + } + }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -23590,8 +23619,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "at-least-node": { "version": "1.0.0", @@ -23631,12 +23659,30 @@ "dev": true }, "axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", - "dev": true, + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", + "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", "requires": { - "follow-redirects": "^1.14.7" + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + }, + "dependencies": { + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + } } }, "babel-jest": { @@ -24321,7 +24367,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -24971,8 +25016,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, "depd": { "version": "2.0.0", @@ -26241,6 +26285,11 @@ "pend": "~1.2.0" } }, + "fetch-jsonp": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fetch-jsonp/-/fetch-jsonp-1.3.0.tgz", + "integrity": "sha512-hxCYGvmANEmpkHpeWY8Kawfa5Z1t2csTpIClIDG/0S92eALWHRU1RnGaj86Tf5Cc0QF+afSa4SQ4pFB2rFM5QA==" + }, "figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -26350,8 +26399,7 @@ "follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", - "dev": true + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" }, "for-each": { "version": "0.3.3", @@ -30435,14 +30483,12 @@ "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "requires": { "mime-db": "1.52.0" } @@ -33338,6 +33384,17 @@ "lodash": "^4.17.21", "minimist": "^1.2.5", "rxjs": "^7.5.4" + }, + "dependencies": { + "axios": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", + "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "dev": true, + "requires": { + "follow-redirects": "^1.14.7" + } + } } }, "walker": { diff --git a/package.json b/package.json index 790d284..b801767 100644 --- a/package.json +++ b/package.json @@ -135,7 +135,9 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "axios": "^1.5.0", "classnames": "^2.3.2", + "fetch-jsonp": "^1.3.0", "iframe-phone": "^1.3.1", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/src/components/app.scss b/src/components/app.scss index 2edc7c5..b9c2a4e 100644 --- a/src/components/app.scss +++ b/src/components/app.scss @@ -86,7 +86,7 @@ button { font-family: 'Montserrat', sans-serif; font-size: 12px; font-weight: 500; - &:hover { + &:hover:not(:disabled) { cursor: pointer; background: $teal-light-12; } diff --git a/src/components/app.tsx b/src/components/app.tsx index 20a2974..57539de 100644 --- a/src/components/app.tsx +++ b/src/components/app.tsx @@ -1,14 +1,37 @@ -import React, {useState} from "react"; +import React, {useEffect, useState} from "react"; import { Dropdown } from "./dropdown"; -import css from "./app.scss"; import classnames from "classnames"; import { Information } from "./information"; -import { defaultSelectedOptions } from "./constants"; +import { attributeOptions, categories, defaultSelectedOptions } from "../constants/constants"; +import { IStateOptions } from "../constants/types"; +import { createTableFromSelections } from "../scripts/api"; +import { connect } from "../scripts/connect"; + +import css from "./app.scss"; function App() { const [showInfo, setShowInfo] = useState(false); - const [selectedOptions, setSelectedOptions] = useState(defaultSelectedOptions); + const [selectedOptions, setSelectedOptions] = useState(defaultSelectedOptions); + const [getDataDisabled, setGetDataDisabled] = useState(true); + + useEffect(() => { + const init = async () => { + await connect.initialize(); + }; + init(); + }, []); + + useEffect(() => { + const {geographicLevel, states, years} = selectedOptions; + const attrKeys = attributeOptions.filter((attr) => attr.key !== "cropUnits").map((attr) => attr.key); + const selectedAttrKeys = attrKeys.filter((key) => selectedOptions[key].length > 0); + if (selectedAttrKeys.length && geographicLevel && states.length && years.length) { + setGetDataDisabled(false); + } else { + setGetDataDisabled(true); + } + }, [selectedOptions]); const handleSetSelectedOptions = (option: string, value: string | string[]) => { const newSelectedOptions = {...selectedOptions, [option]: value}; @@ -19,6 +42,10 @@ function App() { setShowInfo(true); }; + const handleGetData = async () => { + await createTableFromSelections(selectedOptions); + }; + return (
{ showInfo && @@ -37,31 +64,21 @@ function App() {
- - - + {categories.map((cat) => { + return ( + + ); + })}
- +
diff --git a/src/components/attribute-options.tsx b/src/components/attribute-options.tsx new file mode 100644 index 0000000..a60328e --- /dev/null +++ b/src/components/attribute-options.tsx @@ -0,0 +1,57 @@ +import React from "react"; +import { Options } from "./options"; +import { attributeOptions } from "../constants/constants"; +import classnames from "classnames"; +import { IStateOptions } from "../constants/types"; + +import css from "./options.scss"; + +interface IProps { + handleSetSelectedOptions: (option: string, value: string|string[]) => void; + selectedOptions: IStateOptions; +} + +export const AttributeOptions: React.FC = (props) => { + const {handleSetSelectedOptions, selectedOptions} = props; + + const commonProps = { + handleSetSelectedOptions, + selectedOptions + }; + + const getClasses = (key: string) => { + if (key === "cropUnits" || key === "crops") { + return classnames(css.checkOptions, css.narrow); + } else { + return classnames(css.checkOptions, css.vertical); + } + }; + + return ( + <> + { + attributeOptions.map((attr) => { + return ( + <> + {attr.label &&
{attr.label}
} + {attr.instructions && +
+ {attr.instructions} +
+ } +
+ +
+ + ); + }) + } + + ); +}; diff --git a/src/components/constants.ts b/src/components/constants.ts deleted file mode 100644 index 22822be..0000000 --- a/src/components/constants.ts +++ /dev/null @@ -1,65 +0,0 @@ -export const placeOptions = { - label: "Size of area for data", - options : ["State", "County"] -}; - -export const stateOptions = { - label: "Choose states to include in your dataset from the list below", - options: [ - "Alabama", - "Alaska", - "Arizona", - "Arkansas", - "California", - "Colorado", - "Connecticut", - "Delaware", - "Florida", - "Georgia", - "Hawaii", - "Idaho", - "Illinois", - "Indiana", - "Iowa", - "Kansas", - "Kentucky", - "Louisiana", - "Maine", - "Maryland", - "Massachusetts", - "Michigan", - "Minnesota", - "Mississippi", - "Missouri", - "Montana", - "Nebraska", - "Nevada", - "New Hampshire", - "New Jersey", - "New Mexico", - "New York", - "North Carolina", - "North Dakota", - "Ohio", - "Oklahoma", - "Oregon", - "Pennsylvania", - "Rhode Island", - "South Carolina", - "South Dakota", - "Tennessee", - "Texas", - "Utah", - "Vermont", - "Virginia", - "Washington", - "West Virginia", - "Wisconsin", - "Wyoming" - ] -}; - -export const defaultSelectedOptions = { - place: null, - states: [] -}; diff --git a/src/components/dropdown.tsx b/src/components/dropdown.tsx index 5f4650b..974314e 100644 --- a/src/components/dropdown.tsx +++ b/src/components/dropdown.tsx @@ -1,52 +1,41 @@ import React, { useState } from "react"; import classnames from "classnames"; -import css from "./dropdown.scss"; import { PlaceOptions } from "./place-options"; -import { defaultSelectedOptions } from "./constants"; +import { defaultSelectedOptions } from "../constants/constants"; +import { AttributeOptions } from "./attribute-options"; + +import css from "./dropdown.scss"; +import { YearsOptions } from "./years-options"; +import { Summary } from "./summary"; interface IProps { - sectionName: string + category: string sectionAltText: string - sectionDescription: string handleSetSelectedOptions: (option: string, value: string|string[]) => void selectedOptions: typeof defaultSelectedOptions; } export const Dropdown: React.FC = (props) => { - const {sectionName, sectionAltText, handleSetSelectedOptions, selectedOptions} = props; + const {category, sectionAltText, handleSetSelectedOptions, selectedOptions} = props; const [showItems, setShowItems] = useState(false); const handleClick = () => { setShowItems(!showItems); }; - const renderSummary = () => { - if (sectionName === "Place") { - const place = selectedOptions.place || ""; - const states = selectedOptions.states.join(`, `); - return ( - `${place}: ${states}` - ); - } - } + const commonProps = {handleSetSelectedOptions, selectedOptions}; const renderOptions = () => { - if (sectionName === "Place") { - return ( - - ); - } + return category === "Place" ? : + category === "Attributes" ? : + ; }; return (
- {sectionName} -
{renderSummary()}
+ {category} +
diff --git a/src/components/information.tsx b/src/components/information.tsx index f06d75a..ed61e25 100644 --- a/src/components/information.tsx +++ b/src/components/information.tsx @@ -13,7 +13,7 @@ export const Information: React.FC = (props) => {
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ipsum velit, pellentesque eget turpis non, vestibulum egestas tellus. Fusce sed dolor hendrerit, rutrum ligula et, imperdiet est. Nam tincidunt leo a ultricies elementum. Quisque ornare eget massa ac congue. Curabitur et nisi orci. Nulla mollis lacus eu velit mollis, in vehicula lectus ultricies. Nulla facilisi. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ipsum velit, pellentesque eget turpis.
diff --git a/src/components/options.scss b/src/components/options.scss index 0d0d78e..bb1821e 100644 --- a/src/components/options.scss +++ b/src/components/options.scss @@ -51,4 +51,29 @@ .checkOptions { flex-wrap: wrap; display: flex; + &.vertical { + flex-direction: column; + .option { + flex-basis: auto; + padding: 0px; + } + } + &.narrow { + margin: 0px; + .option { + flex-basis: auto; + padding: 3px; + margin-top: 0px; + } + } +} + +.statisticcat_desc { + font-weight: 600; +} + +.instructions { + padding-left: 6px; + margin-top: 6px; + } \ No newline at end of file diff --git a/src/components/options.tsx b/src/components/options.tsx new file mode 100644 index 0000000..043c217 --- /dev/null +++ b/src/components/options.tsx @@ -0,0 +1,83 @@ +import React from "react"; +import { IStateOptions, OptionKey } from "../constants/types"; + +import css from "./options.scss"; + +export interface IOptions { + options: string[], + selectedOptions: IStateOptions, + inputType: "radio" | "checkbox", + handleSetSelectedOptions: (option: string, value: string|string[]) => void, + optionKey: OptionKey +} + + +export const Options: React.FC = (props) => { + const {options, selectedOptions, inputType, handleSetSelectedOptions, optionKey} = props; + + const isOptionSelected = (option: string) => { + if (Array.isArray(selectedOptions[optionKey])) { + return selectedOptions[optionKey].indexOf(option) > -1; + } else { + return selectedOptions[optionKey] === option; + } + }; + + const handleSelectState = (e: React.ChangeEvent) => { + if (Array.isArray(selectedOptions[optionKey])) { + let newArray = [...selectedOptions[optionKey]]; + if (e.currentTarget.checked) { + newArray.push(e.target.value); + // If user selects "Age", "Gender", or "Race", auto-select "Total Farmers" as well + if (optionKey === "farmerDemographics" && !newArray.includes("Total Farmers")) { + newArray.push("Total Farmers"); + } + // If user selects a state, de-select "All States" + if (optionKey === "states" && newArray.includes("All States")) { + newArray = newArray.filter((state) => state !== "All States"); + } + newArray.sort(); + if (optionKey === "years") { + newArray.reverse(); + } + } else { + if (isOptionSelected(e.target.value)) { + const includes = (opt: string) => selectedOptions.farmerDemographics.includes(opt); + // "Total Farmers" can only be unselected if race, gender, and age are unselected + if (optionKey === "farmerDemographics" && e.target.value === "Total Farmers") { + const shouldFilter = !includes("Race") && !includes("Gender") && !includes("Age"); + if (shouldFilter) { + newArray = newArray.filter((o) => o !== e.target.value); + } + } else { + newArray = newArray.filter((o) => o !== e.target.value); + } + } + } + handleSetSelectedOptions(optionKey, newArray); + } else if (optionKey === "geographicLevel" || optionKey === "cropUnits") { + handleSetSelectedOptions(optionKey, e.target.value); + } + }; + + return ( + <> + {options.map((o) => { + return ( +
+ handleSelectState(e)} + /> + +
+ ); + })} + + ); +}; diff --git a/src/components/place-options.tsx b/src/components/place-options.tsx index 0774649..25d9012 100644 --- a/src/components/place-options.tsx +++ b/src/components/place-options.tsx @@ -1,91 +1,64 @@ import React from "react"; -import { placeOptions, stateOptions } from "./constants"; +import { placeOptions } from "../constants/constants"; +import { IStateOptions } from "../constants/types"; +import { Options } from "./options"; import css from "./options.scss"; interface IProps { handleSetSelectedOptions: (option: string, value: string|string[]) => void; - selectedPlace: string|null; - selectedStates: string[]; + selectedOptions: IStateOptions; } export const PlaceOptions: React.FC = (props) => { - const {handleSetSelectedOptions, selectedPlace, selectedStates} = props; + const {handleSetSelectedOptions, selectedOptions} = props; - const isStateSelected = (state: string) => { - return selectedStates.indexOf(state) > - 1; + const isAllStatesSelected = () => { + return selectedOptions.states[0] === "All States"; }; - const handleSelectPlace = (e: React.ChangeEvent) => { - handleSetSelectedOptions("place", e.target.value); + const handleSelectAllStates = () => { + handleSetSelectedOptions("states", ["All States"]); }; - const handleSelectState = (e: React.ChangeEvent) => { - let newSelectedStates = [...selectedStates]; - if (e.currentTarget.checked) { - newSelectedStates.push(e.target.value); - newSelectedStates.sort(); - - } else { - if (isStateSelected(e.target.value)) { - newSelectedStates = newSelectedStates.filter((s) => s !== e.target.value); - } - } - handleSetSelectedOptions("states", newSelectedStates); - }; - - const createPlaceOptions = (options: string[]) => { - return ( - <> - {options.map((o) => { - return ( -
- - -
- ); - })} - - ); - }; - - const createStateOptions = (options: string[]) => { - return ( - <> - {options.map((o) => { + return ( + <> + {placeOptions.map((placeOpt) => { return ( -
- - -
+ <> +
{placeOpt.instructions}:
+
+ {placeOpt.key === "states" && +
+ + +
+ } + +
+ ); })} - - ); - }; - - return ( - <> -
{placeOptions.label}:
-
{createPlaceOptions(placeOptions.options)}
-
{stateOptions.label}:
-
{createStateOptions(stateOptions.options)}
); }; diff --git a/src/components/summary.tsx b/src/components/summary.tsx new file mode 100644 index 0000000..71d60ea --- /dev/null +++ b/src/components/summary.tsx @@ -0,0 +1,53 @@ +import React from "react"; +import { IStateOptions } from "../constants/types"; +import { attributeOptions } from "../constants/constants"; + +interface IProps { + category: string; + selectedOptions: IStateOptions; +} + +export const Summary: React.FC = ({category, selectedOptions}) => { + + const getSummaryText = () => { + if (category === "Place") { + const place = selectedOptions.geographicLevel || ""; + const states = selectedOptions.states.join(`, `); + const colon = place && states ? ": " : ""; + return ( + `${place}${colon}${states}` + ); + } else if (category === "Attributes") { + const resultString = attributeOptions.filter((attr) => { + const value = selectedOptions[attr.key]; + const valueIsArrayWithLength = Array.isArray(value) && value.length > 0; + const valueIsDefined = typeof value === "string" && value; + return valueIsArrayWithLength || valueIsDefined; + }).map((attr) => { + const value = selectedOptions[attr.key]; + const valueIsArrayWithLength = Array.isArray(value) && value.length > 0; + const valueIsDefined = typeof value === "string" && value; + const label = attr.label && (valueIsArrayWithLength || valueIsDefined) ? `${attr.label}: ` : ""; + + if (Array.isArray(value) && value.length > 0) { + return `${label}${value.join(", ")}`; + } else if (value) { + return `${attr.label}: ${value}`; + } else { + return null; + } + }) + .filter((item) => item !== null); + const finalString = resultString.join(", "); + return finalString; + } else if (category === "Years") { + return selectedOptions.years.join(", "); + } + }; + + return ( +
+ {getSummaryText()} +
+ ); +}; diff --git a/src/components/years-options.tsx b/src/components/years-options.tsx new file mode 100644 index 0000000..761a6ff --- /dev/null +++ b/src/components/years-options.tsx @@ -0,0 +1,71 @@ +import React, { useEffect, useState } from "react"; +import { attributeOptions, yearsOptions } from "../constants/constants"; +import { IStateOptions } from "../constants/types"; +import { Options } from "./options"; +import { queryData } from "../constants/queryHeaders"; +import { flatten } from "../scripts/utils"; + +import css from "./options.scss"; + +interface IProps { + handleSetSelectedOptions: (option: string, value: string|string[]) => void; + selectedOptions: IStateOptions; +} + +export const YearsOptions: React.FC = (props) => { + const {handleSetSelectedOptions, selectedOptions} = props; + const [availableYearOptions, setAvailableYearOptions] = useState([]); + + useEffect(() => { + const attrKeys = attributeOptions.filter((attr) => attr.key !== "cropUnits").map((attr) => attr.key); + const selectedAttrKeys = attrKeys.filter((key) => selectedOptions[key].length > 0); + + if (!selectedAttrKeys.length) { + return; + } + + const allSelectedAttrs = flatten(selectedAttrKeys.map((key) => selectedOptions[key])); + const newAvailableYears = allSelectedAttrs.reduce((years, attr) => { + const subAttrData = queryData.find((d) => d.plugInAttribute === attr); + const availableYears = subAttrData?.years[selectedOptions.geographicLevel]; + if (availableYears) { + availableYears.forEach((y) => { + years.add(y); + }); + } + return years; + }, new Set()); + const newSet: string[] = Array.from(newAvailableYears); + setAvailableYearOptions(newSet); + + // if selected years includes years not in available options, remove them from selection + const selectionsNotAvailable = selectedOptions.years.filter(year => !newSet.includes(year)); + if (selectionsNotAvailable.length) { + const newSelectedYears = [...selectedOptions.years]; + selectionsNotAvailable.forEach((year) => { + newSelectedYears.splice(newSelectedYears.indexOf(year), 1); + }); + handleSetSelectedOptions("years", newSelectedYears); + } + + }, [selectedOptions, handleSetSelectedOptions]); + + const handleSelectYear = (yearKey: string, years: string|string[]) => { + handleSetSelectedOptions(yearKey, years); + }; + + return ( +
+ {availableYearOptions.length === 0 ? +
Please select attributes to see available years.
+ : + } +
+ ); +}; diff --git a/src/constants/codapMetadata.ts b/src/constants/codapMetadata.ts new file mode 100644 index 0000000..6a122c9 --- /dev/null +++ b/src/constants/codapMetadata.ts @@ -0,0 +1,183 @@ +interface ICodapColumnData { + "attributeNameInCodapTable": string, + "unitInCodapTable": string +} + +interface IAttrToCodapColumn { + [attr: string]: ICodapColumnData +} + +export const attrToCODAPColumnName: IAttrToCodapColumn = { + "PRODUCERS, (ALL) - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "Total Number of Farmers", + "unitInCodapTable": "# of Farmers" + }, + "OPERATORS, (ALL) - NUMBER OF OPERATORS": { + "attributeNameInCodapTable": "Total Number of Farmers", + "unitInCodapTable": "# of Farmers" + }, + "PRODUCERS, AGE LT 25 - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "Age < 25", + "unitInCodapTable": "# of Farmers" + }, + "PRODUCERS, AGE 25 TO 34 - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "Age 25 - 34", + "unitInCodapTable": "# of Farmers" + }, + "PRODUCERS, AGE 35 TO 44 - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "Age 35 - 44", + "unitInCodapTable": "# of Farmers" + }, + "PRODUCERS, AGE 45 TO 54 - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "Age 45 - 54", + "unitInCodapTable": "# of Farmers" + }, + "PRODUCERS, AGE 55 TO 64 - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "Age 55 - 64", + "unitInCodapTable": "# of Farmers" + }, + "PRODUCERS, AGE 65 TO 74 - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "Age 65 - 74", + "unitInCodapTable": "# of Farmers" + }, + "PRODUCERS, AGE GE 75 - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "Age > 74", + "unitInCodapTable": "# of Farmers" + }, + "PRODUCERS, (ALL), FEMALE - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "Female", + "unitInCodapTable": "# of Farmers" + }, + "PRODUCERS, (ALL), MALE - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "Male", + "unitInCodapTable": "# of Farmers" + }, + "PRODUCERS, AMERICAN INDIAN OR ALASKAN NATIVE - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "American Indian or Alaskan Native", + "unitInCodapTable": "# of Farmers" + }, + "PRODUCERS, ASIAN - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "Asian", + "unitInCodapTable": "# of Farmers" + }, + "PRODUCERS, BLACK OR AFRICAN AMERICAN - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "Black or African American", + "unitInCodapTable": "# of Farmers" + }, + "PRODUCERS, HISPANIC - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "Hispanic", + "unitInCodapTable": "# of Farmers" + }, + "PRODUCERS, MULTI-RACE - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "Multi-race", + "unitInCodapTable": "# of Farmers" + }, + "PRODUCERS, NATIVE HAWAIIAN OR OTHER PACIFIC ISLANDERS - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "Native Hawaiian or Other Pacific Islanders", + "unitInCodapTable": "# of Farmers" + }, + "PRODUCERS, WHITE - NUMBER OF PRODUCERS": { + "attributeNameInCodapTable": "White", + "unitInCodapTable": "# of Farmers" + }, + "FARM OPERATIONS - NUMBER OF OPERATIONS": { + "attributeNameInCodapTable": "Total Number of Farms", + "unitInCodapTable": "# of Farms" + }, + "FARM OPERATIONS, ORGANIZATION, TAX PURPOSES, CORPORATION (EXCL FAMILY HELD) - NUMBER OF OPERATIONS": { + "attributeNameInCodapTable": "Corporate", + "unitInCodapTable": "# of Farms" + }, + "FARM OPERATIONS, ORGANIZATION, TAX PURPOSES, CORPORATION, FAMILY HELD - NUMBER OF OPERATIONS": { + "attributeNameInCodapTable": "Corporate, Family Held", + "unitInCodapTable": "# of Farms" + }, + "FARM OPERATIONS, ORGANIZATION, TAX PURPOSES, FAMILY & INDIVIDUAL - NUMBER OF OPERATIONS": { + "attributeNameInCodapTable": "Family & Individual", + "unitInCodapTable": "# of Farms" + }, + "FARM OPERATIONS, ORGANIZATION, TAX PURPOSES, INSTITUTIONAL & RESEARCH & RESERVATION & OTHER - NUMBER OF OPERATIONS": { + "attributeNameInCodapTable": "Institutional, Research, Reservation, & Other", + "unitInCodapTable": "# of Farms" + }, + "FARM OPERATIONS, ORGANIZATION, TAX PURPOSES, PARTNERSHIP - NUMBER OF OPERATIONS": { + "attributeNameInCodapTable": "Partnership", + "unitInCodapTable": "# of Farms" + }, + "FARM OPERATIONS - ACRES OPERATED": { + "attributeNameInCodapTable": "", + "unitInCodapTable": "# of Farms" + }, + "FARM OPERATIONS, ORGANIC - NUMBER OF OPERATIONS": { + "attributeNameInCodapTable": "Organic", + "unitInCodapTable": "# of Farms" + }, + "LABOR, MIGRANT - NUMBER OF WORKERS": { + "attributeNameInCodapTable": "Migrant", + "unitInCodapTable": "# of Farm Laborers" + }, + "LABOR, UNPAID - NUMBER OF WORKERS": { + "attributeNameInCodapTable": "Unpaid", + "unitInCodapTable": "# of Farm Laborers" + }, + "LABOR, HIRED - NUMBER OF WORKERS": { + "attributeNameInCodapTable": "Hired", + "unitInCodapTable": "# of Farm Laborers" + }, + "LABOR, HIRED - WAGE RATE, MEASURED IN $ / HOUR": { + "attributeNameInCodapTable": "Wage Rate of Laborers", + "unitInCodapTable": "$/Hour" + }, + "LABOR, HIRED - TIME WORKED, MEASURED IN HOURS / WEEK": { + "attributeNameInCodapTable": "Time Worked by Laborers", + "unitInCodapTable": "Hours/Week" + }, + "CORN, GRAIN - YIELD, MEASURED IN BU / ACRE": { + "attributeNameInCodapTable": "Corn Yield", + "unitInCodapTable": "BU/Acre" + }, + "CORN, GRAIN - ACRES HARVESTED": { + "attributeNameInCodapTable": "Corn Area Harvested", + "unitInCodapTable": "Acres Harvested" + }, + "COTTON, - YIELD, MEASURED IN LB / ACRE": { + "attributeNameInCodapTable": "Cotton Yield", + "unitInCodapTable": "LB/Acre" + }, + "COTTON - ACRES HARVESTED": { + "attributeNameInCodapTable": "Cotton Area Harvested", + "unitInCodapTable": "Acres Harvested" + }, + "GRAPES - YIELD, MEASURED IN TONS / ACRE": { + "attributeNameInCodapTable": "Grapes Yield", + "unitInCodapTable": "Tons/Acre" + }, + "GRAPES, ORGANIC - ACRES HARVESTED": { + "attributeNameInCodapTable": "Grapes Area Harvested", + "unitInCodapTable": "Acres Harvested" + }, + "OATS - YIELD, MEASURED IN BU / ACRE": { + "attributeNameInCodapTable": "Oats Yield", + "unitInCodapTable": "BU/Acre" + }, + "OATS - ACRES HARVESTED": { + "attributeNameInCodapTable": "Oats Area Harvested", + "unitInCodapTable": "Acres Harvested" + }, + "SOYBEANS - YIELD MEASURED IN BU / ACRE": { + "attributeNameInCodapTable": "Soybeans Yield", + "unitInCodapTable": "BU/Acre" + }, + "SOYBEANS - ACRES HARVESTED": { + "attributeNameInCodapTable": "Soybeans Area Harvested", + "unitInCodapTable": "Acres Harvested" + }, + "WHEAT - YIELD MEASURED IN BU / ACRE": { + "attributeNameInCodapTable": "Wheat Yield", + "unitInCodapTable": "BU/Acre" + }, + "WHEAT - ACRES HARVESTED": { + "attributeNameInCodapTable": "Wheat Area Harvested", + "unitInCodapTable": "Acres Harvested" + } +}; diff --git a/src/constants/constants.ts b/src/constants/constants.ts new file mode 100644 index 0000000..f23e8c9 --- /dev/null +++ b/src/constants/constants.ts @@ -0,0 +1,134 @@ +import { IAttrOptions, IStateOptions } from "./types"; + +export const geographicLevelOptions: IAttrOptions = { + label: null, + key: "geographicLevel", + instructions: "Size of area for data", + options : ["State", "County"] +}; + +export const fiftyStates = [ + "Alabama", + "Alaska", + "Arizona", + "Arkansas", + "California", + "Colorado", + "Connecticut", + "Delaware", + "Florida", + "Georgia", + "Hawaii", + "Idaho", + "Illinois", + "Indiana", + "Iowa", + "Kansas", + "Kentucky", + "Louisiana", + "Maine", + "Maryland", + "Massachusetts", + "Michigan", + "Minnesota", + "Mississippi", + "Missouri", + "Montana", + "Nebraska", + "Nevada", + "New Hampshire", + "New Jersey", + "New Mexico", + "New York", + "North Carolina", + "North Dakota", + "Ohio", + "Oklahoma", + "Oregon", + "Pennsylvania", + "Rhode Island", + "South Carolina", + "South Dakota", + "Tennessee", + "Texas", + "Utah", + "Vermont", + "Virginia", + "Washington", + "West Virginia", + "Wisconsin", + "Wyoming" +]; + +export const stateOptions: IAttrOptions = { + label: null, + key: "states", + instructions: "Choose states to include in your dataset from the list below", + options: [ + ...fiftyStates + ] +}; + +export const placeOptions = [geographicLevelOptions, stateOptions]; + +const farmerOptions: IAttrOptions = { + key: "farmerDemographics", + label: "Farmer Demographics", + options: ["Total Farmers", "Age", "Race", "Gender"], + instructions: null +}; +const farmOptions: IAttrOptions = { + key: "farmDemographics", + label: "Farm Demographics", + options: ["Total Farms", "Organization Type", "Economic Class", "Acres Operated", "Organic"], + instructions: null +}; +const economicOptions: IAttrOptions = { + key: "economicsAndWages", + label: "Economics & Wages", + options: ["Labor Status", "Wages", "Time Worked"], + instructions: null +}; +const cropUnitOptions: IAttrOptions = { + key: "cropUnits", + label: "Crop Production", + options: ["Area Harvested", "Yield"], + instructions: "(Choose units)" +}; +export const cropOptions: IAttrOptions = { + key: "crops", + label: null, + options: ["Corn", "Cotton", "Grapes", "Oats", "Soybeans", "Wheat"], + instructions: "(Choose crops)" +}; + +export const attributeOptions = [farmerOptions, farmOptions, economicOptions, cropUnitOptions, cropOptions]; + +const yearsArray = []; +for (let year = 2022; year >= 1910; year--) { + yearsArray.push(`${year}`); +} + +export const yearsOptions: IAttrOptions = { + key: "years", + label: "Years", + options: yearsArray, + instructions: null +}; + +export const categories = [ + {header: "Place", options: placeOptions, altText: ""}, + {header: "Attributes", options: attributeOptions, altText: ""}, + {header: "Years", options: yearsOptions, altText: ""} +]; + +export const defaultSelectedOptions: IStateOptions = { + geographicLevel: "State", + states: ["All States"], + farmerDemographics: [], + farmDemographics: [], + economicsAndWages: [], + cropUnits: "", + crops: [], + years: [] +}; diff --git a/src/constants/counties.ts b/src/constants/counties.ts new file mode 100644 index 0000000..abd1d50 --- /dev/null +++ b/src/constants/counties.ts @@ -0,0 +1,3285 @@ +export const countyData: {[state: string]: string[]} = { + "Alabama": [ + "AUTAUGA", + "BALDWIN", + "BARBOUR", + "BIBB", + "BLOUNT", + "BULLOCK", + "BUTLER", + "CALHOUN", + "CHAMBERS", + "CHEROKEE", + "CHILTON", + "CHOCTAW", + "CLARKE", + "CLAY", + "CLEBURNE", + "COFFEE", + "COLBERT", + "CONECUH", + "COOSA", + "COVINGTON", + "CRENSHAW", + "CULLMAN", + "DALE", + "DALLAS", + "DE KALB", + "ELMORE", + "ESCAMBIA", + "ETOWAH", + "FAYETTE", + "FRANKLIN", + "GENEVA", + "GREENE", + "HALE", + "HENRY", + "HOUSTON", + "JACKSON", + "JEFFERSON", + "LAMAR", + "LAUDERDALE", + "LAWRENCE", + "LEE", + "LIMESTONE", + "LOWNDES", + "MACON", + "MADISON", + "MARENGO", + "MARION", + "MARSHALL", + "MOBILE", + "MONROE", + "MONTGOMERY", + "MORGAN", + + "OTHER COUNTIES", + "PERRY", + "PICKENS", + "PIKE", + "RANDOLPH", + "RUSSELL", + "SAINT CLAIR", + "SHELBY", + "SUMTER", + "TALLADEGA", + "TALLAPOOSA", + "TUSCALOOSA", + "WALKER", + "WASHINGTON", + "WILCOX", + "WINSTON" + ], + "Alaska": [ + "ALEUTIAN ISLANDS", + "ANCHORAGE", + "FAIRBANKS NORTH STAR", + "JUNEAU", + "KENAI PENINSULA", + + "OTHER COUNTIES" + ], + "Arizona": [ + "APACHE", + "COCHISE", + "COCONINO", + "GILA", + "GRAHAM", + "GREENLEE", + "LAPAZ", + "MARICOPA", + "MOHAVE", + "NAVAJO", + + "OTHER COUNTIES", + "PIMA", + "PINAL", + "SANTA CRUZ", + "YAVAPAI", + "YUMA" + ], + "Arkansas": [ + "ARKANSAS", + "ASHLEY", + "BAXTER", + "BENTON", + "BOONE", + "BRADLEY", + "CALHOUN", + "CARROLL", + "CHICOT", + "CLARK", + "CLAY", + "CLEBURNE", + "CLEVELAND", + "COLUMBIA", + "CONWAY", + "CRAIGHEAD", + "CRAWFORD", + "CRITTENDEN", + "CROSS", + "DALLAS", + "DESHA", + "DREW", + "FAULKNER", + "FRANKLIN", + "FULTON", + "GARLAND", + "GRANT", + "GREENE", + "HEMPSTEAD", + "HOT SPRING", + "HOWARD", + "INDEPENDENCE", + "IZARD", + "JACKSON", + "JEFFERSON", + "JOHNSON", + "LAFAYETTE", + "LAWRENCE", + "LEE", + "LINCOLN", + "LITTLE RIVER", + "LOGAN", + "LONOKE", + "MADISON", + "MARION", + "MILLER", + "MISSISSIPPI", + "MONROE", + "MONTGOMERY", + "NEVADA", + "NEWTON", + + "OTHER COUNTIES", + "OUACHITA", + "PERRY", + "PHILLIPS", + "PIKE", + "POINSETT", + "POLK", + "POPE", + "PRAIRIE", + "PULASKI", + "RANDOLPH", + "SAINT FRANCIS", + "SALINE", + "SCOTT", + "SEARCY", + "SEBASTIAN", + "SEVIER", + "SHARP", + "STONE", + "UNION", + "VAN BUREN", + "WASHINGTON", + "WHITE", + "WOODRUFF", + "YELL" +], + "California": [ + "ALAMEDA", + "ALPINE", + "AMADOR", + "BUTTE", + "CALAVERAS", + "COLUSA", + "CONTRA COSTA", + "DEL NORTE", + "EL DORADO", + "FRESNO", + "GLENN", + "HUMBOLDT", + "IMPERIAL", + "INYO", + "KERN", + "KINGS", + "LAKE", + "LASSEN", + "LOS ANGELES", + "MADERA", + "MARIN", + "MARIPOSA", + "MENDOCINO", + "MERCED", + "MODOC", + "MONO", + "MONTEREY", + "NAPA", + "NEVADA", + "ORANGE", + + "OTHER COUNTIES", + "PLACER", + "PLUMAS", + "RIVERSIDE", + "SACRAMENTO", + "SAN BENITO", + "SAN BERNARDINO", + "SAN DIEGO", + "SAN FRANCISCO", + "SAN JOAQUIN", + "SAN LUIS OBISPO", + "SAN MATEO", + "SANTA BARBARA", + "SANTA CLARA", + "SANTA CRUZ", + "SHASTA", + "SIERRA", + "SISKIYOU", + "SOLANO", + "SONOMA", + "STANISLAUS", + "SUTTER", + "TEHAMA", + "TRINITY", + "TULARE", + "TUOLUMNE", + "VENTURA", + "YOLO", + "YUBA" + ], + "Colorado": [ + "ADAMS", + "ALAMOSA", + "ARAPAHOE", + "ARCHULETA", + "BACA", + "BENT", + "BOULDER", + "BROOMFIELD", + "CHAFFEE", + "CHEYENNE", + "CLEAR CREEK", + "CONEJOS", + "COSTILLA", + "CROWLEY", + "CUSTER", + "DELTA", + "DENVER", + "DOLORES", + "DOUGLAS", + "EAGLE", + "EL PASO", + "ELBERT", + "FREMONT", + "GARFIELD", + "GILPIN", + "GRAND", + "GUNNISON", + "HINSDALE", + "HUERFANO", + "JACKSON", + "JEFFERSON", + "KIOWA", + "KIT CARSON", + "LA PLATA", + "LAKE", + "LARIMER", + "LAS ANIMAS", + "LINCOLN", + "LOGAN", + "MESA", + "MINERAL", + "MOFFAT", + "MONTEZUMA", + "MONTROSE", + "MORGAN", + "OTERO", + + "OTHER COUNTIES", + "OURAY", + "PARK", + "PHILLIPS", + "PITKIN", + "PROWERS", + "PUEBLO", + "RIO BLANCO", + "RIO GRANDE", + "ROUTT", + "SAGUACHE", + "SAN JUAN", + "SAN MIGUEL", + "SEDGWICK", + "SUMMIT", + "TELLER", + "WASHINGTON", + "WELD", + "YUMA" +], + "Connecticut": [ + "FAIRFIELD", + "HARTFORD", + "LITCHFIELD", + "MIDDLESEX", + "NEW HAVEN", + "NEW LONDON", + + "OTHER COUNTIES", + "TOLLAND", + "WINDHAM" +], + "Delaware": [ + "KENT", + "NEW CASTLE", + "OTHER COUNTIES", + "SUSSEX" +], + "Florida": [ + "ALACHUA", + "BAKER", + "BAY", + "BRADFORD", + "BREVARD", + "BROWARD", + "CALHOUN", + "CHARLOTTE", + "CITRUS", + "CLAY", + "COLLIER", + "COLUMBIA", + "DE SOTO", + "DIXIE", + "DUVAL", + "ESCAMBIA", + "FLAGLER", + "FRANKLIN", + "GADSDEN", + "GILCHRIST", + "GLADES", + "GULF", + "HAMILTON", + "HARDEE", + "HENDRY", + "HERNANDO", + "HIGHLANDS", + "HILLSBOROUGH", + "HOLMES", + "INDIAN RIVER", + "JACKSON", + "JEFFERSON", + "LAFAYETTE", + "LAKE", + "LEE", + "LEON", + "LEVY", + "LIBERTY", + "MADISON", + "MANATEE", + "MARION", + "MARTIN", + "MIAMI-DADE", + "MONROE", + "NASSAU", + "OKALOOSA", + "OKEECHOBEE", + "ORANGE", + "OSCEOLA", + + "OTHER COUNTIES", + "PALM BEACH", + "PASCO", + "PINELLAS", + "POLK", + "PUTNAM", + "SANTA ROSA", + "SARASOTA", + "SEMINOLE", + "ST. JOHNS", + "ST. LUCIE", + "SUMTER", + "SUWANNEE", + "TAYLOR", + "UNION", + "VOLUSIA", + "WAKULLA", + "WALTON", + "WASHINGTON" +], + "Georgia": [ + "APPLING", + "ATKINSON", + "BACON", + "BAKER", + "BALDWIN", + "BANKS", + "BARROW", + "BARTOW", + "BEN HILL", + "BERRIEN", + "BIBB", + "BLECKLEY", + "BRANTLEY", + "BROOKS", + "BRYAN", + "BULLOCH", + "BURKE", + "BUTTS", + "CALHOUN", + "CAMDEN", + "CANDLER", + "CARROLL", + "CATOOSA", + "CHARLTON", + "CHATHAM", + "CHATTAHOOCHEE", + "CHATTOOGA", + "CHEROKEE", + "CLARKE", + "CLAY", + "CLAYTON", + "CLINCH", + "COBB", + "COFFEE", + "COLQUITT", + "COLUMBIA", + "COOK", + "COWETA", + "CRAWFORD", + "CRISP", + "DADE", + "DAWSON", + "DE KALB", + "DECATUR", + "DODGE", + "DOOLY", + "DOUGHERTY", + "DOUGLAS", + "EARLY", + "ECHOLS", + "EFFINGHAM", + "ELBERT", + "EMANUEL", + "EVANS", + "FANNIN", + "FAYETTE", + "FLOYD", + "FORSYTH", + "FRANKLIN", + "FULTON", + "GILMER", + "GLASCOCK", + "GLYNN", + "GORDON", + "GRADY", + "GREENE", + "GWINNETT", + "HABERSHAM", + "HALL", + "HANCOCK", + "HARALSON", + "HARRIS", + "HART", + "HEARD", + "HENRY", + "HOUSTON", + "IRWIN", + "JACKSON", + "JASPER", + "JEFF DAVIS", + "JEFFERSON", + "JENKINS", + "JOHNSON", + "JONES", + "LAMAR", + "LANIER", + "LAURENS", + "LEE", + "LIBERTY", + "LINCOLN", + "LONG", + "LOWNDES", + "LUMPKIN", + "MACON", + "MADISON", + "MARION", + "MCDUFFIE", + "MCINTOSH", + "MERIWETHER", + "MILLER", + "MITCHELL", + "MONROE", + "MONTGOMERY", + "MORGAN", + "MURRAY", + "MUSCOGEE", + "NEWTON", + "OCONEE", + "OGLETHORPE", + + "OTHER COUNTIES", + "PAULDING", + "PEACH", + "PICKENS", + "PIERCE", + "PIKE", + "POLK", + "PULASKI", + "PUTNAM", + "QUITMAN", + "RABUN", + "RANDOLPH", + "RICHMOND", + "ROCKDALE", + "SCHLEY", + "SCREVEN", + "SEMINOLE", + "SPALDING", + "STEPHENS", + "STEWART", + "SUMTER", + "TALBOT", + "TALIAFERRO", + "TATTNALL", + "TAYLOR", + "TELFAIR", + "TERRELL", + "THOMAS", + "TIFT", + "TOOMBS", + "TOWNS", + "TREUTLEN", + "TROUP", + "TURNER", + "TWIGGS", + "UNION", + "UPSON", + "WALKER", + "WALTON", + "WARE", + "WARREN", + "WASHINGTON", + "WAYNE", + "WEBSTER", + "WHEELER", + "WHITE", + "WHITFIELD", + "WILCOX", + "WILKES", + "WILKINSON", + "WORTH" +], + "Hawaii": [ + "HAWAII", + "HONOLULU", + "KAUAI", + "MAUI & KALWAO", + + "OTHER COUNTIES" +], + "Idaho": [ + "ADA", + "ADAMS", + "BANNOCK", + "BEAR LAKE", + "BENEWAH", + "BINGHAM", + "BLAINE", + "BOISE", + "BONNER", + "BONNEVILLE", + "BOUNDARY", + "BUTTE", + "CAMAS", + "CANYON", + "CARIBOU", + "CASSIA", + "CLARK", + "CLEARWATER", + "CUSTER", + "ELMORE", + "FRANKLIN", + "FREMONT", + "GEM", + "GOODING", + "IDAHO", + "JEFFERSON", + "JEROME", + "KOOTENAI", + "LATAH", + "LEMHI", + "LEWIS", + "LINCOLN", + "MADISON", + "MINIDOKA", + "NEZ PERCE", + "ONEIDA", + + "OTHER COUNTIES", + "OWYHEE", + "PAYETTE", + "POWER", + "SHOSHONE", + "TETON", + "TWIN FALLS", + "VALLEY", + "WASHINGTON" +], + "Illinois": [ + "ADAMS", + "ALEXANDER", + "BOND", + "BOONE", + "BROWN", + "BUREAU", + "CALHOUN", + "CARROLL", + "CASS", + "CHAMPAIGN", + "CHRISTIAN", + "CLARK", + "CLAY", + "CLINTON", + "COLES", + "COOK", + "CRAWFORD", + "CUMBERLAND", + "DE KALB", + "DE WITT", + "DOUGLAS", + "DU PAGE", + "EDGAR", + "EDWARDS", + "EFFINGHAM", + "FAYETTE", + "FORD", + "FRANKLIN", + "FULTON", + "GALLATIN", + "GREENE", + "GRUNDY", + "HAMILTON", + "HANCOCK", + "HARDIN", + "HENDERSON", + "HENRY", + "IROQUOIS", + "JACKSON", + "JASPER", + "JEFFERSON", + "JERSEY", + "JO DAVIESS", + "JOHNSON", + "KANE", + "KANKAKEE", + "KENDALL", + "KNOX", + "LA SALLE", + "LAKE", + "LAWRENCE", + "LEE", + "LIVINGSTON", + "LOGAN", + "MACON", + "MACOUPIN", + "MADISON", + "MARION", + "MARSHALL", + "MASON", + "MASSAC", + "MCDONOUGH", + "MCHENRY", + "MCLEAN", + "MENARD", + "MERCER", + "MONROE", + "MONTGOMERY", + "MORGAN", + "MOULTRIE", + "OGLE", + + "OTHER COUNTIES", + "PEORIA", + "PERRY", + "PIATT", + "PIKE", + "POPE", + "PULASKI", + "PUTNAM", + "RANDOLPH", + "RICHLAND", + "ROCK ISLAND", + "SALINE", + "SANGAMON", + "SCHUYLER", + "SCOTT", + "SHELBY", + "ST CLAIR", + "STARK", + "STEPHENSON", + "TAZEWELL", + "UNION", + "VERMILION", + "WABASH", + "WARREN", + "WASHINGTON", + "WAYNE", + "WHITE", + "WHITESIDE", + "WILL", + "WILLIAMSON", + "WINNEBAGO", + "WOODFORD" +], + "Indiana": [ + "ADAMS", + "ALLEN", + "BARTHOLOMEW", + "BENTON", + "BLACKFORD", + "BOONE", + "BROWN", + "CARROLL", + "CASS", + "CLARK", + "CLAY", + "CLINTON", + "CRAWFORD", + "DAVIESS", + "DE KALB", + "DEARBORN", + "DECATUR", + "DELAWARE", + "DUBOIS", + "ELKHART", + "FAYETTE", + "FLOYD", + "FOUNTAIN", + "FRANKLIN", + "FULTON", + "GIBSON", + "GRANT", + "GREENE", + "HAMILTON", + "HANCOCK", + "HARRISON", + "HENDRICKS", + "HENRY", + "HOWARD", + "HUNTINGTON", + "JACKSON", + "JASPER", + "JAY", + "JEFFERSON", + "JENNINGS", + "JOHNSON", + "KNOX", + "KOSCIUSKO", + "LA PORTE", + "LAGRANGE", + "LAKE", + "LAWRENCE", + "MADISON", + "MARION", + "MARSHALL", + "MARTIN", + "MIAMI", + "MONROE", + "MONTGOMERY", + "MORGAN", + "NEWTON", + "NOBLE", + "OHIO", + "ORANGE", + + "OTHER COUNTIES", + "OWEN", + "PARKE", + "PERRY", + "PIKE", + "PORTER", + "POSEY", + "PULASKI", + "PUTNAM", + "RANDOLPH", + "RIPLEY", + "RUSH", + "SCOTT", + "SHELBY", + "SPENCER", + "ST. JOSEPH", + "STARKE", + "STEUBEN", + "SULLIVAN", + "SWITZERLAND", + "TIPPECANOE", + "TIPTON", + "UNION", + "VANDERBURGH", + "VERMILLION", + "VIGO", + "WABASH", + "WARREN", + "WARRICK", + "WASHINGTON", + "WAYNE", + "WELLS", + "WHITE", + "WHITLEY" +], + "Iowa": [ + "ADAIR", + "ADAMS", + "ALLAMAKEE", + "APPANOOSE", + "AUDUBON", + "BENTON", + "BLACK HAWK", + "BOONE", + "BREMER", + "BUCHANAN", + "BUENA VISTA", + "BUTLER", + "CALHOUN", + "CARROLL", + "CASS", + "CEDAR", + "CERRO GORDO", + "CHEROKEE", + "CHICKASAW", + "CLARKE", + "CLAY", + "CLAYTON", + "CLINTON", + "CRAWFORD", + "DALLAS", + "DAVIS", + "DECATUR", + "DELAWARE", + "DES MOINES", + "DICKINSON", + "DUBUQUE", + "EMMET", + "FAYETTE", + "FLOYD", + "FRANKLIN", + "FREMONT", + "GREENE", + "GRUNDY", + "GUTHRIE", + "HAMILTON", + "HANCOCK", + "HARDIN", + "HARRISON", + "HENRY", + "HOWARD", + "HUMBOLDT", + "IDA", + "IOWA", + "JACKSON", + "JASPER", + "JEFFERSON", + "JOHNSON", + "JONES", + "KEOKUK", + "KOSSUTH", + "LEE", + "LINN", + "LOUISA", + "LUCAS", + "LYON", + "MADISON", + "MAHASKA", + "MARION", + "MARSHALL", + "MILLS", + "MITCHELL", + "MONONA", + "MONROE", + "MONTGOMERY", + "MUSCATINE", + "O BRIEN", + "OSCEOLA", + + "OTHER COUNTIES", + "PAGE", + "PALO ALTO", + "PLYMOUTH", + "POCAHONTAS", + "POLK", + "POTTAWATTAMIE", + "POWESHIEK", + "RINGGOLD", + "SAC", + "SCOTT", + "SHELBY", + "SIOUX", + "STORY", + "TAMA", + "TAYLOR", + "UNION", + "VAN BUREN", + "WAPELLO", + "WARREN", + "WASHINGTON", + "WAYNE", + "WEBSTER", + "WINNEBAGO", + "WINNESHIEK", + "WOODBURY", + "WORTH", + "WRIGHT" +], + "Kansas": [ + "ALLEN", + "ANDERSON", + "ATCHISON", + "BARBER", + "BARTON", + "BOURBON", + "BROWN", + "BUTLER", + "CHASE", + "CHAUTAUQUA", + "CHEROKEE", + "CHEYENNE", + "CLARK", + "CLAY", + "CLOUD", + "COFFEY", + "COMANCHE", + "COWLEY", + "CRAWFORD", + "DECATUR", + "DICKINSON", + "DONIPHAN", + "DOUGLAS", + "EDWARDS", + "ELK", + "ELLIS", + "ELLSWORTH", + "FINNEY", + "FORD", + "FRANKLIN", + "GEARY", + "GOVE", + "GRAHAM", + "GRANT", + "GRAY", + "GREELEY", + "GREENWOOD", + "HAMILTON", + "HARPER", + "HARVEY", + "HASKELL", + "HODGEMAN", + "JACKSON", + "JEFFERSON", + "JEWELL", + "JOHNSON", + "KEARNY", + "KINGMAN", + "KIOWA", + "LABETTE", + "LANE", + "LEAVENWORTH", + "LINCOLN", + "LINN", + "LOGAN", + "LYON", + "MARION", + "MARSHALL", + "MCPHERSON", + "MEADE", + "MIAMI", + "MITCHELL", + "MONTGOMERY", + "MORRIS", + "MORTON", + "NEMAHA", + "NEOSHO", + "NESS", + "NORTON", + "OSAGE", + "OSBORNE", + + "OTHER COUNTIES", + "OTTAWA", + "PAWNEE", + "PHILLIPS", + "POTTAWATOMIE", + "PRATT", + "RAWLINS", + "RENO", + "REPUBLIC", + "RICE", + "RILEY", + "ROOKS", + "RUSH", + "RUSSELL", + "SALINE", + "SCOTT", + "SEDGWICK", + "SEWARD", + "SHAWNEE", + "SHERIDAN", + "SHERMAN", + "SMITH", + "STAFFORD", + "STANTON", + "STEVENS", + "SUMNER", + "THOMAS", + "TREGO", + "WABAUNSEE", + "WALLACE", + "WASHINGTON", + "WICHITA", + "WILSON", + "WOODSON", + "WYANDOTTE" +], + "Kentucky": [ + "ADAIR", + "ALLEN", + "ANDERSON", + "BALLARD", + "BARREN", + "BATH", + "BELL", + "BOONE", + "BOURBON", + "BOYD", + "BOYLE", + "BRACKEN", + "BREATHITT", + "BRECKINRIDGE", + "BULLITT", + "BUTLER", + "CALDWELL", + "CALLOWAY", + "CAMPBELL", + "CARLISLE", + "CARROLL", + "CARTER", + "CASEY", + "CHRISTIAN", + "CLARK", + "CLAY", + "CLINTON", + "CRITTENDEN", + "CUMBERLAND", + "DAVIESS", + "EDMONSON", + "ELLIOTT", + "ESTILL", + "FAYETTE", + "FLEMING", + "FLOYD", + "FRANKLIN", + "FULTON", + "GALLATIN", + "GARRARD", + "GRANT", + "GRAVES", + "GRAYSON", + "GREEN", + "GREENUP", + "HANCOCK", + "HARDIN", + "HARLAN", + "HARRISON", + "HART", + "HENDERSON", + "HENRY", + "HICKMAN", + "HOPKINS", + "JACKSON", + "JEFFERSON", + "JESSAMINE", + "JOHNSON", + "KENTON", + "KNOTT", + "KNOX", + "LARUE", + "LAUREL", + "LAWRENCE", + "LEE", + "LESLIE", + "LETCHER", + "LEWIS", + "LINCOLN", + "LIVINGSTON", + "LOGAN", + "LYON", + "MADISON", + "MAGOFFIN", + "MARION", + "MARSHALL", + "MARTIN", + "MASON", + "MCCRACKEN", + "MCCREARY", + "MCLEAN", + "MEADE", + "MENIFEE", + "MERCER", + "METCALFE", + "MONROE", + "MONTGOMERY", + "MORGAN", + "MUHLENBERG", + "NELSON", + "NICHOLAS", + "OHIO", + "OLDHAM", + + "OTHER COUNTIES", + "OWEN", + "OWSLEY", + "PENDLETON", + "PERRY", + "PIKE", + "POWELL", + "PULASKI", + "ROBERTSON", + "ROCKCASTLE", + "ROWAN", + "RUSSELL", + "SCOTT", + "SHELBY", + "SIMPSON", + "SPENCER", + "TAYLOR", + "TODD", + "TRIGG", + "TRIMBLE", + "UNION", + "WARREN", + "WASHINGTON", + "WAYNE", + "WEBSTER", + "WHITLEY", + "WOLFE", + "WOODFORD" +], + "Louisiana": [ + "ACADIA", + "ALLEN", + "ASCENSION", + "ASSUMPTION", + "AVOYELLES", + "BEAUREGARD", + "BIENVILLE", + "BOSSIER", + "CADDO", + "CALCASIEU", + "CALDWELL", + "CAMERON", + "CATAHOULA", + "CLAIBORNE", + "CONCORDIA", + "DE SOTO", + "EAST BATON ROUGE", + "EAST CARROLL", + "EAST FELICIANA", + "EVANGELINE", + "FRANKLIN", + "GRANT", + "IBERIA", + "IBERVILLE", + "JACKSON", + "JEFFERSON", + "JEFFERSON DAVIS", + "LA SALLE", + "LAFAYETTE", + "LAFOURCHE", + "LINCOLN", + "LIVINGSTON", + "MADISON", + "MOREHOUSE", + "NATCHITOCHES", + "ORLEANS", + + "OTHER COUNTIES", + "OUACHITA", + "PLAQUEMINES", + "POINTE COUPEE", + "RAPIDES", + "RED RIVER", + "RICHLAND", + "SABINE", + "SAINT BERNARD", + "SAINT CHARLES", + "SAINT HELENA", + "SAINT JAMES", + "SAINT LANDRY", + "SAINT MARTIN", + "SAINT MARY", + "SAINT TAMMANY", + "ST. JOHN THE BAPTIST", + "TANGIPAHOA", + "TENSAS", + "TERREBONNE", + "UNION", + "VERMILION", + "VERNON", + "WASHINGTON", + "WEBSTER", + "WEST BATON ROUGE", + "WEST CARROLL", + "WEST FELICIANA", + "WINN" +], + "Maine": [ + "ANDROSCOGGIN", + "AROOSTOOK", + "CUMBERLAND", + "FRANKLIN", + "HANCOCK", + "KENNEBEC", + "KNOX", + "LINCOLN", + + "OTHER COUNTIES", + "OXFORD", + "PENOBSCOT", + "PISCATAQUIS", + "SAGADAHOC", + "SOMERSET", + "WALDO", + "WASHINGTON", + "YORK" +], + "Maryland": [ + "ALLEGANY", + "ANNE ARUNDEL", + "BALTIMORE", + "CALVERT", + "CAROLINE", + "CARROLL", + "CECIL", + "CHARLES", + "DORCHESTER", + "FREDERICK", + "GARRETT", + "HARFORD", + "HOWARD", + "KENT", + "MONTGOMERY", + + "OTHER COUNTIES", + "PRINCE GEORGES", + "QUEEN ANNES", + "SOMERSET", + "ST MARYS", + "TALBOT", + "WASHINGTON", + "WICOMICO", + "WORCESTER" +], + "Massachusetts": [ + "BARNSTABLE", + "BERKSHIRE", + "BRISTOL", + "DUKES", + "ESSEX", + "FRANKLIN", + "HAMPDEN", + "HAMPSHIRE", + "MIDDLESEX", + "NANTUCKET", + "NORFOLK", + + "OTHER COUNTIES", + "PLYMOUTH", + "SUFFOLK", + "WORCESTER" +], + "Michigan": [ + "ALCONA", + "ALGER", + "ALLEGAN", + "ALPENA", + "ANTRIM", + "ARENAC", + "BARAGA", + "BARRY", + "BAY", + "BENZIE", + "BERRIEN", + "BRANCH", + "CALHOUN", + "CASS", + "CHARLEVOIX", + "CHEBOYGAN", + "CHIPPEWA", + "CLARE", + "CLINTON", + "CRAWFORD", + "DELTA", + "DICKINSON", + "EATON", + "EMMET", + "GENESEE", + "GLADWIN", + "GOGEBIC", + "GRAND TRAVERSE", + "GRATIOT", + "HILLSDALE", + "HOUGHTON", + "HURON", + "INGHAM", + "IONIA", + "IOSCO", + "IRON", + "ISABELLA", + "JACKSON", + "KALAMAZOO", + "KALKASKA", + "KENT", + "KEWEENAW", + "LAKE", + "LAPEER", + "LEELANAU", + "LENAWEE", + "LIVINGSTON", + "LUCE", + "MACKINAC", + "MACOMB", + "MANISTEE", + "MARQUETTE", + "MASON", + "MECOSTA", + "MENOMINEE", + "MIDLAND", + "MISSAUKEE", + "MONROE", + "MONTCALM", + "MONTMORENCY", + "MUSKEGON", + "NEWAYGO", + "OAKLAND", + "OCEANA", + "OGEMAW", + "ONTONAGON", + "OSCEOLA", + "OSCODA", + + "OTHER COUNTIES", + "OTSEGO", + "OTTAWA", + "PRESQUE ISLE", + "ROSCOMMON", + "SAGINAW", + "SANILAC", + "SCHOOLCRAFT", + "SHIAWASSEE", + "ST CLAIR", + "ST JOSEPH", + "TUSCOLA", + "VAN BUREN", + "WASHTENAW", + "WAYNE", + "WEXFORD" +], + "Minnesota": [ + "AITKIN", + "ANOKA", + "BECKER", + "BELTRAMI", + "BENTON", + "BIG STONE", + "BLUE EARTH", + "BROWN", + "CARLTON", + "CARVER", + "CASS", + "CHIPPEWA", + "CHISAGO", + "CLAY", + "CLEARWATER", + "COOK", + "COTTONWOOD", + "CROW WING", + "DAKOTA", + "DODGE", + "DOUGLAS", + "FARIBAULT", + "FILLMORE", + "FREEBORN", + "GOODHUE", + "GRANT", + "HENNEPIN", + "HOUSTON", + "HUBBARD", + "ISANTI", + "ITASCA", + "JACKSON", + "KANABEC", + "KANDIYOHI", + "KITTSON", + "KOOCHICHING", + "LAC QUI PARLE", + "LAKE", + "LAKE OF THE WOODS", + "LE SUEUR", + "LINCOLN", + "LYON", + "MAHNOMEN", + "MARSHALL", + "MARTIN", + "MCLEOD", + "MEEKER", + "MILLE LACS", + "MORRISON", + "MOWER", + "MURRAY", + "NICOLLET", + "NOBLES", + "NORMAN", + "OLMSTED", + + "OTHER COUNTIES", + "OTTER TAIL", + "PENNINGTON", + "PINE", + "PIPESTONE", + "POLK", + "POPE", + "RAMSEY", + "RED LAKE", + "REDWOOD", + "RENVILLE", + "RICE", + "ROCK", + "ROSEAU", + "SCOTT", + "SHERBURNE", + "SIBLEY", + "ST. LOUIS", + "STEARNS", + "STEELE", + "STEVENS", + "SWIFT", + "TODD", + "TRAVERSE", + "WABASHA", + "WADENA", + "WASECA", + "WASHINGTON", + "WATONWAN", + "WILKIN", + "WINONA", + "WRIGHT", + "YELLOW MEDICINE" +], + "Mississippi": [ + "ADAMS", + "ALCORN", + "AMITE", + "ATTALA", + "BENTON", + "BOLIVAR", + "CALHOUN", + "CARROLL", + "CHICKASAW", + "CHOCTAW", + "CLAIBORNE", + "CLARKE", + "CLAY", + "COAHOMA", + "COPIAH", + "COVINGTON", + "DE SOTO", + "FORREST", + "FRANKLIN", + "GEORGE", + "GREENE", + "GRENADA", + "HANCOCK", + "HARRISON", + "HINDS", + "HOLMES", + "HUMPHREYS", + "ISSAQUENA", + "ITAWAMBA", + "JACKSON", + "JASPER", + "JEFFERSON", + "JEFFERSON DAVIS", + "JONES", + "KEMPER", + "LAFAYETTE", + "LAMAR", + "LAUDERDALE", + "LAWRENCE", + "LEAKE", + "LEE", + "LEFLORE", + "LINCOLN", + "LOWNDES", + "MADISON", + "MARION", + "MARSHALL", + "MONROE", + "MONTGOMERY", + "NESHOBA", + "NEWTON", + "NOXUBEE", + "OKTIBBEHA", + + "OTHER COUNTIES", + "PANOLA", + "PEARL RIVER", + "PERRY", + "PIKE", + "PONTOTOC", + "PRENTISS", + "QUITMAN", + "RANKIN", + "SCOTT", + "SHARKEY", + "SIMPSON", + "SMITH", + "STONE", + "SUNFLOWER", + "TALLAHATCHIE", + "TATE", + "TIPPAH", + "TISHOMINGO", + "TUNICA", + "UNION", + "WALTHALL", + "WARREN", + "WASHINGTON", + "WAYNE", + "WEBSTER", + "WILKINSON", + "WINSTON", + "YALOBUSHA", + "YAZOO" +], + "Missouri": [ + "ADAIR", + "ANDREW", + "ATCHISON", + "AUDRAIN", + "BARRY", + "BARTON", + "BATES", + "BENTON", + "BOLLINGER", + "BOONE", + "BUCHANAN", + "BUTLER", + "CALDWELL", + "CALLAWAY", + "CAMDEN", + "CAPE GIRARDEAU", + "CARROLL", + "CARTER", + "CASS", + "CEDAR", + "CHARITON", + "CHRISTIAN", + "CLARK", + "CLAY", + "CLINTON", + "COLE", + "COOPER", + "CRAWFORD", + "DADE", + "DALLAS", + "DAVIESS", + "DE KALB", + "DENT", + "DOUGLAS", + "DUNKLIN", + "FRANKLIN", + "GASCONADE", + "GENTRY", + "GREENE", + "GRUNDY", + "HARRISON", + "HENRY", + "HICKORY", + "HOLT", + "HOWARD", + "HOWELL", + "IRON", + "JACKSON", + "JASPER", + "JEFFERSON", + "JOHNSON", + "KNOX", + "LACLEDE", + "LAFAYETTE", + "LAWRENCE", + "LEWIS", + "LINCOLN", + "LINN", + "LIVINGSTON", + "MACON", + "MADISON", + "MARIES", + "MARION", + "MCDONALD", + "MERCER", + "MILLER", + "MISSISSIPPI", + "MONITEAU", + "MONROE", + "MONTGOMERY", + "MORGAN", + "NEW MADRID", + "NEWTON", + "NODAWAY", + "OREGON", + "OSAGE", + + "OTHER COUNTIES", + "OZARK", + "PEMISCOT", + "PERRY", + "PETTIS", + "PHELPS", + "PIKE", + "PLATTE", + "POLK", + "PULASKI", + "PUTNAM", + "RALLS", + "RANDOLPH", + "RAY", + "REYNOLDS", + "RIPLEY", + "SALINE", + "SCHUYLER", + "SCOTLAND", + "SCOTT", + "SHANNON", + "SHELBY", + "ST CHARLES", + "ST CLAIR", + "ST FRANCOIS", + "ST LOUIS", + "STE GENEVIEVE", + "STE. GENEVIEVE", + "STODDARD", + "STONE", + "SULLIVAN", + "TANEY", + "TEXAS", + "VERNON", + "WARREN", + "WASHINGTON", + "WAYNE", + "WEBSTER", + "WORTH", + "WRIGHT" +], + "Montana": [ + "BEAVERHEAD", + "BIG HORN", + "BLAINE", + "BROADWATER", + "CARBON", + "CARTER", + "CASCADE", + "CHOUTEAU", + "CUSTER", + "DANIELS", + "DAWSON", + "DEER LODGE", + "FALLON", + "FERGUS", + "FLATHEAD", + "GALLATIN", + "GARFIELD", + "GLACIER", + "GOLDEN VALLEY", + "GRANITE", + "HILL", + "JEFFERSON", + "JUDITH BASIN", + "LAKE", + "LEWIS AND CLARK", + "LIBERTY", + "LINCOLN", + "MADISON", + "MCCONE", + "MEAGHER", + "MINERAL", + "MISSOULA", + "MUSSELSHELL", + + "OTHER COUNTIES", + "PARK", + "PETROLEUM", + "PHILLIPS", + "PONDERA", + "POWDER RIVER", + "POWELL", + "PRAIRIE", + "RAVALLI", + "RICHLAND", + "ROOSEVELT", + "ROSEBUD", + "SANDERS", + "SHERIDAN", + "SILVER BOW", + "STILLWATER", + "SWEET GRASS", + "TETON", + "TOOLE", + "TREASURE", + "VALLEY", + "WHEATLAND", + "WIBAUX", + "YELLOWSTONE" +], + "Nebraska": [ + "ADAMS", + "ANTELOPE", + "ARTHUR", + "BANNER", + "BLAINE", + "BOONE", + "BOX BUTTE", + "BOYD", + "BROWN", + "BUFFALO", + "BURT", + "BUTLER", + "CASS", + "CEDAR", + "CHASE", + "CHERRY", + "CHEYENNE", + "CLAY", + "COLFAX", + "CUMING", + "CUSTER", + "DAKOTA", + "DAWES", + "DAWSON", + "DEUEL", + "DIXON", + "DODGE", + "DOUGLAS", + "DUNDY", + "FILLMORE", + "FRANKLIN", + "FRONTIER", + "FURNAS", + "GAGE", + "GARDEN", + "GARFIELD", + "GOSPER", + "GRANT", + "GREELEY", + "HALL", + "HAMILTON", + "HARLAN", + "HAYES", + "HITCHCOCK", + "HOLT", + "HOOKER", + "HOWARD", + "JEFFERSON", + "JOHNSON", + "KEARNEY", + "KEITH", + "KEYA PAHA", + "KIMBALL", + "KNOX", + "LANCASTER", + "LINCOLN", + "LOGAN", + "LOUP", + "MADISON", + "MCPHERSON", + "MERRICK", + "MORRILL", + "NANCE", + "NEMAHA", + "NUCKOLLS", + + "OTHER COUNTIES", + "OTOE", + "PAWNEE", + "PERKINS", + "PHELPS", + "PIERCE", + "PLATTE", + "POLK", + "RED WILLOW", + "RICHARDSON", + "ROCK", + "SALINE", + "SARPY", + "SAUNDERS", + "SCOTTS BLUFF", + "SEWARD", + "SHERIDAN", + "SHERMAN", + "SIOUX", + "STANTON", + "THAYER", + "THOMAS", + "THURSTON", + "VALLEY", + "WASHINGTON", + "WAYNE", + "WEBSTER", + "WHEELER", + "YORK" +], + "Nevada": [ + "CARSON CITY", + "CHURCHILL", + "CLARK", + "DOUGLAS", + "ELKO", + "ESMERALDA", + "EUREKA", + "HUMBOLDT", + "LANDER", + "LINCOLN", + "LYON", + "MINERAL", + "NYE", + "ORMSBY", + + "OTHER COUNTIES", + "PERSHING", + "STOREY", + "WASHOE", + "WHITE PINE" +], + "New Hampshire": [ + "BELKNAP", + "CARROLL", + "CHESHIRE", + "COOS", + "GRAFTON", + "HILLSBOROUGH", + "MERRIMACK", + + "OTHER COUNTIES", + "ROCKINGHAM", + "STRAFFORD", + "SULLIVAN" +], + "New Jersey": [ + "ATLANTIC", + "BERGEN", + "BURLINGTON", + "CAMDEN", + "CAPE MAY", + "CUMBERLAND", + "ESSEX", + "GLOUCESTER", + "HUDSON", + "HUNTERDON", + "MERCER", + "MIDDLESEX", + "MONMOUTH", + "MORRIS", + "OCEAN", + + "OTHER COUNTIES", + "PASSAIC", + "SALEM", + "SOMERSET", + "SUSSEX", + "UNION", + "WARREN" +], + "New Mexico": [ + "BERNALILLO", + "CATRON", + "CHAVES", + "CIBOLA", + "COLFAX", + "CURRY", + "DE BACA", + "DONA ANA", + "EDDY", + "GRANT", + "GUADALUPE", + "HARDING", + "HIDALGO", + "LEA", + "LINCOLN", + "LOS ALAMOS", + "LUNA", + "MCKINLEY", + "MORA", + "OTERO", + + "OTHER COUNTIES", + "QUAY", + "RIO ARRIBA", + "ROOSEVELT", + "SAN JUAN", + "SAN MIGUEL", + "SANDOVAL", + "SANTA FE", + "SIERRA", + "SOCORRO", + "TAOS", + "TORRANCE", + "UNION", + "VALENCIA" +], + "New York": [ + "ALBANY", + "ALLEGANY", + "BRONX", + "BROOME", + "CATTARAUGUS", + "CAYUGA", + "CHAUTAUQUA", + "CHEMUNG", + "CHENANGO", + "CLINTON", + "COLUMBIA", + "CORTLAND", + "DELAWARE", + "DUTCHESS", + "ERIE", + "ESSEX", + "FRANKLIN", + "FULTON", + "GENESEE", + "GREENE", + "HAMILTON", + "HERKIMER", + "JEFFERSON", + "KINGS", + "LEWIS", + "LIVINGSTON", + "MADISON", + "MONROE", + "MONTGOMERY", + "NASSAU", + "NEW YORK", + "NIAGARA", + "ONEIDA", + "ONONDAGA", + "ONTARIO", + "ORANGE", + "ORLEANS", + "OSWEGO", + + "OTHER COUNTIES", + "OTSEGO", + "PUTNAM", + "QUEENS", + "RENSSELAER", + "RICHMOND", + "ROCKLAND", + "SARATOGA", + "SCHENECTADY", + "SCHOHARIE", + "SCHUYLER", + "SENECA", + "ST LAWRENCE", + "STEUBEN", + "SUFFOLK", + "SULLIVAN", + "TIOGA", + "TOMPKINS", + "ULSTER", + "WARREN", + "WASHINGTON", + "WAYNE", + "WESTCHESTER", + "WYOMING", + "YATES" +], + "North Carolina": [ + "ALAMANCE", + "ALEXANDER", + "ALLEGHANY", + "ANSON", + "ASHE", + "AVERY", + "BEAUFORT", + "BERTIE", + "BLADEN", + "BRUNSWICK", + "BUNCOMBE", + "BURKE", + "CABARRUS", + "CALDWELL", + "CAMDEN", + "CARTERET", + "CASWELL", + "CATAWBA", + "CHATHAM", + "CHEROKEE", + "CHOWAN", + "CLAY", + "CLEVELAND", + "COLUMBUS", + "CRAVEN", + "CUMBERLAND", + "CURRITUCK", + "DARE", + "DAVIDSON", + "DAVIE", + "DUPLIN", + "DURHAM", + "EDGECOMBE", + "FORSYTH", + "FRANKLIN", + "GASTON", + "GATES", + "GRAHAM", + "GRANVILLE", + "GREENE", + "GUILFORD", + "HALIFAX", + "HARNETT", + "HAYWOOD", + "HENDERSON", + "HERTFORD", + "HOKE", + "HYDE", + "IREDELL", + "JACKSON", + "JOHNSTON", + "JONES", + "LEE", + "LENOIR", + "LINCOLN", + "MACON", + "MADISON", + "MARTIN", + "MCDOWELL", + "MECKLENBURG", + "MITCHELL", + "MONTGOMERY", + "MOORE", + "NASH", + "NEW HANOVER", + "NORTHAMPTON", + "ONSLOW", + "ORANGE", + + "OTHER COUNTIES", + "PAMLICO", + "PASQUOTANK", + "PENDER", + "PERQUIMANS", + "PERSON", + "PITT", + "POLK", + "RANDOLPH", + "RICHMOND", + "ROBESON", + "ROCKINGHAM", + "ROWAN", + "RUTHERFORD", + "SAMPSON", + "SCOTLAND", + "STANLY", + "STOKES", + "SURRY", + "SWAIN", + "TRANSYLVANIA", + "TYRRELL", + "UNION", + "VANCE", + "WAKE", + "WARREN", + "WASHINGTON", + "WATAUGA", + "WAYNE", + "WILKES", + "WILSON", + "YADKIN", + "YANCEY" +], + "North Dakota": [ + "ADAMS", + "BARNES", + "BENSON", + "BILLINGS", + "BOTTINEAU", + "BOWMAN", + "BURKE", + "BURLEIGH", + "CASS", + "CAVALIER", + "DICKEY", + "DIVIDE", + "DUNN", + "EDDY", + "EMMONS", + "FOSTER", + "GOLDEN VALLEY", + "GRAND FORKS", + "GRANT", + "GRIGGS", + "HETTINGER", + "KIDDER", + "LA MOURE", + "LOGAN", + "MCHENRY", + "MCINTOSH", + "MCKENZIE", + "MCLEAN", + "MERCER", + "MORTON", + "MOUNTRAIL", + "NELSON", + "OLIVER", + + "OTHER COUNTIES", + "PEMBINA", + "PIERCE", + "RAMSEY", + "RANSOM", + "RENVILLE", + "RICHLAND", + "ROLETTE", + "SARGENT", + "SHERIDAN", + "SIOUX", + "SLOPE", + "STARK", + "STEELE", + "STUTSMAN", + "TOWNER", + "TRAILL", + "WALSH", + "WARD", + "WELLS", + "WILLIAMS" +], + "Ohio": [ + "ADAMS", + "ALLEN", + "ASHLAND", + "ASHTABULA", + "ATHENS", + "AUGLAIZE", + "BELMONT", + "BROWN", + "BUTLER", + "CARROLL", + "CHAMPAIGN", + "CLARK", + "CLERMONT", + "CLINTON", + "COLUMBIANA", + "COSHOCTON", + "CRAWFORD", + "CUYAHOGA", + "DARKE", + "DEFIANCE", + "DELAWARE", + "ERIE", + "FAIRFIELD", + "FAYETTE", + "FRANKLIN", + "FULTON", + "GALLIA", + "GEAUGA", + "GREENE", + "GUERNSEY", + "HAMILTON", + "HANCOCK", + "HARDIN", + "HARRISON", + "HENRY", + "HIGHLAND", + "HOCKING", + "HOLMES", + "HURON", + "JACKSON", + "JEFFERSON", + "KNOX", + "LAKE", + "LAWRENCE", + "LICKING", + "LOGAN", + "LORAIN", + "LUCAS", + "MADISON", + "MAHONING", + "MARION", + "MEDINA", + "MEIGS", + "MERCER", + "MIAMI", + "MONROE", + "MONTGOMERY", + "MORGAN", + "MORROW", + "MUSKINGUM", + "NOBLE", + + "OTHER COUNTIES", + "OTTAWA", + "PAULDING", + "PERRY", + "PICKAWAY", + "PIKE", + "PORTAGE", + "PREBLE", + "PUTNAM", + "RICHLAND", + "ROSS", + "SANDUSKY", + "SCIOTO", + "SENECA", + "SHELBY", + "STARK", + "SUMMIT", + "TRUMBULL", + "TUSCARAWAS", + "UNION", + "VAN WERT", + "VINTON", + "WARREN", + "WASHINGTON", + "WAYNE", + "WILLIAMS", + "WOOD", + "WYANDOT" +], + "Oklahoma": [ + "ADAIR", + "ALFALFA", + "ATOKA", + "BEAVER", + "BECKHAM", + "BLAINE", + "BRYAN", + "CADDO", + "CANADIAN", + "CARTER", + "CHEROKEE", + "CHOCTAW", + "CIMARRON", + "CLEVELAND", + "COAL", + "COMANCHE", + "COTTON", + "CRAIG", + "CREEK", + "CUSTER", + "DELAWARE", + "DEWEY", + "ELLIS", + "GARFIELD", + "GARVIN", + "GRADY", + "GRANT", + "GREER", + "HARMON", + "HARPER", + "HASKELL", + "HUGHES", + "JACKSON", + "JEFFERSON", + "JOHNSTON", + "KAY", + "KINGFISHER", + "KIOWA", + "LATIMER", + "LEFLORE", + "LINCOLN", + "LOGAN", + "LOVE", + "MAJOR", + "MARSHALL", + "MAYES", + "MCCLAIN", + "MCCURTAIN", + "MCINTOSH", + "MURRAY", + "MUSKOGEE", + "NOBLE", + "NOWATA", + "OKFUSKEE", + "OKLAHOMA", + "OKMULGEE", + "OSAGE", + + "OTHER COUNTIES", + "OTTAWA", + "PAWNEE", + "PAYNE", + "PITTSBURG", + "PONTOTOC", + "POTTAWATOMIE", + "PUSHMATAHA", + "ROGER MILLS", + "ROGERS", + "SEMINOLE", + "SEQUOYAH", + "STEPHENS", + "TEXAS", + "TILLMAN", + "TULSA", + "WAGONER", + "WASHINGTON", + "WASHITA", + "WOODS", + "WOODWARD" +], + "Oregon": [ + "BAKER", + "BENTON", + "CLACKAMAS", + "CLATSOP", + "COLUMBIA", + "COOS", + "CROOK", + "CURRY", + "DESCHUTES", + "DOUGLAS", + "GILLIAM", + "GRANT", + "HARNEY", + "HOOD RIVER", + "JACKSON", + "JEFFERSON", + "JOSEPHINE", + "KLAMATH", + "LAKE", + "LANE", + "LINCOLN", + "LINN", + "MALHEUR", + "MARION", + "MORROW", + "MULTNOMAH", + + "OTHER COUNTIES", + "POLK", + "SHERMAN", + "TILLAMOOK", + "UMATILLA", + "UNION", + "WALLOWA", + "WASCO", + "WASHINGTON", + "WHEELER", + "YAMHILL" +], + "Pennsylvania": [ + "ADAMS", + "ALLEGHENY", + "ARMSTRONG", + "BEAVER", + "BEDFORD", + "BERKS", + "BLAIR", + "BRADFORD", + "BUCKS", + "BUTLER", + "CAMBRIA", + "CAMERON", + "CARBON", + "CENTRE", + "CHESTER", + "CLARION", + "CLEARFIELD", + "CLINTON", + "COLUMBIA", + "CRAWFORD", + "CUMBERLAND", + "DAUPHIN", + "DELAWARE", + "ELK", + "ERIE", + "FAYETTE", + "FOREST", + "FRANKLIN", + "FULTON", + "GREENE", + "HUNTINGDON", + "INDIANA", + "JEFFERSON", + "JUNIATA", + "LACKAWANNA", + "LANCASTER", + "LAWRENCE", + "LEBANON", + "LEHIGH", + "LUZERNE", + "LYCOMING", + "MCKEAN", + "MERCER", + "MIFFLIN", + "MONROE", + "MONTGOMERY", + "MONTOUR", + "NORTHAMPTON", + "NORTHUMBERLAND", + + "OTHER COUNTIES", + "PERRY", + "PHILADELPHIA", + "PIKE", + "POTTER", + "SCHUYLKILL", + "SNYDER", + "SOMERSET", + "SULLIVAN", + "SUSQUEHANNA", + "TIOGA", + "UNION", + "VENANGO", + "WARREN", + "WASHINGTON", + "WAYNE", + "WESTMORELAND", + "WYOMING", + "YORK" +], + "Rhode Island": [ + "BRISTOL", + "KENT", + "NEWPORT", + "PROVIDENCE", + "WASHINGTON" +], + "South Carolina": [ + "ABBEVILLE", + "AIKEN", + "ALLENDALE", + "ANDERSON", + "BAMBERG", + "BARNWELL", + "BEAUFORT", + "BERKELEY", + "CALHOUN", + "CHARLESTON", + "CHEROKEE", + "CHESTER", + "CHESTERFIELD", + "CLARENDON", + "COLLETON", + "DARLINGTON", + "DILLON", + "DORCHESTER", + "EDGEFIELD", + "FAIRFIELD", + "FLORENCE", + "GEORGETOWN", + "GREENVILLE", + "GREENWOOD", + "HAMPTON", + "HORRY", + "JASPER", + "KERSHAW", + "LANCASTER", + "LAURENS", + "LEE", + "LEXINGTON", + "MARION", + "MARLBORO", + "MCCORMICK", + "NEWBERRY", + "OCONEE", + "ORANGEBURG", + + "OTHER COUNTIES", + "PICKENS", + "RICHLAND", + "SALUDA", + "SPARTANBURG", + "SUMTER", + "UNION", + "WILLIAMSBURG", + "YORK" +], + "South Dakota": [ + "AURORA", + "BEADLE", + "BENNETT", + "BON HOMME", + "BROOKINGS", + "BROWN", + "BRULE", + "BUFFALO", + "BUTTE", + "CAMPBELL", + "CHARLES MIX", + "CLARK", + "CLAY", + "CODINGTON", + "CORSON", + "CUSTER", + "DAVISON", + "DAY", + "DEUEL", + "DEWEY", + "DOUGLAS", + "EDMUNDS", + "FALL RIVER", + "FAULK", + "GRANT", + "GREGORY", + "HAAKON", + "HAMLIN", + "HAND", + "HANSON", + "HARDING", + "HUGHES", + "HUTCHINSON", + "HYDE", + "JACKSON", + "JERAULD", + "JONES", + "KINGSBURY", + "LAKE", + "LAWRENCE", + "LINCOLN", + "LYMAN", + "MARSHALL", + "MCCOOK", + "MCPHERSON", + "MEADE", + "MELLETTE", + "MINER", + "MINNEHAHA", + "MOODY", + "OGLALA LAKOTA", + + "OTHER COUNTIES", + "PENNINGTON", + "PERKINS", + "POTTER", + "ROBERTS", + "SANBORN", + "SPINK", + "STANLEY", + "SULLY", + "TODD", + "TRIPP", + "TURNER", + "UNION", + "WALWORTH", + "WASHABAUGH", + "WASHINGTON", + "YANKTON", + "ZIEBACH" +], + "Tennessee": [ + "ANDERSON", + "BEDFORD", + "BENTON", + "BLEDSOE", + "BLOUNT", + "BRADLEY", + "CAMPBELL", + "CANNON", + "CARROLL", + "CARTER", + "CHEATHAM", + "CHESTER", + "CLAIBORNE", + "CLAY", + "COCKE", + "COFFEE", + "CROCKETT", + "CUMBERLAND", + "DAVIDSON", + "DE KALB", + "DECATUR", + "DICKSON", + "DYER", + "FAYETTE", + "FENTRESS", + "FRANKLIN", + "GIBSON", + "GILES", + "GRAINGER", + "GREENE", + "GRUNDY", + "HAMBLEN", + "HAMILTON", + "HANCOCK", + "HARDEMAN", + "HARDIN", + "HAWKINS", + "HAYWOOD", + "HENDERSON", + "HENRY", + "HICKMAN", + "HOUSTON", + "HUMPHREYS", + "JACKSON", + "JEFFERSON", + "JOHNSON", + "KNOX", + "LAKE", + "LAUDERDALE", + "LAWRENCE", + "LEWIS", + "LINCOLN", + "LOUDON", + "MACON", + "MADISON", + "MARION", + "MARSHALL", + "MAURY", + "MCMINN", + "MCNAIRY", + "MEIGS", + "MONROE", + "MONTGOMERY", + "MOORE", + "MORGAN", + "OBION", + + "OTHER COUNTIES", + "OVERTON", + "PERRY", + "PICKETT", + "POLK", + "PUTNAM", + "RHEA", + "ROANE", + "ROBERTSON", + "RUTHERFORD", + "SCOTT", + "SEQUATCHIE", + "SEVIER", + "SHELBY", + "SMITH", + "STEWART", + "SULLIVAN", + "SUMNER", + "TIPTON", + "TROUSDALE", + "UNICOI", + "UNION", + "VAN BUREN", + "WARREN", + "WASHINGTON", + "WAYNE", + "WEAKLEY", + "WHITE", + "WILLIAMSON", + "WILSON" +], + "Texas": [ + "ANDERSON", + "ANDREWS", + "ANGELINA", + "ARANSAS", + "ARCHER", + "ARMSTRONG", + "ATASCOSA", + "AUSTIN", + "BAILEY", + "BANDERA", + "BASTROP", + "BAYLOR", + "BEE", + "BELL", + "BEXAR", + "BLANCO", + "BORDEN", + "BOSQUE", + "BOWIE", + "BRAZORIA", + "BRAZOS", + "BREWSTER", + "BRISCOE", + "BROOKS", + "BROWN", + "BURLESON", + "BURNET", + "CALDWELL", + "CALHOUN", + "CALLAHAN", + "CAMERON", + "CAMP", + "CARSON", + "CASS", + "CASTRO", + "CHAMBERS", + "CHEROKEE", + "CHILDRESS", + "CLAY", + "COCHRAN", + "COKE", + "COLEMAN", + "COLLIN", + "COLLINGSWORTH", + "COLORADO", + "COMAL", + "COMANCHE", + "CONCHO", + "COOKE", + "CORYELL", + "COTTLE", + "CRANE", + "CROCKETT", + "CROSBY", + "CULBERSON", + "DALLAM", + "DALLAS", + "DAWSON", + "DE WITT", + "DEAF SMITH", + "DELTA", + "DENTON", + "DICKENS", + "DIMMIT", + "DONLEY", + "DUVAL", + "EASTLAND", + "ECTOR", + "EDWARDS", + "EL PASO", + "ELLIS", + "ERATH", + "FALLS", + "FANNIN", + "FAYETTE", + "FISHER", + "FLOYD", + "FOARD", + "FORT BEND", + "FRANKLIN", + "FREESTONE", + "FRIO", + "GAINES", + "GALVESTON", + "GARZA", + "GILLESPIE", + "GLASSCOCK", + "GOLIAD", + "GONZALES", + "GRAY", + "GRAYSON", + "GREGG", + "GRIMES", + "GUADALUPE", + "HALE", + "HALL", + "HAMILTON", + "HANSFORD", + "HARDEMAN", + "HARDIN", + "HARRIS", + "HARRISON", + "HARTLEY", + "HASKELL", + "HAYS", + "HEMPHILL", + "HENDERSON", + "HIDALGO", + "HILL", + "HOCKLEY", + "HOOD", + "HOPKINS", + "HOUSTON", + "HOWARD", + "HUDSPETH", + "HUNT", + "HUTCHINSON", + "IRION", + "JACK", + "JACKSON", + "JASPER", + "JEFF DAVIS", + "JEFFERSON", + "JIM HOGG", + "JIM WELLS", + "JOHNSON", + "JONES", + "KARNES", + "KAUFMAN", + "KENDALL", + "KENEDY", + "KENT", + "KERR", + "KIMBLE", + "KING", + "KINNEY", + "KLEBERG", + "KNOX", + "LA SALLE", + "LAMAR", + "LAMB", + "LAMPASAS", + "LAVACA", + "LEE", + "LEON", + "LIBERTY", + "LIMESTONE", + "LIPSCOMB", + "LIVE OAK", + "LLANO", + "LOVING", + "LUBBOCK", + "LYNN", + "MADISON", + "MARION", + "MARTIN", + "MASON", + "MATAGORDA", + "MAVERICK", + "MCCULLOCH", + "MCLENNAN", + "MCMULLEN", + "MEDINA", + "MENARD", + "MIDLAND", + "MILAM", + "MILLS", + "MITCHELL", + "MONTAGUE", + "MONTGOMERY", + "MOORE", + "MORRIS", + "MOTLEY", + "NACOGDOCHES", + "NAVARRO", + "NEWTON", + "NOLAN", + "NUECES", + "OCHILTREE", + "OLDHAM", + "ORANGE", + + "OTHER COUNTIES", + "PALO PINTO", + "PANOLA", + "PARKER", + "PARMER", + "PECOS", + "POLK", + "POTTER", + "PRESIDIO", + "RAINS", + "RANDALL", + "REAGAN", + "REAL", + "RED RIVER", + "REEVES", + "REFUGIO", + "ROBERTS", + "ROBERTSON", + "ROCKWALL", + "RUNNELS", + "RUSK", + "SABINE", + "SAN AUGUSTINE", + "SAN JACINTO", + "SAN PATRICIO", + "SAN SABA", + "SCHLEICHER", + "SCURRY", + "SHACKELFORD", + "SHELBY", + "SHERMAN", + "SMITH", + "SOMERVELL", + "STARR", + "STEPHENS", + "STERLING", + "STONEWALL", + "SUTTON", + "SWISHER", + "TARRANT", + "TAYLOR", + "TERRELL", + "TERRY", + "THROCKMORTON", + "TITUS", + "TOM GREEN", + "TRAVIS", + "TRINITY", + "TYLER", + "UPSHUR", + "UPTON", + "UVALDE", + "VAL VERDE", + "VAN ZANDT", + "VICTORIA", + "WALKER", + "WALLER", + "WARD", + "WASHINGTON", + "WEBB", + "WHARTON", + "WHEELER", + "WICHITA", + "WILBARGER", + "WILLACY", + "WILLIAMSON", + "WILSON", + "WINKLER", + "WISE", + "WOOD", + "YOAKUM", + "YOUNG", + "ZAPATA", + "ZAVALA" +], + "Utah": [ + "BEAVER", + "BOX ELDER", + "CACHE", + "CARBON", + "DAGGETT", + "DAVIS", + "DUCHESNE", + "EMERY", + "GARFIELD", + "GRAND", + "IRON", + "JUAB", + "KANE", + "MILLARD", + "MORGAN", + + "OTHER COUNTIES", + "PIUTE", + "RICH", + "SALT LAKE", + "SAN JUAN", + "SANPETE", + "SEVIER", + "SUMMIT", + "TOOELE", + "UINTAH", + "UTAH", + "WASATCH", + "WASHINGTON", + "WAYNE", + "WEBER" +], + "Vermont": [ + "ADDISON", + "BENNINGTON", + "CALEDONIA", + "CHITTENDEN", + "ESSEX", + "FRANKLIN", + "GRAND ISLE", + "LAMOILLE", + "ORANGE", + "ORLEANS", + + "OTHER COUNTIES", + "RUTLAND", + "WASHINGTON", + "WINDHAM", + "WINDSOR" +], + "Virginia": [ + "ACCOMACK", + "ALBEMARLE", + "ALLEGHANY", + "AMELIA", + "AMHERST", + "APPOMATTOX", + "ARLINGTON", + "AUGUSTA", + "BATH", + "BEDFORD", + "BLAND", + "BOTETOURT", + "BRUNSWICK", + "BUCHANAN", + "BUCKINGHAM", + "CAMPBELL", + "CAROLINE", + "CARROLL", + "CHARLES CITY", + "CHARLOTTE", + "CHESAPEAKE CITY", + "CHESTERFIELD", + "CLARKE", + "CRAIG", + "CULPEPER", + "CUMBERLAND", + "DICKENSON", + "DINWIDDIE", + "ESSEX", + "FAIRFAX", + "FAUQUIER", + "FLOYD", + "FLUVANNA", + "FRANKLIN", + "FREDERICK", + "GILES", + "GLOUCESTER", + "GOOCHLAND", + "GRAYSON", + "GREENE", + "GREENSVILLE", + "HALIFAX", + "HAMPTON CITY", + "HANOVER", + "HENRICO", + "HENRY", + "HIGHLAND", + "ISLE OF WIGHT", + "JAMES CITY", + "KING AND QUEEN", + "KING GEORGE", + "KING WILLIAM", + "LANCASTER", + "LEE", + "LOUDOUN", + "LOUISA", + "LUNENBURG", + "MADISON", + "MATHEWS", + "MECKLENBURG", + "MIDDLESEX", + "MONTGOMERY", + "NANSEMOND", + "NELSON", + "NEW KENT", + "NEWPORT NEWS CITY", + "NORTHAMPTON", + "NORTHUMBERLAND", + "NOTTOWAY", + "ORANGE", + + "OTHER COUNTIES", + "PAGE", + "PATRICK", + "PITTSYLVANIA", + "POWHATAN", + "PRINCE EDWARD", + "PRINCE GEORGE", + "PRINCE WILLIAM", + "PULASKI", + "RAPPAHANNOCK", + "RICHMOND", + "ROANOKE", + "ROCKBRIDGE", + "ROCKINGHAM", + "RUSSELL", + "SCOTT", + "SHENANDOAH", + "SMYTH", + "SOUTHAMPTON", + "SPOTSYLVANIA", + "STAFFORD", + "SUFFOLK CITY", + "SURRY", + "SUSSEX", + "TAZEWELL", + "VIRGINIA BEACH CITY", + "WARREN", + "WASHINGTON", + "WESTMORELAND", + "WISE", + "WYTHE", + "YORK" +], + "Washington": [ + "ADAMS", + "ASOTIN", + "BENTON", + "CHELAN", + "CLALLAM", + "CLARK", + "COLUMBIA", + "COWLITZ", + "DOUGLAS", + "FERRY", + "FRANKLIN", + "GARFIELD", + "GRANT", + "GRAYS HARBOR", + "ISLAND", + "JEFFERSON", + "KING", + "KITSAP", + "KITTITAS", + "KLICKITAT", + "LEWIS", + "LINCOLN", + "MASON", + "OKANOGAN", + + "OTHER COUNTIES", + "PACIFIC", + "PEND OREILLE", + "PIERCE", + "SAN JUAN", + "SKAGIT", + "SKAMANIA", + "SNOHOMISH", + "SPOKANE", + "STEVENS", + "THURSTON", + "WAHKIAKUM", + "WALLA WALLA", + "WHATCOM", + "WHITMAN", + "YAKIMA" +], + "West Virginia": [ + "BARBOUR", + "BERKELEY", + "BOONE", + "BRAXTON", + "BROOKE", + "CABELL", + "CALHOUN", + "CLAY", + "DODDRIDGE", + "FAYETTE", + "GILMER", + "GRANT", + "GREENBRIER", + "HAMPSHIRE", + "HANCOCK", + "HARDY", + "HARRISON", + "JACKSON", + "JEFFERSON", + "KANAWHA", + "LEWIS", + "LINCOLN", + "LOGAN", + "MARION", + "MARSHALL", + "MASON", + "MCDOWELL", + "MERCER", + "MINERAL", + "MINGO", + "MONONGALIA", + "MONROE", + "MORGAN", + "NICHOLAS", + "OHIO", + + "OTHER COUNTIES", + "PENDLETON", + "PLEASANTS", + "POCAHONTAS", + "PRESTON", + "PUTNAM", + "RALEIGH", + "RANDOLPH", + "RITCHIE", + "ROANE", + "SUMMERS", + "TAYLOR", + "TUCKER", + "TYLER", + "UPSHUR", + "WAYNE", + "WEBSTER", + "WETZEL", + "WIRT", + "WOOD", + "WYOMING" +], + "Wisconsin": [ + "ADAMS", + "ASHLAND", + "BARRON", + "BAYFIELD", + "BROWN", + "BUFFALO", + "BURNETT", + "CALUMET", + "CHIPPEWA", + "CLARK", + "COLUMBIA", + "CRAWFORD", + "DANE", + "DODGE", + "DOOR", + "DOUGLAS", + "DUNN", + "EAU CLAIRE", + "FLORENCE", + "FOND DU LAC", + "FOREST", + "GRANT", + "GREEN", + "GREEN LAKE", + "IOWA", + "IRON", + "JACKSON", + "JEFFERSON", + "JUNEAU", + "KENOSHA", + "KEWAUNEE", + "LA CROSSE", + "LAFAYETTE", + "LANGLADE", + "LINCOLN", + "MANITOWOC", + "MARATHON", + "MARINETTE", + "MARQUETTE", + "MENOMINEE", + "MILWAUKEE", + "MONROE", + "OCONTO", + "ONEIDA", + + "OTHER COUNTIES", + "OUTAGAMIE", + "OZAUKEE", + "PEPIN", + "PIERCE", + "POLK", + "PORTAGE", + "PRICE", + "RACINE", + "RICHLAND", + "ROCK", + "RUSK", + "SAUK", + "SAWYER", + "SHAWANO", + "SHEBOYGAN", + "ST CROIX", + "TAYLOR", + "TREMPEALEAU", + "VERNON", + "VILAS", + "WALWORTH", + "WASHBURN", + "WASHINGTON", + "WAUKESHA", + "WAUPACA", + "WAUSHARA", + "WINNEBAGO", + "WOOD" +], + "Wyoming": [ + "ALBANY", + "BIG HORN", + "CAMPBELL", + "CARBON", + "CONVERSE", + "CROOK", + "FREMONT", + "GOSHEN", + "HOT SPRINGS", + "JOHNSON", + "LARAMIE", + "LINCOLN", + "NATRONA", + "NIOBRARA", + + "OTHER COUNTIES", + "PARK", + "PLATTE", + "SHERIDAN", + "SUBLETTE", + "SWEETWATER", + "TETON", + "UINTA", + "WASHAKIE", + "WESTON" +] +}; diff --git a/src/constants/queryHeaders.ts b/src/constants/queryHeaders.ts new file mode 100644 index 0000000..b2a50ab --- /dev/null +++ b/src/constants/queryHeaders.ts @@ -0,0 +1,269 @@ +import { IQueryHeaders } from "./types"; + +const allYears = []; +for (let year = 2022; year >= 1910; year--) { + allYears.push(`${year}`); +} + +const sharedDemographicHeaders = { + sect_desc: "Demographics", + group_desc: "Producers", + commodity_desc: "Producers", + statisticcat_desc: "Producers", + domain_desc: "Total", + geographicAreas: ["State", "County"] +}; + +const sharedEconomicHeaders = { + sect_desc: "Economics", + group_desc: "Farms & Land & Assets", + commodity_desc: "Farm Operations", + statisticcat_desc: "Operations" +}; + +const sharedLaborHeaders = { + sect_desc: "Economics", + group_desc: "Expenses", + commodity_desc: "Labor", +}; + +const sharedCropHeaders = { + sect_desc: "Crops", + statisticcat_desc: { + ["Area Harvested"]: "Area Harvested", + ["Yield"]: "Yield" + }, + domain_desc: "Total", + geographicAreas: ["State", "County"], + years: { + "County": allYears, + "State": allYears + } +}; + +export const queryData: Array = [ + { + plugInAttribute: "Total Farmers", + ...sharedDemographicHeaders, + short_desc: ["PRODUCERS, (ALL) - NUMBER OF PRODUCERS"], + years: { + "County": ["2017"], + "State": ["2017"] + } + }, + { + plugInAttribute: "Age", + ...sharedDemographicHeaders, + short_desc: [ + "PRODUCERS, AGE LT 25 - NUMBER OF PRODUCERS", + "PRODUCERS, AGE 25 TO 34 - NUMBER OF PRODUCERS", + "PRODUCERS, AGE 35 TO 44 - NUMBER OF PRODUCERS", + "PRODUCERS, AGE 45 TO 54 - NUMBER OF PRODUCERS", + "PRODUCERS, AGE 55 TO 64 - NUMBER OF PRODUCERS", + "PRODUCERS, AGE 65 TO 74 - NUMBER OF PRODUCERS", + "PRODUCERS, AGE GE 75 - NUMBER OF PRODUCERS" + ], + years: { + "County": ["2017"], + "State": ["2017"] + } + + }, + { + plugInAttribute: "Gender", + ...sharedDemographicHeaders, + short_desc: [ + "PRODUCERS, (ALL), FEMALE - NUMBER OF PRODUCERS", + "PRODUCERS, (ALL), MALE - NUMBER OF PRODUCERS" + ], + years: { + "County": ["2017"], + "State": ["2017"] + } + }, + { + plugInAttribute: "Race", + ...sharedDemographicHeaders, + short_desc: [ + "PRODUCERS, AMERICAN INDIAN OR ALASKAN NATIVE - NUMBER OF PRODUCERS", + "PRODUCERS, ASIAN - NUMBER OF PRODUCERS", + "PRODUCERS, BLACK OR AFRICAN AMERICAN - NUMBER OF PRODUCERS", + "PRODUCERS, HISPANIC - NUMBER OF PRODUCERS", + "PRODUCERS, MULTI-RACE - NUMBER OF PRODUCERS", + "PRODUCERS, NATIVE HAWAIIAN OR OTHER PACIFIC ISLANDERS - NUMBER OF PRODUCERS", + "PRODUCERS, WHITE - NUMBER OF PRODUCERS" + ], + years: { + "County": ["2017"], + "State": ["2017"] + } + }, + { + plugInAttribute: "Total Farms", + ...sharedEconomicHeaders, + short_desc: ["FARM OPERATIONS - NUMBER OF OPERATIONS"], + domain_desc: "Total", + geographicAreas: ["State", "County"], + years: { + "County": allYears, + "State": allYears + } + }, + { + plugInAttribute: "Organization Type", + sect_desc: "Demographics", + group_desc: "Farms & Land & Assets", + commodity_desc: "Farm Operations", + statisticcat_desc: "Operations", + short_desc: [ + "FARM OPERATIONS, ORGANIZATION, TAX PURPOSES, CORPORATION (EXCL FAMILY HELD) - NUMBER OF OPERATIONS", + "FARM OPERATIONS, ORGANIZATION, TAX PURPOSES, CORPORATION, FAMILY HELD - NUMBER OF OPERATIONS", + "FARM OPERATIONS, ORGANIZATION, TAX PURPOSES, FAMILY & INDIVIDUAL - NUMBER OF OPERATIONS", + "FARM OPERATIONS, ORGANIZATION, TAX PURPOSES, INSTITUTIONAL & RESEARCH & RESERVATION & OTHER - NUMBER OF OPERATIONS", + "FARM OPERATIONS, ORGANIZATION, TAX PURPOSES, PARTNERSHIP - NUMBER OF OPERATIONS" + ], + domain_desc: "Total", + geographicAreas: ["County"], + years: { + "County": ["1997", "2002", "2007", "2012", "2017"], + "State": [] + } + }, + { + plugInAttribute: "Economic Class", + ...sharedEconomicHeaders, + short_desc: ["FARM OPERATIONS - NUMBER OF OPERATIONS"], + domain_desc: "Economic Class", + geographicAreas: ["State"], + years: { + "County": allYears.filter(y => Number(y) >= 1987), + "State": allYears.filter(y => Number(y) >= 1987) + } + }, + { + plugInAttribute: "Acres Operated", + sect_desc: "Economics", + group_desc: "Farms & Land & Assets", + commodity_desc: "Farm Operations", + statisticcat_desc: "Area Operated", + short_desc: ["FARM OPERATIONS - ACRES OPERATED"], + domain_desc: "Area Operated", + geographicAreas: ["State", "County"], + years: { + "County": ["1997", "2002", "2007", "2012", "2017"], + "State": ["1997", "2002", "2007", "2012", "2017"] + } + }, + { + plugInAttribute: "Organic", + ...sharedEconomicHeaders, + short_desc: ["FARM OPERATIONS, ORGANIC - NUMBER OF OPERATIONS"], + domain_desc: "Organic Status", + geographicAreas: ["State", "County"], + years: { + "County": ["2008", "2011", "2012", "2014", "2015", "2016", "2017", "2019", "2021"], + "State": ["2008", "2011", "2012", "2014", "2015", "2016", "2017", "2019", "2021"] + } + }, + { + plugInAttribute: "Labor Status", + ...sharedLaborHeaders, + statisticcat_desc: "Workers", + short_desc: [ + "LABOR, MIGRANT - NUMBER OF WORKERS", + "LABOR, UNPAID - NUMBER OF WORKERS", + "LABOR, HIRED - NUMBER OF WORKERS" + ], + domain_desc: "Total", + geographicAreas: ["State", "County"], + years: { + "County": ["2012", "2017"], + "State": ["2012", "2017"] + } + }, + { + plugInAttribute: "Wages", + ...sharedLaborHeaders, + statisticcat_desc: "Wage Rate", + short_desc: ["LABOR, HIRED - WAGE RATE, MEASURED IN $ / HOUR"], + domain_desc: "Total", + geographicAreas: ["REGION : MULTI-STATE"], + years: { + "County": allYears.filter(y => Number(y) >= 1989), + "State": allYears.filter(y => Number(y) >= 1989) + } + }, + { + plugInAttribute: "Time Worked", + ...sharedLaborHeaders, + statisticcat_desc: "Time Worked", + short_desc: ["LABOR, HIRED - TIME WORKED, MEASURED IN HOURS / WEEK"], + domain_desc: "Total", + geographicAreas: ["REGION : MULTI-STATE"], + years: { + "County": allYears.filter(y => Number(y) >= 1989), + "State": allYears.filter(y => Number(y) >= 1989) + } + }, + { + plugInAttribute: "Corn", + group_desc: "Field Crops", + commodity_desc: "Corn", + short_desc: { + ["Area Harvested"]: ["CORN, GRAIN - ACRES HARVESTED"], + ["Yield"]: ["CORN, GRAIN - YIELD, MEASURED IN BU / ACRE"] + }, + ...sharedCropHeaders + }, + { + plugInAttribute: "Cotton", + group_desc: "Field Crops", + commodity_desc: "Cotton", + short_desc: { + ["Area Harvested"]: ["COTTON - ACRES HARVESTED"], + ["Yield"]: ["COTTON - YIELD, MEASURED IN LB / ACRE"] + }, + ...sharedCropHeaders + }, + { + plugInAttribute: "Grapes", + group_desc: "Fruit & Tree Nuts", + commodity_desc: "Grapes", + short_desc: { + ["Area Harvested"]: ["GRAPES, ORGANIC - ACRES HARVESTED"], + ["Yield"]: ["GRAPES - YIELD, MEASURED IN TONS / ACRE"] + }, + ...sharedCropHeaders + }, + { + plugInAttribute: "Oats", + group_desc: "Field Crops", + commodity_desc: "Oats", + short_desc: { + ["Area Harvested"]: ["OATS - ACRES HARVESTED"], + ["Yield"]: ["OATS - YIELD, MEASURED IN BU / ACRE"] + }, + ...sharedCropHeaders + }, + { + plugInAttribute: "Soybeans", + group_desc: "Field Crops", + commodity_desc: "Soybeans", + short_desc: { + ["Area Harvested"]: ["SOYBEANS - ACRES HARVESTED"], + ["Yield"]: ["SOYBEANS - YIELD MEASURED IN BU / ACRE"] + }, + ...sharedCropHeaders + }, + { + plugInAttribute: "Wheat", + group_desc: "Field Crops", + commodity_desc: "Wheat", + + short_desc: { + ["Area Harvested"]: ["WHEAT - ACRES HARVESTED"], + ["Yield"]: ["WHEAT - YIELD MEASURED IN BU / ACRE"] + }, + ...sharedCropHeaders + } +]; diff --git a/src/constants/regionData.ts b/src/constants/regionData.ts new file mode 100644 index 0000000..4a5317c --- /dev/null +++ b/src/constants/regionData.ts @@ -0,0 +1,79 @@ +interface IRegion { + "Region": string + "States": string[] +} + +export const multiRegions: IRegion[] = [ + { + "Region": "Pacific", + "States": ["Washington", "Oregon"] + }, + { + "Region": "Mountain I", + "States": ["Montana", "Idaho", "Wyoming"] + }, + { + "Region": "Mountain II", + "States": ["Nevada", "Utah", "Colorado"] + }, + { + "Region": "Mountain III", + "States": ["Arizona", "New Mexico"] + }, + { + "Region": "Northern Plains", + "States": ["North Dakota", "South Dakota", "Kansas", "Nebraska"] + }, + { + "Region": "Southern Plains", + "States": ["Oklahoma", "Texas"] + }, + { + "Region": "Lake", + "States": ["Minnesota", "Wisconsin", "Michigan"] + }, + { + "Region": "Cornbelt I", + "States": ["Illinois", "Indiana", "Ohio"] + }, + { + "Region": "Cornbelt II", + "States": ["Iowa", "Missouri"] + }, + { + "Region": "Delta", + "States": ["Mississippi", "Louisiana", "Arkansas"] + }, + { + "Region": "Appalachian I", + "States": ["Virginia", "North Carolina"] + }, + { + "Region": "Appalachian II", + "States": ["West Virginia", "Kentucky", "Tennessee"] + }, + { + "Region": "Southeast", + "States": ["South Carolina", "Alabama", "Georgia"] + }, + { + "Region": "Northeast I", + "States": ["Maine", "New Hampshire", "Vermont", "Massachusetts", "Connecticut", "Rhode Island", "New York"] + }, + { + "Region": "Northeast II", + "States": ["Pennsylvania", "New Jersey", "Delaware", "Maryland"] + }, + { + "Region": "California", + "States": ["California"] + }, + { + "Region": "Florida", + "States": ["Florida"] + }, + { + "Region": "Hawaii", + "States": ["Hawaii"] + } +]; diff --git a/src/constants/types.ts b/src/constants/types.ts new file mode 100644 index 0000000..d210207 --- /dev/null +++ b/src/constants/types.ts @@ -0,0 +1,86 @@ +export interface IStateOptions { + geographicLevel: "County"|"State", + states: string[], + farmerDemographics: string[], + farmDemographics: string[], + economicsAndWages: string[], + cropUnits: string, + crops: string[] + years: string[] +} + +export type OptionKey = keyof IStateOptions; + +export interface IAttrOptions { + key: keyof IStateOptions, + label: string|null, + options: string[], + instructions: string|null +} + +export interface IResData { + "CV (%)": string; + Value: string; + agg_level_desc: string; + asd_code: string; + asd_desc: string; + begin_code: string; + class_desc: string; + commodity_desc: string; + congr_district_code: string; + country_code: string; + country_name: string; + county_ansi: string; + county_code: string; + county_name: string; + domain_desc: string; + domaincat_desc: string; + end_code: string; + freq_desc: string; + group_desc: string; + load_time: string; + location_desc: string; + prodn_practice_desc: string; + reference_period_desc: string; + region_desc: string; + sector_desc: string; + short_desc: string; + source_desc: string; + state_alpha: string; + state_ansi: string; + state_fips_code: string; + state_name: string; + statisticcat_desc: string; + unit_desc: string; + util_practice_desc: string; + watershed_code: string; + watershed_desc: string; + week_ending: string; + year: number; + zip_5: string; +} + +export interface ICropCategory { + ["Area Harvested"]: string, + ["Yield"]: string +} + +export interface ICropDataItem { + ["Area Harvested"]: string[], + ["Yield"]: string[] +} + +export interface IQueryHeaders { + plugInAttribute: string, + sect_desc: string, + group_desc: string, + commodity_desc: string, + statisticcat_desc: string|ICropCategory, + short_desc: string[]|ICropDataItem, + domain_desc: string, + geographicAreas: string[], + years: { + "County": string[] + "State": string[] + } +} diff --git a/src/scripts/api.ts b/src/scripts/api.ts new file mode 100644 index 0000000..8dcd166 --- /dev/null +++ b/src/scripts/api.ts @@ -0,0 +1,241 @@ +import fetchJsonp from "fetch-jsonp"; +import { ICropCategory, ICropDataItem, IStateOptions } from "../constants/types"; +import { multiRegions } from "../constants/regionData"; +import { connect } from "./connect"; +import { cropOptions, fiftyStates } from "../constants/constants"; +import { countyData } from "../constants/counties"; +import { getQueryParams } from "./utils"; +import { attrToCODAPColumnName } from "../constants/codapMetadata"; + +const baseURL = `https://quickstats.nass.usda.gov/api/api_GET/?key=9ED0BFB8-8DDD-3609-9940-A2341ED6A9E3`; + +interface IRequestParams { + attribute: string, + geographicLevel: string, + location: string, + year: string, + cropCategory?: keyof ICropDataItem, + state?: string +} + +interface IGetAttrDataParams { + attribute: string, + geographicLevel: string, + cropUnits: string, + location: string, + year: string + state?: string +} + +// export const fetchData = async (req: string) => { +// try { +// const response = await fetchJsonp(req, {timeout: 10000}); +// const json = await response.json(); +// return json; +// } catch (error) { +// console.log("parsing failed", error); +// throw error; +// } +// }; + +export const fetchDataWithRetry = async (req: string, maxRetries = 3) => { + let retries = 0; + while (retries < maxRetries) { + try { + const response = await fetchJsonp(req, { timeout: 30000 }); // Increase the timeout + const json = await response.json(); + return json; + } catch (error) { + console.log(`Request attempt ${retries + 1} failed:`, error); + retries++; + } + } + throw new Error(`Request failed after ${maxRetries} attempts`); +}; + +export const createRequest = ({attribute, geographicLevel, location, year, cropCategory, state}: IRequestParams) => { + const queryParams = getQueryParams(attribute); + + if (!queryParams) { + throw new Error("Invalid attribute"); + } + + const { + sect_desc, + group_desc, + commodity_desc, + statisticcat_desc, + domain_desc, + short_desc, + } = queryParams; + + const item = cropCategory ? + (queryParams?.short_desc as ICropDataItem)[cropCategory] : + short_desc as string[]; + const cat = cropCategory ? + (queryParams?.statisticcat_desc as ICropCategory)[cropCategory] : + statisticcat_desc; + + const locationHeader = geographicLevel === "REGION : MULTI-STATE" ? "region_desc" : geographicLevel === "County" ? "county_name" : "state_name"; + + const baseReq = `${baseURL}` + + `§_desc=${encodeURIComponent(sect_desc)}` + + `&group_desc=${encodeURIComponent(group_desc)}` + + `&commodity_desc=${encodeURIComponent(commodity_desc)}` + + `&statisticcat_desc=${encodeURIComponent(cat as string)}` + + `&domain_desc=${encodeURIComponent(domain_desc)}` + + `&agg_level_desc=${encodeURIComponent(geographicLevel)}` + + `&${locationHeader}=${encodeURIComponent(location)}` + + `&year=${year}`; + + let req = baseReq; + + // if we are creating a request at the county level, we need to also pass in a state + if (state) { + req += `&state_name=${state}`; + } + + item.forEach(subItem => { + req = req + `&short_desc=${encodeURIComponent(subItem)}`; + }); + return req; +}; + +export const createTableFromSelections = async (selectedOptions: IStateOptions) => { + const {geographicLevel, states, cropUnits, years, ...subOptions} = selectedOptions; + await connect.getNewDataContext(); + await connect.createTopCollection(geographicLevel); + + const allAttrs: Array = ["Year"]; + + for (const key in subOptions) { + const selections = subOptions[key as keyof typeof subOptions]; + for (const attribute of selections) { + const queryParams = getQueryParams(attribute); + if (!queryParams) { + throw new Error("Invalid attribute"); + } + const {short_desc} = queryParams; + if (Array.isArray(short_desc)) { + for (const desc of short_desc) { + console.log({desc}); + const codapColumnName = attrToCODAPColumnName[desc].attributeNameInCodapTable; + allAttrs.push(codapColumnName); + } + } else if (typeof short_desc === "object" && cropUnits) { + const attr = short_desc[cropUnits as keyof ICropDataItem][0]; + allAttrs.push(attrToCODAPColumnName[attr].attributeNameInCodapTable); + } + } + } + + await connect.createSubCollection(geographicLevel, allAttrs); + const items = await getItems(selectedOptions); + await connect.createItems(items); + await connect.makeCaseTableAppear(); +}; + +const getItems = async (selectedOptions: IStateOptions) => { + let {states, years} = selectedOptions; + const multipleStatesSelected = states.length > 1 || states[0] === "All States"; + const multipleYearsSelected = years.length > 1; + const countySelected = selectedOptions.geographicLevel === "County"; + + if (states[0] === "All States") { + states = fiftyStates; + } + + const promises = []; + + if (multipleStatesSelected) { + for (const state of states) { + if (multipleYearsSelected) { + for (const year of years) { + if (countySelected) { + const allCounties = countyData[state]; + for (const county of allCounties) { + const item = getDataForSingleYearAndState(selectedOptions, county, year, state); + promises.push(item); + } + } else { + const item = getDataForSingleYearAndState(selectedOptions, state, year); + promises.push(item); + } + } + } else { + const item = getDataForSingleYearAndState(selectedOptions, state, years[0]); + promises.push(item); + } + } + } else { + if (countySelected) { + const allCounties = countyData[states[0]]; + for (const county of allCounties) { + const item = getDataForSingleYearAndState(selectedOptions, county, years[0], states[0]); + promises.push(item); + } + } else { + const item = getDataForSingleYearAndState(selectedOptions, states[0], years[0]); + promises.push(item); + } + } + return await Promise.all(promises); +}; + +const getDataForSingleYearAndState = async (selectedOptions: IStateOptions, countyOrState: string, year: string, state?: string) => { + const {geographicLevel, states, years, cropUnits, ...subOptions} = selectedOptions; + + let item: any = { + [geographicLevel]: countyOrState, + "Year": year, + }; + + for (const key in subOptions) { + const value = subOptions[key as keyof typeof subOptions]; + if (value && Array.isArray(value)) { + for (const attribute of value) { + const queryParams = getQueryParams(attribute); + const yearAvailable = queryParams?.years[geographicLevel].includes(year); + const isMultiStateRegion = queryParams?.geographicAreas[0] === "REGION : MULTI-STATE"; + const geoLevel = isMultiStateRegion ? "REGION : MULTI-STATE" : geographicLevel; + if (yearAvailable) { + let location = countyOrState; + if (isMultiStateRegion) { + const itemToCheck = state ? state : countyOrState; + const regData = multiRegions.find((region) => region.States.includes(itemToCheck)); + location = regData?.Region ? regData.Region : countyOrState; + } + const params: IGetAttrDataParams = {attribute, geographicLevel: geoLevel, location, year, cropUnits}; + if (geoLevel === "County") { + params.state = state; + } + const attrData = await getAttrData(params); + item = {...item, ...attrData}; + } + } + } + } + + return item; +}; + +const getAttrData = async (params: IGetAttrDataParams) => { + const {attribute, geographicLevel, location, year, cropUnits, state} = params; + const reqParams: IRequestParams = {attribute, geographicLevel, location, year, state}; + if (cropOptions.options.includes(attribute) && cropUnits) { + reqParams.cropCategory = cropUnits as keyof ICropDataItem; + } + const req = createRequest(reqParams); + const res = await fetchDataWithRetry(req); + const values: any = {}; + if (res) { + const {data} = res; + data.map((dataItem: any) => { + const codapColumnName = attrToCODAPColumnName[dataItem.short_desc].attributeNameInCodapTable; + return values[codapColumnName] = dataItem.Value; + }); + } else { + console.log("error"); + } + return values; +}; diff --git a/src/scripts/connect.js b/src/scripts/connect.js index 0ac3759..8676f21 100644 --- a/src/scripts/connect.js +++ b/src/scripts/connect.js @@ -1,38 +1,124 @@ import { codapInterface } from "./codapInterface"; +const dataSetName = "NASS Quickstats Data"; +const dataSetTitle = "NASS Quickstats Data"; + export const connect = { initialize: async function () { return await codapInterface.init(this.iFrameDescriptor, null); }, - createNewCollection: async function(dSName, collName) { + makeCODAPAttributeDef: function (attr) { + return { + name: attr + } + }, + + createNewDataContext: async function () { + return codapInterface.sendRequest({ + action: 'create', + resource: 'dataContext', + values: { + name: dataSetName, + title: dataSetTitle + } + }); + }, + + deleteOldDataContext: async function () { + return codapInterface.sendRequest({ + action: 'delete', + resource: `dataContext[${dataSetName}]` + }); + }, + + checkIfDataContextExists: async function () { + const response = await codapInterface.sendRequest({ + action: 'get', + resource: `dataContext[${dataSetName}]`}); + return response; + }, + + getNewDataContext: async function () { + const doesDataContextExist = await this.checkIfDataContextExists(); + if (doesDataContextExist.success) { + await connect.deleteOldDataContext(); + } + const res = await connect.createNewDataContext(); + return res; + }, + + createTopCollection: async function(geoLevel) { + const plural = geoLevel === "State" ? "States" : "Counties"; const message = { "action": "create", - "resource": `dataContext[${dSName}].collection`, + "resource": `dataContext[${dataSetName}].collection`, "values": { - "name": collName, + "name": plural, + "parent": "_root_", "attributes": [{ - "name": "newAttr", + "name": geoLevel, + }, + { + "name": "Boundary", + "formula": `lookupBoundary(US_${geoLevel.toLowerCase()}_boundaries, ${geoLevel})`, + "formulaDependents": "State" }] } }; await codapInterface.sendRequest(message); }, - createNewAttribute: async function(dSName, collName, attrName) { + createSubCollection: async function(geoLevel, attrs) { + const plural = geoLevel === "State" ? "States" : "Counties"; const message = { "action": "create", - "resource": `dataContext[${dSName}].collection[${collName}].attribute`, + "resource": `dataContext[${dataSetName}].collection`, "values": { - "name": attrName, + "name": "Data", + "parent": plural, + "attributes": attrs.map((attr) => this.makeCODAPAttributeDef(attr)) } }; await codapInterface.sendRequest(message); }, + createItems: async function(items) { + for (const item of items) { + const message = { + "action": "create", + "resource": `dataContext[${dataSetName}].item`, + "values": item + }; + await codapInterface.sendRequest(message); + } + }, + + makeCaseTableAppear : async function() { + const theMessage = { + action : "create", + resource : "component", + values : { + type : 'caseTable', + dataContext : dataSetName, + name : dataSetName, + title: dataSetName, + cannotClose : false + } + }; + + const makeCaseTableResult = await codapInterface.sendRequest(theMessage); + if (makeCaseTableResult.success) { + console.log("Success creating case table: " + theMessage.title); + } else { + console.log("FAILED to create case table: " + theMessage.title); + } + return makeCaseTableResult.success && makeCaseTableResult.values.id; + }, + iFrameDescriptor: { version: '0.0.1', name: 'nass-plugin', - title: 'MultiData' + title: 'NASS Quickstats Data' }, } diff --git a/src/scripts/pluginHelper.js b/src/scripts/pluginHelper.js deleted file mode 100644 index fab10ec..0000000 --- a/src/scripts/pluginHelper.js +++ /dev/null @@ -1,162 +0,0 @@ -/** - * Created by tim on 1/19/17. - - - ========================================================================== - pluginHelper.js in gamePrototypes. - - Author: Tim Erickson - - Copyright (c) 2016 by The Concord Consortium, Inc. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ========================================================================== - - - */ - -var pluginHelper = { - - - /** - * Create a new data set (data context) using the input object - * @param iDataSetDescription the object that describes the data set. See the API documentation. - * @returns {Promise} which, when resolved, means that the data set exists - */ - initDataSet: function (iDataSetDescription) { - return new Promise( function( resolve, reject ) { - var tDataContextResourceString = 'dataContext[' + iDataSetDescription.name + ']'; - var tMessage = { action: 'get', resource: tDataContextResourceString }; - - // if the data set already exists, we will not ask CODAP to create one. So we check... - var tAlreadyExistsPromise = codapInterface.sendRequest(tMessage); - - tAlreadyExistsPromise.then( - // iValue is the result of the resolved "get dataContext" call - function( iValue ) { - if (iValue.success) { - console.log("dataContext[" + iDataSetDescription.name + "] already exists"); - resolve( iValue ); - } else { - // the data set did not exist. (Since get dataContext returned success = false) - console.log("Creating dataContext[" + iDataSetDescription.name + "]" ); - tMessage = { - action: 'create', - resource: 'dataContext', - values: iDataSetDescription - }; - codapInterface.sendRequest(tMessage).then( - // iValue is the result of the resolved "create dataContext" call. - function( iValue ) { - resolve( iValue ); - } - ); - } - } - ).catch (function (msg) { - console.log('warning in pluginHelper.initDataSet: ' + msg); - reject( msg ); - }); - }); - }, - - /** - * Create new data items (broader than cases; see the documentation for the API) - * Notes: (1) this refers only to the data context, not to any collections. Right? Has to. - * (2) notice how the values array does not have a "values" key inside it as with createCases. - * - * @param iValuesArray the array (or not) of objects, each of which will be an item. The keys are attribute names. - * @param iDataContextName the name of the data set (or "data context"). - */ - createItems : function(iValuesArray, iDataContextName, iCallback) { - return new Promise( function(resolve, reject) { - iValuesArray = pluginHelper.arrayify( iValuesArray ); - - var tResourceString = iDataContextName ? "dataContext[" + iDataContextName + "].item" : "item"; - - var tMessage = { - action : 'create', - resource : tResourceString, - values : iValuesArray - }; - - var tCreateItemsPromise = codapInterface.sendRequest(tMessage); - resolve( tCreateItemsPromise ); - }) - }, - - createCases : function(iValues, iCollection, iDataContext, iCallback) { - iValues = pluginHelper.arrayify( iValues ); - console.log("DO NOT CALL pluginHelper.createCases YET!!"); - }, - - /** - * - * @param IDs array of case IDs to be selected - * @param iDataContextName name of the data context in which these things live. OK if absent. - * @returns {Promise} - */ - selectCasesByIDs: function (IDs, iDataContextName) { - return new Promise( function( resolve, reject ) { - IDs = pluginHelper.arrayify( IDs ); - - var tResourceString = "selectionList"; - - if (typeof iDataContextName !== 'undefined') { - tResourceString = 'dataContext[' + iDataContextName + '].' + tResourceString; - } - - var tMessage = { - action: 'create', - resource: tResourceString, - values: IDs - }; - - var tSelectCasesPromise = codapInterface.sendRequest(tMessage); - resolve( tSelectCasesPromise ); - }) - }, - - getCaseValuesByCaseID: function (iCaseID, iDataContext) { - return new Promise(function (resolve, reject) { - var tMessage = { - action: 'get', - resource: "dataContext[" - + iDataContext + "].caseByID[" - + iCaseID + "]" - }; - - codapInterface.sendRequest(tMessage).then( - function (iResult) { - if (iResult.success) { - var tCaseValues = iResult.values.case.values; - resolve(tCaseValues); - } - } - ) - }) - }, - - /** - * Change the input to an array if it is not one! - * @param iValuesArray the thing which might be an array - * @returns {*} if it was not an array, a single-item array with the thing. Otherwise, the array. - */ - arrayify : function( iValuesArray ) { - if (iValuesArray && !Array.isArray(iValuesArray)) { - iValuesArray = [iValuesArray]; - } - return iValuesArray; - } - -} \ No newline at end of file diff --git a/src/scripts/utils.ts b/src/scripts/utils.ts new file mode 100644 index 0000000..9450ea4 --- /dev/null +++ b/src/scripts/utils.ts @@ -0,0 +1,10 @@ +import { queryData } from "../constants/queryHeaders"; + +export const flatten = (arr: any[]): any[] => { + return arr.reduce((acc: any[], val: any) => + Array.isArray(val) ? acc.concat(flatten(val)) : acc.concat(val), []); +}; + +export const getQueryParams = (attribute: string) => { + return queryData.find((d) => d.plugInAttribute === attribute); +};